210 lines
8.1 KiB
Markdown
210 lines
8.1 KiB
Markdown
---
|
||
phase: 07-validation-ux-polish
|
||
plan: "01"
|
||
type: execute
|
||
wave: 2
|
||
depends_on:
|
||
- "07-00"
|
||
files_modified:
|
||
- src/schemas/registry.ts
|
||
- src/schemas/index.ts
|
||
autonomous: true
|
||
requirements:
|
||
- VALID-01
|
||
|
||
must_haves:
|
||
truths:
|
||
- "User who enters 'MyStorage' in the Azure account name field sees an inline error before advancing"
|
||
- "User who enters 'us east 1' in the S3 region field sees an inline error"
|
||
- "User who enters 'abc' in the GCS project_number field sees an inline error"
|
||
- "Valid values ('mystorageaccount', 'us-east-1', '123456789') produce no format error"
|
||
- "Empty required fields still show 'required' error (not the regex error) — empty string hits min(1) before regex"
|
||
- "All 147 pre-existing tests still pass after adding validation"
|
||
artifacts:
|
||
- path: "src/schemas/registry.ts"
|
||
provides: "FieldDef interface with validate property; 3 registry entries with validate rules"
|
||
contains: "validate\\?: \\{ regex: RegExp; message: string \\}"
|
||
- path: "src/schemas/index.ts"
|
||
provides: "buildZodSchema() chains .regex() when field.validate is present"
|
||
contains: "field\\.validate"
|
||
key_links:
|
||
- from: "BACKEND_REGISTRY azureblob.account"
|
||
to: "buildZodSchema('azureblob')"
|
||
via: "field.validate.regex applied as .regex() on ZodString"
|
||
pattern: "field\\.validate"
|
||
- from: "buildZodSchema()"
|
||
to: "BACKEND_SCHEMAS"
|
||
via: "Zod schema exported, consumed by zodResolver in RemoteConfigStep"
|
||
---
|
||
|
||
<objective>
|
||
Implement VALID-01: extend FieldDef with a validate property, add regex rules to 3 registry entries (azureblob account, s3 region, gcs project_number), and extend buildZodSchema() to chain .regex() when the property is present.
|
||
|
||
Purpose: Users see inline format errors on malformed credential fields before they can advance in the wizard.
|
||
Output: Modified registry.ts (FieldDef + 3 validate rules) and index.ts (buildZodSchema regex chaining).
|
||
</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/07-validation-ux-polish/07-CONTEXT.md
|
||
@.planning/phases/07-validation-ux-polish/07-RESEARCH.md
|
||
@.planning/phases/07-validation-ux-polish/07-00-SUMMARY.md
|
||
|
||
<interfaces>
|
||
<!-- Extracted from codebase. Executor uses these directly. -->
|
||
|
||
Current FieldDef (src/schemas/registry.ts):
|
||
```typescript
|
||
export interface FieldDef {
|
||
key: string;
|
||
label: string;
|
||
inputType: 'text' | 'password' | 'select' | 'toggle';
|
||
required: boolean;
|
||
placeholder?: string;
|
||
helpText?: string;
|
||
options?: { value: string; label: string }[];
|
||
// validate and tooltipText DO NOT EXIST YET
|
||
}
|
||
```
|
||
|
||
Current buildZodSchema (src/schemas/index.ts):
|
||
```typescript
|
||
function buildZodSchema(backendType: BackendType): z.ZodObject<Record<string, z.ZodTypeAny>> {
|
||
const fields = BACKEND_REGISTRY[backendType].fields;
|
||
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);
|
||
}
|
||
```
|
||
|
||
Zod v4 important: cast to (schema as z.ZodString).regex(...) because schema variable is typed ZodTypeAny.
|
||
Zod v4 chaining order: .min(1).regex() is correct for required fields. .regex().optional() for optional (not needed here — all 3 validated fields are required).
|
||
</interfaces>
|
||
</context>
|
||
|
||
<tasks>
|
||
|
||
<task type="auto" tdd="true">
|
||
<name>Task 1: Extend FieldDef and add validate rules to 3 registry entries</name>
|
||
<files>src/schemas/registry.ts</files>
|
||
<behavior>
|
||
- Adding validate to azureblob.account and submitting 'ABC' produces Zod error 'Must be 3–24 lowercase alphanumeric characters'
|
||
- Adding validate to s3.region and submitting 'us east 1' produces Zod error matching region format
|
||
- Adding validate to gcs.project_number and submitting 'abc' produces Zod error 'digits only' (or similar)
|
||
- Submitting '' on account still produces the required error (not the regex error) — min(1) fires first
|
||
</behavior>
|
||
<action>
|
||
1. Add two optional properties to FieldDef interface:
|
||
```typescript
|
||
validate?: { regex: RegExp; message: string };
|
||
tooltipText?: string; // also add here for Plan 02 — it's just an interface addition, no behavior yet
|
||
```
|
||
Note: Adding tooltipText here avoids a second interface-only edit in Plan 02.
|
||
|
||
2. In BACKEND_REGISTRY, locate the azureblob `account` field entry and add:
|
||
```typescript
|
||
validate: {
|
||
regex: /^[a-z0-9]{3,24}$/,
|
||
message: 'Must be 3–24 lowercase alphanumeric characters (no hyphens or uppercase)',
|
||
},
|
||
```
|
||
|
||
3. Locate the s3 `region` field entry and add:
|
||
```typescript
|
||
validate: {
|
||
regex: /^[a-z][a-z0-9-]+[a-z0-9]$/,
|
||
message: 'Must be a valid AWS region format (e.g. us-east-1)',
|
||
},
|
||
```
|
||
|
||
4. Locate the gcs `project_number` field entry and add:
|
||
```typescript
|
||
validate: {
|
||
regex: /^\d+$/,
|
||
message: 'Must contain digits only',
|
||
},
|
||
```
|
||
|
||
No other fields get validate rules — user decision is explicit on scope.
|
||
</action>
|
||
<verify>
|
||
<automated>npx vitest run src/components/wizard/RemoteConfigStep.test.tsx</automated>
|
||
</verify>
|
||
<done>FieldDef has validate and tooltipText properties. 3 registry entries have validate rules. TypeScript compiles without errors (npx tsc --noEmit).</done>
|
||
</task>
|
||
|
||
<task type="auto" tdd="true">
|
||
<name>Task 2: Extend buildZodSchema() to chain .regex() from field.validate</name>
|
||
<files>src/schemas/index.ts</files>
|
||
<behavior>
|
||
- buildZodSchema('azureblob') produces a schema where the account field rejects 'ABC' with the registry message
|
||
- buildZodSchema('s3') produces a schema where the region field rejects 'us east 1'
|
||
- buildZodSchema('gcs') produces a schema where project_number rejects 'abc'
|
||
- buildZodSchema('onedrive') and others without validate are unaffected
|
||
- VALID-01 failing tests from Plan 00 now PASS
|
||
</behavior>
|
||
<action>
|
||
Replace the buildZodSchema loop body with the regex-aware version:
|
||
|
||
```typescript
|
||
function buildZodSchema(backendType: BackendType): z.ZodObject<Record<string, z.ZodTypeAny>> {
|
||
const fields = BACKEND_REGISTRY[backendType].fields;
|
||
const shape: Record<string, z.ZodTypeAny> = {};
|
||
for (const field of fields) {
|
||
let schema: z.ZodTypeAny = field.required
|
||
? z.string().min(1, `${field.label} is required`)
|
||
: z.string();
|
||
|
||
if (field.validate) {
|
||
schema = (schema as z.ZodString).regex(field.validate.regex, field.validate.message);
|
||
}
|
||
|
||
if (!field.required) {
|
||
schema = (schema as z.ZodString).optional();
|
||
}
|
||
|
||
shape[field.key] = schema;
|
||
}
|
||
return z.object(shape);
|
||
}
|
||
```
|
||
|
||
Critical: cast to (schema as z.ZodString) before .regex() — ZodTypeAny does not expose .regex() in TypeScript but it is present at runtime. This pattern is verified.
|
||
Do NOT touch BACKEND_SCHEMAS export or anything else in the file.
|
||
</action>
|
||
<verify>
|
||
<automated>npx vitest run src/components/wizard/RemoteConfigStep.test.tsx</automated>
|
||
</verify>
|
||
<done>VALID-01 tests from Plan 00 all pass (GREEN). Full suite still at 147+ pass with 0 failures: `npx vitest run`.</done>
|
||
</task>
|
||
|
||
</tasks>
|
||
|
||
<verification>
|
||
1. `npx tsc --noEmit` — no TypeScript errors
|
||
2. `npx vitest run src/components/wizard/RemoteConfigStep.test.tsx` — VALID-01 tests pass (GREEN), UX-01 stubs still fail (expected — UX-01 is Plan 02)
|
||
3. `npx vitest run` — all pre-existing 147 tests pass, no regressions
|
||
</verification>
|
||
|
||
<success_criteria>
|
||
- FieldDef has validate and tooltipText properties
|
||
- 3 registry entries (azureblob.account, s3.region, gcs.project_number) have validate rules with the exact regexes from CONTEXT.md
|
||
- buildZodSchema() chains .regex() when field.validate is present
|
||
- VALID-01 test stubs from Plan 00 all pass
|
||
- Full test suite passes
|
||
</success_criteria>
|
||
|
||
<output>
|
||
After completion, create `.planning/phases/07-validation-ux-polish/07-01-SUMMARY.md`
|
||
</output>
|