TenantAtlas/specs/046-inventory-sync-button/research.md
ahmido cf5b0027e3 046-inventory-sync-button (#47)
Zusammenfassung: Fügt im „Run Inventory Sync“-Modal einen include_dependencies-Toggle hinzu und persistiert die Auswahl in der InventorySyncRun.selection_payload. Tests, Quickstart und Tasks wurden entsprechend aktualisiert.

Files: InventoryLanding.php, InventorySyncButtonTest.php, quickstart.md, tasks.md
Motivation: Ermöglicht explizites Ein-/Ausschalten der Dependency-Extraktion pro Sync-Run (z. B. Assignments/Scope Tags/Foundations), statt starrer Defaults. Passt zur bestehenden selection_hash-Logik (InventorySelectionHasher) und zur deterministischen Selektionspersistenz.
Verhalten: include_dependencies ist im Modal standardmäßig true. Wird die Option gesetzt, landet der Wert als bool im selection_payload und beeinflusst selection_hash über die Normalisierung.
Tests: Neuer/angepasster Pest-Test stellt sicher, dass include_dependencies in selection_payload persistiert. Lokaler Testlauf:
./vendor/bin/sail artisan test tests/Feature/Inventory/InventorySyncButtonTest.php → alle Tests für diese Datei bestanden.
./vendor/bin/pint --dirty wurde ausgeführt (Formatting ok).
How to test (quick):
Start Sail + Queue:
Im Admin → Inventory: „Run Inventory Sync“ öffnen, Include dependencies umschalten, ausführen.
Prüfen: neu erstellter InventorySyncRun.selection_payload.include_dependencies ist der gesetzten Auswahl entsprechend. Oder laufen lassen:
Notes / Next steps:
Diese Änderung bereitet den Weg, später die Dependency-Extraction (042-inventory-dependencies-graph) optional tiefer zu integrieren.
Working tree ist sauber; es gibt ein nicht eingebundenes Verzeichnis 0800-future-features (unrelated).

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #47
2026-01-09 22:15:04 +00:00

3.6 KiB

Phase 0 Research: Inventory Sync Button (046)

Date: 2026-01-09

Findings

Existing patterns to reuse

DB-backed notifications

  • Filament DB notifications are already used in multiple places.
  • Example: Policy Sync action calls Filament\Notifications\Notification::make()->sendToDatabase(auth()->user())->send().

Bottom-right progress widget

  • The bottom-right progress widget is implemented by App\Livewire\BulkOperationProgress and renders resources/views/livewire/bulk-operation-progress.blade.php.
  • It polls BulkOperationRun filtered by tenant_id = Tenant::current()->id and user_id = auth()->id().
  • It is injected globally into Filament via a render hook in App\Providers\Filament\AdminPanelProvider.

Inventory Sync run records

  • Inventory sync runs are already persisted in inventory_sync_runs with counts and status.
  • Current InventorySyncService::syncNow(...) runs inline and uses locks/concurrency to create/update InventorySyncRun.

Authorization

  • The app already uses tenant-role based authorization for sync operations (e.g. User::canSyncTenant($tenant) in TenantResource).

Inventory selection payload

  • Inventory Sync requires a selection payload with shape: {policy_types: list<string>, categories: list<string>, include_foundations: bool, include_dependencies: bool}.
  • There is no existing UI picker for inventory selection.

Decisions

Decision: Start Inventory Sync as a queued job

  • Chosen: Dispatch an Inventory Sync job from the UI action.
  • Rationale: Aligns with existing background operation UX and avoids blocking Livewire requests.
  • Alternatives considered:
    • Run inline (current syncNow) — rejected due to UX (slow request) and mismatch with existing “progress widget” expectations.

Decision: Use DB notifications + progress widget UX consistent with Policy/Bulk operations

  • Chosen: Create a BulkOperationRun (resource inventory, action sync) so the existing bottom-right widget shows progress; also send DB notifications at start and completion/failure.
  • Rationale: Matches established UX language and avoids inventing new UI surfaces.
  • Alternatives considered:
    • Only show toast notifications — rejected; user explicitly requires DB notification panel + progress widget.

Decision: Authorize via tenant role sync permission

  • Chosen: Gate the UI action using auth()->user()->canSyncTenant(Tenant::current()).
  • Rationale: Aligns with existing “sync” authorization patterns already used for tenant/policy operations.
  • Alternatives considered:
    • Introduce new permission strings/roles — rejected for MVP; adds RBAC surface area.

Decision: Default selection = “full inventory”

  • Chosen: Dispatch inventory sync with policy types set to PolicyTypeResolver::supportedPolicyTypes(), empty categories, and include_foundations=true, include_dependencies=true.
  • Rationale: Simplest interpretation of “Run Inventory Sync” without inventing a new picker UX.
  • Alternatives considered:
    • Reuse backup policy picker UI — rejected; different domain (backup selection), more UX than requested.

Decision: Attribute initiator on run record and audit trail

  • Chosen: Store initiator identity on InventorySyncRun and also emit an audit record.
  • Rationale: Improves traceability and aligns with constitution principle “Automation must be Idempotent & Observable”.
  • Alternatives considered:
    • Audit log only — rejected (you chose C).

Open Questions (for Phase 1 design)

  • None remaining for planning; implementation will add a dedicated queued job.