# 🏗️ DB Migrations Strategy V1

**Date:** 04/12/2025
**Scope:** `veza-backend-api`
**Goal:** Canonical, UUID-first, production-ready PostgreSQL schema.

---

## 1. Philosophy

We are moving from an **"Iterative/Repair"** mindset (fixing types, patching IDs) to a **"Declarative/Final"** mindset.
The V1 migrations represent the database as it *should* be created for a fresh deployment.

### Core Rules ("The Standard")
1.  **Identity:** All Primary Keys are `UUID` (`gen_random_uuid()`). No `SERIAL` or `BIGINT` PKs.
2.  **Time:**
    *   `created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP`
    *   `updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP` (with Trigger)
    *   `deleted_at TIMESTAMPTZ` (Nullable, for Soft Delete)
3.  **Integrity:**
    *   All Foreign Keys must be `UUID`.
    *   All Foreign Keys must have explicit `ON DELETE` clauses (mostly `CASCADE` for child entities).
    *   All Foreign Keys must be Indexed.
4.  **Text:** Use `TEXT` or `VARCHAR(N)` appropriately. IDs/Tokens are usually `VARCHAR`.

---

## 2. Migration File Structure

We use a grouped numbering system to organize domains.

### `migrations/`

*   **`001_extensions_and_types.sql`**
    *   Enable `pgcrypto` (legacy support), `uuid-ossp`.
    *   Define global ENUMs (e.g., `user_role`, `playlist_permission` if DB-enforced).

*   **`010_auth_and_users.sql`**
    *   `users`, `federated_identities`.
    *   `refresh_tokens`, `password_reset_tokens`, `email_verification_tokens`.
    *   `user_sessions`.

*   **`020_rbac_and_profiles.sql`**
    *   `roles`, `permissions`, `user_roles`, `role_permissions`.
    *   `user_profiles` (if distinct from users), `user_settings`.

*   **`040_streaming_core.sql`**
    *   `tracks`, `track_versions`.
    *   `playlists`, `playlist_tracks`.
    *   `playlist_collaborators`, `playlist_follows`.

*   **`041_streaming_analytics.sql`**
    *   `track_plays`, `track_likes`, `track_shares`, `track_comments`.
    *   `track_history`.

*   **`042_media_processing.sql`**
    *   `hls_streams`.
    *   `hls_transcode_queue`.
    *   `bitrate_adaptation_logs`.

*   **`050_legacy_chat.sql`**
    *   `rooms` (Legacy support).
    *   *Note: Modern chat is in `chat` schema, managed by Rust service.*

*   **`900_triggers_and_functions.sql`**
    *   `update_updated_at_column()` function.
    *   Apply triggers to all tables with `updated_at`.

---

## 3. Idempotence & Forward-Only

*   **Production:** Migrations are applied forward. We do not support `DOWN` migrations for V1 in the strict sense (rollback is usually "restore backup").
*   **Development:** We support a `reset_db.sh` script that drops the schema and reapplies all V1 migrations.

## 4. Indexes Strategy

*   **Primary Keys:** Implicit B-Tree.
*   **Foreign Keys:** MUST be indexed explicitly (Postgres does not do this automatically).
    *   Naming: `idx_<table>_<column>`
*   **Search Fields:** `email`, `username`, `slug` get `UNIQUE` indexes.
*   **Sorting:** `created_at DESC` indexes for activity feeds.

---

## 5. Example Migration Snippet

```sql
-- === USERS ===
CREATE TABLE public.users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email VARCHAR(255) NOT NULL,
    username VARCHAR(30) NOT NULL,
    
    -- Timestamps
    created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deleted_at TIMESTAMPTZ
);

CREATE UNIQUE INDEX idx_users_email ON public.users(email) WHERE deleted_at IS NULL;
CREATE UNIQUE INDEX idx_users_username ON public.users(username) WHERE deleted_at IS NULL;

-- Trigger
CREATE TRIGGER update_users_updated_at
    BEFORE UPDATE ON public.users
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at_column();
```
