All work

Konku

Personal spaced-repetition learning system — notes, flashcards, and a scheduler that never lets what you learn disappear silently.

React.jsTypeScriptGoChiReact-RouterPostgresRedisDockerSelf HostedSentry
Konku interface
Cross-domain self-directed learning — general knowledge, math, psychology, music, alongside deepening existing coding skills — is easy to start and easy to abandon, and most productivity or habit apps optimize for engagement metrics such as streaks, badges, and notifications rather than for whether anything actually gets retained. I built Konku to solve a specific, real version of that problem for myself: motivation that fades without visible progress, sessions that drift without a hard start and end, and the sharpest one — genuinely forgetting material within weeks without a system that resurfaces it on a schedule I can't forget to check. Rather than adopt an existing habit tracker, I wrote those constraints out as a product brief and built directly against them, with a rule that every feature had to answer at least one of five named failure modes. That constraint-first approach shaped real engineering, not just copy: streaks are weekly rather than daily so one bad day doesn't erase weeks of progress, focus sessions start short (15-20 minutes) and grow over time, and there is no gamification, no losable daily streak, and no guilt-driven notification copy anywhere in the product.
Solo developer — Go backend (chi, Postgres via pgx + sqlc), React/TypeScript frontend, the spaced-repetition scheduling engine, and the deployment architecture
MVP built, full loop working end to end; hardening toward a production-grade, multi-user service is in progress

Kept the spaced-repetition engine pure, and enforced it in CI

`internal/srs` imports nothing else from the codebase, and `make check-pure` fails the build if that ever changes. It carries the product's actual value and is the part most likely to go subtly wrong if it gets entangled with database or HTTP concerns, so isolating it keeps it trivially testable no matter what changes around it.

Rejected: Letting the scheduler reach into storage and request handling directly

Weekly streaks, and no gamification anywhere in the product

The failure mode was guilt, not lack of engagement. A weekly streak means one bad day doesn't erase weeks of progress; there are no badges, no losable daily streak, and no guilt-driven notification copy. Focus sessions start at 15–20 minutes and grow from there.

Rejected: Daily streaks, badges and reminder notifications, as most habit apps use

Two independent mechanisms for multi-tenant isolation

Every query carries a `WHERE user_id` clause, and Postgres Row Level Security enforces the same boundary underneath it. "Your data is yours" is a guarantee that shouldn't rest on either one alone.

Rejected: Application-level filtering on its own

Wrote the constraints out as a product brief before building

Five named failure modes, with a rule that every feature had to answer at least one of them. Building against written constraints rather than a market gap is what produced the weekly streak and the no-guilt copy as engineering rules instead of leaving them as vibes.

Rejected: Adopting an existing habit tracker and working around what it optimizes for

My Role & Impact

This is the project I designed most deliberately around a real personal constraint rather than a market gap, and it's shaped how I think about who a feature is actually for. The spaced-repetition engine (internal/srs) is deliberately isolated — it imports nothing else from the codebase, and a CI check (make check-pure) enforces that — because it carries the product's actual value and is the part most likely to get subtly wrong if it gets entangled with database or HTTP concerns.

What I Learned

  • Translating a personal, qualitative constraint ("don't make me feel guilty about a missed day") into a concrete, testable engineering rule — weekly streaks, no punitive copy — instead of leaving it as a vibe.
  • Keeping the core logic that matters most, the scheduler, genuinely pure and enforcing that purity in CI, so it stays trivially testable no matter what changes around it.
  • Defense in depth for multi-tenancy: treating "your data is yours" as a guarantee that needs two independent mechanisms — a WHERE user_id clause and Postgres Row Level Security — not either alone.

Showcase

Konku — nothing you learn disappears silently
Konku — nothing you learn disappears silently
The same set, again later — a fixed question set returns on the scheduler's terms, and every attempt is kept
The same set, again later — a fixed question set returns on the scheduler's terms, and every attempt is kept
One question, one answer — cards stay deliberately small, tagged by domain and category
One question, one answer — cards stay deliberately small, tagged by domain and category

Screenshots

The full product, as it actually runs.

Beranda — today's review load, the focus session, and recent notes by domain
Beranda — today's review load, the focus session, and recent notes by domain
Notes library, filterable by domain and category
Notes library, filterable by domain and category
Note detail — long-form material with code, kept next to the cards drawn from it
Note detail — long-form material with code, kept next to the cards drawn from it
Cards — a question set and its answers, scoped to what you're studying
Cards — a question set and its answers, scoped to what you're studying
Review session — one set at a time, with the score history behind it
Review session — one set at a time, with the score history behind it
Practice question — answered freely, then checked before moving on
Practice question — answered freely, then checked before moving on
Focus timer — sessions start short and grow, with per-domain history
Focus timer — sessions start short and grow, with per-domain history