# Data Model: Spec 136 Admin Panel Canonical Tenant Resolution Full Rollout ## Overview This feature introduces no new database tables or persisted business objects. Its data model is request-time and behavioral: it formalizes how surface classification, panel mode, canonical admin tenant context, session-backed filter state, and sensitive actions combine into one deterministic tenant outcome. ## Entity: Surface Inventory Entry **Purpose**: Represents one admin-visible or admin-reachable surface in the rollout manifest. **Fields**: - `surface_name` - `class_name` - `surface_kind` enum: `resource`, `page`, `widget`, `shared_helper`, `guarded_file` - `classification` enum: `type_a`, `type_b`, `type_c` - `visibility_mode` enum: `admin_visible`, `shared_code_path`, `tenant_panel_only_but_reviewed` - `has_persisted_tenant_filters` boolean - `has_global_search` boolean - `has_sensitive_actions` boolean - `guard_required` boolean **Relationships**: - may reference one resource, page, or widget class - may depend on one or more support-layer resolver or filter-state helpers **Validation rules**: - Every rollout surface must have exactly one classification. - Type A and Type B surfaces must be guard-covered unless explicitly documented as an exception. - Type C surfaces must not acquire hidden tenant enforcement in read or write paths. ## Entity: Canonical Admin Tenant Context **Purpose**: Represents the single tenant context used by workspace-admin tenant-sensitive flows. **Source fields**: - `workspace_id` - `panel_id` - `route_tenant_id` nullable - `filament_tenant_id` nullable - `remembered_tenant_id` nullable - `resolved_tenant_id` nullable - `resolution_source` enum: `route`, `filament`, `remembered`, `none` - `is_entitled` boolean **Relationships**: - belongs to one current workspace - may resolve to one entitled tenant - drives header context, queries, filter defaults, widgets, links, and sensitive actions for Type A and Type B admin surfaces **Validation rules**: - `resolved_tenant_id` must be null when no entitled tenant exists. - The same resolved tenant must drive every tenant-sensitive element of the same admin surface. - When the panel is admin, raw panel-native tenant reads are not valid substitutes for this entity. ## Entity: Panel Resolver Contract **Purpose**: Encodes which resolver is allowed in a given panel mode. **Fields**: - `panel_id` - `allowed_source` enum: `operate_hub_shell`, `filament_tenant`, `none` - `fallback_behavior` enum: `remembered_allowed`, `no_fallback`, `safe_none` - `applies_to` enum: `admin`, `tenant`, `shared_surface` **Validation rules**: - Admin panel uses `operate_hub_shell`. - Tenant panel uses `filament_tenant`. - Shared surfaces must branch by current panel rather than blending both rules. ## Entity: Persisted Tenant Filter Session State **Purpose**: Represents session-backed filter state whose validity depends on the current canonical admin tenant. **Fields**: - `filters_session_key` - `tenant_sensitive_filters` array - `previous_resolved_tenant_id` nullable - `current_resolved_tenant_id` nullable - `resolution_action` enum: `apply`, `reseed`, `clear` - `has_invalid_values` boolean **Relationships**: - belongs to one table or page surface - depends on one `Canonical Admin Tenant Context` **Validation rules**: - Tenant-sensitive filter values must be cleared or reseeded when resolved tenant changes. - If `current_resolved_tenant_id` is null, tenant-specific filter state must not remain active. - Workspace-wide Type B surfaces may preserve non-tenant filters while clearing or reseeding tenant-specific ones. ## Entity: Sensitive Action Scope Contract **Purpose**: Represents the tenant parity requirement between visible surface context and a sensitive action target. **Fields**: - `surface_name` - `action_name` - `visible_tenant_id` nullable - `query_tenant_id` nullable - `action_tenant_id` nullable - `authorization_outcome` enum: `ok`, `not_found`, `forbidden` - `confirmation_required` boolean **Relationships**: - belongs to one rollout surface - depends on one resolved tenant context and one authorization decision **Validation rules**: - `action_tenant_id` must equal `visible_tenant_id` for Type A surfaces. - Out-of-scope or missing tenant access must remain `not_found` when membership is not established. - Existing destructive-like actions must still require confirmation and server-side authorization. ## Entity: Search and Record Resolution Contract **Purpose**: Represents list, detail, deep-link, and global-search parity for tenant-sensitive resources. **Fields**: - `surface_name` - `access_path` enum: `list`, `detail`, `direct_url`, `deep_link`, `global_search` - `panel_mode` enum: `admin`, `tenant` - `resolved_tenant_id` nullable - `record_tenant_id` nullable - `parity_outcome` enum: `aligned`, `disabled`, `not_found`, `forbidden` **Validation rules**: - Detail and direct access must never be broader than list scope. - Global search must either match list/detail parity or be disabled. - Admin no-context behavior must be explicit and deterministic per surface class. ## Entity: Guard Coverage Entry **Purpose**: Documents whether a file is enforced by the admin tenant resolver guard or allowed as an exception. **Fields**: - `relative_path` - `surface_name` - `guard_status` enum: `guarded`, `exception` - `exception_reason` nullable - `review_owner` **Validation rules**: - Exceptions must be explicit and stable. - Admin-only files are not valid exceptions for raw `Filament::getTenant()` or `Tenant::current()` reads. - Guard output must clearly distinguish true violations from approved tenant-panel-native usage. ## State Transitions ### Canonical admin tenant state 1. `none` - No entitled route, Filament, or remembered tenant is available. - Outcome: safe no-tenant-selected behavior by surface type. 2. `remembered` - Only remembered tenant is valid and entitled. - Outcome: remembered tenant becomes the canonical admin tenant for the full request. 3. `filament` - A Filament tenant is valid and entitled. - Outcome: Filament tenant becomes the canonical admin tenant for the full request. 4. `route` - A route tenant parameter is present and entitled for a tenant-panel or shared route. - Outcome: route tenant governs the request where panel-native semantics apply. ### Persisted filter synchronization state 1. `unchanged` - Previous and current resolved tenant IDs match. - Outcome: persisted tenant filter values may remain. 2. `tenant_switched` - Previous and current resolved tenant IDs differ. - Outcome: tenant-sensitive filter values are cleared or reseeded. 3. `tenant_removed` - Current resolved tenant ID becomes null. - Outcome: tenant-sensitive filter values are cleared. ## Invariants - One workspace-admin surface uses one tenant source for every tenant-sensitive element. - Shared resources must branch by panel mode instead of mixing admin and tenant rules inside one execution path. - Persisted tenant filter state is never trusted without synchronization. - Search, list, detail, and deep-link behavior cannot exceed the same tenant boundary. - Existing destructive or governance-sensitive actions keep their confirmations and authorization while gaining tenant-target parity.