--- description: "Task list for 099 Alerts v1 (Teams + Email)" --- # Tasks: 099 — Alerts v1 (Teams + Email) **Input**: Design documents from `/specs/099-alerts-v1-teams-email/` **Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/ - Spec: `/specs/099-alerts-v1-teams-email/spec.md` - Plan: `/specs/099-alerts-v1-teams-email/plan.md` - Research: `/specs/099-alerts-v1-teams-email/research.md` - Data model: `/specs/099-alerts-v1-teams-email/data-model.md` - Contracts: `/specs/099-alerts-v1-teams-email/contracts/openapi.yaml` **Tests**: REQUIRED (Pest) — this feature changes runtime behavior. **Operations**: Jobs that perform queued delivery MUST create/update canonical `OperationRun` records and show “View run” via the Monitoring hub. **RBAC**: Enforce 404 vs 403 semantics and use capability registry constants (no raw strings). ## Format: `[ID] [P?] [Story] Description` --- ## Phase 1: Setup (Shared Infrastructure) **Purpose**: Basic structure required by the plan - [X] T001 Create alerts namespace directories via keep-files `app/Services/Alerts/.gitkeep` and `app/Jobs/Alerts/.gitkeep` --- ## Phase 2: Foundational (Blocking Prerequisites) **Purpose**: MUST complete before any user story work begins - [X] T002 Add Alerts capability constants to `app/Support/Auth/Capabilities.php` (`ALERTS_VIEW`, `ALERTS_MANAGE`) - [X] T003 Update role → capability mapping in `app/Services/Auth/WorkspaceRoleCapabilityMap.php` for Alerts view/manage - [X] T004 Add audit action IDs to `app/Support/Audit/AuditActionId.php` for Alerts (destination/rule create/update/delete + enable/disable) - [X] T005 [P] Add operation type labels in `app/Support/OperationCatalog.php` (`alerts.evaluate`, `alerts.deliver`) - [X] T006 [P] Implement workspace timezone resolver `app/Services/Alerts/WorkspaceTimezoneResolver.php` (fallback to `config('app.timezone')`) - [X] T007 Update the Alerts “UI Action Matrix” in `specs/099-alerts-v1-teams-email/spec.md` for Targets/Rules/Deliveries surfaces (ensure it matches actual Filament actions) **Checkpoint**: Capabilities + audit IDs + operation type labels exist. --- ## Phase 3: User Story 1 — Configure alert destinations (Priority: P1) 🎯 MVP **Goal**: Workspace members with manage permission can create Teams/email destinations. **Independent Test**: Create a Teams destination and an Email destination; ensure secrets are never revealed after save; list/edit/disable. ### Tests for User Story 1 ⚠️ - [X] T008 [P] [US1] Add RBAC access tests (404 vs 403) in `tests/Feature/Filament/Alerts/AlertDestinationAccessTest.php` - [X] T009 [P] [US1] Add destination CRUD happy-path test in `tests/Feature/Filament/Alerts/AlertDestinationCrudTest.php` ### Implementation for User Story 1 - [X] T010 [P] [US1] Create migration `database/migrations/*_create_alert_destinations_table.php` (workspace_id, type, is_enabled, encrypted config, timestamps) - [X] T011 [P] [US1] Create model `app/Models/AlertDestination.php` (workspace relationship; encrypted config cast; hide config) - [X] T012 [P] [US1] Create policy `app/Policies/AlertDestinationPolicy.php` (404 non-member; 403 missing capability) - [X] T013 [US1] Register policy mapping in `app/Providers/AuthServiceProvider.php` - [X] T014 [US1] Implement Filament resource `app/Filament/Resources/AlertDestinationResource.php` (Targets; action-surface contract; max 2 visible row actions) - [X] T015 [US1] Add Alerts navigation entry via Filament cluster (`app/Filament/Clusters/Monitoring/AlertsCluster.php`) and register Targets resource under it - [X] T016 [US1] Add audited mutations in `app/Filament/Resources/AlertDestinationResource.php` using `app/Services/Audit/WorkspaceAuditLogger.php` + `app/Support/Audit/AuditActionId.php` (no secrets) - [X] T017 [US1] Ensure destructive actions confirm in `app/Filament/Resources/AlertDestinationResource.php` (`->action(...)` + `->requiresConfirmation()`) **Checkpoint**: Destinations are functional and testable independently. --- ## Phase 4: User Story 2 — Configure alert routing rules (Priority: P2) **Goal**: Workspace members with manage permission can define routing rules that send to destination(s). **Independent Test**: Create a rule, attach destinations, set tenant allowlist, and verify it is enforced during evaluation. ### Tests for User Story 2 ⚠️ - [X] T018 [P] [US2] Add RBAC access tests (404 vs 403) in `tests/Feature/Filament/Alerts/AlertRuleAccessTest.php` - [X] T019 [P] [US2] Add rule CRUD test (destinations attach) in `tests/Feature/Filament/Alerts/AlertRuleCrudTest.php` ### Implementation for User Story 2 - [X] T020 [P] [US2] Create migrations `database/migrations/*_create_alert_rules_table.php` and `database/migrations/*_create_alert_rule_destinations_table.php` - [X] T021 [P] [US2] Create models `app/Models/AlertRule.php` and `app/Models/AlertRuleDestination.php` (casts for allowlist + quiet-hours fields) - [X] T022 [P] [US2] Create policy `app/Policies/AlertRulePolicy.php` (404 non-member; 403 missing capability) - [X] T023 [US2] Register policy mapping in `app/Providers/AuthServiceProvider.php` - [X] T024 [US2] Implement Filament resource `app/Filament/Resources/AlertRuleResource.php` (Rules; action-surface contract; destination picker) - [X] T025 [US2] Implement enable/disable actions with audit logging in `app/Filament/Resources/AlertRuleResource.php` (use `->action(...)` and confirmations) - [X] T026 [US2] Register Rules resource under Alerts cluster navigation (no manual `NavigationItem` duplicates) **Checkpoint**: Rules are functional and testable independently. --- ## Phase 5: User Story 3 — Deliver alerts safely + review delivery history (Priority: P3) **Goal**: Queue-driven delivery with fingerprint dedupe, cooldown suppression, quiet-hours deferral, and a delivery history viewer. **Independent Test**: Trigger same event twice within cooldown → only one send + one `suppressed` record; quiet-hours → `deferred`; failures retry with exponential backoff then `failed`. ### Tests for User Story 3 ⚠️ - [X] T027 [P] [US3] Add delivery viewer access test in `tests/Feature/Filament/Alerts/AlertDeliveryViewerTest.php` - [X] T028 [P] [US3] Add fingerprint/cooldown suppression test in `tests/Unit/Alerts/AlertSuppressionTest.php` - [X] T029 [P] [US3] Add quiet-hours deferral test in `tests/Unit/Alerts/AlertQuietHoursTest.php` - [X] T030 [P] [US3] Add retry/backoff terminal failure test in `tests/Unit/Alerts/AlertRetryPolicyTest.php` ### Implementation for User Story 3 - [X] T031 [P] [US3] Create deliveries migration `database/migrations/*_create_alert_deliveries_table.php` (workspace_id, tenant_id NOT NULL, status, fingerprint, send_after, attempt_count, last_error_code/message, indexes) - [X] T032 [P] [US3] Create model `app/Models/AlertDelivery.php` (statuses incl. `suppressed`; prunable retention = 90 days default) - [X] T033 [P] [US3] Create policy `app/Policies/AlertDeliveryPolicy.php` (view requires `ALERTS_VIEW`; enforce tenant entitlement; 404/403 semantics) - [X] T034 [US3] Register policy mapping in `app/Providers/AuthServiceProvider.php` - [X] T035 [P] [US3] Implement fingerprint + quiet-hours helpers `app/Services/Alerts/AlertFingerprintService.php` and `app/Services/Alerts/AlertQuietHoursService.php` - [X] T036 [US3] Implement dispatcher `app/Services/Alerts/AlertDispatchService.php` (creates delivery rows; writes `suppressed` rows) with repo-grounded trigger sources: - High Drift: from `Finding` (drift) severity high/critical where `status=new` (unacknowledged); “newly active/visible” means first appearance (new finding created) - Compare Failed: from failed `OperationRun` where `type=drift_generate_findings` - SLA Due: safe no-op until a due-date signal exists in persistence - [X] T037 [P] [US3] Implement Teams sender `app/Services/Alerts/TeamsWebhookSender.php` (Laravel HTTP client; no secret logging) - [X] T038 [P] [US3] Implement Email notification `app/Notifications/Alerts/EmailAlertNotification.php` (no secrets) - [X] T039 [P] [US3] Implement evaluate job `app/Jobs/Alerts/EvaluateAlertsJob.php` (creates deliveries; records `OperationRun` type `alerts.evaluate`) - [X] T040 [P] [US3] Create dispatch command `app/Console/Commands/TenantpilotDispatchAlerts.php` (`tenantpilot:alerts:dispatch`) that queues evaluation + delivery work idempotently - [X] T041 [P] [US3] Wire scheduler in `routes/console.php` to run `tenantpilot:alerts:dispatch` every minute with `->withoutOverlapping()` - [X] T042 [P] [US3] Implement delivery job `app/Jobs/Alerts/DeliverAlertsJob.php` (sends due deliveries; bounded retries + exponential backoff; records `OperationRun` type `alerts.deliver`) - [X] T043 [P] [US3] Implement send service `app/Services/Alerts/AlertSender.php` (shared send orchestration for Teams/email; safe error capture; no secret logging) - [X] T044 [US3] Add deliveries Filament resource `app/Filament/Resources/AlertDeliveryResource.php` (read-only; inspection affordance; no secrets; list/query must not reveal deliveries for non-entitled tenants) - [X] T045 [US3] Register Deliveries resource under Alerts cluster navigation (no manual `NavigationItem` duplicates) **Checkpoint**: Delivery pipeline works with retries, suppression, quiet-hours deferral, and safe history. --- ## Phase 6: Polish & Cross-Cutting Concerns - [X] T046 Update quickstart queue command in `specs/099-alerts-v1-teams-email/quickstart.md` (use `queue:work`) - [X] T047 Run formatting `vendor/bin/sail bin pint --dirty` on `app/**` and `tests/**` - [X] T048 Run focused tests `vendor/bin/sail artisan test --compact` for `tests/Feature/Filament/Alerts/**` and `tests/Unit/Alerts/**` ## Phase 7: Navigation UX (Monitoring) - [X] T049 Restructure Alerts navigation under Monitoring (no Overview page; no content sub-navigation; Deliveries is default landing) - [X] T050 Update OperateHubShell tests to use Alerts cluster landing and follow redirects --- ## Dependencies & Execution Order ### Phase Dependencies - Setup (Phase 1) → Foundational (Phase 2) → User stories → Polish ### User Story Dependencies - US1 → US2 → US3 --- ## Parallel Execution Examples ### US1 - Tests: T008 + T009 - Model/migration/policy: T010 + T011 + T012 ### US2 - Tests: T018 + T019 - Model/migrations/policy: T020 + T021 + T022 ### US3 - Tests: T027–T030 - Building blocks: T031 + T032 + T035 + T037 + T038 + T039–T041 --- ## Implementation Strategy ### MVP First (User Story 1 Only) 1. Complete Phase 1 + Phase 2 2. Complete US1 3. Validate via `tests/Feature/Filament/Alerts/AlertDestination*` ### Incremental Delivery - Add US2 next, then US3; each story remains independently demoable.