Case study / Wealth management

A compliance-approved client assessment tool for a Texas RIA

0 external requests — every byte served from the client's own origin

Open the live tool →Book a 20-minute callDraft · client permission pending
Client
Trivium Asset Management Partners
Industry
Wealth management
Timeline
Aug–Sep 2026
Services
MVP build, Compliance tooling, DevOps / infra, Legacy modernization
Stack
HTML/CSS/JS (single file)jsPDFNode.jsnginxAmazon SESCloudFrontAWS WAFACMS3CloudWatch
Results
38 questions, ~9 minutes, no login1 compliance condition attached to approval, met on the first screen3 rate-limit layers in front of the PDF endpoint (WAF, nginx, in-process)0 payload fields ever written to a log2 properties moved to AWS (profile tool live; www built, DNS cutover pending)
Status
live

[PERMISSION NEEDED: Trivium / Arkadios Compliance] — The firm name, the fact of compliance approval, and the public URL all appear below. Everything here is either visible on the live tool or in the project handoff. Nothing publishes until the client confirms in writing.

The problem

A registered investment adviser operating under a broker-dealer’s compliance umbrella wanted a client-facing assessment: a visitor answers questions about goals, liquidity, time horizon, and risk, and receives a “portfolio purpose profile” to download and share with an advisor. The firm’s marketing site described the assessment and linked to a third-party risk-tolerance tool as a placeholder, because the real thing did not exist yet.

Two things made this harder than a quiz. The answers include client financial information: income, net worth, liquid net worth, tax rate, and accredited-investor attestations. And the broker-dealer’s compliance department had to approve the tool before any prospect saw it, with disclosure wording and placement that could not drift by one word.

The firm also wanted its Squarespace marketing site moved to infrastructure it controlled.

Constraints

  • Compliance-controlled copy. The affiliation disclosure had to appear on the first screen, visible without scrolling, in exactly the approved wording. Same for every string referencing FINRA Rules 2111, 4512 and 2090, Regulation Best Interest, Rule 506(c), the consent gate, and the accredited-investor attestation.
  • A methodology document on file. All 38 questions, answer options, point values, and scoring logic are described in a document the compliance team holds. Code and document must agree, so every session record is stamped with a METHODOLOGY_VERSION.
  • Client financial data in transit. Once results delivery moved server-side, an unauthenticated public endpoint accepts sensitive data: nothing logged, nothing retained, encryption on every hop.
  • No third-party origins. Zero external requests, which ruled out Google Fonts and CDN-hosted libraries.
  • Shared AWS account. The same account runs a separate live production SaaS, so every resource had to be tagged and scoped so a mistake on one property could not touch the other.

What I built

The assessment is a single HTML file, about 165 KB, with no build step and no framework: one question per full-viewport screen, a canvas-drawn triangle plotting the user’s position across three dimensions, an archetype map with a drag-to-explore panel, and a two-checkbox consent gate that fails closed if either box is unchecked. Fonts are self-hosted woff2 (SIL OFL), so the page loads from exactly one origin.

Results delivery is where the engineering lives. On completion the browser POSTs a plain JSON report model to a Node service behind nginx. The service validates and sanitizes every field (control characters stripped, header fields CR/LF-safe, at least 20 answered questions required), renders the PDF with jsPDF and embedded subset fonts, returns the bytes for download, and in the background emails the identical buffer to the advisor team through Amazon SES. The PDF touches disk only as a mode-0600 spool file unlinked in a finally block; a janitor sweeps anything older than 15 minutes. Logs carry a session id and a status word, never a payload.

If the API is unreachable, the browser lazily loads the vendor bundles (about 500 KB, never fetched on the happy path), renders the same PDF locally, and tells the user the advisor copy did not send.

For the marketing site, I took the designer’s single-file handoff and closed the launch gaps: self-hosted fonts, an accessible mobile menu, favicon, 404 page. A check-compliance.sh gate diffs the footer disclaimer against the approved text, and deploy.sh refuses to publish if it fails. The client’s designer holds a deploy credential scoped to exactly two actions (write the site bucket, invalidate the CDN cache).

Architecture

Request path: viewer → CloudFront (TLS 1.3, ACM certificate) → AWS WAF → origin nginx → Node service on loopback. Origin port 443 accepts only CloudFront’s managed prefix list, so the WAF cannot be bypassed, and the origin hop is TLS too. SES runs with TlsPolicy=REQUIRE: a recipient that refuses STARTTLS gets a bounce, not a plaintext delivery. Six CloudWatch alarms publish to an SNS topic; the most important fires when an advisor email fails after retries. The www site uses the S3 + CloudFront + ACM pattern I have reused across four properties, with versioned objects for one-command rollback.

Results

  • Approved by the broker-dealer’s compliance department for existing clients, prospects, and the firm’s website, conditional on first-screen disclosure placement. The transmission-consent language was approved 2026-08-12 when delivery moved server-side.
  • Live at profile.triviumam.com with zero requests to any host other than its own origin.
  • Advisor copy and user download come from the same in-memory buffer, so they cannot drift. The prior mailto flow relied on the user attaching a file and silently produced incomplete advisor records.
  • Three independent rate limits: 2,000 requests per 5 minutes per IP at the WAF, 12 per minute at nginx, 10 per minute in-process.
  • A WAF default rule was silently blocking every real submission (8 KB body cap against a ~9.5 KB payload). Diagnosed and replaced with a 64 KB inspection window and a 32 KB hard cap.
  • The marketing site is built and serving with HSTS and security headers, waiting on the client’s DNS cutover decision.

Documented, not hidden: the SES account is in sandbox (200 sends/day), the advisor mailbox needs a retention decision, and compliance still needs to review the full data flow before a marketing push.

What this proves

  • MVP Sprint: a regulated client went from placeholder link to an approved, live assessment with server-side delivery, monitoring, and rollback, with no framework or build pipeline to maintain.
  • Legacy Modernization: a Squarespace property rebuilt as a static site on AWS with a compliance gate in the deploy script and a credential the client’s designer can safely hold.
  • AI Integration (adjacent): the hard part of putting any tool in front of a regulated firm’s clients is the controls around it. Same pattern when the tool is an LLM.

Similar project?

Need a client-facing tool that has to pass compliance review before it ships? Book a 20-minute call.

Published Oct 1, 2026

Next step

Similar project?

Twenty minutes to see if this pattern fits your problem.