# JK8 Dual-Platform System Handbook (Master Technical Specification)

> **Document Status**: Production Complete (v2.6)  
> **Source of Truth**: Reconciled directly against `jk8-api` backend controllers, database entities, and `jk8-ui` components.  
> **Publish Outputs**: 
> 1. Customer User Guide (Clean Card Theme): [`plane-docs/system-handbook/Customer User Guide.html`](file:///Users/ryant/Dev/jk8/plane-docs/system-handbook/Customer%20User%20Guide.html)
> 2. Admin User Guide (Clean Card Theme): [`plane-docs/system-handbook/Admin User Guide.html`](file:///Users/ryant/Dev/jk8/plane-docs/system-handbook/Admin%20User%20Guide.html)
> 3. Vendor Handbook (Interactive Dark/Light Theme): [`plane-docs/system-handbook/vendor-handbook.html`](file:///Users/ryant/Dev/jk8/plane-docs/system-handbook/vendor-handbook.html)
> 4. Dual-Platform Master Handbook (Interactive Dark/Light Theme): [`plane-docs/system-handbook/handbook-app.html`](file:///Users/ryant/Dev/jk8/plane-docs/system-handbook/handbook-app.html)
> 5. Master Markdown Specification: [`plane-docs/system-handbook/handbook-master.md`](file:///Users/ryant/Dev/jk8/plane-docs/system-handbook/handbook-master.md)

---

## Table of Contents

1. [Dual-Platform Architecture & Security Perimeter](#1-dual-platform-architecture--security-perimeter)
2. [Complete Page Catalog (All 21 Surfaces)](#2-complete-page-catalog-all-21-surfaces)
   - [Platform 1: System Admin Pages (/system)](#platform-1-system-admin-pages-system)
   - [Platform 2: Vendor Organization Pages (/)](#platform-2-vendor-organization-pages-)
   - [Shared Authentication & Setup Screens](#shared-authentication--setup-screens)
3. [Complete Backend REST API Reference (36+ Endpoints)](#3-complete-backend-rest-api-reference-36-endpoints)
   - [Authentication & 2FA (`/api/auth`)](#authentication--2fa-apiauth)
   - [System Administration (`/api/system-admin`)](#system-administration-apisystem-admin)
   - [Brand & BO Integration (`/api/brands`)](#brand--bo-integration-apibrands)
   - [Analytical Reports (`/api/reports`)](#analytical-reports-apireports)
   - [Transactions & Ledger (`/api/transactions`)](#transactions--ledger-apitransactions)
   - [Members & Cohorts (`/api/members`)](#members--cohorts-apimembers)
   - [Data Export (`/api/export`)](#data-export-apiexport)
   - [Cost Analysis: Method Fees & Game Providers](#cost-analysis-method-fees--game-providers)
   - [Team Management & Staff Invites](#team-management--staff-invites)
   - [Brand Operational Settings](#brand-operational-settings)
4. [Critical Technical Integrations](#4-critical-technical-integrations)
   - [JK System Backoffice (BO Site) Integration Deep-Dive](#jk-system-backoffice-bo-site-integration-deep-dive)
   - [Two-Factor Authentication (2FA) Dual-Mode Framework](#two-factor-authentication-2fa-dual-mode-framework)
5. [Master Procedure Inventory (Step-by-Step Action Catalog)](#5-master-procedure-inventory-step-by-step-action-catalog)
   - [System Admin Platform (Procedures S1 – S7)](#system-admin-platform-procedures-s1--s7)
   - [Vendor Organization Platform (Procedures V1 – V13)](#vendor-organization-platform-procedures-v1--v13)
6. [Troubleshooting, Error Codes & Disaster Recovery](#6-troubleshooting-error-codes--disaster-recovery)
7. [Glossary & Business Calculation Invariants](#7-glossary--business-calculation-invariants)

---

## 1. Dual-Platform Architecture & Security Perimeter

The JK8 system is engineered as an enterprise dual-platform console:

```mermaid
graph TD
    Client(["Web Browser Client"]) --> Router{"URL Path Match"}
    
    Router -->|"/system*"| SysAuth{"Is Authenticated & isSysAdmin?"}
    SysAuth -->|No| SysLogin["SystemLogin.tsx"]
    SysAuth -->|Yes| SysShell["SystemShell.tsx (/system)"]
    
    Router -->|"/*"| VendorAuth{"Is Authenticated?"}
    VendorAuth -->|No: /owner-setup| OwnerSetup["OwnerSetup.tsx"]
    VendorAuth -->|No: /staff-setup/:code| StaffSetup["StaffSetup.tsx"]
    VendorAuth -->|No: Other| VendorLogin["Login.tsx (Supports 2FA Challenge)"]
    VendorAuth -->|Yes & Status=Suspended| LicBlocked["LicenseBlocked.tsx (402)"]
    VendorAuth -->|Yes & Status=Active| AppLayout["AppLayout.tsx (Vendor Platform)"]

    SysShell --> SysModules["Tenants · Plans · Email · Global Audits · System Admins"]
    AppLayout --> VendorModules["Brands · 7 Core Reports · Staff RBAC · Risk & Retention Settings"]
```

---

## 2. Complete Page Catalog (All 21 Surfaces)

### Platform 1: System Admin Pages (`/system`)

| Page ID | UI Component | Path / Route | Required Permission | Core Capabilities & Modals |
| :--- | :--- | :--- | :--- | :--- |
| `orgs` | `SystemOrgs.tsx` | `/system/orgs` | `sys:orgs:view` | Multi-tenant organization list, Create Organization modal, status toggle (Active/Suspended/Decommissioned). |
| `users` | `SystemUsers.tsx` | `/system/users` | `sys:users:view` | Global user directory, elevate/demote system admin status, disable user. |
| `invites` | `SystemInvites.tsx` | `/system/invites` | `sys:invites:view` | Issue owner initialization links (`/owner-setup?token=tok_...`), track invite state (Pending/Accepted/Expired). |
| `plans` | `SystemPlans.tsx` | `/system/plans` | Main Only | Tier pricing, allowed module checkboxes (`performance`, `members`, `method_fees`, etc.), user/brand limits. |
| `settings` | `SystemSettings.tsx` | `/system/settings` | Main Only | Outbound email carrier selector (`manual`, `smtp`, `resend`), Default Invite Host input, Send Test Email modal. |
| `emailTemplates`| `SystemEmailTemplates.tsx`| `/system/email-templates` | Main Only | WYSIWYG & HTML templates for staff invites, owner invites, 2FA OTPs, password reset emails. |
| `announcements` | `SystemAnnouncements.tsx` | `/system/announcements` | Main Only | Broadcast maintenance alerts, banner severity (`info`, `warning`, `critical`), scheduled display window. |
| `audit` | `SystemAudit.tsx` | `/system/audit` | `sys:audit:view` | Cross-organization immutable security event log, CSV export, IP address & actor search. |
| `admins` | `SystemAdmins.tsx` | `/system/admins` | Main Only | Bootstrap staff system-admins, configure delegated operator scopes. |
| `profile` | `SystemProfile.tsx` | `/system/profile` | Signed-in SysAdmin | Update admin password, bind TOTP Authenticator app (2FA). |

---

### Platform 2: Vendor Organization Pages (`/`)

| Page ID | UI Component | Path / Route | Required Permission | Core Capabilities & Modals |
| :--- | :--- | :--- | :--- | :--- |
| `performance` | `Performance.tsx` | `/` or `/performance` | `performance.view` | Executive overview, Net Cash Flow, Gross Deposit, Withdrawal, Margin %, GMT+8 Today Anchor, chart breakdowns. |
| `transactions`| `Transactions.tsx` | `/transactions` | `performance.view` | Detailed audit ledger, deposit/withdrawal/bonus filtering, gateway reconciliation, crypto txid verification. |
| `members` | `Members.tsx` | `/members` | `members.view` | Player directory, First-Time Deposit (FTD) conversion, DAU/WAU/MAU, VIP tier migration, Lifetime Value (LTV). |
| `memberTrends`| `Segments.tsx` | `/segments` | `memberTrends.view` | Recency bucket cohort drill-down (1–7D, 8–14D, 15–30D, Dormant), 1-click **Export Members (Excel)** for CRM. |
| `channels` | `Channels.tsx` | `/channels` | `channels.view` | Acquisition channel attribution, referrer codes, Cost Per Acquisition (CPA), Return On Ad Spend (ROAS). |
| `trends` | `Trends.tsx` | `/trends` | `trends.view` | Longitudinal historical trends (MoM / YoY), seasonal deposit/withdrawal volatility charts. |
| `compareBrands`| `CompareBrands.tsx`| `/compare-brands` | `compareBrands.view` | Side-by-side benchmarking of 2–3 brands (deposit volume, retention, gross margins). |
| `methodFees` | `MethodFees.tsx` | `/method-fees` | `methodFees:view` | Payment processor merchant deduction fee audit (USDT, credit cards, bank relays). |
| `gameProviders`| `GameProviders.tsx` | `/game-providers` | `gameProviders:view`| Game studio revenue shares, RTP (Return To Player) monitoring, provider split audit. |
| `admin` | `Admin.tsx` | `/admin` | `users.view` | **Management Tab Group**: Users (table, invite, reset pw), Roles (permission matrix), Audit, Brands. |
| `organizations`| `OrganizationsScreen.tsx`| `/organizations` | `orgs.view` | Multi-org tenant switching for authorized cross-org operators. |
| `profile` | `Profile.tsx` | `/profile` | Signed-in User | Personal preferences (Language EN/ZH, Theme Dark/Light, Default Brand), Password change, 2FA TOTP setup. |
| *Settings Panel*| `BrandSettingsPanel.tsx`| Modal from TopNav | `settings.edit` | Risk Thresholds (High/Mid %), Retention Days, Recency Buckets, Member Exclusions, Wildcard Rules. |
| *BO Credential* | `BrandActionModals.tsx` | Modal from TopNav | `users.view` | JK System BO credentials, Merchant ID, Staff Username & Password, 2FA Passcode, Test Connection. |

---

### Shared Authentication & Setup Screens

| Screen Name | UI Component | Path / Route | Description & Form Inputs |
| :--- | :--- | :--- | :--- |
| `Login` | `Login.tsx` | `/login` | Public vendor login with 2FA TOTP challenge support (Google / Microsoft Authenticator). |
| `SystemLogin` | `SystemLogin.tsx` | `/system/login` | Dedicated high-security entrance for system superadmins. |
| `OwnerSetup` | `OwnerSetup.tsx` | `/owner-setup` | Initial bootstrap flow for organization founder using secure one-time invite token. |
| `StaffSetup` | `StaffSetup.tsx` | `/staff-setup/:code` | Onboarding flow for invited staff using their cryptographic setup code. |
| `LicenseBlocked`| `LicenseBlocked.tsx` | Rendered on 402 | Automatic modal interceptor blocking UI when tenant license status is `suspended`. |

---

## 3. Complete Backend REST API Reference (36+ Endpoints)

### Authentication & 2FA (`/api/auth`)

| Method | Endpoint | Perm / Auth | Request Body / Params | Response Summary |
| :--- | :--- | :--- | :--- | :--- |
| `POST` | `/api/auth/login` | Public | `{ identifier, password }` | Authenticated session cookie OR `{ state: 'challenge', challenge: { challengeId, allowedMethods: ['totp'] } }` |
| `POST` | `/api/auth/2fa/verify` | Public | `{ challengeId, method: 'totp', code }` | Sets session cookie, returns `{ state: 'authenticated', user, permissions }` |
| `POST` | `/api/auth/2fa/totp/setup` | User | None | Returns `{ secret, qrCodeDataUrl }` for Authenticator app binding |
| `POST` | `/api/auth/2fa/totp/confirm` | User | `{ code }` | Validates code, activates TOTP on user record |
| `POST` | `/api/auth/2fa/disable` | User | `{ password, code }` | Deactivates 2FA on account |
| `GET` | `/api/auth/me` | Session | None | Returns `{ state: 'authenticated', session: { user, permissions, allowed_brands } }` |
| `POST` | `/api/auth/logout` | Session | None | Clears HTTP-only session cookies |
| `POST` | `/api/auth/owner-setup` | Public | `{ token, password, confirmPassword }` | Bootstraps owner account, creates root organization credentials |
| `POST` | `/api/auth/staff-setup` | Public | `{ code, password }` | Activates invited staff account, sets password |

---

### System Administration (`/api/system-admin`)

| Method | Endpoint | Perm / Auth | Request Body / Params | Response Summary |
| :--- | :--- | :--- | :--- | :--- |
| `GET` | `/api/system-admin/organizations` | `sys:orgs:view` | Query: `?search=&status=&page=` | Paginated organization list with brand & user counts |
| `POST` | `/api/system-admin/organizations` | `sys:orgs:edit` | `{ name, slug, planId }` | Returns created organization object |
| `PATCH`| `/api/system-admin/organizations/:id` | `sys:orgs:edit` | `{ name?, planId?, status?: 'active'\|'suspended' }` | Updates tenant status; invalidates tenant sessions on suspension |
| `GET` | `/api/system-admin/users` | `sys:users:view` | Query: `?orgId=&search=` | Global user accounts across all tenant organizations |
| `PATCH`| `/api/system-admin/users/:id/role` | `sys:users:edit` | `{ isSysAdmin: boolean }` | Elevates or revokes system administrator authority |
| `GET` | `/api/system-admin/invites` | `sys:invites:view`| Query: `?status=` | System owner onboarding invites |
| `POST` | `/api/system-admin/invites` | `sys:invites:edit`| `{ organizationId, email }` | Generates token, dispatches invite or returns URL |
| `GET` | `/api/system-admin/plans` | `sys:plans:view` | None | Subscription tiers with module arrays and limits |
| `PATCH`| `/api/system-admin/plans/:id` | `sys:plans:edit` | `{ allowedModules: string[], maxUsers, maxBrands }` | Updates feature gating matrix |
| `GET` | `/api/system-admin/settings` | `sys:settings` | None | `{ 'email.provider', 'invite.default_host', ... }` |
| `PUT` | `/api/system-admin/settings` | `sys:settings` | `{ key, value }` | Persists system configuration item |
| `POST` | `/api/system-admin/settings/test-email`| `sys:settings`| `{ to, subject, body }` | Dispatches test email; verifies SMTP/Resend credentials |
| `GET` | `/api/system-admin/announcements`| `sys:announcements`| None | All active and scheduled platform broadcast banners |
| `POST` | `/api/system-admin/announcements`| `sys:announcements`| `{ title, htmlBody, tone, startsAt, expiresAt }` | Publishes instant announcement event |
| `GET` | `/api/system-admin/audit` | `sys:audit:view` | Query: `?actor=&action=&from=&to=` | Forensic system-level immutable audit records |

---

### Brand & BO Integration (`/api/brands`)

| Method | Endpoint | Perm / Auth | Request Body / Params | Response Summary |
| :--- | :--- | :--- | :--- | :--- |
| `GET` | `/api/brands` | Scoped Org | None | Returns all brands accessible to the authenticated user |
| `POST` | `/api/brands` | `users.view` | `{ name, brandKey }` | Creates new operating brand under active organization |
| `PATCH`| `/api/brands/:id` | `users.view` | `{ name, brandKey }` | Renames brand or updates identifier |
| `GET` | `/api/brands/:id/bo-credential` | `users.view` | None | Returns `{ merchantId, hasCredentials: true, boEnabled }` (Secrets omitted) |
| `PUT` | `/api/brands/:id/bo-credential` | `users.view` | `{ merchantId, username, password, passcode2fa, boEnabled }` | Encrypts & stores BO credentials, sets sync state |
| `POST` | `/api/brands/:id/bo-credential/test`| `users.view` | `{ draft?: BoCredDraft }` | Performs live handshake with JK BO API; returns `{ ok: true, message }` |
| `POST` | `/api/brands/:id/backfill` | `users.view` | `{ startDate: 'YYYY-MM-DD', endDate: 'YYYY-MM-DD' }` | Enqueues background ingestion job for historical records |
| `POST` | `/api/brands/:id/purge` | `users.view` | `{ confirmPassword }` | Purges staging/test transaction and customer records |
| `GET` | `/api/brands/:id/sync-status` | `performance.view` | None | Returns `{ status: 'idle'\|'syncing'\|'error', lastSyncAt, error }` |

---

### Analytical Reports (`/api/reports`)

| Method | Endpoint | Perm / Auth | Request Body / Params | Response Summary |
| :--- | :--- | :--- | :--- | :--- |
| `GET` | `/api/reports/performance` | `performance.view` | Query: `?brandId=&from=&to=` | KPIs: Net Cash Flow, Deposit, Withdraw, Margin %, Chart Series |
| `GET` | `/api/reports/members` | `members.view` | Query: `?brandId=&from=&to=` | FTD metrics, active player counts, VIP tier movements |
| `GET` | `/api/reports/member-trends` | `memberTrends.view`| Query: `?brandId=&from=&to=` | Recency bucket cohorts (1–7D, 8–14D, 15–30D, Dormant) |
| `GET` | `/api/reports/channels` | `channels.view` | Query: `?brandId=&from=&to=` | Referrer code attribution, CPA, ROAS, channel ROI |
| `GET` | `/api/reports/compare-brands` | `compareBrands.view`| Query: `?brandIds=b1,b2,b3&from=&to=` | Side-by-side comparative metric series |

---

### Transactions & Ledger (`/api/transactions`)

| Method | Endpoint | Perm / Auth | Request Body / Params | Response Summary |
| :--- | :--- | :--- | :--- | :--- |
| `GET` | `/api/transactions` | `performance.view` | Query: `?brandId=&search=&type=&status=&from=&to=&page=` | Granular deposit/withdrawal transaction records |
| `GET` | `/api/transactions/:id` | `performance.view` | Param: `id` | Single transaction detail with payment method payload |

---

### Members & Cohorts (`/api/members`)

| Method | Endpoint | Perm / Auth | Request Body / Params | Response Summary |
| :--- | :--- | :--- | :--- | :--- |
| `GET` | `/api/members` | `members.view` | Query: `?brandId=&search=&segment=&tier=&page=` | Player profiles, LTV, total deposits, first/last activity |
| `GET` | `/api/members/:id` | `members.view` | Param: `id` | Comprehensive player profile, deposit history, risk score |

---

### Data Export (`/api/export`)

| Method | Endpoint | Perm / Auth | Request Body / Params | Response Summary |
| :--- | :--- | :--- | :--- | :--- |
| `POST` | `/api/export/members` | `members.export` | `{ brandId, segment, format: 'xlsx'\|'csv' }` | Generates downloadable Excel workbook of player CRM list |
| `POST` | `/api/export/transactions` | `performance.view` | `{ brandId, from, to, format: 'xlsx'\|'csv' }` | Generates wide transaction ledger file |
| `POST` | `/api/export/audit` | `users.view` | `{ format: 'csv' }` | Exports organization audit trail |

---

### Cost Analysis: Method Fees & Game Providers

| Method | Endpoint | Perm / Auth | Request Body / Params | Response Summary |
| :--- | :--- | :--- | :--- | :--- |
| `GET` | `/api/method-fees` | `methodFees:view` | Query: `?brandId=&from=&to=` | Merchant deduction fees per gateway (USDT, relay, etc.) |
| `POST` | `/api/method-fees/config` | `settings.edit` | `{ brandId, rates: [{ method, percentageFee, fixedFee }] }` | Updates fee calculation schedules |
| `GET` | `/api/game-providers` | `gameProviders:view` | Query: `?brandId=&from=&to=` | Game studio revenue share splits, bet volume, RTP |

---

### Team Management & Staff Invites

| Method | Endpoint | Perm / Auth | Request Body / Params | Response Summary |
| :--- | :--- | :--- | :--- | :--- |
| `GET` | `/api/organizations/:orgId/invites` | `users.view` | None | Active staff invitations for the organization |
| `POST` | `/api/organizations/:orgId/invites` | `users.view` | `{ email, roleId, allowedBrands: string[] }` | Generates staff setup code and invite link |
| `DELETE`| `/api/organizations/:orgId/invites/:id` | `users.view`| None | Revokes pending staff invitation |
| `POST` | `/api/organizations/:orgId/invites/:id/resend`| `users.view`| None | Re-dispatches invite email or re-generates link |
| `GET` | `/api/users` | `users.view` | Query: `?brandId=` | Active organization staff members |
| `PATCH`| `/api/users/:id` | `users.view` | `{ roleId, status: 'active'\|'disabled', allowedBrands }` | Updates member permissions or locks account |
| `POST` | `/api/users/:id/reset-password` | `users.view` | None | Triggers password reset email |
| `GET` | `/api/roles` | `users.view` | None | Role definitions and assigned permission lists |
| `POST` | `/api/roles` | `users.view` | `{ name, permissions: string[] }` | Creates custom organizational role |

---

### Brand Operational Settings

| Method | Endpoint | Perm / Auth | Request Body / Params | Response Summary |
| :--- | :--- | :--- | :--- | :--- |
| `GET` | `/api/settings/:brandId` | `settings.view` | None | `{ riskThresholds, retentionSettings, recencyBuckets, excludedIds, excludeRules, channels }` |
| `PUT` | `/api/settings/:brandId` | `settings.edit` | Full settings payload | Persists brand parameters; recalculates risk chips |

---

## 4. Critical Technical Integrations

### JK System Backoffice (BO Site) Integration Deep-Dive

Connecting an operational gaming brand to live ingestion requires credentials from the **JK System Backoffice**:

```mermaid
sequenceDiagram
    autonumber
    actor Admin as Vendor Org Admin
    participant BO as JK System BO Site
    participant Support as JK Support Team
    participant JK8 as JK8 Analytics (/brands/:id/bo-credential)
    participant Worker as Background Ingest Worker

    Note over Admin,Support: Credential Acquisition Phase
    Admin->>Support: Request Merchant ID & Static 2FA Passcode
    Support-->>Admin: Issues Merchant ID (e.g. 60706) & 2FA PIN (e.g. 849201)
    Admin->>BO: Log in to BO Site > Navigate to "Manage Staff"
    Admin->>BO: Create New Dedicated Staff User (e.g. "jk_sync_operator")
    BO-->>Admin: Generates Username & Staff Password

    Note over Admin,JK8: Configuration & Validation Phase
    Admin->>JK8: Open TopNav > Brand Switcher > BO Credentials Modal
    Admin->>JK8: Key in Merchant ID, Staff Username, Staff Password, 2FA Passcode
    Admin->>JK8: Check "boEnabled: True"
    Admin->>JK8: Press "Test Connection" Button
    JK8->>BO: Encrypted Pre-flight Handshake
    BO-->>JK8: Authentication Confirmed (HTTP 200 OK)
    JK8-->>Admin: Toast: "JK BO API Connection Verified"
    Admin->>JK8: Press "Save" Button
    JK8-->>Admin: TopNav Status changes to "LIVE SYNC: HEALTHY"

    Note over JK8,Worker: Ingestion Phase
    Admin->>JK8: Open "Backfill" Modal > Select Date Range > Start
    JK8->>Worker: Enqueue Backfill Job
    Worker->>BO: Pull Historical Transactions & Member Snapshots
    Worker->>JK8: Upsert Records into SQLite/Postgres
```

#### Credential Checklist:
1. **Merchant ID**: Assigned by JK Technical Support. Must match your upstream tenant profile.
2. **2FA Passcode**: Static PIN generated by Support specifically for headless API ingestion.
3. **Staff Account**: Must be created in the BO Site's **Manage Staff** module. **Never reuse a personal human manager login**, as session collisions will invalidate ingestion tokens.

---

### Two-Factor Authentication (2FA) Framework

The system provides two distinct two-factor authentication mechanisms:

```
┌────────────────────────────────────────────────────────────────────────┐
│                   JK8 TWO-FACTOR AUTHENTICATION MODES                  │
├───────────────────────────────────┬────────────────────────────────────┤
│ MODE 1: USER ACCOUNT 2FA (TOTP)   │ MODE 2: BO INTEGRATION 2FA (API)   │
│ • Standard Authenticator App TOTP │ • Static 6-digit PIN from Support  │
│ • Authenticator app (Google, MS)  │ • Stored encrypted with BO creds   │
│ • Disabled by default for users   │ • Authorizes background workers    │
│ • Enabled in /profile after login │ • Validated via "Test Connection"  │
└───────────────────────────────────┴────────────────────────────────────┘
```

#### User Login 2FA (TOTP Only) Activation & Challenge Flow:
1. **Initial Account State**: TOTP is **disabled by default** when an account is created.
2. **First Login**: Users log in using their username/email and password at `/login`. No 2FA prompt is displayed.
3. **Activation in Profile**:
   - User navigates to `/profile` (or `/system/profile`).
   - Under the **Two-factor authentication (TOTP)** card, click **[Enable TOTP]** to initiate enrollment.
   - Server returns the secret string and QR code with a 15-minute setup countdown timer (`Setup expires in M:SS`).
   - User scans the QR code into **Google Authenticator**, **Microsoft Authenticator**, or **1Password** (or enters the secret key manually).
   - User types the current 6-digit rolling code into the **Authenticator code** input and clicks **[Verify and enable]**.
   - System confirms activation and displays one-time emergency recovery codes with **[Copy]** and **[Download]** (`totp-recovery-codes.txt`) buttons.
4. **Subsequent Logins**:
   - User inputs username and password at `/login` or `/system/login`.
   - Backend verifies password and returns a 2FA challenge.
   - User opens their Authenticator app, keys in the 6-digit code, and submits to enter the dashboard.

---

## 5. Master Procedure Inventory (Step-by-Step Action Catalog)

### System Admin Platform (Procedures S1 – S7)

#### S1: Create a New Tenant Organization & Configure Sub-panels
1. **Target**: `/system > Directory > Organizations` (`OrganizationsScreen.tsx`)
2. **Action 1 (Create Organization)**: In the top card form, input **Organization Name** (e.g. `Organization 1`), **Organization Slug** (e.g. `org-1`), and optional **Email host override** (e.g. `tenant.example.com`, bare host only). Click `[+ Add]`. Toast: *"Organization created"*.
3. **Action 2 (Assign Subscription)**: In the table row, click `[Subscription]` to open the sub-panel below. Select **Plan** from dropdown (e.g. `Enterprise Tier`), set **Expires at** calendar date, and click `[Save subscription]`. Toast: *"Subscription updated"*.
4. **Action 3 (Assign Root Owner)**: In the table row, click `[Org Members]` to open the members sub-panel. Input executive **Email**, optional **New password**, select **Role** as `Owner`, check **All brands (*)**, and click `[Invite Member]`. Toast: *"Member assigned"*.
5. **Action 4 (Attach Brands & Domain)**: In the table row, click `[Brands]` to attach initial brands (`Brand Key`, `Name`, click `[+ Add]`). Click `[Email host]` to configure tenant custom domain override (e.g. `app.organization.com`).

#### S2: Configure Plans & Feature Gating
1. **Target**: `/system > Operations > Plans` (`SystemPlans.tsx`)
2. **Action 1**: Select target tier or input **Name**, **Description**, **Max Brands** (0 = unlimited), and **Max Users** (0 = unlimited).
3. **Action 2**: Use `Select all` / `Deselect all` or toggle module checkboxes: `performance`, `members`, `transactions`, `channels`, `trends`, `game_providers`, `method_fees`, `compare_brands`, `export`.
4. **Action 3**: Click `[Create plan]` or `[Update plan]`. Toast: *"Plan created"* / *"Plan updated"*.

#### S3: Manage Organization Lifecycle & License Suspension (402 Shield)
1. **Target**: `/system > Directory > Organizations` (`OrganizationsScreen.tsx`)
2. **Action 1**: Locate organization in table. Check current status chip (`active` in green).
3. **Action 2**: Under Actions column, click the red `[Remove]` button (`common.remove`). System updates status to `disabled` (gray).
4. **Action 3**: Connected vendor sessions immediately receive HTTP 402 on their next API request, which triggers `auth:license-blocked` and renders the full-screen `LicenseBlocked.tsx` shield (*"License Suspended — Please contact your system administrator"*).

#### S4: Issue Owner Setup Invitation
1. **Target**: `/system > Directory > Invitations` (`SystemInvites.tsx`)
2. **Action 1**: Click `[+ New Invitation]`.
3. **Action 2**: Select target organization; enter executive email address (e.g. `owner@organization.com`).
4. **Action 3**: Click `[Generate Invite Token]`. Deliver the secure onboarding link: `https://analytics.jk8.io/owner-setup?token=tok_...`.

#### S5: Configure Email Provider & Default Invite Host
1. **Target**: `/system > Operations > Settings` (`SystemSettings.tsx`)
2. **Action 1**: Under **Default invite host**, enter web domain (e.g. `app.example.com`, bare host only, HTTPS is added automatically). Click `Save`.
3. **Action 2**: Under **Provider**, select `manual`, `smtp`, or `resend`.
   - For SMTP: Enter `Host`, `Port`, `Username`, `Password`, `From address`.
   - For Resend: Enter `API key` and `From address` (must use a verified custom domain on resend.com/domains; public domains like gmail/yahoo are rejected with a warning).
4. **Action 3**: Click `[Send test email]`. Modal opens with `Recipient` (defaults to login email), `Subject`, `Body`. Click `[Send test email]` to confirm deliverability before saving.

#### S6: Publish System Announcements
1. **Target**: `/system > Operations > Announcements` (`SystemAnnouncements.tsx`)
2. **Action 1**: Click `[+ New Announcement]`.
3. **Action 2**: Input **Title**, sanitized **HTML Body**, rotation **Interval (seconds)** (3–120s, default 5s), and toggle DM logo display.
4. **Action 3**: Toggle status to **Enabled** and click `[Save Announcement]`. Live carousel broadcasts across all vendor dashboards and `/login`.

#### S7: Audit Global Administrative Operations
1. **Target**: `/system > Security > Audit Log` (`SystemAudit.tsx`, requires `sys:audit:view`)
2. **Action 1**: Filter by Action Resource (`Brand`, `Role`, `User`, `Invite`), specific action type, actor email, or date range.
3. **Action 2**: Click any log row to open `AuditDetailModal` with GMT+8 timestamp, actor IP address, and JSON metadata diff.
4. **Action 3**: Click `[Export CSV]` for compliance and forensic record-keeping.

---

### Vendor Organization Platform (Procedures V1 – V13)

#### V1: Create & Switch Operating Brands (Brand Lifecycle)
1. **Target**: `TopNav > Brand Switcher` (`BrandSwitcher.tsx`)
2. **Action 1 (Switching)**: Click current brand name in TopNav. Dropdown opens showing all assigned brands with initial badge. Click target brand radio button to switch context instantly with top progress bar.
3. **Action 2 (Default Brand)**: Click `Set as default brand` with star icon at the bottom of the switcher to persist preference on future logins.
4. **Action 3 (Creating Brand)**: Click `+ Add New Brand` at the bottom of the switcher, which deep-links to `/admin` -> `Brands` tab.
5. **Action 4**: In `Brands` tab, click `+ New Brand` to open modal: enter `Brand Key` (e.g. `brand-1`) and `Display Name` (e.g. `Brand 1`), and click `[Create Brand]`.

#### V2: Configure BO Site Integration (JK System)
1. **Target**: `TopNav > Brand Switcher > Gear Icon > [BO Credentials]` (`BoCredentialModal`)
2. **Action 1**: Input Numeric **Merchant ID** (e.g. `60706`) provided by the JK Technical Support Team.
3. **Action 2**: Check `[x] Enable BO integration` (`boEnabled`).
4. **Action 3**: Input **Admin Username** and **Admin Password** (with Show/Hide toggle) created via the BO Site's **Manage Staff** page. *(Never reuse personal human logins)*.
5. **Action 4**: Input **2FA Passcode** (Static 2FA PIN, e.g. `849201`) provided by the JK Technical Support Team.
6. **Action 5**: Press `[Test Connection]` to perform an encrypted pre-flight handshake. Verify green toast: *"Connection verified"*.
7. **Action 6**: Press `[Save]`. Toast: *"BO credentials saved"*.

#### V2-B: Two-Factor Authentication (TOTP Authenticator App)
1. **Target**: `Sidebar > Profile` (`/profile`, `Profile.tsx`)
2. **Initial State**: User logs in with password at `/login`. In Profile, status is `Status: Disabled` ("Scan the QR code with an authenticator app, then enter the 6-digit code it generates to finish enrolling.").
3. **Step 1 (Enable TOTP)**: Click `[Enable TOTP]`. The system initiates a 10-minute setup window (`Setup expires in 10:00`), generates a 256x256 QR code, and displays the secret key (`Setup key (manual entry): <secret>`).
4. **Step 2 (Scan Code)**: Open an authenticator app (Google Authenticator, Microsoft Authenticator, 1Password) and scan the QR code (or enter the secret key manually).
5. **Step 3 (Key in 6 Numbers & Verify)**: Enter the 6-digit numeric code from the authenticator app into `Authenticator code` (`Enter 6-digit code from your app`) and click `[Verify and enable]`. System confirms with toast: *"2FA enabled"*.
6. **Step 4 (Backup Recovery Codes)**: System displays 10 emergency single-use recovery codes ("Save your recovery codes now. Each code can be used once."). Click `[Copy]` or `[Download]` to store them securely.
7. **Step 5 (Password-Protected Authorization)**: When enabled, status updates to `Status: Enabled · Recovery codes remaining: 10`. To disable 2FA or regenerate recovery codes, entering the account's **Current password** is strictly required to authorize the action before pressing `[Regenerate recovery codes]` or `[Disable 2FA]`.
8. **Login Verification**: On future logins at `/login`, entering username and password triggers the 2FA challenge. Enter the 6-digit authenticator code or a backup recovery code and click `[Verify and sign in]`.

#### V3: Invite Staff Members & Manage Users
1. **Target**: `Sidebar > Management > Users` (`/admin`, `Admin.tsx`)
2. **Method A (Direct Creation)**: Click `+ New User` -> modal: enter `Email`, `Password` (≥8 chars), `Status: active`, select `Role` (owner/marketer/custom), set `Brand Access` (`All brands` or `Restricted` with clickable chips), and click `[Save]`.
3. **Method B (Staff Invite Link)**: In the "Staff Invites" card below the table, click `+ Invite`. Modal opens: enter optional `Target email`, select `Role` (`staff` | `marketer`), set `Expires in days` (1–30, default 7), choose `Brand Access` (`All brands` | `Restricted`), and click `[Create invite]`. Link is automatically copied to clipboard.
4. **Action 3**: Staff member visits `https://analytics.jk8.io/staff-setup/<code>`, sets their password, and logs into the workspace.

#### V4: Manage Roles & RBAC Matrix
1. **Target**: `Sidebar > Management > Roles` (`/admin`, `Admin.tsx`)
2. **Action 1**: Review system Owner role and custom roles. Click `+ New Role` -> modal: enter `Name`, `Key`, and select permissions. Click `[Save]`.
3. **Action 2**: Inspect the Permission Matrix table below, grouped by category (performance, members, transactions, channels, methodFees, gameProviders, settings, users).

#### V5: Study & Interpret Executive Performance KPIs
1. **Target**: `Sidebar > Performance` (`/`, `Performance.tsx`)
2. **Action 1**: Confirm GMT+8 date range anchor (`Today`, `Yesterday`, `7D`, `30D`, or custom).
3. **Action 2**: Read KPI cards:
   - `Net Cash Flow`: `Gross Deposits + Gross Withdrawals` (withdrawals stored as negative).
   - `Gross Deposits`: Approved incoming player funds.
   - `Withdrawals`: Approved player cashouts.
   - `Margin %`: `Net Cash Flow ÷ Gross Deposits`.
4. **Action 3**: Check Risk Tier badge: `PROFIT` (<0%), `NORMAL` (0–50%), `MID RISK` (50–75%), `HIGH RISK` (≥75%).
5. **Action 4**: Inspect hourly cash flow bar chart and payment gateway volume distribution.

#### V6: Audit Transactions & Gateway Reconciliation
1. **Target**: `Sidebar > Transactions` (`Transactions.tsx`)
2. **Action 1**: Search transactions by player username, transaction ID, or crypto txid.
3. **Action 2**: Filter by Type (`Deposit`, `Withdrawal`, `Adjustment`) and payment method.
4. **Action 3**: Verify settlement status chips (`Completed`, `Pending`, `Rejected`) against external gateway statements.

#### V7: Analyze Player Lifecycle, FTD & VIP Tiers
1. **Target**: `Sidebar > Members` (`Members.tsx`)
2. **Action 1**: Monitor First-Time Deposit (FTD) conversion rates and active ratios (DAU/WAU/MAU).
3. **Action 2**: Click player username to open detailed Player Dossier modal showing lifetime deposits, net cash flow, VIP tier migration, and risk score.

#### V8: Target Behavioral Segments & Export CRM Lists
1. **Target**: `Sidebar > Segments` (`Segments.tsx`, internal id `memberTrends`)
2. **Action 1**: Review 4 recency bucket cohort cards: `Active (1–7 Days)`, `Slipping (8–14 Days)`, `Dormant (15–30 Days)`, `Churned (>30 Days)`.
3. **Action 2**: Click target cohort card to drill down into player list modal.
4. **Action 3**: Click `[Export Members (Excel)]` to download `.xlsx` workbook for CRM/SMS outreach.

#### V9: Evaluate Marketing Channels, CPA & Affiliate ROI
1. **Target**: `Sidebar > Channels` (`Channels.tsx`)
2. **Action 1**: Review acquisition channel attribution mapping (exact IDs or prefix match patterns).
3. **Action 2**: Compare player acquisition volume, gross deposit total, and bonus expenditure.
4. **Action 3**: Evaluate Channel Efficiency Ratio (`Net Cash Flow ÷ Bonus Given`) to optimize ad spend.

#### V10: Game Provider Data Sync & Revenue Share Fee % Setup
1. **Target**: `Sidebar > Cost Analysis > Game Providers` (`/game-providers`, `GameProvidersSection.tsx`)
2. **Pre-requirements**: `game_providers` subscription module, `gameProviders:edit` permission, active BO credentials with `boEnabled: true`.
3. **Step 1 (Sync from BO)**: In the **Sync from BO** panel, select period type (`Monthly`, `Weekly`, `Daily`), pick `sDate` and `eDate`, and click `[Sync from BO]`. System connects to BO `/reports/siteTransaction` API, pulls deposits, withdrawals, and net totals, auto-discovers newly added wallet keys, and displays toast: *"Synced X rows (Y new wallet keys discovered)"*.
4. **Step 2 (Set Revenue Share %)**: In the **Game Provider Settings** table, locate target wallet key (e.g. `PG`), enter contractual fee in the `Revenue Share %` column (e.g. `12.5`, valid range `0`–`100`), ensure `Active` checkbox is checked, and click inline `[Save]` button.
5. **Step 3 (Summary Recalculation)**: Summary tables recalculate provider fee deductions: $\text{Provider Fee} = \text{Net Total} \times (\text{Revenue Share \%} \div 100)$.

#### V11: Multi-Brand Benchmarking
1. **Target**: `Sidebar > Compare Brands` (`CompareBrands.tsx`)
2. **Action 1**: In top filter, select 2 or 3 operating brands from your organization.
3. **Action 2**: Pick date range (Today, 7D, 30D, custom).
4. **Action 3**: Benchmark cash flow, player velocity, and profit margins side-by-side on comparative charts.

#### V12: Adjust Brand Risk Thresholds, Retention & Recency Buckets
1. **Target**: `TopNav > Brand Switcher > Gear Icon > [Brand Settings]` (`BrandSettingsPanel.tsx`)
2. **Action 1 (Brand Identity)**: Edit `Brand Display Name` and `Brand Key`. Click `[Save Brand]`.
3. **Action 2 (Risk Thresholds)**: Set `High Risk %` (e.g. `75%`) and `Mid Risk %` (e.g. `50%`). (High must be > Mid; High ≤ 100%). Check live preview chips: High ≥75%, Mid 50–75%, Normal 0–50%, Profit <0%. Click `[Save Risk]`.
4. **Action 3 (Retention Settings)**: Set `Threshold` (e.g. `30`), `Unit` (`Days`/`Weeks`/`Months`), `Basis` (`Last Visit Date`/`Last Deposit Date`), `Denominator` (`Known Members`/`All Members`). Click `[Save Retention]`.
5. **Action 4 (Recency Buckets)**: Set `Bucket 1`, `Bucket 2`, `Bucket 3` in days (e.g. `7, 14, 30`; values must strictly increase). Preview chips show: `≤7d`, `8-14d`, `15-30d`, `>30d`. Click `[Save Recency]`.

#### V13: Filter Test Accounts with Member Exclusions & Wildcards
1. **Target**: `TopNav > Brand Switcher > Brand Settings > Exclusions` (`BrandSettingsPanel.tsx`)
2. **Action 1 (Manual Exclusions)**: Enter individual player IDs to exclude in the input (e.g. `test_user_01`), press Enter or click `[+ Add]`. Tags appear with remove `✕` buttons. Click `[Clear All]` if needed.
3. **Action 2 (Auto-Apply Rules)**: Enter comma-separated wildcard patterns (auto-saves on blur):
   - `Name contains`: `test, demo, qa`
   - `Referrer contains`: `internal, staging`
   - `Phone contains`: `000000, 999999`
   - `Exact user IDs`: `uid1, uid2`
4. **Action 3**: All matching accounts are instantly stripped from Performance totals, Member tables, Segments, and Excel exports.

---

## 6. Troubleshooting, Error Codes & Disaster Recovery

| Error Code / Symptom | Root Cause | Exact Resolution Procedure |
| :--- | :--- | :--- |
| `EMAIL_HOST_NOT_CONFIGURED` | Missing invite host domain | Go to `/system/settings`. Set **Default Invite Host** to your web address (e.g. `analytics.jk8.io`). |
| `LICENSE_SUSPENDED` (402) | Tenant disabled by superadmin | Superadmin must visit `/system/orgs` and toggle organization status back to **Active**. |
| `BO_API_AUTH_FAILED` | Bad Merchant ID, staff password, or 2FA | 1. Confirm Merchant ID & 2FA PIN with Support. 2. Verify account exists in BO Site > **Manage Staff**. |
| `Numbers Look Wrong` | Wrong brand, date range, or sync queue | 1. Check active brand. 2. Verify GMT+8 date range. 3. Check `GlobalSyncStatus` to ensure backfill is idle. |
| `HIGH_RISK_ALERT` | Win/Loss exceeds cutoff | Inspect game bets in Transactions; notify fraud prevention to check for bot arbitrage. |

---

## 7. Glossary & Business Calculation Invariants

- **Net Cash Flow (净现金流)**: `Gross Deposits + Gross Withdrawals` *(Note: Withdrawals are stored as negative numbers)*.
- **Platform Margin / Risk (亏损盈利率)**: `Net Cash Flow ÷ Gross Deposits`.
  - Margin ≥ 75%: **HIGH RISK** (Operator suffering extreme losses).
  - 50% ≤ Margin < 75%: **MID RISK**.
  - 0% ≤ Margin < 50%: **NORMAL RISK**.
  - Margin < 0%: **PROFIT** (Operator in net win position).
- **First-Time Deposit (FTD 首充)**: Earliest verified real-money deposit event associated with a registered member account.
- **Channel Efficiency Ratio (渠道效率比)**: `Net Cash Flow ÷ Bonus Given`.
- **Today Anchor**: Backend accounting cutoff synchronized to **GMT+8 (Asia/Shanghai / Asia/Singapore)**.
