Auth, Tenancy & Actors
Three questions, three mechanisms:
They meet in
getOrganizationAndActorId(), which returns the second and third together.
Identity
Portal does not use Auth0. It is the one surface with its own scheme — share token plus postal-code verification, then a signed cookie bound to that token. See Portal. Console has a second gate.requireAuth() checks the session; requireSuperadmin()
additionally checks isConsoleSuperadmin(subject).
Tenancy
Console is cross-tenant by design — it reads across organisations and holds an Auth0ManagementClient. Treat it as a stated exception, not a violation. See
Console.
Actors
Every mutation is attributed.actors relates to 94 of 98 models, almost always as
paired *_modified_by / *_deleted_by relations.
Actors are per-organisation — org_id is non-null, so the same user acting in two
organisations has two actor rows.
Integration-created records get an actor labelled from the integration’s ACTOR_LABEL
constant — which is why even the placeholder integrations define one.
Where attribution is enforced
- Activities —
actorsis the single most-imported core domain from the activity layer (21 imports), ahead ofdocuments. - Core —
actorshas an in-degree of 13 inside core. - Accounting —
createAccountingImpactcallsfindOrCreateSystemActoratcreate-accounting-impact.ts:278, before any write.
Audit trails
Three separate tables, for different things:
Security events go to a separate Axiom dataset, not the database —
/admin and /dev
access is logged from proxy.ts:251-259. See Observability.
Notes
getOrganizationAndActorId() is the pattern to copy. Returning both values from one
call is what stops a developer scoping a query correctly but attributing the write to
nobody.
API keys are a fourth identity path. api_keys backs the partner API routes; Mirakl
credentials are read through mirakl/get-api-credentials.ts.
MFA is managed, not enforced here. 14 files under webapp app/lib/auth/ handle Auth0
user management including MFA enrolment, TOTP deletion, and password changes — the
enforcement lives in Auth0, not in application code.