Skip to content

Platform Authorization And Access — Source Authority


1. Authority Decision

Authorization is not one boolean and is not owned by menu visibility.

Authentication
-> Tenant context
-> Product/module/capability availability
-> Menu/page/API availability
-> Action permission
-> Record ownership/relation
-> Record-state eligibility
-> Required config/credential validity
-> Allow or deny one query/command

Every step can independently deny or return unavailable/unknown.

1.1 Required invariants

Menu visible != Page authorized
Page authorized != API authorized
API authorized != Command authorized
Command authorized != Record authorized
Record authorized != State transition allowed
UI hidden != Backend denied
Module enabled != User authorized
Role assigned != Every action allowed
Super-admin actor != Every impersonated action allowed

1.2 Current owner categories

Question Current source owner
Is the user authenticated? PHP session helpers / API or endpoint bootstrap
Which tenant/user/role is effective? config compatibility helpers and selected typed context
Is a module/config available? module guard and tenant config helper
Is a menu route visible/owned by role? T_MENU, virtual menu rules and menu helpers
May a page load? index.php, page helper/guard and page-local guard
May an API route execute? API v2 route metadata or legacy TYPE/ACTION endpoint owner
May one action execute? route role checks plus handler-specific logic
May one record be read/mutated? module/helper-specific SQL predicates and relation guards
Is the record state eligible? application helper/process logic
Which override is allowed? super-admin, impersonation and allowlisted admin route logic

No single current source fully owns the entire chain.


2. Current Access Layers

2.1 Authentication layer

Current request families use several helpers:

  • application shell redirects to login when login_username is absent;
  • API v2 returns 401 UNAUTHENTICATED;
  • legacy JSON endpoint returns its legacy error envelope;
  • direct page/download helpers return redirect, HTML or plain-text errors;
  • CLI paths may bypass browser authentication and require separate explicit identity.

Authentication is necessary but not sufficient.

2.2 Tenant context layer

Current paths may use:

  • session tenant;
  • impersonation target tenant;
  • allowlisted super-admin API tenant override;
  • strict typed tenant principal;
  • legacy deployment default;
  • handler-supplied/scalar client ID.

Record SQL remains responsible for scoping by effective tenant unless a shared typed relation guard is used.

2.3 Module/config availability layer

Current module guard can use:

  • T_MODULE;
  • T_MODULE_PAGE;
  • T_TENANT_MODULE;
  • config/modules.php;
  • prerequisite config keys.

Current compatibility includes:

  • missing tenant-module row can allow;
  • module source error can allow through isModuleEnabled();
  • unmapped page can allow/unknown;
  • page registry error or inactive page denies;
  • config prerequisite missing/false/error denies in the mapped config guard.

2.4 Menu and role layer

Current menu authority uses:

T_MENU.MENU_URL
T_MENU.MENU_ROLE_LIST
T_ROLE.DEFAULT_MENU_ID
virtual menu rows
special field-role policies

Role values are numeric and can be comma-separated.

Current special policies include Forklift Operator page/menu behavior and virtual menu construction. These are compatibility behavior, not accepted universal semantic capability definitions.

2.5 Page layer

The application shell:

  1. normalizes the requested page;
  2. checks file existence;
  3. evaluates role/menu access;
  4. evaluates module/config availability;
  5. renders access denied, module unavailable or the page;
  6. some direct pages also call requirePageRoleAccess().

Current page compatibility:

  • menu DB error may return unknown/allowed;
  • client ID <= 0 may return unknown/allowed;
  • menu-unregistered page can be allowed to role 1;
  • print-page aliases can inherit an owner page;
  • unmapped module page can remain available/unknown;
  • super-admin generally needs an impersonation target for tenant application pages.

2.6 API v2 route layer

Route metadata can define:

public
strictTenantPrincipal
moduleKey
requiredMenuRoutes
requiredRoleIds
sessionMode

Dispatch order is effectively:

authentication
-> optional strict tenant context
-> module
-> menu
-> numeric role
-> handler

The handler still owns command-level and record-level predicates.

2.7 Legacy TYPE/ACTION endpoint layer

Legacy post/query endpoints use a separate model:

authenticated endpoint
-> TYPE/ACTION to module mapping
-> optional menu assertion
-> effective scalar context
-> selected handler

Some handlers use advancedOperations = super-admin or role 1; others have additional internal role/state checks.

2.8 Record and state layer

Record-level access remains distributed across:

  • tenant predicates in SQL;
  • parent-child relation queries;
  • helper-specific ownership checks;
  • target-user/role comparisons;
  • process status checks;
  • provider/credential owner checks;
  • current action state.

The shared router cannot prove record authorization merely because a route passed its metadata checks.


3. Current Page And Menu Decision Semantics

3.1 getMenuRouteAccessDecision

Current behavior includes:

  • non-impersonating super-admin bypass;
  • exact normalized route and query matching;
  • role intersection with MENU_ROLE_LIST;
  • field-role special denies/allows;
  • caller-selectable failOpen on missing tenant/DB error;
  • route not found returns unknown/denied.

Different callers can request different fail-open behavior.

3.2 getPageRoleAccessDecision

Current behavior includes:

  • current query-specific menu route check;
  • role intersection across menu rows sharing a page base;
  • operations-manual special rule;
  • print-page aliases;
  • DB/menu errors can allow unknown;
  • unregistered pages can allow role 1 only;
  • result contains only known and allowed, so detailed reason/provenance is often lost.

3.3 Module filtering versus actual authorization

Sidebar/menu filtering can remove a menu for a disabled module. A direct route or API still requires its own guard.

Menu filtered out
!= direct URL rejected
!= API rejected

4. Current Super-Admin And Override Semantics

4.1 Physical super-admin

Physical super-admin is detected from original session client/role values.

Current bypasses include:

  • role check bypass in API v2;
  • module bypass when current client is 0 and not impersonating;
  • menu route bypass when not impersonating;
  • admin console access and selected cross-tenant routes.

4.2 Impersonated super-admin

When impersonating a tenant/user:

  • original super-admin status remains true;
  • effective tenant/user/roles can come from target context;
  • application page access generally delegates to target page-role decisions;
  • individual handlers may still use isSuperAdmin() and therefore permit behavior beyond the subject's normal role unless separately constrained.

This is a key reason actor and subject must remain explicit in target authorization.

4.3 Direct-access hub

Admin direct-access UI displays page/module availability and may show:

Available
Default Allow
Unknown Module
Disabled
No Module Guard

It is a diagnostic/navigation surface. Opening a page does not itself authorize every API/action/record behind that page.

4.4 Admin tenant override

Selected platform APIs accept X-Admin-Client-Id only on an allowlist and only for physical super-admin. Typed strict override additionally requires an authorization reference.

This is not the same as session impersonation.


5. UI Visibility And Backend Parity

Current UI can expose or hide actions using:

  • menu rows;
  • role IDs;
  • module/config flags;
  • page state;
  • JavaScript flags such as administrator/super-admin;
  • record status;
  • virtual menu policy.

UI decisions are hints only.

For every consequential action the target must prove:

UI visible -> backend command allows expected actor/record
UI hidden -> backend command still denies direct request
UI partial/unavailable -> user sees exact reason and recovery owner

P2-007 remains the live-tenant role/page/API acceptance owner; this document does not activate it.


6. Current Fail-Open, Fail-Closed And Unknown Inventory

Surface Current behavior Classification
missing T_TENANT_MODULE row module allowed compatibility fail-open
module DB error module allowed availability fail-open
page registry error page denied fail-closed
inactive page registry row page denied fail-closed
unmapped page in module map allowed/unknown compatibility
page menu DB error page allowed/unknown access fail-open
menu route DB error caller-selected fail-open/fail-closed heterogeneous
unregistered page role 1 may enter admin compatibility
API missing authentication 401 fail-closed
API role mismatch 403 fail-closed
strict tenant context mismatch typed 4xx fail-closed
record predicate absent or incomplete handler-dependent unknown/risk
browser button hidden no backend guarantee presentation only

A broad conversion is prohibited while Phase implementation is held and live callers remain uncharacterized.


7. Current Source Gap Register

ID Gap Consequence
ACC-GAP-010 one page decision loses detailed reasons support cannot explain the complete chain
ACC-GAP-020 module/menu/page fail-open behavior differs rollout risk and inconsistent direct/API behavior
ACC-GAP-030 API v2 and legacy endpoints use different guard models one role test does not prove all callers
ACC-GAP-040 record predicates are handler-specific route metadata cannot prove tenant/record safety
ACC-GAP-050 numeric roles serve as action capabilities role additions/remaps can broaden actions unintentionally
ACC-GAP-060 physical super-admin remains true during impersonation actor bypass can conflict with subject expectations
ACC-GAP-070 UI action visibility is separate hidden controls can still have callable endpoints
ACC-GAP-080 direct/unregistered pages have compatibility access page inventory is required before strict rollout
ACC-GAP-090 special field-role policies live in shared config helpers target semantic capability ownership is unclear
ACC-GAP-100 virtual menu rows synthesize role policy DB menu alone is not full authority
ACC-GAP-110 admin direct-access availability is not command authorization support may misread “available” as fully permitted
ACC-GAP-120 no universal decision/correlation record denied/allowed behavior is hard to reconcile across layers
ACC-GAP-130 record-denial disclosure policy varies 403/404/data leakage semantics are inconsistent
ACC-GAP-140 config/credential prerequisites are not universally part of action decision provider/action availability can diverge
ACC-GAP-150 current Role/API matrix is incomplete across live users broad guard changes can cause Client 1 outage

8. Target Authority Map

Concern Target owner
Authentication and actor/subject identity/session authority
Tenant context typed tenant execution context
Profile/module/capability/config/credential platform policy/resolution contracts
Page/API availability route/application adapter policy
Action permission semantic capability/action policy
Record ownership/relation repository/application record predicate
Record-state eligibility owning domain/application command
Override explicit privileged delegation policy
Access decision diagnostics read-only support decision trace
Business mutation owning application command, not access helper

Authorization evaluates existing authority. It does not become a generic workflow or business-state engine.


9. Caller Inventory Required Before Migration

For each selected page/API/action:

page route and direct URL
menu route and roles
module/config prerequisites
API v2 routes
legacy TYPE/ACTION routes
JavaScript callers
server-side internal callers
record tables and parent/child predicates
state blockers
super-admin/impersonation behavior
provider/file/device effects
current denial response

A capability cannot move to strict target authorization while an unlisted legacy caller can still mutate the same record.


10. Access Evidence Required

Per action/record:

  • allowed role/tenant direct path;
  • denied role;
  • foreign tenant;
  • missing record;
  • wrong parent/child relation;
  • wrong record state;
  • module disabled;
  • capability/config unavailable;
  • direct URL;
  • API direct call with hidden UI;
  • super-admin direct mode;
  • user impersonation;
  • tenant-only impersonation;
  • duplicate/unknown request where applicable;
  • exact response and no information leakage;
  • Client 1 non-regression;
  • Client 2 expected behavior.

11. Evidence Boundary

This source authority does not prove:

  • current Production T_MENU, T_ROLE, module/config rows;
  • every direct URL;
  • every legacy endpoint;
  • every JavaScript caller;
  • every record-level predicate;
  • actual field-role behavior;
  • current Client 1/Client 2 role matrix;
  • provider/credential access;
  • current denied-page UX;
  • current Wiki access instructions;
  • Next.js authorization behavior.

These require separately authorized source inventory, DB read, role/browser/API tests and field acceptance.

---

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