diff --git a/public/docs/admin-manual/01-draw-lifecycle.png b/public/docs/admin-manual/01-draw-lifecycle.png deleted file mode 100644 index bc2f73d..0000000 Binary files a/public/docs/admin-manual/01-draw-lifecycle.png and /dev/null differ diff --git a/public/docs/admin-manual/02-wallet-vs-credit.png b/public/docs/admin-manual/02-wallet-vs-credit.png deleted file mode 100644 index c581990..0000000 Binary files a/public/docs/admin-manual/02-wallet-vs-credit.png and /dev/null differ diff --git a/public/docs/admin-manual/03-settlement-dual.png b/public/docs/admin-manual/03-settlement-dual.png deleted file mode 100644 index 61b1e47..0000000 Binary files a/public/docs/admin-manual/03-settlement-dual.png and /dev/null differ diff --git a/public/docs/admin-manual/04-review-payout.png b/public/docs/admin-manual/04-review-payout.png deleted file mode 100644 index 917fc5e..0000000 Binary files a/public/docs/admin-manual/04-review-payout.png and /dev/null differ diff --git a/public/docs/admin-manual/05-agent-tree.png b/public/docs/admin-manual/05-agent-tree.png deleted file mode 100644 index c85d8f3..0000000 Binary files a/public/docs/admin-manual/05-agent-tree.png and /dev/null differ diff --git a/public/docs/admin-manual/06-integration-site.png b/public/docs/admin-manual/06-integration-site.png deleted file mode 100644 index 22e1901..0000000 Binary files a/public/docs/admin-manual/06-integration-site.png and /dev/null differ diff --git a/public/docs/admin-manual/cover.png b/public/docs/admin-manual/cover.png deleted file mode 100644 index 1731341..0000000 Binary files a/public/docs/admin-manual/cover.png and /dev/null differ diff --git a/src/app/admin/docs/integration-guide/page.tsx b/src/app/admin/docs/integration-guide/page.tsx deleted file mode 100644 index 53ba31f..0000000 --- a/src/app/admin/docs/integration-guide/page.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { redirect } from "next/navigation"; - -/** 旧后台路径保留,统一跳转到公开文档站 */ -export default function AdminIntegrationGuidePage(): never { - redirect("/docs/integration"); -} diff --git a/src/app/docs/admin/agents/page.tsx b/src/app/docs/admin/agents/page.tsx deleted file mode 100644 index dfd0436..0000000 --- a/src/app/docs/admin/agents/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminAgentsDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsAgentsPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/config/page.tsx b/src/app/docs/admin/config/page.tsx deleted file mode 100644 index ff4bcae..0000000 --- a/src/app/docs/admin/config/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminConfigDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsConfigPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/draws/page.tsx b/src/app/docs/admin/draws/page.tsx deleted file mode 100644 index 7e05acc..0000000 --- a/src/app/docs/admin/draws/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminDrawsDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsDrawsPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/faq/page.tsx b/src/app/docs/admin/faq/page.tsx deleted file mode 100644 index 7505822..0000000 --- a/src/app/docs/admin/faq/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminFaqDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsFaqPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/fund-operations/page.tsx b/src/app/docs/admin/fund-operations/page.tsx deleted file mode 100644 index df26b84..0000000 --- a/src/app/docs/admin/fund-operations/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminFundOperationsDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsFundOperationsPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/layout.tsx b/src/app/docs/admin/layout.tsx deleted file mode 100644 index 8d84329..0000000 --- a/src/app/docs/admin/layout.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import type { ReactNode } from "react"; - -import { DocsSidebar } from "@/components/docs/docs-sidebar"; -import { DocsBody } from "@/components/docs/docs-shell"; -import { ADMIN_DOCS_NAV_GROUPS } from "@/lib/admin-docs-nav"; - -export default function AdminDocsLayout({ children }: { children: ReactNode }): React.ReactElement { - return ( - }> - {children} - - ); -} diff --git a/src/app/docs/admin/manual-review/page.tsx b/src/app/docs/admin/manual-review/page.tsx deleted file mode 100644 index 259ce4b..0000000 --- a/src/app/docs/admin/manual-review/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminManualReviewDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsManualReviewPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/page.tsx b/src/app/docs/admin/page.tsx deleted file mode 100644 index 0a59006..0000000 --- a/src/app/docs/admin/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminOverviewDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsOverviewPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/players/page.tsx b/src/app/docs/admin/players/page.tsx deleted file mode 100644 index 58940e1..0000000 --- a/src/app/docs/admin/players/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminPlayersDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsPlayersPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/reports/page.tsx b/src/app/docs/admin/reports/page.tsx deleted file mode 100644 index 6fc59f5..0000000 --- a/src/app/docs/admin/reports/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminReportsDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsReportsPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/roles/page.tsx b/src/app/docs/admin/roles/page.tsx deleted file mode 100644 index a2e50aa..0000000 --- a/src/app/docs/admin/roles/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminRolesDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsRolesPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/settlement-center/page.tsx b/src/app/docs/admin/settlement-center/page.tsx deleted file mode 100644 index 585b3cf..0000000 --- a/src/app/docs/admin/settlement-center/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminSettlementCenterDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsSettlementCenterPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/site-setup/page.tsx b/src/app/docs/admin/site-setup/page.tsx deleted file mode 100644 index 1dddb4c..0000000 --- a/src/app/docs/admin/site-setup/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminSiteSetupDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsSiteSetupPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/tickets/page.tsx b/src/app/docs/admin/tickets/page.tsx deleted file mode 100644 index ba47722..0000000 --- a/src/app/docs/admin/tickets/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminTicketsDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsTicketsPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/admin/wallet/page.tsx b/src/app/docs/admin/wallet/page.tsx deleted file mode 100644 index 6692e62..0000000 --- a/src/app/docs/admin/wallet/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { AdminWalletDocScreen } from "@/modules/docs/admin/admin-doc-screens"; - -export default function AdminDocsWalletPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/admin-guide/page.tsx b/src/app/docs/integration/admin-guide/page.tsx deleted file mode 100644 index 7d59c99..0000000 --- a/src/app/docs/integration/admin-guide/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { redirect } from "next/navigation"; - -export default function LegacyAdminGuidePage(): never { - redirect("/docs/admin"); -} diff --git a/src/app/docs/integration/api-reference/page.tsx b/src/app/docs/integration/api-reference/page.tsx deleted file mode 100644 index 6537928..0000000 --- a/src/app/docs/integration/api-reference/page.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { redirect } from "next/navigation"; - -/** 旧链接兼容:完整内容已拆至左侧分章导航 */ -export default function ApiReferencePage(): never { - redirect("/docs/integration"); -} diff --git a/src/app/docs/integration/delivery/page.tsx b/src/app/docs/integration/delivery/page.tsx deleted file mode 100644 index 9477937..0000000 --- a/src/app/docs/integration/delivery/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { DeliveryDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationDeliveryPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/errors/page.tsx b/src/app/docs/integration/errors/page.tsx deleted file mode 100644 index be28feb..0000000 --- a/src/app/docs/integration/errors/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ErrorsDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationErrorsPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/fundamentals/page.tsx b/src/app/docs/integration/fundamentals/page.tsx deleted file mode 100644 index 4bc28de..0000000 --- a/src/app/docs/integration/fundamentals/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { FundamentalsDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationFundamentalsPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/go-live/page.tsx b/src/app/docs/integration/go-live/page.tsx deleted file mode 100644 index 36d3524..0000000 --- a/src/app/docs/integration/go-live/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { GoLiveDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationGoLivePage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/iframe/page.tsx b/src/app/docs/integration/iframe/page.tsx deleted file mode 100644 index 78e0fa6..0000000 --- a/src/app/docs/integration/iframe/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { IframeDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationIframePage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/layout.tsx b/src/app/docs/integration/layout.tsx deleted file mode 100644 index 0477c1b..0000000 --- a/src/app/docs/integration/layout.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import type { ReactNode } from "react"; - -import { DocsSidebar } from "@/components/docs/docs-sidebar"; -import { DocsBody } from "@/components/docs/docs-shell"; -import { DOCS_NAV_GROUPS } from "@/lib/docs-nav"; - -export default function IntegrationDocsLayout({ children }: { children: ReactNode }): React.ReactElement { - return ( - }>{children} - ); -} diff --git a/src/app/docs/integration/page.tsx b/src/app/docs/integration/page.tsx deleted file mode 100644 index 2829b59..0000000 --- a/src/app/docs/integration/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { OverviewDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationOverviewPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/preparation/page.tsx b/src/app/docs/integration/preparation/page.tsx deleted file mode 100644 index 67017ad..0000000 --- a/src/app/docs/integration/preparation/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { SetupDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationPreparationPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/quickstart/page.tsx b/src/app/docs/integration/quickstart/page.tsx deleted file mode 100644 index 2346120..0000000 --- a/src/app/docs/integration/quickstart/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { QuickstartDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationQuickstartPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/sso/page.tsx b/src/app/docs/integration/sso/page.tsx deleted file mode 100644 index 0d51ce6..0000000 --- a/src/app/docs/integration/sso/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { SsoDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationSsoPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/transfer/page.tsx b/src/app/docs/integration/transfer/page.tsx deleted file mode 100644 index c64b683..0000000 --- a/src/app/docs/integration/transfer/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { TransferDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationTransferPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/troubleshooting/page.tsx b/src/app/docs/integration/troubleshooting/page.tsx deleted file mode 100644 index d4bae2e..0000000 --- a/src/app/docs/integration/troubleshooting/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { TroubleshootingDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationTroubleshootingPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/integration/wallet/page.tsx b/src/app/docs/integration/wallet/page.tsx deleted file mode 100644 index 504f383..0000000 --- a/src/app/docs/integration/wallet/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { WalletDocScreen } from "@/modules/docs/integration/integration-doc-screens"; - -export default function IntegrationWalletPage(): React.ReactElement { - return ; -} diff --git a/src/app/docs/layout.tsx b/src/app/docs/layout.tsx deleted file mode 100644 index 8b2e994..0000000 --- a/src/app/docs/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { Metadata } from "next"; -import type { ReactNode } from "react"; - -import { DocsShell } from "@/components/docs/docs-shell"; - -export const metadata: Metadata = { - title: { - template: "%s · Docs", - default: "Documentation", - }, - description: "Lottery admin user guide and API integration documentation.", -}; - -export default function DocsLayout({ children }: { children: ReactNode }): React.ReactElement { - return {children}; -} diff --git a/src/app/docs/page.tsx b/src/app/docs/page.tsx deleted file mode 100644 index f7196c8..0000000 --- a/src/app/docs/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { redirect } from "next/navigation"; - -export default function DocsHomePage(): never { - redirect("/docs/integration"); -} diff --git a/src/components/admin/toolbar.tsx b/src/components/admin/toolbar.tsx index c28bd2b..f85495d 100644 --- a/src/components/admin/toolbar.tsx +++ b/src/components/admin/toolbar.tsx @@ -1,6 +1,5 @@ "use client"; import { - BookOpenIcon, ChevronDownIcon, LogOutIcon, UserRoundIcon, @@ -73,13 +72,6 @@ export function ShellToolbar() { {t("toolbar.accountSettings")} - router.push("/docs/admin")} - > - - {t("toolbar.relatedDocs")} - diff --git a/src/components/docs/doc-code.tsx b/src/components/docs/doc-code.tsx deleted file mode 100644 index 3622372..0000000 --- a/src/components/docs/doc-code.tsx +++ /dev/null @@ -1,62 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; - -import { highlightCode, type HighlightLang } from "@/lib/highlight-code"; -import { cn } from "@/lib/utils"; - -type DocCodeProps = { - children: string; - language?: HighlightLang; - className?: string; - title?: string; -}; - -export function DocCode({ - children, - language = "json", - className, - title, -}: DocCodeProps): React.ReactElement { - const [html, setHtml] = useState(null); - const code = children.trimEnd(); - - useEffect(() => { - let cancelled = false; - - void highlightCode(code, language).then((result) => { - if (!cancelled) { - setHtml(result); - } - }); - - return () => { - cancelled = true; - }; - }, [code, language]); - - return ( -
- {title ? ( -
- {title} -
- ) : null} - {html ? ( -
- ) : ( -
-          {code}
-        
- )} -
- ); -} diff --git a/src/components/docs/doc-ui.tsx b/src/components/docs/doc-ui.tsx deleted file mode 100644 index 58353ab..0000000 --- a/src/components/docs/doc-ui.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import type { ReactNode } from "react"; - -import { cn } from "@/lib/utils"; - -export { DocCode } from "@/components/docs/doc-code"; - -/** 文档正文容器:统一字号与段落间距 */ -export function DocPage({ children }: { children: ReactNode }): React.ReactElement { - return
{children}
; -} - -export function DocPageHeader({ - title, - description, -}: { - title: string; - description?: string; -}): React.ReactElement { - return ( -
-

- {title} -

- {description ? ( -

- {description} -

- ) : null} -
- ); -} - -export function DocSection({ - title, - children, - className, -}: { - title?: string; - children: ReactNode; - className?: string; -}): React.ReactElement { - return ( -
- {title ? ( -

- {title} -

- ) : null} - {children} -
- ); -} - -export function DocParagraph({ children }: { children: ReactNode }): React.ReactElement { - return

{children}

; -} - -export function DocFigure({ - src, - alt, -}: { - src: string; - alt: string; -}): React.ReactElement { - return ( -
- {/* eslint-disable-next-line @next/next/no-img-element */} - {alt} -
- ); -} - -export function DocNote({ children }: { children: ReactNode }): React.ReactElement { - return ( - - ); -} - -export function DocList({ items }: { items: readonly string[] }): React.ReactElement { - return ( -
    - {items.map((item) => ( -
  • - - {item} -
  • - ))} -
- ); -} - -export function DocOrderedList({ items }: { items: readonly string[] }): React.ReactElement { - return ( -
    - {items.map((item) => ( -
  1. - {item} -
  2. - ))} -
- ); -} - -export function DocTable({ - headers, - rows, - compact, -}: { - headers: readonly string[]; - rows: readonly (readonly string[])[]; - compact?: boolean; -}): React.ReactElement { - return ( -
- - - - {headers.map((header) => ( - - ))} - - - - {rows.map((row, rowIndex) => ( - - {row.map((cell, cellIndex) => ( - - ))} - - ))} - -
- {header} -
- {cell} -
-
- ); -} - -export function DocEndpoint({ method, path }: { method: string; path: string }): React.ReactElement { - return ( -
- - {method} - - {path} -
- ); -} - -export function DocInlineCode({ children }: { children: ReactNode }): React.ReactElement { - return ( - - {children} - - ); -} diff --git a/src/components/docs/docs-admin-console-link.tsx b/src/components/docs/docs-admin-console-link.tsx deleted file mode 100644 index 5355cc7..0000000 --- a/src/components/docs/docs-admin-console-link.tsx +++ /dev/null @@ -1,31 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { useTranslation } from "react-i18next"; - -import { cn } from "@/lib/utils"; - -type DocsAdminConsoleLinkProps = { - namespace: "adminDocs" | "integrationDocs"; - className?: string; -}; - -export function DocsAdminConsoleLink({ - namespace, - className, -}: DocsAdminConsoleLinkProps): React.ReactElement { - const { t } = useTranslation(namespace); - const label = t("shell.adminLogin"); - - return ( - - {label} - - ); -} diff --git a/src/components/docs/docs-shell.tsx b/src/components/docs/docs-shell.tsx deleted file mode 100644 index 46d16cb..0000000 --- a/src/components/docs/docs-shell.tsx +++ /dev/null @@ -1,63 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { usePathname } from "next/navigation"; -import { useTranslation } from "react-i18next"; - -import { AdminLanguageSwitcher } from "@/components/admin/admin-language-switcher"; -import { DocsAdminConsoleLink } from "@/components/docs/docs-admin-console-link"; -import { DocsTopNav } from "@/components/docs/docs-top-nav"; -import { cn } from "@/lib/utils"; - -type DocsShellProps = { - children: React.ReactNode; - className?: string; -}; - -export function DocsShell({ children, className }: DocsShellProps): React.ReactElement { - const pathname = usePathname(); - const isAdminDocs = pathname === "/docs/admin" || pathname.startsWith("/docs/admin/"); - const namespace = isAdminDocs ? "adminDocs" : "integrationDocs"; - const homeHref = isAdminDocs ? "/docs/admin" : "/docs/integration"; - const { t } = useTranslation(namespace); - - return ( -
-
-
-
- - {t("shell.title")} - - -
-
- - -
-
-
- {children} -
- ); -} - -export function DocsBody({ - sidebar, - children, -}: { - sidebar?: React.ReactNode; - children: React.ReactNode; -}): React.ReactElement { - return ( -
- {sidebar} -
- {children} -
-
- ); -} diff --git a/src/components/docs/docs-sidebar.tsx b/src/components/docs/docs-sidebar.tsx deleted file mode 100644 index ddff37c..0000000 --- a/src/components/docs/docs-sidebar.tsx +++ /dev/null @@ -1,68 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { usePathname } from "next/navigation"; -import { useTranslation } from "react-i18next"; - -import type { DocsNavGroup } from "@/lib/docs-nav"; -import { resolveDocsNavLabel } from "@/lib/docs-nav-labels"; -import { cn } from "@/lib/utils"; - -export function DocsSidebar({ - groups, - namespace = "integrationDocs", -}: { - groups: readonly DocsNavGroup[]; - namespace?: "integrationDocs" | "adminDocs"; -}): React.ReactElement { - const pathname = usePathname(); - const { t, i18n } = useTranslation(namespace); - - const homeHref = namespace === "adminDocs" ? "/docs/admin" : "/docs/integration"; - - const label = (key: string): string => { - const translated = t(key); - if (translated !== key) { - return translated; - } - return resolveDocsNavLabel(key, i18n.resolvedLanguage ?? i18n.language, namespace); - }; - - return ( - - ); -} diff --git a/src/components/docs/docs-top-nav.tsx b/src/components/docs/docs-top-nav.tsx deleted file mode 100644 index 7e37bc1..0000000 --- a/src/components/docs/docs-top-nav.tsx +++ /dev/null @@ -1,54 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { usePathname } from "next/navigation"; -import { useTranslation } from "react-i18next"; - -import { cn } from "@/lib/utils"; - -type DocSite = { - href: string; - prefix: string; - titleKey: string; - namespace: "adminDocs" | "integrationDocs"; -}; - -const DOC_SITES: readonly DocSite[] = [ - { href: "/docs/admin", prefix: "/docs/admin", titleKey: "shell.title", namespace: "adminDocs" }, - { - href: "/docs/integration", - prefix: "/docs/integration", - titleKey: "shell.title", - namespace: "integrationDocs", - }, -]; - -function DocsTopNavLink({ site }: { site: DocSite }): React.ReactElement { - const pathname = usePathname(); - const { t } = useTranslation(site.namespace); - const active = pathname === site.href || pathname.startsWith(`${site.prefix}/`); - - return ( - - {t(site.titleKey)} - - ); -} - -export function DocsTopNav(): React.ReactElement { - return ( - - ); -} diff --git a/src/i18n/bundles/en.ts b/src/i18n/bundles/en.ts index 2acb7b8..5fa2169 100644 --- a/src/i18n/bundles/en.ts +++ b/src/i18n/bundles/en.ts @@ -1,4 +1,3 @@ -import adminDocs from "@/i18n/locales/en/adminDocs.json"; import adminUsers from "@/i18n/locales/en/adminUsers.json"; import agents from "@/i18n/locales/en/agents.json"; import audit from "@/i18n/locales/en/audit.json"; @@ -7,7 +6,6 @@ import common from "@/i18n/locales/en/common.json"; import config from "@/i18n/locales/en/config.json"; import dashboard from "@/i18n/locales/en/dashboard.json"; import draws from "@/i18n/locales/en/draws.json"; -import integrationDocs from "@/i18n/locales/en/integrationDocs.json"; import jackpot from "@/i18n/locales/en/jackpot.json"; import players from "@/i18n/locales/en/players.json"; import reconcile from "@/i18n/locales/en/reconcile.json"; @@ -38,8 +36,6 @@ const bundle = { adminUsers, agents, config, - integrationDocs, - adminDocs, } satisfies Record>; export default bundle; diff --git a/src/i18n/bundles/ne.ts b/src/i18n/bundles/ne.ts index c1ca865..8a95ff3 100644 --- a/src/i18n/bundles/ne.ts +++ b/src/i18n/bundles/ne.ts @@ -1,4 +1,3 @@ -import adminDocs from "@/i18n/locales/ne/adminDocs.json"; import adminUsers from "@/i18n/locales/ne/adminUsers.json"; import agents from "@/i18n/locales/ne/agents.json"; import audit from "@/i18n/locales/ne/audit.json"; @@ -7,7 +6,6 @@ import common from "@/i18n/locales/ne/common.json"; import config from "@/i18n/locales/ne/config.json"; import dashboard from "@/i18n/locales/ne/dashboard.json"; import draws from "@/i18n/locales/ne/draws.json"; -import integrationDocs from "@/i18n/locales/ne/integrationDocs.json"; import jackpot from "@/i18n/locales/ne/jackpot.json"; import players from "@/i18n/locales/ne/players.json"; import reconcile from "@/i18n/locales/ne/reconcile.json"; @@ -38,8 +36,6 @@ const bundle = { adminUsers, agents, config, - integrationDocs, - adminDocs, } satisfies Record>; export default bundle; diff --git a/src/i18n/bundles/zh.ts b/src/i18n/bundles/zh.ts index ce93c74..0865f4d 100644 --- a/src/i18n/bundles/zh.ts +++ b/src/i18n/bundles/zh.ts @@ -1,4 +1,3 @@ -import adminDocs from "@/i18n/locales/zh/adminDocs.json"; import adminUsers from "@/i18n/locales/zh/adminUsers.json"; import agents from "@/i18n/locales/zh/agents.json"; import audit from "@/i18n/locales/zh/audit.json"; @@ -7,7 +6,6 @@ import common from "@/i18n/locales/zh/common.json"; import config from "@/i18n/locales/zh/config.json"; import dashboard from "@/i18n/locales/zh/dashboard.json"; import draws from "@/i18n/locales/zh/draws.json"; -import integrationDocs from "@/i18n/locales/zh/integrationDocs.json"; import jackpot from "@/i18n/locales/zh/jackpot.json"; import players from "@/i18n/locales/zh/players.json"; import reconcile from "@/i18n/locales/zh/reconcile.json"; @@ -38,8 +36,6 @@ const bundle = { adminUsers, agents, config, - integrationDocs, - adminDocs, } satisfies Record>; export default bundle; diff --git a/src/i18n/locales/en/adminDocs.json b/src/i18n/locales/en/adminDocs.json deleted file mode 100644 index f9627f0..0000000 --- a/src/i18n/locales/en/adminDocs.json +++ /dev/null @@ -1,644 +0,0 @@ -{ - "shell": { - "title": "Admin Operations Guide", - "integrationDocs": "API Integration Docs", - "adminLogin": "Admin Console" - }, - "nav": { - "gettingStarted": "Getting started", - "operations": "Core operations", - "management": "Management", - "finance": "Funds & tickets", - "platform": "Platform configuration", - "reference": "Reference", - "overview": "Overview", - "roles": "Roles & permissions", - "siteSetup": "Integration sites", - "draws": "Draws & results", - "settlementCenter": "Settlement center", - "agents": "Agent hierarchy", - "players": "Player management", - "tickets": "Ticket search", - "wallet": "Wallet & reconciliation", - "config": "Rules & risk control", - "reports": "Reports", - "fundOperations": "Fund operations guide", - "manualReview": "Manual review & payouts", - "faq": "FAQ" - }, - "headers": { - "role": ["Role", "Primary responsibilities", "Typical access"], - "status": ["Status", "Meaning", "Available actions"], - "module": ["Module", "Description"], - "field": ["Field", "Description", "Example"], - "billStatusTable": ["Bill status", "Meaning", "Next step"], - "faq": ["Issue", "Resolution"], - "report": ["Report", "Purpose"], - "menu": ["Sidebar group", "Menu", "Typical users", "Description"], - "ledger": ["Ledger type", "When it occurs", "Effect on player funds", "Where to view"], - "walletTxn": ["Wallet ledger type", "When it occurs", "Description"], - "compare": ["Stage", "Wallet mode", "Credit mode"], - "reconcile": ["Situation", "Action", "Notes"], - "setting": ["System setting", "Location", "When enabled", "When disabled"], - "batchStatus": ["Batch status", "Meaning", "Available actions"] - }, - "pages": { - "overview": { - "title": "Admin operations overview", - "description": "For your organization's super admins, site operators, and bound agent staff. This guide follows the actual admin menu and includes step-by-step instructions. For wallet-mode technical integration, see the API Integration Docs.", - "figureAlt": "Admin console capabilities overview diagram", - "loginNote": "Admin console: https://lotteryadmin.tanumo.com/admin (use the operations account assigned by your organization or our team)", - "scope": "System capabilities", - "scopeItems": [ - "Draw management: schedule generation, close, result review, and payout settlement", - "Players & tickets: search, freeze, view ledgers and ticket history", - "Rule configuration: play switches, odds, caps, jackpot (platform super admin)", - "Settlement center: credit-line period open/close, bill confirmation, payment recording", - "Agent hierarchy: agent tree, share/credit/rebate, downstream operator accounts", - "Wallet & reconciliation: main-site transfer ledger, missing-order handling (wallet mode)", - "Reports: P&L summary, risk occupancy, async export" - ], - "menuMap": "Admin menu map", - "menuMapNote": "Visible menus depend on your account role. Bound agent accounts do not see platform finance menus such as Wallet ledger or Reconciliation.", - "menuMapRows": [ - ["Overview", "Dashboard", "All users", "Home after sign-in; current-period operations summary"], - ["Agent organization", "Agent lines", "Super admin", "Provision independent sites and root agents for credit-line customers (wallet mode usually needs Integration sites only)"], - ["Agent organization", "Agent list", "Site ops / agents", "Maintain agent tree, share/credit/rebate, downstream accounts"], - ["Agent organization", "Settlement center", "Site finance / bound agents", "Credit-line periods, bill confirmation, record payments"], - ["Daily operations", "Draw list", "Platform super admin", "Draw schedule, result review, redraw (shared by wallet and credit modes)"], - ["Daily operations", "Ticket list", "Ops / support / agents", "Search tickets by player, draw, play type"], - ["Daily operations", "Player list", "Site ops / agents", "Create profiles, freeze, view ledgers and tickets"], - ["Daily operations", "Settlement", "Platform ops", "Post-draw payout settlement batches (not credit-line periods)"], - ["Funds & reports", "Wallet ledger", "Platform / site finance", "Wallet mode: main-site transfers and in-lottery balance changes"], - ["Funds & reports", "Reconciliation", "Platform / site finance", "Wallet mode: handle long-pending transfer orders"], - ["Funds & reports", "Reports", "Ops / finance / agents", "P&L, player win/loss, risk, export"], - ["Platform management", "Play rules / odds / limits / risk / jackpot", "Super admin", "Site-wide play and risk parameters (site operators usually do not see these menus)"], - ["Platform management", "Integration sites / Admin users / Role management", "Super admin", "Site secrets, admin accounts, and permission assignment"] - ], - "readingOrder": "Suggested reading order", - "readingItems": [ - "Roles & permissions → confirm what your account can do", - "Wallet super admin: Integration sites → API Integration Docs → Draws & results → Wallet & reconciliation", - "Credit-line site ops: Agent hierarchy → Player management → Settlement center (open/close/payments)", - "Bound agent operator: Agent list → Player management → Settlement center (payments for own line only)", - "Fund semantics and ledger types → Fund operations guide", - "Draw review and payout batches → Manual review & payouts" - ], - "modes": "Two player funding modes", - "modeRows": [ - ["Wallet mode", "Players enter via your main-site SSO; funds move through your wallet gateway; ops use Wallet ledger and Reconciliation. Technical details are in the API Integration Docs"], - ["Credit mode", "Lottery-native accounts or agent-created profiles; bets use credit; wins settle in Settlement center periods; no main-site wallet involved"] - ], - "note": "Share settlement bills use the share rate recorded at bet time. Closed historical periods are not recalculated when agent share rates change later." - }, - "roles": { - "title": "Roles & permissions", - "description": "The admin console manages access as account → role → feature permissions. Bound agent operator accounts only see data within their agent line. Site admins are bound to a single site and do not get platform technical menus such as draw odds configuration.", - "matrix": "Common roles", - "matrixRows": [ - ["Super admin", "Highest access across the system: integration sites, draw intervention, agent line provisioning, global configuration", "Built-in super admin; not limited by site roles"], - ["Site admin", "Single-site credit-line operations: agent tree, players, settlement, tickets, reports", "Bound to one site; no platform play rules/odds configuration"], - ["Bound agent operator", "Manage downstream agents and players under this line; period payments (bills where this account is the payee only)", "Bound to a specific agent node; cannot open or close periods"], - ["Risk / finance / support", "View or operate assigned menus by job function", "Assigned by super admin in Role management"] - ], - "accountModel": "Account and permission model", - "accountItems": [ - "Admin users (Platform management): create admin accounts; bind roles or site/agent scope", - "Role management (Platform management): select menus and actions; accounts do not hold permissions directly", - "Site admins must choose an owning agent when creating players; cannot default to the root agent", - "A bound agent's main account can record settlement payments; payee rules and direct-player/bill-party rules still apply", - "With view-only access, buttons such as record payment, confirm bill, and open/close period are hidden (not shown as errors)" - ], - "accountSetup": "Create an operations account (super admin)", - "accountSetupSteps": [ - "Sign in → Platform management → Admin users → Create account", - "Enter login name, initial password, and display name", - "Choose binding: ① site role (site admin) ② agent node (agent operator) ③ role only (platform role)", - "Site admin: select the target integration site under Site role", - "Agent operator: select the agent node under Agent binding (data scope = that node and downstream)", - "After saving, ask the user to change the initial password; if expected menus are missing, check Role management for the assigned role" - ], - "note": "With no integration site, site-dependent write actions prompt you to create a site (super admin only)." - }, - "siteSetup": { - "title": "Integration sites (super admin)", - "description": "Wallet mode requires an integration site first. Save SSO and wallet secrets and have your technical team configure them on your main-site server. Credit-line agent line provisioning also creates a site.", - "figureAlt": "Integration site configuration diagram", - "path": "Create and configure", - "pathItems": [ - "Sign in at https://lotteryadmin.tanumo.com/admin → Platform management → Integration sites", - "Click Create site; enter site code (must match site_code in your JWT), name, and status", - "After creation, copy immediately the one-time SSO secret and wallet API key shown on screen (they cannot be viewed again after closing)", - "Edit the site: enter your wallet gateway URL (HTTPS root, no path), lottery H5 entry, iframe allowlist (one origin per line)", - "Click Connectivity test and confirm your balance query API returns success", - "Give secrets and site code to your technical team for main-site server configuration; field reference and curl examples are in the API Integration Docs" - ], - "fieldRows": [ - ["Site code", "Written into site_code in JWTs your organization issues; must match on both sides", "demo"], - ["Wallet gateway URL", "Your HTTPS root URL (no path)", "https://wallet.your-domain.com"], - ["Lottery H5 entry", "Redirect or iframe entry URL", "https://front.tanumo.com"], - ["Iframe allowlist", "Domains allowed to embed the lottery; one per line", "https://www.your-domain.com"], - ["SSO secret", "Shown once at creation; your main site uses it to sign JWTs", "—"], - ["Wallet API key", "Shown once at creation; lottery uses it when calling your wallet APIs", "—"] - ], - "fields": "Key fields", - "caution": "Important notes", - "cautionItems": [ - "Keep site codes, secrets, and domains fully isolated between test and production", - "Production wallet gateway must be a public HTTPS URL", - "Secrets must be configured on your main-site server by your technical team; the admin console does not auto-sync them to your systems", - "Integration and go-live checklist: API Integration Docs → Delivery" - ], - "apiLinkNote": "Wallet gateway fields, curl self-tests, and iframe protocol are in", - "apiLinkLabel": "API Integration Docs → Setup" - }, - "draws": { - "title": "Draws & results", - "description": "A draw is the basic betting unit. List times are shown in local timezone; the server stores UTC. Whether the hall accepts bets is determined live; the list shows database status, which may differ slightly from the player-side countdown.", - "figureAlt": "Draw status lifecycle diagram", - "lifecycle": "Draw statuses", - "statusRows": [ - ["Not started", "Before start time", "Edit, delete (no bets)"], - ["Open", "Accepting bets", "Edit some times, cancel (no bets)"], - ["Closing", "No longer accepting new bets", "Wait for draw"], - ["Pending draw / drawing", "Waiting for or generating result", "Proceed to review and publish"], - ["Pending review", "Cooling period for verification", "Approve, redraw/rollback"], - ["Settling", "Calculating wins and payouts", "—"], - ["Settled", "All tickets for this draw processed", "View finance and risk"], - ["Cancelled", "Cancelled by admin", "Record kept; placed bets refunded"] - ], - "workflow": "Daily workflow (platform super admin)", - "workflowItems": [ - "Daily operations → Draw list → Batch generate draw plan: auto-create upcoming draws on configured intervals", - "Manually create a draw or edit times for not-started/open draws when needed", - "After close time the system closes automatically; draw flow: generate result → cooling review → publish → auto settlement", - "Draw detail page shows: finance summary, number occupancy, result batches, related tickets" - ], - "publishWalkthrough": "Publish draw results step by step", - "publishSteps": [ - "Draw list → open the target draw", - "Confirm status is Pending draw or Pending review", - "If no result yet: click Generate draw result", - "During cooling period verify numbers → click Approve and publish", - "After publish the system moves to Settling → Settled; wallet-mode players receive instant payouts, credit-mode players get credit release recorded in period ledger", - "If issues are found after publish: super admin may Redraw during cooling (see next section)" - ], - "reopenWalkthrough": "Redraw and rollback (super admin only, during cooling)", - "reopenSteps": [ - "Draw detail → Redraw/rollback", - "System rolls back payouts/credit releases → regenerate result → review and publish again → settle again", - "Actions are written to audit log; confirm with your finance team before proceeding" - ], - "rules": "Rules & risk (related modules, super admin)", - "rulesItems": [ - "Platform management → Play rules: play switches, min/max stake", - "Platform management → Odds & rebate: affects new tickets only", - "Platform management → Limit versions: per-number caps; sold-out numbers block betting", - "Platform management → Risk center: view occupancy and payout pools by number; occupancy ledger defaults to ticket aggregation" - ], - "note": "Times cannot be changed after close. Cancel a draw only when open/closing with no bets.", - "manualReviewLinkNote": "Draw manual review, cooling period, and payout settlement batches are covered in", - "manualReviewLinkLabel": "Manual review & payouts" - }, - "settlementCenter": { - "title": "Settlement center (credit line)", - "description": "Manage agent settlement periods: open → close and generate bills → confirm → record payments. Bound agents can only view and operate bills for their own line. Wallet-mode players are not part of this module.", - "figureAlt": "Dual settlement systems diagram", - "entry": "Entry & permissions", - "entryItems": [ - "Agent organization → Settlement center: period list", - "Open / close period: site finance accounts not bound to an agent only (usually your finance role)", - "Bound agents: cannot open or close periods; can only handle bills where they are the payee", - "Settlement write permission is required to show record payment, confirm bill, and similar actions; with view-only access the action area is hidden" - ], - "periodFlow": "Period lifecycle", - "periodItems": [ - "Open period: create an in-progress period; start accumulating share ledger and player credit moves", - "During period: player bets use credit, win releases, rebates, etc. are written to ledger", - "Close period: aggregate period data into player bills and agent bills; irreversible", - "Related draws for the period must be settled before close; warnings appear if unsettled tickets remain", - "After close: agents/finance confirm bills → record actual payments → bills reach settled status" - ], - "openWalkthrough": "Open a period (site finance)", - "openSteps": [ - "Settlement center → period list → Open period", - "Enter period name and start/end dates (per your agreement with agents)", - "Confirm no other in-progress period conflicts → submit", - "After open, new bets and credit releases count toward this period" - ], - "closeWalkthrough": "Close a period (site finance)", - "closeSteps": [ - "Confirm all draws for this period are Settled", - "Settlement center → select in-progress period → Close period", - "System aggregates share ledger into player bills (direct players) and agent bills (share at each level)", - "After close, bill status is Pending confirm; historical share uses bet-time snapshot, not current agent profile" - ], - "paymentWalkthrough": "Confirm and record payments", - "paymentSteps": [ - "Settlement center → period detail → Bills tab → open target bill", - "Payee account clicks Confirm bill (status: Pending confirm → Confirmed)", - "Click Record payment; enter actual received/paid amount, method, and notes", - "Multiple payments allowed until Settled; partial payment shows Partial paid", - "Bad debt write-off and top-up reversal: site finance only (not bound to an agent)" - ], - "detailTabs": "Three tabs on period detail", - "detailTabItems": [ - "Bills: player bills and agent bills; open a bill to confirm or record payment", - "Payments & adjustments: operation log for payments, bad debt, top-ups, etc. (by operation record)", - "Credit ledger: player credit limit moves (bet hold, win release, period payment entries, etc.)" - ], - "billStatusSection": "Bill statuses", - "billStatusRows": [ - ["Pending confirm", "After close; awaiting agent or finance confirmation", "Confirm bill"], - ["Confirmed", "Amount confirmed", "Record payment"], - ["Partial paid", "Outstanding balance remains", "Continue payment"], - ["Overdue", "Past due and not fully paid", "Collect or bad debt handling"], - ["Settled", "Payments complete", "Archive for reference"] - ], - "operations": "Permissions and scope notes", - "operationItems": [ - "Record payment: payee only", - "Bound agents: player bills include direct players only; agent bills include bills where this node is bill party or counterparty", - "Bills have no currency_code field; display currency uses player default_currency" - ], - "note": "Closed share bills settle using bet-time snapshot; history is not recalculated from current agent profiles.", - "fundOpsLinkNote": "For credit ledger types and how they differ from wallet mode, see", - "fundOpsLinkLabel": "Fund operations guide" - }, - "agents": { - "title": "Agent hierarchy", - "description": "The agent layer controls which data you can see and credit limits for downstream players; menu permissions still come from roles. Credit-line sites must maintain the agent tree before creating players under it.", - "figureAlt": "Agent organization and settlement periods diagram", - "structure": "Organization", - "structureItems": [ - "Super admin: Agent organization → Agent lines → Provision line: create independent site + root node for external agents", - "Site ops: Agent organization → Agent list: maintain agent tree under existing site", - "Select an agent node to edit profile: share, credit, rebate, delegation permissions", - "Root agent profile editable by super admin only; downstream maintained by parent agent or site admin", - "Agent operator admin accounts can be created (bind agent node in Admin users)" - ], - "provisionWalkthrough": "Provision credit-line agent line (super admin)", - "provisionSteps": [ - "Agent organization → Agent lines → Provision line", - "Enter site info, root agent name and code", - "Set initial share, credit, and rebate for root agent", - "Submit to auto-create integration site and root agent; record returned site code", - "Create site admin or root agent operator account for the partner (see Roles & permissions)" - ], - "dailyWalkthrough": "Daily agent maintenance (site ops)", - "dailySteps": [ - "Agent list → select parent node → Create downstream agent", - "Enter name, code, share/credit/rebate; whether further delegation is allowed", - "After save the node appears in the tree; continue creating downstream agents or players", - "Share/credit changes affect new tickets and future periods only; closed history unchanged" - ], - "profile": "Agent profile fields", - "profileRows": [ - ["Share rate", "This level's share of downstream turnover", "After close, counted in this level's share profit (win/loss)"], - ["Credit line", "Credit ceiling for downstream players", "Total bet holds for downstream players must stay within chain credit rules"], - ["Rebate rate", "Rebate layered on play configuration", "Combined with platform Odds & rebate settings"], - ["Delegation", "Whether creating downstream agents/players is allowed", "Site admins are not limited by this switch; they follow their own role permissions"] - ], - "siteAdmin": "Site admin notes", - "siteAdminItems": [ - "Site admins are not blocked by delegation switches on the selected agent profile; they follow their own role permissions", - "When creating players under an agent you must choose the owning agent (cannot default to root)", - "Open/close period and bad debt write-off require a site finance account not bound to an agent" - ], - "note": "Agent profile changes affect new tickets and future periods only; closed history stays unchanged." - }, - "players": { - "title": "Player management", - "description": "Manage wallet-mode and credit-mode players in one place. List and detail views show different balances and ledger tabs by funding mode.", - "figureAlt": "Wallet mode vs credit mode comparison diagram", - "list": "Player list", - "listItems": [ - "Daily operations → Player list", - "Search: username, nickname, main-site player ID, owning agent", - "Funding mode column distinguishes wallet mode vs credit mode", - "Balance column: credit mode shows credit limit (major); wallet mode shows in-lottery balance (minor)" - ], - "createWalkthrough": "Create credit-mode player (site ops / agent)", - "createSteps": [ - "Player list → Create player", - "Owning agent is required (site admins cannot skip)", - "Enter login name, password, nickname, default currency", - "Set initial credit limit (credit mode)", - "After save the player can sign in with lottery-native credentials; wallet-mode players are usually auto-created on first valid main-site SSO entry" - ], - "freezeWalkthrough": "Freeze / unfreeze", - "freezeSteps": [ - "Player list or player detail → Freeze", - "Frozen players cannot bet; existing tickets settle per rules", - "Unfreeze restores normal betting" - ], - "modes": "Funding mode differences", - "modeRows": [ - ["Wallet mode", "Enter via your main-site SSO; first valid JWT auto-creates profile. Detail tabs: wallet ledger, transfer orders"], - ["Credit mode", "Lottery-native account or created in agent admin. Detail tab: credit ledger; wins settle in agent periods"] - ], - "detail": "Player detail page", - "detailItems": [ - "Credit ledger: bet hold, win release, period payment entries, etc.", - "Wallet ledger / transfer orders: wallet mode only; transfer orders map to main-site transfer records", - "Ticket history: jump to ticket detail (including combo play breakdown)", - "Adjust credit: requires player/agent management write permission" - ], - "note": "Wallet-mode usernames are generated by the lottery (e.g. nlotto******); nicknames are not synced from your main site." - }, - "tickets": { - "title": "Ticket search", - "description": "Search player tickets across dimensions for operations, support, and agent reconciliation. Bound agents only see tickets for players in their agent subtree.", - "entry": "Entry", - "entryItems": [ - "Daily operations → Ticket list", - "Or from player detail → Ticket history for a single player" - ], - "filter": "Common filters", - "filterItems": [ - "Draw, player, play type, ticket number, time range", - "Status: pending draw / won / lost / cancelled, etc.", - "Agent scope: super admin can filter by site; site ops see own site; bound agents see own subtree" - ], - "detail": "Ticket detail", - "detailItems": [ - "Shows bet content, odds, amount, share snapshot (credit mode)", - "Combo plays (e.g. combination bets) show combo breakdown on detail page", - "Related links: player detail, draw detail", - "Excel export supported (export permission required)" - ], - "note": "Ticket amounts are snapshotted at bet time; status updates automatically after draw; no manual ticket edits." - }, - "wallet": { - "title": "Wallet & reconciliation (wallet mode)", - "description": "Applies to wallet-mode players only. Shows transfer records between your main site and the lottery. Bound agent accounts usually do not see this menu.", - "walletSection": "Wallet ledger", - "walletItems": [ - "Funds & reports → Wallet ledger", - "Filter by player, type, time: transfer in, transfer out, bet, payout, etc.", - "Amounts are minor integers; consistent with wallet gateway definitions in API Integration Docs", - "Export filtered results (permission required)" - ], - "transferSection": "Transfer orders", - "transferItems": [ - "Wallet module includes Transfer orders list (main site ↔ lottery)", - "Status: success / failed / pending", - "Long-pending orders can be handled in Reconciliation" - ], - "reconcileSection": "Reconciliation (missing orders)", - "reconcileSteps": [ - "Funds & reports → Reconciliation", - "List shows long-pending or abnormal transfer orders", - "Open an order → verify actual debit/credit result with your main site", - "Per verification: post entry, reverse, or close; actions are audited", - "Technical team should also check your wallet gateway logs and API Integration Docs → Troubleshooting" - ], - "note": "Credit-mode players do not use wallet ledger or reconciliation; their fund moves are in Settlement center credit ledger.", - "fundOpsLinkNote": "For wallet vs credit fund lifecycle comparison, see", - "fundOpsLinkLabel": "Fund operations guide" - }, - "config": { - "title": "Rules & risk control (platform super admin)", - "description": "Site-wide play, odds, limits, and risk parameters. Usually visible only to platform super admins or your organization's super admins with platform access; site ops and agents typically do not see these menus.", - "plays": "Play rules", - "playsItems": [ - "Platform management → Play rules", - "Switch plays on/off: disabled plays cannot be bet on player side", - "Set min/max stake per bet" - ], - "odds": "Odds & rebate", - "oddsItems": [ - "Platform management → Odds & rebate", - "Adjust odds and base rebate; affects new tickets only", - "Combined with rebate rate in agent profiles" - ], - "riskCap": "Limit versions", - "riskCapItems": [ - "Platform management → Limit versions", - "Set per-number caps; number is sold out when cap is reached", - "New version applies to future draws only; open draws use the version active at open" - ], - "risk": "Risk center", - "riskItems": [ - "Platform management → Risk center", - "View number occupancy, payout pools, high-risk numbers", - "Occupancy ledger defaults to ticket aggregation; only numbers with occupancy or high risk are shown", - "Combo play breakdown is on ticket detail, not expanded in risk list" - ], - "jackpot": "Jackpot", - "jackpotItems": [ - "Platform management → Jackpot", - "Maintain jackpot amount and payout rules (when jackpot play is enabled)" - ], - "note": "If your site operator account does not see these menus, that is normal permission isolation; contact our team or your super admin to adjust play settings." - }, - "reports": { - "title": "Reports", - "description": "View P&L and risk by draw, player, play type, and more; async export supported. Data scope narrows automatically by account role.", - "entry": "Entry & filters", - "entryItems": [ - "Funds & reports → Reports", - "Choose report type first, then set time, site, agent, draw, and other filters", - "Bound agent reports include own agent subtree only" - ], - "types": "Main reports", - "reportRows": [ - ["Per-draw P&L", "Stake, payout, and profit summary for one draw"], - ["Daily summary", "Aggregated by business date"], - ["Player win/loss", "Ranking and detail by player"], - ["Play dimension", "Stake and payout structure by play type"], - ["Hot number risk", "Bet concentration and payout pool occupancy by number"], - ["Rebate commission", "Rebate and commission accrual"], - ["Audit log", "Trace key admin actions (super admin)"] - ], - "export": "Export", - "exportItems": [ - "Report export permission required for async export; download when complete", - "Ticket list and wallet ledger also support Excel export", - "Export jobs run asynchronously; narrow time range for large data sets" - ], - "scope": "Data scope", - "scopeItems": [ - "Super admin: all sites or filter by site", - "Site admin: own site", - "Bound agent: own agent subtree" - ] - }, - "fundOperations": { - "title": "Fund operations guide", - "description": "Explains how funds move during betting, draw settlement, and payment in wallet mode vs credit mode. Confirm the player's funding mode first, then check the matching ledger.", - "figureAlt": "Dual settlement systems diagram", - "twoSystems": "Two parallel systems (do not confuse them)", - "twoSystemsItems": [ - "Per-draw settlement (Daily operations → Settlement): calculates win/loss for the draw; wallet mode pays out here, credit mode records release/period ledger here", - "Credit-line period settlement (Agent organization → Settlement center): credit mode only; aggregates share by period and generates bills for agent/player payments", - "Main-site wallet transfers (Funds & reports → Wallet): wallet mode only; transfer in/out between main site and lottery" - ], - "creditModel": "Credit mode: credit limit model", - "creditModelItems": [ - "Credit limit (credit_limit): ceiling set by agent or ops for the player", - "Used credit (used_credit): total of bet holds plus settled losses", - "Available credit = credit limit − used credit − frozen amount; betting blocked when available is insufficient", - "Balance shown in player list/detail for credit mode is credit-related, not cash balance" - ], - "creditLifecycle": "Credit mode: fund lifecycle of one ticket", - "creditLifecycleSteps": [ - "① Bet placed: credit hold (ledger shows Bet hold). This locks available credit, not final deduction", - "② Pending draw: hold remains; ledger shows hold only, no duplicate settlement charge", - "③ After draw settlement: system releases the hold, then posts Draw settlement — loss increases used credit; win releases credit (available rises), no instant cash", - "④ During period: win/loss also written to share ledger for period close and bills", - "⑤ After period close: confirm bills and record payments in Settlement center; player may see Period settlement confirm or Settlement payment entry ledger types", - "⑥ Players with overdue unpaid bills: betting blocked until period payment is completed" - ], - "creditLedger": "Credit mode: credit ledger type reference", - "creditLedgerRows": [ - ["Bet hold", "Player bet succeeds", "Available credit down; used credit up", "Settlement center → Credit ledger; player detail → Credit ledger"], - ["Draw settlement", "Draw payout settlement complete", "Release hold and adjust used credit by win/loss; win = release", "Same; pending draw shows hold only; one settlement line per ticket after draw"], - ["Period settlement confirm", "Period bill payment recorded (some cases)", "Used credit decreases", "Settlement center → Credit ledger"], - ["Settlement payment entry", "Period payment bookkeeping", "Bookkeeping only; available credit unchanged", "Settlement center → Credit ledger"], - ["Top-up / reversal / bad debt", "Site finance adjustment", "Adjust bill and ledger per adjustment type", "Settlement center → Payments & adjustments"] - ], - "creditBill": "Credit mode: what bills and payments mean", - "creditBillItems": [ - "Player bill after close = net receivable/payable for that player's win/loss in the period", - "Agent bill = share receivable/payable at each agent level", - "Positive net: bill party pays payee; negative net: payee pays bill party (admin shows payer/payee)", - "Confirm bill: both sides agree on amount; record payment: log actual funds, multiple entries until settled", - "Bad debt write-off: confirm unrecoverable debt; site finance only (not bound to agent)" - ], - "creditAdjust": "Credit mode: manual credit limit adjustment", - "creditAdjustSteps": [ - "Player detail → Adjust credit (requires player/agent management write permission)", - "Change credit limit ceiling; does not erase historical used credit", - "If new limit is below current used credit, player cannot bet until used credit drops", - "Period payments, bad debt, top-ups belong in Settlement center; do not duplicate manual entries on player detail" - ], - "walletLifecycle": "Wallet mode: fund lifecycle", - "walletLifecycleSteps": [ - "① Player enters lottery H5 from your main site (SSO + JWT)", - "② Transfer in: player initiates in H5 → lottery calls your wallet debit → in-lottery balance up (transfer order + wallet ledger)", - "③ Bet: deducted from in-lottery balance (wallet ledger type Bet debit)", - "④ Draw settlement: win amount to in-lottery balance (Payout credit); credited after Daily operations → Settlement batch review/payout", - "⑤ Transfer out (optional): lottery calls your wallet credit → in-lottery balance down", - "⑥ Exception: long-pending transfer orders handled manually in Reconciliation" - ], - "walletTxn": "Wallet mode: wallet ledger types", - "walletTxnRows": [ - ["Main-site transfer in", "Player transfers from main site to lottery", "In-lottery balance increases"], - ["Main-site transfer out", "Player transfers from lottery to main site", "In-lottery balance decreases"], - ["Bet debit", "Bet succeeds", "Balance decreases"], - ["Payout credit", "Draw payout settlement complete", "Balance increases (when won)"], - ["Bet reversal / transfer-out failure refund", "Ticket cancelled or transfer-out rollback", "Balance restored"] - ], - "walletReconcile": "Wallet mode: transfer order exceptions", - "walletReconcileRows": [ - ["Pending reconciliation", "Main site and lottery status mismatch or timeout", "Verify your gateway logs first, then choose action below"], - ["Complete missing credit", "Main site debited but lottery not credited (transfer in)", "Post transfer in on lottery side and mark success"], - ["Reversal", "Need to undo lottery-side entry", "Reverse lottery wallet balance"], - ["Mark closed", "Resolved outside the system", "Change order status only, no balance move; not for pending transfer-out reconciliation"] - ], - "compare": "Same stage: wallet mode vs credit mode", - "compareRows": [ - ["Entry", "Main-site SSO; first JWT auto-creates profile", "Lottery account or agent admin creates profile"], - ["Must have funds to bet", "In-lottery balance ≥ stake", "Available credit ≥ stake"], - ["When betting", "Balance deducted immediately", "Credit hold (freeze), not final loss"], - ["After win", "Payout to lottery balance", "Credit release; cash settled in period bills"], - ["Daily reconciliation", "Wallet ledger + transfer orders", "Settlement center credit ledger + bills"], - ["Agent payments", "Not applicable", "Settlement center period bills"] - ], - "note": "Credit-mode player UI uses release and period payment wording, not wallet-mode payout wording. The two modes cannot share one account." - }, - "manualReview": { - "title": "Manual review & payouts", - "description": "Covers draw result review, cooling period, per-draw payout settlement batches, and related system switches. This is separate from Settlement center credit-line periods.", - "figureAlt": "Draw review and payout flow diagram", - "distinction": "Difference from credit-line period settlement", - "distinctionItems": [ - "This guide: per-draw payout settlement batches (Daily operations → Settlement) — wallet mode pays out, credit mode posts draw ledger; runs every draw", - "Settlement center: credit-line period open/close/bill payments — aggregated by week/month etc.; not one-to-one with each draw", - "Approve and publish on draw detail: whether draw numbers take effect; settlement batch: how funds move after numbers are effective" - ], - "drawReview": "Manual draw result review", - "drawReviewItems": [ - "When System settings → Require manual review of draw results is on: after RNG generates numbers the draw is Pending review until someone clicks Approve and publish", - "When off: RNG results auto-publish (cooling period may still apply, see below)", - "Manual number entry: after submit, pending review or auto-publish depending on review switch", - "Entry: Daily operations → Draw list → draw detail → draw batch" - ], - "drawPublishSteps": "Publish draw results (step by step)", - "drawPublishStepItems": [ - "Open draw detail; confirm status is Pending draw or Pending review", - "If no result: click Generate draw result or enter numbers", - "Verify numbers match draw and play rules", - "Click Approve and publish", - "After publish, enters cooling period or Settling directly (see system settings)" - ], - "cooldown": "Cooling period", - "cooldownItems": [ - "System settings → Cooling period (minutes): wait after publish before payout settlement runs", - "During cooling, super admin may Redraw: rollback payouts/releases → regenerate → review and publish again", - "Set to 0 minutes: settlement runs immediately after publish, no cooling window", - "Cooling is the last window to verify numbers; unrelated to credit-line periods" - ], - "settlementBatch": "Per-draw payout settlement batch", - "settlementBatchItems": [ - "After each draw is published, the system auto (or manually) creates a settlement batch summarizing all ticket win/loss for that draw", - "Entry: Daily operations → Settlement → batch list; also from draw detail", - "Batch status: In progress → Pending review → Reviewed → Paid/Complete (automation may skip steps)", - "Wallet mode: Execute payout writes win amounts to player lottery balance", - "Credit mode: Execute payout writes draw settlement and share ledger; no cash balance increase" - ], - "batchStatusSection": "Settlement batch statuses", - "batchStatusRows": [ - ["In progress", "Calculating win/loss for this draw", "Wait for completion"], - ["Pending review", "Amounts calculated; awaiting finance/ops confirmation", "Approve / Reject"], - ["Reviewed", "Amounts confirmed; awaiting payout", "Execute payout"], - ["Paid", "Payout written to player account or credit ledger", "View detail, export"], - ["Rejected", "Review failed; tickets return to pending settlement", "Fix and rerun settlement"], - ["Failed", "Settlement process error", "Contact technical support"] - ], - "batchWalkthrough": "Manual review and payout (step by step)", - "batchWalkthroughSteps": [ - "Daily operations → Settlement → filter Pending review batches", - "Open batch detail; verify draw, ticket count, total stake, total payout, platform P&L", - "If consistent with draw result, click Approve; if not, Reject with notes", - "On Reviewed batch, click Execute payout — wallet balance credited, credit draw ledger created", - "After payout there is no one-click undo; wrong numbers require redraw during cooling on the draw" - ], - "settings": "Related system switches (platform super admin)", - "settingRows": [ - ["Require manual review of draw results", "Platform management → System settings → Draw rhythm & review", "RNG results need manual publish", "RNG results auto-publish"], - ["Cooling period duration", "Same as above", "Wait N minutes after publish before settlement", "Settlement immediately after publish"], - ["Auto-run settlement", "System settings → Settlement automation", "Settlement batch runs automatically when due", "Settlement must be triggered manually"], - ["Auto-approve settlement batch", "Same as above", "Batch auto-moves to Reviewed after settlement", "Manual approve required"], - ["Auto payout credit", "Same as above", "Execute payout automatically after review", "Manual Execute payout required"] - ], - "settingsNote": "Common production setup: manual draw review + cooling period + auto settlement run + manual batch review + auto or manual payout. Follow your organization's risk policy.", - "rejectNote": "Rejecting a settlement batch returns linked tickets to pending settlement; it does not rollback published draw numbers. If numbers are wrong, use draw redraw.", - "note": "Before closing a credit-line period, ensure all related draws in the period are Settled and payout batches complete; otherwise close will warn about unsettled tickets." - }, - "faq": { - "title": "FAQ", - "description": "Typical admin issues and how to handle them.", - "faqRows": [ - ["Credit ledger confusing", "See Fund operations guide; pending draw shows Bet hold only; after draw one Draw settlement per ticket — no double charge"], - ["Settlement batch vs Settlement center", "See Manual review & payouts; former is per-draw payout, latter is credit-line period bills"], - ["Wrong draw result", "Draw detail → super admin redraw during cooling → rollback → review and publish again → settle again"], - ["Player hall accepts bets but admin shows closed", "List status is DB snapshot; player hall is authoritative; check close_time and timezone"], - ["Transfer not received (wallet mode)", "Check wallet ledger status; handle pending in Reconciliation; verify your gateway logs"], - ["Integration site connectivity failed", "Confirm your wallet gateway is public HTTPS and implements balance/debit/credit APIs"], - ["Close period button unavailable", "Confirm no other in-progress period, all draws for period are settled, account is not bound to an agent"], - ["No record payment button", "Need settlement write permission; bill must be confirmed/partial paid/overdue with unpaid_amount > 0; must be payee"], - ["Agent cannot see wallet menus", "Bound agent accounts hide wallet/reconciliation; use site finance or super admin account"], - ["Cannot choose agent when creating player", "Site admin must choose owning agent; create downstream agent in Agent list first"], - ["Insufficient permission", "Contact your super admin or our support to assign menus in Role management"] - ], - "integration": "Technical integration", - "integrationItems": [ - "SSO, iframe, wallet gateway: see API Integration Docs", - "Error codes 8001–8005: API Integration Docs → Troubleshooting" - ], - "integrationLinkLabel": "View API Integration Docs" - } - } -} diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 4648a0c..4e13209 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -142,12 +142,8 @@ "notifications": "Notifications", "notificationsComingSoon": "Notifications are under development", "accountSettings": "Account settings", - "relatedDocs": "Documentation", "loggedOut": "Signed out" }, - "docs": { - "learnMore": "Read full guide" - }, "nav": { "home": "Home", "dashboard": "Dashboard", diff --git a/src/i18n/locales/en/config.json b/src/i18n/locales/en/config.json index 4500f74..ce1060d 100644 --- a/src/i18n/locales/en/config.json +++ b/src/i18n/locales/en/config.json @@ -53,8 +53,6 @@ "hub": { "description": "Jump to play rules, odds & rebate, jackpot, and risk cap by domain. The sidebar provides direct links; this page is an overview.", "integrationDesc": "site_code, JWT secrets, partner wallet URL, iframe allowlist", - "integrationGuideDesc": "SSO and wallet integration document for client engineering teams, with index, examples, and test flow", - "integrationGuideTitle": "Client integration guide", "integrationTitle": "Integration sites", "jackpotDesc": "Pool parameters and ledger records", "jackpotTitle": "Jackpot", @@ -66,9 +64,6 @@ "riskCapTitle": "Risk cap rules", "title": "Operations configuration" }, - "integrationGuide": { - "title": "Lottery client integration guide" - }, "integrationSites": { "adminAccountCreated": "Created site admin account {{username}}", "adminAccountSectionDescription": "Creating a site will also create one admin account bound to that site.", diff --git a/src/i18n/locales/en/integrationDocs.json b/src/i18n/locales/en/integrationDocs.json deleted file mode 100644 index b4d1188..0000000 --- a/src/i18n/locales/en/integrationDocs.json +++ /dev/null @@ -1,468 +0,0 @@ -{ - "shell": { - "title": "Lottery Integration Docs", - "admin": "Admin Console", - "adminLogin": "Admin Console" - }, - "nav": { - "overview": "Overview", - "api": "API", - "ship": "Release", - "home": "Overview", - "delivery": "Integration Delivery", - "quickstart": "Quick Start", - "fundamentals": "Fund Model", - "setup": "Integration Setup", - "sso": "Single Sign-On", - "iframe": "iframe Protocol", - "wallet": "Wallet Gateway", - "transfer": "Transfers (Reference)", - "errors": "Error Codes", - "troubleshooting": "Integration Troubleshooting", - "golive": "Go-Live Checklist", - "operations": "Operations Guide", - "adminGuide": "Admin Guide", - "apiReference": "API Integration Reference" - }, - "headers": { - "component": ["Component", "Responsibility", "Owner"], - "convention": ["Item", "Rule"], - "claim": ["Field", "Type", "Required", "Description"], - "param": ["Parameter", "Purpose"], - "methodPath": ["Method", "Path", ""], - "query": ["Parameter", "Type", ""], - "field": ["Field", "Type", "Description"], - "code": ["Error Code", "Description"], - "http": ["Status Code", "message", "Cause"], - "message": ["Direction", "Message Type", "Payload"], - "balance": ["Field", "Account", "Description"], - "call": ["Direction", "API", "Authentication"], - "sequence": ["Step", "Initiator", "Description"], - "envMap": ["Item", "Admin Integration Site", "Main-Site Config", "Description"], - "account": ["Account", "Password", "site_player_id"], - "contract": ["Scenario", "HTTP", "Response Body"], - "adminField": ["Field", "Description", "Example"], - "handoffTable": ["Item", "Description", "Owner"], - "env": ["Environment", "Example URL", "Description"], - "envelopeTable": ["Direction", "Message Fields", "Description"], - "faq": ["Symptom", "Troubleshooting Direction"] - }, - "pages": { - "overview": { - "title": "Integration Overview", - "description": "For main-site developers and integration engineers. You implement: JWT issuance + wallet gateway; we provide H5 and API.", - "roles": "Responsibility Split", - "flow": "Business Flow", - "e2eSequence": "End-to-End Sequence", - "conventions": "General Conventions", - "readingOrder": "Recommended Reading Order", - "matrix": [ - ["Main Site (Partner)", "User login; server-side JWT issuance; wallet gateway implementation", "Partner"], - ["Lottery API (Us)", "JWT verification, transfers, betting, draw, settlement", "Us"], - ["Lottery H5 (Us)", "Player UI; iframe embed or URL redirect entry", "Us"] - ], - "flowItems": [ - "User logs in on main site → main-site server issues short-lived JWT", - "Enter lottery H5 (iframe embed or URL ?token= redirect)", - "Player taps \"Transfer In\" in H5 → lottery callbacks main site to debit → credits lottery balance", - "Player bets / receives winnings in H5 (using in-lottery balance)", - "(Optional) Player taps \"Transfer Out\" in H5 → lottery callbacks main site to credit" - ], - "e2eRows": [ - ["1", "Main Site", "User logs in; server issues JWT (includes site_code, site_player_id)"], - ["2", "Main Site", "Embed lottery H5 in iframe, or redirect to lottery_h5_base_url/?token="], - ["3", "Lottery H5", "Receives JWT; calls GET /api/v1/player/me to verify and auto-provision"], - ["4", "Player", "Taps \"Transfer In\" in H5"], - ["5", "Lottery API", "Server callbacks main site POST /wallet/debit-for-lottery"], - ["6", "Main-Site Wallet", "Debits main_balance; returns success: true"], - ["7", "Lottery API", "Credits in-lottery balance"], - ["8", "Player", "Bets / awaits winnings in H5"], - ["9", "Player", "(Optional) Taps \"Transfer Out\" in H5"], - ["10", "Lottery API", "Callbacks main site POST /wallet/credit-from-lottery"] - ], - "conventionRows": [ - ["Amount", "Integer in minor currency units, e.g. 2000 = 20.00 NPR"], - ["Encoding", "UTF-8 JSON"], - ["Time", "JWT uses Unix seconds (iat / exp); recommend exp - iat ≤ 300 seconds"], - ["Player API Auth", "Authorization: Bearer {JWT} (issued by main site, verified by lottery)"], - ["Wallet Gateway Auth", "Authorization: Bearer {wallet_api_key} (sent by lottery on callbacks)"] - ], - "readingItems": [ - "Integration Delivery — confirm deliverables and environment URLs for both parties", - "Quick Start — complete first integration test step by step", - "Integration Setup — admin site provisioning and key mapping", - "Single Sign-On → iframe Protocol → Wallet Gateway", - "Integration Troubleshooting — common issues", - "Go-Live Checklist — production release checks" - ] - }, - "delivery": { - "title": "Integration Delivery", - "description": "Before integration testing begins, confirm the following deliverables with sales/technical support. Test and production environments must be fully isolated.", - "handoffScope": "Integration Scope (What You Need to Do)", - "weProvide": "We Provide", - "youProvide": "Partner Must Provide", - "environment": "Environment URLs", - "process": "Typical Integration Process", - "note": "Secrets (sso_jwt_secret, wallet_api_key) are shown only once at creation. Save them securely immediately. Secrets must be stored on the main-site server only — never in frontend or mobile apps. URLs below are Tanumo’s current defaults; partner-specific deployments follow sales delivery.", - "handoffRows": [ - ["JWT Issuance", "Main site issues HS256 JWT server-side after login; no \"login-for-token\" API", "Partner"], - ["Wallet Gateway", "Implement three HTTPS endpoints: balance / debit / credit", "Partner"], - ["iframe or URL Entry", "Embed lottery H5 or redirect with JWT", "Partner"], - ["Lottery H5 + API", "Games, transfers, betting, draw", "Us"], - ["Integration Site & Keys", "Create site_code and deliver secrets", "Us (Super Admin)"] - ], - "provideRows": [ - ["site_code", "Site code, written into JWT"], - ["sso_jwt_secret", "JWT signing secret (held and used by main site to sign)"], - ["wallet_api_key", "Bearer secret when lottery callbacks wallet gateway"], - ["lottery_h5_base_url", "Lottery H5 entry (iframe src or redirect); default https://front.tanumo.com"], - ["lottery_api_base_url", "Lottery API base (curl); default https://lotterylaravel.tanumo.com"] - ], - "submitRows": [ - ["wallet_api_url", "Partner wallet gateway HTTPS root URL (publicly reachable)"], - ["iframe_allowed_origins", "Main-site origin allowlist (required for iframe mode, one per line)"], - ["Test Accounts", "Several site_player_id values with initial main_balance (for integration testing)"], - ["Egress IP (if needed)", "If gateway has IP allowlist, request lottery server egress IP"] - ], - "environmentRows": [ - ["Lottery API", "https://lotterylaravel.tanumo.com", "curl: GET /api/v1/player/me"], - ["Lottery H5 entry", "https://front.tanumo.com", "iframe / ?token=; wallet page example /wallet"], - ["Integration docs", "https://lotteryadmin.tanumo.com/docs/integration", "This documentation (public)"], - ["Admin console", "https://lotteryadmin.tanumo.com/admin", "Super admin; integration sites: Config → Integration sites"], - ["Production Environment", "Separate domain and secrets", "site_code, secrets, and domains must not be shared with integration"] - ], - "processSteps": [ - "Sales enables integration → our super admin creates \"Integration Site\" and delivers secrets and H5 URL", - "Partner implements three wallet endpoints and deploys to public HTTPS (integration may use tunnel first)", - "Partner fills wallet_api_url and iframe_allowed_origins in admin, runs connectivity test", - "Partner implements JWT issuance and iframe postMessage (or URL redirect)", - "Complete integration testing per Quick Start acceptance checklist", - "Production: re-provision site, rotate secrets, full end-to-end retest before go-live" - ] - }, - "quickstart": { - "title": "Quick Start", - "description": "Assumes Integration Delivery is complete and you have site_code, secrets, and H5 URL. Follow these steps for first integration test.", - "prereq": "Prerequisites", - "steps": "Integration Steps", - "acceptance": "Acceptance Checklist", - "note": "JWT must be issued on the main-site server — never hardcode sso_jwt_secret in frontend. Production wallet_api_url must be public HTTPS.", - "prereqItems": [ - "Received site_code, sso_jwt_secret, wallet_api_key, lottery_h5_base_url", - "Main site implements GET /wallet/balance, POST /wallet/debit-for-lottery, POST /wallet/credit-from-lottery", - "Admin \"Integration Site\" has wallet_api_url and iframe_allowed_origins filled; connectivity test passed", - "At least one test site_player_id prepared with sufficient main_balance" - ], - "stepItems": [ - "Main-site server implements JWT issuance (see Single Sign-On jsonwebtoken example)", - "Self-test with curl: Bearer JWT call GET https://lotterylaravel.tanumo.com/api/v1/player/me, should return code=0", - "Main-site page embeds - - -`; - -const JWT_SIGN_TS = `const header = base64url(JSON.stringify({ alg: "HS256", typ: "JWT" })); -const payload = base64url(JSON.stringify({ - site_code: "demo", - site_player_id: "100001", - iat: Math.floor(Date.now() / 1000), - exp: Math.floor(Date.now() / 1000) + 300, -})); -const sig = hmacSha256Base64url(\`\${header}.\${payload}\`, SSO_JWT_SECRET); -const token = \`\${header}.\${payload}.\${sig}\`;`; - -export function ApiReferenceDocScreen(): React.ReactElement { - return ( - - - - - - - 金额一律使用最小货币单位整数(minor),如 2000 = 20.00。编码 UTF-8 JSON。 - - - - - - 最小验证步骤: - {CURL_PLAYER_ME} - {CURL_WALLET_BALANCE} - {CURL_WALLET_DEBIT} - - - - - - - 测试与生产环境的 site_code、密钥、域名须完全隔离。生产环境 wallet_api_url 仅允许 HTTPS 公网地址,拒绝 localhost / 私网 IP。 - - - - - 采用 HS256 JWT。主站签发,彩票验签。 - - {JWT_SIGN_TS} - - - 方式 A — URL 跳转: - {`https://{lottery_h5_base_url}/?token={JWT}`} - 方式 B — iframe 嵌入: - {``} - - 首次有效 JWT 调用 GET /api/v1/player/me 时自动建档。username / nickname 由彩票生成,不从主站同步。 - - - - - - {`GET /api/v1/player/me -Authorization: Bearer {JWT} -Accept-Language: zh`} - - 彩票不提供「登录换票」接口。主站登录后自行签发 JWT,玩家 API 统一用 Authorization: Bearer 携带。 - - - - - - - - - - ", - "彩票 H5 加载白名单后发送 LOTTERY_READY", - "主站监听 message,校验 origin 后发送 MAIN_INIT_TOKEN", - "彩票 H5 保存 token,调用 /api/v1/player/me 入场", - "Token 将过期时:彩票发 LOTTERY_TOKEN_NEEDED → 主站续签后发 MAIN_REFRESH_TOKEN", - ]} - /> - - postMessage 第二参数须为具体 origin(如 https://www.partner.com),禁止使用 *。 - 收到 MAIN_INIT_TOKEN 后彩票子页不再发送 LOTTERY_READY,避免重复下发 token。 - - - - - - - - - - - - {IFRAME_EXAMPLE} - - - - - - 由客户实现。彩票服务端调用。鉴权:Authorization: Bearer {"{wallet_api_key}"}。 - - - - - - {`{ - "success": true, - "data": { "main_balance": 500000, "currency_code": "NPR" } -}`} - - - - - - {`{ - "success": true, - "external_ref_no": "MW-001", - "data": { "main_balance": 498000, "currency_code": "NPR" } -}`} - - - - - 请求体与扣款相同。用于转出或失败回滚加款。 - - - - - - - - idempotent_key:相同键 + 相同操作须返回首次 JSON(HTTP 200),禁止重复记账;同键不同操作/金额 → success: false。 - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/src/modules/docs/integration/integration-doc-data.ts b/src/modules/docs/integration/integration-doc-data.ts deleted file mode 100644 index 74c61e3..0000000 --- a/src/modules/docs/integration/integration-doc-data.ts +++ /dev/null @@ -1,194 +0,0 @@ -/** 文档默认环境地址(当前 Tanumo 部署;客户独立环境以商务交付为准) */ -export const DOC_ENV = { - lotteryH5Origin: "https://front.tanumo.com", - lotteryH5Wallet: "https://front.tanumo.com/wallet", - lotteryApiBase: "https://lotterylaravel.tanumo.com", - adminBase: "https://lotteryadmin.tanumo.com", - integrationDocs: "https://lotteryadmin.tanumo.com/docs/integration", - integrationSitesAdmin: "https://lotteryadmin.tanumo.com/admin/config/integration-sites", -} as const; - -/** 代码示例(语言无关,三语共用) */ -export const SSO_JWT_PAYLOAD_EXAMPLE = `{ - "site_code": "demo", - "site_player_id": "100001", - "iat": 1718000000, - "exp": 1718000300 -}`; - -export const SSO_JWT_SIGN_EXAMPLE = `import jwt from "jsonwebtoken"; - -const token = jwt.sign( - { - site_code: "demo", - site_player_id: "100001", - }, - process.env.MAIN_SITE_SSO_JWT_SECRET!, - { - algorithm: "HS256", - expiresIn: 300, - }, -);`; - -export const SSO_ENTRY_URL = `${DOC_ENV.lotteryH5Origin}/?token={JWT}`; - -export const SSO_POSTMESSAGE = `iframe.contentWindow.postMessage( - { type: "MAIN_INIT_TOKEN", token: jwt, source: "main-site" }, - "${DOC_ENV.lotteryH5Origin}" -);`; - -export const PLAYER_ME_REQUEST = `GET ${DOC_ENV.lotteryApiBase}/api/v1/player/me -Authorization: Bearer {JWT} -Accept-Language: zh`; - -export const PLAYER_ME_SUCCESS = `{ - "code": 0, - "msg": "success", - "data": { - "id": 42, - "site_code": "demo", - "site_player_id": "100001", - "auth_source": "main_site_sso", - "funding_mode": "wallet", - "username": null, - "nickname": null, - "default_currency": "NPR", - "status": 0, - "locale": "zh", - "last_login_at": "2026-06-14T10:00:00+00:00", - "created_at": "2026-06-14T10:00:00+00:00" - } -}`; - -export const IFRAME_CHILD_READY = `{ - "type": "LOTTERY_READY", - "payload": { "url": "${DOC_ENV.lotteryH5Origin}/", "userAgent": "..." }, - "timestamp": 1718000000000, - "source": "lottery-iframe" -}`; - -export const IFRAME_PARENT_INIT = `{ - "type": "MAIN_INIT_TOKEN", - "token": "eyJhbGciOiJIUzI1NiIs...", - "timestamp": 1718000000000, - "source": "main-site" -}`; - -export const IFRAME_INTEGRATION_EXAMPLE = ` -`; - -export const ACCEPTANCE_PLAYER_ME = `curl -sS "${DOC_ENV.lotteryApiBase}/api/v1/player/me" \\ - -H "Authorization: Bearer {JWT}" \\ - -H "Accept: application/json"`; - -export const ACCEPTANCE_WALLET_DEBIT = `curl -sS -X POST "https://{wallet_host}/wallet/debit-for-lottery" \\ - -H "Authorization: Bearer {wallet_api_key}" \\ - -H "Content-Type: application/json" \\ - -d '{ - "site_code": "demo", - "site_player_id": "100001", - "player_id": 42, - "currency_code": "NPR", - "amount_minor": 100, - "idempotent_key": "accept-debit-001" - }'`; - -export const PLAYER_AUTH_ERROR = `HTTP/1.1 401 Unauthorized - -{ - "code": 8002, - "msg": "Token 无效或已过期", - "data": null -}`; - -export const WALLET_BALANCE_RESPONSE = `{ - "success": true, - "data": { "main_balance": 500000, "currency_code": "NPR" } -}`; - -export const WALLET_DEBIT_REQUEST = `POST /wallet/debit-for-lottery -Authorization: Bearer {wallet_api_key} - -{ - "site_code": "demo", - "site_player_id": "100001", - "player_id": 42, - "currency_code": "NPR", - "amount_minor": 2000, - "idempotent_key": "TI-20260610-abc" -}`; - -export const WALLET_SUCCESS = `{ - "success": true, - "external_ref_no": "MW-001", - "data": { "main_balance": 498000, "currency_code": "NPR" } -}`; - -export const WALLET_FAIL = `{ - "success": false, - "message": "main balance insufficient", - "data": { "main_balance": 500, "currency_code": "NPR" } -}`; - -export const WALLET_CREDIT_REQUEST = `POST /wallet/credit-from-lottery -Authorization: Bearer {wallet_api_key} - -{ - "site_code": "demo", - "site_player_id": "100001", - "player_id": 42, - "currency_code": "NPR", - "amount_minor": 2000, - "idempotent_key": "TO-20260610-abc" -}`; - -export const TRANSFER_IN = `POST /api/v1/wallet/transfer-in -Authorization: Bearer {player_jwt} - -{ "amount": 2000, "currency": "NPR", "idempotent_key": "ti-001" }`; - -export const TRANSFER_OUT = `POST /api/v1/wallet/transfer-out -Authorization: Bearer {player_jwt} - -{ "amount": 1000, "currency": "NPR", "idempotent_key": "to-001" }`; - -export const TRANSFER_SUCCESS = `{ - "code": 0, - "msg": "success", - "data": { - "transfer_no": "TI20260614001", - "direction": "in", - "currency_code": "NPR", - "amount": 2000, - "status": "success", - "external_ref_no": "debit-for-lottery-1718360000-a1b2c3", - "balance": 2000, - "log_id": "WX_20260614_0001", - "lottery_balance_after": 2000, - "lottery_available_after": 2000, - "finished_at": "2026-06-14T10:00:00+00:00" - } -}`; diff --git a/src/modules/docs/integration/integration-doc-screens.tsx b/src/modules/docs/integration/integration-doc-screens.tsx deleted file mode 100644 index fb452a5..0000000 --- a/src/modules/docs/integration/integration-doc-screens.tsx +++ /dev/null @@ -1,359 +0,0 @@ -"use client"; - -import { - DocCode, - DocEndpoint, - DocList, - DocNote, - DocOrderedList, - DocPage, - DocPageHeader, - DocSection, - DocTable, -} from "@/components/docs/doc-ui"; -import { - SSO_ENTRY_URL, - SSO_JWT_PAYLOAD_EXAMPLE, - SSO_JWT_SIGN_EXAMPLE, - SSO_POSTMESSAGE, - ACCEPTANCE_PLAYER_ME, - ACCEPTANCE_WALLET_DEBIT, - IFRAME_CHILD_READY, - IFRAME_INTEGRATION_EXAMPLE, - IFRAME_PARENT_INIT, - PLAYER_AUTH_ERROR, - PLAYER_ME_REQUEST, - PLAYER_ME_SUCCESS, - TRANSFER_IN, - TRANSFER_OUT, - TRANSFER_SUCCESS, - WALLET_BALANCE_RESPONSE, - WALLET_CREDIT_REQUEST, - WALLET_DEBIT_REQUEST, - WALLET_FAIL, - WALLET_SUCCESS, -} from "@/modules/docs/integration/integration-doc-data"; -import { useIntegrationDoc } from "@/modules/docs/integration/use-integration-doc"; - -export function OverviewDocScreen(): React.ReactElement { - const { p, rows, list, header } = useIntegrationDoc("overview"); - - return ( - - - - - - - - - - - - - - - - - - - ); -} - -export function DeliveryDocScreen(): React.ReactElement { - const { p, rows, list, header } = useIntegrationDoc("delivery"); - - return ( - - - - - - - - - - - - - - - - - - {p("note")} - - ); -} - -export function QuickstartDocScreen(): React.ReactElement { - const { p, list } = useIntegrationDoc("quickstart"); - - return ( - - - - - - - - - - - {ACCEPTANCE_PLAYER_ME} - {ACCEPTANCE_WALLET_DEBIT} - - {p("note")} - - ); -} - -export function FundamentalsDocScreen(): React.ReactElement { - const { p, rows, header } = useIntegrationDoc("fundamentals"); - - return ( - - - - - - - - - {p("note")} - - ); -} - -export function SetupDocScreen(): React.ReactElement { - const { p, rows, list, header } = useIntegrationDoc("setup"); - - return ( - - - - - - - - - - - - - - - - - - - - - - {p("note")} - - ); -} - -export function SsoDocScreen(): React.ReactElement { - const { p, rows, header } = useIntegrationDoc("sso"); - - return ( - - - - - {SSO_JWT_PAYLOAD_EXAMPLE} - - - {SSO_JWT_SIGN_EXAMPLE} - - {p("noExchangeNote")} - - {SSO_ENTRY_URL} - - - - {SSO_POSTMESSAGE} - {p("iframeNote")} - - - - {p("entryApiNote")} - {PLAYER_ME_REQUEST} - {PLAYER_ME_SUCCESS} - - - - - {p("h5ScopeNote")} - {p("refreshNote")} - - {PLAYER_AUTH_ERROR} - - - - - - ); -} - -export function IframeDocScreen(): React.ReactElement { - const { p, rows, list, header } = useIntegrationDoc("iframe"); - - return ( - - - - - - - - {p("envelopeNote")} - - - - {IFRAME_CHILD_READY} - - - - {IFRAME_PARENT_INIT} - - - {IFRAME_INTEGRATION_EXAMPLE} - - - {p("targetOriginNote")} - - {p("timingNote")} - - ); -} - -export function WalletDocScreen(): React.ReactElement { - const { p, rows, header } = useIntegrationDoc("wallet"); - - return ( - - - - - - {WALLET_BALANCE_RESPONSE} - - - - - {WALLET_DEBIT_REQUEST} - - - - {WALLET_CREDIT_REQUEST} - {p("creditNote")} - - - - - -
- {WALLET_SUCCESS} - {WALLET_FAIL} -
-
- - - - {p("idempotentNote")} -
- ); -} - -export function TransferDocScreen(): React.ReactElement { - const { p, rows, header } = useIntegrationDoc("transfer"); - - return ( - - - {p("outOfScopeNote")} - - - - - - {p("inNote")} - {TRANSFER_IN} - - - - {p("outNote")} - {TRANSFER_OUT} - - - {p("responseNote")} - {TRANSFER_SUCCESS} - - - - - - ); -} - -export function ErrorsDocScreen(): React.ReactElement { - const { p, rows, header } = useIntegrationDoc("errors"); - - return ( - - - - - - - - - - - - {p("idempotentNote")} - - ); -} - -export function GoLiveDocScreen(): React.ReactElement { - const { p, list } = useIntegrationDoc("golive"); - - return ( - - - - - - - - - - ); -} - -export function TroubleshootingDocScreen(): React.ReactElement { - const { p, rows, header } = useIntegrationDoc("troubleshooting"); - - return ( - - - - - - - - - - - - - - - {p("note")} - - ); -} diff --git a/src/modules/docs/integration/use-integration-doc.ts b/src/modules/docs/integration/use-integration-doc.ts deleted file mode 100644 index d51d786..0000000 --- a/src/modules/docs/integration/use-integration-doc.ts +++ /dev/null @@ -1,44 +0,0 @@ -"use client"; - -import { useTranslation } from "react-i18next"; - -type DocPageKey = - | "overview" - | "delivery" - | "quickstart" - | "fundamentals" - | "setup" - | "sso" - | "iframe" - | "wallet" - | "transfer" - | "errors" - | "troubleshooting" - | "golive"; - -const INTEGRATION_DOCS_NS = "integrationDocs"; - -function asStringArray(value: unknown): string[] { - return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : []; -} - -function asStringMatrix(value: unknown): string[][] { - return Array.isArray(value) - ? value.filter((row): row is string[] => Array.isArray(row) && row.every((cell) => typeof cell === "string")) - : []; -} - -export function useIntegrationDoc(page: DocPageKey) { - const { t } = useTranslation(INTEGRATION_DOCS_NS); - - return { - t, - p: (key: string) => t(`pages.${page}.${key}`, { ns: INTEGRATION_DOCS_NS }), - rows: (key: string) => - asStringMatrix(t(`pages.${page}.${key}`, { returnObjects: true, ns: INTEGRATION_DOCS_NS })), - list: (key: string) => - asStringArray(t(`pages.${page}.${key}`, { returnObjects: true, ns: INTEGRATION_DOCS_NS })), - header: (key: string) => - asStringArray(t(`headers.${key}`, { returnObjects: true, ns: INTEGRATION_DOCS_NS })), - }; -}