Building to a written spec instead of a vibe
Chekka's whole pitch — "before you buy, Chekka" — is that an independent professional inspects a used car so the buyer doesn't have to gamble. When the product is trust, you can't improvise the definition of "verified" halfway through the build. So Chekka started from a written specification.
A real spec, honestly sized
The spec (Chekka_Core_Features.md) is about 4,728 words across 596 lines —
twelve numbered core features plus a "Tech Stack & Code Conventions" section.
It isn't enormous; it's dense and structured, and its most useful trick is that
it ships the code skeleton the build then follows verbatim. The route-handler
shape and the Mongoose model conventions are written into the spec itself, so
"spec" and "scaffold" are the same document, and the build follows a contract
instead of rediscovering scope in code review. (One correction worth making
plainly: an internal brief called this a "37k-word" spec — the verified count is
4.7k. Precision is the point of a spec; it should extend to describing the spec.)
Descended from the reference architecture
The spec doesn't invent conventions — it inherits them. Chekka is explicitly
"built on the same conventions as managerenta-client" (README line 5): the same
server-only src/server/ triad, the same withApiHandler(withAuth(...)) route
skeleton, the same pre/post("aggregate") hooks, databaseResponseTimeHistogram
timers, select:false soft-delete, and model memoization. The infrastructure is
deliberately unsurprising so the surprise budget can go entirely to the domain.
The domain is a lifecycle
The core entity is inspections, and its status field is a one-directional
state machine: submitted → assigned → (declined) → scheduled → in_progress → report_processing → completed. Each transition stamps its own timestamp
(assignedAt, acceptedAt, startedAt, reportDeadline, completedAt,
reportLockedAt), and dashboards bucket off the status — declined is
intentionally excluded from every bucket. Assigning an inspector at creation
stamps assignedAt and jumps straight to assigned; pricing is computed
server-side from an admin-tunable siteConfig plus a flat urgent surcharge, never
trusted from the client.
Report integrity is the product
A report a buyer paid to trust must be immutable once filed, and its numbers must be the server's, not the client's. On submit, Chekka recomputes the summary counts from the checklist item statuses across all four sections and refuses to touch a locked report:
if (current.reportLockedAt) throw ErrReportLocked;
const all = [...report.exterior, ...report.interior, ...report.mechanical, ...report.roadTest];
const summary = { ...report.summary,
passed: all.filter((i) => i.status === "good").length,
minor: all.filter((i) => i.status === "minor").length,
serious: all.filter((i) => i.status === "serious").length };
if (lock) { patch.status = "completed"; patch.reportLockedAt = new Date(); patch.completedAt = new Date(); }
Locking flips the status to completed, stamps the lock/complete timestamps,
publishes a report_filed event to the admin live feed over Redis pub/sub, and
notifies the buyer. Sharing a finished report is then a read-only, self-expiring
capability: a uuidv4() nonce maps to the inspection id in Redis under a 7-day
TTL, so the link grants unauthenticated read access to one report and the
inspection id never appears in the URL.
Why the spec paid off
Report integrity, S3-backed photo evidence (an append-only collection with a
race-safe photoCount), and a booking flow that schedules real humans are the
three things that carry the product; everything else is plumbing in service of
them. Because those three were pinned in writing before the first route existed,
the build could be aggressive about the plumbing and careful about the trust —
which is the correct place to spend care in a product that sells verification.
The delivery leaned on 15 Playwright specs across booking, the inspection
flow, photo upload, the live feed and share links; the thinner unit story (no
Vitest here) is itself an honest line in the ledger.