# Database Rules

> Persistence conventions and owner decisions validated from the code and docs.

_Verified against models, migrations, and `NUMU_MCP_GAP_ANALYSIS.md` on 2026-07-23._

---

## Owner decisions (validated)
- **No DELETE operations are exposed** across the AI/API surface — an explicit owner decision.
- **Note deletion is role-scoped (DR-010):** the **admin dashboard** may delete a note (`NotesController::destroy`, `admin.auth`-gated); the **AI/API/MCP** surface is create/edit-only and exposes no note deletion. Admin deletion is a **hard delete** but writes a forensic `ActivityLog` (`action=note_deleted`, full body snapshot) **before** removal, atomically in one transaction (DR-011).
- **Tags: no delete / no detach** via the exposed surfaces.
- Core entities use **`SoftDeletes`** (Investor, Startup, Committee, Demo, …).

## Structural conventions
- **Merge-on-insert deduplication** — no satellite rows; a canonical row absorbs duplicates via `additional_monday_item_ids` (JSON) + `is_duplicate`. `canonical()/satellites()` relations were **removed** (superseded design — see [`../06-history/deprecated.md`](../06-history/deprecated.md)).
- **Dual natural keys on labels/options** — `(type, key)` for app lookups; `(type, monday_label_id)` / `(label_id, monday_option_id)` for sync.
- **Polymorphism** — `Meeting.meetingable`, `NotificationLog.recipient`, `File`/`EntityNote` morphs, `AutomationDispatch.source`.
- **Monthly uniqueness** — Committee & Demo share `meeting_month_key` unique + cron expiry.
- **Notification idempotency** — `event_id` groups a multi-channel send; `idempotency_key` = `entity:recipient:channel:message_type`.
- **Timezone** — meetings store Riyadh wall-clock via a custom cast; other timestamps are UTC.
- **Append-only audit** — `ai_activity_logs` uses DB-level append-only privileges (GRANT/REVOKE per `ai-connectors-rollout.md`).

## Scale & environment
- **~219 migrations** with heavy documented churn — see [`../06-history/migrations.md`](../06-history/migrations.md).
- DB name `numu_angels`; MySQL/MariaDB.
- **Agent tables:** 8 tables reported for the managed-agent runtime; the knowledge cache is a **single** `agent_knowledge_cache` table.
