Secret Key Mint
Minted metal coins carrying a QR code the owner can repoint forever — with the scan metrics to prove it worked.
Secret Key Mint sells a physical object with a software promise attached: a precision-minted coin — a "Key" — whose engraved QR code resolves through infrastructure we run rather than pointing at a URL that will eventually rot. The destination is a database row, so a client can repoint a coin that is already in someone's pocket, at any time, forever. Behind the splash sits the whole business: a QR designer that refuses to export a code it could not itself scan, a redirect engine with per-slug scan analytics, customers, products, invoices, and a client portal. One Go binary, one SQLite file.
- Go 1.26
- SQLite (WAL)
- html/template
- Vanilla JS
- qr-code-styling
- Postmark
- Google Cloud Storage
- Apache
- systemd
- just
Secret Key Mint mints custom physical coins — "Keys" — that carry a QR code pointing at infrastructure we operate. That single layer of indirection is the entire product. A printed QR code is a promise you cannot keep: the link dies, the campaign ends, the company rebrands, and the object becomes litter. A Key's destination is a row in a database, so the coin in someone's hand can be repointed years after it was struck.
Works forever, by design
The hard part of selling a permanent object is what happens when the customer relationship ends. The answer here is a deliberate one: a slug marked minted — meaning a physical coin exists that carries it — can never hard-404. Forwarding is free and permanent. The monthly fee buys powers: scan metrics, self-serve repointing, custom branding on the resting page. Let it lapse and the coin degrades gracefully to a branded resting page that still logs the scan; it never becomes a dead link. The whole decision is a single pure function with unit tests around it, because it is the one behaviour that would betray a customer holding metal.
The QR designer that refuses to lie
- A scan-verify gate. Export is blocked until the
rendered code is decoded back —
BarcodeDetectorwhere the browser has it, ajsQRfallback where it does not. A styled QR that renders beautifully and does not scan is the single most expensive mistake available in this business, because you only discover it after a thousand coins are struck. - Engrave and print modes — different module shapes, gradients, and quiet-zone handling for laser-engraved metal versus ink on paper.
- Forced error correction H whenever a logo is embedded, so the mark cannot eat the payload.
- SVG plus 2048px PNG export, archived to object storage as the artefact of record for that coin run.
A business, not a link shortener
- Scan analytics per slug — asynchronous logging off the redirect hot path, bots and dry-run test scans excluded from the counts, CSV export.
- Funnel to customer to invoice. Quote requests arrive with attachments (sniffed server-side, disk authoritative, mirrored to object storage), thread themselves by email address, and promote into customer records that carry their whole history.
- Products and invoices with cents-based pricing and frozen unit prices on issued lines, so editing a price list never rewrites history.
- A client portal where a customer sees their own Keys, repoints them, and reads their own scan metrics — gated by entitlement, with no self-registration anywhere in the system. Access is granted, never claimed.
- Email both directions — Postmark outbound, plus a token-gated inbound webhook that files replies into the admin inbox.
How it's built
One Go binary and one SQLite file
in WAL mode. Rendering is html/template; the front end
is hand-written CSS and JavaScript with no framework, no bundler and
no node_modules in the serving path. Migrations are
additive-only — columns are never rewritten or dropped, because a
coin struck last year still has to resolve. Deployment is a systemd
unit behind Apache on a single host; just ship runs the
tests, builds, restarts and health-checks it.
The codebase enforces its own conventions in CI: files stay under 150 lines and functions under 30, a headless browser harness probes every admin page for console errors and axe-core accessibility failures, and a static gate scans the whole tree for words that must never appear in anything a client could see.
Straight from the source
The project's own README.
Rendered in place — every link, image, and code block carried over from the repo. The page below is what a contributor would see opening the project for the first time.
Secret Key Mint
secretkeymint.com — we mint custom physical coins ("Keys") that carry a QR code you control: the code points at a redirect we host, so the destination can change at any time — long after the metal is struck — with scan metrics included.
Single Go binary, SQLite, html/template, vanilla CSS/JS. No frameworks, no build pipeline. Public splash + contact/quote funnel + admin panel.
Live: https://secretkeymint.com
Docs
Start at docs/quick-start.md. Roadmap/status in docs/PROGRESS.md. Per-feature docs in docs/feature/. Founding directives in docs/project/.
Commands
just # list all recipes
just dev # run locally with race detector
just ship # test + build + restart service + health check
just check # tests + lint + scrub gate
Private repository — all rights reserved.
Build something like this
Want a tool like this for your shop?
We've shipped this kind of thing before. Twenty-minute intro call, no slides.