Files
kawa 4514fc9033 docs(01-foundation): create phase plan
4 plans across 3 waves: scaffold, registry+test stubs, Zod schemas and WizardState store (parallel wave 3).
2026-03-26 10:05:01 +01:00

6.6 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
01-foundation 03 execute 3
01-02
src/schemas/index.ts
true
truths artifacts key_links
BACKEND_SCHEMAS['azureblob'].safeParse({account: 'x'}) returns success: true
BACKEND_SCHEMAS['azureblob'].safeParse({account: ''}) returns success: false
BACKEND_SCHEMAS['s3-compatible'].safeParse({...without endpoint}) returns success: false
Zod schemas are derived programmatically from BACKEND_REGISTRY — no hand-written z.object() calls
All 12 tests in src/schemas/index.test.ts pass
path provides exports
src/schemas/index.ts BACKEND_SCHEMAS constant and BackendFormValues utility type
BACKEND_SCHEMAS
BackendFormValues
from to via pattern
src/schemas/index.ts src/schemas/registry.ts imports BACKEND_REGISTRY and BackendType to build schemas programmatically import.*BACKEND_REGISTRY.*registry
Implement the Zod schema builder that derives runtime validation schemas programmatically from the Backend Schema Registry.

Purpose: Schema and registry must never drift — if someone adds a field to the registry, validation automatically covers it. Writing Zod schemas by hand separate from the registry breaks this invariant. Output: src/schemas/index.ts with BACKEND_SCHEMAS and BackendFormValues type — all 12 tests in src/schemas/index.test.ts pass.

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

@.planning/PROJECT.md @.planning/phases/01-foundation/01-02-SUMMARY.md ```typescript export type BackendType = 'azureblob' | 's3' | 's3-compatible';

export interface FieldDef { key: string; label: string; inputType: 'text' | 'password' | 'select' | 'toggle'; required: boolean; placeholder?: string; helpText?: string; options?: { value: string; label: string }[]; }

export const BACKEND_REGISTRY: Record<BackendType, FieldDef[]>; // azureblob fields: account (required), key (optional), sas_url (optional) // s3 fields: provider (required), access_key_id (required), secret_access_key (required), region (required) // s3-compatible fields: provider (required), access_key_id (required), secret_access_key (required), endpoint (required), region (optional)


<!-- Test expectations from src/schemas/index.test.ts (created in Plan 02) -->
<!-- BACKEND_SCHEMAS.azureblob.safeParse({account: 'x'}) → success: true -->
<!-- BACKEND_SCHEMAS.azureblob.safeParse({account: ''}) → success: false -->
<!-- BACKEND_SCHEMAS.azureblob.safeParse({key: 'x'}) (no account) → success: false -->
<!-- BACKEND_SCHEMAS.s3.safeParse({provider,access_key_id,secret_access_key,region}) → success: true -->
<!-- BACKEND_SCHEMAS.s3.safeParse({...missing access_key_id}) → success: false -->
<!-- BACKEND_SCHEMAS['s3-compatible'].safeParse({...with endpoint}) → success: true -->
<!-- BACKEND_SCHEMAS['s3-compatible'].safeParse({...without endpoint}) → success: false -->
</interfaces>
</context>

<tasks>

<task type="auto" tdd="true">
  <name>Task 1: Implement schema builder and BACKEND_SCHEMAS</name>
  <files>src/schemas/index.ts</files>
  <behavior>
    - buildZodSchema(backendType) constructs a z.object() from BACKEND_REGISTRY[backendType]
    - required fields → z.string().min(1, '{label} is required')
    - optional fields → z.string().optional()
    - BACKEND_SCHEMAS is a const object keyed by BackendType
    - BackendFormValues<T> infers the TypeScript type from the schema using z.infer
    - No z.object() calls hardcoded with field names — all field shapes derived from the registry loop
  </behavior>
  <action>
    Run the failing test first to confirm RED state:
    ```
    npx vitest run src/schemas/index.test.ts
    ```
    Expected: "Cannot find module './index'" error.

    Create src/schemas/index.ts:

    ```typescript
    // src/schemas/index.ts
    // Zod schemas derived programmatically from the Backend Schema Registry.
    // DO NOT hand-write z.object() calls with hardcoded field names — all shapes come from the registry.
    // Adding a field to BACKEND_REGISTRY automatically adds it to validation.

    import { z } from 'zod';
    import { BACKEND_REGISTRY, BackendType } from './registry';

    function buildZodSchema(backendType: BackendType): z.ZodObject<Record<string, z.ZodTypeAny>> {
      const fields = BACKEND_REGISTRY[backendType];
      const shape: Record<string, z.ZodTypeAny> = {};
      for (const field of fields) {
        shape[field.key] = field.required
          ? z.string().min(1, `${field.label} is required`)
          : z.string().optional();
      }
      return z.object(shape);
    }

    export const BACKEND_SCHEMAS = {
      azureblob:        buildZodSchema('azureblob'),
      s3:               buildZodSchema('s3'),
      's3-compatible':  buildZodSchema('s3-compatible'),
    } as const;

    // Utility type: infer TypeScript type from a backend's Zod schema
    export type BackendFormValues<T extends BackendType> =
      z.infer<typeof BACKEND_SCHEMAS[T]>;
    ```

    Run the tests:
    ```
    npx vitest run src/schemas/index.test.ts
    ```
    All tests must pass (GREEN). If any fail, diagnose and fix — do not move on with failing tests.

    Run the full test suite to confirm no regressions:
    ```
    npx vitest run
    ```
  </action>
  <verify>
    <automated>npx vitest run src/schemas/index.test.ts 2>&1</automated>
  </verify>
  <done>All tests in src/schemas/index.test.ts pass. BACKEND_SCHEMAS exported with entries for all three backends. BackendFormValues type exported. npx vitest run (full suite) exits 0 with registry and schema tests green.</done>
</task>

</tasks>

<verification>
1. `npx vitest run src/schemas/index.test.ts` — all tests pass (12 tests green)
2. `npx vitest run src/schemas/registry.test.ts` — still passing (no regression)
3. `npx vitest run` — full suite green for all schema tests
4. Confirm src/schemas/index.ts has no hardcoded field names in z.object() — only the loop over BACKEND_REGISTRY
</verification>

<success_criteria>
- src/schemas/index.ts creates Zod schemas by looping over BACKEND_REGISTRY field definitions
- All 12 tests in src/schemas/index.test.ts pass
- BACKEND_SCHEMAS and BackendFormValues are exported
- Full test suite (registry + index) exits 0
</success_criteria>

<output>
After completion, create `.planning/phases/01-foundation/01-03-SUMMARY.md` using the summary template.
</output>