# 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)

```text
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)

```text
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_links` unique 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)

1. UI filters: direction + relationship-type via querystring.
2. Query: use DB filtering via `DependencyQueryService` optional `relationship_type`.
3. Extraction: align unknown/unsupported shapes to warning-only and persist warnings on run record.
4. Tests: add/adjust unit/feature/UI smoke tests for relationship filtering and warning-only behavior.
5. 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] |
