Files
sneakyklaus/docs/decisions/0001-core-technology-stack.md
Phil Skentelbery b077112aba chore: initial project setup
Initialize Sneaky Klaus project with:
- uv package management and pyproject.toml
- Flask application structure (app.py, config.py)
- SQLAlchemy models for Admin and Exchange
- Alembic database migrations
- Pre-commit hooks configuration
- Development tooling (pytest, ruff, mypy)

Initial structure follows design documents in docs/:
- src/app.py: Application factory with Flask extensions
- src/config.py: Environment-based configuration
- src/models/: Admin and Exchange models
- migrations/: Alembic migration setup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-22 11:28:15 -07:00

8.5 KiB

0001. Core Technology Stack

Date: 2025-12-22

Status

Accepted (Updated 2025-12-22)

Context

Sneaky Klaus is a self-hosted Secret Santa organization application designed for individuals, families, and small organizations who want full control over their data. The application must be:

  • Easy to self-host via containerization
  • Simple to deploy and maintain
  • Minimal in external dependencies
  • Suitable for small-scale usage (dozens of participants, not thousands)
  • Functional without complex infrastructure

Key requirements that inform technology choices:

  1. Self-hosting first: Users should be able to deploy with a single container
  2. Simplicity: The tech stack should be straightforward and well-documented
  3. No participant accounts: Authentication must support passwordless magic links
  4. Email delivery: Must send transactional emails reliably
  5. Background jobs: Must handle scheduled tasks (reminders, data purging)
  6. Data persistence: Must store user data reliably but doesn't need high-scale database features

Decision

We will use the following core technology stack:

Component Technology Version Constraint
Backend Framework Flask ^3.0
Language Python ^3.11
Database SQLite ^3.40 (via Python stdlib)
Email Service Resend Latest SDK
Deployment Docker Latest
Package Manager uv Latest
Background Jobs APScheduler ^3.10
Template Engine Jinja2 ^3.1 (Flask default)
WSGI Server Gunicorn ^21.0 (production)
Form Handling Flask-WTF (includes WTForms) ^1.2
Session Management Flask-Session ^0.8
Timezone Validation pytz Latest
CSS Framework Pico CSS Latest (via CDN)

Key Technology Rationale

Flask: Lightweight, well-documented, excellent for small-to-medium applications. Large ecosystem, straightforward patterns, and no unnecessary complexity.

Python 3.11+: Modern Python with performance improvements, excellent type hinting support, and active security support.

SQLite: Perfect for self-hosted applications. Zero-configuration, single-file database, excellent for read-heavy workloads with occasional writes. Eliminates need for separate database server.

Resend: Modern transactional email API with excellent deliverability, simple API, and reasonable pricing for small-scale usage.

Docker: Industry-standard containerization. Single container deployment simplifies self-hosting significantly.

uv: Fast, modern Python package manager and project manager. Significantly faster than pip, with better dependency resolution and lockfile support.

APScheduler: In-process job scheduling. Eliminates need for separate job queue infrastructure (Redis, Celery) while still supporting background tasks like reminder emails and data purging.

Jinja2: Flask's default templating engine. Server-side rendering eliminates need for frontend JavaScript framework, simplifying deployment and maintenance.

Gunicorn: Production-ready WSGI server for Flask applications. Well-tested, stable, and appropriate for the scale of this application.

Flask-WTF: Integrates WTForms with Flask, providing form validation, CSRF protection, and secure form handling. Industry-standard for Flask applications.

Flask-Session: Server-side session management for Flask. Stores session data in SQLite, providing secure session handling without client-side storage concerns.

pytz: Standard Python library for timezone validation and handling. Required for validating IANA timezone names in exchange configurations.

Pico CSS: Minimal, classless CSS framework delivered via CDN. Provides clean, semantic styling without requiring a build step or complex class names. Fully responsive and accessible out of the box.

Frontend Approach

Pure server-side rendering with Jinja2 templates. No JavaScript framework (React, Vue, etc.). This decision:

  • Eliminates build tooling complexity
  • Reduces deployment artifacts (no separate frontend bundle)
  • Simplifies security (no client-side state management)
  • Ensures full functionality without JavaScript enabled
  • Maintains mobile-friendliness through responsive CSS

Progressive enhancement with minimal JavaScript for interactivity (copy-to-clipboard, form validation) is acceptable but not required for core functionality.

Consequences

Positive

  • Simple deployment: Single container with no external service dependencies (except Resend for email)
  • Low resource requirements: SQLite and in-process job scheduling minimize memory and CPU usage
  • Fast development: Flask's simplicity and Jinja2's straightforward templating accelerate development
  • Easy debugging: All code runs in single process, simplifying troubleshooting
  • Predictable performance: Server-side rendering is fast and consistent
  • No build step: Templates render directly; no frontend compilation required
  • Security by default: Server-side rendering reduces attack surface compared to client-side SPAs
  • Excellent for scale target: Perfect for dozens to hundreds of participants per deployment

Negative

  • SQLite limitations: Not suitable if application needs to scale to thousands of concurrent users (not a concern for target use case)
  • No horizontal scaling: Single SQLite file prevents multi-instance deployment (acceptable trade-off for simplicity)
  • Email vendor lock-in: Resend is the only supported email provider (could be abstracted later if needed)
  • APScheduler constraints: Job scheduling tied to application process lifetime; jobs don't survive application restarts (acceptable for reminder scheduling)
  • Less interactive UI: Server-side rendering means no SPA-style instant interactivity (acceptable trade-off for simplicity)

Neutral

  • Python expertise required: Development requires Python knowledge (expected for Flask application)
  • Database portability: SQLite schema could be migrated to PostgreSQL if scaling needs change, but would require development effort
  • Email testing: Requires Resend account for development (free tier available) or mocking in tests

Implementation Notes

Database Considerations

SQLite will be configured with:

  • WAL (Write-Ahead Logging) mode for better concurrency
  • Foreign keys enabled
  • Appropriate timeout for locked database scenarios
  • Regular backups recommended via volume mounts

Job Scheduling Considerations

APScheduler will run in-process with:

  • JobStore backed by SQLite for job persistence across restarts (for scheduled jobs)
  • Executor using thread pool for background tasks
  • Misfire grace time configured appropriately for reminders

Email Configuration

Resend integration will:

  • Store API key in environment variable (not in code)
  • Support template-based emails
  • Handle failures gracefully with logging
  • Rate limit appropriately

Development vs Production

  • Development: Flask development server, SQLite in local file
  • Production: Gunicorn with multiple workers, SQLite in mounted volume, proper logging

Alternatives Considered

Database Alternatives

PostgreSQL: More scalable but requires separate database container/service, significantly complicating self-hosting. Overkill for target scale.

MySQL/MariaDB: Same drawbacks as PostgreSQL for this use case.

Job Queue Alternatives

Celery + Redis: More robust job processing but requires Redis container, significantly complicating deployment. Overkill for reminder emails and daily data purging tasks.

Cron + separate script: Could work but fragments application logic and complicates deployment.

Email Service Alternatives

SendGrid: Viable alternative but more complex API and pricing structure.

Amazon SES: Requires AWS account and more complex setup. Higher barrier for self-hosters.

SMTP: Requires users to configure their own SMTP server, significantly increasing setup complexity and deliverability issues.

Frontend Alternatives

React/Vue SPA: Considered but rejected. Would require build tooling, increase deployment complexity, and provide minimal benefit for the application's relatively simple UI needs.

HTMX: Considered for progressive enhancement. May be added later but not required for MVP.

References