A bilingual community resource platform for Central Texas families — taken from a blank page to four shipped products in one continuous run. Brand, UX, design system, front end, database, analytics, and a second map-based product. One team, no handoffs.
Food pantries, rental assistance, clinics, legal aid, school programs — across Central Texas the services are real and funded. The information about them is not. It lives in PDFs emailed between case workers, in Word documents last updated two years ago, in spreadsheets with dead phone numbers.
A family that needs rent help this week has to know which organization to call, whether they qualify, whether anyone there speaks Spanish, and whether the address on the flyer is still an address. The people doing the connecting — navigators, promotoras, church volunteers — were doing it from memory and paper.
Puente ATX arrived with a mission and nothing else. No brand, no site, no database, no name on a business card.
Not "Spanish available." The default locale is Spanish; English is the toggle.
44px targets everywhere, a list that works when the map fails, and a real print stylesheet.
A directory that lists a closed pantry is worse than no directory at all.
Asking an undocumented family to register is asking them to leave.
The reference point for "government services website" is institutional blue, gray tables, and a tone that makes you feel processed. Puente ATX needed the opposite: it needed to feel like a neighbor gave you a phone number.
The palette is warm and earthed — a cream canvas, a deep brown ink instead of black, and a single terracotta accent that does all the pointing. Brown on cream reads at 9.75:1, so the warmth costs nothing in legibility. There is no second accent and no gradient anywhere in the product. When everything on the page is quiet, one orange element is enough to direct the entire screen.
The mark is a bridge. Headings are set in Poppins — geometric, friendly, self-hosted so it renders identically on a low-end Android and a MacBook — paired with a humanist sans for body copy.
Ten tokens carry the whole product: three surfaces, two ink values, two accent values, three border weights. They live as CSS custom properties in one file and map straight into the Tailwind theme — so the public site, the admin console, and the map product are physically incapable of drifting apart.
People don't type "housing." They type "no puedo pagar la renta." Search covers localized titles, organization names, summaries, descriptions, keywords, categories and service area in both languages — and every filter state lives in the URL, so a navigator can send a family a link to a filtered result set instead of instructions for reproducing one.
There is no login on the public site. Saved resources live in the browser as a list of public slugs — no names, no email, no identifiers — and a list can be shared as a URL or a WhatsApp message containing nothing but those slugs. A shared list is previewed before import and never silently overwrites what someone already saved.
Six results, then a button. Infinite scroll destroys the ability to print, to share a position, or to know how much is left — all of which this audience needs more than it needs smoothness.
Spanish runs roughly 20% longer than English, so every button, card and label was sized to the longer string first. Below 800px the four-column category grid becomes two; at 480px the search button drops below the input rather than crushing its label; at 320px categories go to a single column. Every one of those breakpoints was set by Spanish, not English.
Halfway through, a distinct problem surfaced: search-by-keyword is the wrong interaction when the real question is what is near me right now. So we designed a second product against the same database and the same tokens.
Enter a ZIP code and an optional category; get the nearest resources with list and map synchronized, nearest first. The ZIP centroid becomes an approximate origin — generated from official U.S. Census sources, covering 100 ZCTAs across five counties — and the search expands through a radius ladder of 15 → 30 → 50 miles until it finds something.
The list holds every essential detail and stays usable when the tile provider is down. Desktop splits 38% list / 62% map; mobile toggles, with only one map instance ever mounted.
Every location is geocoded once, reviewed by a person, and stored with a status. Addresses without a unique match stay unpositioned — and the interface says how many are pending review rather than dropping them quietly.
Real labels, native controls, keyboard-selectable cards and markers, selection never signalled by color alone, reduced-motion fallback for the location pulse.
Puente ATX needed to answer real questions — which categories people search, which areas generate the most searches, what people search for and don't find — to talk to funders and decide where to recruit resources next. For an immigrant-serving organization in Texas, that makes the analytics layer a safety question, not a growth question.
The constraint was written before the first event fired: the system must be unable to identify anyone, including by us. A closed allowlist of 16 events. No writes from the browser. Reads that return aggregates only. Anonymity thresholds enforced in the database — an area appears on the map only with at least 20 searches and 10 distinct sessions behind it, and below that the suppressed counts never leave PostgreSQL. The choropleth renders local Census polygons with no third-party tiles at all.
Every metric is defined in a published data dictionary that states its formula, its source, its thresholds, and — the part that matters — its limitations. "Contact actions" counts taps on a phone number. It does not measure whether anyone answered. The dashboard says so, on the dashboard.
The implementation was written with Codex and Claude Code — but the leverage was never in generating code faster. It was in writing the specification first.
Every subsystem got a document before it got a component: the resource system, the finder, the analytics contract, the referral module, the map methodology. Those documents defined the data model, the routes, the security posture, the privacy thresholds, and an explicit list of things the system must never do. The code was then generated against them, and the documents stayed in the repository as the source of truth.
That inversion is what let a six-week scope survive contact with reality. When the dashboard needed a new metric, the change started in the data dictionary. When the finder needed a fifth county, the expansion procedure was already written down, in order, with the official data sources named.
The least glamorous piece was the most valuable: a review-and-import pipeline that turned eight community documents — a family resource guide, an eviction solidarity handbook, a counseling list, a healthcare catalog, a county roster — into hundreds of validated bilingual records, and a directory that now holds 728. Duplicates consolidated, URLs recovered from Excel hyperlink objects, missing Spanish translated, every record written as a draft, and every import shipped with a report naming the judgment calls and what was deliberately left empty. Converting a document is not the same as verifying a fact, and the system says so.
"The bridge is only useful if people trust it will hold."
Every specification in this project has a section listing what the system must never do. That section, more than any feature list, is what kept a fast build from becoming a liability for the people it serves.
Generation was never the hard part. Deciding what the product should refuse to do — invent a coordinate, store a ZIP as if it were a person, show a map cell with four people behind it — was the work.