Back to all work
Application
Secret Santa
Gift-exchange draws where even the organiser does not know the result.
- Year
- 2026
- Status
- Live
- Role
- Solo: back end, front end, security.

The organiser types in the participants, the app draws the pairs and gives each person their own signed link. Only the owner of a link sees what is behind it: the organiser, even when taking part, sees only who has looked already. No accounts for participants, no email addresses collected.
Stack
- Python
- Flask 3
- SQLAlchemy 2
- itsdangerous
- pytest
- Vanilla JS
- REST APIs
In practice
- Nobody draws themselves, and no two people draw each other: a shuffled cycle when there are no restrictions, and a solver with a hard step limit when couples have to be kept apart.
- A link that cannot be forged or reused by somebody it was not meant for: each one is signed, and the part that identifies you rides in the piece of the address a browser never sends to the server, so it stays out of the logs.
- The organiser can see who has already looked and nothing else, which is checked by a test that fails if a pair ever appears in that response.
- An optional account that grants no extra sight: it remembers your events, and that is all it does.
- Works on the cheapest hosting there is: no build step, no Node, and the same code runs on SQLite at home and MySQL in production.
How it is built
- A REST API kept clear of the static front end: 15 endpoints, 81 tests under pytest.
- Draw: a Hamiltonian cycle in linear time with no exclusions, backtracking with an MRV heuristic and a step ceiling when there are, seeded from a CSPRNG.
- Tokens signed with HMAC over a separate salt, carrying a one-time component from the database so a single link can be revoked.
- Sessions with CSRF protection scoped to cookie-authenticated requests only, and a password reset with no token table: the payload holds a fingerprint of the current hash, so changing the password spends the link.
- SQLAlchemy throughout, so SQLite locally and MySQL or PostgreSQL in production without touching the code.

