# Implementation Plan: Remove Legacy Tenant Graph Options **Branch**: `088-remove-tenant-graphoptions-legacy` | **Date**: 2026-02-11 | **Spec**: [spec.md](spec.md) **Input**: Feature specification in [spec.md](spec.md) ## Summary Hard cut removal of the deprecated tenant-based Graph options accessor. All Microsoft Graph configuration must be derived exclusively from a resolved `ProviderConnection` via `ProviderConnectionResolver::resolveDefault()` and `ProviderGateway::graphOptions()`. Add a CI guardrail scanning `app/` for `$tenant->graphOptions()` / `Tenant::graphOptions()` and implement a kill-switch by making `Tenant::graphOptions()` throw. ## Technical Context **Language/Version**: PHP 8.4.15 (Laravel 12) **Primary Dependencies**: Filament v5, Livewire v4, Pest v4 **Storage**: PostgreSQL (Sail locally) **Testing**: Pest via `vendor/bin/sail artisan test --compact` **Target Platform**: Containerized Linux deployment (Sail local, Dokploy staging/prod) **Project Type**: Laravel web application (monolith) **Performance Goals**: N/A (internal refactor + CI guard) **Constraints**: - No fallback to tenant-stored credentials. - Guardrail scans `app/` only (do not fail due to `tests/`). - No new Graph endpoints; Graph calls remain routed through `GraphClientInterface`. **Scale/Scope**: Repo-wide refactor of call sites in `app/Services/**`. ## Constitution Check *GATE: Must pass before implementation. Re-check after design decisions.* - Inventory-first / snapshots: **N/A** (no inventory/snapshot semantics change) - Read/write separation: **PASS** (no new write surfaces; existing flows only refactored) - Single contract path to Graph: **PASS** (Graph calls remain through `GraphClientInterface`; only options sourcing changes) - Deterministic capabilities: **N/A** (no capability mapping changes) - RBAC-UX / workspace isolation / tenant isolation: **N/A** (no routing or authorization semantic changes) - Run observability: **N/A** (no new operations or run tracking changes) - Data minimization / safe logging: **PASS** (no secrets introduced; provider credentials remain in credential store) - Filament UI Action Surface Contract: **N/A** (no UI resources/pages are added or modified) ## Project Structure ### Documentation (this feature) ```text specs/088-remove-tenant-graphoptions-legacy/ ├── plan.md ├── research.md ├── data-model.md ├── quickstart.md ├── contracts/ └── tasks.md # created by /speckit.tasks (later) ``` ### Source Code (repository root) ```text app/ ├── Models/ │ └── Tenant.php ├── Services/ │ ├── Providers/ │ │ ├── ProviderConnectionResolver.php │ │ └── ProviderGateway.php │ └── ... (multiple Graph-enabled services) tests/ └── Feature/ └── Guards/ ``` **Structure Decision**: Laravel monolith; refactor stays within existing services/models. ## Implementation Plan ### Phase 0 — Outline & Research (completed) - Documented decisions and call sites in [research.md](research.md). ### Phase 1 — Design & Implementation (planned) 1. **Kill-switch the deprecated accessor** - Update `Tenant::graphOptions()` in `app/Models/Tenant.php` to throw a clear exception explaining that provider connections are required. 2. **Refactor all `app/` call sites off `$tenant->graphOptions()`** - For each call site, resolve the default Microsoft provider connection via `ProviderConnectionResolver::resolveDefault($tenant, 'microsoft')`. - If resolution fails, fail fast with a clear, actionable error (include the effective reason code/message). - Replace option building with `ProviderGateway::graphOptions($connection, $overrides)`. - Update `app/Services/Intune/TenantConfigService.php` (currently returns `$tenant->graphOptions()`), so it no longer provides a tenant-based path. 3. **Add CI guardrail (Pest)** - Add a new guard test under `tests/Feature/Guards/` that scans `app/` for forbidden patterns: - `\$tenant->graphOptions(` - `Tenant::graphOptions(` - Ensure failure message explains how to fix (use provider connection resolution). 4. **Verification** - Run the guard test and the most relevant subsets described in [quickstart.md](quickstart.md). - Run `vendor/bin/sail bin pint --dirty`. ### Phase 2 — Tasks (next step) - Completed: `tasks.md` has been generated and Phase 1 is broken into smaller, reviewable steps. ## Complexity Tracking No constitution violations are required for this feature.