Selegic CRM Docs
ServerSchema

Authoring Schemas

How to create and organize Valibot schemas for CRM data models.

Schema Structure

Schemas are organized by model:

// packages/crm/schema/src/contact.ts
import { v } from "valibot";

export const ContactSchema = v.object({
  id: v.string(),
  name: v.string(),
  email: v.string(),
  phone: v.optional(v.string()),
  orgId: v.string(),
  createdAt: v.date(),
  updatedAt: v.date(),
});

export const ContactCreateSchema = v.object({
  name: v.pipe(v.string(), v.minLength(1)),
  email: v.pipe(v.string(), v.email()),
  phone: v.optional(v.string()),
});

export const ContactUpdateSchema = v.partial(ContactCreateSchema);

export const ContactFindManySchema = v.object({
  where: v.optional(v.record(v.string(), v.unknown())),
  orderBy: v.optional(v.record(v.string(), v.string())),
  limit: v.optional(v.pipe(v.number(), v.integer(), v.min(1), v.max(100))),
  cursor: v.optional(v.string()),
});

Schema Exports

Export schemas from an index file:

// packages/crm/schema/src/index.ts
export * from "./contact";
export * from "./organization";
export * from "./entity";

Using with Hono

import { zValidator } from "@hono/zod-validator";
import { ContactCreateSchema } from "@repo/crm-schema";

app.post("/contacts", zValidator("json", ContactCreateSchema), async (c) => {
  const input = c.req.valid("json");
  // input is fully typed
});

Best Practices

  1. Separate create/update schemas: Use v.partial() for updates
  2. Use pipes: Add validation like v.minLength(), v.email()
  3. Include orgId: Always include organization context
  4. Export for RPC: Schemas enable typed RPC client

On this page