--- description: Primary/aggregate entities must have status, created_at, updated_at, created_by, updated_by via primaryEntityColumns alwaysApply: true --- # Primary Entity Audit Fields ## Mandatory Every **primary / aggregate** table and its domain model MUST include: | Field | DB | Domain | | ----- | -- | ------ | | `status` | `text`, default `draft` | `Status` | | `created_at` / `updated_at` | `bigint` unix ms | `DateTime` | | `created_by` / `updated_by` | `uuid` → `users.id` | `string` userId | Use `primaryEntityColumns(users)` from `src/database/primary-entity-columns.ts` — do not re-declare these five columns by hand. Timestamps follow `.cursor/rules/date-time.mdc`. Status follows `.cursor/rules/status.mdc`. Actor ids come from `@CurrentUser()` on write. ```typescript export const shipments = pgTable('shipments', { id: uuid('id').defaultRandom().notNull().primaryKey(), name: text('name').notNull(), ...primaryEntityColumns(users), }) ``` On create/update in the repository: ```typescript const now = DateTime.fromUnixMs(Date.now()) await db.insert(table).values({ ...data, status: (status ?? Status.create(Status.DEFAULT)).value, createdAt: now.value, updatedAt: now.value, createdBy: userId, updatedBy: userId, }) ``` ## Exemptions Do **not** require these columns on: - Auth/session tables (`refresh_tokens`, `revoked_access_tokens`) - Junction / child rows that are not first-class resources - Existing `users` until an explicit migration adds them ## Forbidden - Omitting audit fields on a new primary table - Using plain `Date` / ISO strings for `created_at` / `updated_at` in domain code - Hardcoding actor ids or leaving `created_by` / `updated_by` nullable on primary entities