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
3.9 KiB
Implementation Plan: Inventory Dependencies Graph (042)
Branch: feat/042-inventory-dependencies-graph | Date: 2026-01-10 | Spec: specs/042-inventory-dependencies-graph/spec.md
Summary
Provide a read-only dependency view for an Inventory Item (direct inbound/outbound edges) with filters for direction and relationship type. Dependencies are derived from inventory sync payloads and stored idempotently in inventory_links.
MVP Constraints (Explicit)
- Direct neighbors only (no depth > 1 traversal / transitive blast radius).
- Limit-only queries (no pagination/cursors).
- UI shows <= 50 edges per direction (<= 100 total when showing both directions).
- Unknown/unsupported reference shapes are warning-only (no edge created).
- Warnings persist on
InventorySyncRun.error_context.warnings[]. - No new tables for warnings.
Technical Context
Language/Version: PHP 8.4.x Primary Dependencies: Laravel 12, Filament v4, Livewire v3 Storage: PostgreSQL (JSONB) Testing: Pest v4 Target Platform: Web (Filament admin) Project Type: Laravel monolith Performance Goals: dependency section renders in <2s with indexed + limited queries Constraints: tenant scoped only; no extra Graph lookups for enrichment Scale/Scope: edge rendering and extraction are hard-capped
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
- Inventory-first: edges reflect last observed sync payloads; no backups/snapshots.
- Read/write separation: UI is read-only; no Intune write paths.
- Single contract path to Graph: no new Graph calls for this feature.
- Tenant isolation: all edges stored/queried with
tenant_id. - Automation: idempotent via unique key + upsert; observable via run record; warnings persisted.
- Data minimization: only metadata stored; no secrets/tokens.
Gate status: PASS.
Project Structure
Documentation (this feature)
specs/042-inventory-dependencies-graph/
├── plan.md
├── spec.md
├── tasks.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│ ├── README.md
│ └── dependency-edge.schema.json
└── checklists/
├── pr-gate.md
└── requirements.md
Source Code (repository root)
app/Filament/Resources/InventoryItemResource.php
app/Models/InventoryItem.php
app/Models/InventoryLink.php
app/Models/InventorySyncRun.php
app/Services/Inventory/DependencyExtractionService.php
app/Services/Inventory/DependencyQueryService.php
app/Support/Enums/RelationshipType.php
resources/views/filament/components/dependency-edges.blade.php
tests/Feature/InventoryItemDependenciesTest.php
tests/Feature/DependencyExtractionFeatureTest.php
tests/Unit/DependencyExtractionServiceTest.php
Phase 0: Research (Output: research.md)
Document decisions + rationale + alternatives for MVP clarifications (limit-only, 50 per direction, warnings-on-run-record, warning-only unknown shapes, required foundation_type metadata, relationship-type filter).
Phase 1: Design (Outputs: data-model.md, contracts/*, quickstart.md)
- Data model: entities and fields, including
inventory_linksunique key and metadata shapes. - Contracts: JSON schema describing the dependency edge data passed to the UI.
- Quickstart: how to view dependencies and run targeted tests.
Phase 2: Implementation Plan (MVP)
- UI filters: direction + relationship-type via querystring.
- Query: use DB filtering via
DependencyQueryServiceoptionalrelationship_type. - Extraction: align unknown/unsupported shapes to warning-only and persist warnings on run record.
- Tests: add/adjust unit/feature/UI smoke tests for relationship filtering and warning-only behavior.
- Quality gates: Pint + targeted Pest tests.
Complexity Tracking
None for MVP (no constitution violations). | [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |