Skip to content

🧩 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 schemas

Build: 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:

typescript
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

FieldPurposeFormatExample
nameInternal identifier (JSON key)camelCase"text1", "yesNo1"
displayNameUI labelAny format"Text 1", "Yes/No 1"
typescript
normalizePropertyName("Yes/No 1");  // → "yesNo1"

Schema Inheritance

All property schemas extend PropertyBaseSchemaRaw:

typescript
const StringPropertySchema = PropertyBaseSchemaRaw.extend({
  type: z.literal('string'),
  maxLength: z.number().optional(),
});

✅ Best Practices

typescript
// ✅ 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
}

Backend (Schemas Package)

Frontend

  • Property Type Icons: propertyTypes.icons.ts - Maps iconName strings from schema metadata to MUI icon components