- PropTech · RegTech
- AML compliance SaaS
- Replit prototype → Next.js + Node.js
- AI guidance search
- 2026
- Website
- SaaS
RiskBright: AI-assisted AML compliance SaaS for UK estate agents, rebuilt from a Replit prototype
Your checks. Your judgement. Your records.



Project Overview
UK estate and letting agents supervised by HMRC must check far more than ID: ownership, source of funds and sanctions, each in a different official source, often across a dozen open browser tabs.
RiskBright replaces that scattered process with one guided workflow. The founder brought us a working Replit prototype; from July to September 2026 we audited it and rebuilt it as a production SaaS in Next.js and Node.js.
Adaptive Journey
Asks only the questions that fit the deal and the customer, and opens the right official source, from Companies House to the FATF lists, at the moment it's needed.
Instant Audit Trail
Each completed Journey becomes a clean, editable Word record for the agency's own client file. The Journey itself is cleared after 7 days.
Guide, Never Decide
Never scores, grades or approves a client: it raises factual considerations and leaves the judgement with the agent.
Goal, problem and solution
Goal
Help UK estate agents turn a scattered, anxious compliance process into one guided, evidenced Journey.
Problem
Agents struggle to connect the identity check with beneficial ownership, source of funds, and a defensible record across 7+ disconnected sources.
- HMRC guidance
- Companies House
- Sanctions list
- FATF list
- Funds spreadsheet
- Word checklist
- Personal notes
Solution
Create one guided Journey connecting adaptive questions, practical tools, HMRC-grounded guidance, and an editable Word record.

- Work type
- Party role
- Customer type
- Customer checks
- Risk questions
- Considerations
Journey document
An editable Word document recording every question and your answers, with space for your own assessment.
Journey complete
Download your summary and retain it in your agency's own records.
UX Approach
Guide, Never Decide
RiskBright never scores, grades, or approves a client. We surface factual considerations and leave the judgement to the professional.
Adaptive, Not Generic
Questions branch on work type, party role and customer type, and follow-ups appear only when an answer calls for them. A company buyer and an individual tenant never sit through the same questions.
Evidence You Can Trust
HMRC Guidance Search answers only from HMRC's estate and letting agency guidance and shows the passages it quoted. Every Journey downloads as an editable Microsoft Word record.
One Calm System
Dashboard, Journey, tools and the knowledge library share the same UI structure, so nothing ever feels bolted on.
Where RiskBright stops and the agent starts
Guide, never decide
RiskBright guides
- Asks yes/no questions that adapt to the work type, party role and customer type
- Raises factual considerations, such as PEP, sanctions or source of funds, when an answer triggers them
- Opens the UK Sanctions List, Companies House search or the funds calculator at the step that needs it
- Answers HMRC guidance questions with the source passages quoted
- Writes every question and answer into an editable Word record
The agent decides
- Whether a consideration needs further checks
- The risk assessment for this customer
- Whether to act for the customer
- When to escalate to the MLRO
- What goes into the agency's own client file
RiskBright never gives
- a risk score
- approve or reject
- a pass or fail
Replit app rescue
From Replit prototype to production SaaS
RiskBright reached us as a working prototype built on Replit: a Vite and React single-page app on an Express and Postgres backend. Before writing any new code we audited it for security, SEO, performance, structure and third-party integrations. Then we rebuilt it as a production SaaS on Next.js and Node.js. We kept what worked and fixed what didn't.
What our audit found, and what the rebuild changed
Code audit dated 2 August 2026. It covered every server module and the shared schema, and swept all 47 client pages and 60 components.
- Found
Rendering
A 1.5 MB bundle before the first paint
The prototype rendered entirely in the browser. Every visitor, including anonymous ones on the landing page, downloaded the whole app as one JavaScript file before anything appeared, admin panel and calculators included. Crawlers got an empty root div.
index.js · 1,539,953 bytes · 431 KB gzippedFixedRendering
Server-rendered pages, split by route
We rebuilt it on the Next.js 16 App Router. Public pages are rendered on the server as real HTML, and each of the 52 routes loads only its own code, so the landing page no longer carries the dashboard.
frontend/src/app · 52 route pages - Found
SEO
Every URL pointed Google at the homepage
A hard-coded canonical tag sent every page back to the homepage, privacy, terms and login included. There was no per-route head management either, so every page had the same title and description. In practice the site had one indexable page.
index.html · rel="canonical" → /FixedSEO
Metadata on every route
Every page exports its own title and description through Next.js metadata, inside a site-wide “%s — RiskBright” template. Blog articles build theirs on the server, with a self-referencing canonical and Open Graph tags.
export const metadata · generateMetadata() - Found
Content
The content pages were behind a login
Best practices, templates and the blog were the only pages that read like search content, and all three sat behind a client-side auth check. Every crawler was redirected to the login page, and the blog itself was an empty array.
blog.tsx · const blogPosts = []FixedContent
A public, crawlable blog
The blog is now public, rendered on the server and managed from the admin panel. sitemap.js lists every published article, robots.js keeps the signed-in app out of the index, and unknown URLs get a real 404 page.
app/sitemap.js · app/robots.js · not-found.js - Found
Social
Shared links showed a broken image
At build time, a Vite plugin swapped the Open Graph and Twitter image for one on an internal Replit preview domain. Every link to the live site shared on LinkedIn, Slack or WhatsApp showed a broken image.
vite-plugin-meta-images.ts → *.replit.devFixedSocial
Image URLs built from the live domain
metadataBase comes from a single SITE_URL constant, so Open Graph and Twitter images always resolve against the production domain. Articles can add their own feature image.
app/layout.js · metadataBase - Found
Security · cost
The AI quota could be raced
The guidance assistant read a user's usage count, called OpenAI, and only then wrote the new count back. Requests sent at the same moment all read the same out-of-date number, so one account could use many times its quota, at real OpenAI cost.
routes.ts · check, call, then incrementFixedSecurity · cost
The quota is claimed in one database write
The claim is a single findOneAndUpdate whose filter includes the plan's limit. It runs before the OpenAI call and is released if the call fails. A limit of 10 questions a minute sits in front of it.
aiUsage.service.js · aiQueryCount: { $lt: max } - Found
Structure
One 1,783-line routes file
All 60 endpoints, from Stripe checkout to HMRC reminders, lived in a single routes.ts with no Router(). Next to it was a 546-line storage object covering 11 domains, so every change touched the same two files.
server/routes.ts · 1,783 linesFixedStructure
Small modules, one job each
The API is split into 35 Express routers, each with its own controller, service and zod validator, and documented in Swagger. The largest route file is now 122 lines.
routes/ · controllers/ · services/ · validators/
The stack swap
Each layer of the Replit prototype and what replaced it in the production build.
- RenderingBefore: Vite + React SPA, rendered in the browserreplaced by Next.js 16 App Router, React 19 and Tailwind CSS v4
- APIBefore: Express with one 1,783-line routes.tsreplaced by Express 5: 35 routers, controllers and services
- DataBefore: Drizzle ORM on PostgreSQLreplaced by MongoDB with Mongoose, 30 models
- ContractsBefore: Schema types never reached the clientreplaced by zod validators and Swagger (OpenAPI) docs
- SessionsBefore: express-session stored in Postgresreplaced by JWT access and rotating refresh cookies
- FilesBefore: Replit Object Storagereplaced by AWS S3
Also fixed in the rebuild
- Stripe webhooks are refused when no signing secret is set, and the Stripe API version is pinned
- Passwords need at least 8 characters and are hashed with bcrypt at cost 12, up from 10
- Rate limits on sign-in, sign-up, password reset, AI questions and Companies House lookups
- Guidance embeddings are stored in the database, so one failed OpenAI call no longer takes the assistant down until a restart
- Helmet security headers, plus a short-lived JWT access cookie with a rotating refresh token, both httpOnly
- Stripe webhook idempotency, already the strongest part of the prototype, was carried over as a claim-once WebhookEvent record
Have a Replit or AI-built prototype that needs to become a product? We audit it first, then rebuild what needs rebuilding.









Website
A server-rendered Next.js marketing site, rebuilt from a client-rendered Replit SPA.
The public site lives in the same Next.js app as the product. Every marketing page is rendered on the server with its own title and description, the sitemap is generated from the routes and the published blog articles, and robots.txt keeps the account area out of the index. The Replit prototype served one empty HTML shell, with one title and one canonical tag, for every URL.
- Rendering
- Server-rendered pages, with small client islands for the hero buttons, FAQ accordion and cookie banner
- Metadata
- A title and description per route; blog articles add a canonical URL and Open Graph tags
- Crawling
- sitemap.xml built from the routes and published articles; robots.txt disallows the app routes
- Content
- A public blog fed by the admin CMS, replacing the prototype's empty, login-only blog
Hero
“From identity check to informed judgement.”
One centred column with the four-step “where RiskBright fits” graphic under the headline. It replaced a mock dashboard showing risk ratings the product never gives. “No card required” sits beside the button.
How it fits
“A clearer process after every identity check.”
Five steps on one rail. Steps one and four answer objections before they are asked: keep your ID provider, and the decision stays with you.
Journey
“More than a static AML checklist.”
The claim and the five things a Journey does sit side by side. No screenshot: a still frame would misrepresent a process that adapts to every answer.
Record
“Create a clear record of what informed your assessment.”
The Word record is shown as field labels only, never a filled-in example, so the page invents no client. The caveat that it does not confirm AML obligations stays.
Tools
“Practical support when you need to look deeper.”
Cut from five cards to three: HMRC Guidance Search, Source of Funds and Beneficial Ownership. Companies House and reminders move to the platform list, so the page never reads like a directory.
Pricing
“Simple pricing. Full platform access.”
The AI allowance on each plan is read from the database the admin edits, so the page never quotes a number the product no longer honours. The one-off Toolkit is its own card, not a cheaper tier.
FAQs
Every question is an h3 with a real button and aria-expanded, and every answer is in the server HTML, so the content a visitor opens is also the content a crawler reads.
Captured from the live site, October 2026
Dashboard
Inside the app: an AML compliance workspace for estate agents
Six modules, one rule: guide, never decide. RiskBright asks the questions, links the sources and writes the record; the judgement stays with the agent. Scroll through the agency workspace as the app shows it, in its demo workspace “RiskBright HQ”.
01 / 06
Dashboard
- Start or resume a Journey
- See trial and plan status
- Quick access to tools
The signed-in home answers one question: what should I do next? A large call to action starts a Compliance Journey, and four quick-start tiles (Seller, Buyer, Landlord, Tenant) skip the first wizard choices. Tasks due and upcoming events link straight to the calendar, and the plan badge shows whether the agency is on a trial or a subscription. There is deliberately no compliance score.

02 / 06
Compliance Journey
- Adaptive branching
- CDD and risk questions
- Considerations review
The core of the product: a guided wizard for one customer at a time, from work type and party role through customer checks and risk questions to a considerations review. Questions branch on earlier answers (a company customer gets company and beneficial-owner questions; follow-ups appear only when they apply), every Continue auto-saves, and the API validates each answer against that journey’s own question set. The last step lists factual considerations from 13 fixed triggers, never a risk rating or a verdict.

03 / 06
Toolkit
- Companies House lookup
- Source of Funds calculator
- Ownership check tool
Standalone tools for the checks HMRC’s guidance expects, usable on their own or from a Journey. Companies House search pulls a company’s profile, officers and people with significant control live from the Companies House API, cached on the server. The Source of Funds calculator records up to four funding parties against the price or the rent paid in advance, counts joint funds once and shows what is identified and evidenced, without verifying documents or drawing a conclusion. PEP and sanctions is a page of guidance and official links, not automated screening.

04 / 06
Knowledge & Guidance
- HMRC Guidance Search (AI, sourced)
- Best Practices articles
- Training and quiz
Agents ask a plain-English AML question and get a short summary drawn only from HMRC’s AML guidance for estate and letting agency businesses, with the passages it came from listed underneath. Behind it: 98 embedded passages, OpenAI embeddings for retrieval, gpt-4o-mini at temperature 0, three locked prompt rules, a monthly quota per plan claimed before every call, and a 30-day answer cache. Best-practice articles and a 12-question AML knowledge quiz, with every attempt saved, sit alongside.

Live demo
Demo data
HMRC Guidance Search
38 of 50 questions left this month
What must our business risk assessment cover?
AI summary
HMRC’s guidance says every estate or letting agency business must develop a business risk assessment. It must show that you understand all the ways your business could be exposed to money laundering, terrorist financing and proliferation financing, and you design your systems to deal with them. It then guides your policies, controls and procedures, and the level of customer due diligence you apply.
“must” = legal obligation. A locked rule keeps it apart from “should”.
Source passage · Risk Assessment
“You must be able to understand all the ways that your business could be exposed to money laundering, terrorism financing and proliferation financing risks and design systems to deal with them.”
Based only on HMRC’s AML guidance for estate and letting agency businesses. Not legal advice.
Rebuilt in HTML from the app’s own answer layout. The figures in the usage meter are illustrative; 50 questions a month is the default allowance on paid plans. 05 / 06
Records & Compliance Calendar
- Editable Word summary
- HMRC renewal reminders
- Tasks
Finishing a Journey builds an editable Word record on the server: every question asked and answered, the considerations raised, the Source of Funds breakdown where there is one, and blank sections for the agency’s own assessment. It goes into the agency’s own file, and RiskBright deletes the completed journey after seven days. The calendar holds prioritised tasks and compliance events, and the HMRC registration renewal date sends reminder emails 90, 30, 7 and 1 days before it falls due.

Word record, as generated
Buyer – Individual Customer JourneyDOCX
- 1Customer and transaction details
- 2Identity verification
- 3Representation
- 4Customer and transaction risk
- 5Source of funds
- 6Additional considerations
- 7Assessment and additional notes
Answers in, assessment left blank for the agency.
06 / 06
Admin Panel
- FATF list management
- AI usage and cost control
- Business KPIs
A console that lets the RiskBright team run the product without a developer: users, subscribers, trials, active agencies and journey completion by type, plus user management, articles, templates, videos and an audit log. Admins edit the AI prompt (never its locked rules), set the monthly question limits and see usage. The FATF high-risk jurisdiction lists refresh from HM Treasury’s notice on GOV.UK, and no change goes live until an admin approves the diff.







Architecture
Platform and integrations
A Next.js web app in front of an Express 5 API and MongoDB. Every third-party service sits behind the API: billing, AI guidance search, company data, email, file storage, Word records and the FATF lists.
What the API talks to
Stripe subscriptions
Monthly and annual plans, a one-off Toolkit purchase, plan changes, cancel and resume, and invoices as PDFs inside the app. Webhooks are signature-checked and claimed once per event, so a retried delivery is never processed twice.
OpenAI guidance search
Retrieval over HMRC's AML guidance for estate and letting agents, using text-embedding-3-small and gpt-4o-mini. How it stays grounded is explained below.
Companies House API
Live company search, officers and people with significant control for the ownership tools. Searches are cached for 5 minutes and company details for 15, and lookups are rate-limited.
Resend email
11 transactional emails built on one shared layout: verification, password reset, billing events, HMRC renewal reminders, task digests and admin notices.
AWS S3 storage
Templates, article images, agency logos, feedback screenshots and generated Word summaries, all kept under keys the server generates.
Word records
The Compliance Journey and the Source of Funds calculator each produce an editable .docx summary for the agency's own file, generated on the server with docx.
FATF list refresh
A job reads HM Treasury's FATF advisory notice on GOV.UK, parses both lists with cheerio and stages the differences. Nothing changes until an admin approves the import.
Scheduled jobs
Standalone cron scripts send HMRC renewal reminders and task digests, purge completed journeys and refresh the FATF lists. Each is safe to re-run.
AI Guidance Search
Grounded in HMRC's own guidance, with sources
Agents ask a question in plain English. The answer can only come from passages of HMRC's AML guidance for estate and letting agency businesses, and those passages are shown under every answer so the agent can check each point against its source.
Question
Normalised and hashed. A repeat within 30 days is answered from the cache.
Embedding
text-embedding-3-small turns the question into a vector.
Retrieval
Cosine similarity across 98 embedded guidance passages, with a +0.18 boost when a passage uses the guidance's term for the agent's word (probate → executor, EDD, PEP). The top 8 above a threshold go forward.
98 HMRC guidance passages
8 retrieved · 1 lifted by a synonym
Answer
gpt-4o-mini at temperature 0, in JSON mode. The model sees only those passages and works under three locked rules.
Sources
A 2–5 sentence summary, followed by the passages it came from with their paragraph numbers, and a not-legal-advice note.
When do we need to apply enhanced due diligence?
Sources
- Enhanced due diligenceParagraphs 205–210
- Additional measures to takeParagraphs 214–217
- Politically exposed persons’ riskParagraphs 234–239
This answer is based only on the HMRC Anti-Money Laundering Supervision guidance for estate and letting agency businesses. It is not legal advice.
Three locked rules
An admin can reword them but can't remove them.
Answer ONLY from the supplied excerpts. Do not use your own knowledge, outside sources, or the internet.
Preserve the difference between 'must' (a legal obligation) and 'should' (HMRC-recommended good practice).
Never state that the user is compliant, has satisfied a requirement, or may proceed.
Cost and quality controls
- Monthly question quota per plan, claimed atomically before the OpenAI call and released if the call fails
- A limit of 10 questions a minute per user
- 30-day answer cache, cleared whenever the prompt is changed
- If no passage clears the threshold, the model isn't called at all
- Daily usage history and lifetime totals in the admin panel
By the numbers
Counted in the RiskBright repositories, not estimated.
- pages across the public site, app and admin
- 52
- API route handlers
- 172
- data models
- 30
- transactional emails
- 11
- guidance passages indexed
- 98
Privacy by design
RiskBright isn't the agency's record system: the Word document is, filed in the agency's own CRM. So a completed journey, with its names, addresses and answers, is purged after 7 days together with its document and any linked funds calculation. A database TTL is the backstop if the purge job doesn't run.
Need AI that cites its sources, Stripe billing or a third-party API wired into your product?
Design System
RiskBright's own type pair and palette, set in the faces and colours the app ships. Every swatch carries its measured contrast, because two of the brand colours cannot hold white text.
From identity check to informed judgement. Plus Jakarta Sans sets every heading in RiskBright, from the landing-page hero to Journey step titles and dashboard cards. Its open, rounded shapes keep a compliance product calm and readable, and the bold weights give a long Journey clear signposts without shouting.
Your checks. Your judgement. Your records. Inter carries the body text, form labels, calendar cells and admin tables. It stays crisp at 14 and 16px on dense screens, so a Journey question, a Companies House result or a task's due date is easy to read while an agent works through a client file.
Primary
Navy
#1F2F5A
Headings, body text, header and footer
Contrast: White text 13.02:1 AAA
Green
#5FB26A
Primary buttons and the brand mark
Contrast: White text 2.60:1 Fails
Navy text 5.00:1 AA
Teal
#4FA7A3
Links, focus ring, step markers
Contrast: White text 2.84:1 Fails
Navy text 4.58:1 AA
Secondary
White
#F5F5F5
Page background
Contrast: Navy text 11.95:1 AAA
Background
#E2E8F0
Borders and dividers
Contrast: Navy text 10.56:1 AAA
Body
#4A5568
Secondary text
Contrast: On white 7.53:1 AAA
Caution
#D97706
Warnings, Medium badge
Contrast: On white 3.19:1 Large text only
Alert
#DC2626
Errors, Overdue
Contrast: On white 4.83:1 AA
Contrast decision
Green and teal are fills, not text colours
Measured against WCAG 2.2, white text on the brand green is 2.60:1 and on teal 2.84:1, below the 4.5:1 that body text needs. Our design handoff flags both. The rule: the brand shades stay for fills, icons and borders, navy text sits on them, and wherever green or teal has to carry text it moves to a deeper shade that passes AA. This page follows the same rule.
- Green for text#5FB26A → #387D42 · 5.02:1 on white
- Teal for text#4FA7A3 → #2F7F7B · 4.73:1 on white
Components, rebuilt from the tokens
A few of RiskBright's interface pieces built here in HTML and CSS from the app's tokens (radii 4, 8, 12 and 16px; 48px inputs), with the AA text shades applied.
- 2 pending
- Low
- Medium
- Overdue
Compliance Journey
- Work type
- Party role
- Customer type
- Customer checks
- Risk questions
- Considerations
- Word record
SaaS rebuild FAQ
SaaS development, Replit to Next.js migration and AI integration: Questions, answered
What founders ask us before we audit, rebuild or extend a SaaS product, from a Replit prototype to a production app.
Ask us anythingYes, and we start with an audit rather than a rewrite. For RiskBright we reviewed the Replit prototype (a client-rendered Vite and React app on Express with a Postgres database) for security, SEO, performance, structure, dead code and third-party integrations. The findings set the plan: keep what holds up, rebuild what does not. RiskBright needed a full rebuild, so we moved it to Next.js with a Node.js and Express API on MongoDB.
Yes. Search engines and link previews need real HTML, so public pages are server-rendered with their own titles and descriptions, a sitemap and a robots file that keeps the private app out of search. RiskBright went from a single-page app to a Next.js App Router build of 52 pages across the marketing site, the app and the admin panel.
Yes. We build retrieval-augmented features that answer only from your own content and show the passages they used. RiskBright's HMRC Guidance Search embeds 98 passages of HMRC's estate and letting agency guidance; answers run at temperature 0 under locked rules (answer only from the excerpts, keep must apart from should, never call a client compliant), with monthly quotas per plan, an answer cache and usage reporting for the admin.
Yes. We set up subscription plans and one-off purchases in Stripe, keep each account's plan in sync with your database, and handle Stripe webhooks with idempotency, so a retried event never applies a payment or a plan change twice. On RiskBright, subscriptions and a toolkit purchase both run this way.
Yes. RiskBright looks up companies, officers and people with significant control through the Companies House API with a cache in front, sends 11 kinds of transactional email through Resend, stores files on AWS S3, generates Word documents and refreshes the FATF high-risk list behind an admin approval step. Each integration gets input validation, error handling and logging.
It depends on the scope. RiskBright took about two months, July to September 2026, from the audit of the Replit prototype to the production app with its admin panel and integrations. We quote after a short call and a first look at your product, so you know the scope before we start.
We design for it from the first sprint: input validation on every route, rate limiting and secure headers, short-lived access tokens with refresh tokens, hashed passwords, role-based admin access and an audit log. We also keep data to what the product needs. RiskBright removes completed journeys after 7 days, because the Word record the agent keeps is the real deliverable. We test every release before it ships.
We can. Maintenance covers dependency and security updates, monitoring, fixes and new features. We also build an admin panel, so your team runs content, users, templates and AI settings without a developer.
Got a Replit or AI-built prototype?
Let’s do a project together!
Send us the link. We audit it the way we audited RiskBright, then take it to production: Next.js, Node.js, Stripe billing and AI with clear limits.
How we take a prototype to production
- Prototype
- Audit
- Rebuild
- Launch







