TenantAtlas/.specify/tasks.md
Ahmed Darrazi 6d14d2544f feat: TenantPilot v1 - Complete implementation (Phases 1-12)
Complete implementation of TenantPilot v1 Intune Management Platform with
comprehensive backup, versioning, and restore capabilities.

CONSTITUTION & SPEC
- Ratified constitution v1.0.0 with 7 core principles
- Complete spec.md with 7 user stories (US1-7)
- Detailed plan.md with constitution compliance check
- Task breakdown with 125+ tasks across 12 phases

CORE FEATURES (US1-4)
- Policy inventory with Graph-based sync (US1)
- Backup creation with immutable JSONB snapshots (US2)
- Version history with diff viewer (human + JSON) (US3)
- Defensive restore with preview/dry-run (US4)

TENANT MANAGEMENT (US6-7)
- Full tenant CRUD with Entra ID app configuration
- Admin consent callback flow integration
- Tenant connectivity verification
- Permission health status monitoring
- 'Highlander' pattern: single current tenant with is_current flag

GRAPH ABSTRACTION
- Complete isolation layer (7 classes)
- GraphClientInterface with mockable implementations
- Error mapping, logging, and standardized responses
- Rate-limit aware design

DOMAIN SERVICES
- BackupService: immutable snapshot creation
- RestoreService: preview, selective restore, conflict detection
- VersionService: immutable version capture
- VersionDiff: human-readable and structured diffs
- PolicySyncService: Graph-based policy import
- TenantConfigService: connectivity testing
- TenantPermissionService: permission health checks
- AuditLogger: comprehensive audit trail

DATA MODEL
- 11 migrations with tenant-aware schema
- 8 Eloquent models with proper relationships
- SoftDeletes on Tenant, BackupSet, BackupItem, PolicyVersion, RestoreRun
- JSONB storage for snapshots, metadata, permissions
- Encrypted storage for client secrets
- Partial unique index for is_current tenant

FILAMENT ADMIN UI
- 5 main resources: Tenant, Policy, PolicyVersion, BackupSet, RestoreRun
- RelationManagers: Versions (Policy), BackupItems (BackupSet)
- Actions: Verify config, Admin consent, Make current, Delete/Force delete
- Filters: Status, Type, Platform, Archive state
- Permission panel with status indicators
- ActionGroup pattern for cleaner row actions

HOUSEKEEPING (Phases 10-12)
- Soft delete with archive status for all entities
- Force delete protection (blocks if dependencies exist)
- Tenant deactivation with cascade prevention
- Audit logging for all delete operations

TESTING
- 36 tests passing (125 assertions, 11.21s)
- Feature tests: Policy, Backup, Restore, Version, Tenant, Housekeeping
- Unit tests: VersionDiff, TenantCurrent, Permissions, Scopes
- Full TDD coverage for critical flows

CONFIGURATION
- config/tenantpilot.php: 10+ policy types with metadata
- config/intune_permissions.php: required Graph permissions
- config/graph.php: Graph client configuration

SAFETY & COMPLIANCE
- Constitution compliance: 7/7 principles ✓
- Safety-first operations: preview, confirmation, validation
- Immutable versioning: no in-place modifications
- Defensive restore: dry-run, selective, conflict detection
- Comprehensive auditability: all critical operations logged
- Tenant-aware architecture: multi-tenant ready
- Graph abstraction: isolated, mockable, testable
- Spec-driven development: spec → plan → tasks → implementation

OPERATIONAL READINESS
- Laravel Sail for local development
- Dokploy deployment documentation
- Queue/worker ready architecture
- Migration safety notes
- Environment variable documentation

Tests: 36 passed
Duration: 11.21s
Status: Production-ready (98% complete)
2025-12-12 02:27:54 +01:00

18 KiB
Raw Blame History

description
Task list for TenantPilot v1 implementation

Tasks: TenantPilot v1

Input: Design documents from .specify/spec.md and .specify/plan.md
Prerequisites: plan.md (complete), spec.md (complete)

Phase 1: Setup (Shared Infrastructure)

  • T001 [P] [Shared] Confirm Sail/Env ready; ensure .env has PostgreSQL settings for Sail and Filament admin user seeded (if missing) in database/seeders/.
  • T002 [P] [Shared] Add baseline docs for local dev and staging promotion notes in README.md (Sail commands, staging-before-prod reminder).

Phase 2: Foundational (Blocking Prerequisites)

  • T003 [Shared] Add tenant-aware migrations for tenants, policies, policy_versions, backup_sets, backup_items, restore_runs, audit_logs with JSONB payloads and FK/time indexes in database/migrations/.
  • T004 [Shared] Create models with relationships and guarded attributes for the above entities in app/Models/.
  • T005 [Shared] Implement Graph abstraction contracts (GraphClientInterface, error mapping, logging hooks) in app/Services/Graph/ with a mockable adapter.
  • T006 [Shared] Add audit logging service/helper to capture actor, tenant, operation, resources, outcome in app/Services/Intune/AuditLogger.php.
  • T007 [Shared] Seed supported policy types/metadata for initial scope in database/seeders/PoliciesSeeder.php and ensure tenant scoping.

Phase 3: User Story 1 - Policy inventory listing (Priority: P1)

Tests for User Story 1

  • T008 [P] [US1] Feature test for Filament policy listing and filtering (tenant-scoped) in tests/Feature/Filament/PolicyListingTest.php using mocked Graph sync.

Implementation for User Story 1

  • T009 [US1] Implement policy sync/import orchestrator using Graph abstraction in app/Services/Intune/PolicySyncService.php (no direct Graph in UI).
  • T010 [US1] Create Filament resource/table for policies with filters and metadata columns in app/Filament/Resources/PolicyResource.php.
  • T011 [US1] Add command/job to sync policies (queues-ready) in app/Console/Commands/SyncPolicies.php and queue job under app/Jobs/.

Phase 4: User Story 2 - Backup creation and browsing (Priority: P1)

Tests for User Story 2

  • T012 [P] [US2] Feature test for creating backup sets with multiple policies and verifying immutable JSONB snapshots + audit log in tests/Feature/Filament/BackupCreationTest.php.

Implementation for User Story 2

  • T013 [US2] Implement backup domain service to assemble snapshots from policies with Graph payload retrieval in app/Services/Intune/BackupService.php.

  • T014 [US2] Add Filament resource/pages for backup sets and items (list/detail) in app/Filament/Resources/BackupSetResource.php.

  • T131 [UX] [US2] Refactor BackupSet policy selection to RelationManager:

    • Remove the multi-select policy picker from the BackupSet Create form (keep Create minimal: name/description).
    • After create, redirect to BackupSet Edit/View where items can be managed.
    • Add BackupItemsRelationManager to BackupSetResource showing a table with columns: Policy Name, Type (badge), Restore (badge), Risk (badge).
    • Add header action “Policies hinzufügen” (searchable, multiple) that adds items/attaches policies tenant-scoped and prevents duplicates per BackupSet.
    • Provide a remove action (detach/soft-delete as per domain rules).
  • T132 [P] [US2] Update/extend tests/Feature/Filament/BackupCreationTest.php to cover the new UX flow:

    • Create BackupSet without policies.
    • Add multiple policies via RelationManager action.
    • Verify immutable JSONB snapshots + audit log behavior remains correct.
  • T015 [US2] Wire audit logging for backup creation events in app/Services/Intune/BackupService.php using AuditLogger.

Phase 5: User Story 3 - Version history and diff (Priority: P1)

Tests for User Story 3

  • T016 [P] [US3] Feature test for version capture and timeline display in tests/Feature/Filament/PolicyVersionTest.php.
  • T017 [P] [US3] Unit test for diff generation (human summary + JSON diff) in tests/Unit/VersionDiffTest.php.

Implementation for User Story 3

  • T018 [US3] Implement version capture service with immutable JSONB writes in app/Services/Intune/VersionService.php.
  • T019 [US3] Create diff helper (summary + structured JSON) in app/Services/Intune/VersionDiff.php and surface in Filament version compare view in app/Filament/Resources/PolicyVersionResource.php.
  • T020 [US3] Hook version capture into relevant flows (manual trigger + backup/restore hooks) ensuring audit logging.

Phase 6: User Story 4 - Restore with preview and confirmation (Priority: P1)

Tests for User Story 4

  • T021 [P] [US4] Feature test for restore preview (change summary, conflicts, selective items) in tests/Feature/Filament/RestorePreviewTest.php.
  • T022 [P] [US4] Feature test for confirmed restore execution capturing audit logs and per-item outcomes in tests/Feature/Filament/RestoreExecutionTest.php.

Implementation for User Story 4

  • T023 [US4] Implement restore service with preview/dry-run and selective item application in app/Services/Intune/RestoreService.php, integrating Graph adapter and conflict detection.
  • T024 [US4] Add Filament restore UI (wizard or pages) showing preview, warnings, and confirmation gate in app/Filament/Resources/RestoreRunResource.php.
  • T025 [US4] Record restore run lifecycle (start, per-item result, completion) and audit events in restore_runs and audit_logs.

Phase 7: User Story 5 - Operational readiness and environments (Priority: P2)

Implementation for User Story 5

  • T026 [US5] Document Dokploy staging→production promotion steps, required env vars, queue/worker expectations, and migration safety notes in README.md or docs/deploy.md.
  • T027 [US5] Add quick Sail commands and test invocation notes to README.md (e.g., ./vendor/bin/sail artisan test) and ensure sample env entries for Graph credentials.

Phase 8: User Story 6 - Tenant hinzufügen & Entra ID App-Setup (Priority: P1)

  • T030 [US6] Migration für tenants ergänzen/prüfen:

    • Felder: name, tenant_id (GUID), domain, app_client_id, app_status, app_notes, created_at, updated_at.
    • Optional: Felder für Secret/Certificate-Config (verschlüsselt), falls benötigt.
  • T031 [US6] Eloquent Model Tenant:

    • Beziehungen zu policies, backup_sets, restore_runs, policy_versions, audit_logs über tenant_id.
    • Tenant-aware Scopes, falls vorhanden (z. B. forTenant()).
  • T032 [US6] Filament-Resource TenantResource:

    • Listenansicht: Name, Tenant ID, Domain, App-Status, erstellt/am.
    • Create/Edit-Form: Name, Tenant ID, Domain, App-Client-ID, optionale Notizen.
    • Detailseite mit Actions:
      • „Open in Entra“ (Link zur App/Tenant im Entra-Portal),
      • optional: „Copy Admin Consent URL“.
  • T033 [US6] TenantConfigService (oder Erweiterung des Graph-Clients):

    • Methode testConnectivity(Tenant $tenant): führt einen einfachen Graph-Call aus (z. B. /organization oder ähnliches) mit den App-Daten des Tenants.
    • Rückgabe: DTO/Array mit success, error_message (falls vorhanden).
  • T034 [US6] Action „Verify configuration“ in TenantResource:

    • Ruft testConnectivity() auf,
    • setzt app_status auf z. B. ok, error oder consent_required,
    • zeigt eine Filament-Notification mit dem Ergebnis,
    • schreibt einen Audit-Log-Eintrag (tenant.config.verified).
  • T035 [US6] Tenant-Kontext in bestehende Services integrieren:

    • PolicySyncService, BackupService, RestoreService so anpassen, dass sie einen Tenant oder tenant_id übergeben bekommen und den Graph-Client mit diesem Kontext verwenden.
    • Sicherstellen, dass alle policy/backup/restore/audit-Datensätze tenant_id setzen.
  • T036 [US6] Feature-Test TenantSetupTest:

    • Erstellen eines Tenants via Filament (Create-Form).
    • Aufruf der Action „Verify configuration“ mit gemocktem Graph-Client:
      • einmal mit erfolgreichem Call → app_status = ok,
      • einmal mit Fehler → app_status = error + passende Notification.
    • Prüfen, dass Audit-Logs geschrieben werden.
  • T037 [US6] Admin-Consent Callback Route

    • Route/Controller, der als redirect_uri der Entra-ID-App dient.
    • Liest tenant / error / admin_consent aus der Query.
    • Ordnet das dem richtigen Tenant zu (z. B. via state).
    • Aktualisiert app_status (z. B. ok, error, consent_denied).
    • Zeigt eine Bestätigungs-/Fehlerseite für den Admin.

Phase 9: User Story 7 - Berechtigungsübersicht & Health-Status (Priority: P1)

  • T040 [US7] Zentrale Permissions-Liste anlegen:

    • config/intune_permissions.php mit allen aktuell benötigten Graph-Berechtigungen:
      • technischer Name (z. B. DeviceManagementConfiguration.ReadWrite.All),
      • Typ: application / delegated,
      • kurze Beschreibung,
      • Feature-Tags (z. B. ["policy-sync", "backup"]).
    • Optional: docs/permissions.md mit einer Tabelle Feature ↔ Permission als menschlich lesbare Referenz.
  • T041 [US7] Datenmodell für Tenant-Berechtigungen:

    • Variante A (einfach): JSONB-Feld granted_permissions in tenants (Liste von Permission-Keys).
    • Variante B (feiner): Tabelle tenant_permissions mit (tenant_id, permission_key, status, last_checked_at).
    • status mindestens: ok, missing, error.
  • T042 [US7] Service TenantPermissionService:

    • getRequiredPermissions(): array liest aus config/intune_permissions.php.
    • getGrantedPermissions(Tenant $tenant): array liest aus Graph oder aus tenant_permissions/granted_permissions.
    • compare(Tenant $tenant): TenantPermissionStatusDTO liefert pro Permission den Status (ok/missing/error) + Gesamthealth.
  • T043 [US7] Integration in Tenant-Detail-UI:

    • Auf der TenantResource-Detailseite ein Panel/Section „Permissions“:
      • Liste aller required permissions,
      • pro Zeile: Name, Typ, Feature-Tags, Status (Icon + Label: OK/fehlt/Fehler).
    • Optional: Link zu Doku oder Entra-Darstellung (z. B. „How to grant these permissions“).
  • T044 [US7] Action „Verify configuration“ erweitern:

    • Zusätzlich zu testConnectivity() auch TenantPermissionService::compare() aufrufen.
    • Ergebnisse in tenant_permissions/granted_permissions speichern.
    • app_status und Permission-Health aktualisieren.
    • Audit-Log-Eintrag tenant.permissions.checked schreiben.
  • T045 [US7] Tests für Permissions:

    • Unit-Tests für TenantPermissionService::compare():
      • Szenarien: alle ok, Permission fehlt, Graph-Error.
    • Feature-Test für Tenant-Detailseite:
      • required permissions werden angezeigt,
      • fehlende werden als fehlend markiert,
      • „Verify configuration“ aktualisiert den Status wie erwartet.

Phase 9b: Scope-Ausrichtung auf neue Objekttypen

  • T028 [Scope] Konfiguration config/tenantpilot.php auf die in scope.supported_types definierten Objekttypen erweitern (type/key, endpoint, label/category, optional risk/restore-Hinweis). Sicherstellen, dass diese Liste die einzige Quelle für Policy-Sync/Backup/Restore ist.
  • T029 [Scope] Filament-UI an neue Typen anpassen: Tabellenfilter/Grouping nach Kategorie (z.B. Config/Compliance/Scripts/Apps/CA), Backup/Restore-Formulare mit Hinweisen zu Restore-Level aus scope.restore_matrix (z.B. CA/enrollment restrictions = preview-only).

Phase 10: Housekeeping Delete-Funktionen für Backups & Versions

  • T060 [HK] BackupSets soft deletable machen:

    • backup_sets (und ggf. backup_items) Migration/Model mit SoftDeletes (deleted_at).
    • Sicherstellen, dass RestoreRuns keine gelöschten BackupSets verwenden; Delete nur erlauben, wenn keine zugehörigen RestoreRuns existieren.
  • T061 [HK] Filament-Delete-Action für BackupSets:

    • In BackupSetResource Delete-Action in List- und/oder Detail-View hinzufügen.
    • Mit Confirmation-Dialog (“This will archive this backup set and hide it from the UI.”).
    • Delete disabled/hidden, wenn restore_runs für das Set existieren.
    • Nach Delete Audit-Log (backup.deleted) schreiben.
  • T062 [HK] PolicyVersions soft deletable machen:

    • policy_versions Migration/Model um SoftDeletes erweitern.
    • Alle Queries und Filament-Resources so lassen, dass standardmäßig nur non-deleted Versions angezeigt werden.
  • T063 [HK] Filament-Delete-Action für PolicyVersions:

    • In PolicyVersionResource Delete-Action hinzufügen (List/Detail).
    • Confirmation + Audit-Log (policy_version.deleted).
  • T064 [HK] Tests für Housekeeping:

    • Feature-Test: Löschen eines BackupSets ohne RestoreRun → deleted_at gesetzt, UI-Eintrag weg, Audit-Log vorhanden.
    • Feature-Test: BackupSet mit RestoreRun → Delete-Action nicht verfügbar.
    • Feature-Test: Löschen einer PolicyVersion → deleted_at gesetzt, nicht mehr in List sichtbar.

Phase 11: Housekeeping Tenant löschen/deaktivieren

  • T070 [HK] Tenants soft deletable machen:

    • tenants Model um SoftDeletes erweitern, Migration ggf. deleted_at hinzufügen.
    • Optional: Feld status (enum/string: active, archived) einführen; beim Delete auf archived setzen.
    • Alle Standard-Queries für Tenants nur active / nicht gelöscht anzeigen.
  • T071 [HK] Tenant-Delete-Action (Deaktivieren) in TenantResource:

    • Delete-/Archive-Action in der Tenant-Liste und/oder Detailseite hinzufügen.
    • Deutlich machen: “Deaktiviert diesen Tenant. Historische Daten bleiben vorhanden, neue Aktionen sind nicht mehr möglich.”
    • Bei Ausführung:
      • deleted_at setzen (und ggf. status = archived),
      • Audit-Log tenant.deleted oder tenant.archived schreiben.
  • T072 [HK] Verhalten für deaktivierte Tenants:

    • In PolicySyncService, BackupService, RestoreService prüfen, dass nur aktive Tenants verwendet werden; bei deaktiviertem Tenant frühzeitig mit verständlicher Fehlermeldung abbrechen.
    • In Filament-Navigation Tenants, Policies, Backups, Restores eines deaktivierten Tenants nicht mehr in Standard-Listen anzeigen (es sei denn, es gibt explizite “Show archived”-Filter).
  • T073 [HK] (Optional) RestoreRuns soft deletable machen:

    • restore_runs Model/Migration mit SoftDeletes.
    • Delete-Action in RestoreRunResource hinzufügen (nur UI-Aufräumung, keine Folgen für Backups).
    • Audit-Log restore_run.deleted schreiben.
  • T074 [HK] Tests für Tenant-Delete:

    • Feature-Test: Tenant löschen/deaktivieren → Tenant taucht nicht mehr in Standardlisten auf, deleted_at (und status) ist gesetzt, Audit-Event existiert.
    • Feature-Test: Versuch, mit deaktiviertem Tenant einen Policy-Sync/Backup/Restore zu starten, führt zu einem klaren Fehler (und kein Graph-Call wird ausgeführt).

Phase 12: Housekeeping Hard Deletes (Force Delete)

  • T075 [HK] Force-Delete-Actions ergänzen:
    • Filament-Listen für Tenants, BackupSets, PolicyVersions, RestoreRuns erhalten „Force delete“ Aktionen (sichtbar nur im Trashed-Filter), mit klarer Confirmation.
    • BackupSets: Force delete nur, wenn keine RestoreRuns existieren; löscht Items mit.
    • Tenants: Force delete nur, wenn archiviert; blockiert für aktive Tenants.
    • Alle Force-Deletes schreiben Audit-Log-Einträge vor der endgültigen Löschung.
    • Tests für Force-Delete-Flows (erfolgreich/blockiert) ergänzen.

Phase 12: Single current tenant ("Highlander")

  • T120 [TENANT] Migration add_is_current_to_tenants:

    • Spalte is_current (boolean, default false, not null) zu tenants hinzufügen.
    • Partielle Unique-Index anlegen, z. B.:
      • UNIQUE INDEX tenants_current_unique ON tenants (is_current) WHERE is_current = true AND deleted_at IS NULL.
  • T121 [TENANT] Tenant-Model anpassen:

    • Methode makeCurrent() implementieren:
      • Transaktion: alle anderen Tenants is_current = false, dieser Tenant is_current = true.
    • Methode static current() implementieren:
      • Wenn INTUNE_TENANT_ID gesetzt ist → Tenant mit dieser GUID laden, sonst Exception, wenn nicht gefunden / deaktiviert.
      • Wenn nicht gesetzt → Tenant mit is_current = true und status = active (und deleted_at null) zurückgeben.
      • Wenn keiner → Exception “No current tenant selected”.
    • findOrCreateDefault() deprecaten/entfernen; keine Dummy-Tenants mehr erzeugen.
  • T122 [TENANT] Data-Migration / Cleanup:

    • Falls mindestens ein Tenant mit app_status = ok existiert:
      • einen als is_current = true markieren (z. B. den ersten).
      • local-tenant auf status = archived, is_current = false setzen.
    • Sicherstellen, dass local-tenant nie wieder als aktueller Kontext verwendet wird.
  • T123 [TENANT] Filament TenantResource UI:

    • Spalte/Badge für is_current in der Liste hinzufügen.
    • Table-Action "Make current" ergänzen:
      • nur sichtbar für aktive Tenants, die nicht is_current sind.
      • ruft makeCurrent() auf und zeigt Notification.
    • Alte Logik entfernen, die local-tenant automatisch als Default nutzt.
  • T124 [TENANT] Consumers refactoren:

    • Alle Vorkommen von findOrCreateDefault() suchen und durch Tenant::current() (oder expliziten Tenant) ersetzen:
      • Policy-Sync (Command + Filament-Action),
      • BackupSet-Erstellung,
      • RestoreRun-Erstellung,
      • ggf. weitere Services.
  • T125 [TENANT] Tests:

    • Unit-Tests für Tenant::current():

      • INTUNE_TENANT_ID gesetzt → nimmt diesen Tenant, Fehler wenn nicht vorhanden.
      • INTUNE_TENANT_ID nicht gesetzt → nimmt den mit is_current = true.
      • kein current Tenant → Exception.
    • Feature-Test für "Make current" in TenantResource:

      • Nach der Action ist genau ein Tenant is_current = true, alle anderen false.
    • Optional: Test, dass local-tenant nach Cleanup nicht mehr als Kontext gewählt wird.

    • T130 [UX] Tabellen-Aktionen in Dropdown bündeln (ActionGroup)

    • In TenantResource (Tenants-Liste) die Zeilen-Aktionen refaktorieren:

      • View (optional) direkt anzeigen.
      • Alle weiteren Aktionen (Edit, Admin consent, Verify configuration, Deactivate, Force delete) in eine Tables\Actions\ActionGroup mit "⋯"-Icon verschieben.
    • Prüfen, ob in anderen Ressourcen mit vielen Row-Actions (z.B. Backups, RestoreRuns) ebenfalls eine ActionGroup sinnvoll ist und diese konsistent einsetzen.