TenantAtlas/specs/099-alerts-v1-teams-email/tasks.md
ahmido 3ed275cef3 feat(alerts): Monitoring cluster + v1 resources (spec 099) (#121)
Implements spec `099-alerts-v1-teams-email`.

- Monitoring navigation: Alerts as a cluster under Monitoring; default landing is Alert deliveries.
- Tenant panel: Alerts points to `/admin/alerts` and the cluster navigation is hidden in tenant panel.
- Guard compliance: removes direct `Gate::` usage from Alert resources so `NoAdHocFilamentAuthPatternsTest` passes.

Verification:
- Full suite: `1348 passed, 7 skipped` (EXIT=0).

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #121
2026-02-18 15:20:43 +00:00

193 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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: T027T030
- Building blocks: T031 + T032 + T035 + T037 + T038 + T039T041
---
## 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.