{
  "shell": {
    "title": "Integration API",
    "admin": "Admin"
  },
  "nav": {
    "overview": "Overview",
    "api": "API",
    "ship": "Ship",
    "home": "Overview",
    "quickstart": "Quickstart",
    "fundamentals": "Money model",
    "setup": "Setup",
    "sso": "SSO",
    "iframe": "iframe protocol",
    "wallet": "Wallet gateway",
    "transfer": "Transfers (ref)",
    "errors": "Errors",
    "golive": "Go-live"
  },
  "headers": {
    "component": ["Component", "Role", "Owner"],
    "convention": ["Item", "Rule"],
    "claim": ["Claim", "Type", "Req", "Note"],
    "param": ["Parameter", "Purpose"],
    "methodPath": ["Method", "Path", ""],
    "query": ["Query", "Type", ""],
    "field": ["Field", "Type", "Note"],
    "code": ["Code", "Message"],
    "http": ["Status", "message", "Cause"],
    "message": ["Dir", "type", "Payload"],
    "balance": ["Field", "Account", "Note"],
    "call": ["Direction", "API", "Auth"],
    "sequence": ["Step", "Actor", "Action"],
    "envMap": ["Item", "Admin site", "Main-site .env", "Note"],
    "account": ["User", "Password", "site_player_id"],
    "contract": ["Scenario", "HTTP", "Body"],
    "adminField": ["Field", "Note", "Example"]
  },
  "pages": {
    "overview": {
      "title": "Integration",
      "description": "Main-site SSO + wallet gateway. Identity via JWT; funds split between main wallet and in-lottery balance.",
      "roles": "Roles",
      "flow": "Flow",
      "e2eSequence": "End-to-end sequence",
      "conventions": "Conventions",
      "readingOrder": "Reading order",
      "matrix": [
        ["Main site", "Issue JWT; implement wallet gateway", "Partner"],
        ["Lottery API", "Verify JWT, play, transfers, bets", "Us"],
        ["Lottery H5", "H5 / iframe shell", "Us"]
      ],
      "flowItems": [
        "Main-site login → issue JWT",
        "Enter lottery (URL or iframe)",
        "transfer-in → debit main + credit lottery",
        "Bet / settle (lottery balance)",
        "transfer-out → debit lottery + credit main"
      ],
      "e2eRows": [
        ["1", "Main site", "User logs in; server signs JWT"],
        ["2", "Main site", "Embed lottery H5 in iframe, or redirect ?token="],
        ["3", "Lottery H5", "Receives token; calls GET /api/v1/player/me"],
        ["4", "Player", "Taps transfer-in inside lottery H5"],
        ["5", "Lottery API", "Server calls POST /wallet/debit-for-lottery"],
        ["6", "Partner wallet", "Debits main_balance; returns success"],
        ["7", "Lottery API", "Credits in-lottery balance"],
        ["8", "Player", "Bets / settles in H5"],
        ["9", "Player", "(optional) transfer-out in H5"],
        ["10", "Lottery API", "Calls POST /wallet/credit-from-lottery"]
      ],
      "conventionRows": [
        ["Amount", "Minor units (integer), e.g. 2000 = 20.00"],
        ["Encoding", "UTF-8 JSON"],
        ["Time", "JWT: Unix seconds (iat / exp)"],
        ["Auth", "Player API: Bearer JWT; gateway: Bearer wallet_api_key"]
      ],
      "readingItems": ["Quickstart → Setup → SSO → iframe protocol → Wallet → Errors → Go-live"]
    },
    "quickstart": {
      "title": "Quickstart",
      "description": "Local integration guide. The main-site/ package in the repo is a runnable reference; secrets must match the admin integration site or lottery .env.",
      "prereq": "Prerequisites",
      "steps": "Integration steps",
      "testAccounts": "Test accounts (main-site)",
      "reference": "Reference implementation",
      "note": "Production requires HTTPS and isolated site_code/secrets. Without wallet_api_url locally, lottery API may stub main-site debits (non-production only).",
      "prereqItems": [
        "Lottery API (lotterLaravel) and lottery H5 (lotteryfront) running",
        "main-site running (default http://localhost:5173)",
        "Integration site created in admin, or lottery .env MAIN_SITE_* aligned with main-site .env"
      ],
      "stepItems": [
        "Super admin creates integration site in admin (see Setup) and saves secrets",
        "Copy secrets to main-site .env; set wallet_api_url and iframe_allowed_origins in admin",
        "Log in on main-site → open lottery H5 in iframe (/player)",
        "On LOTTERY_READY, send MAIN_INIT_TOKEN",
        "Transfer-in inside lottery H5 → observe /wallet/debit-for-lottery callback",
        "Place a bet in H5 after balance increases",
        "(optional) transfer-out in H5 → observe /wallet/credit-from-lottery",
        "Run acceptance curl checks for JWT and wallet gateway"
      ],
      "accountRows": [
        ["alice", "alice123", "10001"],
        ["bob", "bob123", "10002"],
        ["demo", "demo123", "10003"]
      ],
      "referenceItems": [
        "Code: main-site/ in the monorepo (Next.js test shell)",
        "Main site: http://localhost:5173; lottery H5: http://localhost:3800",
        "See main-site README for env vars and postMessage protocol",
        "Config mapping table on the Setup page"
      ],
      "acceptance": "Acceptance checklist",
      "acceptanceItems": [
        "Sign JWT → curl GET /api/v1/player/me returns code=0",
        "Self-test wallet debit: success:true and correct main_balance",
        "Replay same idempotent_key: identical response, no double debit",
        "iframe: after LOTTERY_READY receive MAIN_INIT_TOKEN and enter hall",
        "H5 transfer-in: partner gateway logs show debit-for-lottery"
      ]
    },
    "fundamentals": {
      "title": "Money model",
      "balances": "Two balances",
      "calls": "Call directions",
      "note": "All amounts use minor integers. Credit-line players are out of scope.",
      "balanceRows": [
        ["main_balance", "Main wallet", "Partner gateway; lottery calls back"],
        ["lottery balance", "In-lottery balance", "Used for betting after transfer-in"]
      ],
      "callRows": [
        ["Lottery → main", "balance / debit / credit", "wallet_api_key"],
        ["Lottery H5 → lottery API", "me / transfers / bets", "Player JWT (not main site)"]
      ]
    },
    "setup": {
      "title": "Setup",
      "description": "Secrets are shown once when the integration site is created. Store them immediately.",
      "weProvide": "We provide",
      "youProvide": "Partner provides",
      "defaultPaths": "Default wallet paths",
      "envMapping": "Config mapping",
      "note": "Isolate test/prod site_code, secrets, and domains. Copy secrets into main-site .env manually. Local dev may use lottery .env MAIN_SITE_* as fallback.",
      "receiveRows": [
        ["site_code", "Site code"],
        ["sso_jwt_secret", "JWT signing secret (held by main site)"],
        ["wallet_api_key", "Wallet callback auth (validated by main site)"],
        ["lottery_h5_base_url", "Lottery entry URL"]
      ],
      "provideRows": [
        ["wallet_api_url", "HTTPS wallet base URL"],
        ["Test accounts", "site_player_id + initial balance"],
        ["iframe origin", "Parent origin when embedding"]
      ],
      "pathRows": [
        ["GET", "/wallet/balance", "Balance"],
        ["POST", "/wallet/debit-for-lottery", "Debit"],
        ["POST", "/wallet/credit-from-lottery", "Credit"]
      ],
      "envMappingRows": [
        ["site_code", "site_code", "MAIN_SITE_CODE", "JWT + player identity; must match"],
        ["SSO secret", "sso_jwt_secret", "MAIN_SITE_SSO_JWT_SECRET", "Main site signs; lottery verifies"],
        ["Wallet auth", "wallet_api_key", "MAIN_SITE_WALLET_API_KEY", "Lottery sends on callbacks; main site validates"],
        ["Wallet base URL", "wallet_api_url", "— (routes on main site)", "Partner HTTPS base; lottery appends /wallet/*"],
        ["Lottery entry", "lottery_h5_base_url", "NEXT_PUBLIC_LOTTERY_IFRAME_URL", "Redirect or iframe target"],
        ["iframe allowlist", "iframe_allowed_origins", "NEXT_PUBLIC_LOTTERY_ORIGIN", "Parent origin allowed to embed"],
        ["Lottery API", "—", "LOTTERY_API_BASE_URL", "Reference impl only"]
      ],
      "adminSop": "Admin provisioning",
      "adminSopSteps": [
        "Super admin → Config → Integration sites",
        "Create site: code, name, currency",
        "Set wallet_api_url (HTTPS root, no path), lottery_h5_base_url, iframe_allowed_origins (one origin per line)",
        "Save sso_jwt_secret and wallet_api_key shown once at creation",
        "Copy secrets to main-site .env; run connectivity test (probes GET /wallet/balance)",
        "Local dev: use main-site/ reference; production wallet_api_url must be public HTTPS"
      ],
      "adminFieldRows": [
        ["code", "Site code in JWT site_code", "demo"],
        ["wallet_api_url", "Partner wallet HTTPS base", "https://wallet.partner.com"],
        ["lottery_h5_base_url", "Lottery H5 entry URL", "https://lottery.partner.com"],
        ["iframe_allowed_origins", "Parent origins allowed to embed", "https://www.partner.com"],
        ["sso_jwt_secret", "Shown once at create", "—"],
        ["wallet_api_key", "Shown once at create", "—"]
      ],
      "network": "Network",
      "networkItems": [
        "Wallet callbacks are server-to-server from lottery to partner — not from the browser",
        "Production wallet_api_url: HTTPS public only (no localhost / private IP)",
        "Default paths: /wallet/balance, /wallet/debit-for-lottery, /wallet/credit-from-lottery",
        "Timeout ≤ 10s recommended; timeouts may enter pending reconcile"
      ]
    },
    "sso": {
      "title": "SSO",
      "description": "HS256 JWT. Main site signs; lottery verifies. Entry: URL redirect or iframe postMessage.",
      "claims": "Claims",
      "sign": "Sign",
      "entryA": "Entry A — redirect",
      "entryB": "Entry B — iframe",
      "noExchangeNote": "Lottery has no token-exchange login API. After main-site login, sign a JWT and send Authorization: Bearer on player APIs. First valid call to GET /api/v1/player/me auto-provisions the player.",
      "entryApi": "Entry API (lottery)",
      "entryApiNote": "Optional: main site may call once server-side after login to verify JWT and provision (see main-site). Day-to-day play APIs are called by lottery H5.",
      "publicApis": "Public APIs (no token)",
      "h5ScopeNote": "Transfers, betting, and in-lottery balance are called by our H5 with the player JWT — out of scope for main-site integration. You only issue JWT and implement the wallet gateway.",
      "partnerApis": "Main-site APIs (partner implements)",
      "refreshNote": "iframe refresh: on LOTTERY_TOKEN_NEEDED, re-issue JWT and send MAIN_REFRESH_TOKEN. See main-site POST /api/auth/refresh.",
      "authResponse": "Auth failure response",
      "errors": "Errors",
      "iframeNote": "Set iframe_allowed_origins. Do not resend LOTTERY_READY after token is delivered.",
      "claimRows": [
        ["site_code", "string", "Y", "Integration site code"],
        ["site_player_id", "string", "Y", "Stable main-site user ID"],
        ["iat", "number", "Y", "Issued at (seconds)"],
        ["exp", "number", "Y", "Expires (seconds); ≤ 300s"]
      ],
      "messageRows": [
        ["→ main", "LOTTERY_READY", "Child ready"],
        ["→ main", "LOTTERY_TOKEN_NEEDED", "Refresh requested"],
        ["→ lottery", "MAIN_INIT_TOKEN", "{ token }"],
        ["→ lottery", "MAIN_REFRESH_TOKEN", "{ token }"]
      ],
      "publicApiRows": [
        ["GET", "/api/v1/player/ping", "Player API connectivity probe"],
        ["GET", "/api/v1/integration/runtime-origins", "Allowed iframe parent origins"]
      ],
      "partnerApiRows": [
        ["POST", "/api/auth/refresh", "(reference) Re-issue JWT for MAIN_REFRESH_TOKEN"]
      ],
      "errorRows": [
        ["8001", "Missing Authorization"],
        ["8002", "JWT invalid or expired"],
        ["8003", "Player not provisioned"],
        ["8004", "SSO secret not configured"],
        ["8005", "Account suspended"]
      ]
    },
    "iframe": {
      "title": "iframe protocol",
      "description": "postMessage contract when embedding lottery H5. Skip if using URL redirect only.",
      "sequence": "Recommended sequence",
      "envelope": "Message shape",
      "childMessages": "Lottery → main",
      "parentMessages": "Main → lottery",
      "targetOrigin": "targetOrigin",
      "envelopeNote": "JSON objects. Lottery sends LOTTERY_* types; main site sends MAIN_*. Include timestamp and source when possible.",
      "targetOriginNote": "postMessage targetOrigin must be a specific origin (e.g. https://www.partner.com), never *. Main site validates event.origin against iframe_allowed_origins; lottery child validates parent origin against the allowlist.",
      "timingNote": "After MAIN_INIT_TOKEN, do not send LOTTERY_READY again. Refresh: child sends LOTTERY_TOKEN_NEEDED or LOTTERY_TOKEN_REFRESH_REQUEST → parent replies MAIN_REFRESH_TOKEN.",
      "sequenceSteps": [
        "Embed <iframe src=\"{lottery_h5_base_url}\">",
        "Lottery H5 loads allowlist then sends LOTTERY_READY",
        "Parent validates origin and sends MAIN_INIT_TOKEN",
        "H5 stores token and calls /api/v1/player/me",
        "Before expiry: LOTTERY_TOKEN_NEEDED → parent sends MAIN_REFRESH_TOKEN"
      ],
      "childMessageRows": [
        ["→ main", "LOTTERY_READY", "Child ready; request token"],
        ["→ main", "LOTTERY_TOKEN_NEEDED", "Token expired; request refresh"],
        ["→ main", "LOTTERY_TOKEN_REFRESH_REQUEST", "Active refresh request"],
        ["→ main", "LOTTERY_HEARTBEAT", "Heartbeat (optional)"],
        ["→ main", "LOTTERY_TOKEN_REFRESHED", "Refresh succeeded notice"]
      ],
      "parentMessageRows": [
        ["→ lottery", "MAIN_INIT_TOKEN", "{ token } initial"],
        ["→ lottery", "MAIN_REFRESH_TOKEN", "{ token } refresh"],
        ["→ lottery", "MAIN_REQUEST_STATUS", "Request child status"],
        ["→ lottery", "MAIN_NAVIGATE", "{ path } navigate"]
      ]
    },
    "wallet": {
      "title": "Wallet gateway",
      "description": "Partner implements. Lottery calls server-to-server. Auth: Bearer wallet_api_key.",
      "balance": "GET balance",
      "debit": "POST debit",
      "credit": "POST credit",
      "response": "Response",
      "httpContract": "HTTP contract",
      "httpErrors": "HTTP errors",
      "creditNote": "Same body as debit; used for transfer-out or refund after failed transfer-in.",
      "idempotentNote": "idempotent_key: same key + same operation must return the first JSON (HTTP 200); no double posting. Different operation/amount → success: false.",
      "queryRows": [
        ["site_code", "string", ""],
        ["site_player_id", "string", ""],
        ["currency_code", "string", ""]
      ],
      "fieldRows": [
        ["site_code", "string", ""],
        ["site_player_id", "string", ""],
        ["player_id", "number", "Lottery player ID"],
        ["currency_code", "string", ""],
        ["amount_minor", "integer", "Positive minor units"],
        ["idempotent_key", "string", "Idempotency key"]
      ],
      "httpErrorRows": [
        ["401", "unauthorized", "Invalid API key"],
        ["422", "invalid request", "Invalid fields/amount"],
        ["409", "main balance insufficient", "Business rejection; may include data.main_balance"]
      ],
      "httpContractRows": [
        ["Debit/credit success", "200", "success: true; external_ref_no (recommended) + data.main_balance"],
        ["Balance success", "200", "success: true; data.main_balance + currency_code"],
        ["Invalid params", "422", "success: false; message: invalid request"],
        ["Unauthorized", "401", "success: false; message: unauthorized"],
        ["Business reject", "409", "success: false; message explains reason"],
        ["Idempotent replay", "200", "Identical JSON to first success/reject response"]
      ]
    },
    "transfer": {
      "title": "Transfers (reference)",
      "description": "Internal: called by lottery H5, not a partner integration surface.",
      "outOfScopeNote": "Partners do not implement these APIs. Transfer-in/out is invoked by our H5 with the player JWT; you only implement wallet gateway debit/credit. This page explains how funds move internally.",
      "requestFields": "Request fields",
      "transferIn": "transfer-in",
      "transferOut": "transfer-out",
      "transferResponse": "Success response",
      "errors": "Common errors",
      "inNote": "Flow: lottery calls debit-for-lottery → credits in-lottery balance.",
      "outNote": "Flow: debits lottery balance → calls credit-from-lottery.",
      "responseNote": "transfer-in and transfer-out share the same shape; direction is in / out. Idempotent replay returns the same data.",
      "requestFieldRows": [
        ["amount", "integer", "Positive minor units"],
        ["currency", "string", "Optional; defaults to player default_currency"],
        ["idempotent_key", "string", "Globally unique; retries return same result"]
      ],
      "errorRows": [
        ["1001", "Insufficient lottery balance (transfer-out)"],
        ["1009", "Main wallet operation failed"],
        ["1010", "Idempotency conflict (same key, different amount)"],
        ["2003", "Transfer in before betting"]
      ]
    },
    "errors": {
      "title": "Errors",
      "sso": "SSO",
      "lotteryWallet": "Lottery wallet",
      "gateway": "Wallet gateway (HTTP)",
      "idempotentNote": "Idempotency: same idempotent_key must return the same result; different amount → 1010.",
      "ssoRows": [
        ["8001", "Missing Authorization"],
        ["8002", "JWT invalid or expired"],
        ["8003", "Player not provisioned"],
        ["8004", "SSO secret not configured"],
        ["8005", "Account suspended"]
      ],
      "lotteryRows": [
        ["1001", "Insufficient lottery balance"],
        ["1009", "Main wallet operation failed"],
        ["1010", "Idempotency conflict"],
        ["2003", "Transfer in first"]
      ],
      "gatewayRows": [
        ["401", "unauthorized", "Invalid API key"],
        ["422", "invalid request", "Invalid fields/amount"],
        ["409", "—", "Business rejection"]
      ]
    },
    "golive": {
      "title": "Go-live",
      "checklist": "Checklist",
      "items": [
        "Isolate test/prod site_code, secrets, domains",
        "JWT server-side only, TTL ≤ 5min",
        "Wallet HTTPS, timeout ≤ 10s",
        "idempotent_key idempotency",
        "iframe: configure iframe_allowed_origins",
        "Full path: transfer-in → bet → settle → transfer-out"
      ]
    }
  }
}
