The firm did not want another subscription with its name on the invoice and someone else's name on the product. It wanted a system of its own: one codebase serving two very different audiences, built around the firm's actual commercial rules, and safe enough to hold its clients' financial information.

  • Pipedrive
  • Notion
  • Reconcile
  • Returns engine
  • Isolation layer
  • CRM & portal

01 — The brief

A book of investors, run from three places

People and their owning sales reps lived in Pipedrive. Contracts, terms and signature dates lived in a Notion register. Everything else lived in email. The team could run the business that way; the investors could not see any of it. Every “what is my position”, every missing statement and every payout date was a message someone had to answer by hand.

The firm asked for one platform with two faces, and set three constraints that could not bend:

  • IsolationNo investor may ever see another investor's data. Not in the interface, not through the API, not through a file link.
  • No phoning homeNothing in the product may call out to a third-party vendor the firm has not approved.
  • Truly white-labelledNo trace of any underlying framework may be visible anywhere in the product.

02 — What we delivered

One codebase, two audiences

A single self-hosted application. On one side, an internal CRM where the investor-relations team runs investors, contracts, payouts and documents. On the other, a client portal where each investor signs in to their own portfolio, returns schedule and document vault.

The legacy systems stay authoritative and read-only. The platform syncs from them twice a day and never writes back, so the team did not have to change how it works to get the new system.

  • PipedrivePeople and their owning sales repRead-only · ~50,000 contacts
  • NotionThe contract registerRead-only · terms, signatures, dates
  • Admin entryInvestors and contractsTyped directly in the CRM

Ingest & reconcile

Contacts matched on name plus email or phone. Ambiguous matches quarantined, never guessed. Every row commits or rolls back on its own.

Core record model & returns engine

Investor, investment, valuation, payout, document and newsletter across 68 record types, with the firm's real contract terms applied.

Isolation & cryptography layer Every request passes through here

Row-level permission cascade, record-bound field encryption, hardened credentials, and a log of every document access.

Internal CRM /crm

The investor-relations team: records, payouts, analytics, newsletters, sync consoles.

Investor portal /portal

Each investor, and only their own: portfolio, returns, documents, profile.

Outbound & operations

Mail through the firm's own Microsoft 365 mailbox, encrypted backups, and a hardening routine on every deploy.

03 — Ingest and reconcile

Messy human data, matched without guessing

Around 50,000 contacts came from Pipedrive, and the contract register came from Notion. Both were entered by hand, which means inconsistent names, missing details, and the same sales rep written several different ways.

Contacts are matched on name plus an email address or a phone number, never on a name alone. Sales-rep names written several different ways are resolved to the right person. Anything that could belong to more than one person is quarantined for a human to decide.

Clean match

  • Source row
  • Name + email or phone
  • Sales-rep alias resolved
  • Committed on its own

Ambiguous match

  • Source row
  • More than one candidate
  • Quarantined
  • Weekly data-quality report

Each row commits or rolls back on its own, so one bad record never takes a whole sync down with it. A weekly data-quality report lists every gap that is left, as a worklist the team can clear.

In a financial system, a confident wrong match is worse than an honest “we are not sure”.

04 — Core record model and returns engine

The firm's real commercial rules, written into the engine

Underneath both faces is one record model: an investor holds investments, and each investment carries its valuations, payouts, documents and newsletters. In total it spans 68 record types.

  • Investor
  • Investment
  • Valuation · Payout · Document · Newsletter

A contract engine applies the terms the firm actually sells, rather than a generic template. Payouts follow each contract's own start date, not the calendar quarter, so two investors who signed in different months each get their own correct schedule.

  • The firm's own return terms
  • Fixed contract duration
  • Scheduled payouts
  • Counted from each contract's start date
  • Maturity tracking
  • Swiss IBAN validation
  • Payment reference per investor

05 — Isolation and cryptography

For an investor, their own records are the only ones that exist

The first constraint shaped the whole architecture. Isolation is not a filter on a screen; it is a layer that every request passes through, and it was designed in from the first phase rather than added at the end.

  • Row-level permission cascadeAn investor's own records are the only records that exist for them. Proven by probing the API and file URLs directly, not just the interface.
  • Record-bound field encryptionSensitive fields are encrypted and tied to the record they belong to, so encrypted values cannot be copied from one investor to another.
  • Hardened credentialsCredentials are hashed with a server-side secret and held outside the framework's own store.
  • Access loggingEvery document access is logged, whether it was granted or refused.

06 — The two faces

Same data, very different jobs

The team needs every record and the tools to act on them. An investor needs one portfolio, explained clearly, and nothing else. Both run on the same codebase and the same records, so the numbers on either side can never disagree.

Internal CRM

/crm

For the investor-relations team.

  • Investor and contract records, documents, banking details
  • Payout schedules, maturities and return tracking
  • Portfolio analytics: capital under management, pipeline, activity
  • Newsletters written and sent to selected investors
  • Sync consoles and the weekly data-quality worklist
  • Portal access invited, enrolled and managed per investor

Investor portal

/portal

For each investor, and only their own portfolio.

  • First sign-in by an emailed one-time code, then their own password
  • A personal dashboard the investor arranges themselves
  • Capital, current value, returns by contract year, upcoming maturities
  • A private document vault for statements and contracts
  • Newsletters and in-app notifications
  • Self-service profile, IBAN and payment reference

07 — Outbound and operations

Nothing leaves that the client has not approved

The second constraint, no phoning home, applies to everything around the application as well as the application itself.

  • All mail leaves through the firm's own Microsoft 365 mailbox. No mailbox password is stored anywhere.
  • Backups are encrypted in chunks and are useless without the key vault.
  • A repeatable hardening routine disables every unused integration and vendor callback on each deploy.
  • Separate development and production environments, enforced in code rather than by convention.
  • The live product makes no outbound call the client has not approved.
  • The interface loads nothing from an external CDN.

08 — Delivery

Eight phases, each one signed off before the next

The build ran from August to September 2026 in eight gated phases. At the end of each one the client tested what had been built and signed it off, and only then did the next phase begin. Nobody had to wait for a big reveal to find out whether the system was right.

  1. 01Signed off
  2. 02Signed off
  3. 03Signed off
  4. 04Signed off
  5. 05Signed off
  6. 06Signed off
  7. 07Signed off
  8. 08Signed off

09 — What it is built on

The building blocks

  • Custom applicationOne codebase for the backend, sync jobs, contract engine and both interfaces
  • Single record storeThe same records behind the CRM and the portal, so they never disagree
  • Pipedrive & NotionRead-only sources, synced twice a day
  • Microsoft 365Mail sent from the firm's own mailbox, with no password stored
  • Encryption & access loggingRecord-bound field encryption, hardened credentials, every document access logged
  • Self-hostedNo per-seat licence and no dependency the client cannot end

10 — Why it matters

Software a firm trusts with its clients' financial data

Before

Sales CRM + Notion contract register + email → every investor question answered by hand

After

One self-hosted platform → the team runs the book in the CRM, each investor sees their own position in the portal

  • Trust as a featureData isolation, encryption and access logging designed in from the first phase, not retrofitted.
  • Real integration workTwo live third-party systems reconciled against messy, human-entered data.
  • Genuinely white-labelledThe client's product, with no vendor's name or logo anywhere in it.
  • Owned, not rentedSelf-hosted, no per-seat licence, no dependency the client cannot terminate.

This is the kind of work where being wrong is expensive: a system close to regulated finance, delivered end to end by a small team. The hard part was not the screens. It was finding the real commercial rules underneath a short brief, and building something a firm is prepared to put its clients' information into.