All work

Case 04 · Product design & development, solo · personal PWA

Baki
concept to shipped, every decision mine.

Stack · React + FastAPI · mobile-firstStatus · Running daily · not publicly launched
Baki real app screens (home, nutrition, training) composed on the Aura scene; demo data only

01 · What it is

A private personal trainer with exactly one user, on purpose.

Baki combines strength training and nutrition tracking, built around evidence-based training principles, female physiology and sustainable health, with a hard constraint: the objective is always maintenance or recomposition, never a caloric deficit. It monitors for RED-S (Relative Energy Deficiency in Sport) and surfaces warnings before problems compound.

It runs as an installable PWA on my phone: no App Store, no Play Store, no platform fees. Deployed on a local server; accessible on my home network. Private by decision, not by limitation. The product question was never "how do I monetise this?" It was "what would I actually build if I had to live with every product decision I made?"

02 · The product decisions that matter

Before any screen, I had to decide what the product would never do.

Health above progress

The app monitors for RED-S (Relative Energy Deficiency in Sport) and flags it proactively. A training goal never overrides a health signal.

AI communicates, doesn't calculate

All logic (progression, nutrition totals, volume load, RED-S risk) lives in a deterministic, testable engine. The AI coach only reads from it and communicates in plain language. It can't override a rule.

Objective is always maintenance/recomposition, never deficit

The product is opinionated by design. It monitors that the user is eating enough, not restricting. That's a product decision, not a feature.

These aren't feature decisions. They're product invariants. Rules the product enforces even when the user might prefer it didn't. Writing them down before building anything forced me to understand what problem I was actually solving.

03 · The architecture decision, and why it was a design call

Deterministic engine + AI communication layer, not the other way around.

Option A · rejected

Let the AI decide

Ask an LLM to calculate progression, nutrition targets and health flags on the fly. Fast to build. Impossible to test. The model hallucinates, drifts between sessions, and can't be audited when it says "eat less."

Option B · chosen

Engine calculates, AI communicates

All logic lives in a deterministic Python engine: testable, auditable, consistent between sessions. The AI coach reads the engine's outputs and surfaces them in plain language. It has no write access to the calculation layer. When the engine says RED-S risk: 0.8, the coach flags it as a card. It can't override it.

This is a product design decision that happens to have engineering consequences, not the other way around. The question was: "what does the user need to trust this product with their health?" The answer was: consistency and auditability, not conversational flexibility.

04 · Decision log

The senior work was not adding features. It was deciding what the product should protect, simplify and refuse.

Design for one committed user first

The riskiest assumption was not market size; it was whether the product could support a real routine without becoming noisy.

Impact

Kept the scope honest: fewer generic dashboards, more daily-use flows that had to survive repeated use.

Make health guardrails part of the core logic

A fitness product can push harmful behavior if progress is the only success metric.

Impact

RED-S warnings, maintenance/recomposition defaults and enough-eating prompts became product rules, not optional content.

Use AI for communication, never authority

Health, progression and nutrition logic need consistency and auditability.

Impact

The coach feels helpful while the underlying system remains deterministic, testable and predictable.

05 · The product

Two surfaces, one engine: training and nutrition, built to work together.

Training

Multi-week challenges and single-day sessions. Each set logs reps and RIR (Reps in Reserve). Double progression: when you complete the rep range with good RIR, the weight increases. Full load history per exercise.

Nutrition

Meal log with a food library. Tracks kcal, carbs, protein and fat. Dish composer by ingredient and gram weight. Day navigator with breakfast/lunch/dinner alerts. RED-S watchdog.

Deterministic engine

All business logic lives in one testable core: progression rules, volume calculations, nutrition totals, RED-S risk, trend detection. No AI in the calculation layer.

AI coach layer

A communication layer on top of the engine. The coach reads engine outputs and surfaces proactive cards (RED-S caution, data gaps, milestone) with Accept/Dismiss. It's a messenger, not a decision-maker.

Motion proof · 26 seconds, recorded live

Not a prototype. This is the product running.

Home, nutrition, training and progress in one take of the real build. The coach opens with a check-in nudge — a card the engine raised, offered as Accept / Not now. The AI never acts on its own, and Progress reads a 7-day weight average back in plain language.

Baki home screen: today's training and nutrition at a glance

Home

Where you stand, surfaced calmly

Today's session and the day's macros in one glance. The engine has already done the reading; the screen's job is to stay quiet about it until something matters.

Baki nutrition day view: macro targets and per-meal breakdown

Nutrition

Eating enough is the success state

The day reads against protein, kcal and a fat floor, broken down per meal. Maintenance is the target: a deficit shows up as a warning, never as an achievement.

Baki training library: routines and today's session

Training

The rule picks the next weight, not a guess

Multi-week challenges beside single sessions, with a search-and-filter library for breadth without noise. Behind every logged set, the double-progression rule decides what comes next.

Real UI captured from the running app · demo data only (no personal health data)

06 · The system underneath

Brand discipline, applied to product: every token is a decision, documented where it lives.

Baki's UI runs on a semantic token system: CSS variables for colour, radius, spacing and type, consumed by 11 re-themed primitives underneath 43 domain components. The values below are read from the shipped code, not a styleguide made for this page — including the contrast ratios, which are written as comments next to the decision they justify.

Token

Light

Dark

--bg

#F8F8FC
#111118

--surface

#FFFFFF
#1E1E2A

--text-primary

#1A1A2E
#ECECF3

--text-secondary

#6B6B80
#9C9CB2

--accent

#5B5BD6
#8486EF

--primary · CTA

#5B5BD6
#5B5BD6

--danger-text

#D70015
#FF3B30

--warning-text

#A85900
#FF9500

--success-text

#1F7A33
#34C759

Note the pair that breaks the pattern: --accent lightens for dark mode, --primary doesn't. That asymmetry is the point — see below.

The CTA purple refuses to lighten

In dark mode the accent lightens to #8486EF so it reads on dark surfaces — but the primary button keeps the brand #5B5BD6. On brand purple the white label holds 5.37:1 (AA); on the lightened accent it drops to 3.16:1. One colour became two tokens so neither brand nor contrast had to lose.

Every state colour exists twice

The bright fills (danger #FF3B30, warning #FF9500, success #34C759) are reserved for fills and large text. As body text in light mode they swap to darkened variants that pass AA ≥ 4.5. The system encodes where a colour may be used, not just what it looks like.

Accessibility guarantees live outside the utility layer

Focus rings come from a single --focus-ring source; reduced-motion and the iOS input anti-zoom are written outside Tailwind's layers, so no utility class can accidentally override them. They behave as guarantees, not conventions.

Scales

Radius
card 16 · pill 24 · input 10
Spacing
4 · 8 · 12 · 16 · 24 · 32
Type
11 → 28 px · weights 400 / 600 / 700 / 800

Six spacing steps and six type sizes — small enough to hold in your head, which is what keeps a solo product visually consistent at 10pm.

Two layers · 11 primitives → 43 domain components

Generic primitives (button, card, sheet, dialog…) are re-themed once through the semantic tokens; everything the user actually touches is a named domain component built on top:

WorkoutCardRestTimerMacroBarsCoachChatCoachFABWeekCalendarCheckInSheetExercisePickerSheetMealTemplateCardSugerenciaComidaEmptyStatePwaUpdateToast+31 more

07 · How it was built

Designed and built solo, with AI as the development partner, every decision directed by me.

Frontend
React 18 · Vite · TypeScript · PWA (installable, mobile-first)
Design system
Semantic CSS variables · light/dark theme-aware · 11 re-themed primitives under 43 domain components
Backend
Python 3.12 · FastAPI · SQLite
AI coach
Anthropic API (Claude Haiku) · communicates, never calculates
Alerts
python-telegram-bot · proactive nudges when the engine flags something
Development
Claude Code (Anthropic) · AI-assisted dev, every decision directed by me

The build methodology was iterative: two-week cycles, feature by feature. Design in Figma first: every significant interaction as a hi-fi prototype or annotated spec, including the session-log flow, the nutrition day navigator, and the coach-card dismissal interaction. Then build. Then use it for two weeks before touching the next feature. Nothing went to code that wasn't clear enough to build correctly the first time.

I used Claude Code (Anthropic) as a development tool throughout: writing prompts, reviewing the output, making architecture calls, and course-correcting when the generated code didn't match the product intent. The engineering is AI-assisted. The product direction, design decisions and business logic are not.

08 · What I would validate next

Shipping solo proves judgment and execution. The next layer is evidence from people who are not me.

Test whether the coach cards feel supportive or intrusive after repeated daily use.

Validate the nutrition language with users who dislike calorie-focused tracking.

Stress-test empty states and missed-day recovery so the product supports lapses without guilt.

09 · What this proves

One person took this from first sketch to a PWA in daily use — no PM, no budget review, no stakeholder approval.
the clearest version of "resourceful self-starter, minimal oversight." The design system and iterative delivery are what made that possible at solo scale.

1

user · me, by design

2

surfaces: training + nutrition

1

engine · no AI in the calculation layer

0

stakeholders to approve it

The brief I set myself was harder in some ways than a client brief: no one to validate with, no PM to check priorities with, no budget conversation. Just design thinking and decision-making, end to end.