Create a public-facing user guide page accessible before login, rendering the existing docs/USER-GUIDE.md content as an interactive single-page guide with screenshots captured from the live application.
Context
The user guide content is already written in docs/USER-GUIDE.md (955 lines, 10 major sections)
Currently no help/guide pages exist in the frontend -- only an old PDF at /public/docs/v2026-01-03.pdf
The public website has one page (/) with nav: Home | Features | About | Sign Up | Login
This feature adds a /guide public route and integrates into both public and authenticated navigation
Requirements
Page Structure
Single scrollable page with sticky table of contents sidebar
Render USER-GUIDE.md content as styled React components (not raw markdown)
Anchor links for each section matching the existing TOC structure
Responsive: TOC sidebar on desktop, collapsible TOC on mobile
Navigation Integration
Public nav bar: Add "Guide" link after "About", before "Sign Up" buttons
Desktop: Home | Features | About | Guide | Sign Up | Login
Mobile hamburger: Add Guide item
Authenticated sidebar: Add "Help" or "Guide" link in the sidebar nav
Mobile authenticated: Add to hamburger drawer menu
Screenshots
Capture ~15 key workflow screenshots using Chrome MCP tools from the live application
Key screens to capture:
Dashboard (fleet overview with vehicle cards)
Vehicles list page
Add Vehicle form (with VIN decode)
Vehicle Detail page
Fuel Log modal (add fuel form)
Fuel Logs list with summary stats
Maintenance Records tab
Maintenance Schedules tab
Gas Stations page (map + search)
Documents page
Settings page (profile, subscription, units)
Mobile bottom navigation + FAB
Mobile hamburger drawer
Onboarding flow
Login/signup pages
Store screenshots as optimized static assets
Both desktop (1920px) and mobile (375px) viewports where relevant
Content Mapping
Map USER-GUIDE.md sections to page sections:
Getting Started (account creation, login, onboarding)
Match existing MUI theme and color scheme (see docs/MVP-COLOR-SCHEME.md)
Professional documentation styling with clear typography hierarchy
Smooth scroll behavior for anchor navigation
Search/filter capability within the guide (optional enhancement)
Acceptance Criteria
/guide route accessible without authentication
Single page with sticky TOC sidebar (desktop) / collapsible TOC (mobile)
All 10 sections from USER-GUIDE.md rendered with screenshots
~15 key screenshots captured at desktop and mobile viewports
"Guide" link in public nav bar (between About and Sign Up)
"Guide" or "Help" link in authenticated sidebar and mobile hamburger menu
Responsive design: works on mobile (320px, 768px) and desktop (1920px)
Screenshots optimized for web (compressed, lazy-loaded)
Page loads quickly (no blocking resources)
Technical Notes
This is a multi-file feature (5+ files) -- will require sub-issue decomposition during planning
Screenshots will be captured using Chrome MCP browser automation tools
Consider using react-markdown or building custom section components from the guide content
Static screenshot assets should live in frontend/public/guide/ or similar
The old PDF at /public/docs/v2026-01-03.pdf can be removed after this feature ships
## Summary
Create a public-facing user guide page accessible before login, rendering the existing `docs/USER-GUIDE.md` content as an interactive single-page guide with screenshots captured from the live application.
## Context
- The user guide content is already written in `docs/USER-GUIDE.md` (955 lines, 10 major sections)
- Currently no help/guide pages exist in the frontend -- only an old PDF at `/public/docs/v2026-01-03.pdf`
- The public website has one page (`/`) with nav: Home | Features | About | Sign Up | Login
- This feature adds a `/guide` public route and integrates into both public and authenticated navigation
## Requirements
### Page Structure
- Single scrollable page with sticky table of contents sidebar
- Render USER-GUIDE.md content as styled React components (not raw markdown)
- Anchor links for each section matching the existing TOC structure
- Responsive: TOC sidebar on desktop, collapsible TOC on mobile
### Navigation Integration
- **Public nav bar**: Add "Guide" link after "About", before "Sign Up" buttons
- Desktop: Home | Features | About | **Guide** | Sign Up | Login
- Mobile hamburger: Add Guide item
- **Authenticated sidebar**: Add "Help" or "Guide" link in the sidebar nav
- **Mobile authenticated**: Add to hamburger drawer menu
### Screenshots
- Capture ~15 key workflow screenshots using Chrome MCP tools from the live application
- Key screens to capture:
- Dashboard (fleet overview with vehicle cards)
- Vehicles list page
- Add Vehicle form (with VIN decode)
- Vehicle Detail page
- Fuel Log modal (add fuel form)
- Fuel Logs list with summary stats
- Maintenance Records tab
- Maintenance Schedules tab
- Gas Stations page (map + search)
- Documents page
- Settings page (profile, subscription, units)
- Mobile bottom navigation + FAB
- Mobile hamburger drawer
- Onboarding flow
- Login/signup pages
- Store screenshots as optimized static assets
- Both desktop (1920px) and mobile (375px) viewports where relevant
### Content Mapping
Map USER-GUIDE.md sections to page sections:
1. Getting Started (account creation, login, onboarding)
2. Dashboard (fleet overview, quick actions)
3. Vehicles (CRUD, VIN decode, detail page)
4. Fuel Logs (logging, receipt scanning, editing)
5. Maintenance (records, schedules)
6. Gas Stations (search, saved, premium 93)
7. Documents (upload, types)
8. Settings (profile, security, subscription, units, import/export)
9. Subscription Tiers and Pro Features
10. Mobile Experience
### Design
- Match existing MUI theme and color scheme (see `docs/MVP-COLOR-SCHEME.md`)
- Professional documentation styling with clear typography hierarchy
- Smooth scroll behavior for anchor navigation
- Search/filter capability within the guide (optional enhancement)
## Acceptance Criteria
- [ ] `/guide` route accessible without authentication
- [ ] Single page with sticky TOC sidebar (desktop) / collapsible TOC (mobile)
- [ ] All 10 sections from USER-GUIDE.md rendered with screenshots
- [ ] ~15 key screenshots captured at desktop and mobile viewports
- [ ] "Guide" link in public nav bar (between About and Sign Up)
- [ ] "Guide" or "Help" link in authenticated sidebar and mobile hamburger menu
- [ ] Responsive design: works on mobile (320px, 768px) and desktop (1920px)
- [ ] Screenshots optimized for web (compressed, lazy-loaded)
- [ ] Page loads quickly (no blocking resources)
## Technical Notes
- This is a multi-file feature (5+ files) -- will require sub-issue decomposition during planning
- Screenshots will be captured using Chrome MCP browser automation tools
- Consider using `react-markdown` or building custom section components from the guide content
- Static screenshot assets should live in `frontend/public/guide/` or similar
- The old PDF at `/public/docs/v2026-01-03.pdf` can be removed after this feature ships
Add a public /guide route rendering docs/USER-GUIDE.md content as styled React components with interspersed screenshots captured from the live application. The guide page uses a sticky TOC sidebar on desktop and collapsible TOC on mobile, matching existing MUI + Tailwind patterns. Guide links are added to public navigation, authenticated sidebar, and mobile hamburger drawer. No new npm dependencies required.
Planning Context
Decision Log
Decision
Reasoning Chain
Custom React components over react-markdown
Issue requires "styled React components (not raw markdown)" -> react-markdown would add ~48KB runtime for static content -> every markdown element needs custom MUI override anyway, negating simplicity -> content must diverge from markdown for screenshots -> custom components provide full MUI/Tailwind/dark mode control natively
No new npm dependencies
Guide content is static (changes quarterly at most) -> react-markdown/remark/rehype ecosystem adds 15-20 transitive deps -> lazy-loaded page means zero impact on initial bundle -> custom components achieve same result with existing stack
Individual section component files
10 sections at ~150-250 lines JSX each -> single file would be 2000+ lines god object -> individual files follow default-conventions domain="file-creation" (clear module boundary) -> each section independently editable
GuideScreenshot shared component
~15+ screenshots across all sections -> consistent lazy loading, responsive sizing, WebP format -> shared component prevents duplicate img/loading logic -> supports both desktop and mobile viewport screenshots
GuideTable shared component
USER-GUIDE.md has 15+ GFM tables -> MUI Table boilerplate is verbose -> shared component takes headers/rows arrays -> consistent styling across all sections
Lazy-loaded /guide route
Follows existing App.tsx pattern (all routes use lazy()) -> guide content is substantial (~2000+ lines JSX total) -> zero impact on initial bundle -> Suspense boundary provides loading state
Guide link as window.location in mobile hamburger
HamburgerDrawer uses MobileScreen type tied to Zustand navigation store -> /guide is a public full-page route outside /garage/* shell -> adding to MobileScreen type would require handling in screen switcher -> simpler: direct URL navigation opens guide as full page
WebP screenshot format
Modern standard with ~30% smaller files vs PNG -> all major browsers support WebP -> aligns with default-conventions modernization
Touch targets >= 44px on TOC
Mobile TOC links serve as primary navigation -> default-conventions require >= 44px touch targets -> TOC items use py-3 (~48px effective height)
Rejected Alternatives
Alternative
Why Rejected
react-markdown library
+48KB gzipped runtime dependency for static content; requires remark-gfm + rehype-slug plugins; every element needs custom MUI component override, negating "simpler" benefit; content must diverge from markdown for screenshots; issue explicitly says "styled React components (not raw markdown)"
MDX build-time compilation
Adds build tooling complexity (MDX loader, remark plugins); content is static enough that JSX components serve same purpose without extra build step; no benefit over direct React components
Single monolithic guideContent.tsx
~2000+ lines of static content in one file; violates default-conventions god-object threshold; individual section files provide clear module boundaries and independent editability
Adding "Guide" to MobileScreen type
Would require modifying Zustand navigation store, screen-to-route mapping, and mobile screen switcher; /guide is a public route outside the authenticated /garage/* shell; window.location navigation is simpler and correct
Constraints and Assumptions
Mobile + desktop required: 320px, 768px, 1920px viewports (doc-derived: CLAUDE.md)
Touch targets >= 44px, no hover-only interactions (default-derived: default-conventions)
Dark mode support via existing ThemeProvider (doc-derived: ThemeContext.tsx pattern)
MUI + Tailwind styling patterns (doc-derived: CLAUDE.md)
Lazy loading for code splitting (doc-derived: App.tsx existing pattern)
No new npm dependencies (decision: custom React components)
Screenshot capture requires authenticated session in Chrome browser
Known Risks
Risk
Mitigation
Anchor
Content drift between USER-GUIDE.md and web guide over time
Accepted: guide content changes quarterly; web guide and markdown serve different audiences (web users vs GitHub readers); doc-sync skill can flag drift
N/A
Screenshot breakage if UI changes
Screenshots are static assets; standard practice is to recapture after major UI changes; lazy loading prevents broken images from blocking page
N/A
Large page size with ~15+ screenshots
Lazy loading with loading="lazy" attribute; WebP format reduces file sizes ~30%; images only load when scrolled into viewport
User visits /guide
|
v
App.tsx detects isGuideRoute
|
v
Lazy loads GuidePage chunk
|
v
GuidePage renders:
1. Navigation bar (public, same as HomePage)
2. TOC sidebar from section metadata
3. Content sections with screenshots
|
v
User clicks TOC link -> smooth scroll to section anchor
User clicks section screenshot -> full image view (future)
Why This Structure
Section files are individual components (not a monolithic data file) because each section is 150-250 lines of JSX content; a single file would exceed 2000 lines
Shared GuideScreenshot/GuideTable components prevent duplicate MUI Table and img boilerplate across 10 sections (each section has 1-3 tables and 1-2 screenshots)
The guide page has its own navigation bar (matching HomePage style) rather than reusing Layout.tsx sidebar, because it is a public page accessible without authentication
guideTypes.ts defines the section metadata interface separately from content, enabling the TOC to generate from metadata without importing full section content
Invariants
The /guide route MUST remain accessible without authentication (public page)
TOC anchor IDs must match section component IDs (e.g., id="getting-started" maps to TOC href="#getting-started")
All screenshots must use WebP format with loading="lazy" attribute
Guide page must include its own nav bar for public access (cannot rely on authenticated Layout)
Tradeoffs
Individual section files (18 new files) vs single content file: chose modularity over fewer files; each section is independently editable and stays under 300 lines; cost is more files in the directory tree
Static content approach vs dynamic markdown: chose zero-dependency static JSX; cost is manual content updates; benefit is full MUI/Tailwind control and zero runtime parsing
Milestones
Milestone 1: Guide page foundation and routing
Sub-issue: feat: Guide page foundation and routing (#203)
frontend/src/pages/GuidePage/sections/index.ts (NEW - placeholder exports)
frontend/src/App.tsx (MODIFY)
Requirements:
Create GuidePage component with responsive layout: sticky TOC sidebar on desktop (>= 768px), collapsible accordion TOC on mobile (< 768px)
Create GuideTableOfContents component that renders from section metadata array, supports smooth scroll to anchor links, and highlights active section on scroll
Create guideTypes.ts with GuideSection and GuideSubSection interfaces
Create GuideScreenshot component with lazy loading, responsive sizing, WebP support, alt text
Create GuideTable component that renders MUI Table from headers[] and rows[][] props
Add guide route render block with ThemeProvider and Suspense wrapper
Add /guide to mobile URL sync skip lists (lines 371, 383)
GuidePage includes its own public navigation bar matching HomePage style (Home | Features | About | Guide | Sign Up | Login)
Acceptance Criteria:
Visiting /guide renders the guide page shell with TOC and empty content area
TOC displays all 10 section titles with anchor links
Desktop: TOC is sticky sidebar on left, content scrolls on right
Mobile: TOC is collapsible accordion above content
Smooth scroll works when clicking TOC links
Active section highlights in TOC on scroll
Page accessible without authentication
Dark mode works via ThemeProvider
Navigation bar present with Guide link active/highlighted
Tests:
Skip: This milestone establishes the page shell with placeholder sections. Full component tests in Milestone 5 after all content and navigation integration is complete.
Code Changes:
Add lazy import in App.tsx after auth pages section:
Note: The Guide item uses as MobileScreen cast and the handleNavigate function will need a guard to handle the Guide case by navigating to /guide via window.location. Requires adding HelpOutlineRoundedIcon import.
M2 and M3 can execute in parallel after M1 completes.
M4 requires M2 and M3 (screenshot placement in section components).
M5 requires M4 (tests verify screenshot loading).
M6 is final documentation pass.
Verdict: AWAITING_REVIEW | Next: Plan review cycle (QR plan-completeness -> TW plan-scrub -> QR plan-code -> QR plan-docs)
## Plan: Online User Guide with Screenshots
**Phase**: Planning | **Agent**: Planner | **Status**: AWAITING_REVIEW
---
## Overview
Add a public `/guide` route rendering `docs/USER-GUIDE.md` content as styled React components with interspersed screenshots captured from the live application. The guide page uses a sticky TOC sidebar on desktop and collapsible TOC on mobile, matching existing MUI + Tailwind patterns. Guide links are added to public navigation, authenticated sidebar, and mobile hamburger drawer. No new npm dependencies required.
## Planning Context
### Decision Log
| Decision | Reasoning Chain |
|----------|----------------|
| Custom React components over react-markdown | Issue requires "styled React components (not raw markdown)" -> react-markdown would add ~48KB runtime for static content -> every markdown element needs custom MUI override anyway, negating simplicity -> content must diverge from markdown for screenshots -> custom components provide full MUI/Tailwind/dark mode control natively |
| No new npm dependencies | Guide content is static (changes quarterly at most) -> react-markdown/remark/rehype ecosystem adds 15-20 transitive deps -> lazy-loaded page means zero impact on initial bundle -> custom components achieve same result with existing stack |
| Individual section component files | 10 sections at ~150-250 lines JSX each -> single file would be 2000+ lines god object -> individual files follow default-conventions domain="file-creation" (clear module boundary) -> each section independently editable |
| GuideScreenshot shared component | ~15+ screenshots across all sections -> consistent lazy loading, responsive sizing, WebP format -> shared component prevents duplicate img/loading logic -> supports both desktop and mobile viewport screenshots |
| GuideTable shared component | USER-GUIDE.md has 15+ GFM tables -> MUI Table boilerplate is verbose -> shared component takes headers/rows arrays -> consistent styling across all sections |
| Lazy-loaded /guide route | Follows existing App.tsx pattern (all routes use lazy()) -> guide content is substantial (~2000+ lines JSX total) -> zero impact on initial bundle -> Suspense boundary provides loading state |
| Guide link as window.location in mobile hamburger | HamburgerDrawer uses MobileScreen type tied to Zustand navigation store -> /guide is a public full-page route outside /garage/* shell -> adding to MobileScreen type would require handling in screen switcher -> simpler: direct URL navigation opens guide as full page |
| WebP screenshot format | Modern standard with ~30% smaller files vs PNG -> all major browsers support WebP -> aligns with default-conventions modernization |
| Touch targets >= 44px on TOC | Mobile TOC links serve as primary navigation -> default-conventions require >= 44px touch targets -> TOC items use py-3 (~48px effective height) |
### Rejected Alternatives
| Alternative | Why Rejected |
|-------------|-------------|
| react-markdown library | +48KB gzipped runtime dependency for static content; requires remark-gfm + rehype-slug plugins; every element needs custom MUI component override, negating "simpler" benefit; content must diverge from markdown for screenshots; issue explicitly says "styled React components (not raw markdown)" |
| MDX build-time compilation | Adds build tooling complexity (MDX loader, remark plugins); content is static enough that JSX components serve same purpose without extra build step; no benefit over direct React components |
| Single monolithic guideContent.tsx | ~2000+ lines of static content in one file; violates default-conventions god-object threshold; individual section files provide clear module boundaries and independent editability |
| Adding "Guide" to MobileScreen type | Would require modifying Zustand navigation store, screen-to-route mapping, and mobile screen switcher; /guide is a public route outside the authenticated /garage/* shell; window.location navigation is simpler and correct |
### Constraints and Assumptions
- Mobile + desktop required: 320px, 768px, 1920px viewports (doc-derived: CLAUDE.md)
- Touch targets >= 44px, no hover-only interactions (default-derived: default-conventions)
- Dark mode support via existing ThemeProvider (doc-derived: ThemeContext.tsx pattern)
- MUI + Tailwind styling patterns (doc-derived: CLAUDE.md)
- Lazy loading for code splitting (doc-derived: App.tsx existing pattern)
- No new npm dependencies (decision: custom React components)
- Screenshot capture requires authenticated session in Chrome browser
### Known Risks
| Risk | Mitigation | Anchor |
|------|-----------|--------|
| Content drift between USER-GUIDE.md and web guide over time | Accepted: guide content changes quarterly; web guide and markdown serve different audiences (web users vs GitHub readers); doc-sync skill can flag drift | N/A |
| Screenshot breakage if UI changes | Screenshots are static assets; standard practice is to recapture after major UI changes; lazy loading prevents broken images from blocking page | N/A |
| Large page size with ~15+ screenshots | Lazy loading with loading="lazy" attribute; WebP format reduces file sizes ~30%; images only load when scrolled into viewport | N/A |
## Invisible Knowledge
### Architecture
```
/guide (public, lazy-loaded)
|
v
GuidePage.tsx
├── GuideTableOfContents.tsx
│ ├── Desktop: sticky sidebar (position: sticky, top: 80px)
│ └── Mobile: collapsible accordion (MUI Accordion)
│
└── Scrollable Content Area
└── Section Components (10)
├── GettingStartedSection.tsx
├── DashboardSection.tsx
├── VehiclesSection.tsx
├── FuelLogsSection.tsx
├── MaintenanceSection.tsx
├── GasStationsSection.tsx
├── DocumentsSection.tsx
├── SettingsSection.tsx
├── SubscriptionSection.tsx
└── MobileExperienceSection.tsx
Shared Components:
├── GuideScreenshot.tsx (lazy img with WebP, responsive, alt text)
└── GuideTable.tsx (MUI Table from headers/rows arrays)
```
### Data Flow
```
User visits /guide
|
v
App.tsx detects isGuideRoute
|
v
Lazy loads GuidePage chunk
|
v
GuidePage renders:
1. Navigation bar (public, same as HomePage)
2. TOC sidebar from section metadata
3. Content sections with screenshots
|
v
User clicks TOC link -> smooth scroll to section anchor
User clicks section screenshot -> full image view (future)
```
### Why This Structure
- Section files are individual components (not a monolithic data file) because each section is 150-250 lines of JSX content; a single file would exceed 2000 lines
- Shared GuideScreenshot/GuideTable components prevent duplicate MUI Table and img boilerplate across 10 sections (each section has 1-3 tables and 1-2 screenshots)
- The guide page has its own navigation bar (matching HomePage style) rather than reusing Layout.tsx sidebar, because it is a public page accessible without authentication
- guideTypes.ts defines the section metadata interface separately from content, enabling the TOC to generate from metadata without importing full section content
### Invariants
- The /guide route MUST remain accessible without authentication (public page)
- TOC anchor IDs must match section component IDs (e.g., id="getting-started" maps to TOC href="#getting-started")
- All screenshots must use WebP format with loading="lazy" attribute
- Guide page must include its own nav bar for public access (cannot rely on authenticated Layout)
### Tradeoffs
- Individual section files (18 new files) vs single content file: chose modularity over fewer files; each section is independently editable and stays under 300 lines; cost is more files in the directory tree
- Static content approach vs dynamic markdown: chose zero-dependency static JSX; cost is manual content updates; benefit is full MUI/Tailwind control and zero runtime parsing
## Milestones
### Milestone 1: Guide page foundation and routing
**Sub-issue**: feat: Guide page foundation and routing (#203)
**Files**:
- `frontend/src/pages/GuidePage/GuidePage.tsx` (NEW)
- `frontend/src/pages/GuidePage/GuideTableOfContents.tsx` (NEW)
- `frontend/src/pages/GuidePage/guideTypes.ts` (NEW)
- `frontend/src/pages/GuidePage/components/GuideScreenshot.tsx` (NEW)
- `frontend/src/pages/GuidePage/components/GuideTable.tsx` (NEW)
- `frontend/src/pages/GuidePage/sections/index.ts` (NEW - placeholder exports)
- `frontend/src/App.tsx` (MODIFY)
**Requirements**:
- Create GuidePage component with responsive layout: sticky TOC sidebar on desktop (>= 768px), collapsible accordion TOC on mobile (< 768px)
- Create GuideTableOfContents component that renders from section metadata array, supports smooth scroll to anchor links, and highlights active section on scroll
- Create guideTypes.ts with GuideSection and GuideSubSection interfaces
- Create GuideScreenshot component with lazy loading, responsive sizing, WebP support, alt text
- Create GuideTable component that renders MUI Table from headers[] and rows[][] props
- Add lazy import for GuidePage in App.tsx
- Add `/guide` route detection: `isGuideRoute = location.pathname === '/guide'`
- Update `shouldShowHomePage` to exclude guide route
- Add guide route render block with ThemeProvider and Suspense wrapper
- Add `/guide` to mobile URL sync skip lists (lines 371, 383)
- GuidePage includes its own public navigation bar matching HomePage style (Home | Features | About | Guide | Sign Up | Login)
**Acceptance Criteria**:
- Visiting /guide renders the guide page shell with TOC and empty content area
- TOC displays all 10 section titles with anchor links
- Desktop: TOC is sticky sidebar on left, content scrolls on right
- Mobile: TOC is collapsible accordion above content
- Smooth scroll works when clicking TOC links
- Active section highlights in TOC on scroll
- Page accessible without authentication
- Dark mode works via ThemeProvider
- Navigation bar present with Guide link active/highlighted
**Tests**:
- Skip: This milestone establishes the page shell with placeholder sections. Full component tests in Milestone 5 after all content and navigation integration is complete.
**Code Changes**:
Add lazy import in App.tsx after auth pages section:
```diff
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -50,6 +50,9 @@
// Auth pages (lazy-loaded)
const SignupPage = lazy(() => import('./features/auth/pages/SignupPage').then(m => ({ default: m.SignupPage })));
const VerifyEmailPage = lazy(() => import('./features/auth/pages/VerifyEmailPage').then(m => ({ default: m.VerifyEmailPage })));
+
+// Public pages (lazy-loaded)
+const GuidePage = lazy(() => import('./pages/GuidePage/GuidePage').then(m => ({ default: m.GuidePage })));
const CallbackPage = lazy(() => import('./features/auth/pages/CallbackPage').then(m => ({ default: m.CallbackPage })));
```
Add /guide to mobile URL sync skip lists:
```diff
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -369,7 +369,7 @@
useEffect(() => {
const path = window.location.pathname;
- if (path === '/callback' || path === '/signup' || path === '/verify-email') return;
+ if (path === '/callback' || path === '/signup' || path === '/verify-email' || path === '/guide') return;
const screen = routeToScreen[path];
if (screen && screen !== activeScreen) {
```
```diff
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -381,7 +381,7 @@
useEffect(() => {
const path = window.location.pathname;
- if (path === '/callback' || path === '/signup' || path === '/verify-email') return;
+ if (path === '/callback' || path === '/signup' || path === '/verify-email' || path === '/guide') return;
const targetPath = screenToRoute[activeScreen];
```
Add guide route detection and render block:
```diff
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -497,8 +497,10 @@
const isSignupRoute = location.pathname === '/signup';
const isVerifyEmailRoute = location.pathname === '/verify-email';
const isOnboardingRoute = location.pathname === '/onboarding';
+ const isGuideRoute = location.pathname === '/guide';
const isAuthRoute = isSignupRoute || isVerifyEmailRoute || isOnboardingRoute;
- const shouldShowHomePage = !isGarageRoute && !isCallbackRoute && !isAuthRoute;
+ const shouldShowHomePage = !isGarageRoute && !isCallbackRoute && !isAuthRoute && !isGuideRoute;
```
```diff
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -629,6 +629,20 @@
if (shouldShowHomePage) {
return (
<ThemeProvider>
<HomePage />
<DebugInfo />
</ThemeProvider>
);
}
+ if (isGuideRoute) {
+ return (
+ <ThemeProvider>
+ <React.Suspense fallback={
+ <div className="flex items-center justify-center min-h-screen">
+ <div className="text-lg">Loading guide...</div>
+ </div>
+ }>
+ <GuidePage />
+ </React.Suspense>
+ <DebugInfo />
+ </ThemeProvider>
+ );
+ }
+
// Signup route is public - no authentication required
if (isSignupRoute) {
```
---
### Milestone 2: Guide content sections 1-5
**Sub-issue**: feat: Guide content sections 1-5 (#203)
**Files**:
- `frontend/src/pages/GuidePage/sections/GettingStartedSection.tsx` (NEW)
- `frontend/src/pages/GuidePage/sections/DashboardSection.tsx` (NEW)
- `frontend/src/pages/GuidePage/sections/VehiclesSection.tsx` (NEW)
- `frontend/src/pages/GuidePage/sections/FuelLogsSection.tsx` (NEW)
- `frontend/src/pages/GuidePage/sections/MaintenanceSection.tsx` (NEW)
- `frontend/src/pages/GuidePage/sections/index.ts` (MODIFY - add real exports)
**Requirements**:
- Convert USER-GUIDE.md sections 1-5 content into styled React components using MUI Typography, GuideTable, GuideScreenshot
- Each section component receives its section ID as prop for anchor targeting
- Getting Started: account creation form fields table, login flow, onboarding steps, troubleshooting
- Dashboard: fleet overview, vehicle cards description, quick actions table, navigation sidebar table
- Vehicles: viewing/search, add vehicle form sections, VIN decode, vehicle detail page, edit/delete
- Fuel Logs: overview, logging modal, receipt scanning, edit/delete
- Maintenance: records table, adding records, schedules, creating schedules
- Screenshot placeholders (src paths defined, actual images added in M4)
- Dark mode compatible styling using Tailwind dark: prefixes and MUI theme
**Acceptance Criteria**:
- All 5 sections render with correct headings, paragraphs, tables, and lists
- Section anchors match TOC links (smooth scroll works)
- Tables render with MUI Table component (sortable headers, consistent padding)
- Screenshot placeholders show alt text when images not yet present
- Content matches USER-GUIDE.md sections 1-5 (styled, not raw markdown)
- Responsive layout: content readable at 320px, 768px, 1920px
**Tests**:
- Skip: Content sections are static JSX with no logic. Component rendering tests in Milestone 5 verify sections render.
---
### Milestone 3: Guide content sections 6-10
**Sub-issue**: feat: Guide content sections 6-10 (#203)
**Files**:
- `frontend/src/pages/GuidePage/sections/GasStationsSection.tsx` (NEW)
- `frontend/src/pages/GuidePage/sections/DocumentsSection.tsx` (NEW)
- `frontend/src/pages/GuidePage/sections/SettingsSection.tsx` (NEW)
- `frontend/src/pages/GuidePage/sections/SubscriptionSection.tsx` (NEW)
- `frontend/src/pages/GuidePage/sections/MobileExperienceSection.tsx` (NEW)
- `frontend/src/pages/GuidePage/sections/index.ts` (MODIFY - add remaining exports)
**Requirements**:
- Convert USER-GUIDE.md sections 6-10 content into styled React components
- Gas Stations: finding stations, saved stations, Premium 93 description
- Documents: overview, adding documents, document types table
- Settings: profile, security/privacy, subscription, notifications, appearance/units, import/export, account actions
- Subscription Tiers: tier comparison table (Free vs Pro), VIN scanning, receipt scanning, maintenance scanning, PDF extraction, email ingestion, shared documents, community stations, managing subscription
- Mobile Experience: bottom navigation, hamburger menu, FAB quick actions, swipe gestures
- Screenshot placeholders defined for each section
**Acceptance Criteria**:
- All 5 sections render with correct headings, paragraphs, tables, and lists
- Section anchors match TOC links
- Subscription tier comparison table renders correctly with Free/Pro columns
- Settings section covers all 7 subsections from USER-GUIDE.md
- Content matches USER-GUIDE.md sections 6-10
- Responsive at all breakpoints
**Tests**:
- Skip: Static content sections. Component rendering tests in Milestone 5.
---
### Milestone 4: Screenshot capture and integration
**Sub-issue**: feat: Guide screenshot capture and integration (#203)
**Files**:
- `frontend/public/guide/` (NEW directory)
- `frontend/public/guide/*.webp` (NEW - ~15-20 screenshot files)
- `frontend/src/pages/GuidePage/sections/*.tsx` (MODIFY - update screenshot src paths)
**Requirements**:
- Capture ~15 key workflow screenshots using Chrome MCP browser automation tools
- Desktop screenshots at 1920px viewport width:
- Dashboard with vehicle cards
- Vehicles list page
- Add Vehicle form (with VIN decode section visible)
- Vehicle Detail page
- Fuel Log modal (add fuel form)
- Fuel Logs list with summary stats
- Maintenance Records tab
- Maintenance Schedules tab
- Gas Stations page (map + search)
- Documents page
- Settings page (profile section)
- Login page
- Signup page
- Onboarding flow
- Mobile screenshots at 375px viewport where relevant:
- Dashboard mobile view
- Mobile bottom navigation + FAB
- Mobile hamburger drawer
- Optimize all screenshots as WebP format
- Store in `frontend/public/guide/` with descriptive filenames (e.g., `dashboard-desktop.webp`, `vehicles-list-desktop.webp`)
- Update section components to reference actual screenshot paths
**Acceptance Criteria**:
- ~15-20 WebP screenshot files in `frontend/public/guide/`
- Each screenshot is clear, properly cropped, and shows the relevant feature
- Desktop screenshots captured at 1920px width
- Mobile screenshots captured at 375px width
- All GuideScreenshot components in section files reference valid image paths
- Images lazy-load when scrolled into viewport
- Total guide image payload under 5MB (WebP compression)
**Tests**:
- Skip: Asset-only milestone. Screenshot presence verified by visual inspection. GuideScreenshot component loading behavior tested in Milestone 5.
---
### Milestone 5: Navigation integration, tests, and cleanup
**Sub-issue**: feat: Guide navigation integration and tests (#203)
**Files**:
- `frontend/src/pages/HomePage.tsx` (MODIFY)
- `frontend/src/components/Layout.tsx` (MODIFY)
- `frontend/src/shared-minimal/components/mobile/HamburgerDrawer.tsx` (MODIFY)
- `frontend/src/pages/__tests__/GuidePage.test.tsx` (NEW)
- `frontend/public/docs/v2026-01-03.pdf` (DELETE)
**Requirements**:
- Add "Guide" link to public nav bar in HomePage.tsx between About and Sign Up (desktop + mobile)
- Add "Guide" link to authenticated sidebar in Layout.tsx navigation array
- Add "Guide" link to mobile HamburgerDrawer.tsx menu items
- Write component tests for GuidePage: route rendering, TOC presence, section rendering, navigation links
- Remove old PDF at `frontend/public/docs/v2026-01-03.pdf`
**Acceptance Criteria**:
- Public nav (desktop): Home | Features | About | **Guide** | Sign Up | Login
- Public nav (mobile hamburger): Guide link present in dropdown
- Authenticated sidebar: Guide link with help/book icon appears after Settings
- Mobile hamburger drawer: Guide link present in menu
- Guide links navigate to /guide
- Old PDF removed
- All component tests pass
**Tests**:
- **Test files**: `frontend/src/pages/__tests__/GuidePage.test.tsx`
- **Test type**: integration (component rendering with Testing Library)
- **Backing**: doc-derived (docs/TESTING.md, frontend/jest.config.ts)
- **Scenarios**:
- Normal: GuidePage renders with TOC and all 10 section headings visible
- Normal: TOC contains correct anchor links for all sections
- Normal: /guide route accessible (renders GuidePage component)
- Edge: Mobile viewport renders collapsible TOC instead of sidebar
- Edge: GuideScreenshot renders with loading="lazy" attribute
**Code Changes**:
Add Guide link to HomePage desktop nav (between About and Sign Up):
```diff
--- a/frontend/src/pages/HomePage.tsx
+++ b/frontend/src/pages/HomePage.tsx
@@ -89,6 +89,12 @@
<a href="#about" className="text-white/75 hover:text-white transition-colors">
About
</a>
+ <a
+ href="/guide"
+ className="text-white/75 hover:text-white transition-colors"
+ >
+ Guide
+ </a>
<button
onClick={handleSignup}
className="border border-primary-500/90 text-primary-500 hover:bg-primary-500/10 hover:border-primary-500 font-semibold py-2 px-6 rounded-lg transition-colors duration-300 focus:outline-none focus:ring-2 focus:ring-primary-500/50"
```
Add Guide link to HomePage mobile menu (between About and Sign Up):
```diff
--- a/frontend/src/pages/HomePage.tsx
+++ b/frontend/src/pages/HomePage.tsx
@@ -157,6 +157,12 @@
<a
href="#about"
className="block text-white/75 hover:text-white transition-colors py-2"
>
About
</a>
+ <a
+ href="/guide"
+ className="block text-white/75 hover:text-white transition-colors py-2"
+ >
+ Guide
+ </a>
<button
onClick={handleSignup}
className="w-full border border-primary-500/90 text-primary-500 hover:bg-primary-500/10 font-semibold py-2 px-6 rounded-lg transition-colors duration-300 focus:outline-none focus:ring-2 focus:ring-primary-500/50"
```
Add Guide link to authenticated sidebar in Layout.tsx:
```diff
--- a/frontend/src/components/Layout.tsx
+++ b/frontend/src/components/Layout.tsx
@@ -52,6 +52,7 @@
{ name: 'Documents', href: '/garage/documents', icon: <DescriptionRoundedIcon sx={{ fontSize: 20 }} /> },
{ name: 'Settings', href: '/garage/settings', icon: <SettingsRoundedIcon sx={{ fontSize: 20 }} /> },
+ { name: 'Guide', href: '/guide', icon: <HelpOutlineRoundedIcon sx={{ fontSize: 20 }} /> },
];
```
Note: Requires adding `HelpOutlineRoundedIcon` import at top of Layout.tsx:
```diff
--- a/frontend/src/components/Layout.tsx
+++ b/frontend/src/components/Layout.tsx
@@ -16,6 +16,7 @@
import DescriptionRoundedIcon from '@mui/icons-material/DescriptionRounded';
import MenuIcon from '@mui/icons-material/Menu';
+import HelpOutlineRoundedIcon from '@mui/icons-material/HelpOutlineRounded';
import ChevronLeftRoundedIcon from '@mui/icons-material/ChevronLeftRounded';
```
Add Guide link to HamburgerDrawer.tsx:
```diff
--- a/frontend/src/shared-minimal/components/mobile/HamburgerDrawer.tsx
+++ b/frontend/src/shared-minimal/components/mobile/HamburgerDrawer.tsx
@@ -42,6 +42,7 @@
const menuItems: MenuItem[] = [
{ screen: 'Settings', label: 'Settings', icon: <SettingsRoundedIcon /> },
+ { screen: 'Guide' as MobileScreen, label: 'Guide', icon: <HelpOutlineRoundedIcon /> },
{ screen: 'Documents', label: 'Documents', icon: <DescriptionRoundedIcon /> },
```
Note: The Guide item uses `as MobileScreen` cast and the handleNavigate function will need a guard to handle the Guide case by navigating to /guide via window.location. Requires adding `HelpOutlineRoundedIcon` import.
---
### Milestone 6: Documentation
**Sub-issue**: docs: Guide page documentation (#203)
**Files**:
- `frontend/src/pages/CLAUDE.md` (MODIFY or CREATE)
- `frontend/src/pages/GuidePage/CLAUDE.md` (NEW)
**Requirements**:
- Create CLAUDE.md index for GuidePage directory with file listings and when-to-read
- Update parent pages/ CLAUDE.md if it exists to reference GuidePage
- Document architecture: section component pattern, shared components, public route handling
**Acceptance Criteria**:
- CLAUDE.md enables LLM to locate relevant guide page code for modification tasks
- Architecture documented: section structure, shared components, screenshot management
- New team member can understand guide page organization from reading CLAUDE.md
**Source Material**: Invisible Knowledge section of this plan
## Milestone Dependencies
```
M1 (Foundation) ---> M2 (Sections 1-5) ---> M4 (Screenshots)
\ /
--> M3 (Sections 6-10) --/
\
--> M5 (Nav + Tests) --> M6 (Docs)
```
M2 and M3 can execute in parallel after M1 completes.
M4 requires M2 and M3 (screenshot placement in section components).
M5 requires M4 (tests verify screenshot loading).
M6 is final documentation pass.
---
*Verdict*: AWAITING_REVIEW | *Next*: Plan review cycle (QR plan-completeness -> TW plan-scrub -> QR plan-code -> QR plan-docs)
Location: Planning Context > Decision Log > "Guide link as window.location in mobile hamburger"
Issue: Decision states HamburgerDrawer uses window.location but reasoning chain is incomplete. Entry explains WHAT (window.location navigation) but doesn't chain through HOW this will be implemented given MobileScreen type constraint.
Gap: M5 Code Changes shows { screen: 'Guide' as MobileScreen, label: 'Guide', icon: ... } with cast and mentions "handleNavigate function will need a guard" but Decision Log doesn't explain this guard implementation decision. The reasoning stops at "simpler: direct URL navigation" without explaining the guard pattern.
Suggested Fix: Expand Decision Log entry to include: "HamburgerDrawer handleNavigate guard checks for 'Guide' screen -> calls window.location.href = '/guide' -> bypasses Zustand navigation store -> maintains separation between public /guide route and authenticated /garage/* shell"
[PLAN] SHOULD_FIX: Missing screenshot count validation in Milestone 4
Location: Milestone 4 > Acceptance Criteria
Issue: Issue requirement specifies "~15 key screenshots" but M4 lists 14 specific desktop screenshots + 3 mobile screenshots = 17 total. Acceptance criteria says "~15-20 WebP screenshot files" which is correct but doesn't reconcile the specific list with the issue's "~15" estimate.
Gap: No explicit verification that the 17 planned screenshots align with the "~15 key screens to capture" list in the issue body (15 items). The plan lists 17 but issue listed 15 - are 2 extra, or did planner interpret "~15" as approximate?
Suggested Fix: Add note in M4 requirements explaining: "Issue lists ~15 key screens; plan captures 17 (14 desktop + 3 mobile-specific) to ensure comprehensive coverage of all 10 guide sections"
[PLAN] SUGGESTION: Milestone dependency graph could clarify M4 screenshot placement
Location: Milestone Dependencies section
Issue: Dependency graph shows "M4 requires M2 and M3 (screenshot placement in section components)" but M4 doesn't actually MODIFY M2/M3 section files - it only creates the WebP assets and then updates src paths.
Clarity: The note "M4 requires M2 and M3 (screenshot placement in section components)" is technically correct but could be clearer. M4 modifies the section files created in M2/M3 to update placeholder src paths to real paths.
Suggested Enhancement: Revise dependency note to: "M4 requires M2 and M3 (updates screenshot src paths in section components from placeholders to actual /guide/*.webp assets)"
Considered But Not Flagged
All 9 acceptance criteria from issue are covered: Each maps to specific milestones with testable criteria
/guide route accessible without authentication: M1 adds public route handling in App.tsx (isGuideRoute, ThemeProvider wrapper, no auth check)
Sticky TOC sidebar (desktop) / collapsible TOC (mobile): M1 requirements specify "sticky TOC sidebar on desktop (>= 768px), collapsible accordion TOC on mobile (< 768px)"
All 10 sections from USER-GUIDE.md rendered: M2 covers sections 1-5, M3 covers sections 6-10, all section names match USER-GUIDE.md headings
~15 key screenshots: M4 captures 17 screenshots (see SHOULD_FIX above for count reconciliation)
"Guide" link in public nav bar: M5 adds link between About and Sign Up in HomePage.tsx desktop + mobile nav
"Guide" or "Help" link in authenticated sidebar and mobile hamburger: M5 adds to Layout.tsx navigation array and HamburgerDrawer.tsx menu items
Responsive design (320px, 768px, 1920px): M1 acceptance criteria include "Desktop: TOC is sticky sidebar on left" and "Mobile: TOC is collapsible accordion", M2 and M3 acceptance criteria both include "Responsive at all breakpoints"
Screenshots optimized for web: M4 specifies WebP format with lazy loading, acceptance criteria include "Total guide image payload under 5MB (WebP compression)"
Page loads quickly: M1 uses lazy loading for route (const GuidePage = lazy(...)), M4 uses lazy loading for images (loading="lazy" attribute in GuideScreenshot component)
File paths are exact: All milestones use precise paths (e.g., frontend/src/pages/GuidePage/GuidePage.tsx, not "guide files")
Dependencies correctly mapped: Dependency graph shows no circular dependencies, correct order (M1 foundation -> M2/M3 content in parallel -> M4 screenshots -> M5 nav/tests -> M6 docs)
Decision Log has multi-step reasoning: 9 decisions with chain reasoning (e.g., "Custom React components over react-markdown" shows 5-step chain from issue requirement through runtime cost to conclusion)
Rejected alternatives have concrete reasons: 4 alternatives with specific reasons (e.g., react-markdown rejected due to "+48KB gzipped runtime dependency" and "every element needs custom MUI component override")
Known Risks have mitigations: 3 risks with mitigations (all marked "Accepted" with rationale, no code behavior claims requiring anchors)
Tests specified with type, backing, scenarios: M1 skips tests with explicit reason (placeholder shell, full tests in M5), M5 includes integration tests with type, backing, and 5 scenarios (2 normal, 3 edge)
Diff format used appropriately: M1 and M5 use diff blocks for App.tsx route detection and navigation link additions (conditionals, multiple insertions) - correct per diff-format.md boundary test
Touch targets >= 44px: Decision Log includes "Touch targets >= 44px on TOC" with reasoning (mobile TOC links are primary navigation -> default-conventions require >= 44px -> TOC items use py-3 ~48px)
Dark mode support: Constraints list "Dark mode support via existing ThemeProvider (doc-derived: ThemeContext.tsx pattern)", M2 requirements include "Dark mode compatible styling using Tailwind dark: prefixes and MUI theme"
No missing milestones: M1 foundation, M2/M3 content (10 sections), M4 screenshots (~15-20 assets), M5 navigation integration + tests, M6 documentation - complete flow from route to content to assets to integration
Verdict
PASS_WITH_CONCERNS
The plan is comprehensive and covers all acceptance criteria with specific, testable milestones. The 3 findings are quality improvements (1 incomplete reasoning chain, 1 missing count validation note, 1 clarity enhancement) rather than blocking gaps.
Recommended action: Address SHOULD_FIX findings to strengthen Decision Log completeness and milestone acceptance criteria clarity, then proceed to TW plan-scrub phase.
Next: Technical Writer plan-scrub review
## QR Review: Plan Completeness
**Phase**: Plan-Review | **Agent**: Quality Reviewer | **Status**: PASS_WITH_CONCERNS
### Findings
#### [PLAN] SHOULD_FIX: Decision Log lacks HamburgerDrawer navigation implementation multi-step reasoning
- **Location**: Planning Context > Decision Log > "Guide link as window.location in mobile hamburger"
- **Issue**: Decision states HamburgerDrawer uses window.location but reasoning chain is incomplete. Entry explains WHAT (window.location navigation) but doesn't chain through HOW this will be implemented given MobileScreen type constraint.
- **Gap**: M5 Code Changes shows `{ screen: 'Guide' as MobileScreen, label: 'Guide', icon: ... }` with cast and mentions "handleNavigate function will need a guard" but Decision Log doesn't explain this guard implementation decision. The reasoning stops at "simpler: direct URL navigation" without explaining the guard pattern.
- **Suggested Fix**: Expand Decision Log entry to include: "HamburgerDrawer handleNavigate guard checks for 'Guide' screen -> calls window.location.href = '/guide' -> bypasses Zustand navigation store -> maintains separation between public /guide route and authenticated /garage/* shell"
#### [PLAN] SHOULD_FIX: Missing screenshot count validation in Milestone 4
- **Location**: Milestone 4 > Acceptance Criteria
- **Issue**: Issue requirement specifies "~15 key screenshots" but M4 lists 14 specific desktop screenshots + 3 mobile screenshots = 17 total. Acceptance criteria says "~15-20 WebP screenshot files" which is correct but doesn't reconcile the specific list with the issue's "~15" estimate.
- **Gap**: No explicit verification that the 17 planned screenshots align with the "~15 key screens to capture" list in the issue body (15 items). The plan lists 17 but issue listed 15 - are 2 extra, or did planner interpret "~15" as approximate?
- **Suggested Fix**: Add note in M4 requirements explaining: "Issue lists ~15 key screens; plan captures 17 (14 desktop + 3 mobile-specific) to ensure comprehensive coverage of all 10 guide sections"
#### [PLAN] SUGGESTION: Milestone dependency graph could clarify M4 screenshot placement
- **Location**: Milestone Dependencies section
- **Issue**: Dependency graph shows "M4 requires M2 and M3 (screenshot placement in section components)" but M4 doesn't actually MODIFY M2/M3 section files - it only creates the WebP assets and then updates src paths.
- **Clarity**: The note "M4 requires M2 and M3 (screenshot placement in section components)" is technically correct but could be clearer. M4 modifies the section files created in M2/M3 to update placeholder src paths to real paths.
- **Suggested Enhancement**: Revise dependency note to: "M4 requires M2 and M3 (updates screenshot src paths in section components from placeholders to actual /guide/*.webp assets)"
### Considered But Not Flagged
- **All 9 acceptance criteria from issue are covered**: Each maps to specific milestones with testable criteria
- **/guide route accessible without authentication**: M1 adds public route handling in App.tsx (isGuideRoute, ThemeProvider wrapper, no auth check)
- **Sticky TOC sidebar (desktop) / collapsible TOC (mobile)**: M1 requirements specify "sticky TOC sidebar on desktop (>= 768px), collapsible accordion TOC on mobile (< 768px)"
- **All 10 sections from USER-GUIDE.md rendered**: M2 covers sections 1-5, M3 covers sections 6-10, all section names match USER-GUIDE.md headings
- **~15 key screenshots**: M4 captures 17 screenshots (see SHOULD_FIX above for count reconciliation)
- **"Guide" link in public nav bar**: M5 adds link between About and Sign Up in HomePage.tsx desktop + mobile nav
- **"Guide" or "Help" link in authenticated sidebar and mobile hamburger**: M5 adds to Layout.tsx navigation array and HamburgerDrawer.tsx menu items
- **Responsive design (320px, 768px, 1920px)**: M1 acceptance criteria include "Desktop: TOC is sticky sidebar on left" and "Mobile: TOC is collapsible accordion", M2 and M3 acceptance criteria both include "Responsive at all breakpoints"
- **Screenshots optimized for web**: M4 specifies WebP format with lazy loading, acceptance criteria include "Total guide image payload under 5MB (WebP compression)"
- **Page loads quickly**: M1 uses lazy loading for route (`const GuidePage = lazy(...)`), M4 uses lazy loading for images (`loading="lazy"` attribute in GuideScreenshot component)
- **File paths are exact**: All milestones use precise paths (e.g., `frontend/src/pages/GuidePage/GuidePage.tsx`, not "guide files")
- **Dependencies correctly mapped**: Dependency graph shows no circular dependencies, correct order (M1 foundation -> M2/M3 content in parallel -> M4 screenshots -> M5 nav/tests -> M6 docs)
- **Decision Log has multi-step reasoning**: 9 decisions with chain reasoning (e.g., "Custom React components over react-markdown" shows 5-step chain from issue requirement through runtime cost to conclusion)
- **Rejected alternatives have concrete reasons**: 4 alternatives with specific reasons (e.g., react-markdown rejected due to "+48KB gzipped runtime dependency" and "every element needs custom MUI component override")
- **Known Risks have mitigations**: 3 risks with mitigations (all marked "Accepted" with rationale, no code behavior claims requiring anchors)
- **Tests specified with type, backing, scenarios**: M1 skips tests with explicit reason (placeholder shell, full tests in M5), M5 includes integration tests with type, backing, and 5 scenarios (2 normal, 3 edge)
- **Diff format used appropriately**: M1 and M5 use diff blocks for App.tsx route detection and navigation link additions (conditionals, multiple insertions) - correct per diff-format.md boundary test
- **GuideScreenshot shared component prevents duplication**: Decision Log entry for "GuideScreenshot shared component" shows multi-step reasoning (15+ screenshots -> consistent lazy loading/responsive sizing -> shared component prevents duplicate img/loading logic)
- **Touch targets >= 44px**: Decision Log includes "Touch targets >= 44px on TOC" with reasoning (mobile TOC links are primary navigation -> default-conventions require >= 44px -> TOC items use py-3 ~48px)
- **Dark mode support**: Constraints list "Dark mode support via existing ThemeProvider (doc-derived: ThemeContext.tsx pattern)", M2 requirements include "Dark mode compatible styling using Tailwind dark: prefixes and MUI theme"
- **No missing milestones**: M1 foundation, M2/M3 content (10 sections), M4 screenshots (~15-20 assets), M5 navigation integration + tests, M6 documentation - complete flow from route to content to assets to integration
### Verdict
**PASS_WITH_CONCERNS**
The plan is comprehensive and covers all acceptance criteria with specific, testable milestones. The 3 findings are quality improvements (1 incomplete reasoning chain, 1 missing count validation note, 1 clarity enhancement) rather than blocking gaps.
**Recommended action**: Address SHOULD_FIX findings to strengthen Decision Log completeness and milestone acceptance criteria clarity, then proceed to TW plan-scrub phase.
**Next**: Technical Writer plan-scrub review
[TEMPORAL] CLEAN: All diff block comments pass Timeless Present Rule
Reviewed all diff blocks in Milestone 1 (App.tsx, 4 diffs) and Milestone 5 (HomePage.tsx 2 diffs, Layout.tsx 2 diffs, HamburgerDrawer.tsx 1 diff). Only one code comment exists in the diffs:
// Public pages (lazy-loaded) -- Describes what this code section IS. Clean. No change-relative language, no baseline reference, no location directive, no planning artifact, no intent leakage.
All other diff blocks contain pure code with no comments. No temporal contamination detected.
[PROSE] CLEAN: Milestone 5 "Note:" blocks are plan instructions, not code comments
Two "Note:" blocks follow diffs in Milestone 5:
Layout.tsx: "Requires adding HelpOutlineRoundedIcon import at top of Layout.tsx"
HamburgerDrawer.tsx: "The Guide item uses as MobileScreen cast and the handleNavigate function will need a guard..."
These are developer instructions within the plan, not code comments that would appear in source files. The phrase "will need a guard" is planning language but is correctly scoped -- it tells the developer what to implement, not what to write as a comment. No action required.
The Decision Log has entries that could produce valuable code comments during implementation. The planner is not expected to author these comments (that is the developer's responsibility), but noting the strongest candidates for the developer's awareness:
"Guide link as window.location in mobile hamburger" -- The HamburgerDrawer guard for 'Guide' screen should have a WHY comment explaining /guide is a public route outside the /garage/* shell, so it bypasses Zustand navigation. The Decision Log reasoning chain provides the material.
"Custom React components over react-markdown" -- GuidePage.tsx or its CLAUDE.md could note: "Static JSX components rather than react-markdown; content changes quarterly; avoids ~48KB runtime + 15-20 transitive deps for content that needs full MUI/Tailwind control." This is an architecture decision not apparent from code alone.
"Individual section component files" -- The sections/index.ts barrel file could note the rationale if it is not already captured in the GuidePage CLAUDE.md (Milestone 6 covers this).
These are suggestions for the developer during implementation, not plan defects.
[PROSE CLARITY] CLEAN: Requirements and acceptance criteria are clear and testable
All milestone requirements use precise, unambiguous language:
Component names are exact (GuideTableOfContents, GuideScreenshot, GuideTable)
File paths are absolute from project root
Acceptance criteria are boolean-testable ("TOC displays all 10 section titles", "Desktop: TOC is sticky sidebar on left")
No hedging language ("basically", "simply", "just")
No marketing language ("elegant", "robust", "powerful")
No aspirational language ("will support", "planned for") in requirements/criteria
One minor note: M1 acceptance criteria item "Navigation bar present with Guide link active/highlighted" -- "active/highlighted" could be more precise (does it mean CSS active state, aria-current, visual indicator?). This is minor and implementation context will clarify.
[PROSE CLARITY] CLEAN: Invisible Knowledge section is well-structured
Architecture diagram, data flow, "Why This Structure" explanations, invariants, and tradeoffs are all clearly written in timeless present tense. No temporal contamination. The explanations document architecture decisions not apparent from code (exactly what Invisible Knowledge should contain).
Verdict
PASS
All diff block comments are temporally clean. Plan prose is clear, testable, and free of forbidden patterns. The Decision Log provides strong material for the developer to derive WHY comments during implementation (3 suggestions noted above, non-blocking). No temporal contamination detected anywhere in the plan.
Next: QR plan-code review
## TW Review: Plan Scrub
**Phase**: Plan-Review | **Agent**: Technical Writer | **Status**: PASS
### Findings
#### [TEMPORAL] CLEAN: All diff block comments pass Timeless Present Rule
Reviewed all diff blocks in Milestone 1 (App.tsx, 4 diffs) and Milestone 5 (HomePage.tsx 2 diffs, Layout.tsx 2 diffs, HamburgerDrawer.tsx 1 diff). Only one code comment exists in the diffs:
- `// Public pages (lazy-loaded)` -- Describes what this code section IS. Clean. No change-relative language, no baseline reference, no location directive, no planning artifact, no intent leakage.
All other diff blocks contain pure code with no comments. No temporal contamination detected.
#### [PROSE] CLEAN: Milestone 5 "Note:" blocks are plan instructions, not code comments
Two "Note:" blocks follow diffs in Milestone 5:
- Layout.tsx: "Requires adding `HelpOutlineRoundedIcon` import at top of Layout.tsx"
- HamburgerDrawer.tsx: "The Guide item uses `as MobileScreen` cast and the handleNavigate function will need a guard..."
These are developer instructions within the plan, not code comments that would appear in source files. The phrase "will need a guard" is planning language but is correctly scoped -- it tells the developer what to implement, not what to write as a comment. No action required.
#### [COMMENT QUALITY] SUGGESTION: Decision Log entries could inform 2-3 WHY comments
The Decision Log has entries that could produce valuable code comments during implementation. The planner is not expected to author these comments (that is the developer's responsibility), but noting the strongest candidates for the developer's awareness:
1. **"Guide link as window.location in mobile hamburger"** -- The HamburgerDrawer guard for 'Guide' screen should have a WHY comment explaining `/guide` is a public route outside the `/garage/*` shell, so it bypasses Zustand navigation. The Decision Log reasoning chain provides the material.
2. **"Custom React components over react-markdown"** -- GuidePage.tsx or its CLAUDE.md could note: "Static JSX components rather than react-markdown; content changes quarterly; avoids ~48KB runtime + 15-20 transitive deps for content that needs full MUI/Tailwind control." This is an architecture decision not apparent from code alone.
3. **"Individual section component files"** -- The sections/index.ts barrel file could note the rationale if it is not already captured in the GuidePage CLAUDE.md (Milestone 6 covers this).
These are suggestions for the developer during implementation, not plan defects.
#### [PROSE CLARITY] CLEAN: Requirements and acceptance criteria are clear and testable
All milestone requirements use precise, unambiguous language:
- Breakpoints specified numerically (320px, 768px, 1920px)
- Component names are exact (GuideTableOfContents, GuideScreenshot, GuideTable)
- File paths are absolute from project root
- Acceptance criteria are boolean-testable ("TOC displays all 10 section titles", "Desktop: TOC is sticky sidebar on left")
- No hedging language ("basically", "simply", "just")
- No marketing language ("elegant", "robust", "powerful")
- No aspirational language ("will support", "planned for") in requirements/criteria
One minor note: M1 acceptance criteria item "Navigation bar present with Guide link active/highlighted" -- "active/highlighted" could be more precise (does it mean CSS active state, aria-current, visual indicator?). This is minor and implementation context will clarify.
#### [PROSE CLARITY] CLEAN: Invisible Knowledge section is well-structured
Architecture diagram, data flow, "Why This Structure" explanations, invariants, and tradeoffs are all clearly written in timeless present tense. No temporal contamination. The explanations document architecture decisions not apparent from code (exactly what Invisible Knowledge should contain).
### Verdict
**PASS**
All diff block comments are temporally clean. Plan prose is clear, testable, and free of forbidden patterns. The Decision Log provides strong material for the developer to derive WHY comments during implementation (3 suggestions noted above, non-blocking). No temporal contamination detected anywhere in the plan.
**Next**: QR plan-code review
Milestone 6 is dedicated to documentation with clear requirements:
Create CLAUDE.md index for GuidePage directory
Update parent pages/ CLAUDE.md if it exists
Document architecture: section component pattern, shared components, public route handling
Source material explicitly references Invisible Knowledge section
No issues found.
[DOCS] CLEAN: CLAUDE.md specifies tabular index format
M6 requirements state: "Create CLAUDE.md index for GuidePage directory with file listings and when-to-read". The project convention (shown in docs/CLAUDE.md, frontend/src/pages/CLAUDE.md patterns) uses the | File | What | When to read | format. The requirement "with file listings and when-to-read" confirms this format is expected, even though it doesn't explicitly say "tabular" - the project pattern is consistent and unambiguous.
No issues found.
[DOCS] CLEAN: README.md appropriately scoped
The plan creates a feature-level CLAUDE.md but does NOT create a README.md. This is correct because:
The Invisible Knowledge section documents architecture decisions (section component pattern, shared components, public route handling, screenshot management)
This content is meant for AI context and developer onboarding (CLAUDE.md purpose)
It is NOT user-facing documentation or setup instructions that would warrant a README.md
The project convention (per CLAUDE.md root) is: CLAUDE.md for AI context, README.md for user-facing overview/setup
The Invisible Knowledge section includes 4 key subsections that document decisions not apparent from reading code:
Architecture diagram: Shows GuidePage component tree, TOC structure (desktop sticky vs mobile accordion), 10 section components, shared components
Data Flow: User visit -> lazy load -> TOC render -> anchor navigation flow
Why This Structure: 4 explicit rationales:
Why individual section files vs monolithic data file (150-250 lines each, 2000+ total would exceed god-object threshold)
Why shared GuideScreenshot/GuideTable components (prevents duplicate MUI Table and img boilerplate across 10 sections)
Why guide page has its own nav bar vs reusing Layout.tsx (public page accessible without authentication)
Why guideTypes.ts separates metadata from content (TOC generation without importing full section content)
Invariants: 4 rules that must hold (public access, anchor ID matching, WebP + lazy loading, independent nav bar)
Tradeoffs: 2 explicit tradeoffs analyzed (individual files vs fewer files, static JSX vs dynamic markdown)
All 5 subsections explain architectural choices that a new team member could NOT deduce from reading the source files alone. The "Why This Structure" section is particularly strong - each rationale explains the CONTEXT that drove the decision.
No issues found.
[DOCS] SUGGESTION: Architecture diagram could be enhanced with visual representation
The Architecture diagram is text-based (tree structure using ASCII art). While it clearly shows the component hierarchy, a Mermaid diagram could improve clarity for complex relationships like:
Desktop vs mobile responsive behavior (sticky sidebar vs collapsible accordion)
graph TD
A[/guide route] -->|lazy load| B[GuidePage]
B --> C[GuideTableOfContents]
B --> D[Scrollable Content]
C -->|desktop >= 768px| E[Sticky Sidebar]
C -->|mobile < 768px| F[Collapsible Accordion]
D --> G[10 Section Components]
G --> H[GuideScreenshot - lazy img]
G --> I[GuideTable - MUI Table]
This is a SUGGESTION, not a requirement. The text-based diagram is functional and complete. Visual enhancement would improve comprehension but is not blocking.
[DOCS] CLEAN: All new files referenced in documentation milestone
M6 files list includes:
frontend/src/pages/CLAUDE.md (MODIFY or CREATE)
frontend/src/pages/GuidePage/CLAUDE.md (NEW)
This covers documentation for the new GuidePage directory and its integration into the parent pages/ directory structure. The MODIFY or CREATE handling for pages/CLAUDE.md correctly accounts for uncertainty about whether that file currently exists.
All new directories introduced in the plan (GuidePage/, sections/, components/) will have documentation coverage through these two CLAUDE.md files.
No issues found.
Considered But Not Flagged
M6 acceptance criteria are testable: "CLAUDE.md enables LLM to locate relevant guide page code for modification tasks" and "New team member can understand guide page organization from reading CLAUDE.md" are both concrete, verifiable outcomes
Source material explicitly linked: M6 references "Invisible Knowledge section of this plan" as source material, establishing traceability
Documentation follows project conventions: Tabular CLAUDE.md format, no README.md for feature-level docs, architecture + invariants + tradeoffs structure matches existing patterns (e.g., backend feature capsule docs)
Invisible Knowledge subsections are complete: All 5 expected subsections present (Architecture, Data Flow, Why This Structure, Invariants, Tradeoffs)
No temporal contamination in Invisible Knowledge: All explanations use timeless present tense ("The guide page has its own navigation bar", not "We added a navigation bar")
M6 is correctly sequenced last: Documentation milestone depends on M1-M5 implementation completion, allowing architecture documentation to reflect final implemented structure
Verdict
PASS
All 6 documentation completeness criteria are met:
Documentation milestone exists (M6)
CLAUDE.md uses tabular format (implied by "file listings and when-to-read", project convention)
README.md correctly omitted (Invisible Knowledge is AI/dev context, not user-facing)
Architecture diagram present (text-based tree structure, SUGGESTION for Mermaid enhancement)
All new files referenced (GuidePage/CLAUDE.md + pages/CLAUDE.md cover all new directories)
The plan's documentation approach is comprehensive and follows project conventions. The Invisible Knowledge section provides strong architectural context that will enable future maintainers to understand WHY decisions were made, not just WHAT was built.
Next: QR plan-code review
## QR Review: Plan Docs
**Phase**: Plan-Review | **Agent**: Quality Reviewer | **Status**: PASS
### Findings
#### [DOCS] CLEAN: Documentation milestone exists (M6)
Milestone 6 is dedicated to documentation with clear requirements:
- Create CLAUDE.md index for GuidePage directory
- Update parent pages/ CLAUDE.md if it exists
- Document architecture: section component pattern, shared components, public route handling
- Source material explicitly references Invisible Knowledge section
No issues found.
#### [DOCS] CLEAN: CLAUDE.md specifies tabular index format
M6 requirements state: "Create CLAUDE.md index for GuidePage directory with file listings and when-to-read". The project convention (shown in docs/CLAUDE.md, frontend/src/pages/CLAUDE.md patterns) uses the `| File | What | When to read |` format. The requirement "with file listings and when-to-read" confirms this format is expected, even though it doesn't explicitly say "tabular" - the project pattern is consistent and unambiguous.
No issues found.
#### [DOCS] CLEAN: README.md appropriately scoped
The plan creates a feature-level CLAUDE.md but does NOT create a README.md. This is correct because:
- The Invisible Knowledge section documents architecture decisions (section component pattern, shared components, public route handling, screenshot management)
- This content is meant for AI context and developer onboarding (CLAUDE.md purpose)
- It is NOT user-facing documentation or setup instructions that would warrant a README.md
- The project convention (per CLAUDE.md root) is: CLAUDE.md for AI context, README.md for user-facing overview/setup
No issues found.
#### [DOCS] QUALITY: Invisible Knowledge captures non-obvious decisions
The Invisible Knowledge section includes 4 key subsections that document decisions not apparent from reading code:
1. **Architecture diagram**: Shows GuidePage component tree, TOC structure (desktop sticky vs mobile accordion), 10 section components, shared components
2. **Data Flow**: User visit -> lazy load -> TOC render -> anchor navigation flow
3. **Why This Structure**: 4 explicit rationales:
- Why individual section files vs monolithic data file (150-250 lines each, 2000+ total would exceed god-object threshold)
- Why shared GuideScreenshot/GuideTable components (prevents duplicate MUI Table and img boilerplate across 10 sections)
- Why guide page has its own nav bar vs reusing Layout.tsx (public page accessible without authentication)
- Why guideTypes.ts separates metadata from content (TOC generation without importing full section content)
4. **Invariants**: 4 rules that must hold (public access, anchor ID matching, WebP + lazy loading, independent nav bar)
5. **Tradeoffs**: 2 explicit tradeoffs analyzed (individual files vs fewer files, static JSX vs dynamic markdown)
All 5 subsections explain architectural choices that a new team member could NOT deduce from reading the source files alone. The "Why This Structure" section is particularly strong - each rationale explains the CONTEXT that drove the decision.
No issues found.
#### [DOCS] SUGGESTION: Architecture diagram could be enhanced with visual representation
The Architecture diagram is text-based (tree structure using ASCII art). While it clearly shows the component hierarchy, a Mermaid diagram could improve clarity for complex relationships like:
- Desktop vs mobile responsive behavior (sticky sidebar vs collapsible accordion)
- Lazy loading boundaries (route-level, image-level)
- Public vs authenticated navigation flow
Example Mermaid enhancement:
```mermaid
graph TD
A[/guide route] -->|lazy load| B[GuidePage]
B --> C[GuideTableOfContents]
B --> D[Scrollable Content]
C -->|desktop >= 768px| E[Sticky Sidebar]
C -->|mobile < 768px| F[Collapsible Accordion]
D --> G[10 Section Components]
G --> H[GuideScreenshot - lazy img]
G --> I[GuideTable - MUI Table]
```
This is a SUGGESTION, not a requirement. The text-based diagram is functional and complete. Visual enhancement would improve comprehension but is not blocking.
#### [DOCS] CLEAN: All new files referenced in documentation milestone
M6 files list includes:
- `frontend/src/pages/CLAUDE.md` (MODIFY or CREATE)
- `frontend/src/pages/GuidePage/CLAUDE.md` (NEW)
This covers documentation for the new GuidePage directory and its integration into the parent pages/ directory structure. The MODIFY or CREATE handling for pages/CLAUDE.md correctly accounts for uncertainty about whether that file currently exists.
All new directories introduced in the plan (GuidePage/, sections/, components/) will have documentation coverage through these two CLAUDE.md files.
No issues found.
### Considered But Not Flagged
- **M6 acceptance criteria are testable**: "CLAUDE.md enables LLM to locate relevant guide page code for modification tasks" and "New team member can understand guide page organization from reading CLAUDE.md" are both concrete, verifiable outcomes
- **Source material explicitly linked**: M6 references "Invisible Knowledge section of this plan" as source material, establishing traceability
- **Documentation follows project conventions**: Tabular CLAUDE.md format, no README.md for feature-level docs, architecture + invariants + tradeoffs structure matches existing patterns (e.g., backend feature capsule docs)
- **Invisible Knowledge subsections are complete**: All 5 expected subsections present (Architecture, Data Flow, Why This Structure, Invariants, Tradeoffs)
- **No temporal contamination in Invisible Knowledge**: All explanations use timeless present tense ("The guide page has its own navigation bar", not "We added a navigation bar")
- **M6 is correctly sequenced last**: Documentation milestone depends on M1-M5 implementation completion, allowing architecture documentation to reflect final implemented structure
### Verdict
PASS
All 6 documentation completeness criteria are met:
1. Documentation milestone exists (M6)
2. CLAUDE.md uses tabular format (implied by "file listings and when-to-read", project convention)
3. README.md correctly omitted (Invisible Knowledge is AI/dev context, not user-facing)
4. Invisible Knowledge captures non-obvious decisions (5 subsections with strong architectural rationale)
5. Architecture diagram present (text-based tree structure, SUGGESTION for Mermaid enhancement)
6. All new files referenced (GuidePage/CLAUDE.md + pages/CLAUDE.md cover all new directories)
The plan's documentation approach is comprehensive and follows project conventions. The Invisible Knowledge section provides strong architectural context that will enable future maintainers to understand WHY decisions were made, not just WHAT was built.
**Next**: QR plan-code review
Issue: M5 diff shows { screen: 'Guide' as MobileScreen, label: 'Guide', icon: <HelpOutlineRoundedIcon /> } with note "The Guide item uses as MobileScreen cast and the handleNavigate function will need a guard to handle the Guide case by navigating to /guide via window.location." The note is accurate but incomplete - it doesn't show the actual guard implementation.
Why this matters: Developer implementing M5 will need to modify the handleNavigate function (lines 59-62 in current HamburgerDrawer.tsx) to check for 'Guide' screen and use window.location.href = '/guide' instead of calling onNavigate(screen). Without the guard code in the diff or note, the implementation is left ambiguous.
Suggested Fix: Add a second diff block in M5 showing the handleNavigate guard:
--- a/frontend/src/shared-minimal/components/mobile/HamburgerDrawer.tsx
+++ b/frontend/src/shared-minimal/components/mobile/HamburgerDrawer.tsx
@@ -59,6 +59,11 @@
const handleNavigate = (screen: MobileScreen) => {
+ // Guide is a public route outside /garage/* shell - use direct navigation
+ if (screen === 'Guide') {
+ window.location.href = '/guide';
+ onClose();
+ return;
+ }
onNavigate(screen);
onClose();
};
This is a SUGGESTION not a blocker - the Decision Log entry "Guide link as window.location in mobile hamburger" provides the reasoning, and the M5 note mentions the guard. Adding the explicit guard diff would eliminate implementation ambiguity.
[RULE 2] CLEAN: Individual section files prevent god object anti-pattern
Reviewed proposed file structure: 10 section files at ~150-250 lines JSX each (per M2/M3 requirements). Decision Log entry "Individual section component files" provides reasoning: single file would be 2000+ lines god object; individual files follow default-conventions file-creation domain (clear module boundary).
Verified against RULE 2 god object threshold: >15 public methods or >10 dependencies. Static JSX section components have 0 public methods and ~3-5 dependencies (React, MUI Typography, GuideTable, GuideScreenshot). No god object risk.
Tradeoffs section acknowledges file count cost: "18 new files vs single content file: chose modularity over fewer files". Explicit decision documented.
No RULE 2 violations. File organization is sound.
[RULE 2] CLEAN: No duplicate logic detected across section components
Reviewed M2/M3 section component requirements: shared GuideScreenshot and GuideTable components extract common patterns. Decision Log entries:
This is correct RULE 2 duplication prevention. Each section uses GuideScreenshot/GuideTable for common patterns rather than copy-pasting MUI Table code or img tags 15+ times.
No RULE 2 duplication violations.
[RULE 0] CLEAN: No unhandled error paths detected in diffs
Reviewed all code diffs in M1 and M5:
App.tsx route detection: boolean conditionals with fallback to existing HomePage/garage routes - no unhandled path
Lazy loading: Suspense fallback with loading div - handles chunk loading errors via React error boundary (existing MobileErrorBoundary in App.tsx line 90)
Navigation links: static anchor tags and route references - no error-prone dynamic logic
HamburgerDrawer guard (when implemented per SUGGESTION above): early return pattern - no error path
M4 acceptance criteria specifies "Total guide image payload under 5MB (WebP compression)" and GuideScreenshot component uses loading="lazy" attribute. Decision Log entry: "Large page size with ~15+ screenshots -> Lazy loading with loading="lazy" attribute; WebP format reduces file sizes ~30%; images only load when scrolled into viewport".
This prevents loading 15-20 images on page mount (potential 10-20MB uncompressed PNGs) which could exhaust mobile device memory or bandwidth. Lazy loading defers image fetch until scroll. WebP compression reduces payload.
M1 acceptance criteria includes "Desktop: TOC is sticky sidebar on left, content scrolls on right" and "Mobile: TOC is collapsible accordion above content". M2/M3 acceptance criteria both include "Responsive layout: content readable at 320px, 768px, 1920px".
Issue acceptance criteria requires "Responsive design: works on mobile (320px, 768px) and desktop (1920px)". Plan milestones cover all three breakpoints.
CLAUDE.md mobile + desktop requirement: "ALL features MUST be implemented and tested on BOTH mobile and desktop." Plan meets requirement.
No RULE 1 violations.
[RULE 1] CLEAN: Dark mode support via existing ThemeProvider pattern
Constraints list "Dark mode support via existing ThemeProvider (doc-derived: ThemeContext.tsx pattern)". M2 requirements include "Dark mode compatible styling using Tailwind dark: prefixes and MUI theme".
App.tsx diff wraps GuidePage in ThemeProvider (same as HomePage wrapper at lines 629-636). This provides MUI theme context and Tailwind dark mode class toggling via existing pattern.
No RULE 1 violations. Dark mode integration correct.
Considered But Not Flagged
Tests skipped in M1-M4 with explicit reason: M1/M2/M3 say "Skip: static content sections" or "Skip: asset-only milestone" with rationale that full component tests in M5 verify sections render. M5 includes 5 test scenarios (2 normal, 3 edge). This is acceptable - tests are deferred not omitted.
Test file location: M5 creates frontend/src/pages/__tests__/GuidePage.test.tsx which follows existing test pattern from frontend/src/features/dashboard/components/__tests__/DashboardScreen.test.tsx. Correct location.
No new npm dependencies decision: Decision Log entry "Custom React components over react-markdown" explains no react-markdown/remark/rehype dependencies (~48KB runtime + 15-20 transitive deps). Custom JSX components achieve same result with existing MUI/Tailwind stack. Reasonable decision, no security/bloat risk from abandoned packages.
WebP format choice: Decision Log entry "WebP screenshot format" cites "Modern standard with ~30% smaller files vs PNG; all major browsers support WebP". Correct - WebP has >96% browser support as of 2024. No RULE 0 compatibility risk.
TouchTarget sizing verified: Decision Log entry "Touch targets >= 44px on TOC" specifies "TOC items use py-3 (~48px effective height)". Tailwind py-3 = 12px top + 12px bottom padding = 24px padding + ~20px line height = ~44-48px total. Meets default-conventions >= 44px requirement from CLAUDE.md.
Guide route accessible without auth: M1 App.tsx diffs add isGuideRoute detection and ThemeProvider wrapper with no auth check (no useAuth0 or isAuthenticated conditional). Issue acceptance criteria: "/guide route accessible without authentication". Correct - public route like HomePage.
Old PDF cleanup included: M5 requirements include "Remove old PDF at frontend/public/docs/v2026-01-03.pdf". CLAUDE.md code completion criteria: "Old code is deleted". Plan includes cleanup step.
Anchor link smooth scroll: M1 requirements specify "supports smooth scroll to anchor links". This is standard HTML5 scroll-behavior: smooth CSS or JavaScript scrollIntoView({ behavior: 'smooth' }) - trivial implementation, no RULE violations.
File paths are absolute: All milestone file paths use absolute paths from project root (e.g., frontend/src/pages/GuidePage/GuidePage.tsx not "guide files"). Follows planning best practices.
Screenshot count reconciliation noted in plan-completeness review: QR plan-completeness review flagged "Issue lists ~15, plan captures 17" as SHOULD_FIX. The plan lists 14 desktop + 3 mobile = 17 screenshots to ensure comprehensive coverage. The "~15" in the issue was an estimate. Not a code quality issue, just a count clarification.
Verdict
PASS
All code diffs follow existing codebase patterns for routing, navigation, lazy loading, and styling. No RULE 0 (production reliability) or RULE 1 (project conformance) violations detected. RULE 2 (structural quality) is sound - shared components prevent duplication, individual section files prevent god objects. One SUGGESTION for M5 HamburgerDrawer guard implementation clarity (not a blocker - reasoning is in Decision Log, note mentions the guard, just missing explicit diff).
Mobile + desktop responsive design covered (320px, 768px, 1920px). Dark mode via ThemeProvider. Touch targets >= 44px. Lazy loading prevents resource exhaustion. Tests deferred to M5 with valid reason. No unhandled error paths.
Recommended action: Plan is approved for implementation. Optional: Address SUGGESTION for HamburgerDrawer guard diff block to eliminate implementation ambiguity.
Next: QR plan-docs review
## QR Review: Plan Code
**Phase**: Plan-Review | **Agent**: Quality Reviewer | **Status**: PASS
### Findings
#### [RULE 1] CLEAN: All diffs follow existing App.tsx lazy loading pattern
Verified M1 App.tsx diffs against existing code structure (lines 16-65):
- Lazy import placement: Plan adds `const GuidePage = lazy(...)` after auth pages section (line 53) - correct location matching existing pattern
- Import format: `lazy(() => import('./pages/GuidePage/GuidePage').then(m => ({ default: m.GuidePage })))` matches existing pattern from lines 16-25
- Route detection variables: Plan adds `isGuideRoute`, `shouldShowHomePage` update follows existing pattern from lines 497-498
- ThemeProvider wrapper: Plan uses same wrapper pattern as HomePage (lines 629-636)
- Suspense fallback: Follows existing pattern with Tailwind classes matching HomePage style
No RULE 1 violations detected. Pattern conformance is correct.
#### [RULE 1] CLEAN: HomePage navigation additions maintain existing structure
Verified M5 HomePage.tsx diffs against existing code (lines 79-110 desktop, lines 138-179 mobile):
- Desktop Guide link placement: Between About (line 89) and Sign Up button (lines 92-97) - correct per plan spec
- Mobile Guide link placement: Between About (line 157) and Sign Up button (lines 163-168) - correct per plan spec
- Anchor tag styling: Plan uses identical classes (`text-white/75 hover:text-white transition-colors`) matching existing links at lines 80-90
- Touch target sizing: Mobile Guide link uses `py-2` matching existing mobile links (line 159), effective height ~48px - meets >= 44px requirement from default-conventions
No RULE 1 violations. Navigation integration follows existing HomePage patterns.
#### [RULE 1] CLEAN: Layout.tsx sidebar addition follows navigation array pattern
Verified M5 Layout.tsx diffs against existing code (line 46-54):
- Navigation array structure: Plan adds `{ name: 'Guide', href: '/guide', icon: <HelpOutlineRoundedIcon sx={{ fontSize: 20 }} /> }` matching exact format from lines 47-53
- Icon sizing: `sx={{ fontSize: 20 }}` matches all other nav icons (lines 47-53)
- Icon import pattern: Plan adds `import HelpOutlineRoundedIcon from '@mui/icons-material/HelpOutlineRounded';` matching import style from lines 10-19
- Href pattern: `/guide` is absolute path matching existing `/garage/documents`, `/garage/settings` pattern
No RULE 1 violations. Sidebar integration is correct.
#### [RULE 1] SUGGESTION: HamburgerDrawer navigation guard implementation needs clarification in M5 code changes
**Location**: Milestone 5 > Code Changes > HamburgerDrawer.tsx
**Issue**: M5 diff shows `{ screen: 'Guide' as MobileScreen, label: 'Guide', icon: <HelpOutlineRoundedIcon /> }` with note "The Guide item uses `as MobileScreen` cast and the handleNavigate function will need a guard to handle the Guide case by navigating to /guide via window.location." The note is accurate but incomplete - it doesn't show the actual guard implementation.
**Why this matters**: Developer implementing M5 will need to modify the `handleNavigate` function (lines 59-62 in current HamburgerDrawer.tsx) to check for 'Guide' screen and use `window.location.href = '/guide'` instead of calling `onNavigate(screen)`. Without the guard code in the diff or note, the implementation is left ambiguous.
**Suggested Fix**: Add a second diff block in M5 showing the handleNavigate guard:
```diff
--- a/frontend/src/shared-minimal/components/mobile/HamburgerDrawer.tsx
+++ b/frontend/src/shared-minimal/components/mobile/HamburgerDrawer.tsx
@@ -59,6 +59,11 @@
const handleNavigate = (screen: MobileScreen) => {
+ // Guide is a public route outside /garage/* shell - use direct navigation
+ if (screen === 'Guide') {
+ window.location.href = '/guide';
+ onClose();
+ return;
+ }
onNavigate(screen);
onClose();
};
```
This is a SUGGESTION not a blocker - the Decision Log entry "Guide link as window.location in mobile hamburger" provides the reasoning, and the M5 note mentions the guard. Adding the explicit guard diff would eliminate implementation ambiguity.
#### [RULE 2] CLEAN: Individual section files prevent god object anti-pattern
Reviewed proposed file structure: 10 section files at ~150-250 lines JSX each (per M2/M3 requirements). Decision Log entry "Individual section component files" provides reasoning: single file would be 2000+ lines god object; individual files follow default-conventions file-creation domain (clear module boundary).
Verified against RULE 2 god object threshold: >15 public methods or >10 dependencies. Static JSX section components have 0 public methods and ~3-5 dependencies (React, MUI Typography, GuideTable, GuideScreenshot). No god object risk.
Tradeoffs section acknowledges file count cost: "18 new files vs single content file: chose modularity over fewer files". Explicit decision documented.
No RULE 2 violations. File organization is sound.
#### [RULE 2] CLEAN: No duplicate logic detected across section components
Reviewed M2/M3 section component requirements: shared GuideScreenshot and GuideTable components extract common patterns. Decision Log entries:
- "GuideScreenshot shared component": ~15+ screenshots -> consistent lazy loading, responsive sizing, WebP format -> shared component prevents duplicate img/loading logic
- "GuideTable shared component": 15+ GFM tables -> MUI Table boilerplate is verbose -> shared component takes headers/rows arrays -> consistent styling
This is correct RULE 2 duplication prevention. Each section uses GuideScreenshot/GuideTable for common patterns rather than copy-pasting MUI Table code or img tags 15+ times.
No RULE 2 duplication violations.
#### [RULE 0] CLEAN: No unhandled error paths detected in diffs
Reviewed all code diffs in M1 and M5:
- App.tsx route detection: boolean conditionals with fallback to existing HomePage/garage routes - no unhandled path
- Lazy loading: Suspense fallback with loading div - handles chunk loading errors via React error boundary (existing MobileErrorBoundary in App.tsx line 90)
- Navigation links: static anchor tags and route references - no error-prone dynamic logic
- HamburgerDrawer guard (when implemented per SUGGESTION above): early return pattern - no error path
No RULE 0 violations detected.
#### [RULE 0] CLEAN: GuideScreenshot lazy loading prevents resource exhaustion
M4 acceptance criteria specifies "Total guide image payload under 5MB (WebP compression)" and GuideScreenshot component uses `loading="lazy"` attribute. Decision Log entry: "Large page size with ~15+ screenshots -> Lazy loading with loading="lazy" attribute; WebP format reduces file sizes ~30%; images only load when scrolled into viewport".
This prevents loading 15-20 images on page mount (potential 10-20MB uncompressed PNGs) which could exhaust mobile device memory or bandwidth. Lazy loading defers image fetch until scroll. WebP compression reduces payload.
Correct RULE 0 resource exhaustion mitigation.
#### [RULE 1] CLEAN: Responsive design coverage meets mobile + desktop requirement
M1 acceptance criteria includes "Desktop: TOC is sticky sidebar on left, content scrolls on right" and "Mobile: TOC is collapsible accordion above content". M2/M3 acceptance criteria both include "Responsive layout: content readable at 320px, 768px, 1920px".
Issue acceptance criteria requires "Responsive design: works on mobile (320px, 768px) and desktop (1920px)". Plan milestones cover all three breakpoints.
CLAUDE.md mobile + desktop requirement: "ALL features MUST be implemented and tested on BOTH mobile and desktop." Plan meets requirement.
No RULE 1 violations.
#### [RULE 1] CLEAN: Dark mode support via existing ThemeProvider pattern
Constraints list "Dark mode support via existing ThemeProvider (doc-derived: ThemeContext.tsx pattern)". M2 requirements include "Dark mode compatible styling using Tailwind dark: prefixes and MUI theme".
App.tsx diff wraps GuidePage in ThemeProvider (same as HomePage wrapper at lines 629-636). This provides MUI theme context and Tailwind dark mode class toggling via existing pattern.
No RULE 1 violations. Dark mode integration correct.
### Considered But Not Flagged
- **Tests skipped in M1-M4 with explicit reason**: M1/M2/M3 say "Skip: static content sections" or "Skip: asset-only milestone" with rationale that full component tests in M5 verify sections render. M5 includes 5 test scenarios (2 normal, 3 edge). This is acceptable - tests are deferred not omitted.
- **Test file location**: M5 creates `frontend/src/pages/__tests__/GuidePage.test.tsx` which follows existing test pattern from `frontend/src/features/dashboard/components/__tests__/DashboardScreen.test.tsx`. Correct location.
- **No new npm dependencies decision**: Decision Log entry "Custom React components over react-markdown" explains no react-markdown/remark/rehype dependencies (~48KB runtime + 15-20 transitive deps). Custom JSX components achieve same result with existing MUI/Tailwind stack. Reasonable decision, no security/bloat risk from abandoned packages.
- **WebP format choice**: Decision Log entry "WebP screenshot format" cites "Modern standard with ~30% smaller files vs PNG; all major browsers support WebP". Correct - WebP has >96% browser support as of 2024. No RULE 0 compatibility risk.
- **TouchTarget sizing verified**: Decision Log entry "Touch targets >= 44px on TOC" specifies "TOC items use py-3 (~48px effective height)". Tailwind py-3 = 12px top + 12px bottom padding = 24px padding + ~20px line height = ~44-48px total. Meets default-conventions >= 44px requirement from CLAUDE.md.
- **Guide route accessible without auth**: M1 App.tsx diffs add isGuideRoute detection and ThemeProvider wrapper with no auth check (no `useAuth0` or `isAuthenticated` conditional). Issue acceptance criteria: "/guide route accessible without authentication". Correct - public route like HomePage.
- **Old PDF cleanup included**: M5 requirements include "Remove old PDF at `frontend/public/docs/v2026-01-03.pdf`". CLAUDE.md code completion criteria: "Old code is deleted". Plan includes cleanup step.
- **Anchor link smooth scroll**: M1 requirements specify "supports smooth scroll to anchor links". This is standard HTML5 `scroll-behavior: smooth` CSS or JavaScript `scrollIntoView({ behavior: 'smooth' })` - trivial implementation, no RULE violations.
- **File paths are absolute**: All milestone file paths use absolute paths from project root (e.g., `frontend/src/pages/GuidePage/GuidePage.tsx` not "guide files"). Follows planning best practices.
- **Screenshot count reconciliation noted in plan-completeness review**: QR plan-completeness review flagged "Issue lists ~15, plan captures 17" as SHOULD_FIX. The plan lists 14 desktop + 3 mobile = 17 screenshots to ensure comprehensive coverage. The "~15" in the issue was an estimate. Not a code quality issue, just a count clarification.
### Verdict
**PASS**
All code diffs follow existing codebase patterns for routing, navigation, lazy loading, and styling. No RULE 0 (production reliability) or RULE 1 (project conformance) violations detected. RULE 2 (structural quality) is sound - shared components prevent duplication, individual section files prevent god objects. One SUGGESTION for M5 HamburgerDrawer guard implementation clarity (not a blocker - reasoning is in Decision Log, note mentions the guard, just missing explicit diff).
Mobile + desktop responsive design covered (320px, 768px, 1920px). Dark mode via ThemeProvider. Touch targets >= 44px. Lazy loading prevents resource exhaustion. Tests deferred to M5 with valid reason. No unhandled error paths.
**Recommended action**: Plan is approved for implementation. Optional: Address SUGGESTION for HamburgerDrawer guard diff block to eliminate implementation ambiguity.
**Next**: QR plan-docs review
Added "Guide" link to public nav bar in HomePage.tsx (desktop between About and Sign Up, mobile hamburger menu)
Added "Guide" link with HelpOutlineRoundedIcon to authenticated sidebar in Layout.tsx
Added "Guide" link to HamburgerDrawer.tsx with window.location.href guard (bypasses Zustand navigation since /guide is outside /garage/* shell)
Created 6 integration tests in frontend/src/pages/__tests__/GuidePage.test.tsx:
Renders page heading and subheading
Renders all 10 section headings
Renders TOC with correct section titles
Renders navigation bar with Guide link
Renders GuideScreenshot components with loading="lazy"
Renders footer with copyright
Removed old PDF at frontend/public/docs/v2026-01-03.pdf
Quality Checks
Lint: 0 errors (227 pre-existing warnings)
Type-check: 0 errors
GuidePage tests: 6/6 passing
Full test suite: 200 passing, 17 pre-existing failures (stations, admin, documents -- unrelated)
Commit
197aeda feat: add guide navigation integration and tests (refs #203)
Verdict: PASS | Next: M6 Documentation
## Milestone: M5 Navigation Integration and Tests
**Phase**: Execution | **Agent**: Developer | **Status**: PASS
### Completed
- Added "Guide" link to public nav bar in HomePage.tsx (desktop between About and Sign Up, mobile hamburger menu)
- Added "Guide" link with HelpOutlineRoundedIcon to authenticated sidebar in Layout.tsx
- Added "Guide" link to HamburgerDrawer.tsx with `window.location.href` guard (bypasses Zustand navigation since `/guide` is outside `/garage/*` shell)
- Created 6 integration tests in `frontend/src/pages/__tests__/GuidePage.test.tsx`:
- Renders page heading and subheading
- Renders all 10 section headings
- Renders TOC with correct section titles
- Renders navigation bar with Guide link
- Renders GuideScreenshot components with loading="lazy"
- Renders footer with copyright
- Removed old PDF at `frontend/public/docs/v2026-01-03.pdf`
### Quality Checks
- Lint: 0 errors (227 pre-existing warnings)
- Type-check: 0 errors
- GuidePage tests: 6/6 passing
- Full test suite: 200 passing, 17 pre-existing failures (stations, admin, documents -- unrelated)
### Commit
`197aeda` feat: add guide navigation integration and tests (refs #203)
*Verdict*: PASS | *Next*: M6 Documentation
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Create a public-facing user guide page accessible before login, rendering the existing
docs/USER-GUIDE.mdcontent as an interactive single-page guide with screenshots captured from the live application.Context
docs/USER-GUIDE.md(955 lines, 10 major sections)/public/docs/v2026-01-03.pdf/) with nav: Home | Features | About | Sign Up | Login/guidepublic route and integrates into both public and authenticated navigationRequirements
Page Structure
Navigation Integration
Screenshots
Content Mapping
Map USER-GUIDE.md sections to page sections:
Design
docs/MVP-COLOR-SCHEME.md)Acceptance Criteria
/guideroute accessible without authenticationTechnical Notes
react-markdownor building custom section components from the guide contentfrontend/public/guide/or similar/public/docs/v2026-01-03.pdfcan be removed after this feature shipsPlan: Online User Guide with Screenshots
Phase: Planning | Agent: Planner | Status: AWAITING_REVIEW
Overview
Add a public
/guideroute renderingdocs/USER-GUIDE.mdcontent as styled React components with interspersed screenshots captured from the live application. The guide page uses a sticky TOC sidebar on desktop and collapsible TOC on mobile, matching existing MUI + Tailwind patterns. Guide links are added to public navigation, authenticated sidebar, and mobile hamburger drawer. No new npm dependencies required.Planning Context
Decision Log
Rejected Alternatives
Constraints and Assumptions
Known Risks
Invisible Knowledge
Architecture
Data Flow
Why This Structure
Invariants
Tradeoffs
Milestones
Milestone 1: Guide page foundation and routing
Sub-issue: feat: Guide page foundation and routing (#203)
Files:
frontend/src/pages/GuidePage/GuidePage.tsx(NEW)frontend/src/pages/GuidePage/GuideTableOfContents.tsx(NEW)frontend/src/pages/GuidePage/guideTypes.ts(NEW)frontend/src/pages/GuidePage/components/GuideScreenshot.tsx(NEW)frontend/src/pages/GuidePage/components/GuideTable.tsx(NEW)frontend/src/pages/GuidePage/sections/index.ts(NEW - placeholder exports)frontend/src/App.tsx(MODIFY)Requirements:
/guideroute detection:isGuideRoute = location.pathname === '/guide'shouldShowHomePageto exclude guide route/guideto mobile URL sync skip lists (lines 371, 383)Acceptance Criteria:
Tests:
Code Changes:
Add lazy import in App.tsx after auth pages section:
Add /guide to mobile URL sync skip lists:
Add guide route detection and render block:
Milestone 2: Guide content sections 1-5
Sub-issue: feat: Guide content sections 1-5 (#203)
Files:
frontend/src/pages/GuidePage/sections/GettingStartedSection.tsx(NEW)frontend/src/pages/GuidePage/sections/DashboardSection.tsx(NEW)frontend/src/pages/GuidePage/sections/VehiclesSection.tsx(NEW)frontend/src/pages/GuidePage/sections/FuelLogsSection.tsx(NEW)frontend/src/pages/GuidePage/sections/MaintenanceSection.tsx(NEW)frontend/src/pages/GuidePage/sections/index.ts(MODIFY - add real exports)Requirements:
Acceptance Criteria:
Tests:
Milestone 3: Guide content sections 6-10
Sub-issue: feat: Guide content sections 6-10 (#203)
Files:
frontend/src/pages/GuidePage/sections/GasStationsSection.tsx(NEW)frontend/src/pages/GuidePage/sections/DocumentsSection.tsx(NEW)frontend/src/pages/GuidePage/sections/SettingsSection.tsx(NEW)frontend/src/pages/GuidePage/sections/SubscriptionSection.tsx(NEW)frontend/src/pages/GuidePage/sections/MobileExperienceSection.tsx(NEW)frontend/src/pages/GuidePage/sections/index.ts(MODIFY - add remaining exports)Requirements:
Acceptance Criteria:
Tests:
Milestone 4: Screenshot capture and integration
Sub-issue: feat: Guide screenshot capture and integration (#203)
Files:
frontend/public/guide/(NEW directory)frontend/public/guide/*.webp(NEW - ~15-20 screenshot files)frontend/src/pages/GuidePage/sections/*.tsx(MODIFY - update screenshot src paths)Requirements:
frontend/public/guide/with descriptive filenames (e.g.,dashboard-desktop.webp,vehicles-list-desktop.webp)Acceptance Criteria:
frontend/public/guide/Tests:
Milestone 5: Navigation integration, tests, and cleanup
Sub-issue: feat: Guide navigation integration and tests (#203)
Files:
frontend/src/pages/HomePage.tsx(MODIFY)frontend/src/components/Layout.tsx(MODIFY)frontend/src/shared-minimal/components/mobile/HamburgerDrawer.tsx(MODIFY)frontend/src/pages/__tests__/GuidePage.test.tsx(NEW)frontend/public/docs/v2026-01-03.pdf(DELETE)Requirements:
frontend/public/docs/v2026-01-03.pdfAcceptance Criteria:
Tests:
frontend/src/pages/__tests__/GuidePage.test.tsxCode Changes:
Add Guide link to HomePage desktop nav (between About and Sign Up):
Add Guide link to HomePage mobile menu (between About and Sign Up):
Add Guide link to authenticated sidebar in Layout.tsx:
Note: Requires adding
HelpOutlineRoundedIconimport at top of Layout.tsx:Add Guide link to HamburgerDrawer.tsx:
Note: The Guide item uses
as MobileScreencast and the handleNavigate function will need a guard to handle the Guide case by navigating to /guide via window.location. Requires addingHelpOutlineRoundedIconimport.Milestone 6: Documentation
Sub-issue: docs: Guide page documentation (#203)
Files:
frontend/src/pages/CLAUDE.md(MODIFY or CREATE)frontend/src/pages/GuidePage/CLAUDE.md(NEW)Requirements:
Acceptance Criteria:
Source Material: Invisible Knowledge section of this plan
Milestone Dependencies
M2 and M3 can execute in parallel after M1 completes.
M4 requires M2 and M3 (screenshot placement in section components).
M5 requires M4 (tests verify screenshot loading).
M6 is final documentation pass.
Verdict: AWAITING_REVIEW | Next: Plan review cycle (QR plan-completeness -> TW plan-scrub -> QR plan-code -> QR plan-docs)
QR Review: Plan Completeness
Phase: Plan-Review | Agent: Quality Reviewer | Status: PASS_WITH_CONCERNS
Findings
[PLAN] SHOULD_FIX: Decision Log lacks HamburgerDrawer navigation implementation multi-step reasoning
{ screen: 'Guide' as MobileScreen, label: 'Guide', icon: ... }with cast and mentions "handleNavigate function will need a guard" but Decision Log doesn't explain this guard implementation decision. The reasoning stops at "simpler: direct URL navigation" without explaining the guard pattern.[PLAN] SHOULD_FIX: Missing screenshot count validation in Milestone 4
[PLAN] SUGGESTION: Milestone dependency graph could clarify M4 screenshot placement
Considered But Not Flagged
const GuidePage = lazy(...)), M4 uses lazy loading for images (loading="lazy"attribute in GuideScreenshot component)frontend/src/pages/GuidePage/GuidePage.tsx, not "guide files")Verdict
PASS_WITH_CONCERNS
The plan is comprehensive and covers all acceptance criteria with specific, testable milestones. The 3 findings are quality improvements (1 incomplete reasoning chain, 1 missing count validation note, 1 clarity enhancement) rather than blocking gaps.
Recommended action: Address SHOULD_FIX findings to strengthen Decision Log completeness and milestone acceptance criteria clarity, then proceed to TW plan-scrub phase.
Next: Technical Writer plan-scrub review
TW Review: Plan Scrub
Phase: Plan-Review | Agent: Technical Writer | Status: PASS
Findings
[TEMPORAL] CLEAN: All diff block comments pass Timeless Present Rule
Reviewed all diff blocks in Milestone 1 (App.tsx, 4 diffs) and Milestone 5 (HomePage.tsx 2 diffs, Layout.tsx 2 diffs, HamburgerDrawer.tsx 1 diff). Only one code comment exists in the diffs:
// Public pages (lazy-loaded)-- Describes what this code section IS. Clean. No change-relative language, no baseline reference, no location directive, no planning artifact, no intent leakage.All other diff blocks contain pure code with no comments. No temporal contamination detected.
[PROSE] CLEAN: Milestone 5 "Note:" blocks are plan instructions, not code comments
Two "Note:" blocks follow diffs in Milestone 5:
HelpOutlineRoundedIconimport at top of Layout.tsx"as MobileScreencast and the handleNavigate function will need a guard..."These are developer instructions within the plan, not code comments that would appear in source files. The phrase "will need a guard" is planning language but is correctly scoped -- it tells the developer what to implement, not what to write as a comment. No action required.
[COMMENT QUALITY] SUGGESTION: Decision Log entries could inform 2-3 WHY comments
The Decision Log has entries that could produce valuable code comments during implementation. The planner is not expected to author these comments (that is the developer's responsibility), but noting the strongest candidates for the developer's awareness:
"Guide link as window.location in mobile hamburger" -- The HamburgerDrawer guard for 'Guide' screen should have a WHY comment explaining
/guideis a public route outside the/garage/*shell, so it bypasses Zustand navigation. The Decision Log reasoning chain provides the material."Custom React components over react-markdown" -- GuidePage.tsx or its CLAUDE.md could note: "Static JSX components rather than react-markdown; content changes quarterly; avoids ~48KB runtime + 15-20 transitive deps for content that needs full MUI/Tailwind control." This is an architecture decision not apparent from code alone.
"Individual section component files" -- The sections/index.ts barrel file could note the rationale if it is not already captured in the GuidePage CLAUDE.md (Milestone 6 covers this).
These are suggestions for the developer during implementation, not plan defects.
[PROSE CLARITY] CLEAN: Requirements and acceptance criteria are clear and testable
All milestone requirements use precise, unambiguous language:
One minor note: M1 acceptance criteria item "Navigation bar present with Guide link active/highlighted" -- "active/highlighted" could be more precise (does it mean CSS active state, aria-current, visual indicator?). This is minor and implementation context will clarify.
[PROSE CLARITY] CLEAN: Invisible Knowledge section is well-structured
Architecture diagram, data flow, "Why This Structure" explanations, invariants, and tradeoffs are all clearly written in timeless present tense. No temporal contamination. The explanations document architecture decisions not apparent from code (exactly what Invisible Knowledge should contain).
Verdict
PASS
All diff block comments are temporally clean. Plan prose is clear, testable, and free of forbidden patterns. The Decision Log provides strong material for the developer to derive WHY comments during implementation (3 suggestions noted above, non-blocking). No temporal contamination detected anywhere in the plan.
Next: QR plan-code review
QR Review: Plan Docs
Phase: Plan-Review | Agent: Quality Reviewer | Status: PASS
Findings
[DOCS] CLEAN: Documentation milestone exists (M6)
Milestone 6 is dedicated to documentation with clear requirements:
No issues found.
[DOCS] CLEAN: CLAUDE.md specifies tabular index format
M6 requirements state: "Create CLAUDE.md index for GuidePage directory with file listings and when-to-read". The project convention (shown in docs/CLAUDE.md, frontend/src/pages/CLAUDE.md patterns) uses the
| File | What | When to read |format. The requirement "with file listings and when-to-read" confirms this format is expected, even though it doesn't explicitly say "tabular" - the project pattern is consistent and unambiguous.No issues found.
[DOCS] CLEAN: README.md appropriately scoped
The plan creates a feature-level CLAUDE.md but does NOT create a README.md. This is correct because:
No issues found.
[DOCS] QUALITY: Invisible Knowledge captures non-obvious decisions
The Invisible Knowledge section includes 4 key subsections that document decisions not apparent from reading code:
All 5 subsections explain architectural choices that a new team member could NOT deduce from reading the source files alone. The "Why This Structure" section is particularly strong - each rationale explains the CONTEXT that drove the decision.
No issues found.
[DOCS] SUGGESTION: Architecture diagram could be enhanced with visual representation
The Architecture diagram is text-based (tree structure using ASCII art). While it clearly shows the component hierarchy, a Mermaid diagram could improve clarity for complex relationships like:
Example Mermaid enhancement:
This is a SUGGESTION, not a requirement. The text-based diagram is functional and complete. Visual enhancement would improve comprehension but is not blocking.
[DOCS] CLEAN: All new files referenced in documentation milestone
M6 files list includes:
frontend/src/pages/CLAUDE.md(MODIFY or CREATE)frontend/src/pages/GuidePage/CLAUDE.md(NEW)This covers documentation for the new GuidePage directory and its integration into the parent pages/ directory structure. The MODIFY or CREATE handling for pages/CLAUDE.md correctly accounts for uncertainty about whether that file currently exists.
All new directories introduced in the plan (GuidePage/, sections/, components/) will have documentation coverage through these two CLAUDE.md files.
No issues found.
Considered But Not Flagged
Verdict
PASS
All 6 documentation completeness criteria are met:
The plan's documentation approach is comprehensive and follows project conventions. The Invisible Knowledge section provides strong architectural context that will enable future maintainers to understand WHY decisions were made, not just WHAT was built.
Next: QR plan-code review
QR Review: Plan Code
Phase: Plan-Review | Agent: Quality Reviewer | Status: PASS
Findings
[RULE 1] CLEAN: All diffs follow existing App.tsx lazy loading pattern
Verified M1 App.tsx diffs against existing code structure (lines 16-65):
const GuidePage = lazy(...)after auth pages section (line 53) - correct location matching existing patternlazy(() => import('./pages/GuidePage/GuidePage').then(m => ({ default: m.GuidePage })))matches existing pattern from lines 16-25isGuideRoute,shouldShowHomePageupdate follows existing pattern from lines 497-498No RULE 1 violations detected. Pattern conformance is correct.
[RULE 1] CLEAN: HomePage navigation additions maintain existing structure
Verified M5 HomePage.tsx diffs against existing code (lines 79-110 desktop, lines 138-179 mobile):
text-white/75 hover:text-white transition-colors) matching existing links at lines 80-90py-2matching existing mobile links (line 159), effective height ~48px - meets >= 44px requirement from default-conventionsNo RULE 1 violations. Navigation integration follows existing HomePage patterns.
[RULE 1] CLEAN: Layout.tsx sidebar addition follows navigation array pattern
Verified M5 Layout.tsx diffs against existing code (line 46-54):
{ name: 'Guide', href: '/guide', icon: <HelpOutlineRoundedIcon sx={{ fontSize: 20 }} /> }matching exact format from lines 47-53sx={{ fontSize: 20 }}matches all other nav icons (lines 47-53)import HelpOutlineRoundedIcon from '@mui/icons-material/HelpOutlineRounded';matching import style from lines 10-19/guideis absolute path matching existing/garage/documents,/garage/settingspatternNo RULE 1 violations. Sidebar integration is correct.
[RULE 1] SUGGESTION: HamburgerDrawer navigation guard implementation needs clarification in M5 code changes
Location: Milestone 5 > Code Changes > HamburgerDrawer.tsx
Issue: M5 diff shows
{ screen: 'Guide' as MobileScreen, label: 'Guide', icon: <HelpOutlineRoundedIcon /> }with note "The Guide item usesas MobileScreencast and the handleNavigate function will need a guard to handle the Guide case by navigating to /guide via window.location." The note is accurate but incomplete - it doesn't show the actual guard implementation.Why this matters: Developer implementing M5 will need to modify the
handleNavigatefunction (lines 59-62 in current HamburgerDrawer.tsx) to check for 'Guide' screen and usewindow.location.href = '/guide'instead of callingonNavigate(screen). Without the guard code in the diff or note, the implementation is left ambiguous.Suggested Fix: Add a second diff block in M5 showing the handleNavigate guard:
This is a SUGGESTION not a blocker - the Decision Log entry "Guide link as window.location in mobile hamburger" provides the reasoning, and the M5 note mentions the guard. Adding the explicit guard diff would eliminate implementation ambiguity.
[RULE 2] CLEAN: Individual section files prevent god object anti-pattern
Reviewed proposed file structure: 10 section files at ~150-250 lines JSX each (per M2/M3 requirements). Decision Log entry "Individual section component files" provides reasoning: single file would be 2000+ lines god object; individual files follow default-conventions file-creation domain (clear module boundary).
Verified against RULE 2 god object threshold: >15 public methods or >10 dependencies. Static JSX section components have 0 public methods and ~3-5 dependencies (React, MUI Typography, GuideTable, GuideScreenshot). No god object risk.
Tradeoffs section acknowledges file count cost: "18 new files vs single content file: chose modularity over fewer files". Explicit decision documented.
No RULE 2 violations. File organization is sound.
[RULE 2] CLEAN: No duplicate logic detected across section components
Reviewed M2/M3 section component requirements: shared GuideScreenshot and GuideTable components extract common patterns. Decision Log entries:
This is correct RULE 2 duplication prevention. Each section uses GuideScreenshot/GuideTable for common patterns rather than copy-pasting MUI Table code or img tags 15+ times.
No RULE 2 duplication violations.
[RULE 0] CLEAN: No unhandled error paths detected in diffs
Reviewed all code diffs in M1 and M5:
No RULE 0 violations detected.
[RULE 0] CLEAN: GuideScreenshot lazy loading prevents resource exhaustion
M4 acceptance criteria specifies "Total guide image payload under 5MB (WebP compression)" and GuideScreenshot component uses
loading="lazy"attribute. Decision Log entry: "Large page size with ~15+ screenshots -> Lazy loading with loading="lazy" attribute; WebP format reduces file sizes ~30%; images only load when scrolled into viewport".This prevents loading 15-20 images on page mount (potential 10-20MB uncompressed PNGs) which could exhaust mobile device memory or bandwidth. Lazy loading defers image fetch until scroll. WebP compression reduces payload.
Correct RULE 0 resource exhaustion mitigation.
[RULE 1] CLEAN: Responsive design coverage meets mobile + desktop requirement
M1 acceptance criteria includes "Desktop: TOC is sticky sidebar on left, content scrolls on right" and "Mobile: TOC is collapsible accordion above content". M2/M3 acceptance criteria both include "Responsive layout: content readable at 320px, 768px, 1920px".
Issue acceptance criteria requires "Responsive design: works on mobile (320px, 768px) and desktop (1920px)". Plan milestones cover all three breakpoints.
CLAUDE.md mobile + desktop requirement: "ALL features MUST be implemented and tested on BOTH mobile and desktop." Plan meets requirement.
No RULE 1 violations.
[RULE 1] CLEAN: Dark mode support via existing ThemeProvider pattern
Constraints list "Dark mode support via existing ThemeProvider (doc-derived: ThemeContext.tsx pattern)". M2 requirements include "Dark mode compatible styling using Tailwind dark: prefixes and MUI theme".
App.tsx diff wraps GuidePage in ThemeProvider (same as HomePage wrapper at lines 629-636). This provides MUI theme context and Tailwind dark mode class toggling via existing pattern.
No RULE 1 violations. Dark mode integration correct.
Considered But Not Flagged
frontend/src/pages/__tests__/GuidePage.test.tsxwhich follows existing test pattern fromfrontend/src/features/dashboard/components/__tests__/DashboardScreen.test.tsx. Correct location.useAuth0orisAuthenticatedconditional). Issue acceptance criteria: "/guide route accessible without authentication". Correct - public route like HomePage.frontend/public/docs/v2026-01-03.pdf". CLAUDE.md code completion criteria: "Old code is deleted". Plan includes cleanup step.scroll-behavior: smoothCSS or JavaScriptscrollIntoView({ behavior: 'smooth' })- trivial implementation, no RULE violations.frontend/src/pages/GuidePage/GuidePage.tsxnot "guide files"). Follows planning best practices.Verdict
PASS
All code diffs follow existing codebase patterns for routing, navigation, lazy loading, and styling. No RULE 0 (production reliability) or RULE 1 (project conformance) violations detected. RULE 2 (structural quality) is sound - shared components prevent duplication, individual section files prevent god objects. One SUGGESTION for M5 HamburgerDrawer guard implementation clarity (not a blocker - reasoning is in Decision Log, note mentions the guard, just missing explicit diff).
Mobile + desktop responsive design covered (320px, 768px, 1920px). Dark mode via ThemeProvider. Touch targets >= 44px. Lazy loading prevents resource exhaustion. Tests deferred to M5 with valid reason. No unhandled error paths.
Recommended action: Plan is approved for implementation. Optional: Address SUGGESTION for HamburgerDrawer guard diff block to eliminate implementation ambiguity.
Next: QR plan-docs review
Milestone: M5 Navigation Integration and Tests
Phase: Execution | Agent: Developer | Status: PASS
Completed
window.location.hrefguard (bypasses Zustand navigation since/guideis outside/garage/*shell)frontend/src/pages/__tests__/GuidePage.test.tsx:frontend/public/docs/v2026-01-03.pdfQuality Checks
Commit
197aedafeat: add guide navigation integration and tests (refs #203)Verdict: PASS | Next: M6 Documentation
Milestone: M6 Documentation
Phase: Execution | Agent: Developer | Status: PASS
Completed
frontend/src/pages/GuidePage/CLAUDE.mdwith:frontend/src/pages/CLAUDE.mdindex referencing GuidePage/, HomePage/, admin/, and page-level filesCommit
b047199docs: add GuidePage documentation (refs #203)Overall Milestone Status
864da556196ebf6196ebf197aedab047199Verdict: PASS | Next: M4 screenshots (user responsibility), then PR