Building the Rental Atlas: a civic data platform, not a brochure
True North Housing Alliance connects Butte County residents with housing and the services that make housing stick. When we started, the org had the relationships and the local knowledge — what it didn't have was a working data tool. Not a marketing page. A map of the county's rental stock, and a directory of the services residents actually get referred to.
Three audiences, one dataset
The thing that shaped every decision here: the audience is three-sided. Residents searching for a place to live. Caseworkers making referrals. Local government looking at the same numbers everyone else is looking at. One dataset, three very different ways of touching it — so the data model had to be right before the UI did anything interesting.
What shipped
Two public tools, plus the machinery that keeps them honest.
The Rental Atlas is an interactive map covering 5,700+ properties across the county, with HUD Fair Market Rent calculations built in and flags for post-Camp-Fire rebuilds, Section 8 acceptance, and student housing — the details that actually change whether a listing is useful to the person looking at it.
The Community Services Directory catalogs 200+ services across 12 categories — food, shelter, mental health, legal aid, and more — so a referral is a link, not a rumor a caseworker half-remembers.
Behind Supabase-gated auth sits the admin suite: address and APN imports, property management, a resource hub, an AI copilot for data curation, and a GitHub-bound code workspace. Data platforms live or die on upkeep, so the admin tooling got as much attention as the public-facing map.
The part I care most about: the scraper
Property data goes stale fast, and stale civic data is worse than no data — it sends people to addresses that don't exist anymore. The scraper engine runs Puppeteer in stealth mode with a native-fetch fallback, a four-strategy extraction pipeline, and a GPT-4o-mini fallback for pages that resist all four. Everything that comes out the other side gets normalized through Zod before it touches the database, and writes are idempotent upserts — re-running the scraper never duplicates a row.
The scrape endpoint fetches arbitrary URLs by design, which makes it an SSRF target by default. It's guarded accordingly. An endpoint that fetches whatever URL you hand it is a liability right up until you make it not one.
Splitting the codebase
The project started life inside the Quenga Designs monorepo, under a /true-north route. In July 2026 I split it into its own repository so the alliance's tools and the studio site could deploy independently of each other. The two apps share a Supabase project, so the split needed zero data migration — just a new deployment target and the old paths becoming the new site's root.
Where it stands
Live in production on Vercel, serving residents, caseworkers, and local government from one codebase, still on the same data pipeline described above. A custom domain is the remaining step — the metadata and sitemap are already staged for it.
Read the full case study, or see the platform's stack in the portfolio.