Mathew Hager

Explore Kingston

A mobile-first tourism platform for a Washington ferry town, live in production. Built solo, unpaid, for the Greater Kingston Chamber of Commerce.

Why it exists

On 1 June 2026, the ferry line moved.

Kingston is a ferry town. The Edmonds–Kingston run is Washington's second-busiest route, carrying nearly 4 million people a year, and its holding line used to idle through downtown.

That summer WSDOT switched on a new traffic system for State Route 104. The queue now forms a mile up the highway, drivers collect an automated boarding pass from a kiosk, and anyone without one is turned back to the end of the line.

It fixed line-cutting and downtown gridlock. It also left arriving drivers guessing at the rules, and downtown without the captive queue that used to sit outside its storefronts.

The chamber's question was how to help visitors and businesses adjust. The answer was this app, including a page built for a driver parked in the line: pass rules, next boats, food, restrooms, loading instantly on cellular.

What it does

  • Ferry planning with live Washington State DOT sailing and drive-up space data
  • Eat & drink listings with live open-now badges driven by a real hours engine
  • Events, parking payment links, lodging, webcams, tides. The practical answers a visitor actually needs
  • A fullscreen kiosk mode for the town's physical information terminal
  • A public business directory with member profiles and a map

The constraint that shaped everything

One developer, no reviewer, no budget, and a real deadline.

A volunteer project has no code review, no product owner, and nobody to notice a shortcut. The usual result is software that works and cannot be handed to anyone.

That was the actual risk here, and it was not hypothetical. An app a town depends on, understood by exactly one unpaid person, is a liability dressed as a contribution.

The interesting constraint was never can this be built. It was can it be built so that my leaving is survivable.

The decision: build it as though a team would inherit it

Every governance practice that normally exists because someone enforces it, applied with nobody enforcing it.

Not for tidiness. The handover was the requirement.

  • 369 test files across two suites, one of which runs against real Postgres rather than a mock
  • Architecture decision records. Seven of them, each naming the option rejected and why
  • Dependency-boundary linting, so the layering is machine-enforced instead of remembered
  • Lighthouse CI with a performance floor that fails the build
  • A freeze manifest. A list of files that agents may not edit without a human, enforced by a pre-edit hook and a CI check, not by a comment asking nicely
  • Around 35 documents covering architecture, data provenance, operations, incident response, and restore drills

The result is currently 496 source files and 511 commits across 164 merged pull requests. A pull-request workflow maintained by someone with no one to review the pull requests.

The first option I rejected: ship it the way solo projects get shipped

A volunteer project has higher handover risk than a funded one, not lower.

No decision records, no boundary lint, no freeze manifest. There is no reviewer, and every one of those costs time that could go into features. For a weekend project that is the correct call.

It is the wrong call here, and the reason is counter-intuitive.

A funded team has payroll, onboarding, and people who will still be there next quarter. A volunteer project has one person's attention, and that attention is the single point of failure.

The discipline is worth more precisely where nobody is requiring it.

The second option I rejected: keep renting the membership system

This scope arrived during planning, not as a pivot.

Writing user stories, I reached the chamber-admin stories and realized the stack already being built for the ferry problem could carry membership management too. Staff were unhappy with the incumbent, and the marginal cost was near zero.

Beyond tourism, the app is becoming the chamber's membership system of record, replacing a commercial association-management product. The safe option was to keep paying for it and let the app stay a brochure. What made the decision serious is a one-way door.

The incumbent product auto-renews annually. Written non-renewal notice is due well before term end. And there is no data export after termination. Get the sequence wrong and the records are simply gone.

So the plan is written export-first. Everything comes out while the subscription is still live. The app becomes the system of record before anything is cancelled. The accounting system keeps owning the money.

That sequencing is the whole decision. The build is the easy half.

This one is in progress, not finished. The rollout is phased and deliberately slow. Claiming an outcome here would be claiming something I cannot yet show.

Cycle time

First production build: five weeks, from empty repository to live app.

Roughly 468 commits and 446 TypeScript files between 2 July and 4 August 2026. Development has continued since.

The number worth noticing is not the speed on its own. It is the speed with the test suite, the decision records, and the gates already in place. Those are usually what gets dropped to hit a date.

What this doesn't prove, and one thing it got wrong

It is not evidence of stakeholder management.

There was no client, no procurement, and no organisational resistance to move. It is evidence that I build, and that I build to a standard when nobody is checking.

And the documentation is aimed at the wrong reader.

Around 35 documents for humans. The agent-facing configuration is a single file of a few hundred bytes.

I built a codebase that a person can learn and an AI assistant largely cannot navigate. That is a strange thing to have done while using AI assistance to build it.

Fixing it is now in progress: the chamber gets its own Claude plan, a memory and onboarding tool, an MCP server, and staff enablement. The goal is a product the chamber can maintain and improve, not a codebase they inherit.

Built with

Next.js, TypeScript, Drizzle and Postgres, deployed on Render, with a token-driven accessible design system. The same discipline this site runs on.