# Implementation Plan: Internal Tenant Model Naming Consolidation **Branch**: `300-internal-tenant-model-naming-consolidation` | **Date**: 2026-05-13 | **Spec**: `specs/300-internal-tenant-model-naming-consolidation/spec.md` **Input**: Feature specification from `/specs/300-internal-tenant-model-naming-consolidation/spec.md` ## Summary Spec 300 is a structural cleanup after the managed-environment cutover pack. Current repo truth already has `App\Models\ManagedEnvironment`, `ManagedEnvironmentFactory`, `managed_environments`, `managed_environment_id`, and canonical workspace/environment routes, but active technical owners still use Tenant-first names across Filament resources/pages/widgets, route parameters, services, tests, migration filenames, table names, index/constraint names, and provider-adjacent payloads. The implementation approach is inventory-first: classify every remaining tenant reference, rename only platform-owned Managed Environment references, preserve provider-specific and framework-required terms, run focused route/RBAC/Filament/browser validation, and leave no compatibility alias or legacy route in final state. ## Technical Context **Language/Version**: PHP 8.4.15, Laravel 12.52.0 **Primary Dependencies**: Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, Laravel Sail 1.52.0 **Storage**: PostgreSQL; current source-of-truth table is `managed_environments` **Testing**: Pest via `cd apps/platform && ./vendor/bin/sail artisan test --compact`; Browser tests under `apps/platform/tests/Browser` for smoke anchors **Validation Lanes**: Feature/Guards, Workspaces, ProviderConnections, RequiredPermissions, Filament, Rbac, targeted Browser smoke, Pint dirty, `git diff --check` **Target Platform**: Laravel SaaS admin app deployed via Dokploy containers; local validation via Sail **Project Type**: Monorepo with Laravel platform app under `apps/platform` **Performance Goals**: No broad suite repair loop by default; keep scans and tests focused around structural rename blast radius **Constraints**: No runtime behavior change, no production compatibility layer, no route resurrection, no RBAC widening, no provider payload corruption **Scale/Scope**: Structural rename across platform-owned environment concepts only ## UI / Surface Guardrail Plan - **Guardrail scope**: workflow/route/resource guardrail change, no intended visible UI redesign - **Native vs custom classification summary**: native Filament/resource/page behavior preserved - **Shared-family relevance**: canonical links, navigation/route registration, global search, audit metadata, OperationRun metadata, guard tests - **State layers in scope**: route binding, page/resource class names, table/column/index/constraint names, helper names, test helper names, audit/metadata keys - **Audience modes in scope**: operator-MSP and support-platform only as existing surfaces; no new customer-facing mode - **Decision/diagnostic/raw hierarchy plan**: unchanged - **Raw/support gating plan**: unchanged - **One-primary-action / duplicate-truth control**: unchanged; any touched actions keep existing hierarchy - **Handling modes by drift class or surface**: review-mandatory for active `Tenant*` technical owners; allowed classification for provider/framework/historical/regression-guard - **Repository-signal treatment**: review-mandatory for final scans, route proof, helper retirement, DB naming, provider allowlist, and browser anchors - **Special surface test profiles**: `route-contract`, `standard-native-filament`, `global-context-shell`, `browser-smoke` for selected anchors - **Required tests or manual smoke**: focused Pest guard/feature lanes plus selected Browser smokes - **Exception path and spread control**: provider-specific and framework-required tenant terms are documented in `allowed-tenant-references.md`; no unclassified exception - **Active feature PR close-out entry**: Guardrail / Structural Tenant Naming Consolidation / Smoke Coverage ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes - **Systems touched**: `ManagedEnvironmentLinks`, workspace intended URL handling, Filament resource/page discovery and routes, route model binding, global search, RBAC helper/policies, OperationRun metadata, audit logs, evidence/report/review references, tests - **Shared abstractions reused**: Existing route helpers, existing RBAC/policy helpers, existing OperationRun link/service truth, existing Filament v5 resources/pages/actions - **New abstraction introduced? why?**: none - **Why the existing abstraction was sufficient or insufficient**: Existing environment-first helpers and models are sufficient; the issue is remaining names around them. - **Bounded deviation / spread control**: Provider-specific and Filament framework terms remain only with explicit classification. ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: no - **Central contract reused**: Existing `OperationRunLinks`, `OperationRunService`, and OperationRun monitoring semantics remain unchanged if touched - **Delegated UX behaviors**: N/A - **Surface-owned behavior kept local**: N/A - **Queued DB-notification policy**: N/A - **Terminal notification path**: N/A - **Exception path**: none ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: yes - **Provider-owned seams**: Microsoft/Entra tenant identifiers, Graph `tenantId`, `entra_tenant_id`, `microsoft_tenant_id`, target-scope provider metadata, raw provider payloads - **Platform-core seams**: Managed Environment model/table/resource/page/service/helper naming, route parameters, platform metadata keys, evidence/report/review references - **Neutral platform terms / contracts preserved**: `ManagedEnvironment`, `managed_environment_id`, `environment`, `workspace`, `ManagedEnvironmentLinks` - **Retained provider-specific semantics and why**: Microsoft/Entra terms stay because they represent external directory identity, not platform object ownership. - **Bounded extraction or follow-up path**: document-in-feature. Stop only if ambiguous active platform-owned references cannot be classified safely. ## Constitution Check *GATE: Must pass before implementation. Re-check after structural rename phases.* - Inventory-first: no inventory domain change; source scans/classification precede edits. - Read/write separation: no new user-triggered write behavior; touched destructive actions must keep confirmation, authorization, audit, and tests. - Graph contract path: no Graph endpoint changes; provider-specific Graph tenant identifiers remain provider-owned. - Deterministic capabilities: no capability derivation change. - RBAC-UX: `/admin` and `/system` planes remain separated; workspace/environment non-entitlement stays 404; member-without-capability stays 403. - Workspace isolation: workspace remains primary session context; Managed Environment remains secondary context. - Tenant isolation: current tenant-owned-by-history semantics are preserved behaviorally while platform-owned naming moves to environment-first. - Run observability: no new queued/remote work; OperationRun metadata naming may change only where platform-owned. - Test governance: focused structural rename lanes are explicit; no broad test family growth by default. - Proportionality: broad rename is justified as post-cutover cleanup; no new runtime abstraction. - No premature abstraction: no registries/resolvers/frameworks added. - Persisted truth: no new table/entity/product truth; only names may change. - Behavioral state: no new states or reason families. - Shared pattern first: existing link/RBAC/Filament/OperationRun patterns are reused. - Provider boundary: platform-owned Tenant-first terms are removed; provider-owned tenant terms are kept and documented. - LEAN-001: pre-production posture means no compatibility aliases, dual paths, or historical fixtures unless a spec-blocking migration risk is discovered. - Filament v5: Livewire v4.0+ is required; this repo has Livewire 4.1.4. - Laravel 12 panel providers: remain registered in `apps/platform/bootstrap/providers.php`, not `bootstrap/app.php`. - Global search: any renamed globally searchable resource must keep View/Edit pages or disable global search. - Filament actions: any touched destructive actions must remain `Action::make(...)->action(...)` with `->requiresConfirmation()` and authorization. - Asset strategy: unchanged; if assets are unexpectedly registered, deployment must run `cd apps/platform && php artisan filament:assets`. ## Test Governance Check - **Test purpose / classification by changed surface**: Feature guards for route/helper/naming contracts; Filament/Livewire feature tests for resources/pages/actions; Unit tests for pure helper services; Browser smoke for selected visible anchors. - **Affected validation lanes**: Feature/Guards, Workspaces, ProviderConnections, RequiredPermissions, Filament, Rbac, targeted Browser. - **Why this lane mix is the narrowest sufficient proof**: It proves route/RBAC equivalence and stale-name absence without treating the rename as a full-suite stabilization spec. - **Narrowest proving command(s)**: - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/RequiredPermissions` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Rbac` - **Fixture / helper / factory / seed / context cost risks**: Rename helpers without widening default workspace/provider/browser setup. - **Expensive defaults or shared helper growth introduced?**: no - **Heavy-family additions, promotions, or visibility changes**: none planned; Browser anchors stay explicit. - **Surface-class relief / special coverage rule**: `standard-native-filament` unless a visible context-shell/browser anchor changes. - **Closing validation and reviewer handoff**: final scans, focused lanes, Browser anchors, Pint dirty, `git diff --check`, and close-out inventory. - **Budget / baseline / trend follow-up**: none expected; document any unexpected lane runtime growth. - **Review-stop questions**: Did any active platform-owned `Tenant*` owner remain? Did route parameters still use `{tenant}` for platform environment routes? Did provider terms remain correct? Did global search remain valid? Did RBAC widen? - **Escalation path**: document-in-feature; follow-up-spec only for unresolved migration/schema risk or ambiguous platform-owned references. - **Active feature PR close-out entry**: Guardrail / Structural Tenant Naming Consolidation / Smoke Coverage - **Why no dedicated follow-up spec is needed**: The rename is explicitly scoped as the post-297-299 cleanup; unresolved blockers must stop this spec rather than silently deferring core cleanup. ## Project Structure ### Documentation (this feature) ```text specs/300-internal-tenant-model-naming-consolidation/ ├── allowed-tenant-references.md ├── checklists/ │ └── requirements.md ├── plan.md ├── spec.md ├── tasks.md └── tenant-reference-inventory.md ``` ### Source Code (repository root) ```text apps/platform/ ├── app/ │ ├── Console/Commands/ │ ├── Filament/ │ │ ├── Concerns/ │ │ ├── Pages/ │ │ ├── Resources/ │ │ ├── System/ │ │ └── Widgets/ │ ├── Http/Controllers/ │ ├── Jobs/ │ ├── Models/ │ ├── Policies/ │ ├── Services/ │ └── Support/ ├── config/ ├── database/ │ ├── factories/ │ └── migrations/ ├── resources/ ├── routes/ └── tests/ ├── Browser/ ├── Feature/ └── Unit/ ``` **Structure Decision**: Use the existing Laravel/Filament layout. Do not introduce new base folders. Rename files/classes in-place to established destination names. ## Complexity Tracking | Violation | Why Needed | Simpler Alternative Rejected Because | |-----------|------------|-------------------------------------| | Broad structural rename | Active technical names keep old Tenant-first architecture alive after route/copy cutover | Comments/docs alone do not stop future code from using active `Tenant*` classes/helpers/routes | | Migration/index/constraint rename review | DB source truth is already `managed_environment`, but tenant-named migration files/indexes/constraints remain | Leaving schema names mixed makes future migrations and guard tests ambiguous | ## Proportionality Review - **Current operator problem**: Future platform/environment work can regress visible behavior and provider boundaries because active code still presents Tenant as the platform managed target. - **Existing structure is insufficient because**: Specs 297-299 cleaned route/copy/final seal surfaces, not internal class/table/helper ownership. - **Narrowest correct implementation**: Classify first, rename platform-owned names only, preserve provider/framework/historical/guard terms, and prove equivalence. - **Ownership cost created**: High review and testing cost, plus migration/schema risk; contained by phased tasks and final inventory. - **Alternative intentionally rejected**: Leave active internal names as legacy debt. Rejected because the project is pre-production and LEAN-001 favors canonical replacement over legacy preservation. - **Release truth**: Current-release structural cleanup ## Repository Truth From Preparation - Current branch before prep: `platform-dev`, clean. - Current branch after `create-new-feature`: `300-internal-tenant-model-naming-consolidation`. - Latest starting commit: `b98bafcf feat: finalize managed environment cutover seal (#354)`. - Related specs: - `specs/297-managed-environment-canonical-route-cutover/` has completed task/checklist signals and route-cutover artifacts. - `specs/298-managed-environment-terminology-copy-cleanup/` has completed checklist signals and terminology audit artifacts. - `specs/299-managed-environment-cutover-final-seal/` has completed checklist signals and final cutover audit artifacts. - Current model/table truth: - `App\Models\ManagedEnvironment` exists. - `ManagedEnvironmentFactory` exists. - `managed_environments` exists. - No active `App\Models\Tenant` model was found through application info or `app/Models` scan. - Current route truth: - `/admin/workspaces/{workspace}/environments/...` routes exist. - `/admin/t` and `/admin/tenants` had no matching routes via Boost route lookup. - Sail route scan shows canonical environment routes still use `{tenant}` as a route parameter and active classes such as `TenantDashboard`, `TenantDiagnostics`, and `TenantRequiredPermissions`. - Current scan volume: - Broad tenant scan: 2323 line hits. - Provider-allowed scan: 1661 line hits. - Migration/schema scan: 851 line hits. - Legacy route/helper/resource scan: 242 line hits. ## Phase 0: Preparation And Safety 1. Confirm branch and dirty state. 2. Refresh the inventory scans in `tenant-reference-inventory.md`. 3. Stop if unrelated uncommitted changes exist. 4. Stop if production-data migration requirements are discovered. 5. Confirm no app implementation begins until spec/plan/tasks/checklist are accepted. ## Phase 1: Baseline Inventory And Guard Tests 1. Run required route/source/provider/schema scans. 2. Expand `tenant-reference-inventory.md` from preparation summary into file-level classification. 3. Expand `allowed-tenant-references.md` with all provider/framework/historical/regression-guard references. 4. Add/update guard tests for route resurrection, active `Tenant*` platform owners, stale helper names, and provider terminology preservation. ## Phase 2: DB And Schema Naming Cleanup 1. Verify `managed_environments` remains the source-of-truth table. 2. Rename platform-owned tenant-named tables/columns/indexes/constraints where safe. 3. Rename migration filenames/classes where they are historical names for active platform Managed Environment truth and pre-production safety allows it. 4. Keep provider-owned `entra_tenant_id` / `microsoft_tenant_id` payload fields. 5. Validate with `migrate:fresh --seed` or document why targeted migration validation is the narrower proof. ## Phase 3: Model, Factory, Service, And Helper Rename 1. Keep `ManagedEnvironment` model and `ManagedEnvironmentFactory` as canonical. 2. Rename platform-owned model classes such as `TenantPermission`, `TenantSetting`, `TenantRoleMapping`, `TenantOnboardingSession`, and review/triage classes when classification says they represent Managed Environment-owned truth. 3. Rename platform-owned service/support classes and variables. 4. Remove stale compatibility aliases. 5. Run focused Unit/Feature tests for renamed helpers and services. ## Phase 4: Filament Resource/Page/Widget Rename 1. Rename `TenantResource` and nested Pages/RelationManagers to environment-first names. 2. Rename `TenantDashboard`, `TenantDiagnostics`, and `TenantRequiredPermissions` to environment-first page names. 3. Update route owner classes and route names without changing canonical URL segments. 4. Review global search: renamed resources must have View/Edit pages or disable global search. 5. Preserve destructive action confirmation, server authorization, and audit behavior. ## Phase 5: Tests, Fixtures, Browser Anchors 1. Rename stale test helpers and fixtures. 2. Keep negative guard literals only where explicitly documented. 3. Update Browser smoke selectors only where visible copy/test IDs depend on renamed technical owners. 4. Run focused validation lanes and Browser anchors. ## Phase 6: Final Classification And Validation 1. Rerun final scans. 2. Ensure no unclassified active platform-owned tenant references remain. 3. Complete final `tenant-reference-inventory.md` and `allowed-tenant-references.md`. 4. Run Pint dirty and `git diff --check`. 5. Produce final implementation report with rename summary, DB changes, remaining references, route contract, validation, and decision. ## Risk Controls - No blind global search/replace. - No permanent alias classes. - No route compatibility layer. - No dual-write/dual-read unless this spec is stopped and replaced with a production migration spec. - Provider-specific and framework-required tenant references must be preserved, not renamed for cleanliness. - Broad scan output must be triaged before code changes. - Keep implementation commits phased so rollback/review is possible. ## Final Decision Criteria Implementation may report only one of: - `merge-ready; internal tenant naming consolidation complete` - `merge-ready with documented provider/framework tenant references` - `blocked by unresolved platform-owned tenant references` - `blocked by migration/schema risk` - `incomplete; canonical route or RBAC regression found`