TenantAtlas/specs/147-tenant-selector-remembered-context-enforcement/data-model.md
ahmido 73a879d061 feat: implement spec 147 tenant context enforcement (#176)
## Summary
- implement Spec 147 for workspace-first tenant selector and remembered tenant context enforcement
- harden canonical and tenant-bound route behavior so selected tenant mismatch stays informational
- fix drift finding subject fallback for workspace-safe RBAC identifiers and centralize finding subject resolution

## Testing
- vendor/bin/sail artisan test --compact tests/Feature/Filament/FindingViewRbacEvidenceTest.php tests/Feature/Findings/FindingsListDefaultsTest.php
- vendor/bin/sail bin pint --dirty --format agent

## Notes
- branch pushed at de0679cd8b
- includes the spec artifacts under specs/147-tenant-selector-remembered-context-enforcement/

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #176
2026-03-16 22:52:58 +00:00

5.4 KiB

Data Model: Tenant Selector and Remembered Context Enforcement

Overview

This feature does not introduce a new persistence model. It formalizes how existing workspace, tenant, route, and remembered-context concepts interact at the shell and routing layers.

Entities

1. Workspace Context

Represents: The primary operating boundary for the current admin session.

Key fields:

  • workspace_id
  • workspace.slug
  • workspace.archived_at

Relationships:

  • Owns many tenants
  • Owns many canonical workspace records such as operation runs
  • Owns one session-scoped remembered tenant preference map entry per user session

Validation rules:

  • Must exist
  • Must not be archived for active selection
  • Actor must be a workspace member or the request resolves as deny-as-not-found

2. Tenant

Represents: A workspace-owned tenant record that may be active, onboarding, draft, or archived.

Key fields:

  • id
  • workspace_id
  • external_id
  • status
  • deleted_at
  • operator-facing identity fields such as name, domain, environment

Relationships:

  • Belongs to one workspace
  • May be a route subject on tenant-bound pages
  • May be referenced by canonical workspace records such as operation runs
  • May be persisted as remembered active-lane context only when selector-eligible

Validation rules:

  • For standard active selector use, tenant must belong to current workspace, remain entitled to the actor, exist, and satisfy active-lane eligibility
  • For tenant-bound route validity, tenant must satisfy workspace and entitlement checks; selector eligibility is not required

3. Remembered Tenant Context

Represents: A workspace-scoped user/session preference for the last active-lane tenant.

Key fields:

  • workspace_last_tenant_ids[workspace_id] session entry
  • optional persisted recency signals through users.last_tenant_id or user_tenant_preferences.last_used_at

Relationships:

  • Belongs logically to one workspace context
  • References one tenant candidate for active-lane convenience

Validation rules:

  • Must only be read inside an established workspace context
  • Must resolve to an existing tenant in the current workspace
  • Must satisfy entitlement-sensitive access checks
  • Must satisfy active-lane eligibility checks
  • Invalid values must be cleared or ignored deterministically

4. Active Selector Option

Represents: A tenant that is eligible to appear in the standard active tenant selector.

Derived from:

  • TenantOperabilityDecision.canSelectAsContext

Required attributes:

  • tenant identity
  • lifecycle presentation
  • selector-safe label and helper copy

Validation rules:

  • Must not include draft, onboarding, or archived tenants under the current lifecycle model
  • Must not include tenants outside the current workspace
  • Must not include tenants the actor cannot access

5. Route Subject

Represents: The record made authoritative by the current route.

Variants:

  • tenant-bound route subject: Tenant
  • canonical workspace record subject: OperationRun or other workspace-owned records

Validation rules:

  • Route subject legitimacy is resolved from route record identity plus policy checks
  • Remembered tenant context may influence convenience UI only and must not replace route authority

Derived Domain Objects

Tenant Operability Decision

Represents: The existing lifecycle-aware rule set produced by TenantOperabilityService.

Relevant flags for this feature:

  • canSelectAsContext
  • canViewTenantSurface
  • canReferenceInWorkspaceMonitoring

Shell Context Resolution Result

Represents: The runtime decision for what tenant, if any, the shell should treat as active convenience context.

Possible states:

  • route_authoritative_tenant
  • validated_selected_tenant
  • no_selected_tenant
  • stale_context_cleared

State Transitions

Remembered Tenant Context Lifecycle

  1. unset
    • No remembered tenant exists for the current workspace.
  2. remembered_active
    • An active-lane-eligible tenant is selected and stored for the current workspace.
  3. revalidated_active
    • A later request reads the remembered tenant and confirms workspace match, entitlement, existence, and selector eligibility.
  4. invalidated_cleared
    • A later request detects stale or ineligible remembered tenant context and clears or ignores it.
  5. no_selected_tenant
    • The shell falls back to a legitimate workspace-level no-tenant state.

Invalidation triggers:

  • workspace switch
  • tenant no longer exists
  • tenant no longer belongs to current workspace
  • tenant no longer satisfies active-lane eligibility
  • actor no longer has tenant entitlement where required

Page Semantics By Category

Workspace-level page

  • Accepts remembered_active, invalidated_cleared, or no_selected_tenant
  • Selected tenant may become a filter only

Tenant-bound page

  • Route tenant is authoritative
  • Selected tenant may match, differ, or be absent

Canonical workspace record viewer

  • Route record is authoritative
  • Referenced tenant may differ from selected tenant without invalidating the page

Invariants

  • Workspace is always the primary context boundary.
  • Remembered tenant context never broadens authorization.
  • Standard selector membership never implies universal tenant discoverability.
  • Route legitimacy always outranks selected tenant context.
  • No-selected-tenant is a valid workspace shell state.