Finance, crypto assetsNext.js · NestJS · PostgreSQL

Crypto asset trust management platform: landing, investor dashboard and admin

Investors see their balance, trades and fees on live data from the trading terminal, and the website calculator uses the same code as the server — the numbers match everywhere.

In short: in eight weeks (August–September 2026) we built a complete platform for a crypto asset trust management company: a public website with a calculator, an investor dashboard fed by MetaTrader 5, a separate admin panel reachable only over VPN, an AI support chat and a mobile app. The high-water-mark fee is calculated by one shared code package on the website and on the server, so the numbers are identical everywhere.

The client and the brief

The client is a Ukrainian company that manages investors’ crypto assets under contract (we will name it once the client approves). It came with a detailed specification covering:

  • a public website: how it works, strategies, security, team, FAQ and a returns and fee calculator;
  • an investor dashboard: balance, trades, open positions, monthly fees, reports and contracts;
  • a closed admin panel for operators;
  • high-water-mark fees: a performance fee is charged only on new profit above the account’s previous peak.

The key acceptance requirement: the website calculator, the dashboard and the reports must show the same numbers.

Constraints

  • Money and trust. A fee calculation error means a dispute with an investor, and every promise on the website has to be true.
  • Sensitive data. Trading account passwords, tokens and client data. One investor must never see another’s account.
  • Terminals run in-house. Trading happens in MetaTrader 5 terminals hosted by the company. The dashboard has to read from the terminal, not from manual reports.
  • Several ways to connect an account. The spec listed multiple models — deposit, API key and future ones — to be added without rewriting the core.
  • A small team. One stack, so a single full-stack developer can maintain it.

The solution: architecture and stack

A TypeScript monorepo (pnpm workspaces and Turborepo). One language on the front end and back end gave us the most important thing: shared fee code.

Part Technology What it does
Website and dashboard Next.js (App Router), React Landing pages, calculator, investor dashboard
Core API NestJS, PostgreSQL Users, accounts, terminal data intake, fees, contracts, support
Admin panel A separate NestJS service Statistics, users, blocking, sessions, contracts, audit log
Fee engine A standalone pure TypeScript package Monthly high-water-mark calculation, identical on the site and the server
Connection models A contract package and a registry A new way to connect an account is a new module; the core stays untouched
Infrastructure Docker, Caddy, OpenVPN Images built locally and shipped to the server; the admin lives only on the VPN network

Stage 1. Foundations and the fee engine

Architecture first: the monorepo, the fee engine package with tests against a reference data set and edge cases, the connection model contract with its registry, and the first two models as plugins. A dedicated CI check stops anyone from quietly changing the fee rate in code.

Stage 2. The public website

A design system built on CSS tokens with light and dark themes, a home page of 16 sections and nine pages following the spec’s sitemap, and a live equity chart with the high-water-mark line. The calculator imports the same package as the server. A disclaimer sits under the return projection, and we reviewed the copy so the site never claims more than the platform does. Later the site moved to a black-and-white palette with a yellow accent, and fonts are self-hosted.

Stage 3. MetaTrader 5 integration

  • An Expert Advisor in the terminal sends a full account snapshot to the server; trades are stored by ticket number, so re-sending never creates duplicates.
  • Every account has its own ingest token, and the token alone decides which account the data is written to.
  • Data intake is abstract: a new trading platform is a new adapter, while storage, snapshots and fees stay the same.
  • Clients never type a broker’s technical server name: they pick the broker from a list and an operator enters the exact name after the terminal logs in. A terminal logged into the wrong account is flagged immediately.

Stage 4. The investor dashboard

Google sign-in with a server-side session, a KPI dashboard, a 12-month equity chart, live trades and open positions, a monthly fee statement, contracts and invoices. The dashboard tells “failed to load” apart from “no data yet”: there are no mock-ups, and an empty state says so honestly.

Stage 5. Admin, AI support and mobile

  • The admin panel is a separate service with no public port: access requires a VPN profile issued by the company plus an operator login with attempt limits. Every action is written to an audit log in the same transaction as the change. Blocking a user ends all their sessions immediately but does not stop trading on the account.
  • An AI support chat in the dashboard with streaming replies. The model runs locally in Docker or through any OpenAI-compatible provider, and everything it knows lives in a single knowledge file.
  • Mobile: the dashboard installs as a PWA with a bottom tab bar, there is an Android app (Trusted Web Activity) and a home-screen profile for iPhone. Trading notifications arrive via a Telegram bot and push.

Challenges and how we solved them

  • Identical numbers everywhere. Instead of two implementations of the formula (site and server), one tested package. The acceptance criterion is met by architecture, not by manual reconciliation.
  • Trading passwords. Encrypted with AES-256-GCM, never returned to the browser, and wiped once the contract is running if nobody revealed them.
  • Client isolation. Each account is tied to its owner, the API never returns someone else’s account, and a strict Content Security Policy lets the browser talk only to its own domain.
  • Spoofing the AI chat context. The browser sends only the new message and the server loads history from the database, so nobody can inject a fake assistant reply or system instruction. Limits apply per user, overall and per IP address.
  • Google sign-in inside the app. Google blocks sign-in in a plain WebView, so the Android app uses Trusted Web Activity: it runs on Chrome, and new website features appear without re-publishing the APK.

Results

We do not publish the platform’s financial or business metrics; they belong to the client. What the company got:

  • investors see real terminal data in the dashboard, not mock-ups;
  • fees are transparent and identical on the site, in the dashboard and in reports;
  • the admin panel is unreachable from the internet, and every operator action leaves a trace;
  • new connection models and trading platforms are added as modules;
  • the dashboard works on a phone like an app.

Scope: 124 commits between 3 August and 25 September 2026, from an empty repository to production with a one-script deploy.

What you can apply to your business

  • If a number matters, calculate it in one place. A package shared by front end and back end removes a whole class of discrepancies.
  • Your admin panel does not need to face the internet. A VPN and a closed network beat any password.
  • Design for extension: plugins and adapters are cheaper than rewriting the core.
  • An honest empty state beats demo data a client may mistake for the real thing.
  • PWA and TWA put your product on a phone without a separate native build.

Wondering whether an AI assistant would help your customers? Start with our piece on AI agents for business.

Related services and reading

Planning a client portal or a financial service? Send us your spec or describe the idea and we will review the architecture and estimate the phases.

Want the same result?

Discuss your project

Tell us about your project

We reply within one business day. Or message us on your favourite messenger.

  • Reply within one business day
  • Free consultation and estimate
  • NDA on request, before we start