Shared data contracts using Zod schemas in the @template/contracts package. Ensures consistent DTOs, schema validation, and type inference across the monorepo. Trigger: When creating/modifying shared data contracts, Zod schemas, or DTOs.
contract-enforcement - Enforce contract usagecontract-versioning - SemVer and changelogcontract-testing - Fixture-based testingzod-4 - Zod schema validationtypescript - Type safety patternsEnsure every API request, response, and data transfer uses contracts defined in the @template/contracts package. This is the single source of truth for all shared data types in the monorepo.
packages/contracts/
├── src/
│ ├── index.ts # Re-exports all contracts
│ ├── auth.ts # Auth: User, Login, Signup, Session
│ ├── chat.ts # Chat: Message, Session, Stream
│ ├── common.ts # Common: Error, Pagination, shared types
│ └── courses.ts # Courses: Course, Enrollment, Progress
├── package.json
└── tsconfig.json
packages/contracts/src/Schema suffix for Zod schemas (e.g., LoginRequestSchema)type LoginRequest = z.infer<typeof LoginRequestSchema>index.tsas const for enum-like valuesui/ or other packages| Pattern | Example |
|---|---|
| Schema (Zod object) | LoginRequestSchema |
| Inferred type | type LoginRequest = z.infer<typeof LoginRequestSchema> |
| Enum-like constants | export const MessageRole = { USER: "user", ASSISTANT: "assistant" } as const |
import { z } from "zod";
// Enum-like constant
export const MessageRole = {
USER: "user",
ASSISTANT: "assistant",
SYSTEM: "system",
} as const;
// Zod schema
export const ChatMessageSchema = z.object({
id: z.string().uuid(),
role: z.enum([MessageRole.USER, MessageRole.ASSISTANT, MessageRole.SYSTEM]),
content: z.string().min(1),
createdAt: z.string().datetime(),
});
// Inferred type
export type ChatMessage = z.infer<typeof ChatMessageSchema>;
Import contracts using subpath exports:
// Import from specific domain
import { LoginRequestSchema, type LoginRequest } from "@template/contracts/auth";
import { ChatMessageSchema, type ChatMessage } from "@template/contracts/chat";
import { PaginationSchema } from "@template/contracts/common";
import { CourseSchema } from "@template/contracts/courses";
// Or import from barrel export
import { LoginRequestSchema, ChatMessageSchema } from "@template/contracts";
auth.ts, chat.ts, common.ts, courses.ts, or new file)z.object({...}) with Schema suffixtype MyType = z.infer<typeof MyTypeSchema>index.ts if using barrel exportsas const objectscontract-versioning| Action | Invoke? |
|---|---|
| New API endpoint | ✅ Yes |
| Request/response shape change | ✅ Yes |
| New shared data type | ✅ Yes |
| UI-only state (no API crossing) | ❌ No |
| Local component props | ❌ No |
Schema suffixindex.ts