Lulu Bank: AI Banking App

How I vibe-coded a working AI banking app, from a real Postgres ledger to a streaming assistant

Most banking concepts are screens. I wanted one where the money actually moves.

Solo. I designed and built the whole thing with AI coding agents: the Expo app, the Express API, the Postgres schema, and the AI assistant.

Role

Designer and Builder

Category

Vibe Coded · Fintech

Timeline

2026

Lulu Bank: AI Banking App

6

Screens: home, transactions, cards, chat, profile, transfer

1

Postgres ledger with atomic transfers

SSE

Streaming AI assistant

IBAN

Mod-97 valid accounts, generated per user

Solo

Designed and built by one person

“Powered by AI · Not financial advice”

From the app's assistant screen

01

Overview

The context

Lulu Bank is a digital banking app I built for myself, end to end, using AI coding agents. It is not a Figma prototype with tappable hotspots: it is an Expo mobile client talking to an Express API over a real PostgreSQL database, where a transfer actually debits one account and credits another.

I wanted to find out what happens when a designer stops handing off and starts shipping. The answer, mostly, is that the interesting problems move from 'what should this look like' to 'what happens when two people send money at the same time'.

02

Challenge

The problem

Vibe coding gets you a convincing screen in minutes. It does not get you a bank. The hard parts showed up immediately:

Fake data hides the real design problems

An agent will happily hardcode a balance of €6,820 and call it done. But a balance that never changes never forces you to design the empty state, the failed transfer, or the race between two screens.

Money needs to be correct, not plausible

A transfer that looks right but leaves the ledger unbalanced is worse than no transfer at all. Correctness had to live in the database, not in the UI.

AI features drift into decoration

An assistant that answers 'what can you do?' with marketing copy is a demo. It had to read the actual account and act on it.

Design and code can drift apart fast

With no handoff step, nothing stops the app and its API from describing money differently. That gap has to be closed structurally.

The core problem: make an AI-built banking app where the money is real, the failures are handled, and the assistant is a feature rather than a widget.

Home, Insights and Cards: balance and quick actions, spending broken down by category, and virtual cards with a freeze toggle.
Home, Insights and Cards: balance and quick actions, spending broken down by category, and virtual cards with a freeze toggle.
AI assistant, transfer and profile: suggested prompts, a money-transfer flow with recent contacts, and account settings.
AI assistant, transfer and profile: suggested prompts, a money-transfer flow with recent contacts, and account settings.
03

Approach

The process

Put correctness in the database

Transfers run as a single Drizzle transaction against PostgreSQL. The API rejects self-transfers, insufficient funds and unknown IBANs before anything is written, so a half-completed transfer cannot exist.

Give every account a real IBAN

Each new user gets a generated, mod-97-valid IBAN rather than a random string, so transfers look up a real counterparty and the transaction history can join back to the person who sent the money.

Treat auth as a first-class surface

Signup, login and logout with scrypt-hashed passwords and random 32-byte bearer tokens stored as sessions. The design of the signed-out state mattered as much as the dashboard.

Make the assistant do the work

The AI screen streams over SSE and opens with the actions people actually want, pay €25 to Marco, show my latest transfers, request €40 from Emma, instead of an empty prompt box waiting for inspiration.

Generate the contract, don't retype it

The API is described once in an OpenAPI spec, and Orval generates the typed client hooks and Zod schemas from it. The app cannot quietly disagree with the server about what a transfer is.

04

Outcome

The result

The app runs as a real product rather than a prototype:

A working ledger

transfers move money atomically between two IBANs, with self-transfer, insufficient funds and unknown-account cases all handled explicitly.

Six connected screens

home, transactions, cards, AI chat, profile and transfer, each reading live data rather than fixtures.

A streaming assistant

the AI screen answers over SSE with suggested actions grounded in the account, not a generic chatbot.

A typed contract end to end

one OpenAPI spec generates the client hooks and validation schemas, so the app and API stay in step.

Building it myself changed what I notice as a designer. Most of the decisions that made the app feel trustworthy were not visual: they were about what the system does when something goes wrong.

05

Key learnings

What I took away

AI writes the screen, not the system, the agent produced a balance in minutes and a correct ledger only after I designed the transaction rules myself.

Correctness belongs in the database, putting transfer validation in a single Postgres transaction removed a whole class of states the UI would otherwise have to explain.

Generated contracts beat good intentions, one OpenAPI spec generating both client hooks and schemas stopped the app and API drifting apart with no handoff step.

Suggested actions beat an empty prompt, opening the assistant with real account actions made it a feature instead of a chat box.

More projects

AllpdfTools: PDF Workspace

AllpdfTools: PDF Workspace

HDDP: Health Data Playground

HDDP: Health Data Playground

Contact me

Let's work together

Have a project in mind, or just want to say hi? I'm always open to new conversations.

Get in touch