Onward — the owner who is leaving meets the one who is arriving.
Most small businesses never change hands. The owner is ready, the business is sound, and there is no mechanism — brokers work the top of the market, and below that line an owner is left asking a question nobody will answer for free: what is this actually worth?
Onward answers it first and asks who you are second. The estimator on the homepage runs without a sign-up, and the data model enforces that promise rather than merely honouring it: estimates are append-only, carry no identifying columns, and none may ever be added. Identity is a separate opt-in written in the same transaction as its consent record. Lead capture is switched off in configuration until there is a backend that can do both halves atomically.
Behind the estimate is the part brokers do: a readiness plan, a listing, buyer qualification, diligence, an LOI, encrypted document exchange, and the messages in between — both sides of the table, in one product.
The engineering decision I’d point at is the triage agent. It reads a Slack channel, investigates each report against the code, files a ticket and answers in thread. It began as a scheduled task inside my own session, holding my credentials, with “read-only” and its circuit breakers written as sentences in a Markdown file. Now every one of those limits is a line of code: a checkout it cannot push from, no shell and no file-writing tool at all, one channel, one project, tokens that are refused if they are broad enough to read a user profile. What the model still owns is judgment. The containment is what bounds the damage when judgment fails — and that is the lesson worth carrying into someone else’s organization.
Visit onwardlegacy.com
- Two surfaces, one product A static marketing site carrying the valuation estimator and its API, and a Next.js 15 marketplace app on Auth.js and Drizzle behind it — separate deployments, one npm workspace, one backlog.
- A valuation estimator that refuses to guess A three-layer taxonomy — buckets, sectors, hand-curated aliases — matched deterministically with no fuzzy fallback. An unmatched trade returns low confidence and says so; it never quietly lands in a default bucket, because a confident wrong multiple is worse than an honest shrug.
- A data model that keeps the homepage’s promise The page offers an estimate without asking who you are, so estimates are an append-only table with no PII columns and none may ever be added. Identity is a separate opt-in, written in the same transaction as its consent row — channel, scope, timestamp, and the exact version of the consent language shown.
- Documents encrypted before they leave the app Ciphertext in Vercel Blob, per-document keys wrapped in Neon under a versioned master key. Rotation rewraps every live key and never touches a blob; without the key the store refuses to work rather than falling back to plaintext.
- The build refuses to ship without its secrets A preview or production build fails on a missing auth secret, mail key, document master key or blob store — and says what breaks without each, rather than deploying a site whose signed-in routes silently redirect.
- A seeded demo cast, quarantined Personas confined to one demo domain that reset cleanly, plus a dev sign-in that writes a session row directly — and refuses to run against a production environment or any connection string resolving to the production host.
- An autonomous triage agent, contained in code It sweeps a Slack channel, investigates each report against the codebase, files a Jira ticket and replies in thread. Every limit is a line of code rather than a sentence in a prompt: a read-only clone whose push URL is disabled, no shell and no file-writing tool at all, one channel and threads only, one Jira project, purpose-scoped tokens checked against a scope canary, and circuit breakers on tickets, turns, dollars and wall clock.
- Identity verification and payments Stripe Identity on the accounts that need to be real, because the whole market rests on a stranger being who they say they are.
- 552 tests Across 48 files, run on every branch against a real Postgres.
Register · Onward
Live from Jira, Confluence, GitHub and Vercel · updated 12:43 PM ET
github.com/productdetroit- Days building
- 30Since 29 August 2026, day one for Onward.
- Work items delivered
- 101Stories and tasks closed Done in Jira, in production.
- Median idea → live
- 17hoursMedian created → resolved, all issue types.
- Spec → shipped
- 2hoursMedian epic lifetime: Confluence spec to production.
- Specs written
- 54Problem, data model, architecture decision — before code.
- Epics complete
- 1/23Done of created. The rest are sequenced, not stalled.
- Pull requests merged
- 75
- Production deploys
- 172
- Lines of code
- 152,740
- Reviewed by me
- 100%
- Last shipped
- Margaret gets an intro video in the demo (ONWARD-105) 3 days ago