// full-stack app
SleepTrack
A sleep journal with an analytics engine: an async FastAPI service and a Next.js and daisyUI app.
SleepTrack turns logged nights into a nightly score, trends, a chronotype estimate, the habits that help or hurt your sleep and a weekly report. Version 2 is a ground-up rewrite: an async FastAPI service on PostgreSQL and Redis with a background worker, and a Next.js 16 app typed from the API's OpenAPI schema.
- year
- 2025
- type
- full-stack app
- group
- platforms and backends
- tests
- 1,032 at 98% coverage
the problem
//01the problem
Logging sleep is the easy part. Making the log useful means knowing which night a session belongs to, which habits change your sleep and how steady your schedule really is, all in your own time zone and behind an account system you can trust with health data.
how it works
//02how it works
- 01
Analytics that respect the clock
Bedtimes are averaged as angles, so 23:30 and 00:30 average to midnight instead of noon, and every night belongs to the date it began in the user's time zone. The API computes a weighted score from duration, quality, latency, awakenings and bedtime, plus consistency, sleep debt, streaks, chronotype and social jet lag, cached per user in Redis.
- 02
Insights in plain language
A rule engine behind a pluggable provider compares nights with and without each tag and ranks findings such as caffeine lowering your sleep quality. An ARQ worker emails weekly reports in each user's time zone, sends optional bedtime reminders and clears out demo accounts.
- 03
Sessions built to be trusted
Argon2id passwords, 15-minute access tokens and hashed refresh tokens that rotate on every use: reuse revokes the device, with a short grace window for two tabs refreshing at once. CSRF protection, Redis rate limits, device management, an audit log, email verification and optional Google sign-in with PKCE sit around it.
- 04
Rules the database enforces
PostgreSQL rejects overlapping nights with an exclusion constraint, allows one running timer per user through a partial unique index and searches notes with a trigram index. Every error leaves the API as an RFC 9457 problem document with a stable code.
- 05
A client typed from the schema
The Next.js app generates its types from the OpenAPI schema, keeps the access token in memory and refreshes it single-flight. A same-origin route handler streams /api to the service and forwards the client address, so rate limits see real users. It has two themes, a command menu, a mobile dock and charts with table views.
- 06
Tested against the real thing
Over a thousand backend tests run on real PostgreSQL and Redis, and Playwright drives sign-up with email confirmation, the journal, the timer and settings against the live API in CI. Both repos ship Docker images, a Compose stack and GitHub Actions, and a one-click demo seeds 90 nights.
measured
//03measured
- 1,032
- backend tests
- run against real postgresql and redis in ci
- 98%
- test coverage
- measured on the api service
- 15 min
- access token lifetime
- with rotating, hashed refresh tokens
- 90
- nights seeded by the demo
- one click, no sign-up
highlights
//04highlights
- Weighted sleep score with circular bedtime statistics, chronotype and tag impact
- Rotating refresh tokens with reuse detection and CSRF protection
- Overlapping nights rejected by a Postgres exclusion constraint
- Weekly email reports and bedtime reminders from a background worker
- Client types generated from the API's OpenAPI schema
- 1,032 backend tests at 98% coverage plus Playwright end-to-end tests in CI
built with
- Python
- FastAPI
- SQLAlchemy
- PostgreSQL
- Redis
- ARQ
- TypeScript
- Next.js
- daisyUI
- TanStack Query
- Playwright
- Docker
//05contact
Say hello. I read everything.
Email is the fastest way to reach me. For anything that needs a conversation, book a call.
to
- name
- Khaled Saeed
- country
- Lebanon