# Model Implementation

## Context

Module: {{MODULE_NAME}}
Model doc: {{MODEL_DOC}}

## Instructions

Implement a database model based on the documentation.

1. Read the model doc at the path above
2. Read existing models in `{{MODULES_ROOT}}/{{MODULE_NAME}}/db/` for patterns
3. Implement the model in `{{MODULES_ROOT}}/{{MODULE_NAME}}/db/<model-name>.ts`

## Implementation Rules

**Read these references before implementing:**

- [Model patterns](models.md) — factory function, generics, stateful enums
- [Field builder API](../../erp-kit-shared/references/db-field-api.md) — available field types, optional fields, no `.nullable()` / `db.json()`
- [Database relations](db-relations.md) — `.relation()` for foreign keys
- [Cross-module dependencies](cross-module-dependency.md) — DB type injection

### Key Patterns

1. **Factory function**: `export function create<Model>Type<const F extends Record<string, TailorAnyDBField> = Record<string, never>>(params: { ... })`
2. **Timestamps**: Always include `db.fields.timestamps()`
3. **Descriptions**: Add `.description()` on every field
4. **Relations**: Use `.relation()` instead of plain `db.uuid()` for foreign keys
5. **Stateful models**: If a `.lifecycle.generated.ts` exists for the model, use `lifecycle.states` for the status enum
6. **Reserved-field guard**: See [Reserved Field Guard](models.md#reserved-field-guard) — the example below follows it

### From Doc to Code

| Doc Element        | Code Element                              |
| ------------------ | ----------------------------------------- |
| Fields table       | `db.string()`, `db.int()`, etc.           |
| Required fields    | Field without `{ optional: true }`        |
| Optional fields    | `db.string({ optional: true })`           |
| Status/state enum  | `db.enum(lifecycle.states)` from `.lifecycle.generated.ts` |
| Relationships      | `.relation()` with type and toward config |
| Unique constraints | `.unique()` on field or `.indexes({ unique: true })` for composite |

### Concrete Example

```typescript
import { db, type TailorAnyDBField, type TailorAnyDBType } from "@tailor-platform/sdk";
import {
  type CommonReservedFields,
  type NoReservedFields,
  defaultGqlPermission,
  defaultPermission,
} from "@tailor-platform/erp-kit/core";

import { orderLifecycle } from "./order.lifecycle.generated";

const builtins = (params: { companyType?: TailorAnyDBType }) => {
  // Cross-module FK: relation only when the foreign type is injected; plain uuid at codegen
  const companyId = db.uuid().description("Foreign key to Company");
  return {
    // Required string with unique constraint
    code: db.string().unique().description("Order code"),
    name: db.string().description("Order name"),
    // Optional string
    note: db.string({ optional: true }).description("Optional note"),
    // Enum — derived from generated lifecycle
    status: db.enum(orderLifecycle.states).description("Lifecycle status"),
    // Date
    orderDate: db.date().description("Order document date"),
    // Integer
    lineCount: db.int({ optional: true }).description("Number of lines"),
    // Decimal
    totalAmount: db.decimal().description("Total order amount"),
    // Boolean
    isUrgent: db.bool().description("Whether this order is urgent"),
    // Relation (n-1 foreign key) — cross-module, attached only when injected
    companyId: params.companyType
      ? companyId.relation({ type: "n-1", toward: { type: params.companyType }, backward: "orders" })
      : companyId,
    // Nested object (array)
    snapshotLines: db
      .object(
        {
          kind: db.string({ optional: true }),
          amount: db.decimal({ optional: true }),
        },
        { optional: true, array: true },
      )
      .description("Snapshotted line items"),
  };
};

type ReservedFields = keyof ReturnType<typeof builtins> | CommonReservedFields;

export interface CreateOrderTypeParams<F extends Record<string, TailorAnyDBField>> {
  fields?: NoReservedFields<F, ReservedFields>;
  companyType?: TailorAnyDBType;
}

export function createOrderType<const F extends Record<string, TailorAnyDBField>>(
  params: CreateOrderTypeParams<F>,
) {
  return db
    .type("Order", {
      ...builtins(params),
      // Custom fields spread + timestamps
      ...((params.fields ?? {}) as F),
      ...db.fields.timestamps(),
    })
    .permission(defaultPermission)
    .gqlPermission(defaultGqlPermission);
}

// Codegen instance with no cross-module types; real FK injected via module.ts
export const order = createOrderType({});
```

## Output

Write the model file to `{{MODULES_ROOT}}/{{MODULE_NAME}}/db/<model-name>.ts`.
Follow existing patterns in the module's `db/` directory.
