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>
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
---
|
||||
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>
|
||||
Reference in New Issue
Block a user