Amended by 0133:
@Nullable, the semantic field types and @Stored are recorded there.
Context
With decorators as the only authoring style (0094), fields on models and action inputs need validation, input transforms and output shaping declared on the class. The Nest ecosystem uses class-validator and class-transformer, which depend onreflect-metadata (0011) and duplicate what
Zod already does for forms and the API client (0055). The IR already
converts schemas to Zod (0092). The owner asked for the class-validator and
class-transformer developer experience with Zod underneath, rather than only @Field(z…).
Decision
- A new client-safe package,
@stackra/validation, owns the validation, transform and serializer decorators.@stackra/model(0097) builds on it. It imports no ORM and no Node-only module. - Short, Laravel-style rule decorators append to a per-class schema:
@Str,@Min,@Max,@Email,@Int,@Between,@Enum,@Date,@After,@ArrayOf,@Nested,@Uuid,@Optionaland@Default.@Field(z…)is the escape hatch for anything the shorthands do not cover. - Each class compiles to one cached
z.object. That schema is the one used by actions, forms, wire types, OpenAPI, MCP tool schemas and the IR. Zod is the only validation engine. - Async rules
@Existsand@Uniquerun through a database rule driver supplied by@stackra/database. - Input transforms compile into the same Zod schema:
@Trim,@Lowercase,@ToInt,@ToBoolean,@ToDateand@Transform(fn).X.parse(input)returns a typed instance ofXor anSTK-codedValidationError. - Output goes through a serializer, separate from validation:
@Hidden,@Visible({ audience }),@Expose,@Castand@Format. The audiences arepublic,app,adminandagent. - class-validator and class-transformer are rejected.
Consequences
- One schema per shape, shared from database model to form to agent tool.
- Every shorthand must map exactly to a Zod construct, and the set needs a maintainer and a test per decorator.
- What an agent sees of a record is an explicit audience, so a field hidden from
agentnever reaches a prompt. - Which rule driver answers
@Existsand@Uniqueon the client (skip, or a remote call) is left to the package spec. - A row for class-validator and class-transformer is added to 0011 by a superseding change to that page.
Enforcement
Planned:FORBIDDEN_DEPENDENCIES in tools/scripts/validate-repository.mjs gains class-validator and class-transformer;
a test in @stackra/validation that every decorator produces its documented Zod construct; boundaries.jsonc keeps
@stackra/validation free of Node-only imports. Nothing checks this today.