TenantAtlas/specs/100-alert-target-test-actions/data-model.md
ahmido d49d33ac27 feat(alerts): test message + last test status + deep links (#122)
Implements feature 100 (Alert Targets):

- US1: “Send test message” action (RBAC + confirmation + rate limit + audit + async job)
- US2: Derived “Last test” status badge (Never/Sent/Failed/Pending) on view + edit surfaces
- US3: “View last delivery” deep link + deliveries viewer filters (event_type, destination) incl. tenantless test deliveries

Tests:
- Full suite green (1348 passed, 7 skipped)
- Added focused feature tests for send test, last test resolver/badges, and deep-link filters

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #122
2026-02-18 23:12:38 +00:00

80 lines
2.6 KiB
Markdown

# 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.)