Frontend Architecture
Frontend Architecture
Three separate frontend surfaces, all served from
core.auth.medkronos.com, all using core.assets stylesheets and core.backend HTML init.Frontend Surfaces
| Surface | URL | Purpose |
| Registration / Login | /register, /login | Account creation and authentication |
| Account Management | /account | User settings, security, data management |
| App Authorization | /authorize | Consent screen for app data access |
All three share the same visual language (colors, buttons, typography) from core.assets. Registration/login and app authorization use the single-page progressive-reveal pattern. Account management uses a sidebar + main content layout.
Registration / Login Frontend
See Registration & Login for complete flow details.
Key characteristics:
- Single HTML page, all screens loaded at once
- Progressive reveal via JS (only current screen visible)
- AJAX calls to core.auth API
connection_refparameter carries app context- Mobile responsive
- No framework — vanilla JS + DOM manipulation
Account Management Frontend
Served at
core.auth.medkronos.com/account. Requires authentication (valid JWT or session_ref cookie). If not authenticated, redirects to login.Layout
┌──────────────────────────────────────────────────────┐
│ core.auth [Logo] │
├────────────┬─────────────────────────────────────────┤
│ │ │
│ Overview │ [Main Content Area] │
│ │ │
│ Settings │ Content changes based on selected │
│ │ nav item. AJAX-loaded, no page reload. │
│ Personal │ │
│ Data │ │
│ │ │
│ Security │ │
│ │ │
│ App │ │
│ Access │ │
│ │ │
│ Terms & │ │
│ Policies │ │
│ │ │
└────────────┴─────────────────────────────────────────┘Navigation Sections
#### 1. Overview
┌─────────────────────────────────────────┐
│ │
│ Account Overview │
│ │
│ Account type: Free │
│ Member since: January 2026 │
│ │
│ ┌─ Storage ──────────────────────────┐ │
│ │ ████████░░░░░░░░░░░░ 412 MB / 1 GB│ │
│ └────────────────────────────────────┘ │
│ │
│ ┌─ AI Tokens (Today) ───────────────┐ │
│ │ ██████░░░░░░░░░░░░░░ 423 / 1000 │ │
│ └────────────────────────────────────┘ │
│ │
│ ┌─ AI Tokens (This Month) ──────────┐ │
│ │ ███░░░░░░░░░░░░░░░░░ 3,210 / 15k │ │
│ └────────────────────────────────────┘ │
│ │
│ ┌─ Special Credits ─────────────────┐ │
│ │ ████████████████░░░░ 812 / 1000 │ │
│ └────────────────────────────────────┘ │
│ │
│ Connected apps: 3 │
│ Active sessions: 2 │
│ │
└─────────────────────────────────────────┘#### 2. Settings
- Language preference
- Notification preferences (email notifications for security events)
- Theme (light/dark)
#### 3. Personal Data
- Display name (editable)
- Email (editable, requires verification on change)
- Phone (editable, requires verification on change)
- Avatar (upload/change)
- Third-party accounts:
- "Link another account" button
- Unlink option (if user has password set)
#### 4. Security
- Change password (requires current password)
- 2FA management:
- Register/passkey management
- View recovery codes (requires re-authentication)
- Regenerate recovery codes
- Active sessions:
- "This device" indicator
- Revoke individual sessions
- "Log out everywhere" button
- Account deletion (requires re-authentication + confirmation)
#### 5. App Access
Lists all apps the user has authorized. For each app:
┌─────────────────────────────────────────┐
│ 📦 Todo App │
│ Authorized: Jan 15, 2026 │
│ Last used: 2 hours ago │
│ Data accessed: Profile, Email │
│ │
│ [Revoke Access] │
└─────────────────────────────────────────┘- Revoke Access → calls
POST /api/app/revoke→ immediately invalidates the app's ability to refresh tokens for this user → next time the app tries to refresh, it gets401→ app must redirect user back through auth flow
#### 6. Terms & Policies
- Terms of service
- Privacy policy
- Data processing agreement
- Links to legal documents (served from core.docs or static pages)
Data Export (GDPR)
Under Personal Data or a dedicated "Your Data" section:
- "Download my data" button → generates a JSON/ZIP export of all user data stored in core.auth
- Includes: profile, sessions, ident_events, linked apps, third-party auth records
- Excludes: password hash, 2FA secrets, recovery codes
- Generated asynchronously, emailed as a download link
Account Deletion
Under Security:
User clicks "Delete Account"
│
▼
Re-authentication required (password + 2FA if enabled)
│
▼
Confirmation screen:
"Are you sure? This will:
- Delete your account and all associated data
- Revoke access to all connected apps
- This action cannot be undone
Type DELETE to confirm: [ ]"
│
▼
User types "DELETE" and confirms
│
▼
core.auth:
1. Soft-delete user (set deleted_at, set status = 'deleted')
2. Revoke all sessions
3. Revoke all app authorizations
4. Schedule hard deletion after 30-day grace period
5. Send confirmation emailApp Authorization Frontend
Served at
core.auth.medkronos.com/authorize. Uses the same progressive-reveal pattern as registration/login. Typically shown immediately after login or registration when the user is coming from an app.When It's Shown
User completes login/registration (has connection_ref)
│
▼
core.auth checks: has user already authorized this app?
│
├── Yes → skip, issue auth code, redirect to app
└── No → show authorization screenAuthorization Screen
┌─────────────────────────────────────────┐
│ │
│ [App Logo] │
│ │
│ Todo App wants to │
│ access your account │
│ │
│ This app may request your personal │
│ info, like name, email, etc. for │
│ the login process. │
│ │
│ Storage and AI usage in this app │
│ count towards your global account │
│ usage. │
│ │
│ [ Authorize ] │
│ [ Deny ] │
│ │
└─────────────────────────────────────────┘Phase 1 (current): No granular permissions. The screen is informational — the user authorizes or denies. If authorized, the app gets access to the user's basic profile (name, email, avatar).
Phase 2+: The screen will list specific permissions the app is requesting (scopes), and the user can modify which ones to grant.
Post-Authorization
User clicks "Authorize"
│
▼
core.auth:
1. Creates user_app_access record
2. Issues authorization code
3. Redirects to app's callback URL with code + state
│
▼
App exchanges code for JWT via core.console → user is logged in
User clicks "Deny"
│
▼
core.auth:
1. Does NOT create user_app_access record
2. Redirects to app's callback URL with error: access_denied
│
▼
App shows: "Access denied. You need to authorize to use this app."User Circle
A persistent UI element present on every UNVRSL app page, inspired by Google's profile circle. It serves as the always-visible account indicator and quick-access menu.
Purpose
- At-a-glance identity — the user always knows which account they're logged into, just by looking at the circle in the corner
- Quick settings — no need to navigate to the full account dashboard for common actions
- Account switching — seamless switching between multiple logged-in accounts (e.g. personal vs. work)
- Quota awareness — live usage indicators so the user never hits a quota wall unexpectedly
Appearance
┌──────────────────────────────────────────────────┐
│ ┌─────┐│
│ [App Content] │ 👤 ││
│ └─────┘│
│ User │
│ Circle │
└──────────────────────────────────────────────────┘- Fixed position: top-right corner of every page
- Size: 36–40px diameter circle
- Content: user's avatar (photo or initials fallback)
- Subtle ring color can indicate account type (e.g. free vs. premium) — optional, Phase 2
- On hover: slight scale-up + shadow
- Mobile: same position, slightly smaller (32px)
Click → Popover
Clicking the circle opens a popover dropdown anchored to the circle:
┌───────────────────────────────────────────┐
│ ┌───┐ │
│ │ 👤 │ Olivier Mironescu │
│ └───┘ olivier@example.com │
│ Free account │
│───────────────────────────────────────────│
│ │
│ 📦 Storage │
│ ████████░░░░░░░░░░░░ 412 MB / 1 GB │
│ │
│ 🤖 AI Credits (July) │
│ ██████░░░░░░░░░░░░░░ 1.2M / 4M credits │
│ (≈ 8,400 input + 2,100 output tokens) │
│ │
│ 🎨 Hypermedia Credits (July) │
│ ████████████░░░░░░░░ 38K / 100K credits │
│ │
│ ⚡ Special Credits (July) │
│ ████████████████░░░░ 412K / 500K credits │
│ (overflow: 18 MB storage + 12K AI) │
│───────────────────────────────────────────│
│ │
│ 🔄 Switch Account │
│ ├── olivier@example.com ✓ │
│ └── work@company.com │
│ │
│ ⚙️ Account Settings │
│ 🚪 Log Out │
│ │
└───────────────────────────────────────────┘Popover Sections
#### 1. Account Header
- Avatar (larger, 48px)
- Display name
- Account type badge (Free / Standard / Premium)
#### 2. Quota Meters
- Storage — used / total (e.g. "412 MB / 1 GB")
- AI Credits — credits consumed this month / monthly allowance. Sub-label shows approximate token equivalent for context (e.g. "≈ 8,400 input + 2,100 output tokens")
- Hypermedia Credits — credits consumed this month / monthly allowance
- Special Credits — credits consumed this month / monthly allowance. Sub-label shows what overflow was used (e.g. "overflow: 18 MB storage + 12K AI")
- Each meter is a thin progress bar with label
- Clicking a meter → navigates to full account dashboard
- Phase 2: color shifts from green → yellow → red as usage approaches limit
- All credit meters reset monthly on the same billing cycle
#### 3. Account Switcher
- Lists all accounts the user has authenticated with on this device
- Current account has a checkmark (✓)
- Clicking another account → switches without re-entering password (if session is still valid)
- "Add account" option → opens core.auth login in a new context (like Google's "Add account")
- Session cookies are scoped per account; switching is instant
#### 4. Quick Actions
- Account Settings → navigates to
/accountdashboard - Log Out → logs out of current app (revokes local session, keeps core.auth session alive)
- Phase 2: "Log out of all apps" option
Technical Implementation
- Owned by core.auth, delivered through core.console — the User Circle JS (
user-circle.js) is built and owned by core.auth, where the session context lives. But apps never call microservices directly: it is served to apps through core.console (the single entry point for all service traffic), embedded via a single<script>tag or PHP helper from core.backend. It is NOT served by core.assets (public static CDN; no user context). - Avatar images — user content, stored in S3 via core.storage; the circle renders them by URL (initials fallback).
- Core.auth session cookie — the popover reads the core.auth session cookie (
.medkronos.comdomain) to identify the current user. No extra API call needed for basic identity. - Quota data — fetched via a lightweight
GET /api/user/quotacall to core.console when the popover opens. Cached for 60 seconds to avoid hammering the API. - Account list — stored in
localStorageper device (list of user IDs + emails). Actual switching triggers a redirect to core.auth which checks for existing sessions. - Styling — the popover uses the shared design tokens/components from the core.assets design stylesheets that every app already loads via core.backend (DocumentShell); it matches the app's theme (light/dark). No per-component CSS is shipped.
- No framework — vanilla JS, same as all other auth frontends.
Multi-Account Session Model
Device localStorage:
{
"unvrsl_accounts": [
{ "user_id": "uuid-1", "email": "olivier@example.com", "last_active": 1719840000 },
{ "user_id": "uuid-2", "email": "work@company.com", "last_active": 1719753600 }
],
"unvrsl_active": "uuid-1"
}
core.auth cookies (scoped by user_id):
- session_ref_uuid-1 = "abc123..."
- session_ref_uuid-2 = "def456..."When the user switches accounts, the User Circle:
- Updates
unvrsl_activein localStorage - Redirects to core.auth with
?switch_to=uuid-2 - core.auth activates that session and redirects back to the app
- App receives a fresh JWT for the new account
Mobile Behavior
- Same top-right position
- Tap → full-screen bottom sheet instead of popover (better for thumbs)
- Quota meters and account switcher stacked vertically
- Swipe down to dismiss
Console Relay
All app-backend → core.auth service calls are routed through core.console with the project API key (
https://core.console.medkronos.com/v1/auth/*). Browser-facing UI pages (login, registration, authorize consent, account dashboard) remain on core.auth.medkronos.com — users' browsers interact with core.auth directly for these federated UI flows. Apps never call core.auth.medkronos.com from backend code.Shared Design System
All three frontends use core.assets for visual consistency:
- Colors, typography, spacing — from core.assets design tokens
- Buttons — primary (filled), secondary (outline), danger (red)
- Form inputs — consistent styling across all screens
- HTML init — core.backend provides the base HTML structure
- Responsive breakpoints — mobile-first, responsive layout
Theming
- Light mode (default)
- Dark mode (system preference detection + manual toggle)
- Brand customization per app (logo, accent color) — for the authorization screen
Cross-Origin & Cookie Policies
| Policy | Value |
SameSite | Lax (session_ref cookie sent on top-level navigations) |
Secure | true (HTTPS only) |
HttpOnly | true (not accessible to JavaScript) |
Domain | .medkronos.com (shared across all subdomains) |
Path | /session/refresh (only sent to refresh endpoint) |
CORS for browser-consumable endpoints (e.g. silent refresh, if routed through core.console to the browser) is handled by core.console per project's registered domains. Server-to-server calls (app backend → console) don't require CORS.
CSP Headers
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{random}';
style-src 'self' 'nonce-{random}';
img-src 'self' data: https://*.medkronos.com;
connect-src 'self' https://core.auth.medkronos.com;
frame-ancestors 'none';
form-action 'self';See also: Registration & Login for auth flow details, App Integration for how apps connect.