Data Model
Data Model
Master accounts, per-app data sharding, and shared quotas across the UNVRSL ecosystem.
Master Accounts
All users have a single master account in core.auth's SQL. This account is the identity across every application project — no per-app registrations, no duplicate users.
Account Structure
core.auth SQL:
┌─────────────────────────────────────┐
│ users (master) │
├─────────────────────────────────────┤
│ id (PK) │
│ email │
│ password_hash │
│ display_name │
│ created_at │
│ storage_quota_bytes │
│ ai_calls_quota │
│ hypermedia_quota │
│ status (active/suspended/deleted) │
└─────────────────────────────────────┘Per-App Data Sharding
Each application project manages its own data in its own tables (or its own database), but every record links back to the master account via
user_id.core.auth (master)
│
├── todo_app_db
│ └── tasks, folders, files → user_id FK
│
├── lang_learner_db
│ └── articles, translations, flashcards → user_id FK
│
├── psychiatry_app_db
│ └── notes, progress, saved_protocols → user_id FK
│
├── medical_app_db
│ └── patient_records, notes → user_id FK
│
└── webos_db
└── desktops, folders, files, drawings → user_id FKKey principle: Apps never store user identity data. They only store
user_id as a foreign key and query core.auth for account details, permissions, and quotas.Shared Quotas
All resource consumption draws from the master account's quotas, regardless of which app is being used.
| Resource | Service | Quota Field | Enforcement Point |
| File storage | core.storage | storage_quota_bytes | core.storage on upload |
| AI calls | core.ai | ai_calls_quota | core.ai on request |
| Media processing | core.hypermedia | hypermedia_quota | core.hypermedia on processing |
Quota Check Flow
Client (core.backend SDK) → core.console (API gateway)
│
▼
core.console validates API key, checks project status
│
▼
core.console checks: is this service in the key's allowed_services?
│
▼
core.console routes to appropriate core.service
│
▼
core.service reads user_id from request context
│
▼
core.service queries core.auth: "has user X exceeded quota Y?"
│
├── No → proceed, increment usage counter
└── Yes → return 429 / quota exceeded
│
▼
core.console logs request to request_log, returns response to clientQuota Reset
Quotas reset on a configurable cycle (monthly, per subscription tier). The reset logic lives in core.auth.
Project Registry
Projects are managed in core.console, not in core.auth. Each project has its own set of enabled services, API keys, and quotas. Projects belong to either a dev user or an organization.
core.console SQL:
┌─────────────────────────────────────────────┐
│ projects │
├─────────────────────────────────────────────┤
│ id (PK) │
│ name │
│ slug (unique per owner) │
│ owner_dev_user_id (FK, nullable) │
│ owner_org_id (FK, nullable) │
│ enabled_services (JSON) │
│ status (active/suspended) │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ api_keys │
├─────────────────────────────────────────────┤
│ id (PK) │
│ project_id (FK → projects) │
│ name │
│ key_hash (Argon2id) │
│ key_prefix │
│ allowed_services (JSON — scoped subset) │
│ quotas (JSON — per-key overrides) │
│ status (active/revoked) │
└─────────────────────────────────────────────┘See: Console Architecture for the full data model including dev users, organizations, billing, stats, and logs.
Cross-App Sessions
A single session token from core.auth grants access to any app the user has been granted access to. No per-app login required. The session contains:
user_idapp_id(current app)scopes(what this app can do)expires_at
See: Auth Architecture for full session management details.
Storage Data Model
The storage data model (pools, objects, shards, ownership, comments) is documented separately in the storage architecture docs.
See: Storage Database Schemas