# Entity Template

Standards for domain entities / ORM models in every service.

## Entities

| Rule | Detail |
| --- | --- |
| Naming | `PascalCase` class; `snake_case` table |
| Primary key | UUID (preferred) or documented exception |
| Tenant | Business entities include non-null `tenant_id` ([ADR-003](../architecture/adr/ADR-003.md)) |
| Timestamps | `created_at` / `updated_at` (timezone-aware) |
| Identity | No business meaning in surrogate keys |
| Mapping | SQLAlchemy models in `app/models/`; no business workflows in model methods beyond trivial helpers |

## Relationships

1. Relationships only within the same database.
2. No cross-service foreign keys.
3. Cross-service association: store external ref IDs (`*_ref`, UUID strings) without FK.
4. Prefer explicit relationship directions; avoid implicit cascade deletes across aggregates unless documented.
5. Owning aggregate controls lifecycle of child rows.

## Indexes

1. Index `tenant_id` (alone or composite) for tenant-scoped lists.
2. Composite indexes for common filters: `(tenant_id, status)`, `(tenant_id, created_at)`, unique business numbers per tenant.
3. Unique constraints that are tenant-scoped must include `tenant_id`.
4. Document unusual indexes in the phase/migration notes.

## Constraints

1. DB constraints enforce integrity the domain relies on (unique, check, non-null).
2. Do not rely only on application validation for critical invariants.
3. Monetary / quantity fields use precise types (Numeric) where applicable.
4. Enums: DB + Python enums kept in sync; prefer string enums for readability.

## Soft Delete

| Rule | Detail |
| --- | --- |
| Default for master/business records | Prefer `deleted_at` / `is_deleted` pattern used by sibling modules — **mandatory** unless justified N/A |
| Queries | Default repositories exclude soft-deleted rows |
| Uniqueness | Unique constraints must consider soft-delete strategy (partial unique indexes when required) |
| Hard delete | Only when phase explicitly allows (e.g. ephemeral logs with retention policy) |

## Optimistic Locking

| Rule | Detail |
| --- | --- |
| When | Concurrent updates are a domain risk (shared editable aggregates) |
| How | `version` / row-version column; conflict → 409 with stable error code |
| Tests | Concurrent update conflict covered when locking is enabled |

## Audit

1. Every business action must be auditable ([project-principles.md](../development/project-principles.md)).
2. Prefer `created_by` / `updated_by` (actor ids) on mutable entities when the service pattern uses them.
3. Sensitive domains keep append-only audit tables (CRM/Loyalty/Accounting patterns).
4. Audit rows are tenant-scoped and immutable after insert.
5. Aggregate design must state which entity is the consistency boundary for the phase.

## Validation

1. Structural validation: Pydantic schemas at API boundary.
2. Domain validation: service-layer validators (`app/validators/`).
3. DB constraints: last line of defense.
4. Never trust client-provided `tenant_id` over resolved tenant context.
5. Normalize phones/codes via shared helpers where applicable.

## Entity Checklist (per new table)

- [ ] Table name + model documented in phase
- [ ] Aggregate ownership stated
- [ ] `tenant_id` (if business data)
- [ ] Indexes / uniques defined
- [ ] Soft delete policy stated
- [ ] Optimistic locking stated (Yes / N/A with reason)
- [ ] Audit fields or audit table linkage
- [ ] Migration included
- [ ] Schema reference updated when public/shared docs require it ([database-schema.md](../reference/database-schema.md))

## Related Documents

- [Database Architecture](../architecture/database-architecture.md)
- [Repository Template](repository-template.md)
- [Mandatory Phase Artifacts](mandatory-phase-artifacts.md)
- [Coding Standards](../development/coding-standards.md)
- [ADR-001](../architecture/adr/ADR-001.md) · [ADR-003](../architecture/adr/ADR-003.md)
