RWA Customer Portal
A Next.js portal giving customers self-serve dashboards over their own data, with a staff console behind it.
Why there is no measurement
Measured internally at RWA — not mine to publish
No measurement
Why not
This runs in production and its usage is measured internally, but those numbers are RWA's rather than mine and are not mine to publish. I would rather show the gap than publish a figure I cannot let anyone check, or leave the project off the site because the result is inconvenient to evidence.
Problem
Customers needed their own view onto their data — dashboards, benchmarking, reports — without a person at RWA pulling and sending it by hand, and without every customer seeing every other customer's numbers. Internally, the team running the platform needed a different set of controls entirely: who gets access to what, which modules are configured for which account, what support requests are open. Two audiences, two sets of needs, and a single account model has to keep them apart correctly every time.
Approach
One Next.js application, split by route group into a customer-facing area and a staff area, sitting behind a shared auth layer rather than two separate deployments. What a signed-in user can reach is resolved from their account rather than assumed from which URL they typed, and the same session and revocation checks run in front of both halves. Dashboards themselves are largely embedded Tableau views, wrapped in a layer this project owns so sizing, loading state and failure handling are consistent regardless of which view is on screen.
Components
-
Tenant-scoped dashboards
Evidence: MEASURED INTERNALLY — NOT PUBLISHABLECustomer-facing pages — benchmarking, mapping, reporting — built on embedded views and gated so an account only ever resolves to its own data.
-
Tableau embed layer
Evidence: MEASURED INTERNALLY — NOT PUBLISHABLEA wrapper around the Tableau embedding API with its own sizing and fit logic, so every embedded view behaves the same regardless of the page it's on.
-
Staff console
Evidence: MEASURED INTERNALLY — NOT PUBLISHABLEA separate route tree behind the same login for access control, module configuration, targets and support tickets — internal operation of the platform, not customer-facing.
-
Session and revocation
Evidence: MEASURED INTERNALLY — NOT PUBLISHABLEAuth-layer middleware that can force a password change or invalidate a session outright, checked on every request rather than only at sign-in.
-
Tenant and module catalog
Evidence: MEASURED INTERNALLY — NOT PUBLISHABLEA database-backed record of which modules and dashboards a given account can reach, read by the app to decide what to render rather than hard-coded per customer.
-
Notifications
Evidence: MEASURED INTERNALLY — NOT PUBLISHABLEA per-user notification feed with its own validation step, decoupled from whatever produced the notification.
-
GDPR tooling
Evidence: MEASURED INTERNALLY — NOT PUBLISHABLEExport, erase and purge routines for a customer's data, built as a module of their own rather than one-off scripts run by hand.
-
Rate limiting
Evidence: MEASURED INTERNALLY — NOT PUBLISHABLEA shared request-limiting layer in front of the API routes, keyed off client IP rather than left to each route to implement separately.
Two audiences, one login
The obvious shape for “customers see their data, staff run the platform” is two applications. This is one, split by route group behind a shared auth layer, because the alternative means keeping two session models, two deployments and two versions of “who is allowed to see this” in sync by hand. Access is resolved from the account, not from which half of the URL space someone landed on.
Dashboards as an embedding problem, not a data problem
Most of what a customer sees is an embedded view rather than a page this project renders itself. The work that belongs to this project is what surrounds that: consistent sizing and loading state, a failure path that doesn’t leave a blank rectangle, and gating so an embedded view only ever resolves to the account that’s allowed to see it.
What is deliberately absent here
No client names, no internal metrics, no architecture diagram of an RWA system, and no mention of the sector this platform serves — even though the repository itself is not shy about it. The employer boundary on this site holds regardless of what the code makes convenient to say.