# Cross-layer guide — same VO in front and back ## Principle One catalog type (`Title`, `EmailAddress`, …) defines rules once. Front-end and back-end both import from `smart-value-objects`. ## UI binding ```tsx import { Title } from 'smart-value-objects'; ``` Never hard-code `120` or copy regex from docs — read `Title.constraints`. ## Shared validation schema Define validators once; reuse in API route and form submit: ```typescript import type { ValidateRecordSchema } from 'smart-value-objects'; import { Title, PersonName, EmailAddress } from 'smart-value-objects'; export const profileSchema: ValidateRecordSchema = { title: Title.tryCreate, name: PersonName.tryCreate, email: EmailAddress.tryCreate, }; ``` Import `profileSchema` in both your Express/Fastify handler and your React/Vue form handler. ## Serialization boundary - **Inside domain:** keep `Title`, `EmailAddress`, etc. - **JSON wire / DB primitive column:** `vo.getValue()` → `string` - **Parse inbound:** `Title.tryCreate(raw)` → `Title` ## Anti-patterns | Don't | Do | |-------|-----| | `string` for email in domain models | `EmailAddress` | | Local regex for catalog types | `EmailAddress.tryCreate` | | Different max lengths in UI vs API | `X.constraints.maxLength` | | Import demo `User` entity from examples | Catalog + your own entities |