At a Glance
Owner: Sysadmin (+ Security Officer for sessions) · Table:tb_user(+tb_user_profile,tb_user_login_session) · Used by: every*_by_idaudit column in the system · Identity layer — the most-FK'd entity in the platform. Passwords are externalized (thetb_passwordtable was dropped 2026-05-17).


The user entity is the identity layer for the entire platform. Every transactional row in every tenant carries created_by_id / updated_by_id / deleted_by_id referencing a row here, so this is the most-foreign-keyed entity in the system. It also feeds RBAC (access-control/application-role), per-BU access (access-control/business-unit-user), and per-location scoping (access-control/user-location).
The entity is split across three platform tables: tb_user (account), tb_user_profile (name/phone/bio/avatar), tb_user_login_session (tokens). Splitting keeps the hot path narrow. The tb_password table was removed on 2026-05-17 — password storage and verification now live in an external identity provider that issues the tokens recorded in tb_user_login_session. The platform schema is therefore credential-free.
Maintained by Sysadmin (accounts) and Security Officer (sessions). Read by every API request (audit + token validation). Password reset / rotation is handled by the external identity provider.
| Task | Where | Notes |
|---|---|---|
| Create a user account | Platform admin → User Management → New | Sets tb_user row; initial credential provisioning happens in the external identity provider |
| Edit profile (firstname, phone, avatar) | Account → Profile screen | User can self-edit |
| Reset password | External identity provider's flow (e.g. reset email link) | No schema effect on the carmen platform side; subsequent logins simply present a fresh access_token |
| Deactivate account | Set is_active = false |
Login blocked here even if external IdP still issues tokens (server validates is_active) |
| Force logout | Delete tb_user_login_session rows |
Or wait for expired_on to lapse |
| Soft-delete user | Set deleted_at |
FK targets remain valid for historical audit |
| Symptom | Cause | Action |
|---|---|---|
| "Username already exists" | App-level uniqueness on non-deleted users | Pick a different username |
| Login rejected unexpectedly | External identity provider rejected the credential or returned an unmapped subject | Investigate at the IdP; the platform schema no longer stores password state |
| "Must accept T&Cs" | is_consent = false |
User must accept to unlock transactional UI |
| Cannot hard-delete user | Audit FKs reference the row | Inactivate or soft-delete instead |
| Forced password change | Driven by the external IdP's rotation policy | Handled outside this schema |
super_admin / platform_admin bypass tenant RBAC; security_officer manages credentials; integration_developer exists for service accounts.is_online / socket_id are caches written by the realtime channel — not authoritative for security.tb_user_login_session.token is globally unique so token reuse is detectable.Source: platform schema.
tb_user| Field | Prisma Type | Nullable | Description |
|---|---|---|---|
id |
String @db.Uuid |
No | Primary key. Target of every *_by_id FK. |
username |
String @db.VarChar |
No | Login username. |
email |
String @db.VarChar |
No | Login / contact email. |
alias_name |
String? @db.VarChar |
Yes | Optional display alias. |
platform_role |
enum_platform_role |
No | Default user. Coarse platform-wide role. |
is_active |
Boolean? |
Yes | Default false. Account-enabled. |
is_consent |
Boolean? |
Yes | Default false. T&C acceptance. |
socket_id |
String? |
Yes | Live socket id (presence). |
is_online |
Boolean |
No | Default false. Cached presence. |
consent_at |
DateTime? @db.Timestamptz(6) |
Yes | When user accepted T&C. |
| Audit columns | — | Yes | created_*, updated_*, deleted_*. |
enum_platform_role: super_admin, platform_admin, support_manager, support_staff, security_officer, integration_developer, user.
tb_user_profile| Field | Prisma Type | Nullable | Description |
|---|---|---|---|
id |
String @db.Uuid |
No | Primary key. |
user_id |
String? @db.Uuid |
Yes | FK to tb_user. |
firstname / middlename / lastname |
String @db.VarChar(100) |
Mixed | Default "". |
telephone |
String? @db.VarChar(20) |
Yes | Phone. |
bio |
Json? @db.Json |
Yes | Default {}. |
avatar_file_token |
String? @db.VarChar |
Yes | Reference to the user's avatar image in the platform file service (added 2026-05-20). Same file_token pattern as tb_business_unit.logo_file_token and tb_product_image.file_token. |
| Audit columns | — | Yes | created_*, updated_*, deleted_*. |
tb_user_login_session| Field | Prisma Type | Nullable | Description |
|---|---|---|---|
id / user_id |
String @db.Uuid |
No | Keys. |
token |
String @db.VarChar |
No | Token string. |
token_type |
enum_token_type |
No | Default access_token. |
expired_on |
DateTime @db.Timestamptz(6) |
No | Default now() + '1 day'. |
Constraints: @@unique([token]). enum_token_type: access_token, refresh_token.
username and email globally unique among non-deleted users.is_consent = true required before transactional UI is unlocked.token.tb_user.*_by_id audit column.../carmen-turborepo-backend-v2/packages/prisma-shared-schema-platform/prisma/schema.prisma — tb_user, tb_user_profile, tb_user_login_session, enums. tb_password was removed in commit b2829da2 (2026-05-17); credential storage and verification now live in the external identity provider.../carmen-turborepo-frontend/apps/web/app/(app)/configuration/account/ + platform admin user-management.../carmen/docs/workflow-permissions-system.md.