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>
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:
- Self-hosting first: Users should be able to deploy with a single container
- Simplicity: The tech stack should be straightforward and well-documented
- No participant accounts: Authentication must support passwordless magic links
- Email delivery: Must send transactional emails reliably
- Background jobs: Must handle scheduled tasks (reminders, data purging)
- 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
- Flask documentation: https://flask.palletsprojects.com/
- SQLite documentation: https://www.sqlite.org/docs.html
- Resend documentation: https://resend.com/docs
- APScheduler documentation: https://apscheduler.readthedocs.io/
- uv documentation: https://docs.astral.sh/uv/