Automatischer Commit und PR erstellt auf Anfrage. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #309
14 KiB
Feature Specification: TenantPilot v1
Status: Historical
Last reviewed: 2026-04-30
Use for: Early product-history context and original v1 framing
Do not use for: Current implementation truth, current roadmap priority, or current spec structure without repo verification
Feature Branch: tenantpilot-v1
Created: 2025-12-10
Status: Draft
Input: TenantPilot v1 scope covering policy inventory, backup, version history, and defensive restore for Intune administrators.
User Scenarios & Testing (mandatory)
User Story 1 - Policy inventory listing (Priority: P1)
Admin can view supported Intune policy types with normalized metadata for selection.
Why this priority: Inventory is the entry point for backup/version flows. Without it, no downstream workflows are usable.
Independent Test: From Filament, navigate to Policies; verify supported types render with identifiers, platform/type metadata, and tenant scoping.
Acceptance Scenarios:
- Given an authenticated admin, When they open the Policies list, Then they see supported policy types with identifiers, platform, and last-updated metadata.
- Given policy filtering by type, When the admin selects a type, Then only matching policies appear and the view remains tenant-scoped.
User Story 2 - Backup creation and browsing (Priority: P1)
Admin creates backup sets containing multiple policies with immutable snapshots and can browse backup details in Filament.
Why this priority: Backups provide safety and enable restore; immutability and audit are foundational.
Independent Test: Initiate a backup set selecting multiple policies; confirm immutable JSONB snapshots persisted, audit log written, and Filament shows backup detail and items.
Acceptance Scenarios:
-
Given selected policies, When the admin creates a backup set, Then backup items store immutable payload snapshots with policy identifiers and types.
-
Given a completed backup set, When the admin opens its detail page, Then all items and metadata display along with the audit record of creation.
-
Given mehrere Backup-Sets existieren, When der Admin ein Backup-Set auswählen oder ansehen möchte, Then sieht er für jedes Set:
- einen sprechenden Namen (nicht nur Timestamp),
- das Erstellungsdatum,
- die Anzahl der enthaltenen Items,
- und optional eine kurze Beschreibung, damit er das Set sinnvoll unterscheiden kann.
User Story 3 - Version history and diff (Priority: P1)
Admin can capture policy versions, view timelines, and compare any two versions with meaningful diffs.
Why this priority: Version visibility and diffs enable rollback readiness and change comprehension.
Independent Test: Create multiple versions for a policy; verify timeline ordering, version metadata, and diff output (human summary + JSON diff where feasible) between any two versions.
Acceptance Scenarios:
- Given an admin triggers version capture, When the version is saved, Then an immutable snapshot and metadata (actor, time, type, tenant) are recorded.
- Given two versions of the same policy, When the admin requests a comparison, Then the UI shows a human-readable summary and structured JSON diff where available.
User Story 4 - Restore with preview and confirmation (Priority: P1)
Admin can run a restore from a backup set with preview/dry-run, selective restore, clear warnings, and required confirmation before execution.
Why this priority: Restore is high-risk; safety features are mandatory for production readiness.
Independent Test: Start a restore from a backup set in preview; view change summary and warnings; select items; confirm execution; verify audit logs and outcomes recorded (success/failure/partial).
Acceptance Scenarios:
-
Given a backup set, When the admin initiates a restore in preview mode, Then the system shows a change summary with selectable items and conflict warnings.
-
Given selected items and explicit confirmation, When execution proceeds, Then applied changes are tenant-scoped and audit logs record start, result, and any failures.
-
Given mehrere Backup-Sets existieren, When der Admin einen Restore Run erstellt, Then zeigt die Auswahl für das "Backup set" mindestens:
- den Backup-Namen,
- das Erstellungsdatum,
- die Anzahl der Items, damit der Admin das richtige Backup-Set sicher auswählen kann.
-
Given ein Restore Run wurde erstellt, When der Admin die Detailseite des Restore Runs öffnet, Then sieht er, welche Policies/Items in diesem Run enthalten sind (z. B. Liste der Policies mit Name/Typ/Plattform).
User Story 5 - Operational readiness and environments (Priority: P2)
Local development uses Sail; deployments target Dokploy staging then production with clear validation steps.
Why this priority: Ensures reproducible local setup and safe promotion to production.
Independent Test: Run the app locally via Sail; validate migrations on staging before production; confirm required env vars and queues/workers are documented.
User Story 6 - Berechtigungsübersicht & Health-Status (Priority: P1)
Als Admin möchte ich für jeden Tenant sehen, welche Microsoft Graph-Berechtigungen erforderlich sind, welche bereits erteilt wurden und welche fehlen, damit ich sicherstellen kann, dass alle Funktionen von TenantPilot sicher und vollständig arbeiten.
Why this priority: Jede neue Funktion kann zusätzliche Berechtigungen benötigen. Ohne transparente Übersicht und Abgleich besteht das Risiko, dass Features still kaputt sind oder unsicher laufen.
Acceptance Scenarios:
-
Given ein Tenant ist in TenantPilot hinterlegt, When der Admin die Tenant-Detailseite öffnet, Then sieht er eine Liste aller erforderlichen Berechtigungen mit Status (z. B. OK, fehlt).
-
Given neue Funktionen wurden eingeführt, die zusätzliche Berechtigungen benötigen und diese wurden in der zentralen Permissions-Liste hinzugefügt, When der Admin die Tenant-Detailseite öffnet, Then erscheinen die neuen Berechtigungen automatisch in der Übersicht und fehlende Berechtigungen werden klar als fehlend markiert.
-
Given der Admin klickt auf "Verify configuration", When TenantPilot einen Graph-Twestcall und/oder das Permission-Setup prüft, Then wird der Status der Berechtigungen aktualisiert (OK/fehlt/Fehler) und es wird ein Audit-Eintrag erstellt.
-
Given ein Tenant hat fehlende kritische Berechtigungen, When andere Features (Policy-Sync, Backup, Restore) diesen Tenant verwenden, Then kann TenantPilot dem Admin entsprechende Warnungen anzeigen oder die Funktion mit einem klaren Fehler abbrechen.
Acceptance Scenarios:
- Given a fresh checkout, When Sail commands run (
./vendor/bin/sail up -d,./vendor/bin/sail artisan migrate), Then the app boots with PostgreSQL and Filament admin available. - Given a pending release, When migrations and restore flows are validated on staging, Then production deployment proceeds with documented steps and environment parity.
Edge Cases
- Graph permissions missing or expired, causing policy fetch/restore failures with clear error mapping and audit entries.
- Large policy payloads or many items in a backup set; ensure JSONB storage and pagination handle load without timeouts.
- Restore conflicts when target tenant already has newer versions; preview must surface warnings and allow skip.
- Partial restore failures; audits must capture per-item outcomes and surface retry guidance.
- Diff generation for incompatible or malformed payloads should fail gracefully with admin-facing messaging.
- Retention/size concerns for snapshots; document defaults and guard against unbounded growth.
Requirements (mandatory)
Functional Requirements
-
FR-001: System MUST list supported Intune policies with normalized metadata and tenant scoping for selection.
-
FR-002: System MUST allow admins to create backup sets containing multiple policies with immutable JSONB payload snapshots.
-
FR-003: Backup creation MUST log audit events including actor, timestamp, tenant, items, and outcome.
-
FR-004: System MUST capture policy versions on demand and present per-policy timelines.
-
FR-005: Users MUST be able to diff any two versions with a human-readable summary and structured JSON diff where feasible.
-
FR-006: Restore MUST support preview/dry-run, selective item restore, and explicit confirmation before applying changes.
-
FR-007: Restore execution MUST produce audit logs covering success, failure, and partial outcomes.
-
FR-008: Graph integration MUST route through a dedicated abstraction layer with standardized error mapping, safe retries, and high-level logging without secrets.
-
FR-009: All policy, version, backup, and restore data MUST be tenant-aware; queries enforce tenant isolation.
-
FR-010: Application MUST run locally via Laravel Sail with PostgreSQL and provide Filament admin flows.
-
FR-011: Deployments MUST target Dokploy staging before production with documented migration and worker implications.
-
FR-012: Tests MUST cover backup composition rules, version immutability, audit events, and Filament backup/restore flows (with Graph boundaries mocked).
-
FR-013: Raw policy snapshots and backup payloads MUST be stored as JSONB with indexes justified by query needs (e.g., FK and time-based; GIN when filters require).
-
FR-014: UI MUST provide clear warnings for potential restore conflicts and require confirmation for destructive operations.
-
FR-015: Admins MUST be able to safely delete (archive) backup sets that are no longer needed. Deletion is implemented as soft-delete with audit logging, and backup sets referenced by completed restore runs cannot be removed.
-
FR-016: Admins MUST be able to delete individual policy versions for housekeeping. Deletion is implemented as soft-delete with audit logging.
-
FR-017: Admins MUST be able to deactivate (soft-delete) a tenant. Deactivated tenants:
- do not appear in default lists,
- cannot be used for new sync/backup/restore operations,
- keep their historical data and audit logs for traceability.
-
FR-018: Admins MAY soft-delete restore runs to keep the UI clean; underlying backup and policy data remains untouched.
Key Entities (include if feature involves data)
- tenants: Represents the deployment tenant context; referenced by all scoped data.
- policies: Normalized metadata for supported Intune policies.
- policy_versions: Immutable snapshots with metadata (actor, timestamp, tenant, policy type).
- backup_sets: Group of backup items with creator, timestamp, and tenant context.
- backup_items: Individual policy snapshots within a backup set (immutable JSONB payload + identifiers).
- restore_runs: Execution records for restores, including preview/actual flags and outcomes.
- audit_logs: Audit trail entries for backups, restores, version captures, and significant Graph actions.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: Admin can create a backup set selecting multiple policies and view immutable backup items with audit logs in Filament.
- SC-002: Policy version history timeline is available per policy and supports comparing any two versions with summary and JSON diff outputs.
- SC-003: Restore preview shows change summaries and conflict warnings; execution requires explicit confirmation and produces audit logs for all outcomes.
- SC-004: Core flows run locally via Sail; staging validation of migrations and restore paths completes before production deployments.
- SC-005: Automated tests covering backup composition, version immutability, audit logging, and Filament backup/restore flows pass via
./vendor/bin/sail artisan test.
Technical Story – Enforce Single Current Tenant ("Highlander Principle")
Context
Aktuell können mehrere Tenants status = active sein. Graph-Operationen (Policy Sync,
Backup, Restore) wählen den Kontext über Heuristiken (findOrCreateDefault,
local-tenant), was zu falschen Tenants und Fehlern führt.
Goal
Es soll immer genau einen klar definierten "current" Tenant geben, über den alle Graph-Operationen laufen. Die Auswahl dieses Tenants ist explizit und transparent (UI + Env), nicht implizit.
Requirements
-
Es gibt ein Flag
is_currentintenants, das den aktuell verwendeten Kontext markiert. -
Die Datenbank erzwingt per partiellem Unique Index, dass höchstens ein nicht-gelöschter Tenant
is_current = truehaben kann. -
Tenant::current()liefert:- falls
INTUNE_TENANT_IDgesetzt ist, genau diesen Tenant (Fehler, wenn er nicht existiert oder deaktiviert ist), - sonst den Tenant mit
is_current = trueundstatus = active. - falls keiner gefunden wird, eine klare Exception (“No current tenant selected”); es werden keine Dummy-Tenants erzeugt.
- falls
-
In der Tenant-Verwaltung gibt es eine Action "Make current", die:
- in einer Transaktion alle anderen Tenants auf
is_current = falsesetzt und den gewählten Tenant aufis_current = true, - nur für aktive Tenants verfügbar ist.
- in einer Transaktion alle anderen Tenants auf
-
Der frühere Placeholder
local-tenantdarf nicht mehr als Graph-Kontext genutzt werden; sobald ein echter Tenant existiert, wird er archiviert und ist nieis_current. -
Alle Graph-basierten Funktionen (Policy Sync, Backup, Restore) verwenden konsistent
Tenant::current()oder einen explizit übergebenen Tenant.Tenant-level actions such as "Admin consent" and "Verify configuration" MUST be exposed on the tenant detail view (and/or row actions), not as a global button without explicit tenant context.
UX Guideline – Table Actions / Dropdowns
- Tabellen in Filament mit mehr als zwei Zeilen-Aktionen (z.B. View, Edit, Admin consent, Verify, Deactivate, Force delete) MÜSSEN ihre Aktionen in einem kompakten Dropdown / ActionGroup bündeln, statt alle Buttons nebeneinander anzuzeigen.
- Ausnahmen: besonders häufige, nicht-destruktive Aktionen (z.B. "View") dürfen weiterhin als einzelner Button sichtbar bleiben; alle weiteren Aktionen (z.B. Admin-Aktionen, Housekeeping) sollen im Dropdown liegen.
- Ziel: die Tabellen bleiben übersichtlich, Spaltenbreite wird begrenzt, und Admins bekommen eine konsistente "⋯"-Interaktion für erweiterte Aktionen.