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