# Adoption POC — consumer form + API (G1/G2) **Version:** smart-value-objects **4.0.0** **Date:** 2026-08-03 **Goal:** Prove a consumer app replaces primitives and shares the same validation rules in form and API. ## Scenario A profile form collects `title`, `name`, and `email`. Rules must match on: - Client submit handler - Server POST handler - UI `maxLength` bindings ## Before (primitive obsession) ```typescript type ProfileDto = { title: string; name: string; email: string; }; // Front: maxLength={255} invented locally // Back: if (!email.includes('@')) throw ... // Rules drift between layers ``` ## After (catalog + shared schema) ```typescript import type { ValidateRecordSchema } from 'smart-value-objects'; import { EmailAddress, PersonName, Title } from 'smart-value-objects'; export const profileFormSchema: ValidateRecordSchema = { title: Title.tryCreate, name: PersonName.tryCreate, email: EmailAddress.tryCreate, }; ``` Import **the same** `profileFormSchema` in both handlers — see `examples/consumer-form-api/`. ## G1 — Encapsulate primitives | Field | Before | After | |-------|--------|-------| | title | `string` | validated via `Title.tryCreate` → domain type at boundary | | name | `string` | `PersonName.tryCreate` | | email | `string` | `EmailAddress.tryCreate` | Persist JSON with `getValue()` when crossing the wire. ## G2 — Same rules front and back ```typescript import { Title, PersonName, EmailAddress } from 'smart-value-objects'; // 120 // 80 // 254 ``` Never copy limits from README — read `X.constraints`. ## G3 — Aggregated errors Both handlers call `validateRecord(input, profileFormSchema)` and return **all** field errors: ```typescript const validation = validateRecord(body, profileFormSchema); if (!validation.isValid) { return { status: 400, errors: validation.errors }; } ``` Run the proof in-repo: ```bash npm test -- examples/consumer-form-api ``` ## Agent session (Cursor skill) 1. Install: `npm install smart-value-objects@^4.0.0` 2. Copy skill: `cp -r node_modules/smart-value-objects/skills/smart-value-objects-consumer .cursor/skills/` 3. Agent loads skill when editing consumer DTOs/forms 4. Agent must **not** use local regex for catalog types or invent `maxLength` **Anti-pattern blocked:** `email: string` with inline `/^...$/` **Required pattern:** `EmailAddress.tryCreate(raw, 'email')` + `EmailAddress.constraints` ## Checklist (roadmap metric) | Metric | Status | |--------|--------| | VOs Must shipped (Email, Title, PersonName, Uuid) | Done in 4.0.0 | | Form + API same `validateRecord` | `examples/consumer-form-api/` | | UI limits from `constraints` | Documented above | | Skill in npm tarball | `skills/smart-value-objects-consumer/` | | npm `latest` = 4.0.0 | Published | ## Next (P1 backlog) - `@smart-value-objects/zod` adapter from `FieldConstraints` - `toFormErrors()` helper for React/Vue - Real app POC in a separate consumer repository