Date: 2026-07-07 Reviewed: PRD v1 (19 FRs, 5 UJs) vs Architecture Spine draft
All 19 FRs are explicitly mapped in the spine's Capability-to-Architecture table, each assigned to a source file and an architectural decision (or marked with no AD where none applies, e.g. solver). No FR is missing or orphaned.
| FR | Mapped? | Location | Notes |
|---|---|---|---|
| FR-1 | Yes | client/src/hooks/usePersistence.ts | AD-7 |
| FR-2 | Yes | client/src/screens/Screen1.tsx | AD-7 |
| FR-3 | Yes | client/src/components/Grid.tsx | AD-7 |
| FR-4 | Yes | client/src/components/Keyboard.tsx | AD-7 |
| FR-5 | Yes | client useGame → server guess.ts | AD-5, AD-6 |
| FR-6 | Yes | server/src/validate.ts | AD-5 |
| FR-7 | Yes | server/src/feedback.ts | AD-6 |
| FR-8 | Yes | client/src/hooks/useGame.ts | AD-7 |
| FR-9 | Yes | client/src/hooks/useGame.ts | AD-7 |
| FR-10 | Yes | server/src/daily-word.ts | AD-2 |
| FR-11 | Yes | server/src/routes/play-again.ts | AD-8 |
| FR-12 | Yes | client/src/hooks/useStats.ts | AD-7 |
| FR-13 | Yes | client/src/screens/Screen3.tsx | AD-7 |
| FR-14 | Yes | client/src/screens/Screen3.tsx | AD-7 |
| FR-15 | Yes | client/src/screens/Screen3.tsx | AD-7 |
| FR-16 | Yes | solver/src/ | (no AD; algorithm selection deferred) |
| FR-17 | Yes | solver/src/ → data/word-bank.json | AD-4 |
| FR-18 | Yes | data/word-bank.json | AD-4 |
| FR-19 | Yes | client/src/hooks/usePersistence.ts | AD-7 |
All 5 user journeys are realized through the FR mappings above. The three-screen flow (Screen1→Screen2→Screen3) is reflected in the source tree. No user journey falls through the cracks at the FR level.
PRD source: Vision ("Works on mobile and desktop via web browser"), MVP Scope section 6.1 ("Works on mobile and desktop via web browser").
Problem: The spine contains no architectural decision, convention, or structural element addressing responsive design. There is no viewport strategy, no breakpoint system, no mobile-first or desktop-first decision, and no mention of touch vs. pointer interaction handling. The on-screen keyboard (FR-4) partially addresses mobile input but says nothing about layout adaptation.
Risk: Without an architectural stance, mobile and desktop implementations may diverge or mobile may be an afterthought, directly violating an MVP scope commitment.
PRD source: MVP Scope section 6.1 ("Physical keyboard support"), FR-5 describes "physical keyboard or on-screen keyboard" input.
Problem: The spine maps FR-5 to client/src/hooks/useGame.ts and server/src/routes/guess.ts. The Keyboard.tsx component handles the on-screen keyboard, but physical keyboard events (keydown for letters, Enter to submit, Backspace to delete) have no designated architectural home. These are a distinct input modality with their own event handling lifecycle (document-level keydown listeners, focus management).
Risk: Physical keyboard support may be bolted on late without a clear ownership boundary, or may conflict with on-screen keyboard state management.
PRD source: User journeys describe Screen1→Screen2→Screen3 transitions. The PRD section 4.1 describes "Tapping Play navigates to Screen 2." Section 4.5 describes the Play Again button navigating back to Screen 2.
Problem: The spine lists client/src/screens/Screen1.tsx, Screen2.tsx, Screen3.tsx but makes no architectural decision about screen navigation: state-based conditional rendering vs. client-side router (React Router) vs. URL-driven. The transition triggers (Play button, game-over detection, Play Again button) are not architecturally placed.
Risk: Low. This is a three-screen app; any approach will work. However, if the team later adds screens (post-v1), an unstated routing approach may cause rework.
PRD source: JTBD ("clear, immediate feedback on every guess"), AD-6 states "Feedback scoring on server" and "The client only renders the colors it receives."
Problem: AD-6 mandates that feedback is computed server-side only. Every guess incurs a network round-trip before the player sees green/yellow/gray tiles. The PRD calls for "immediate" feedback. There is no architectural discussion of this tension: should the client also compute feedback locally for instant display (optimistic rendering, later confirmed by the server response), or is the latency budget acceptable? The decision is made (server-only) without acknowledging the UX trade-off.
Risk: If round-trip latency is perceptible (200ms+ on slow connections), the game will feel sluggish, undermining the "immediate feedback" JTBD and "quick, satisfying" feel. This is the most architecturally significant gap because AD-6 makes a binding decision that directly affects a stated UX quality.
PRD source: Implicit in the SPA architecture — the game should degrade gracefully or inform the user when the server is unreachable.
Problem: The spine has no architectural concern for network failure modes. What happens when POST /api/guess fails? Does the client retry? Show an error? The Consistency Conventions mention error shapes ({ error: string }) but only for validation errors (400) and not-found (404), not for connectivity failures.
Risk: Network failures produce an unhandled state in the UI. Given this is a hobby project, the risk is low, but the PRD's "clear, immediate feedback" JTBD implies reliability.
PRD source: Not explicitly stated in the PRD, but the game's core mechanic relies entirely on color discrimination (green/yellow/gray). This is a well-known accessibility issue with Wordle clones.
Problem: The spine contains no accessibility architecture: no ARIA conventions, no color-blind mode/alternative indicators (patterns, symbols, high-contrast mode), no keyboard navigation model, no screen-reader announcements for guess results.
Risk: The game will be inaccessible to color-blind users and screen-reader users. While the PRD does not mandate accessibility, it is a significant UX gap that the architecture should at minimum acknowledge as deferred rather than silently omit.
PRD source: UJ-1 climax: "the row confirms green, a brief celebration."
Problem: The spine maps win detection to client/src/hooks/useGame.ts and results display to Screen3.tsx, but there is no architectural concern for the celebration animation itself. Is it a CSS animation? A library? A component? The PRD explicitly calls for this UX moment.
Risk: Low. A celebration animation is a small UI detail. But the PRD explicitly names it as part of the user journey climax, and the architecture provides no home for it.
| Concern | PRD Source | Spine Coverage |
|---|---|---|
| "Quick, satisfying" feel | Vision, JTBD | Partial — stateless server supports simplicity, but no latency budget or optimistic UI (see GAP-4) |
| "Clear, immediate feedback" | JTBD | Partial — feedback scoring is defined (AD-6), but "immediate" is undermined by server-only computation (see GAP-4) |
| "Jump straight in without friction" | JTBD (returning player) | Covered — FR-1 cookie detection, no-loading-screen architecture implied by SPA |
| "Brief celebration" | UJ-1 climax | Not covered (see GAP-7) |
| Mobile + desktop parity | Vision, MVP Scope | Not covered (see GAP-1) |
| Learning-project simplicity | Vision, SM-C1 | Well-covered — AD-1 (stateless), AD-4 (no database), AD-9 (monorepo) all push toward simplicity |
| Color-blind accessibility | Implicit (green/yellow mechanic) | Not covered (see GAP-6) |
All 19 FRs and 5 UJs are explicitly mapped. The spine's strength is its thorough functional coverage. No requirement falls through at the FR level.
Seven gaps identified. Two are architecturally significant:
The remaining gaps (physical keyboard routing, screen navigation, network resilience, accessibility, celebration animation) are lower severity but worth acknowledging in the spine, even if only as deferred or implementation-detail notes.