feat(docs, integration): update integration documentation and redirect legacy paths
Introduced a new public documentation site for client integration at `/docs` and `/docs/integration`, removing the need for admin login. Updated the integration guide to redirect from the old admin path to the new documentation site. Added localization support for the integration documentation in English, Nepali, and Chinese. Enhanced the layout structure and improved the handling of currency display in settlement bills.
This commit is contained in:
372
src/i18n/locales/en/integrationDocs.json
Normal file
372
src/i18n/locales/en/integrationDocs.json
Normal file
@@ -0,0 +1,372 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user