diff --git a/frontend-dapp/src/config/omnlInternalPaths.ts b/frontend-dapp/src/config/omnlInternalPaths.ts new file mode 100644 index 0000000..2302c1b --- /dev/null +++ b/frontend-dapp/src/config/omnlInternalPaths.ts @@ -0,0 +1,109 @@ +/** + * Same-origin internal path map for hub /docs and in-portal navigation. + * SSOT: proxmox repo config/omnl-internal-paths.v1.json — keep in sync on edits. + */ +export type InternalPathEntry = { + label: string; + path: string; + method?: string; + auth?: string; + notes?: string; +}; + +export type InternalPathGroup = { + id: string; + label: string; + entries: InternalPathEntry[]; +}; + +export const INTERNAL_PATH_POLICY = { + internalLinks: + 'Same-origin paths only — no FQDNs, localhost, or 127.0.0.1 in portal navigation or /docs links.', + nginxRequired: + 'API prefixes /settlement/, /exchange/, /api/v1/, /omnl/ require nginx in front of the SPA (production LXC or dev deploy-omnl-domains.sh).', + externalShare: + 'Institutional share URLs (https://… FQDNs) are documented in operator manifests — not used as internal links.', +} as const; + +export const INTERNAL_PATH_PREFIXES = [ + { label: 'Settlement', prefix: '/settlement', upstream: '/api/v1/settlement', port: 3011 }, + { label: 'Exchange', prefix: '/exchange', upstream: '/api/v1/exchange', port: 3012 }, + { label: 'OMNL API', prefix: '/api/v1', upstream: '/api/v1', port: 3000 }, + { label: 'OMNL HTML', prefix: '/omnl', upstream: '/omnl', port: 3000 }, +] as const; + +export const INTERNAL_PATH_FORBIDDEN = [ + '/settlement/api/v1/settlement/', + '/exchange/api/v1/exchange/', + 'z-bank/settle-m0-m4', +] as const; + +export const INTERNAL_PATH_GROUPS: InternalPathGroup[] = [ + { + id: 'spa', + label: 'React SPA', + entries: [ + { label: 'DBIS Hub', path: '/hub' }, + { label: 'Central Bank', path: '/central-bank' }, + { label: 'M0→M4 panel', path: '/central-bank#z-full-settlement' }, + { label: 'Settlement protocols', path: '/central-bank#z-settlement-protocols' }, + { label: 'Office 24', path: '/office-24' }, + { label: 'DBIS Trade', path: '/trade' }, + { label: 'Digital Swap', path: '/swap' }, + { label: 'Bridge', path: '/bridge' }, + { label: 'Reserve', path: '/reserve' }, + { label: 'History', path: '/history' }, + { label: 'Wallets', path: '/wallets' }, + { label: 'Admin', path: '/admin' }, + { label: 'API docs', path: '/docs' }, + ], + }, + { + id: 'settlement', + label: 'Settlement API', + entries: [ + { method: 'GET', path: '/settlement/health', auth: 'none' }, + { method: 'GET', path: '/settlement/public/money-supply', auth: 'none' }, + { method: 'GET', path: '/settlement/chains', auth: 'none' }, + { method: 'POST', path: '/settlement/external-transfer', auth: 'super-admin', notes: '→ Fineract journals' }, + { method: 'POST', path: '/settlement/token-load', auth: 'super-admin' }, + { method: 'POST', path: '/settlement/transfer/external', auth: 'super-admin' }, + ], + }, + { + id: 'exchange', + label: 'Exchange API', + entries: [ + { method: 'GET', path: '/exchange/health', auth: 'none' }, + { method: 'GET', path: '/exchange/tokens', auth: 'read' }, + { method: 'GET', path: '/exchange/quote', auth: 'read' }, + { method: 'POST', path: '/exchange/plan', auth: 'trade' }, + { method: 'POST', path: '/exchange/swap/settle', auth: 'admin' }, + ], + }, + { + id: 'omnl-api', + label: 'OMNL API', + entries: [ + { method: 'GET', path: '/api/v1/omnl/catalog', auth: 'none' }, + { method: 'GET', path: '/api/v1/omnl/openapi.json', auth: 'none' }, + { method: 'GET', path: '/api/v1/omnl/health', auth: 'omnl-key-in-production' }, + { method: 'GET', path: '/api/v1/omnl/ipsas/fineract-health', auth: 'omnl-key-in-production' }, + ], + }, + { + id: 'omnl-html', + label: 'OMNL HTML consoles', + entries: [ + { path: '/omnl/compliance', label: 'Compliance' }, + { path: '/omnl/dashboard', label: 'Dashboard' }, + { path: '/omnl/terminal', label: 'Terminal' }, + ], + }, +]; + +export const INTERNAL_STACK_FLOW = [ + 'POST /settlement/external-transfer → settlement-middleware → Fineract POST /journalentries', + 'GET /settlement/public/money-supply ← Fineract GL (fineractConnected / fineractLive)', + 'GET /api/v1/omnl/ipsas/fineract-health → probes Fineract /glaccounts?limit=1', +] as const; diff --git a/frontend-dapp/src/features/omnl-dashboard/QuickPortalLinks.tsx b/frontend-dapp/src/features/omnl-dashboard/QuickPortalLinks.tsx index 4c5e795..e1d730c 100644 --- a/frontend-dapp/src/features/omnl-dashboard/QuickPortalLinks.tsx +++ b/frontend-dapp/src/features/omnl-dashboard/QuickPortalLinks.tsx @@ -1,28 +1,30 @@ -import NasaIcon from '../../components/icons/NasaIcon'; - -const LINKS = [ - { label: 'Central Bank', href: 'https://secure.omdnl.org/central-bank', icon: 'central-bank' as const }, - { label: 'Online banking', href: 'https://online.omdnl.org/central-bank', icon: 'globe' as const }, - { label: 'Office 24', href: 'https://office24.omdnl.org/office-24', icon: 'office' as const }, - { label: 'DBIS Trade', href: 'https://exchange.omdnl.org/trade', icon: 'trade' as const }, - { label: 'Digital swap', href: 'https://digital.omdnl.org/swap', icon: 'swap' as const }, -] as const; - -export default function QuickPortalLinks() { - return ( -
-

- - Public portals -

-
- {LINKS.map(({ label, href, icon }) => ( - - - {label} - - ))} -
-
- ); -} +import { Link } from 'react-router-dom'; +import NasaIcon from '../../components/icons/NasaIcon'; + +/** Same-origin portal surfaces — no FQDNs (see /docs). */ +const LINKS = [ + { label: 'Central Bank', to: '/central-bank', icon: 'central-bank' as const }, + { label: 'Office 24', to: '/office-24', icon: 'office' as const }, + { label: 'DBIS Trade', to: '/trade', icon: 'trade' as const }, + { label: 'Digital swap', to: '/swap', icon: 'swap' as const }, + { label: 'API paths', to: '/docs', icon: 'link' as const }, +] as const; + +export default function QuickPortalLinks() { + return ( +
+

+ + Portal surfaces +

+
+ {LINKS.map(({ label, to, icon }) => ( + + + {label} + + ))} +
+
+ ); +} diff --git a/frontend-dapp/src/pages/DocsPage.tsx b/frontend-dapp/src/pages/DocsPage.tsx index 7378865..0a25988 100644 --- a/frontend-dapp/src/pages/DocsPage.tsx +++ b/frontend-dapp/src/pages/DocsPage.tsx @@ -1,18 +1,157 @@ /** - * Developer / API documentation. Not shown in main UI. + * Developer / API documentation — same-origin internal path map. */ +import { Link } from 'react-router-dom'; +import { + INTERNAL_PATH_FORBIDDEN, + INTERNAL_PATH_GROUPS, + INTERNAL_PATH_POLICY, + INTERNAL_PATH_PREFIXES, + INTERNAL_STACK_FLOW, +} from '../config/omnlInternalPaths'; + +function PathCode({ path }: { path: string }) { + const isSpa = INTERNAL_PATH_GROUPS.find((g) => g.id === 'spa')?.entries.some((e) => e.path === path); + if (isSpa) { + return ( + + {path} + + ); + } + return {path}; +} + export default function DocsPage() { return ( -
+

Developer reference

- For swap+bridge+swap (Dodoex PMM): use POST /api/bridge/quote with{' '} - sourceToken, destinationToken,{' '} - sourceChainId, destinationChainId,{' '} - amount. Response includes{' '} - sourceSwapQuote,{' '} - destinationSwapQuote,{' '} - minReceived. + Internal links use same-origin paths only — no FQDNs, + localhost, or 127.0.0.1. Institutional share URLs live in operator manifests. +

+ +
+

Policy

+
    +
  • {INTERNAL_PATH_POLICY.internalLinks}
  • +
  • {INTERNAL_PATH_POLICY.nginxRequired}
  • +
  • {INTERNAL_PATH_POLICY.externalShare}
  • +
+
+ +
+

Nginx prefixes

+
+ + + + + + + + + + + {INTERNAL_PATH_PREFIXES.map((row) => ( + + + + + + + ))} + +
LayerPortal prefixService pathPort
{row.label} + {row.prefix}/ + + {row.upstream} + {row.port}
+
+
+ + {INTERNAL_PATH_GROUPS.map((group) => ( +
+

{group.label}

+
+ + + + {(group.id === 'spa' || group.id === 'omnl-html') && ( + + )} + {group.id !== 'spa' && group.id !== 'omnl-html' && ( + + )} + + {group.id !== 'spa' && group.id !== 'omnl-html' && ( + + )} + {group.id !== 'spa' && group.id !== 'omnl-html' && ( + + )} + + + + {group.entries.map((entry) => ( + + {(group.id === 'spa' || group.id === 'omnl-html') && ( + + )} + {group.id !== 'spa' && group.id !== 'omnl-html' && ( + + )} + + {group.id !== 'spa' && group.id !== 'omnl-html' && ( + + )} + {group.id !== 'spa' && group.id !== 'omnl-html' && ( + + )} + + ))} + +
LabelMethodPathAuthNotes
{entry.label}{entry.method ?? '—'} + + {entry.auth ?? '—'}{entry.notes ?? ''}
+
+
+ ))} + +
+

Stack flow (paths only)

+
    + {INTERNAL_STACK_FLOW.map((line) => ( +
  • {line}
  • + ))} +
+
+ +
+

Forbidden patterns

+
    + {INTERNAL_PATH_FORBIDDEN.map((p) => ( +
  • + {p} +
  • + ))} +
+
+ +
+

Bridge quote API

+

+ For swap+bridge+swap (DODO PMM):{' '} + POST /api/v1/bridge/quote with{' '} + sourceToken,{' '} + destinationToken, chain IDs, and{' '} + amount. +

+
+ +

+ SSOT: config/omnl-internal-paths.v1.json · Operator map:{' '} + docs/04-configuration/ZARDASHT_ENDPOINT_MAP.md

);