diff --git a/HANDOFF.md b/HANDOFF.md index 30abae6..e9c67a7 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -1,6 +1,6 @@ # Payment Intelligence Modules — handoff -_Last updated: 2026-05-05 21:30 SGT_ +_Last updated: 2026-05-07 17:07 +08_ This is the next-session entry point for `Raafet57/payment-intelligence-modules`. Read this file first, then check live `git` / GitHub state before acting. @@ -9,22 +9,22 @@ Read this file first, then check live `git` / GitHub state before acting. - Repository: `https://github.com/Raafet57/payment-intelligence-modules` - Local path on Hermes: `/Users/Shared/AgentWork/repos/payment-intelligence-modules` -- Active feature branch for SSI work: `feat/ssi-hybrid-instruction-flow` -- SSI Control Tower is being folded into `apps/ssi-control-tower/` as a separate FastAPI/Jinja backend module. The root Vite/React browser suite remains static/browser-only, and root `src/` plus `scripts/privacy-audit.sh src` must stay scoped to the browser runtime. +- Product baseline before the current branch: `c31575c` — merge commit for PR #11, which folded SSI Control Tower into `apps/ssi-control-tower/`. +- Active feature branch for unified SSI UI integration: `feat/ssi-unified-ui-integration` +- Deployment/release/tag/public announcement: **not done** -## Previous handoff snapshot +## Current branch scope -- Repository: `https://github.com/Raafet57/payment-intelligence-modules` -- Local path on Hermes: `/Users/Shared/AgentWork/repos/payment-intelligence-modules` -- Branch to start from next time: `main` -- Product code baseline at handoff: `1dae872` — merge commit for PR #10 -- Latest merged PR: [#10 — `feat: expand IBAN workbench`](https://github.com/Raafet57/payment-intelligence-modules/pull/10) -- PR #10 branch commit: `45818c2 feat: expand IBAN workbench` -- Post-merge `main` CI run: `25379147860` — `success` -- Feature branch cleanup: `feat/iban-workbench` deleted locally and remotely after same-tree proof -- Deployment/release/tag/public announcement: **not done** +This branch adds the first unified-suite UI slice for SSI Control Tower while preserving the root static/browser-only privacy boundary. + +Implemented shape: -After this handoff file is committed, there may be a later docs-only `main` commit. Treat `1dae872` as the shipped product-code baseline and the handoff commit as documentation only. +- New root-suite route: `/ssi`. +- New static page: `src/pages/SsiPage.tsx`. +- SSI appears in the suite header nav and Home module grid with `Backend` status. +- The `/ssi` page documents the folded FastAPI/Jinja app posture and local run path without coupling to the backend runtime. +- No root-suite API call, iframe, storage, telemetry, external request, or clickable localhost link was added. +- README and ROADMAP route lists/docs include `/ssi` and clarify root-browser-runtime boundaries. ## Modules currently in the browser suite @@ -36,80 +36,54 @@ After this handoff file is committed, there may be a later docs-only `main` comm | BIC Validator | `/bic` | Demo/snapshot-bound only; not current-production BIC Directory validation. | | CBPR+ Readiness Checker | `/cbpr` | Local readiness/structure checks only; not certified/full XSD/MyStandards validation. | | Payment Insights Lite | `/insights` | Local lifecycle insight over files the user provides; not live payment tracking. | +| SSI Control Tower | `/ssi` | Static entry page for the folded backend module under `apps/ssi-control-tower/`. | -## What was completed today - -1. **CBPR+ Readiness Checker** merged earlier as PR #4. -2. **raafetchoukri.com design polish** merged as PR #5. -3. **Storyteller operator workbench refinement** merged as PR #6. -4. **Payment Insights Lite** added and merged as PR #7. -5. **Payment Insights hardening/refactor** merged as PR #8. -6. **Insights CI hotfix** merged as PR #9, restoring green `main` CI. -7. **IBAN Workbench** merged as PR #10. - -## IBAN Workbench details from PR #10 - -PR #10 upgraded `/iban` from a single validator/explainer into a four-panel workbench: - -- **Validate** — keeps offline IBAN syntax/length/structure/MOD-97 validation and registry samples. -- **Build** — derives exact BBAN field templates from bundled registry data and computes ISO 13616 MOD-97 check digits locally. -- **Catalogue** — browses bundled country IBAN/BBAN structures, examples, segment hints, and snapshot SEPA flags. -- **Provenance** — explains generated registry metadata and no-live-service boundaries. - -Important guardrails: - -- No backend/API/upload path. -- No telemetry, analytics, remote logging, cookies, `localStorage`, `sessionStorage`, or IndexedDB for payment data. -- No IBAN-side `fetch`, XHR, storage, cookie, or telemetry APIs; `scripts/privacy-audit.sh` now checks this explicitly. -- Build rejects missing fields, wrong lengths, and wrong character classes; it does **not** auto-pad BBAN values or infer domestic account data. -- No claim of live BIC lookup, VOP, account ownership, account existence, current bank details, SEPA reachability, settlement status, or payment tracking. - -## Verification evidence for PR #10 +## Verification evidence for this branch -Local verification before PR: +Local gates run before handoff: ```bash -git diff --check pnpm verify pnpm test:e2e -npx -y @google/design.md lint DESIGN.md +git diff --check +cd apps/ssi-control-tower && make test ``` Results: -- `pnpm verify` passed: 29 test files / 226 tests plus lint, format, typecheck, privacy audit, deterministic data checks, and build. -- `pnpm test:e2e` passed: 20/20 Playwright tests. -- `DESIGN.md` lint returned 0 errors, with existing unused-token warnings only. -- Added-line security/browser scans were clean. -- Codex implementation review returned `APPROVED`. -- PR branch CI run `25377224769` passed. -- Post-merge `main` CI run `25379147860` passed. +- `pnpm verify` passed: lint, format check, typecheck, Vitest, privacy audit, deterministic IBAN/BIC/CBPR data checks, and build. +- `pnpm test:e2e` passed, including the new `/ssi` Playwright smoke and the privacy-boundary route loop. +- `git diff --check` passed. +- `cd apps/ssi-control-tower && make test` passed as a sanity check that the folded backend module was not broken. +- Static secret scan over changed/untracked files: 11 files scanned, 0 findings. +- Independent read-only Codex diff review: `APPROVE`. -## Design and product boundaries to preserve +## Boundaries to preserve Design source: -- `DESIGN.md` is derived from `raafetchoukri.com` and remains the app-level design contract. -- Use the existing light fintech/practitioner visual system: spacious white cards, subtle borders/shadows, blue/cyan accents, and strong browser-only/privacy-first messaging. +- `DESIGN.md` remains the app-level design contract. +- Use the light fintech/practitioner visual system: spacious white cards, subtle borders/shadows, blue/cyan accents, and strong privacy-first messaging. -Payment/product claim boundaries: +Root suite privacy/product boundaries: -- BIC module must remain demo/snapshot-bound and use the caveat `found in bundled demo snapshot` when describing lookup hits. -- VOP remains out of scope: `VOP requires a certificate and access to the EPC, which we won't have.` -- CBPR+ checker is local readiness/structure checking only; not a certified validator, full XSD engine, or MyStandards usage-rule engine. -- Payment Insights Lite is: `Local lifecycle insight over files you provide — not live payment tracking.` -- Deployment to `payments.raafetchoukri.com` remains paused until explicit user authorization. +- The root Vite/React app remains static and browser-only. +- Root `src/` must not add backend coupling, telemetry, analytics, remote logging, browser persistence, external fetches, or payment-data upload paths. +- `/ssi` is a static entry page only. It must remain fetch-free and iframe-free unless a separate architecture/security review explicitly changes the posture. -## Next sensible options +SSI backend module boundaries: -When work resumes, first choose one path: +- `apps/ssi-control-tower/` is a separate FastAPI/Jinja backend module with its own Python environment, tests, SQLite dev data, and synthetic fixtures. +- Public SSI data must remain synthetic and masked. +- Real SSI data, raw account numbers, proprietary workflows, credentials, and reversible redaction maps must never be committed. -1. **Post-merge housekeeping only** — confirm the handoff docs-only commit is synced and, if a docs-only CI run exists, confirm it passed. -2. **Deployment readiness** — prepare static hosting for `payments.raafetchoukri.com`, but do not run host-side Hetzner/Caddy commands without explicit authorization. -3. **Product polish pass** — pick one existing module and do a narrow review-gated refinement. -4. **Cross-module provenance/privacy pass** — extract reusable provenance components and make BIC/IBAN/CBPR+ boundaries even more consistent. +Payment/product claim boundaries: -Recommended next product pass if no deployment: a **cross-module provenance/privacy consistency pass**, because IBAN now has richer provenance and BIC/CBPR+/Insights could benefit from the same pattern without adding live-data risk. +- BIC module remains demo/snapshot-bound. +- VOP remains out of scope because certified EPC access is required. +- CBPR+ checker is local readiness/structure checking only; not a certified validator, full XSD engine, or MyStandards usage-rule engine. +- Payment Insights Lite is local lifecycle insight over files the user provides; not live payment tracking. +- Deployment to `payments.raafetchoukri.com` remains paused until explicit user authorization. ## Fresh-session opener @@ -136,8 +110,6 @@ Do not deploy or publish unless I explicitly authorize it. cd /Users/Shared/AgentWork/repos/payment-intelligence-modules git fetch origin --prune -git checkout main -git pull --ff-only origin main git status --short --branch git log --oneline --decorate --max-count=8 @@ -147,13 +119,3 @@ gh run list --branch main --limit 5 \ --json databaseId,status,conclusion,headSha,name,event,createdAt,url \ --jq '.[] | [.databaseId,.status,(.conclusion // ""),.headSha[0:7],.name,.event,.createdAt,.url] | @tsv' ``` - -## Vault pointer - -The matching vault checkpoint is in: - -- `/Users/Shared/AgentWork/vault/raf-second-brain/Memory.md` -- `/Users/Shared/AgentWork/vault/raf-second-brain/wiki/hot.md` -- `/Users/Shared/AgentWork/vault/raf-second-brain/wiki/projects/payment-intelligence-suite.md` - -The vault should say PR #10 is merged, `main` CI is green, and this repo has a `HANDOFF.md` as the next-session entry point. diff --git a/README.md b/README.md index 2c6f8ac..d78add8 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,16 @@ The root suite remains static and browser-only. Backend/product-control modules ## Modules -| Module | Route | Status | What it does | -| --------------------------- | -------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| **Scrubber** | `/scrubber` | Available | Strip personally identifying fields from `pacs.*` / `camt.*` XML before sharing with peers or vendors. Produces a privacy-safe mapping summary. | -| **Storyteller** | `/storyteller` | Available | Turn a `pacs.002 / 004 / 008 / 009` or `camt.052 / 053 / 054` message into a plain-language narrative plus a structured field projection and quick insights. | -| **IBAN Workbench** | `/iban` | Available | Validate, build, catalogue, and trace provenance for IBANs from bundled SWIFT IBAN Registry-derived data. Builder computes MOD-97 check digits from exact-length BBAN fields; no live BIC, VOP, account existence, or reachability checks. | -| **BIC Validator\*** | `/bic` | Demo | ISO 9362 syntax checks plus a tiny bundled snapshot lookup. **Demonstration only:** bundled BIC data is not accurate/current enough for production, routing, compliance, reachability, or payment decisions. | -| **CBPR+ Readiness Checker** | `/cbpr` | Available | Browser-only AppHdr / Document namespace / CBPR+ schema-profile coverage checks, plus UETR, BIC syntax, and IBAN syntax/checksum hints. Not a certified validator or MyStandards usage-rule engine. | -| **Payment Insights Lite** | `/insights` | Available | Local lifecycle insight over ACK/NACK, `pacs.*`, and `camt.*` files you provide. Groups files by identifiers in memory; not live payment tracking, VOP, reachability, or settlement monitoring. | -| Vault | — | Planned | Planned encrypted local export bundle: user-controlled download/import, no cloud vault, no server storage, and no persistent browser storage by default. Not built yet. | +| Module | Route | Status | What it does | +| --------------------------- | -------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Scrubber** | `/scrubber` | Available | Strip personally identifying fields from `pacs.*` / `camt.*` XML before sharing with peers or vendors. Produces a privacy-safe mapping summary. | +| **Storyteller** | `/storyteller` | Available | Turn a `pacs.002 / 004 / 008 / 009` or `camt.052 / 053 / 054` message into a plain-language narrative plus a structured field projection and quick insights. | +| **IBAN Workbench** | `/iban` | Available | Validate, build, catalogue, and trace provenance for IBANs from bundled SWIFT IBAN Registry-derived data. Builder computes MOD-97 check digits from exact-length BBAN fields; no live BIC, VOP, account existence, or reachability checks. | +| **BIC Validator\*** | `/bic` | Demo | ISO 9362 syntax checks plus a tiny bundled snapshot lookup. **Demonstration only:** bundled BIC data is not accurate/current enough for production, routing, compliance, reachability, or payment decisions. | +| **CBPR+ Readiness Checker** | `/cbpr` | Available | Browser-only AppHdr / Document namespace / CBPR+ schema-profile coverage checks, plus UETR, BIC syntax, and IBAN syntax/checksum hints. Not a certified validator or MyStandards usage-rule engine. | +| **Payment Insights Lite** | `/insights` | Available | Local lifecycle insight over ACK/NACK, `pacs.*`, and `camt.*` files you provide. Groups files by identifiers in memory; not live payment tracking, VOP, reachability, or settlement monitoring. | +| **SSI Control Tower** | `/ssi` | Backend (folded) | Static entry point for the separate FastAPI/Jinja SSI readiness and governance cockpit under `apps/ssi-control-tower/`. Not part of the root browser runtime; run locally when needed. | +| Vault | — | Planned | Planned encrypted local export bundle: user-controlled download/import, no cloud vault, no server storage, and no persistent browser storage by default. Not built yet. | \*The BIC module intentionally does **not** perform live BIC Directory lookup, current bank-directory enrichment, current SEPA reachability checks, SWIFT FIN @@ -30,7 +31,7 @@ This is the load-bearing property of the suite, not a footer line: - All parsing, validation, explanation, and rendering happens in the browser using platform APIs and pure JS/TS. -- There is no backend. No analytics, no telemetry, no error reporting, no remote +- In the root browser-suite runtime, there is no backend API. No analytics, no telemetry, no error reporting, no remote logging. - No persistence — `localStorage`, `sessionStorage`, `indexedDB`, and cookies are never written. @@ -105,7 +106,7 @@ pnpm verify # lint + format:check + typecheck + test + privacy/data ch - Tailwind v3 with light fintech tokens in `src/index.css`, derived from [`DESIGN.md`](./DESIGN.md) - React Router for `/`, `/scrubber`, `/storyteller`, `/iban`, `/bic`, `/cbpr`, - `/insights`, plus a `*` fallback + `/insights`, `/ssi`, plus a `*` fallback - Vitest + Testing Library for unit/page tests - Playwright for end-to-end smoke tests - ESLint + Prettier @@ -138,6 +139,7 @@ src/ CbprPage.tsx IbanPage.tsx ScrubberPage.tsx + SsiPage.tsx # static entry point for the folded SSI backend module StorytellerPage.tsx NotFoundPage.tsx lib/ @@ -179,10 +181,10 @@ To deploy on any static host, the host must: - Serve the contents of `dist/` from the site root. - For unknown / deep-link routes (for example `/scrubber`, `/storyteller`, - `/iban`, `/bic`, `/cbpr`, `/insights`, or `/anything-else`), fall back to serving + `/iban`, `/bic`, `/cbpr`, `/insights`, `/ssi`, or `/anything-else`), fall back to serving `index.html` so React Router can resolve the route on the client. This is sometimes called "SPA fallback" or "rewrite all to index.html". -- Not require any server-side execution. There is no API. +- Not require any server-side execution for the root static SPA. There is no root API. - Preserve the privacy posture: no analytics injection, no remote logging, and no third-party scripts added by the host configuration. diff --git a/ROADMAP.md b/ROADMAP.md index 634764d..d573a33 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -20,16 +20,17 @@ the suite is browser-only, static-host friendly, and privacy-first. ### 0. SSI Control Tower folded backend module -SSI Control Tower now lives under `apps/ssi-control-tower/` as a separate FastAPI/Jinja backend module inside this repository. It is not part of the root static browser suite runtime, and it must not weaken the browser-only privacy boundary for `src/`. +SSI Control Tower now lives under `apps/ssi-control-tower/` as a separate FastAPI/Jinja backend module inside this repository. It is not part of the root static browser suite runtime, and it must not weaken the browser-only privacy boundary for `src/`. The root suite now includes `/ssi` as a static, fetch-free entry page that explains the backend module posture and local run path without coupling the browser app to the FastAPI runtime. -Current branch scope is the approved hybrid unified SSI instruction flow, Phase -1 through Phase 2: +Merged SSI foundation includes: -- fold the module into this repo as ordinary tracked files; -- keep CSV demo imports compatible while also creating canonical `SsiInstruction` records with source lineage; -- make SSI Plus V3 imports use the same canonical ingestion path; -- add instruction-level validation, instruction exceptions, and a unified control queue API. +- folded module source as ordinary tracked files; +- CSV demo imports compatible while also creating canonical `SsiInstruction` records with source lineage; +- SSI Plus V3 imports on the same canonical ingestion path; +- instruction-level validation, instruction exceptions, and a unified control queue API; +- approval, export, and account-privacy hardening for the synthetic public prototype. -Approvals, exports, readiness expansion, and full UI polish remain follow-up scope. +Follow-up scope remains: deeper product UI polish inside the FastAPI app, deployment/publication decisions, and real-data/private-lab workflows only after explicit approval. ### 1. Deployment target decision @@ -47,7 +48,7 @@ Acceptance criteria: - Static build only; no backend or API. - SPA fallback works for `/scrubber`, `/storyteller`, `/iban`, `/bic`, `/cbpr`, - and `/insights`. + `/insights`, and `/ssi`. - No analytics injection, remote logging, third-party scripts, cookies, or browser persistence introduced by the host configuration. - README hosting notes are updated with the chosen target. diff --git a/e2e/smoke.spec.ts b/e2e/smoke.spec.ts index 1b83afd..2121bc4 100644 --- a/e2e/smoke.spec.ts +++ b/e2e/smoke.spec.ts @@ -37,7 +37,16 @@ test("privacy boundary does not use external requests or browser persistence", a const requestedUrls: string[] = []; page.on("request", (request) => requestedUrls.push(request.url())); - for (const route of ["/", "/scrubber", "/storyteller", "/iban", "/bic", "/cbpr", "/insights"]) { + for (const route of [ + "/", + "/scrubber", + "/storyteller", + "/iban", + "/bic", + "/cbpr", + "/insights", + "/ssi", + ]) { await page.goto(route); await expect( page.getByText(/runs entirely in your browser\. nothing is uploaded\./i).first(), diff --git a/e2e/ssi.spec.ts b/e2e/ssi.spec.ts new file mode 100644 index 0000000..2eb815e --- /dev/null +++ b/e2e/ssi.spec.ts @@ -0,0 +1,21 @@ +import { expect, test } from "@playwright/test"; + +test("SSI Control Tower overview is a static backend-module entry point", async ({ page }) => { + const requestedUrls: string[] = []; + page.on("request", (request) => requestedUrls.push(request.url())); + + await page.goto("/ssi"); + + await expect(page.getByRole("heading", { level: 1, name: /ssi control tower/i })).toBeVisible(); + await expect(page.getByText(/backend module/i)).toBeVisible(); + await expect(page.getByText(/synthetic-data public prototype/i)).toBeVisible(); + await expect(page.getByText(/apps\/ssi-control-tower/)).toBeVisible(); + await expect(page.getByText(/make run/)).toBeVisible(); + + const origin = new URL(page.url()).origin; + const externalRequests = requestedUrls.filter((url) => { + const parsed = new URL(url); + return parsed.protocol.startsWith("http") && parsed.origin !== origin; + }); + expect(externalRequests).toEqual([]); +}); diff --git a/src/App.test.tsx b/src/App.test.tsx index 32491c4..83e1d4e 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -41,6 +41,7 @@ describe("App", () => { expect(screen.getAllByRole("link", { name: /iban/i }).length).toBeGreaterThan(0); expect(screen.getAllByRole("link", { name: /cbpr\+/i }).length).toBeGreaterThan(0); expect(screen.getAllByRole("link", { name: /insights/i }).length).toBeGreaterThan(0); + expect(screen.getAllByRole("link", { name: /ssi/i }).length).toBeGreaterThan(0); }); it("renders the Scrubber page at /scrubber", async () => { @@ -75,6 +76,13 @@ describe("App", () => { await waitFor(() => expect(global.fetch).toHaveBeenCalled()); }); + it("renders the SSI Control Tower overview at /ssi", () => { + renderAt("/ssi"); + expect( + screen.getByRole("heading", { level: 1, name: /ssi control tower/i }), + ).toBeInTheDocument(); + }); + it("renders a not-found page for unknown routes", () => { renderAt("/does-not-exist"); expect( diff --git a/src/App.tsx b/src/App.tsx index a7044a5..f47f1e8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,6 +7,7 @@ import { IbanPage } from "@/pages/IbanPage"; import { InsightsPage } from "@/pages/InsightsPage"; import { NotFoundPage } from "@/pages/NotFoundPage"; import { ScrubberPage } from "@/pages/ScrubberPage"; +import { SsiPage } from "@/pages/SsiPage"; import { StorytellerPage } from "@/pages/StorytellerPage"; export function App() { @@ -20,6 +21,7 @@ export function App() { } /> } /> } /> + } /> } /> diff --git a/src/components/layout/SuiteHeader.tsx b/src/components/layout/SuiteHeader.tsx index 6d1edc5..facc81a 100644 --- a/src/components/layout/SuiteHeader.tsx +++ b/src/components/layout/SuiteHeader.tsx @@ -16,6 +16,7 @@ const navItems: NavItem[] = [ { to: "/bic", label: "BIC*", end: false }, { to: "/cbpr", label: "CBPR+", end: false }, { to: "/insights", label: "Insights", end: false }, + { to: "/ssi", label: "SSI", end: false }, ]; export function SuiteHeader() { diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index 423a253..2086665 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -19,7 +19,7 @@ interface ModuleTile { name: string; summary: string; icon: typeof Eraser; - status: "available" | "demo" | "planned"; + status: "available" | "demo" | "backend" | "planned"; } const modules: ModuleTile[] = [ @@ -71,6 +71,14 @@ const modules: ModuleTile[] = [ icon: GitBranch, status: "available", }, + { + to: "/ssi", + name: "SSI Control Tower", + summary: + "Static entry point for the folded FastAPI/Jinja SSI governance cockpit. Runs locally from apps/ssi-control-tower and stays outside the browser-only runtime.", + icon: ShieldCheck, + status: "backend", + }, { to: "#", name: "Vault", @@ -88,7 +96,7 @@ const howItWorks = [ ]; const whatItDoesNotDo = [ - "No upload to a server. No backend, no API, no remote logging.", + "No upload from the root browser runtime. No root API, telemetry, or remote logging.", "No persistence — nothing is written to localStorage, sessionStorage, IndexedDB or cookies.", "No telemetry, analytics or error reporting beacons.", ]; @@ -171,14 +179,12 @@ export function HomePage() {
- {["No backend API", "No localStorage or cookies", "No analytics beacons"].map( - (item) => ( -
-
- ), - )} + {["No root API", "No localStorage or cookies", "No analytics beacons"].map((item) => ( +
+
+ ))}
@@ -202,6 +208,7 @@ export function HomePage() { const Icon = module.icon; const isPlanned = module.status === "planned"; const isDemo = module.status === "demo"; + const isBackend = module.status === "backend"; const tileClass = cn( "group relative flex min-h-64 flex-col p-6 transition-all", "practice-card", @@ -209,12 +216,20 @@ export function HomePage() { ? "cursor-not-allowed opacity-65" : "hover:-translate-y-0.5 hover:border-accent/40 hover:shadow-md hover:shadow-slate-200/80", ); - const badgeLabel = isPlanned ? "Planned" : isDemo ? "Demo" : "Available"; + const badgeLabel = isPlanned + ? "Planned" + : isDemo + ? "Demo" + : isBackend + ? "Backend" + : "Available"; const badgeClass = isPlanned ? "border-border bg-muted text-muted-foreground" : isDemo ? "border-amber-300/60 bg-amber-100/70 text-amber-900" - : "border-brand/25 bg-brand/10 text-primary"; + : isBackend + ? "border-indigo-200 bg-indigo-50 text-indigo-900" + : "border-brand/25 bg-brand/10 text-primary"; const inner = ( <>
diff --git a/src/pages/SsiPage.test.tsx b/src/pages/SsiPage.test.tsx new file mode 100644 index 0000000..b8a830f --- /dev/null +++ b/src/pages/SsiPage.test.tsx @@ -0,0 +1,38 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; +import { render, screen } from "@testing-library/react"; +import { SsiPage } from "./SsiPage"; + +afterEach(() => { + vi.unstubAllGlobals(); + vi.restoreAllMocks(); +}); + +describe("SsiPage", () => { + it("renders the backend module posture and synthetic prototype disclaimer", () => { + render(); + + expect( + screen.getByRole("heading", { level: 1, name: /ssi control tower/i }), + ).toBeInTheDocument(); + expect(screen.getByText(/backend module/i)).toBeInTheDocument(); + expect(screen.getByText(/synthetic-data public prototype/i)).toBeInTheDocument(); + expect(screen.getByText(/not part of the browser-only runtime/i)).toBeInTheDocument(); + }); + + it("shows local run instructions without linking to localhost", () => { + render(); + + expect(screen.getByText(/apps\/ssi-control-tower/)).toBeInTheDocument(); + expect(screen.getByText(/make run/)).toBeInTheDocument(); + expect(screen.queryByRole("link", { name: /localhost/i })).not.toBeInTheDocument(); + }); + + it("does not call fetch while rendering the static integration page", () => { + const fetchSpy = vi.fn(); + vi.stubGlobal("fetch", fetchSpy); + + render(); + + expect(fetchSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/src/pages/SsiPage.tsx b/src/pages/SsiPage.tsx new file mode 100644 index 0000000..e38e37f --- /dev/null +++ b/src/pages/SsiPage.tsx @@ -0,0 +1,131 @@ +import { CheckCircle2, FileText, Lock, ShieldCheck } from "lucide-react"; +import { ModuleLayout } from "@/components/layout/ModuleLayout"; + +const capabilities = [ + "Ingest synthetic SSI CSV or SSI Plus-shaped tab-delimited files into a canonical governance model.", + "Normalize standing-settlement-instruction records, run YAML rule checks, and persist validation evidence.", + "Track exception ownership, SLA posture, four-eyes approvals, immutable audit events, readiness scoring, and approved-record exports.", +]; + +const ruleHighlights = [ + "Required market, country, asset-class, settlement-method, owner, and effective-date checks.", + "BIC, country-code, currency-code, date-range, duplicate-active, stale-record, and T+1 readiness controls.", + "Instruction-level exception queue and approval workflow backed by synthetic masked-account fixtures only.", +]; + +export function SsiPage() { + return ( + + {/* Intentionally static: do not add fetch/effects/iframes here. The FastAPI app remains separate. */} +
+
+
+
+

+ First-class in the suite, separate from the browser runtime. +

+

+ SSI Control Tower is not part of the browser-only runtime. It lives as a folded + FastAPI/Jinja application inside this repository, while this React page documents the + entry point, posture, and local operator workflow without calling an API. +

+
+

+ Synthetic public prototype disclaimer +

+

+ This project is a synthetic-data public prototype for SSI readiness and governance. It + is not affiliated with DTCC, SSImple, Swift, FMSB, ISITC, any custodian, or any market + infrastructure. It does not connect to production SSI utilities and does not contain + real settlement instructions, client data, account numbers, or proprietary workflows. +

+
+
+ + +
+ +
+
+
+ + +
+

What it does

+

Control workflow

+
+
+
    + {capabilities.map((item) => ( +
  • +
  • + ))} +
+
+ +
+

Run it locally

+

+ Start the folded FastAPI app separately +

+
+            {"cd apps/ssi-control-tower && make run\n# opens http://localhost:8000"}
+          
+

+ The local app owns its Python dependencies, SQLite development data, templates, APIs, + tests, and synthetic fixtures. Read the folded app README for command details and demo + flow. +

+
+
+ +
+

Rule catalogue

+

+ Controls surfaced by the folded app +

+
+ {ruleHighlights.map((item) => ( +
+

{item}

+
+ ))} +
+
+
+ ); +}