← Back to list

Inside the Build: What It Actually Takes to Build Something People Trust

The one project explained properly instead of in ninety seconds. Part four of four, and the one I was most nervous to write.

Nicole Drew Lazo · 2026-09-03 08:14 · 3 claps · 10.6 min read
#devcon #devcon-internship #devcon-jumpstart #ai #internships
Open on Medium ↗
Wiki topics: AI · AI · General

Inside the Build: What It Actually Takes to Build Something People Trust

The one project explained properly instead of in ninety seconds. Part four of four, and the one I was most nervous to write.

Of everything I touched in five months, the Smart Liquidation Dashboard, happens to sound, on paper, like the least exciting thing I built, which is exactly why I want to slow down here and actually explain it properly. No summary, no highlight reel. The whole thing, start to finish.

The Problem, in Plain Terms

The Flowchart

The Flowchart

DEVCON chapters request funds from the National Office and later have to liquidate them, a formal way of saying prove where the money actually went, with receipts to back it up. Both of those flows arrived, in practice, as Google Form notification emails, receipts scattered across photos, PDFs, and random Drive links. One volunteer encoder had to open every single one, retype it by hand into a seventeen-column master spreadsheet, compute VAT with an actual calculator, and hold in their memory which liquidations were still hanging open.

That process was slow by design, not by accident of laziness. It was error-prone in specific, nameable ways: duplicate entries slipping through because nobody remembers every submission they’ve already seen, VAT miscalculated because manual arithmetic is manual arithmetic, tax identification numbers mistyped because a nine and a blurry photo don’t always agree with each other. And underneath all of that sat the real structural problem: volunteers rotate. When they do, that memory, of what’s owed, what’s overdue, what chapter is dangerously close to its ceiling, quietly leaves with them, like it was never written down anywhere at all.

Put plainly, side by side: encoding a single submission by hand used to take about five minutes of retyping, start to finish. Duplicate detection relied entirely on one person’s memory of what they’d already seen that week. Liquidation status lived on a side sheet, or nowhere written down at all. And chasing an overdue chapter meant someone manually typing out a Telegram message, ad hoc, whenever they happened to remember to. None of that is a criticism of the people doing it. It’s just what happens when a repetitive, detail-heavy process is run entirely on human attention, with no system underneath catching what a tired person on a Tuesday afternoon is bound to eventually miss.

A Distinction I Didn’t Know I Needed

Before any of the actual building, I had to understand a piece of DEVCON’s own financial vocabulary that the whole product hinges on: a Seed Fund is not a Cash Advance, even though both are, colloquially, “money someone asked for.”

A Seed Fund is a chapter or member requesting funds from the organization, and it has to be liquidated, receipts and all, afterward. A Cash Advance is the organization itself requesting funds from HQ, a completely different relationship one level up the chain. This dashboard tracks the first one. It deliberately does not track the second, not because it was forgotten, but because no form, no email pattern, and no existing data source for Cash Advances currently exists to build against. Building a feature for data that doesn’t exist yet isn’t ambition, it’s guessing, and guessing is exactly what this entire product exists to stop doing. That single vocabulary distinction, learned in week one of this specific project, ended up shaping where the whole system’s boundary sits.

What We Built

A single-page, browser-based dashboard, built around four core surfaces: a live Dashboard view, a Scan a Receipt flow, an Email Submissions flow, and a History ledger, backed by an audit engine and a per-chapter Budgets view, with a Weekly Telegram report running entirely unattended.

The Smart Liquidation Dashboard and Functions

The Smart Liquidation Dashboard and Functions

  1. Scan a Receipt. An encoder drags a receipt image or PDF onto the uploader, or pastes a Google Drive share link for the HEIC photos an iPhone insists on producing, which the extraction step can’t read directly on its own. The app resolves that file through a fallback chain: Drive API metadata first, then a direct download attempt, then Drive’s own JPEG render of the HEIC if the direct approach fails, then a public CDN fallback for files shared as “anyone with the link.” Once an actual readable image exists, Claude extracts all seventeen master-sheet fields through structured outputs. The three VAT figures get immediately recomputed in plain JavaScript regardless of what the model returned, using the standard divide-by-1.12 formula, every single time. Any field the model wasn’t confident about is left empty and highlighted amber rather than guessed at. The encoder reviews a split view, the actual receipt zoomed in on one side, the editable extracted fields on the other, and clicks “Copy Row for Spreadsheet,” which runs the audit engine, commits the entry to history, and updates that chapter’s budget spend.
  2. Email Submissions. Both request types arrive today purely as Google Form notification emails, so the dashboard connects to Gmail with read-only access and runs a query, either the default or a shortcut preset like “fund requests only.” Each email gets classified and extracted in a single Claude call into one of three buckets: Seed Fund, Liquidation, or Other. Amounts are never taken from email text alone; attached receipts and linked Google Sheets get opened and read too. An Auto-process mode can poll for new matching emails every two minutes, and a running processed-and-skipped ID list, combined with the same invoice-and-TIN duplicate check used on the receipt side, keeps that automation from silently double-encoding anything. The encoder can process an item, skip it, view the raw email body if something looks off, or send it to the receipt tab for closer manual review.
  3. Confirming and Tracking a Liquidation. Every scanned or emailed liquidation lands in History as “Awaiting” and contributes nothing to Total Liquidated or to any chapter’s spend total. A human has to review it and toggle it to Liquidated, the only action that moves it into confirmed totals. An entry can also be separately marked Included or Excluded; excluded rows get dimmed and drop out of every money metric and report, but stay visible in History and in CSV export, so nothing actually disappears, it just stops counting.
  4. The Weekly Telegram Report. Every Monday morning, Manila time, a scheduled job runs the exact same report-building logic that the dashboard’s own “Preview” button uses, so what a person sees on-screen and what gets sent are always identical. The message covers a summary of the week, activity from the last seven days capped at twelve items with an “and N more” line if there’s overflow, seed funds pending liquidation grouped by how overdue they are, and any chapters currently over budget. A seed fund becomes officially “overdue” in both the dashboard and the report the moment it passes its due date with an outstanding balance over one peso, named specifically, not just counted.

It runs on a static host and a small number of serverless functions, deliberately unglamorous infrastructure, because the organization running it is staffed entirely by volunteers with no budget for a dedicated team quietly keeping the lights on.

The Design Decision That Mattered Most

“The AI extracts, a human confirms.”

That was never just a tagline we liked the sound of. It was a real constraint on every single screen we drew. No submission ever counts as final money movement until someone clicks to actually mark it liquidated. An extracted receipt lands in the system as awaiting, and contributes nothing to any total until a real person reviews it. It’s a slower way to build than just trusting the model outright, and it was still the right call. This dashboard feeds an organization’s real, authoritative finance sheet, the master Google Sheet remains the actual system of record; this dashboard exists to feed it correctly, not to replace it. Fast and wrong helps absolutely nobody. A little slower and right is worth every extra second.

The Tech Stack, Briefly

For anyone curious about the actual pieces: extraction and email classification run on Claude, called with structured outputs so the response is constrained to exactly the shape the master sheet expects rather than free text to be parsed afterward. Gmail and Drive access run through read-only OAuth, meaning the dashboard can see submitted receipts and linked sheets but can never write back to either service, by design, not by oversight. The entire client is a single self-contained page with no build step, styled with Tailwind loaded from a CDN. Hosting is a static host plus a small handful of serverless functions on Vercel, with a single Supabase table holding the shared workspace state. Scheduling runs on Vercel’s own cron, which is what fires the Monday morning report without anyone needing to remember to.

It’s a deliberately small stack for a deliberately small team to maintain. Impressive-sounding architecture wasn’t the goal. A volunteer being able to understand and fix it eight months from now, without me in the room, was.

What This Deliberately Doesn’t Do

Almost as important as what got built is what got explicitly ruled out, on purpose, in writing, before anyone could scope-creep their way into it by accident.

This is not a system of record. The master Google Sheet stays authoritative; this dashboard exists purely to feed it correctly, never to replace it as the source of truth. It is not a multi-user system with roles or a per-person audit trail, at least not yet, a single shared workspace was accepted as the tradeoff for shipping something real quickly. It never writes to Gmail or Drive under any circumstance, strictly read-only, always, no exceptions carved out for convenience. It does not track Cash Advances, for the reason above. And it does not approve spending. It records what happened and reports on it; it was never designed to be the thing that authorizes money to move in the first place.

Saying “no” to all of that, in writing, before building anything, is probably the single most underrated skill I picked up this internship. It’s much easier to add scope later than to walk it back once people are depending on it.

The Audit Engine, Specifically

Extraction gets the model. Validation deliberately doesn’t. Every entry that reaches the “Copy Row for Spreadsheet” step passes through an audit engine that runs four checks in plain, predictable code: a duplicate check comparing invoice number together with the vendor’s tax ID against every existing entry, a missing-field check for anything still blank after review, a VAT-mismatch check comparing the recomputed figures against what’s on the entry, and a future-date check, since a receipt dated after today is either a typo or a red flag worth a second look either way.

None of those four checks involve asking a model anything. They’re deterministic, boring, and completely explainable to a non-technical finance lead in one sentence each, which was exactly the point. The parts of this system that decide whether something is wrong were never going to be the same parts that might occasionally be wrong themselves.

Getting the Threshold Wrong Before Getting It Right

Deciding exactly when a field counts as “confidently extracted” versus “leave it blank and flag it” isn’t a one-time decision, it’s a dial that has to be tuned against real receipts, not hypothetical ones. Too strict, and encoders end up manually filling in fields the model actually had right, which defeats the entire point of automating this in the first place. Too lenient, and a wrong number slips through wearing the same confident, unflagged appearance as a correct one, which is the exact failure this whole design exists to prevent.

Getting that balance right took actual iteration against messy, real-world receipts: crumpled ones, poorly lit ones, ones photographed at an angle nobody would recommend. There’s no elegant formula that gets you there on the first attempt. There’s just running it against enough real, ugly input until the amber flags start showing up on the right fields, for the right reasons, often enough that an encoder starts trusting the flag itself as meaningful signal rather than noise to click past.

What I Actually Learned

Deterministic math will always beat confident math. The second I realized I could just recompute the arithmetic myself, five lines of JavaScript, every time, I stopped needing to trust a model’s version of it at all, ever again.

  1. Design it to be rotating out next month, not the one sitting here today. Institutional memory is basically the entire reason this project gets to exist.
  2. Empty and flagged beats wrong and confident, every time. Watching the extraction engine leave a field blank rather than guess changed how I think about every AI feature I will ever design from now on.
  3. Boring infrastructure isn’t a compromise. It’s kind of the whole point, actually.
  4. A duplicate check is only as good as the fields it actually compares. Using invoice number together with the vendor’s tax ID, rather than either one alone, catches the specific, real-world case where two different vendors happen to number their receipts the same way, something a simpler check would have quietly missed.
  5. And a report is only trustworthy if the preview and the delivered version are provably the same message. Building the Monday cron job to call the exact same function the in-app preview button calls, rather than a similar-but-separate version of it, was a small decision that removed an entire category of “wait, that’s not what I previewed” problems before they could ever happen.

What’s Still Ahead

This is a live prototype, not a finished product, and it’s honest about that in its own roadmap. A few things planned for what comes next: moving authentication and workspace isolation to a proper, dedicated phase rather than the current single shared setup; routing AI extraction calls through a server-side proxy so the API key never has to live in a browser at all; making the sync between devices concurrency-safe instead of last-write-wins; adding an interactive side to the Telegram bot, so a finance lead could ask it directly for pending items, budget status, or open audit flags instead of only receiving the weekly push; and eventually writing directly to the master Google Sheet through its API, removing the current manual “Copy Row” step as anything more than a fallback.

None of that is a secret. It’s just next. Every real product has a version after this one, and the honest version of “what I built” includes admitting what it doesn’t do yet.

What I find genuinely satisfying about that roadmap is how unglamorous every item on it is. Nobody’s proposing a flashier AI feature or a slicker interface. Every planned phase is about making the existing promise more solid: safer access, safer key handling, safer concurrent edits, a more direct connection to the sheet it feeds. That’s what a maturing product actually looks like once the exciting part, proving the core idea works at all, is already behind it.

Get Involved

DEVCON runs programs like this all year, nationwide, and none of them move an inch without people willing to show up for the parts that never make it onto a slide. If this series made you want to be one of those people:

👉 **Follow DEVCON Philippines on Facebook**


메타데이터
post_id
e4758e20a9a5
slug
inside-the-build-what-it-actually-takes-to-build-something-people-trust-e4758e20a9a5
url
https://medium.com/@lazonicoledrew/inside-the-build-what-it-actually-takes-to-build-something-people-trust-e4758e20a9a5
canonical_url
https://medium.com/@lazonicoledrew/inside-the-build-what-it-actually-takes-to-build-something-people-trust-e4758e20a9a5
author_url
https://medium.com/@lazonicoledrew
status
ok
fetched_at
2026-09-07 21:42:04