docs(07): create phase plan — 3 plans for VALID-01 and UX-01
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
---
|
||||
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>
|
||||
Reference in New Issue
Block a user