chore: complete v1.3 milestone — Backend Expansion
Archives v1.3 milestone (Phase 13: 18 rclone backends), updates PROJECT.md with all 30 validated requirements, reorganizes ROADMAP.md with all 4 milestones in collapsed details blocks, adds v1.2 and v1.3 retrospective entries. Also commits minor CSS token fixes in src/ (text-on-surface-container class alignment) that were uncommitted from phase 13 execution. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,83 @@
|
||||
|
||||
---
|
||||
|
||||
## Milestone: v1.2 — UI Polish & Clarity
|
||||
|
||||
**Shipped:** 2026-04-01
|
||||
**Phases:** 5 (8–12) | **Plans:** 14 | **Stats:** 78 files, +9,908 / -287 lines
|
||||
|
||||
### What Was Built
|
||||
- Full MD3 color token system in a single token file; all components use semantic utility classes (`bg-surface`, `text-on-primary`) instead of hardcoded Tailwind colors
|
||||
- System/Light/Dark theme toggle persisted in localStorage with zero flash of unstyled content (DOM class toggle, not React Context)
|
||||
- TextFieldMD3 with CSS-only floating label, MD3 button hierarchy constants, rebuilt StepIndicator with numbered circles + checkmarks + connectors
|
||||
- App intro section, step descriptions on all 4 steps, remote name live config preview, contextual help/tooltip enrichment across all credential fields
|
||||
- Mobile-responsive layout, `focus-visible` ring-3 indicators, step fade/slide transition with `prefers-reduced-motion` guard, auto-scroll to first validation error
|
||||
- Dark mode visibility fixes: semantic tokens on select, h2 headings, DeploymentStep form controls, ReviewStep security checkbox
|
||||
|
||||
### What Worked
|
||||
- **Bottom-up migration order** (tokens → primitives → content → polish → fixes): each phase stood on solid ground from the one below; no circular rework
|
||||
- **CSS-only floating label** (`peer-[:not(:placeholder-shown)]`) with no JS state — simpler to reason about, trivially animatable, one fewer React state variable
|
||||
- **DOM class toggle for dark mode** (not React Context): theme switch is instant and doesn't trigger a re-render cascade across 150+ components
|
||||
- **`key={state.currentStep}` on step wrapper**: one-line way to force React remount and reset CSS animation to initial state — no animation JS state needed
|
||||
- **TDD discipline held** on Phase 12 dark mode fixes: found and fixed selector issues before they became regressions
|
||||
|
||||
### What Was Inefficient
|
||||
- **Phase 12 inserted as a gap fix**: dark mode regressions were discovered post-Phase 11 instead of being caught in Phase 11 validation — cost 1 extra phase
|
||||
- **`aria-label` / `getByLabelText` selector ambiguity** recurred across Phases 9, 10, and 12 — the DEBT-01 pattern (`{ selector: 'input' }`) had to be applied three times in three different phases instead of being resolved once and documented
|
||||
- **Traceability table in REQUIREMENTS.md not updated** as plans completed — table showed "Planned" for completed items, causing confusion at milestone close
|
||||
|
||||
### Patterns Established
|
||||
- Two-layer CSS token pattern: `@theme var()` references + `@layer base :root/.dark` raw values — required for `.dark` cascade in Tailwind v4
|
||||
- `vi.stubGlobal` for localStorage/matchMedia — Node v25 experimental WebStorage breaks standard Storage API in jsdom
|
||||
- CSS-only reduced-motion guard via `@media (prefers-reduced-motion: reduce)` — no JS listener needed
|
||||
- Tooltip hover: dual-state (`hoverTooltip` + `showTooltip`); click-unpin clears `hoverTooltip` to prevent sticky tooltip after dismiss
|
||||
- `ring-inset` on ThemeToggle focus ring because `overflow-hidden` on container clips outset rings
|
||||
|
||||
### Key Lessons
|
||||
1. **Validate dark mode in every phase, not as a separate cleanup phase**: each component migration should include a dark-mode check, not defer it
|
||||
2. **When a test selector pattern is discovered, document it once and reference it** — the `{ selector: 'input' }` guard should have been in a testing conventions note from Phase 9
|
||||
3. **Keep traceability tables current** during execution, not just at planning time
|
||||
|
||||
---
|
||||
|
||||
## Milestone: v1.3 — Backend Expansion
|
||||
|
||||
**Shipped:** 2026-04-16
|
||||
**Phases:** 1 (13) | **Plans:** 4 | **Stats:** 28 files, +3,959 / -206 lines
|
||||
|
||||
### What Was Built
|
||||
- BACKEND_REGISTRY expanded from 7 → 18 backends; `BackendType` derived from `keyof typeof BACKEND_REGISTRY` — no manual union to maintain
|
||||
- `BACKEND_SCHEMAS` auto-generated from registry keys via `Object.fromEntries` — zero per-backend boilerplate
|
||||
- `OAuthInstructions` collapsible component with backend-specific `rclone authorize` commands (TDD, 4 tests)
|
||||
- `GdriveAuthToggle` dual-auth component (OAuth token vs service account) — CSS hidden pattern extended from SftpAuthToggle
|
||||
- `BackendSelectionStep` with 3 category groups, instant search filtering across 4 fields, inline SVG icons
|
||||
- `RemoteConfigStep` wired for all 18 backends via clean `renderBackendFields()` switch function; `backendLabel` derived from registry
|
||||
|
||||
### What Worked
|
||||
- **`as const` registry with derived BackendType**: one touch-point when adding a backend (registry entry only); Zod schemas auto-generate, type union auto-narrows
|
||||
- **Incremental plan structure** (registry → components → UI → wiring): each plan had exactly the right scope — no plan was too large or too small
|
||||
- **TDD for new UI components**: `OAuthInstructions` and `GdriveAuthToggle` written test-first; caught a step-prefix detection edge case before integration
|
||||
- **type=search for search input**: simple attribute that prevents `getByRole('textbox')` collision — elegant selector discipline
|
||||
- **renderBackendFields() switch**: 7+ backend branches are unreadable as nested ternaries; switch is flat and extensible
|
||||
|
||||
### What Was Inefficient
|
||||
- **Registry had 18 backends but plan said 17**: a counting error in the plan caused minor confusion during 13-01 execution — plans should verify counts against reality
|
||||
- **Traceability table not updated** (same as v1.2) — REMOTE-03/04/05 showed "Planned" at milestone close despite being complete
|
||||
|
||||
### Patterns Established
|
||||
- `BackendType` from `keyof typeof BACKEND_REGISTRY` (not explicit union) — the canonical pattern going forward
|
||||
- `BACKEND_SCHEMAS` from `Object.fromEntries` — zero per-backend call sites
|
||||
- Registry `as const` (not `Record<BackendType,…>` cast) — cast is circular when BackendType derived from registry
|
||||
- `Partial<Record<BackendType, FC<IconProps>>>` for optional icon map — missing entries render nothing (no error)
|
||||
- `getByLabelText` partial regex (`/label/i` not `/^label$/i`) — TextFieldMD3 appends `*` to required field labels
|
||||
|
||||
### Key Lessons
|
||||
1. **Update the traceability table as plans complete**, not just at the start — stale status fields caused confusion at milestone close (2nd occurrence after v1.2)
|
||||
2. **Count registry entries in the plan, not just at planning time** — the 17/18 mismatch was avoidable
|
||||
3. **`as const` registries with derived types are strictly superior to explicit unions**: eliminates an entire class of drift bugs, zero cost
|
||||
|
||||
---
|
||||
|
||||
## Cross-Milestone Trends
|
||||
|
||||
### Process Evolution
|
||||
@@ -48,14 +125,23 @@
|
||||
| Milestone | Phases | Plans | Key Change |
|
||||
|-----------|--------|-------|------------|
|
||||
| v1.0 | 4 | 18 | Wave 0 TDD pattern established; inside-out build order validated |
|
||||
| v1.1 | 3 | 11 | CSS-hidden auth toggle pattern; FieldDef additive extension model |
|
||||
| v1.2 | 5 | 14 | Two-layer CSS token system; DOM class dark mode; CSS-only floating label |
|
||||
| v1.3 | 1 | 4 | `keyof typeof` derived BackendType; `Object.fromEntries` schema auto-gen |
|
||||
|
||||
### Cumulative Quality
|
||||
|
||||
| Milestone | Tests | Notes |
|
||||
|-----------|-------|-------|
|
||||
| v1.0 | 98 (12 files) | 24/24 requirements satisfied, 5/5 E2E flows |
|
||||
| v1.1 | 159 (18 files) | 7 browser UI verifications deferred |
|
||||
| v1.2 | 159+ (same files, heavier coverage) | All DEBT-01 + POLISH/DARK/UX requirements satisfied |
|
||||
| v1.3 | 165+ | All 6 REMOTE requirements satisfied; visual verification approved |
|
||||
|
||||
### Top Lessons (Verified Across Milestones)
|
||||
|
||||
1. Single source of truth (BACKEND_REGISTRY) eliminates entire classes of drift bugs
|
||||
1. Single source of truth (BACKEND_REGISTRY) eliminates entire classes of drift bugs — validated at v1.0, proven at v1.3 scale (18 backends)
|
||||
2. Wave 0 TDD stubs are worth the upfront cost — they define the contract and make RED→GREEN progress visible
|
||||
3. **Update traceability tables as plans complete** — stale status fields caused confusion at both v1.2 and v1.3 milestone close (recurring issue)
|
||||
4. CSS-only approaches (floating label, reduced-motion guard, auth toggle) are simpler than JS state — reach for CSS first
|
||||
5. `as const` registries with derived types (`keyof typeof`) are strictly superior to explicit unions — zero drift possible
|
||||
|
||||
Reference in New Issue
Block a user