feat: Add online user guide with screenshots to public website #203

Closed
opened 2026-02-15 19:12:19 +00:00 by egullickson · 7 comments
Owner

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
## 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
egullickson added the
status
backlog
type
feature
labels 2026-02-15 19:12:30 +00:00
egullickson added this to the Sprint 2026-02-02 milestone 2026-02-15 19:12:31 +00:00
egullickson added
status
in-progress
and removed
status
backlog
labels 2026-02-15 19:13:43 +00:00
Author
Owner

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:

--- 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:

--- 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) {
--- 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:

--- 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;
--- 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):

--- 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):

--- 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:

--- 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:

--- 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:

--- 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)

## 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)
Author
Owner

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

## 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
Author
Owner

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

## 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
Author
Owner

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:

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

## 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
Author
Owner

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:

--- 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

## 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
Author
Owner

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

## 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
Author
Owner

Milestone: M6 Documentation

Phase: Execution | Agent: Developer | Status: PASS

Completed

  • Created frontend/src/pages/GuidePage/CLAUDE.md with:
    • File/directory index with When to read guidance
    • Architecture documentation (static JSX approach, section component pattern, shared components)
    • Key patterns (anchor ID matching, lazy loading, TOC breakpoint, HamburgerDrawer navigation guard)
  • Created frontend/src/pages/CLAUDE.md index referencing GuidePage/, HomePage/, admin/, and page-level files

Commit

b047199 docs: add GuidePage documentation (refs #203)

Overall Milestone Status

Milestone Status Notes
M1: Foundation and routing DONE 864da55
M2: Sections 1-5 DONE 6196ebf
M3: Sections 6-10 DONE 6196ebf
M4: Screenshots USER User captures screenshots and updates section src paths
M5: Nav integration + tests DONE 197aeda
M6: Documentation DONE b047199

Verdict: PASS | Next: M4 screenshots (user responsibility), then PR

## Milestone: M6 Documentation **Phase**: Execution | **Agent**: Developer | **Status**: PASS ### Completed - Created `frontend/src/pages/GuidePage/CLAUDE.md` with: - File/directory index with When to read guidance - Architecture documentation (static JSX approach, section component pattern, shared components) - Key patterns (anchor ID matching, lazy loading, TOC breakpoint, HamburgerDrawer navigation guard) - Created `frontend/src/pages/CLAUDE.md` index referencing GuidePage/, HomePage/, admin/, and page-level files ### Commit `b047199` docs: add GuidePage documentation (refs #203) ### Overall Milestone Status | Milestone | Status | Notes | |-----------|--------|-------| | M1: Foundation and routing | DONE | `864da55` | | M2: Sections 1-5 | DONE | `6196ebf` | | M3: Sections 6-10 | DONE | `6196ebf` | | M4: Screenshots | USER | User captures screenshots and updates section src paths | | M5: Nav integration + tests | DONE | `197aeda` | | M6: Documentation | DONE | `b047199` | *Verdict*: PASS | *Next*: M4 screenshots (user responsibility), then PR
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: egullickson/motovaultpro#203