Summary
Kurz: Implementiert Feature 054 — canonical OperationRun-flow, Monitoring UI, dispatch-safety, notifications, dedupe, plus small UX safety clarifications (RBAC group search delegated; Restore group mapping DB-only).
What Changed
Core service: OperationRun lifecycle, dedupe and dispatch helpers — OperationRunService.php.
Model + migration: OperationRun model and migration — OperationRun.php, 2026_01_16_180642_create_operation_runs_table.php.
Notifications: queued + terminal DB notifications (initiator-only) — OperationRunQueued.php, OperationRunCompleted.php.
Monitoring UI: Filament list/detail + Livewire pieces (DB-only render) — OperationRunResource.php and related pages/views.
Start surfaces / Jobs: instrumented start surfaces, job middleware, and job updates to use canonical runs — multiple app/Jobs/* and app/Filament/* updates (see tests for full coverage).
RBAC + Restore UX clarifications: RBAC group search is delegated-Graph-based and disabled without delegated token; Restore group mapping remains DB-only (directory cache) and helper text always visible — TenantResource.php, RestoreRunResource.php.
Specs / Constitution: updated spec & quickstart and added one-line constitution guideline about Graph usage:
spec.md
quickstart.md
constitution.md
Tests & Verification
Unit / Feature tests added/updated for run lifecycle, notifications, idempotency, and UI guards: see tests/Feature/* (notably OperationRunServiceTest, MonitoringOperationsTest, OperationRunNotificationTest, and various Filament feature tests).
Full test run locally: ./vendor/bin/sail artisan test → 587 passed, 5 skipped.
Migrations
Adds create_operation_runs_table migration; run php artisan migrate in staging after review.
Notes / Rationale
Monitoring pages are explicitly DB-only at render time (no Graph calls). Start surfaces enqueue work only and return a “View run” link.
Delegated Graph access is used only for explicit user actions (RBAC group search); restore mapping intentionally uses cached DB data only to avoid render-time Graph calls.
Dispatch wrapper marks runs failed immediately if background dispatch throws synchronously to avoid misleading “queued” states.
Upgrade / Deploy Considerations
Run migrations: ./vendor/bin/sail artisan migrate.
Background workers should be running to process queued jobs (recommended to monitor queue health during rollout).
No secret or token persistence changes.
PR checklist
Tests updated/added for changed behavior
Specs updated: 054-unify-runs-suitewide docs + quickstart
Constitution note added (.specify)
Pint formatting applied
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #63
Summary
Adds a tenant-scoped Entra Groups “Directory Cache” to enable DB-only group name resolution across the app (no render-time Graph calls), plus sync runs + observability.
What’s included
• Entra Groups cache
• New entra_groups storage (tenant-scoped) for group metadata (no memberships).
• Retention semantics: groups become stale / retained per spec (no hard delete on first miss).
• Group Sync Runs
• New “Group Sync Runs” UI (list + detail) with tenant isolation (403 on cross-tenant access).
• Manual “Sync Groups” action: creates/reuses a run, dispatches job, DB notification with “View run” link.
• Scheduled dispatcher command wired in console.php.
• DB-only label resolution (US3)
• Shared EntraGroupLabelResolver with safe fallback Unresolved (…last8) and UUID guarding.
• Refactors to prefer cached names (no typeahead / no live Graph) in:
• Tenant RBAC group selects
• Policy version assignments widget
• Restore results + restore wizard group mapping labels
Safety / Guardrails
• No render-time Graph calls: fail-hard guard test verifies UI paths don’t call GraphClientInterface during page render.
• Tenant isolation & authorization: policies + scoped queries enforced (cross-tenant access returns 403, not 404).
• Data minimization: only group metadata is cached (no membership/owners).
Tests / Verification
• Added/updated tests under tests/Feature/DirectoryGroups and tests/Unit/DirectoryGroups:
• Start sync → run record + job dispatch + upserts
• Retention purge semantics
• Scheduled dispatch wiring
• Render-time Graph guard
• UI/resource access isolation
• Ran:
• ./vendor/bin/pint --dirty
• ./vendor/bin/sail artisan test tests/Feature/DirectoryGroups
• ./vendor/bin/sail artisan test tests/Unit/DirectoryGroups
Notes / Follow-ups
• UI polish remains (picker/lookup UX, consistent progress widget/toasts across modules, navigation grouping).
• pr-gate checklist still has non-blocking open items (mostly UX/ops polish); requirements gate is green.
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #57
Summary
This PR implements Spec 049 – Backup/Restore Job Orchestration: all critical Backup/Restore execution paths are job-only, idempotent, tenant-scoped, and observable via run records + DB notifications (Phase 1). The UI no longer performs heavy Graph work inside request/Filament actions for these flows.
Why
We want predictable UX and operations at MSP scale:
• no timeouts / long-running requests
• reproducible run state + per-item results
• safe error persistence (no secrets / no token leakage)
• strict tenant isolation + auditability for write paths
What changed
Foundational (Runs + Idempotency + Observability)
• Added a shared RunIdempotency helper (dedupe while queued/running).
• Added a read-only BulkOperationRuns surface (list + view) for status/progress.
• Added DB notifications for run status changes (with “View run” link).
US1 – Policy “Capture snapshot” is job-only
• Policy detail “Capture snapshot” now:
• creates/reuses a run (dedupe key: tenant + policy.capture_snapshot + policy DB id)
• dispatches a queued job
• returns immediately with notification + link to run detail
• Graph capture work moved fully into the job; request path stays Graph-free.
US3 – Restore runs orchestration is job-only + safe
• Live restore execution is queued and updates RestoreRun status/progress.
• Per-item outcomes are persisted deterministically (per internal DB record).
• Audit logging is written for live restore.
• Preview/dry-run is enforced as read-only (no writes).
Tenant isolation / authorization (non-negotiable)
• Run list/view/start are tenant-scoped and policy-guarded (cross-tenant access => 403, not 404).
• Explicit Pest tests cover cross-tenant denial and start authorization.
Tests / Verification
• ./vendor/bin/pint --dirty
• Targeted suite (examples):
• policy capture snapshot queued + idempotency tests
• restore orchestration + audit logging + preview read-only tests
• run authorization / tenant isolation tests
Notes / Scope boundaries
• Phase 1 UX = DB notifications + run detail page. A global “progress widget” is tracked as Phase 2 and not required for merge.
• Resilience/backoff is tracked in tasks but can be iterated further after merge.
Review focus
• Dedupe behavior for queued/running runs (reuse vs create-new)
• Tenant scoping & policy gates for all run surfaces
• Restore safety: audit event + preview no-writes
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #56
Ordering + limit-only Test für created_at DESC in DependencyExtractionFeatureTest.php
UI Test für masked Identifier (ID: 123456…) + Guest-Access blocked in InventoryItemDependenciesTest.php
Quickstart ergänzt um manuellen <2s Check in quickstart.md
pr-gate Checkbox-Format normalisiert (kein leading space) in pr-gate.md
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #49
tenantpilot.php/graph_contracts.php include the new policy type, Graph contract, and /assign assignment flow (deviceHealthScriptAssignments payload key).
ScriptsPolicyNormalizer now supports deviceComplianceScript (more metadata + script display), and InteractsWithODataTypes knows the new type.
UI diff view highlights detection-script changes (same logic as other script policies) once tenantpilot.display.show_script_content is enabled.
Added regression coverage in tests/Feature/Filament/ScriptPoliciesNormalizedDisplayTest plus new feature test DeviceComplianceScriptPolicyTypeTest.
Runs: ScriptPoliciesNormalizedDisplayTest.php, ./vendor/bin/pint --dirty.
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #29
Added a resolver/validation flow that fetches endpoint security template definitions and enforces them before CREATE/PATCH so we don’t call Graph with invalid settings.
Hardened restore endpoint resolution (built-in fallback to deviceManagement/configurationPolicies, clearer error metadata, preview-only fallback when metadata is missing) and exposed Graph path/method in restore UI details.
Stripped read-only fields when PATCHing endpointSecurityIntent so the request no longer fails with “properties not patchable”.
Added regression tests covering endpoint security restore, intent sanitization, unknown type safety, Graph error metadata, and endpoint resolution behavior.
Testing
GraphClientEndpointResolutionTest.php
./vendor/bin/pint --dirty
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #25
Hydrate configurationPolicies/{id}/settings for endpoint security/baseline policies so snapshots include real rule data.
Treat those types like Settings Catalog policies in the normalizer so they show the searchable settings table, recognizable categories, and readable choice values (firewall-specific formatting + interface badge parsing).
Improve “General” tab cards: badge lists for platforms/technologies, template reference summary (name/family/version/ID), and ISO timestamps rendered as YYYY‑MM‑DD HH:MM:SS; added regression test for the view.
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #23
Replaces the “Add Policies” picker with a modal table (search, pagination, multi-select).
Adds filters: policy type, platform, last synced, ignored, has versions; “Select all” applies to the current filtered results.
Improves identifiers shown (short external id), and fixes has-versions filtering behavior.
Backup set items table: groups row actions (View policy / Remove) into an action group.
Adds bulk action to remove multiple backup items at once.
Updates/adds tests covering the picker table bulk add and backup items bulk remove.
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #21
This PR completes Feature 014 (Enrollment & Autopilot).
Adds normalization for:
Autopilot deployment profiles (windowsAutopilotDeploymentProfile)
Enrollment Status Page / ESP (windowsEnrollmentStatusPage)
Enrollment Restrictions (enrollmentRestriction, restore remains preview-only)
Improves settings readability:
Autopilot OOBE settings are expanded into readable key/value entries
Enrollment restriction platform restrictions are shown as explicit fields (with sensible defaults)
Array/list values render as badges (avoids Blade rendering crashes on non-string values)
Fixes enrollment configuration type collisions during sync:
Canonical type resolution prevents enrollmentRestriction from “claiming” ESP items
Safe reclassification updates existing wrong rows instead of skipping
Enhances reclassification command:
Can detect ESP even if a policy has no local versions (fetches snapshot from Graph)
Dry-run by default; apply with --write
Tests
Added/updated unit + Filament feature tests for normalization and UI rendering.
Preview-only enforcement for enrollment restrictions is covered.
Targeted test suite and Pint are green.
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #20
Wichtige Änderungen:
- Eine neue "Restore via Wizard"-Aktion wurde der PolicyVersion-Tabelle hinzugefügt.
- Diese Aktion ermöglicht die Erstellung eines Einzelposten-BackupSets aus dem ausgewählten
Policy-Version-Snapshot.
- Der CreateRestoreRun Wizard unterstützt nun das Vorbefüllen seiner Formularfelder basierend auf
Abfrageparametern, was eine nahtlose Übergabe von der PolicyVersion-Aktion ermöglicht.
- Umfassende Feature-Tests wurden hinzugefügt, um die korrekte Funktionalität und Integration dieses
neuen Workflows sicherzustellen.
- Die specs/011-restore-run-wizard/tasks.md wurde aktualisiert, um den Abschluss von Aufgabe T023
widerzuspiegeln.
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #17
Resolves assignment filter names when Graph stores filter IDs at assignment root.
Tracks assignment fetch success/failure and shows clearer UI states for versions.
Adds scope tag fallback display in backup set items.
Restored versions now capture applied assignments consistently.
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #8