Skip to content

SPEC-152-Q4: Client-Facing Suitability Report Viewer

Capability: SUITABILITY-ENGINE · Status: draft Repo: suitability-engine

Audience: WTP engineers building/reviewing this; Origo’s own front-end team, who will build their own equivalent view against the JSON contract below (we do not ship this UI into their product — see Deployment model).

Origo needs their end-client to view and acknowledge a suitability report, matching the UX pattern already proven live in client-onboarding’s own client-facing report (apps/client-onboarding/src/app/report/) — a progressive-disclosure, section-by-section review that gates the acceptance action on having actually viewed every required section, with every transition captured as an audit event (the same pattern the real client-portal repo formalises for FCA acknowledgement). This spec documents that reference UX precisely enough for Origo to reproduce it (or diverge deliberately), and ships a working reference implementation proving the JSON contract is sufficient to drive it.

2. Reference UX (as built in client-onboarding, source of truth)

Section titled “2. Reference UX (as built in client-onboarding, source of truth)”
  • Fixed left sidebar (dark navy, wtp-navy-deep in the source brand palette — a placeholder in the reference implementation, see Branding), full viewport height, collapsible on mobile behind a hamburger toggle.

  • Report title + client name at the top of the sidebar (“Suitability Report” / “Jane Doe”).

  • Nine section links, each with an icon, in a fixed order:

    OrderSection idLabel
    1overviewOverview
    2about-youAbout You
    3objectivesYour Objectives
    4riskAttitude to Risk
    5recommendationsMy Recommendations
    6suitabilityWhy This is Suitable
    7costsCosts & Charges
    8risksKey Risks
    9downloadsDownloads
  • Each link shows a checkmark once viewed (teal accent), and the currently active section gets a left border + lighter background — pure client-side state, driven by navigation, not a separate “mark as read” button.

  • “Proceed to Acceptance” button, fixed at the bottom of the sidebar, disabled until every section in a required subset has been viewed (not necessarily all nine — client-onboarding’s REQUIRED_SECTIONS_FOR_ACCEPTANCE is a subset; Origo should decide their own required set, but the pattern — some sections may be “must-read”, others optional context — is worth keeping).

2.2 Section-view tracking = the audit trail

Section titled “2.2 Section-view tracking = the audit trail”

This is the part that matters most and is easy to under-build: viewing a section is itself the event being audited, not a side effect of a “mark read” click. In the reference implementation, navigating to a section fires a “viewed” event exactly once per section per session (idempotent — revisiting doesn’t re-fire). client-onboarding persists this server-side per client (reportSectionsViewed on the client record, patched via the API) so the gate on “Proceed to Acceptance” survives a page reload — this is not just client-side UI state, it’s the FCA-relevant record of what the client actually looked at before accepting.

For Origo: this means your own back end needs an equivalent durable “sections viewed” store per client engagement, and your acceptance/proceed action needs to check it server-side, not just trust client-side state — otherwise the audit trail is forgeable by anyone who can call your “accept” endpoint directly.

Each section is its own scrollable panel in the main content area. Representative example (suitability, the “Why This is Suitable” section):

  • A heading card explaining the recommended management approach (recommendation.dfmManager etc.) with a 3-up feature-benefit grid.
  • A performance-comparison visual (current vs. recommended platform).
  • A list of collapsible reason cards — each with a heading and an expandable explanation (accordion pattern, one open/closed state per card, independent of the others).

Other sections (About You, Objectives, Risk, Recommendations, Costs, Risks, Downloads) follow the same visual language — card-based panels, consistent spacing, no page-level scroll competing with section-level scroll.

2.4 Data mapping — SuitabilityData → the nine sections

Section titled “2.4 Data mapping — SuitabilityData → the nine sections”

The reference implementation renders directly off GET /v1/tenants/:tenantId/clients/:clientToken/suitability (or the format=json export route)‘s response, i.e. { data: SuitabilityData, audit } per suitability-template/contract.ts. Mapping:

SectionSource fields
overviewclient.fullName, report.generatedAt, firm.name, adviser.*
about-youclient.* (address, DOB, risk profile, investment experience)
objectivesclient.objectives.timeHorizonYears
riskclient.riskScore, client.riskRating, client.capacityForLoss
recommendationsrecommendedPlatform.*, recommendation.*
suitabilityrecommendation.summaryStatement, recommendation.dfmManager
costscharges.*, currentPlatform.{amc,platformFee,totalCharges}
risks(see gap below)
downloadsreport.enclosures

Known contract gap, not solved by this spec: client-onboarding’s real suitability page renders a list of narrative reason cards (suitabilityReasons: [{id, heading, explanation}]) that do not exist anywhere in SuitabilityData (contract.ts). That narrative content is generated/stored elsewhere in client-onboarding’s own client record, not by this engine’s rules pipeline. The reference implementation below synthesises a single generic reason card from recommendation.summaryStatement instead of reproducing the real multi-card narrative — this is a simplification, not full parity, and should be called out to Origo explicitly rather than presented as done. Closing this gap for real means either extending SuitabilityData with a suitabilityReasons array (a schema change, rules-engine work) or accepting that the narrative “why-suitable” copy is something Origo authors themselves per the derived recommendation data. Same gap likely applies to risks (Key Risks) — client-onboarding’s version isn’t traced to this contract either; the reference implementation leaves it as an Origo-authored static section for now.

The colour palette, typography, and logo in client-onboarding’s real report are WTP/Benchmark brand tokens — not part of what Origo integrates against. The JSON contract carries data, never presentation. The reference implementation uses a neutral placeholder palette (documented in its own README) specifically so it reads as “swap this,” not “this is WTP’s brand, keep it.”

3. Integration flow — how Origo actually calls this

Section titled “3. Integration flow — how Origo actually calls this”
  1. Origo’s back end calls POST /v1/tenants/{tenantId}/clients/{clientToken}/suitability/export?format=json (bearer: SUITABILITY_ENGINE_SERVER_TOKEN, or the Origo-facing API-key-with-scopes model once that ships — see docs/external/origo-suitability-and-adviser-api-design.md §5.1 in client-onboarding) to get { data: SuitabilityData, audit }.
  2. Origo’s front end renders it using their own equivalent of the shell described above (or the reference implementation as a starting point).
  3. Section-view events are recorded by Origo, in Origo’s own store — this engine has no concept of “has this client viewed this section”, and is not the right place to add one (it’s a stateless derive-and-render pipeline, not a session/audit-trail service).
  4. Origo’s own “accept” action is Origo’s own audit event, entirely outside this engine’s scope.
  5. If the branded document (not just the web view) is needed — e.g. for download/email — that’s the format=docx path (suitability-engine#6, now implemented) against Origo’s own registered template.

4. Deployment model — what WTP ships vs. what Origo builds

Section titled “4. Deployment model — what WTP ships vs. what Origo builds”

Per the scope decision made with the user 2026-08-16: WTP ships this spec + a reference implementation (examples/client-report-viewer/) that Origo can literally copy, fork, or just read for the interaction pattern. WTP does not operate, host, or maintain a production version of this UI for Origo — Origo’s own client-facing product is Origo’s to build and brand. The reference implementation is explicitly not embedded into client-onboarding or any other WTP product’s UX.

See examples/client-report-viewer/ — a standalone Vite + React app (no Next.js/WTP-app-shell coupling, so it’s genuinely portable). Run npm run dev inside that directory; it renders against a bundled sample SuitabilityData payload (examples/client-report-viewer/src/sample-data.ts) matching the shape a real API response would carry, so no live backend call is required to see it work. See that directory’s own README for architecture notes and exactly what is/isn’t implemented.