Case study · Fintech / pensions · 2025

One screen for all of a saver's pension money, in 8 days

An early-stage Israeli fintech venture wanted to show investors and partners a mobile app that pulls a person's pension, provident and study-fund policies from the national pension clearing house and turns them into a single, readable picture. I designed and built the proof of concept end to end: a secure API layer, a data mapper for a deeply nested Hebrew payload, and a mobile-first, right-to-left dashboard.

React 19TypeScriptVite 7Tailwind CSS 4Redux ToolkitNestJS 11JWT / PassportSwaggerTypeORM / SQL Server
Client
Israeli early-stage fintech venture, consumer pensions & savings (confidential)
My role
Team lead & architect (hands-on)
Stage · Timeline
Clickable POC · Jul 29 – Aug 5, 2025
Status
Proof of concept
At a glance
684 to 3raw data points in one clearing-house response, reduced to 3 headline cards
≈48 to 9fields per policy, mapped to a 9-field typed model the UI can trust
≈45 to ≈1 minestimated time for a saver to see all their policies in one place
8 daysfrom first commit to a working, demo-ready flow across 2 repos
0clearing-house credentials in the browser. The API key lives server-side only.
4JWT-protected, Swagger-documented API endpoints
The problem

The data exists, but nobody can read it

Most Israeli employees hold several long-term savings products: a pension fund, one or more provident funds and a study fund, often with different providers. The national clearing house can return all of them in one response, but that response is built for institutions, not people. One sample answer for three policies holds 684 data points, with Hebrew field names, nested tables, numbers stored as text with thousands separators, and the same field arriving as a list in one policy and an object in another. A saver who wants to know “how much do I have and how is it doing?” usually ends up logging into each provider separately.

What I built

A thin, safe path from raw payload to a clear answer

  • Designed the architecture and set up both repositories: a React single-page app and a NestJS API.
  • Built the API layer: JWT sign-in, a clearing-house module for data requests, transaction status and policy retrieval, and Swagger docs at one URL.
  • Wrote the mapper that turns each policy's ≈48 Hebrew-keyed fields into 9 typed fields, and classifies products into short- and long-term horizons.
  • Built the mobile-first RTL flow from the design: sign-in, a 7-field consent form (3 required, 9-digit ID), and a dashboard with balance-weighted returns per horizon.
  • Gated every build on lint and type-checking, and cleaned out unused code before the demo.
Architecture

The browser never talks to the clearing house

The diagram is wider than the screen: swipe sideways to see all of it →

For the demo, the dashboard reads a recorded clearing-house response through the same mapper the live data will use. Switching to live data is a change in one service file; nothing in the UI changes.

Design decisions

Keep the secrets on the server and the mess in one file

A thin API in front of the clearing house

The clearing-house key and the personal-data request never touch the browser. The NestJS layer adds JWT auth, CORS and Swagger docs, so the front end and any future mobile client share one documented contract. Trade-off: one more service to run, which is cheap compared with leaking a regulated credential.

An anti-corruption mapper

All knowledge of the payload's Hebrew keys, nested tables and inconsistent shapes lives in one mapper. Components only see a 9-field PensionFund type. Trade-off: the mapper drops most fields for now, but adding one is a single line in one file.

Demo on a recorded response, wired for live

Live clearing-house access needs licensing and the saver's signed consent, which a one-week POC can't wait for. The server routes for the live flow were built first; the UI runs on a recorded response through the same mapper. Trade-off: the demo shows real data shapes, not real-time data.

Weighted figures instead of charts

A chart library was installed and tried, but for a first screen a saver needs three honest numbers: total, liquid amount and a balance-weighted return. Charts were left for the next phase. Trade-off: less visual flair in the demo.

Engineering log

What the payload tried to break

A one-week POC still has real problems. Most of them came from the shape of the data.

Jul 30

The guard couldn't find the token service

The JWT guard on the clearing-house routes failed at start-up: the token service was registered in the auth module but not visible to the rest of the app.

Exported the JWT module from the auth module so every guarded route resolves the same configuration (1-hour tokens).

Aug 5

Same field, two shapes

The investment-track details came back as a list in 2 of the 3 sample policies and as a single object in the third. Code that assumed a list would have crashed on a real customer.

The mapper normalises both shapes before reading the track's net return.

Aug 5

Numbers that were really strings

Projected balances arrived as text with thousands separators, other amounts as plain numbers, and dates as day-month-year strings.

One parsing path for every amount and date, with safe zero defaults, so a missing field shows ₪0 instead of “NaN”.

Aug 4

An average that flattered the portfolio

A simple mean of fund returns let a small fund with a high return outweigh a large pension fund. On realistic balances the headline return was overstated by more than 2 percentage points.

Returns are now weighted by balance, separately for short- and long-term horizons and for the total.

Aug 5

“As of when?”

Each policy has its own validity date, so a single “as of” label could be wrong for half the cards.

Each card shows the latest validity month of the policies it sums, in Hebrew month names.

Aug 5

Demo-ready, not just working

Lint warnings and leftover scaffolding had built up during a fast week.

Fixed all lint warnings, removed unused code, and made the production build fail on any lint or type error.

Try it

Why the headline return is weighted

A synthetic three-policy portfolio (no client data). Switch between the two ways of computing the headline return.

Outcome

Where it landed

  • Before: a 684-value institutional payload. After: one screen with total savings, liquid amount and a balance-weighted return, plus short- and long-term cards.
  • Before: logging into each provider (≈45 min, estimate). After: one consent form and a single dashboard (≈1 min, estimate).
  • Before: no backend. After: 4 documented, JWT-protected endpoints with the clearing-house key kept off the client.
  • A clickable flow on a 390px mobile frame, right-to-left, matching the product design, delivered in 8 calendar days.
  • A 5-tab navigation already in place for the roadmap: buckets, recommendations, a personal assistant, actions and news.
  • Clear next steps: live clearing-house access with signed consent, users in SQL Server, and the AI assistant tab.
Stack

Technology stack

Front end
React 19, TypeScript, Vite 7, Tailwind CSS 4, SCSS, React Router 7
State & data
Redux Toolkit, Axios, typed API thunks, payload mapper
API
NestJS 11, Passport JWT, class-validator, Swagger / OpenAPI
Data store
SQL Server via TypeORM (scaffolded)
Integration
National pension clearing-house REST API
Quality
ESLint + TypeScript gate on every build, Jest, Prettier

Free scoping call · 30 minutes · No commitment

Bring one process. Leave with a plan and a number to beat.

Write a few lines: the process or system, what hurts today (time, errors, cost or an AI pilot that stalled) and who uses it. After a short call you get a written plan and a fixed quote within ≈3 days.

Get a free scoping callafif.mansour@gmail.com

Opens a pre-filled email · reply within one business day

The model reads. The code counts.

All projects