🧩 Schemas
@tellia-solutions/schemas - Shared Zod schemas for type safety, validation, and UI generation across frontend and backend.
Location: packages/schemas/
Benefits: Single source of truth for types, runtime validation, automatic TypeScript inference, shared validation logic.
📁 Structure
packages/schemas/src/
├── common/ # Property types (string, number, etc.) + registry
├── workspace/ # Workspace schemas
├── user/ # User schemas
├── company/ # Company schemas
└── fields/ # Field schemasBuild: pnpm --filter @tellia-solutions/schemas build (outputs CJS, ESM, and .d.ts files)
🎨 Property Type Registry
Centralized catalog of property types (Text, Number, Boolean, etc.) with metadata for validation and UI generation.
Key File: propertyTypes.registry.ts
Schema Metadata Pattern
REQUIRED: All value schemas must call .meta() with PropertyTypeMetadata:
export const StringSchema = z.string().meta({
id: 'string',
label: 'Text',
iconName: 'TextFields',
description: 'Single line or multi-line text',
category: 'primitive',
needsConfiguration: false,
suggestFor: ['name', 'title', 'description'],
} satisfies PropertyTypeMetadata);Without .meta(), the registry cannot extract UI information (labels, icons) or provide proper validation. Schemas are registered using schema.register(propertyTypeRegistry, schema.meta()).
🔑 Key Concepts
name vs displayName
| Field | Purpose | Format | Example |
|---|---|---|---|
name | Internal identifier (JSON key) | camelCase | "text1", "yesNo1" |
displayName | UI label | Any format | "Text 1", "Yes/No 1" |
normalizePropertyName("Yes/No 1"); // → "yesNo1"Schema Inheritance
All property schemas extend PropertyBaseSchemaRaw:
const StringPropertySchema = PropertyBaseSchemaRaw.extend({
type: z.literal('string'),
maxLength: z.number().optional(),
});✅ Best Practices
// ✅ Use registry, not hardcoded labels
const typeDef = getPropertyTypeDefinition(type);
const label = typeDef?.label || 'Field';
// ✅ Always normalize user input
const name = normalizePropertyName(userInput);
// ✅ Check displayName when searching properties
generateDefaultPropertyName(type, properties); // Uses displayName
// ✅ TypeScript narrows discriminated unions
if (property.type === 'string') {
console.log(property.maxLength); // Type-safe
}🔗 Related Files
Backend (Schemas Package)
- Property Base Schema:
propertyBase.ts - Property Registry:
propertyTypes.registry.ts - Main Export:
index.ts - Build Config:
tsup.config.ts
Frontend
- Property Type Icons:
propertyTypes.icons.ts- MapsiconNamestrings from schema metadata to MUI icon components