Speak Five
The early skeleton of a learning app where you listen to, repeat, and recall five English sentences matched to your job and situation - 18 hours and 8 commits set up the selection screen, the time-zone rules, and the test gates, and nothing else. Zero sentences so far, and even the product name is provisional.
- React
- TypeScript
- Vite
- Capacitor
- Playwright
- Temporal
- QA
Today screen - pick a role and situation and the matching sentences appear here. With zero reviewed sentences, the empty state is shown as is
Role picker - 16 roles grouped into 5 families. IDs are defined once in the domain types
Situation picker - 5 per role, 80 in all. Display dates are KST calendar dates while storage stays UTC Z
Setup
- Problem
The BRD starts from a single case: a QA engineer who joined a US company and is juggling work English with a graduation speaking score. Someone who knows how to explain the work but struggles to put progress, problems, expected outcomes, and requests for help into English. The BRD states that this one case is not to be generalised into market demand, and only proposes "Korean-speaking professionals collaborating with overseas colleagues" as the initial customer. The PRD's one line is "a product for briefly repeating expressions you will pull out at work." The first user story is "as a QA engineer, I want to pick and practise the expressions for explaining today's bug." The business status is written at the top of the BRD: a plan whose customer experiment and revenue are not yet validated.
- Context
First commit at 22:58 on 3 October 2026, eighth commit at 16:56 the next day. Everything here fits inside 18 hours. There are 10 documents (README, SSOT, BRD, PRD, ARCHITECTURE,
DATA_API_SPEC,CONTENT_SPEC,QA_TEST_PLAN, ROADMAP,PROJECT_STRUCTURE) at version 0.1.7 Draft. Speak Five is a working title and the app identifier for release is undecided. The roadmap runs R0 planning and content, R1 a shared web and WebView trial, an R1 customer experiment (20 people, 14 days), R2 accounts and paid operation, R3 extensions. Even the price, 4,900 won a month, is written only as a "proposal before validation". The current position is the R1 skeleton, and the README says up front that "this skeleton does not mean R1 is complete or that it is ready to ship."- Users
The hypothesised user is a professional working in Korean and collaborating with overseas colleagues, with a QA engineer as the first case. Actual users: zero. With no reviewed sentences, the current screen offers only family, role, and situation selection plus an empty-content state, and the selection lives in memory, so a refresh clears it.
- Hypothesis
If a short loop of listening to, repeating, and recalling five sentences chosen by job and situation genuinely helps people use work English, then 200 reviewed sentences (4 roles × 50) are enough for a 20-person, 14-day experiment to show a signal. Until that experiment runs, none of this is confirmed.
Build
- What I did
- Set up the React, TypeScript, and Vite runtime with lint, unit tests, E2E, and GitHub Actions CI first. A single npm run verify runs lint (zero warnings), unit tests, build, and E2E in order
- A selection screen for 5 families, 16 roles, and 80 situations - a role dropdown grouped by family on a shared custom Select. IDs are defined once in domain/profile/
types.tsand the content tree references them - Pinned the time-zone rules in code first - storage, API, and logs use UTC Z notation, display and study and review days use Asia/Seoul, and
day_keyis a calendar date in the learning time zone rather than a timestamp.calendar.tsrejects any non-Z timestamp with a RangeError - Pulled session selection, review scheduling, and report aggregation into pure domain modules that know nothing about adapters. Dependencies run one way and domain never references adapters
- Content schema validation, domain types, the storage, audio, lifecycle, and content adapter contracts, plus the Capacitor config and platform generation steps - but no native build and no device testing
- In the last commit, split the Temporal test path in two - CI's Node 26 ships Temporal natively, so the polyfill path had never been verified
- Product decisions
- No unreviewed sentences and no fake completion results go into the app - so the catalog is bootstrap-empty-v1 with zero sentences. The selection screen showing an empty state is a decision, not a bug
- Build the shared features on the web and ship iOS and Android as WebView apps. The build target is the iOS 16.4 WebView, native/ holds only the Capacitor config, and no empty placeholder native project is generated
- No business backend in R1. backend/ holds only the UTC Z contract, with no running server
- Leave the product name, app identifier, and price unconfirmed. So that nothing unknown is written as if it were decided
- The next unit is content, not features - 4 roles × 1 situation × 5 sentences, 20 reviewed sentences with audio, to wire the core flow once end to end
- QA considerations
- Is the code under test the code that ships - Playwright attaches to the production build (preview on port 4174), not the dev server. The config comment gives the reason: the production build is what ships
- Does the CI environment hide a path - Node 26 ships Temporal natively, so the polyfill path had never run in CI. Vitest now runs two projects, runtime and polyfill, so the same 296 unit cases run twice (592), and an E2E spec deletes Temporal via addInitScript and checks that 2026-10-03T15:00Z renders as 4 October
- Same input, same result at the day boundary - UTC Z storage is separated from the KST calendar date, and non-Z timestamps are refused outright. An off-by-one-day near midnight is blocked by the contract of a single function
- Is a passing test being read as done -
QA_TEST_PLANhas an FR-001 to FR-010 traceability table and a device and audio matrix, but every cell is "not run". The documents themselves say "passing the structural tests is not treated as passing the full acceptance criteria" and "test doubles are not treated as completed storage or voice verification" - Device verification is missing - the README states that "these tests do not replace real iOS and Android WebView verification", and the plan's principle is that simulators do not stand in for voice and permission checks
Outcome
- Metrics
- 8 commits, 2026-10-03 22:58 to 10-04 16:56 KST, single author
- 10 documents, version 0.1.7 Draft. Content tree of 5 families, 16 roles, 80 situations, zero reviewed sentences
- 9 unit test files (179 declarations, 592 runs across two Temporal paths), 2 E2E specs (25 passed, 1 desktop-only skipped), zero integration tests. Figures are the run results recorded in the last commit message
- CI - npm run verify on Node 26 for every push and PR, with traces and screenshots kept 7 days on failure
- User, learning, and revenue metrics all unmeasured. All four release gates in the QA plan read not run, not produced, or not ready
- Result / Learning
There is no result. What 18 hours left behind is a skeleton in which "what will not go in" is fixed in code. The screen stays empty until sentences are reviewed, and the polyfill path CI used to hide now runs every time. The documents also say the next unit is 20 reviewed sentences, not a feature. This entry records a starting line, not a finish. Once the customer experiment (20 people, 14 days) has run, its numbers go here.
- Retrospective
- Ten documents, close to ten thousand characters, written in a day - and zero reviewed sentences. The roadmap already knows this product's bottleneck is content review, not code. The next thing touched should not be code.
- That the Temporal polyfill path was unverified in CI only surfaced in the last commit. Which environment "CI green" actually means should have been asked from the start.
- Tech stack
- React
- TypeScript
- Vite
- Vitest
- Playwright
- Temporal (@js-temporal/polyfill)
- Capacitor
- GitHub Actions