Authentication, Onboarding & RBAC Flow Diagrams

Agencio Predict — User flows from UI to backend with role gates and license validation

Generated: 2026-05-19

1. System Overview

High-level view of user authentication, authorization, and feature access in Agencio Predict.

flowchart TB subgraph "User Entry Points" LP["/login Page"] RP["/register Page"] TD["Terminal Subdomain"] end subgraph "Authentication Layer" AS["Auth Store
(Zustand)"] JWT["JWT Token"] MFA["MFA Challenge"] SS["Session Service"] end subgraph "Auth Providers" LOCAL["Local Provider
(bcrypt + JWT)"] COGNITO["AWS Cognito"] AGENCIO["Agencio Auth Service"] end subgraph "Authorization Layer" MW["Auth Middleware
extractUser() / requireAuth()"] RBAC["RBAC Engine
hasRole() / hasPermission()"] FG["Feature Gate
checkFeatureAccess()"] end subgraph "License Layer" DG["Deployment Guard"] LS["License Server"] SUB["Subscription Service"] end subgraph "Protected Resources" DASH["/dashboard"] ADMIN["/admin/*"] TRADE["/trading"] ALGO["/algorithms"] end LP --> AS RP --> AS TD --> AS AS --> LOCAL AS --> COGNITO AS --> AGENCIO LOCAL --> JWT COGNITO --> JWT AGENCIO --> JWT JWT --> MFA MFA --> SS SS --> MW MW --> RBAC RBAC --> FG FG --> DG DG --> LS FG --> SUB MW --> DASH RBAC --> ADMIN FG --> TRADE FG --> ALGO

Key Security Principles

Principle Implementation
Role Authority Local DB role takes precedence over external provider token role
Defense in Depth Role checks at API route, handler, AND database levels
Dev Bypass Safety Requires BOTH NODE_ENV !== 'production' AND ALLOW_DEV_AUTH_BYPASS=true
Session Tokens SHA256 hashed in DB, never stored raw
License Validation HMAC-SHA256 signed requests/responses with timestamp freshness check

2. Login Flow (UI → Backend)

Complete login sequence from user input to authenticated session.

sequenceDiagram autonumber participant U as User participant LP as /login Page participant AS as Auth Store participant API as /api/auth/login participant MW as Middleware participant P as Auth Provider participant DB as Database participant SS as Session Service U->>LP: Enter email + password LP->>AS: login(email, password) AS->>API: POST /auth/login API->>MW: extractUser() [skip - login is public] API->>P: provider.authenticate(credentials) alt Provider: Local P->>DB: SELECT from auth.users WHERE email DB-->>P: User record + password_hash P->>P: bcrypt.compare(password, hash) P-->>API: AuthResult {tokens} else Provider: Cognito P->>P: InitiateAuthCommand P-->>API: AuthResult {tokens OR challenge} else Provider: Agencio P->>P: HTTP to auth service P-->>API: AuthResult {tokens OR challenge} end alt MFA Required API-->>AS: {challenge: {name, session}} AS->>AS: Store pendingMfa AS-->>LP: {status: 'mfa_required'} LP->>U: Redirect to /login/mfa else No MFA API->>DB: Sync external user to local DB-->>API: localUser with DB role API->>SS: createSession(userId, token, deviceInfo) SS->>DB: INSERT into auth.user_sessions SS-->>API: {sessionId, sessionsRevoked} API-->>AS: {user, token, expiresIn, nextStep} AS->>AS: Set user, token, isAuthenticated AS-->>LP: {status: 'ok', nextStep} LP->>U: Route based on nextStep end

Login Response Structure

{
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "name": "John Doe",
    "role": "user | editor | administrator | super_admin",
    "status": "active | pending_verification | pending_mfa | pending_subscription",
    "mfaRequired": true | false
  },
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "...",
  "expiresIn": 604800,
  "provider": "cognito | agencio | local",
  "nextStep": "verify-email | await-approval | enroll-mfa | subscribe | null",
  "sessionsRevoked": 2  // if session limit exceeded
}

File References

Component File Path Key Lines
Login Page apps/web/src/app/login/page.tsx 44-69 (handleSubmit)
Auth Store packages/fe/src/store/auth.ts 272-346 (login action)
Login Handler packages/be/src/api/predict/v1/auth/handlers.ts 64-108
Local Provider packages/be/src/lib/auth/providers/local.ts 76-100+
Cognito Provider packages/be/src/lib/auth/providers/cognito.ts 148-197

3. MFA Challenge Flow

Second-factor authentication for SMS and TOTP (authenticator apps).

sequenceDiagram autonumber participant U as User participant MP as /login/mfa Page participant AS as Auth Store participant API as /api/auth/mfa/* participant P as Auth Provider participant DB as Database Note over U,DB: MFA_SETUP (First-time enrollment) U->>MP: Arrive with pendingMfa.challengeName = 'MFA_SETUP' MP->>API: GET /auth/mfa/setup-challenge API->>P: startMfaEnrollment({email, session}) P-->>API: {secret, otpauthUrl, session} API-->>MP: QR code data MP->>U: Display QR code + manual secret U->>U: Scan QR in authenticator app U->>MP: Enter 6-digit code Note over U,DB: Code Verification (all MFA types) MP->>MP: Auto-submit on 6 digits MP->>AS: submitMfaCode(code) AS->>API: POST /auth/mfa/challenge API->>P: respondToMfaChallenge({email, session, code, challengeName}) alt Valid Code P-->>API: AuthResult {tokens} API->>DB: Create session API-->>AS: {user, token, nextStep} AS->>AS: Clear pendingMfa, set authenticated AS-->>MP: {status: 'ok'} MP->>U: Redirect to nextStep destination else Invalid Code P-->>API: Error API-->>AS: {error: 'Invalid code'} AS-->>MP: {status: 'error'} MP->>U: Show error, allow retry else Session Expired P-->>API: Error (session timeout) API-->>AS: {error: 'MFA_SESSION_EXPIRED'} AS->>AS: Clear pendingMfa AS-->>MP: Redirect to /login end

MFA Challenge Types

Challenge Description UI Behavior
SMS_MFA Code sent via SMS to registered phone Shows "Code sent to +*****45"
SOFTWARE_TOKEN_MFA TOTP code from authenticator app Shows "Enter your authenticator app code"
MFA_SETUP First-time TOTP enrollment Shows QR code + manual secret entry
NEW_PASSWORD_REQUIRED Password change required (Cognito) Shows password change form

TOTP Configuration

Setting Value
Algorithm SHA-1 (RFC 6238)
Digits 6
Period 30 seconds
Window ±1 step (absorbs clock skew)
Secret Storage AES-256-GCM encrypted in auth.users.mfa_secret_encrypted
File: packages/be/src/lib/auth/mfa-enrollment.ts (lines 72-141)

4. Session Management

Multi-device session tracking with configurable limits and timeout handling.

flowchart TB subgraph "Session Creation" LOGIN["Successful Login"] HASH["SHA256 Hash Token"] PARSE["Parse User-Agent"] CHECK["Check Session Count"] end subgraph "Limit Enforcement" COUNT{{"count >= max_sessions?"}} REVOKE["Revoke Oldest Sessions"] INSERT["Insert New Session"] end subgraph "Session State" ACTIVE["Active Sessions"] REVOKED["Revoked Sessions"] EXPIRED["Expired Sessions"] end subgraph "User Actions" LOGOUT["Logout (Single)"] LOGOUT_ALL["Logout All Devices"] SETTINGS["Session Settings"] end LOGIN --> HASH HASH --> PARSE PARSE --> CHECK CHECK --> COUNT COUNT -->|Yes| REVOKE COUNT -->|No| INSERT REVOKE --> INSERT INSERT --> ACTIVE LOGOUT --> REVOKED LOGOUT_ALL --> REVOKED ACTIVE -.->|Expiry| EXPIRED SETTINGS -->|"max_sessions
(5-20)"| CHECK

Session Data Structure

interface UserSession {
  id: string;
  userId: string;
  deviceName: string;      // "Chrome on Windows", "Safari on iOS"
  deviceType: 'desktop' | 'mobile' | 'tablet' | 'terminal' | 'unknown';
  ipAddress: string;
  locationCity: string;
  locationCountry: string;
  createdAt: Date;
  lastActivityAt: Date;
  expiresAt: Date;
  isCurrent: boolean;      // Highlighted in UI
}

Session Timeout Configuration

Mode Default Range
Desktop 60 minutes 5-240 minutes
Terminal 480 minutes (8 hours) 15-480 minutes

Revocation Reasons

Reason Trigger
user_logout User clicked logout
remote_logout User logged out from another device
admin_action Admin forced logout
password_change Password was changed
session_limit Max concurrent sessions exceeded
File: packages/be/src/lib/auth/session-service.ts (lines 184-331)

5. Registration & Email Verification

New user signup flow with CAPTCHA, email verification, and optional admin approval.

sequenceDiagram autonumber participant U as User participant RP as /register Page participant API as /api/auth/register participant CF as Cloudflare Turnstile participant P as Auth Provider participant DB as Database participant EM as Email Service U->>RP: Fill registration form RP->>CF: Complete CAPTCHA challenge CF-->>RP: Turnstile token RP->>API: POST /auth/register API->>CF: Verify Turnstile token CF-->>API: {success: true} API->>DB: Check email blacklist DB-->>API: Not blacklisted API->>P: provider.register(credentials) P->>DB: INSERT auth.users (status='pending_verification') P-->>API: AuthResult API->>EM: Send verification email EM-->>U: Email with 6-digit code API-->>RP: {nextStep: 'verify-email'} RP->>U: Redirect to /verify-email Note over U,EM: Email Verification U->>API: POST /auth/verify-email {code} API->>P: provider.confirmEmail(email, code) P->>DB: UPDATE status='pending_approval' OR 'pending_mfa' API-->>U: {nextStep: 'await-approval' OR 'enroll-mfa'}

Registration Gates

Gate Check Response on Failure
CAPTCHA Turnstile token verification 400 "Invalid CAPTCHA"
Email Blacklist Check auth.email_blacklist 400 "Registration blocked"
Provider Email uniqueness, password policy 400 with validation errors
File: packages/be/src/api/predict/v1/auth/handlers.ts (lines 389-505)

6. Onboarding Status Ladder

User status progression from registration to fully active account.

stateDiagram-v2 [*] --> pending_verification: Register pending_verification --> pending_approval: Verify Email pending_verification --> rejected: Admin Reject pending_approval --> pending_mfa: Admin Approve (MFA required) pending_approval --> pending_subscription: Admin Approve (no MFA) pending_approval --> rejected: Admin Reject pending_mfa --> pending_subscription: Complete MFA Setup pending_subscription --> active: Complete Payment pending_subscription --> active: Free Plan Selected active --> suspended: Admin Suspend active --> deactivated: User Deactivate active --> pending_deletion: User Request Delete suspended --> active: Admin Unsuspend deactivated --> active: User Login (auto-reactivate) pending_deletion --> deleted: Grace Period Expires pending_deletion --> active: User Cancel Deletion rejected --> [*] deleted --> [*]

Status Routing

Status Login Result Redirect To
pending_verification nextStep: 'verify-email' /verify-email
pending_approval nextStep: 'await-approval' /pending-approval
pending_mfa nextStep: 'enroll-mfa' /onboarding/mfa
pending_subscription nextStep: 'subscribe' /onboarding/subscribe
active nextStep: null /dashboard
deactivated Auto-reactivate on login /dashboard
suspended / deleted 401 Unauthorized Error page

Onboarding Pages

/onboarding/mfa

  • QR code for authenticator app
  • Manual secret backup
  • 6-digit code verification
  • Advances to pending_subscription

/onboarding/subscribe

  • Plan selection (Free/Pro/Enterprise)
  • Stripe Checkout redirect
  • Webhook activates account
  • Polling for status update
File: packages/be/src/lib/auth/onboarding.ts (lines 1-148)

7. Getting Started Hub

Centralized onboarding page with guided setup for 6 key features.

flowchart LR subgraph "Entry Points" DB["Dashboard Banner"] SB["Sidebar Badge"] URL["/getting-started URL"] end subgraph "Getting Started Hub" GS["GettingStartedPage"] subgraph "Setup Cards" TS["Trading Setup"] AB["Algorithm Builder"] SP["Smart Portfolio"] FM["Fund Manager"] PH["Pattern Hunter"] MI["Market Intelligence"] end end subgraph "Destinations" TSP["/trading/setup"] ABP["/admin/algorithms"] SPP["/smart-portfolio/new"] FMP["/fund-manager"] PHP["/patterns"] MIP["/markets/discoveries"] end subgraph "Progress Tracking" STORE["Getting Started Store"] API["Setup Progress API"] DBWP["user_wizard_progress"] end DB --> GS SB --> GS URL --> GS GS --> TS --> TSP GS --> AB --> ABP GS --> SP --> SPP GS --> FM --> FMP GS --> PH --> PHP GS --> MI --> MIP TSP --> STORE ABP --> STORE SPP --> STORE FMP --> STORE PHP --> STORE MIP --> STORE STORE <--> API <--> DBWP

Setup Cards

Card Wizard ID Best For Destination
Trading Setup trading-setup All users (foundation) /trading/setup
Build a Strategy algorithm-builder Algorithmic traders /admin/algorithms
Smart Portfolio smart-portfolio Passive investors /smart-portfolio/new
Fund Manager fund-creator Multi-strategy users /fund-manager
Pattern Hunter pattern-import Technical analysts /patterns
Market Intelligence market-intelligence Market researchers /markets/discoveries

API Endpoints

Endpoint Method Purpose
/api/predict/v1/user/setup-progress GET Fetch all wizard progress + settings
/api/predict/v1/user/setup-progress/{wizardId}/complete POST Mark wizard as complete
/api/predict/v1/user/setup-progress/settings PUT Update show-on-login preferences
/api/predict/v1/user/setup-progress/dismiss POST Hide getting started permanently
/api/predict/v1/user/setup-progress/reset POST Reset all progress
File: packages/fe/src/components/getting-started/GettingStartedPage.tsx (lines 94-120+)

8. Feature Wizards

Step-by-step guided flows for complex feature setup.

flowchart TB subgraph "Algorithm Builder Wizard (7 steps)" AW1["1. Welcome
Choose method"] AW2["2. Create
Build algorithm"] AW3["3. Critique
LLM review"] AW4["4. Backtest
90-day test"] AW5["5. Validate
Walk-forward"] AW6["6. Stress
Regime replay"] AW7["7. Complete
Launch paper"] AW1 --> AW2 --> AW3 --> AW4 --> AW5 --> AW6 --> AW7 end subgraph "Trading Wizard (5 steps)" TW1["1. Welcome"] TW2["2. Portfolio
Select/create"] TW3["3. Signals
Configure AI"] TW4["4. Execute
Mode + risk"] TW5["5. Complete
Summary"] TW1 --> TW2 --> TW3 --> TW4 --> TW5 end subgraph "Smart Portfolio Wizard (5 steps)" SW1["1. Universe
Select symbols"] SW2["2. Analysis
AI recommendations"] SW3["3. Strategies
Auto-generate"] SW4["4. Config
Fund params"] SW5["5. Launch
Start trading"] SW1 --> SW2 --> SW3 --> SW4 --> SW5 end subgraph "Fund Creator Wizard (5 steps)" FW1["1. Basics
Name + capital"] FW2["2. Risk
DD + limits"] FW3["3. Allocation
Weight method"] FW4["4. Strategies
Select algos"] FW5["5. Review
Launch"] FW1 --> FW2 --> FW3 --> FW4 --> FW5 end

Algorithm Builder Gates

Step Gate Condition Quick Path
Backtest Sharpe >= 0.5, Max DD <= 25% Required
Validate OOS/IS ratio >= 0.7 Skipped
Critique LLM adversarial review pass Skipped
Stress No regime with DD > 50% Required

Wizard Progress Storage

// localStorage key: agencio-algorithm-wizard-progress
{
  "version": 1,
  "currentStep": "backtest",
  "algorithmId": "uuid",
  "createdAt": "2026-05-19T10:00:00Z",
  "expiresAt": "2026-05-20T10:00:00Z",  // 24-hour expiry
  "data": {
    "backtestResults": {...},
    "validationResults": {...}
  }
}
File: packages/fe/src/components/algorithms/wizard/AlgorithmBuilderWizard.tsx (lines 1-150+)

9. Mini-Tours & Platform Tour

Contextual feature guides and full platform walkthrough.

flowchart TB subgraph "Platform Tour (14 steps)" PT["Onboarding Store"] PT1["1. Dashboard"] PT2["2. Terminal"] PT3["3. Prediction Markets"] PT4["4. All-Seeing Eye"] PT5["5. AI Engine"] PT6["6-8. ..."] PT9["9. Marketing"] PT10["10-14. ..."] PT --> PT1 --> PT2 --> PT3 --> PT4 --> PT5 --> PT6 --> PT9 --> PT10 end subgraph "Mini-Tours" MT["Mini-Tours Store"] subgraph "algorithms-mini (6 steps)" AM1["Guided Setup"] AM2["From English"] AM3["Strategy List"] AM4["Backtest Button"] AM5["Paper Button"] end subgraph "trading-mini (5 steps)" TM1["Mock Credits"] TM2["Portfolios"] TM3["Place a Trade"] TM4["Guardrails"] TM5["Graduation"] end subgraph "datasets-mini (4 steps)" DM1["Your Datasets"] DM2["System Datasets"] DM3["Import New"] DM4["Use in Backtests"] end MT --> AM1 MT --> TM1 MT --> DM1 end

Tour State Management

Store Key Purpose
Onboarding Store agencio-predict-onboarding 14-step platform tour + show-on-login
Mini-Tours Store agencio-predict-mini-tours Feature-specific tours + completions
Getting Started Store agencio-getting-started 6-card wizard progress

Tour API Endpoints

Endpoint Purpose
GET /api/predict/v1/user/onboarding/status Get tour completion state
POST /api/predict/v1/user/onboarding/complete Mark platform tour complete
POST /api/predict/v1/user/onboarding/reset Reset tour for replay
PUT /api/predict/v1/user/onboarding/tour-on-login Configure auto-start
POST /api/predict/v1/user/mini-tours/complete Mark mini-tour complete
File: packages/fe/src/store/onboarding.ts (lines 1-331) File: packages/fe/src/store/mini-tours.ts (lines 1-323)

10. User Roles & Hierarchy

8 user roles with hierarchical inheritance.

flowchart TB subgraph "Role Hierarchy" SA["super_admin"] AD["admin / administrator"] ED["editor"] US["user"] CU["console_user"] VW["viewer"] SV["service"] SA --> AD AD --> ED ED --> US US --> VW CU --> VW end subgraph "Access Levels" L1["Platform Config
(super_admin only)"] L2["Admin Panel
(admin+)"] L3["Create/Edit
(editor+)"] L4["Read/Trade
(user+)"] L5["Console Only
(console_user)"] L6["Read Only
(viewer)"] end SA --> L1 AD --> L2 ED --> L3 US --> L4 CU --> L5 VW --> L6

Role Definitions

Role Description Typical Use Case
super_admin Platform-wide access, billing, integrations Platform operators
admin Org-scoped admin, user management Organization administrators
administrator Alias for admin (Same as admin)
support Support chat access, read-only admin Customer support staff
editor Create/edit events, signals Content contributors
user Standard access, trading, algorithms Regular subscribers
console_user Terminal console only, read feeds Terminal-only access
viewer Read-only access Observers, demo accounts
service API-only, programmatic access Service accounts, integrations

Role Inheritance

ROLE_HIERARCHY = {
  super_admin: [admin, administrator, editor, user, console_user, viewer],
  admin: [administrator, editor, user, console_user, viewer],
  administrator: [admin, editor, user, console_user, viewer],
  editor: [user, viewer],
  user: [viewer],
  console_user: [viewer],
  viewer: [],
  service: []
}
File: packages/shared/src/auth.ts (lines 13-63) File: packages/be/src/lib/auth/rbac.ts (lines 54-63)

11. RBAC Permission System

Fine-grained permission checks for API endpoints.

flowchart LR subgraph "Request Flow" REQ["API Request"] MW["requireAuth()"] ROLE["hasRole()"] PERM["hasPermission()"] FEAT["checkFeatureAccess()"] HAND["Handler"] end subgraph "Permission Types" ER["events:read"] EC["events:create"] EU["events:update"] ED["events:delete"] EV["events:resolve"] SR["signals:read"] SC["signals:create"] OM["orgs:manage"] AA["admin:access"] SY["system:config"] end REQ --> MW --> ROLE --> PERM --> FEAT --> HAND PERM --> ER PERM --> EC PERM --> EU PERM --> ED PERM --> EV PERM --> SR PERM --> SC PERM --> OM PERM --> AA PERM --> SY

Role → Permission Matrix

Permission super_admin admin editor user viewer service
events:read
events:create
events:update
events:delete
events:resolve
signals:create
orgs:manage
admin:access
system:config

RBAC Functions

// Check if user has any of the specified roles (direct or inherited)
hasRole(user, ...roles: Role[]): boolean

// Check if user has all specified permissions
hasPermission(user, ...permissions: Permission[]): boolean

// Check if user has any of the specified permissions
hasAnyPermission(user, ...permissions: Permission[]): boolean

// Throw 403 if permission check fails
requirePermissions(user, ...permissions: Permission[]): void

// Throw 403 if role check fails
requireRoles(user, ...roles: Role[]): void

// Get all effective permissions for a user
getEffectivePermissions(user): Permission[]
File: packages/be/src/lib/auth/rbac.ts (lines 117-182)

12. Admin Route Protection

Admin panel access control and super_admin-only features.

flowchart TB subgraph "Admin Layout Check" REQ["Request to /admin/*"] AUTH["isAuthenticated?"] ROLE["isAdminRole(user.role)?"] SUPER["isSuperAdmin?"] end subgraph "Admin Routes (all admins)" AU["/admin/users"] AT["/admin/trades"] AA["/admin/algorithms"] AC["/admin/categories"] AP["/admin/predictions"] AS["/admin/signals"] AN["/admin/news"] ASF["/admin/social-follows"] end subgraph "Super-Admin Only" AB["/admin/billing"] AAI["/admin/ai-billing"] APK["/admin/platform-ai-keys"] ASH["/admin/stock-hunter-config"] ABR["/admin/brokers"] ASA["/admin/service-accounts"] ACG["/admin/cognito"] AAW["/admin/aws"] AI["/admin/integrations"] AF["/admin/feeds"] AFL["/admin/flow"] ASI["/admin/silo"] ABE["/admin/bertha"] ASY["/admin/system"] ASS["/admin/assistant"] ASD["/admin/support-docs"] APM["/admin/pinn-models"] end REQ --> AUTH AUTH -->|No| LOGIN["/login"] AUTH -->|Yes| ROLE ROLE -->|No| DENY["403 Forbidden"] ROLE -->|Yes| AU & AT & AA & AC & AP & AS & AN & ASF ROLE -->|Yes| SUPER SUPER -->|Yes| AB & AAI & APK & ASH & ABR & ASA & ACG & AAW & AI & AF & AFL & ASI & ABE & ASY & ASS & ASD & APM SUPER -->|No| HIDE["Items hidden from nav"]

Backend Admin Pattern

// In route.ts (thin wrapper)
export async function GET(request: NextRequest) {
  const adminError = await requireAdmin(request);
  if (adminError) return adminError;
  return handleListUsers(request);
}

// In handlers.ts
async function requireAdmin(request: NextRequest) {
  const user = await requireAuth(request);
  if (!isAdminRole(user.role)) {
    throw Errors.forbidden('Admin role required');
  }
  return user;
}

async function requireSuperAdmin(request: NextRequest) {
  const user = await requireAuth(request);
  if (!isSuperAdmin(user.role)) {
    throw Errors.forbidden('Super admin role required');
  }
  return user;
}

Org-Scoped Admin Access

Role Scope Can See
super_admin Platform-wide All users, all orgs
admin / administrator Own org only Users in their organization
File: apps/web/src/app/admin/layout.tsx (lines 17-100) File: packages/be/src/api/predict/v1/admin/users/handlers.ts (lines 54-80)

13. License & Deployment Guard

Anti-piracy protection with License Server validation.

sequenceDiagram autonumber participant APP as Next.js App participant DG as Deployment Guard participant LS as License Server Note over APP,LS: Startup Validation APP->>DG: initializeDeploymentGuard() DG->>DG: generateFingerprint() Note right of DG: hostname, platform,
arch, CPUs, MACs
→ SHA256 hash DG->>LS: POST /api/deployments/validate Note right of DG: Headers:
X-Deployment-Signature
X-Deployment-Id LS->>LS: Verify HMAC signature LS->>LS: Check deployment license LS-->>DG: {valid, tier, features, expiresAt, _sig, _ts} DG->>DG: verifyResponseSignature() Note right of DG: Check _sig HMAC
Check _ts freshness (<5 min) alt Valid License DG->>DG: Cache result DG->>DG: Start heartbeat (60 min) DG-->>APP: Continue startup else Invalid (Production) DG-->>APP: throw "UNAUTHORIZED DEPLOYMENT" else Invalid (Dev) DG->>DG: Log warning DG-->>APP: Continue with degraded mode end Note over APP,LS: Hourly Heartbeat loop Every 60 minutes DG->>LS: POST /api/deployments/validate LS-->>DG: ValidationResult alt 3 Consecutive Failures DG->>APP: onHeartbeatFailure callback end end

Machine Fingerprint

interface DeploymentFingerprint {
  deploymentId: string;      // From DEPLOYMENT_ID env
  machineHash: string;       // SHA256 of hardware info
  version: string;           // From APP_VERSION env
  environment: string;       // From NODE_ENV
  timestamp: number;         // Current epoch
}

// Machine hash computed from:
// - os.hostname()
// - os.platform()
// - os.arch()
// - os.cpus()[0].model
// - os.totalmem()
// - MAC addresses (sorted)

Response Signing

Field Purpose
_sig HMAC-SHA256 signature of response body
_ts Response timestamp (rejects if >5 min old)
_did Deployment ID echo (prevents replay)

Environment Variables

Variable Required Default
LICENSE_SERVER_URL Production https://licensing.agencio.cloud
DEPLOYMENT_KEY Production (none)
DEPLOYMENT_ID No Auto-generated
DEPLOYMENT_GUARD_ENABLED No true
File: packages/be/src/lib/deployment-guard/validator.ts (lines 105-268) File: apps/web/src/instrumentation.ts (lines 1-69)

14. Subscription & Billing Gates

Three-tier subscription model with feature gating.

flowchart TB subgraph "Subscription Tiers" FREE["Free Tier"] PRO["Pro Tier"] ENT["Enterprise Tier"] end subgraph "Feature Gates" API["API Access"] PRED["Predictions"] MKT["Marketing Predictions"] EXP["Exports"] CSV["CSV Export"] PDF["PDF Export"] HIST["Trade History"] SUPP["Priority Support"] CUST["Custom Models"] WL["White Label"] end subgraph "History Limits" H30["30 days"] H365["365 days"] HUNL["Unlimited"] end FREE --> API & PRED FREE --> H30 PRO --> API & PRED & MKT & EXP & CSV PRO --> H365 ENT --> API & PRED & MKT & EXP & CSV & PDF & SUPP & CUST & WL ENT --> HUNL

Feature Access Check

// Non-throwing check
const result = await checkFeatureAccess(userId, 'trade_export_pdf');
// Returns: { allowed: boolean, planName, feature, upgradeRequired?, message? }

// Throwing check
await requireFeature(userId, 'custom_models', 'Custom models require Enterprise');
// Throws 403 if denied

// Trade history limit
const days = await getTradeHistoryLimit(userId);
// Returns: 30 | 365 | null (unlimited)

Plan Features

Feature Free Pro Enterprise
API Access
Predictions
Marketing Predictions
Exports
CSV Export
PDF Export
Trade History 30 days365 daysUnlimited
Priority Support
Custom Models
White Label
File: packages/be/src/billing/services/feature-gate.ts (lines 43-222) File: packages/be/src/billing/services/subscription-service.ts (lines 631-900)

15. Plan Overrides (Gratuitous Subscriptions)

Admin-managed subscription overrides for trials, VIP users, and testing.

flowchart TB subgraph "Override Sources" SA["Super Admin"] API["Admin API"] UI["/admin/users"] end subgraph "Override Table" OV["billing.user_plan_overrides"] end subgraph "Resolution Priority" P1["1. Active Override
(not expired, not revoked)"] P2["2. Real Subscription
(billing.subscriptions)"] P3["3. Free Plan Default"] end subgraph "User Experience" BADGE["'Gratuitous Pro'
badge in UI"] EXP["Expiry countdown"] FEAT["Full plan features"] end SA --> API --> OV UI --> API OV --> P1 P1 -->|Found| BADGE & EXP & FEAT P1 -->|Not Found| P2 P2 -->|Found| FEAT P2 -->|Not Found| P3

Override Schema

CREATE TABLE billing.user_plan_overrides (
  id              UUID PRIMARY KEY,
  user_id         UUID REFERENCES auth.users(id),
  plan_id         UUID REFERENCES billing.subscription_plans(id),
  granted_by      UUID REFERENCES auth.users(id),
  reason          TEXT CHECK (length(reason) >= 10),
  starts_at       TIMESTAMPTZ DEFAULT NOW(),
  expires_at      TIMESTAMPTZ,           -- NULL = open-ended
  revoked_at      TIMESTAMPTZ,           -- NULL = active
  revoked_by      UUID REFERENCES auth.users(id),
  created_at      TIMESTAMPTZ DEFAULT NOW()
);

Admin API Endpoints

Endpoint Method Purpose
/admin/users/{id}/plan-override POST Grant override (super_admin only)
/admin/users/{id}/plan-override/{overrideId} DELETE Revoke override
/admin/users/{id}/plan-overrides GET List all overrides for user

Grant Override Request

POST /api/predict/v1/admin/users/{id}/plan-override
{
  "planId": "uuid",
  "reason": "Enterprise trial for evaluation (min 10 chars)",
  "expiresAt": "2026-06-19T00:00:00Z"
  // OR
  "durationHours": 720  // 30 days
}

Single-Active Invariant

When granting a new override, any existing active override is automatically revoked to prevent audit confusion.

File: packages/be/src/api/predict/v1/admin/users/handlers.ts (lines 1233-1346) File: db/migrations/145_user_plan_overrides.sql

16. File Reference

Complete file listing for authentication, onboarding, and authorization components.

Frontend Components

Component File Path Lines
Login Page apps/web/src/app/login/page.tsx 232
MFA Page apps/web/src/app/login/mfa/page.tsx 222
Register Page apps/web/src/app/register/page.tsx 180+
Getting Started Page apps/web/src/app/getting-started/page.tsx 7
Getting Started Component packages/fe/src/components/getting-started/GettingStartedPage.tsx 120+
Algorithm Wizard packages/fe/src/components/algorithms/wizard/AlgorithmBuilderWizard.tsx 150+
Admin Layout apps/web/src/app/admin/layout.tsx 100+
Onboarding MFA apps/web/src/app/onboarding/mfa/page.tsx 80+
Onboarding Complete apps/web/src/app/onboarding/complete/page.tsx 108

Frontend Stores

Store File Path Lines
Auth Store packages/fe/src/store/auth.ts 400+
Getting Started Store packages/fe/src/store/getting-started.ts 277
Onboarding Store packages/fe/src/store/onboarding.ts 331
Mini-Tours Store packages/fe/src/store/mini-tours.ts 323

Backend Auth

Component File Path Lines
Auth Middleware packages/be/src/lib/auth/middleware.ts 287
RBAC Engine packages/be/src/lib/auth/rbac.ts 253
Session Service packages/be/src/lib/auth/session-service.ts 331
MFA Enrollment packages/be/src/lib/auth/mfa-enrollment.ts 148
Onboarding Logic packages/be/src/lib/auth/onboarding.ts 148
Provider Factory packages/be/src/lib/auth/providers/index.ts 128
Local Provider packages/be/src/lib/auth/providers/local.ts 200+
Cognito Provider packages/be/src/lib/auth/providers/cognito.ts 400+
Provider Types packages/be/src/lib/auth/providers/types.ts 212

Backend Handlers

Handler File Path Lines
Auth Handlers packages/be/src/api/predict/v1/auth/handlers.ts 912
Admin Users packages/be/src/api/predict/v1/admin/users/handlers.ts 1400+
Setup Progress packages/be/src/api/predict/v1/user/setup-progress/handlers.ts 290

License & Billing

Component File Path Lines
Deployment Guard packages/be/src/lib/deployment-guard/index.ts 108
License Validator packages/be/src/lib/deployment-guard/validator.ts 278
Watermark packages/be/src/lib/deployment-guard/watermark.ts 62
Feature Gate packages/be/src/billing/services/feature-gate.ts 222
Subscription Service packages/be/src/billing/services/subscription-service.ts 900+
AI Credit Service packages/be/src/billing/services/ai-credit-service.ts 300+
AI Billing Router packages/be/src/billing/services/ai-billing-router.ts 200+

Shared Types

Module File Path Lines
Auth Types packages/shared/src/auth.ts 120+

Database Migrations

Migration File Path Purpose
001 db/migrations/001_auth_schema.sql Base auth.users table
031 db/migrations/031_user_status_and_roles.sql Role + status columns
145 db/migrations/145_user_plan_overrides.sql Gratuitous subscriptions
164 db/migrations/164_session_management.sql user_sessions table
175 db/migrations/175_onboarding_enhancements.sql user_wizard_progress + mini-tours
235 db/migrations/235_getting_started_settings.sql Getting started preferences