PROBLEM
Your bank shows transactions, not subscriptions
I was driving to Shiphaus CHI #1, a one-day build hackathon in Chicago in late February 2026, when a bank notification told me a subscription charge had just gone through, one I had been meaning to cancel for weeks. I made a mental note to deal with it later and forgot before I parked. That was the product.
Bank apps tell you money left, never that it leaves every month for something you stopped using. The real question is not what am I subscribed to, it is why don't I already know. SubScan answers it from a single statement upload, with no account to connect and nothing stored.
THE BUILD
What I set out to make
The concept was simple on the surface: drag and drop a credit card statement, get back a clean list of subscriptions with amounts, categories, and a cancel link where one exists. No account, no persistent storage, no friction. I owned the whole thing: concept, UX, build, and deployment.
Three targets going in:
A working demo inside the first hour
A deployed product before the event ended
The AI doing the real work, not keyword matching against a list of known merchants
EXECUTION
Four hours, four problems
The interface was the fast part: drag and drop with multi-file support, and three states, a loading view with per-file progress, a results view with cards for subscriptions found and monthly and annual totals, and category tabs, all off clean fintech dashboard patterns. The four hours went to what came after.
The AI needed real prompt engineering
The system prompt carries the product. It has to separate subscriptions from one-time charges, loan payments, and transfers on the same statement, and return clean structured JSON. That took several iterations. For PDFs I used PDF.js to pull the text in the browser first, sending about 50kb of text instead of a 5MB file, which kept statements off the server and made the privacy line on the upload screen real.
Deployment surfaced the real architecture
The React build worked in the artifact environment but broke on Netlify, where the browser was blocked from calling the API directly. I rewrote the frontend in vanilla JS and put a Netlify serverless function in front as a proxy, which also kept the API key off the client.
The timeout forced sequential processing
Parallel file processing hit the ten-second function timeout on the first multi-file test, so I switched to one statement at a time. Not elegant, but correct.
Logos ran into content security limits
Merchant logos load from a CDN, but content security policy rules blocked part of that, and plenty of niche merchants have no clean logo anyway. I built a letter-avatar fallback, so a missing logo never leaves a blank row.
DESIGN DECISIONS
The calls AI didn't make
The first build came back in dark mode. It looked sleek. I changed it to light, because a financial tool earns trust by reading as transparent and credible, not as a product trying to impress. The model had no reason to reach for that.
An early version colored the stat numbers, red for high and teal for low. I changed all three to black. Color implies a verdict, and surfacing what you pay is not the same as judging whether it is too much.
Cancel buttons only appear when a confirmed cancellation URL exists. Putting one on every row was easier, but a cancel button that leads nowhere destroys trust faster than no button at all.
The exclusion logic in the prompt is domain knowledge, not engineering. It tells the model to drop the recurring charges that look like subscriptions but are not: installment loan servicers, gym memberships, in-person services. Ten years in fintech is what told it where the line sits.
OUTCOME
What shipped
SubScan went live at subscan.mosullivan.design before the hackathon ended. It takes PDF and image uploads across browsers, processes multiple statements in sequence, categorizes what it finds with Claude, and surfaces a direct cancel link for the major services. The API key lives in Netlify environment variables. Statements are processed and never stored.
WHERE THE HOURS WENT
~10 min
WORKING DEMO
~1 hr
DESIGN AND POLISH
~3 hrs
DEPLOYMENT
The thinking was fast. Production was the tax, and it has never been smaller.
REFLECTION
What an AI build still needs from a designer
The shift was from using a tool to directing one. I was not drawing screens, I was deciding what good looked like and catching the wrong turns early, which is the part that does not get faster with a better model. The rebrand, the color call, the dead-end cancel button I refused to ship, the merchants I told it to ignore: none of that came from the AI.
That is what 25+ years buys in an AI-native workflow. A junior designer with the same model may reach a deployed app just as fast and ship the dark mode, the colored numbers, and the cancel buttons that go nowhere, because the model will not stop them. The production barrier between thinking and shipping has mostly collapsed. What is left is judgment.
+
Production stopped being the bottleneck: idea to deployed was four hours, most of it deployment, not design.
+
Domain knowledge is the moat: knowing an installment loan is not a subscription is what separated a useful scan from a noisy one.
+
The system prompt is a design surface: what the tool returns is shaped by how you instruct the model, which makes it a UX decision.
+
Judgment shows in what you refuse to ship: the dark mode, the colored numbers, and the dead-end buttons were all easy defaults I overrode.


