# Phase 1 — Data Model (099.1 Add-on)

## Entities

### AlertDestination (existing)

- **Table**: `alert_destinations`
- **Ownership**: workspace-owned
- **Key fields (relevant here)**:
  - `id`
  - `workspace_id`
  - `type` (e.g. Teams webhook, Email)
  - `config` (Teams webhook URL or list of recipients)
  - `is_enabled`

### AlertDelivery (existing, extended for test sends)

- **Table**: `alert_deliveries`
- **Ownership**:
  - v1 deliveries for real alerts remain tenant-associated
  - **test deliveries for this add-on are tenantless** (workspace-only)

- **Key fields (relevant here)**:
  - `id`
  - `workspace_id` (required)
  - `tenant_id` (**nullable for test deliveries**)
  - `alert_rule_id` (**nullable for test deliveries**)
  - `alert_destination_id` (required)
  - `event_type` (string, includes `alerts.test`)
  - `status` (`queued|deferred|sent|failed|suppressed|canceled`)
  - `send_after` (nullable; used for deferral/backoff)
  - `sent_at` (nullable)
  - `attempt_count`
  - `last_error_code`, `last_error_message` (sanitized)
  - `payload` (array/json)
  - timestamps: `created_at`, `updated_at`

## Relationships

- `AlertDelivery` → `AlertDestination` (belongsTo via `alert_destination_id`)
- `AlertDelivery` → `AlertRule` (belongsTo via `alert_rule_id`, nullable)
- `AlertDelivery` → `Tenant` (belongsTo via `tenant_id`, nullable)

## New derived concepts (no storage)

### LastTestStatus (derived)

Derived from the most recent `alert_deliveries` record where:
- `alert_destination_id = {destination}`
- `event_type = 'alerts.test'`

Mapping:
- no record → `Never`
- `status in (queued, deferred)` → `Pending`
- `status = sent` → `Sent`
- `status = failed` → `Failed`

Associated timestamp (derived):
- Sent → `sent_at`
- Failed → `updated_at`
- Pending → `send_after` (fallback `created_at`)

## Validation / invariants

- Creating a test delivery requires:
  - `alert_destination_id` exists and belongs to current workspace
  - destination is enabled (if disabled, refuse test request)
  - rate limit: no prior test delivery for this destination in last 60 seconds
- Test delivery record must not persist secrets in payload or error message.

## Migration notes

To support tenantless test deliveries:
- Make `alert_deliveries.tenant_id` nullable and adjust the FK behavior.
- Make `alert_deliveries.alert_rule_id` nullable and adjust the FK behavior.
- Add or adjust indexes for efficient status lookup per destination + event type:
  - `(workspace_id, alert_destination_id, event_type, created_at)`

(Exact migration steps and DB constraint changes are specified in the implementation plan.)
