Snap It Daily

Snap It Daily

A daily photo game: everyone gets the same colour prompt, nobody sees anyone else shot until the 24-hour reveal.

Role
Solo developer
Year
2026
Stack
React Native · Expo · Fastify
Snap It Daily interface

Snap It Daily replaces the infinite feed with a single daily constraint. Everyone gets the same colour, you get one photo to find it in the world, and no one sees anyone else attempt until the reveal. The scarcity is the product: there is nothing to scroll and nothing to optimise for.

It is an npm-workspaces monorepo with an Expo client, a Fastify API, and a shared package holding the types, Zod validation schemas and colour palettes both sides compile against. The API covers authentication with JWT and rotating refresh tokens plus Google sign-in, friendships and blocks, likes, comments and reposts, reporting and moderation, streaks, and Expo push notifications. Uploads are processed with sharp into a capped full-size image and a square thumbnail, then written through a pluggable storage driver that runs against the local disk in development and Cloudflare R2 in production.

The daily colour cannot simply be random. It is drawn by a PRNG seeded from the date string, filtered against the last fourteen days so colours do not repeat, and picked from a palette that varies by season. Because the seed is the date, any process that needs today colour derives the same answer without coordinating, and the insert is guarded with an on-conflict clause so two workers racing at midnight cannot produce two different colours.

Engineering notes

Deterministic colour selection

The daily colour comes from a date-seeded PRNG over a seasonal palette, excluding anything used in the past fortnight. Seeding on the date makes the choice reproducible from any process, and an on-conflict insert makes the midnight race harmless.

Reveal enforced twice, on purpose

A cron job flips expired snaps every minute, but read paths also reveal lazily when they encounter a snap whose reveal time has passed. Correctness does not depend on the scheduler having run, so a missed tick delays nothing.

One shared package, two consumers

Types, Zod schemas and the colour palettes live in a shared workspace package imported by both the API and the Expo client. Validation rules cannot drift between client and server because there is only one copy of them.

Built with

React NativeExpoFastifyPostgreSQLDrizzle ORMCloudflare R2