DETAIL 1 / E-201 — BENCHPROJECT 3 OF 7
Family Screen Bank
SELF-HOSTED WEB APP · HOUSEHOLD
A screen-time bank: minutes are earned, banked and spent in timed sessions.
- DETAIL
- 1 / E-201
- SHEET
- E-201 · BENCH
- STATUS
- PILOT · IN FAMILY USE
- ZONE / LAYER
- BENCH · SOFTWARE
- BUILT WITH
- TypeScript, Fastify, SQLite
BALANCE, FOLDED
175 MIN
- BASE
- 100
- EARNED
- 25
- BANKED
- 50
NO SESSION RUNNING
| Entry | Minutes | Bucket | Note |
|---|---|---|---|
| #001 | +100 | BASE | sample base |
| #002 | +25 | EARNED | sample earn |
| #003 | +50 | BANKED | sample carryover |
SAMPLE VALUES FOR THE DEMO. NOT MY FAMILY’S DATA OR RULES.
PROBLEM
I wanted screen-time rules that are easy to follow: the balance is a fact, not a verdict; running out is never shown in red; quiet hours read as rest, not lockout.
BUILD
A Fastify and TypeScript API over SQLite with a React PWA, self-hosted. Balances are never stored; they’re folded from an append-only ledger with base, earned and banked buckets. A daily reset moves unused base minutes to the bank. Sessions work as leases, so ending early refunds unused whole minutes.
STATUS
In use by my family as a pilot. The latest phase was built September 8, 2026.
STACK
- TypeScript (strict)
- Node 24
- Fastify 5
- SQLite (WAL)
- Drizzle ORM
- Luxon
- React 19
- Vite PWA
- Web Push
- Server-Sent Events
- Vitest
KEYNOTES · BUILD NOTES
- A property-style test checks derived balances after 1,000 random operations.
- The daily reset is idempotent and tested across spring-forward and fall-back. One test seeds a 169-hour week.
- Design tokens are tested code: OKLCH colors with 73 contrast and gamut assertions, and a lint against hard-coded colors.
- Built with AI coding agents from phase specs with numbered acceptance tests: 108 commits, 19 merged pull requests.
MICHAEL MORALE · DETAIL 1 — FAMILY SCREEN BANK
DETAIL
1 / E-201
SHEET
E-201