Use when changing Prisma models/enums, reading or writing any Json column, or adding validation for external input (API bodies / forms / env). Requires a paired zod schema per Json column, forbids raw type assertions, and defines how coordinates/rules are unpacked and how immutable versioned models may change.
Install
npx skillscat add sundaydev-arch/hrsign/schema-zod Install via the SkillsCat registry.
Skill 01: Schema and Zod conventions
When to use
- Add/change Prisma models, fields, or enums (prisma/schema.prisma)
- Read or write any
Json/Json?column - Add validation for API bodies, forms, third-party responses, or environment variables
Hard rules
Every Json column must have a matching-responsibility zod schema under src/schemas/, exported from schemas/index.ts. Current mapping:
Prisma column zod schema TemplateField.coordinates CoordinatesSchema TemplateField.validationRules template-field.ts TemplateField.labelI18n label-i18n.ts TemplateVersion.watermarkConfig watermark.ts Document.fieldValues field-values.ts AuditLog.detail audit-detail.ts WebhookDelivery.payload webhook-payload.ts NotificationLog.templateParams / NotificationTemplate.defaultParams notification.ts Signature.verificationResult signature.ts Reading Json must parse; never
f.coordinates as XxxType. Trusted data uses.parse(); external or possibly dirty data uses.safeParse()with an explicit failure path (see TemplateEditor.tsx skipping dirty fields on init).When writing Json, Prisma input types use
Prisma.InputJsonValue; do not cast toany.After adding an enum value, sync: (1)
Record<Enum, string>in labels.ts (or i18n messages) (2) everyRecord<Enum, …>mapping (TypeScript will error on missing keys; fill them; do not bypass withas). Reserved enums still need mapping values (e.g. FieldType PERFORATION_SEAL).Template versions are immutable: status/pageCount/storageKey/fields belong to TemplateVersion; field edits are allowed only on DRAFT versions (see fields/route.ts); changing a PUBLISHED version = create a new version; there is no in-place edit.
All external input goes through zod: parse API bodies as
unknown, then parse; do not trust frontend types.Do not ship implicit
db pushschema drift as a formal delivery; new fields get defaults or are nullable so historical rows stay valid.
Standard steps
- Change schema.prisma →
pnpm prisma generate(andprisma migrate dev --name xxxwhen needed; migrations need team confirmation) - For Json columns: create/update
src/schemas/xxx.tsand export from index.ts - Switch every read/write site to schema parse (grep the field name)
- Fill enum mappings;
pnpm exec tsc --noEmitmust be 0 errors
Do not
- ❌ Use
JSON.parsethen treat the result as a typed shape - ❌ Hand-write Json shapes in frontend components instead of referencing zod
- ❌ Add "patch fields" onto an already PUBLISHED version
- ❌ Casually change column types (e.g.
@db.Text) without documenting impact
Done when
- New Json columns have a paired zod schema exported from index.ts
- No new
as any/ direct assertions on Json - tsc 0 errors; enum Record mappings have no missing keys
- Delivery notes list changed files, rationale, and test points