Backend / API
StreakFit API
Kotlin/Ktor backend for workout schedules and streaks, versioned plans, JWT + Google auth.
- Kotlin
- Ktor
- Exposed ORM
- PostgreSQL
- Flyway
- Redis
- JWT
- Google OAuth
- Docker
Overview
StreakFit is the backend for a fitness app built around consistency: users define a weekly workout schedule, follow it day by day, and keep a streak going. It is deliberately a different stack from the rest of this site, Kotlin on the JVM with Ktor, chosen to show that the engineering approach (clean domain modeling, tests first, disciplined migrations) is language-independent, not tied to one ecosystem.
Problem
A training schedule is not static: people change routines, and a change should take effect on a future date without corrupting the history of what they were supposed to do before it. Most simple CRUD backends overwrite the plan in place, which loses that history and makes "what was my schedule last Tuesday" unanswerable. Auth also has to support both classic email/password and Google sign-in from day one.
Solution
A Ktor REST API with a versioned schedule model: each user can have an active schedule and a pending one with an effective-from date, so edits roll forward cleanly instead of mutating the past. A schedule is a set of per-day entries (workout or rest), each holding ordered exercise slots with sets, reps, or duration. Auth issues JWTs and accepts both password and Google OAuth. Exercises live in their own catalog referenced by the schedule.
Architecture
Kotlin + Ktor (Netty) with kotlinx.serialization for JSON. Domain code is split by feature, auth, users, schedules, exercises, with the schedule logic isolated behind a service, a validator, and a clock abstraction so effective-from date math is testable without wall-clock flakiness. Persistence is PostgreSQL through the Exposed ORM, with Flyway managing migrations, and Redis for caching. It ships as a Docker image behind Traefik on the homelab at streakfit-api.theevolvedalligator.com.
Key decisions
A versioned active/pending schedule instead of in-place edits, so plan changes are auditable and future-dated. A dedicated ScheduleClock so date-sensitive rules are unit-testable and deterministic. Exposed over a heavier framework to keep SQL close and explicit. Flyway so schema changes are ordered and reproducible across environments. JWT with both password and Google OAuth so the client is not locked to one identity provider. Kover coverage and a unit-test suite that runs without an embedded database during fast agent iteration.
Challenges
Modeling schedule versioning so that switching the active plan never rewrites past days; keeping the effective-from transition logic deterministic under test; validating that every day entry and exercise slot is internally consistent before it reaches the database; and keeping the JVM image small and fast to boot for homelab deploys.
Outcome
A live, health-checked Kotlin API on the homelab with a clean, versioned domain and a real test suite: evidence that the same ownership and quality bar carries across languages, not just the TypeScript and Python stacks that dominate the rest of this portfolio.