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
193 lines
10 KiB
Markdown
193 lines
10 KiB
Markdown
---
|
||
|
||
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.
|