# `invitations` — Digital Wedding Invitation

**Module:** Invitation  
**Soft Delete:** No (lifecycle via `invitation_status`)

---

## Purpose

Stores the configuration for the digital wedding invitation. Each workspace has exactly one invitation record. This is the core of the guest-facing experience.

---

## Columns

| Column | Type | Nullable | Default | Description |
|--------|------|----------|---------|-------------|
| `id` | `BIGINT UNSIGNED AUTO_INCREMENT` | No | — | — |
| `workspace_id` | `BIGINT UNSIGNED` | No | — | → `workspaces.id`. Unique — one per workspace |
| `theme_version_id` | `SMALLINT UNSIGNED` | No | — | → `theme_versions.id`. Pinned at selection |
| `color_variant` | `VARCHAR(50)` | Yes | NULL | Selected color variant slug from theme manifest |
| `groom_display_name` | `VARCHAR(100)` | No | — | Name shown on invitation |
| `bride_display_name` | `VARCHAR(100)` | No | — | Name shown on invitation |
| `love_story` | `TEXT` | Yes | NULL | Couple narrative text |
| `music_enabled` | `TINYINT(1)` | No | `0` | Whether background music is active |
| `music_file_id` | `BIGINT UNSIGNED` | Yes | NULL | → `media_files.id`. NULL if music disabled |
| `rsvp_enabled` | `TINYINT(1)` | No | `0` | Whether RSVP form is active |
| `rsvp_opens_at` | `DATETIME` | Yes | NULL | RSVP form becomes available after this |
| `rsvp_closes_at` | `DATETIME` | Yes | NULL | RSVP form closes at this timestamp |
| `rsvp_allow_edit` | `TINYINT(1)` | No | `1` | Whether guests can edit RSVP before closing |
| `wish_wall_enabled` | `TINYINT(1)` | No | `1` | Whether wish wall is shown |
| `gift_info_enabled` | `TINYINT(1)` | No | `0` | Whether gift info section is shown |
| `gift_info_content` | `TEXT` | Yes | NULL | Gift details, bank info, registry links |
| `invitation_status` | `VARCHAR(20)` | No | `draft` | `draft \| configured \| published \| rsvp_open \| rsvp_closed \| archived` |
| `published_at` | `DATETIME` | Yes | NULL | First guest URL access timestamp |
| `created_at` | `DATETIME` | No | `CURRENT_TIMESTAMP` | — |
| `updated_at` | `DATETIME` | Yes | NULL | — |

---

## Primary Key / Indexes

| Name | Columns | Type |
|------|---------|------|
| `PRIMARY` | `id` | Primary |
| `uq_invitations_workspace` | `workspace_id` | Unique |
| `idx_invitations_rsvp_closes` | `rsvp_closes_at` | Index |

---

## Foreign Keys

| Column | References | On Delete |
|--------|-----------|-----------|
| `workspace_id` | `workspaces.id` | CASCADE |
| `theme_version_id` | `theme_versions.id` | RESTRICT |
| `music_file_id` | `media_files.id` | SET NULL *(deferred)* |

---

## Referenced By

| Table | Column |
|-------|--------|
| `invitation_sections` | `invitation_id` |

---

## Business Rules

- One invitation per workspace (UNIQUE constraint)
- `theme_version_id` is pinned at selection — updating the theme creates a new selection, not an overwrite
- RSVP window is controlled by `rsvp_opens_at` and `rsvp_closes_at`
- `published_at` is set on first guest URL access, not on publish action
