Skip to content

Platform, Tenant, Role And Access — Source-Reconciled Current Contract

  • Status: SOURCE_RECONCILED / TARGET ROLLOUT NOT APPROVED
  • Task: NS0-003
  • Current-source revision: 98b3a59d76ce66c3e69788c93aac7e3e08e6edff
  • Scope: Platform/Tenant/Role/Access/Config/Audit/File dependencies consumed by CTC and MK
  • Evidence level: repository source, schema-plan, migration and test review
  • Runtime/DB/browser/operator verification: NOT_RUN

1. Authority Decision

Current Platform behavior is not one gate.

Authentication
-> effective Tenant Context
-> module/config availability
-> menu/page/API availability
-> numeric-role compatibility
-> command-specific authorization
-> record tenant/relation predicate
-> record-state eligibility
-> provider/config/credential prerequisites

The following implications are invalid:

authenticated
!= authorized for every tenant

module enabled
!= menu visible
!= process capability enabled
!= action allowed

menu visible
!= page/API/record authorized

role assigned
!= every action allowed

super-admin actor
!= impersonated subject has every permission

2. Current Tenant Context

2.1 Legacy scalar resolution

The common PHP compatibility path resolves the effective local tenant in this order:

impersonation target CLIENT_ID
-> session CLIENT_ID
-> deployment Config::CLIENT_ID fallback

Actor and subject helpers also prefer impersonation target data where present.

Current implications:

  • normal authenticated Web/API requests generally carry one numeric local tenant;
  • impersonation separates the physical super-admin actor from the effective tenant/user;
  • selected super-admin API routes can use an allowlisted tenant override;
  • legacy CLI/direct callers can receive deployment tenant 1 unless they bind an explicit context;
  • numeric CLIENT_ID is deployment-local compatibility identity, not the target portable identity.

2.2 Typed context foundation

TenantExecutionContext already models:

localTenantId
optional globalTenantId
identityState: MAPPED | LEGACY_LOCAL_ONLY
tenantProvenance
entrypoint
sourceName / requestId
accessMode
actor
optional subject
optional credentialOwnerRef
policyState: STRICT | COMPATIBILITY_ONLY

A strict typed context rejects all-tenant request scope and can reject a new write when the context is compatibility-only.

2.3 Current rollout boundary

Typed context is active only for selected callers and opt-in routes.

strictTenantPrincipal = true
-> create strict TenantExecutionContext
-> expose compatibility scalar context to the handler

Non-opted routes still consume apiContext() and legacy scalar helpers.

Therefore:

typed foundation exists
!= repository-wide strict tenant execution

3. Current Authentication And Session Validation

Current API authentication:

session start
-> login_username present
-> active session user reread
-> role/tenant consistency check
-> 401 on failure

Session validation can invalidate a session when the current active user, tenant or role assignment no longer matches the session. Impersonated sessions additionally validate the original administrator and the target subject.

This proves active-session reread behavior. It does not prove SSO, token rotation, distributed session ownership or a target Next.js session bridge.

4. Current Module, Config And Capability Resolution

4.1 Concerns remain separate

Current and target questions are distinct:

Concern Current source owner
Tenant identity session/impersonation helpers and selected TenantExecutionContext adapters
Module availability T_MODULE, T_MODULE_PAGE, T_TENANT_MODULE, config/modules.php, module guard
Config value T_TENANT_CONFIG, current config helper and caller fallback
Named process capability mixed direct config/module/route logic; typed resolver foundation exists
Menu visibility T_MENU, role lists and menu helpers
Action/record authorization route metadata plus handler-specific predicates
Secret ownership config/provider helper plus optional typed credential-owner reference

4.2 Current compatibility behavior

Current page/module compatibility includes:

explicit disabled tenant-module row
-> deny

missing tenant-module row
-> compatibility allow

module source error
-> compatibility allow

inactive or failed page-registry lookup
-> deny

unmapped page
-> allowed / unknown

required config missing/false/error
-> deny for that mapped config gate

A boolean allow from the current module helper does not preserve whether the module was explicitly enabled or merely unconfigured.

4.3 Typed resolver foundation

The typed resolver distinguishes:

PLATFORM_CORE
MODULE_ENABLEMENT
PROCESS_CAPABILITY
CONFIG_VALUE
SECRET

and returns decision, source, validity, compatibility fallback and stable reason. It requires a strict tenant context. Broad first-party caller adoption is not proven.

Target new-system code should consume one resolved effective contract and must not reproduce raw config reads or numeric tenant branches across pages.

5. Current Menu, Page, API And Role Model

5.1 Storage

T_USER.ROLE_ID
= comma-separated numeric role IDs

T_ROLE
= tenant role records and DEFAULT_MENU_ID

T_MENU.MENU_ROLE_LIST
= comma-separated numeric role visibility/access compatibility

T_MODULE_PAGE
= global page registry/module binding

The menu tree is tenant scoped and excludes soft-deleted and permission-only rows. It can join a menu to a page by registry ID or legacy URL.

5.2 API route decision order

Current API v2 route handling can enforce:

authentication
-> optional strict tenant principal
-> moduleKey
-> requiredMenuRoutes
-> requiredRoleIds
-> handler

The handler still owns record predicates and state eligibility.

5.3 Current role limitations

  • role IDs are implementation identifiers, not semantic action capabilities;
  • route role lists are incomplete as a Product authorization model;
  • super-admin bypasses several numeric-role checks;
  • impersonation keeps the physical super-admin actor while changing the effective subject;
  • UI hiding is not backend authorization.

A complete target action matrix cannot be inferred from the current menu alone.

6. Booking Dependency Readback

Booking currently depends on this Platform chain:

session tenant
-> page route
-> module/page compatibility
-> menu/role access
-> Booking API module tms.booking
-> handler tenant predicates

Current ownership conflict:

CTC booking-list page
= oms.inbound-order module binding

MK mk-booking-list page
= tms.booking module binding

shared Booking API
= tms.booking

The Legacy routes must remain available during coexistence. The target semantic owner remains Transportation/Ocean Booking, subject to target approval.

7. Audit And Correlation

Current audit/evidence is fragmented across:

  • page usage/reporting;
  • super-admin operations;
  • Control Tower/admin audit helpers;
  • operation events;
  • table lifecycle timestamps;
  • request IDs and application logs;
  • process-specific evidence tables and fields.

No single current source proves a universal business-command audit envelope for Booking, Commercial Order or every Platform write.

Target requirement:

command request
-> actor/subject/tenant/correlation
-> owning transaction/effect
-> authoritative readback
-> immutable audit/event evidence

This is a target foundation requirement, not a claim that current Runtime already provides it.

8. File And Object Storage

Current file authority is split:

T_FILE
= tenant-scoped polymorphic metadata and record attachment

FileStorage
= EFS or S3 object adapter

record-specific helpers
= upload, preview, cleanup and relation validation

The object key includes tenant, related table and file UUID. Storage supports EFS and S3. Database soft-delete/cleanup and physical object deletion are separate effects.

Important current boundary:

T_FILE mutation committed
!= remote/local object deletion succeeded

Commercial Order delete explicitly prepares file object cleanup before soft-deleting attached file rows. Other modules require their own evidence.

9. Current Gaps

ID Gap Consequence
PLAT-GAP-010 strict typed tenant context is not universal caller-by-caller migration required
PLAT-GAP-020 missing module rows/errors can allow current boolean cannot prove explicit enablement
PLAT-GAP-030 menu/page/API/action/record gates are distributed one route test does not prove authorization
PLAT-GAP-040 numeric role IDs act as coarse capabilities role changes can unintentionally broaden actions
PLAT-GAP-050 first-class Operating Profile binding is not universally consumed profile cannot be inferred from current tenant ID
PLAT-GAP-060 config provenance/validity often collapses to a fallback value diagnostics and strict rollout are incomplete
PLAT-GAP-070 audit/effect evidence is fragmented no universal command completion proof
PLAT-GAP-080 file metadata and object effects are separate cleanup/retry/reconciliation need explicit ownership
PLAT-GAP-090 CTC/MK Booking pages have different current module bindings target owner and compatibility routes must be separated

10. Target Contract Direction

The new system should use:

strict TenantExecutionContext
-> Operating Profile binding
-> module resolution
-> named capability resolution
-> typed policy/config resolution
-> role/action/record access
-> owning command/query
-> repository transaction
-> audit/outbox/effect
-> authoritative readback

Rules:

  • no new if (clientId === 2) or customer-name branch;
  • no module allow interpreted as action permission;
  • no profile interpreted as authorization;
  • no request-time Control Tower database dependency;
  • no all-tenant business write context;
  • no record access without tenant and relation predicates;
  • no secret value in safe serialized diagnostics.

11. Lifecycle Result

Platform/Tenant/Role source map
= SOURCE_RECONCILED

strict typed Runtime adoption
= PARTIAL / CALLER-SPECIFIC

target profile binding
= OPEN_DECISION

target role/action matrix
= OPEN_DECISION

live role/menu/config proof
= NOT_RUN

12. Evidence Sources

Primary current sources:

config/config.php
config/modules.php
config/page_routes.php
app/shared/api/runtime.php
app/platform/tenant/TenantExecutionContext.php
app/platform/tenant/tenant_execution_context_adapter.php
app/platform/tenant/module_guard.php
app/platform/tenant/config_helper.php
app/platform/tenant/CapabilityDefinitionRegistry.php
app/platform/tenant/capability_resolver.php
app/platform/menu/menu_query_helper.php
app/platform/master-data/api_helper.php
app/shared/storage/file_storage.php
app/platform/audit/**

Secondary dated evidence:

docs/reconstruction/PLATFORM_TENANT_PROFILE_CAPABILITY_CONFIGURATION_SOURCE_AUTHORITY.md
docs/reconstruction/PLATFORM_AUTHORIZATION_ACCESS_SOURCE_AUTHORITY.md
scripts/migrations/2026-08-01_p2_003_client2_office_access.php

Secondary documents provide historical reconciliation only; current source remains the current-behavior authority.

---

Source: new-system/docs/reconstruction/PLATFORM_TENANT_ROLE_SOURCE_RECONCILED.md — ctc repository · This page is an English translation of the source document. Identifiers, file paths and code symbols are unchanged.