Files
Ready2Blob/.planning/phases/05-tech-debt/05-01-PLAN.md
T
kawaandClaude Sonnet 4.6 0a0a51b45a docs(05-tech-debt): create phase 5 plan — 4 plans across 2 waves
Wave 0 TDD stubs, Wave 1 parallel (registry + ReviewStep), Wave 2 act() fix.
Covers TECH-01 through TECH-05.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 09:26:17 +02:00

249 lines
11 KiB
Markdown

---
phase: 05-tech-debt
plan: "01"
type: execute
wave: 1
depends_on:
- "05-00"
files_modified:
- src/schemas/registry.ts
- src/schemas/index.ts
- src/components/wizard/RemoteConfigStep.tsx
- src/components/wizard/BackendSelectionStep.tsx
autonomous: true
requirements:
- TECH-03
- TECH-04
must_haves:
truths:
- "BACKEND_REGISTRY entries each have displayName, description, and fields properties"
- "BackendSelectionStep renders cards using Object.entries(BACKEND_REGISTRY) — no hardcoded BACKENDS array"
- "All consumers of BACKEND_REGISTRY access field arrays via .fields"
- "BackendFormValues<T> export is absent from src/schemas/index.ts"
- "TypeScript compiles with zero errors after changes"
artifacts:
- path: "src/schemas/registry.ts"
provides: "Enriched BACKEND_REGISTRY with displayName, description, fields"
contains: "displayName"
- path: "src/components/wizard/BackendSelectionStep.tsx"
provides: "Registry-driven card list"
contains: "Object.entries(BACKEND_REGISTRY)"
key_links:
- from: "src/schemas/registry.ts"
to: "src/schemas/index.ts"
via: "buildZodSchema accesses BACKEND_REGISTRY[backendType].fields"
pattern: "\\.fields"
- from: "src/schemas/registry.ts"
to: "src/components/wizard/RemoteConfigStep.tsx"
via: "field iteration uses BACKEND_REGISTRY[backendType].fields"
pattern: "BACKEND_REGISTRY\\[backendType\\]\\.fields"
- from: "src/schemas/registry.ts"
to: "src/components/wizard/BackendSelectionStep.tsx"
via: "Object.entries(BACKEND_REGISTRY) replaces BACKENDS const"
pattern: "Object\\.entries\\(BACKEND_REGISTRY\\)"
---
<objective>
Enrich BACKEND_REGISTRY with display metadata, wire BackendSelectionStep to derive its card list from the registry, update all consumers to use .fields access, and remove the dead BackendFormValues<T> export.
Purpose: TECH-03 makes the registry the single source of truth for both field definitions AND display metadata — Phase 6 backend additions auto-surface with zero additional UI code. TECH-04 removes dead code.
Output: registry.ts with new shape, BackendSelectionStep.tsx driven by registry, schemas/index.ts clean.
</objective>
<execution_context>
@C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md
@C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/05-tech-debt/05-CONTEXT.md
@.planning/phases/05-tech-debt/05-RESEARCH.md
@.planning/phases/05-tech-debt/05-00-SUMMARY.md
<interfaces>
<!-- Extracted from codebase — executor uses these directly -->
From src/schemas/registry.ts (CURRENT shape — executor REPLACES this):
```typescript
export type BackendType = 'azureblob' | 's3' | 's3-compatible';
export interface FieldDef { key, label, inputType, required, placeholder?, helpText?, options? }
export const BACKEND_REGISTRY: Record<BackendType, FieldDef[]> = { ... }
```
New shape (TECH-03 target):
```typescript
export const BACKEND_REGISTRY: Record<BackendType, {
displayName: string;
description: string;
fields: FieldDef[];
}> = {
azureblob: {
displayName: 'Azure Blob Storage',
description: 'Microsoft Azure cloud storage',
fields: [ /* existing FieldDef[] content unchanged */ ],
},
s3: {
displayName: 'Amazon S3',
description: 'AWS Simple Storage Service',
fields: [ /* existing FieldDef[] content unchanged */ ],
},
's3-compatible': {
displayName: 'S3-Compatible',
description: 'Wasabi, MinIO, Cloudflare R2, and others',
fields: [ /* existing FieldDef[] content unchanged */ ],
},
};
```
Display strings MUST match existing BackendSelectionStep card text exactly (test assertions check these strings).
From src/schemas/index.ts line 10 (consumer 1 — must update):
```typescript
const fields = BACKEND_REGISTRY[backendType]; // CHANGE TO: BACKEND_REGISTRY[backendType].fields
```
From src/components/wizard/RemoteConfigStep.tsx (consumers 2 and 3 — must update):
```typescript
// Line 58: BACKEND_REGISTRY.azureblob.find(f => f.key === 'account')
// CHANGE TO: BACKEND_REGISTRY.azureblob.fields.find(f => f.key === 'account')
// Line 73: BACKEND_REGISTRY[backendType].map(field => ...)
// CHANGE TO: BACKEND_REGISTRY[backendType].fields.map(field => ...)
```
From src/components/wizard/BackendSelectionStep.tsx (TECH-03 — replace hardcoded BACKENDS):
```typescript
// Remove: const BACKENDS: { type: BackendType; name: string; description: string }[] = [...]
// Replace rendering with:
import { BACKEND_REGISTRY } from '../../schemas/registry';
// ...
{Object.entries(BACKEND_REGISTRY).map(([type, entry]) => (
<BackendCard
key={type}
name={entry.displayName}
description={entry.description}
selected={state.remote.backendType === type}
onClick={() => handleCardClick(type as BackendType)}
/>
))}
```
From src/schemas/index.ts lines 27-28 (TECH-04 — remove entirely):
```typescript
// REMOVE these two lines:
export type BackendFormValues<T extends BackendType> =
z.infer<typeof BACKEND_SCHEMAS[T]>;
```
</interfaces>
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Enrich BACKEND_REGISTRY and update all consumers</name>
<files>src/schemas/registry.ts, src/schemas/index.ts, src/components/wizard/RemoteConfigStep.tsx</files>
<behavior>
- registry.test.ts 'each backend entry has displayName and description metadata' passes
- registry.test.ts 'each backend has at least one field definition' passes (via .fields.length)
- registry.test.ts 'Azure Blob has account field' passes (via .fields.find)
- schemas/index.ts buildZodSchema receives FieldDef[] from .fields — all BACKEND_SCHEMAS build correctly
- RemoteConfigStep renders fields correctly (existing RemoteConfigStep.test.tsx passes)
</behavior>
<action>
1. Edit src/schemas/registry.ts:
- Change BACKEND_REGISTRY value type from `FieldDef[]` to `{ displayName: string; description: string; fields: FieldDef[] }`
- Wrap each backend's existing FieldDef array in the new object shape, adding displayName and description
- displayName and description strings MUST match the existing BACKENDS array in BackendSelectionStep.tsx exactly:
- azureblob: displayName='Azure Blob Storage', description='Microsoft Azure cloud storage'
- s3: displayName='Amazon S3', description='AWS Simple Storage Service'
- s3-compatible: displayName='S3-Compatible', description='Wasabi, MinIO, Cloudflare R2, and others'
- All existing FieldDef content is preserved unchanged inside fields
2. Edit src/schemas/index.ts line 10:
- Change `const fields = BACKEND_REGISTRY[backendType];` to `const fields = BACKEND_REGISTRY[backendType].fields;`
3. Edit src/components/wizard/RemoteConfigStep.tsx:
- Line 58: Change `BACKEND_REGISTRY.azureblob.find(f => f.key === 'account')` to `BACKEND_REGISTRY.azureblob.fields.find(f => f.key === 'account')`
- Line 73: Change `BACKEND_REGISTRY[backendType].map(field =>` to `BACKEND_REGISTRY[backendType].fields.map(field =>`
</action>
<verify>
<automated>cd /c/Users/SebastienQUEROL/Documents/projets/Ready2Blob && npx vitest run src/schemas/registry.test.ts src/components/wizard/RemoteConfigStep.test.tsx 2>&1 | tail -15</automated>
</verify>
<done>
registry.test.ts passes with all tests green (including new displayName/description test and .fields access tests).
RemoteConfigStep.test.tsx still passes.
TypeScript sees no errors on the modified files.
</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Wire BackendSelectionStep to registry + remove dead export</name>
<files>src/components/wizard/BackendSelectionStep.tsx, src/schemas/index.ts</files>
<behavior>
- BackendSelectionStep renders 'Azure Blob Storage', 'Amazon S3', 'S3-Compatible' cards (from registry, not hardcoded)
- Azure Blob card appears before S3 in DOM order (Object.entries insertion order preserved)
- Clicking a card with a valid remote name still dispatches SET_BACKEND_TYPE and SET_STEP (existing WIZD-01 test passes)
- BackendFormValues<T> type is absent from src/schemas/index.ts
- npx tsc --noEmit exits with code 0
</behavior>
<action>
1. Edit src/components/wizard/BackendSelectionStep.tsx:
- Add import: `import { BACKEND_REGISTRY } from '../../schemas/registry';`
- Remove the `BACKENDS` constant entirely (lines 21-37)
- In the JSX rendering section, replace `{BACKENDS.map((backend) => (` block with:
```tsx
{Object.entries(BACKEND_REGISTRY).map(([type, entry]) => (
<BackendCard
key={type}
name={entry.displayName}
description={entry.description}
selected={state.remote.backendType === type}
onClick={() => handleCardClick(type as BackendType)}
/>
))}
```
- Remove the now-unused local type import for BackendType from '../../store/types' IF it is only used by the BACKENDS const (check — it may still be needed for pendingBackend.current type annotation). If BackendType is still needed, keep the import.
2. Edit src/schemas/index.ts:
- Remove lines 27-28: the `export type BackendFormValues<T extends BackendType> = z.infer<typeof BACKEND_SCHEMAS[T]>;` export
- Also remove the blank comment line above it (line 26: `// Utility type: infer TypeScript type from a backend's Zod schema`) to avoid orphan comment
3. Run TypeScript check to confirm no consumers of BackendFormValues exist:
`npx tsc --noEmit`
</action>
<verify>
<automated>cd /c/Users/SebastienQUEROL/Documents/projets/Ready2Blob && npx vitest run src/components/wizard/BackendSelectionStep.test.tsx && npx tsc --noEmit 2>&1 | tail -10</automated>
</verify>
<done>
BackendSelectionStep.test.tsx passes (WIZD-01 card text assertions still green — display strings match).
npx tsc --noEmit exits with zero errors.
BackendFormValues export is absent from src/schemas/index.ts.
</done>
</task>
</tasks>
<verification>
Full suite green except pre-existing RED stubs (TECH-01, TECH-02 ReviewStep stubs remain RED — implemented in Plan 02):
```
cd /c/Users/SebastienQUEROL/Documents/projets/Ready2Blob && npx vitest run && npx tsc --noEmit
```
Expected: All registry tests green, all BackendSelectionStep tests green, RemoteConfigStep tests green. Only TECH-01/TECH-02 ReviewStep stubs still RED.
</verification>
<success_criteria>
- BACKEND_REGISTRY shape is `Record<BackendType, { displayName, description, fields: FieldDef[] }>`
- BackendSelectionStep uses `Object.entries(BACKEND_REGISTRY)` — no hardcoded BACKENDS array
- schemas/index.ts uses `.fields` access and has no BackendFormValues export
- RemoteConfigStep uses `.fields` access
- registry.test.ts fully green
- BackendSelectionStep.test.tsx fully green
- npx tsc --noEmit: zero errors
</success_criteria>
<output>
After completion, create `.planning/phases/05-tech-debt/05-01-SUMMARY.md`
</output>