30 Days Solo, From First Commit to Stripe Live: the order that mattered
Between 2026-07-25 and 2026-08-24, Tamperlens went from an empty repository to an API in production with Stripe billing in dollars and reais. That took 271 commits, one person. This post is not about speed. Speed is a consequence. It is about order: what came first, what came later, and why that specific sequence is the reusable part for any solo product.
First, the verifiable chronology, straight from git and the project’s records. Then, the sequencing decisions behind it.
The chronology, with timestamps
Day 1: 2026-07-25, overnight. The first commit, at 00:51, contains not a single line of product code. It is the plan: go-to-market, architecture, build and deploy plan. Two minutes later, the second commit creates the engine contract with a stub, an empty implementation that only satisfies the interface. At 01:08, the Fastify shell exists with authentication, quotas, and the free checker. At 01:23, the real engine arrives: forensic parser, the first 10 signal families, scoring, fixtures and 111 tests. At 01:27, deployed, with one manual Cloudflare step remaining.
That is: plan, contract, shell with billing-shaped auth (authentication already shaped for charging), engine with tests, production. All in 36 minutes of commits, within the project’s first hour. That same day, the entire Stripe flow was verified in test mode: checkout → signed webhook (the notice Stripe sends back) → plan applied → cancellation reverting to free.
Day 3: 2026-07-27. Stripe in live mode, verified end to end with real money: real checkout, signed live webhook, plan applied, immediate cancellation, downgrade, refund. Same day, the entry tier was created. Prices began being quoted in the visitor’s currency. And the Portuguese page started saying in plain words that Brazilian cards are charged in reais.
The rest of the month, which is most of it. A repricing closing 23 review findings, and the prepaid credit packs (July 30). A public status page (July 31). An evasion bench measured against real tools (August 3, re-run on August 15 and 24). A post publishing the product’s own false-positive rate, measured on 1,728 real documents (August 4). An evidence page with the measurements, including the ones that failed (August 6). An MCP server, the protocol that connects AI assistants to tools, packaged (August 4) and published to the official registry (August 18). And the 111 tests from day one became 1,605.
The honest reading rule: charging was possible on day 3. The product that sustains the charging took the following 27 days and is still taking them.
Decision 1: the first commit is the plan, and the plan lives in the repo
Starting with the document was not ceremony. The plan in the repository did two things a plan in one’s head does not. First, it pinned the engine contract before the engine: the second commit is the interface plus a stub, and everything else in the system was born programming against it. Second, it wrote down the scope of “ready to charge” before the enthusiasm of a late night got a vote.
The practical consequence showed up within hours. With a stable contract, the HTTP shell, authentication, and quotas could be born before the engine did anything useful. And when the engine arrived, it slotted in without a remodel.
Decision 2: deploy in the first hour, because deploy is a learning feature
The fourth milestone of day 1 is the deploy. Not because there were users, because there weren’t. It was because the commit → production pipeline is the measuring instrument for everything that comes after. Every decision of the following 29 days was made against a system running in the real place: real TLS, a real edge, real latency. That includes billing, headers, anonymous quota and the status page. The alternative is integrating everything “when it’s ready”. It charges compound interest: every day without a deploy is a day accumulating differences between the imagined environment and the real one.
Decision 3: billing verified with a real charge — and a refund
The day-3 verification deserves detail, because “I integrated Stripe” and “I verified billing” are very different claims. The test was the entire flow, in live mode, with a real card. Pay, receive the signed webhook, watch the plan land on the account, cancel, watch the downgrade happen, refund the money. Every state transition observed, not presumed.
Why so early? Because billing is the subsystem with the most external integrations and the most states (out-of-order webhooks, cancellation, currency, disputes). It is the worst candidate in the whole system for “leave it for the end”. Verifying it on day 3, when the product was small, cost hours. Discovering a mis-signed webhook on day 30, with real customers in the middle, would cost something else.
And even verified early, billing produced the cheapest-expensive lesson of the month. Weeks later, a repricing changed the displayed price. But the env var naming the Stripe Price, the identifier of the amount Stripe charges, was not repointed along with it. For a window, the site quoted one amount and checkout charged another.
The fix became an architecture rule. The plans file is the source for display and comparison. What charges is the Price the env var names. And a test compares the two. Price is the number that cannot diverge. And “cannot” only holds when a test fails.
Decision 4: USD and BRL without conversion — currency is a billing decision, not an exchange rate
The support for reais is not a conversion of the dollar price. Each Stripe Price carries a BRL amount set by hand (currency_options). There are two reasons. Stripe’s Brazilian entity can only charge Brazilian-issued cards in reais. And local-currency pricing is a positioning decision, not the day’s exchange rate.
The display mechanics are simple. A public pricing endpoint reads the country the Cloudflare edge, the network server nearest the visitor, stamps onto the request (CF-IPCountry). It then answers with the currency: Brazil sees reais, everyone else sees dollars, binary, in the first paint.
The fine point worth copying: the country decides the currency; the language is decided by a different signal, deliberately. A Brazilian in Lisbon should read Portuguese and see euros… no. They should read Portuguese and see the currency their card will pay from where they are. Mixing the two signals is how you produce the page that says $ and charges five times the printed number.
The prepaid credit packs were born from the same reading of reality. The buyer they exist for is the one who won’t sign up for a subscription. A pack quoted in dollars and charged in reais would surprise exactly the person it was meant to serve.
Decision 5: publishing measurements is product work, not marketing
From day 9 onward, a growing fraction of the commits adds no capability. It adds verifiability.
The bench measures which signals survive which file transformations, and records the result in versioned JSON. The post publishes the product’s own false-positive rate, measured on 1,728 real documents (985 public US government PDFs, 743 Brazilian web PDFs). Those are high numbers, published together with what changed because of them. The evidence page lists even the measurements that failed. And the tests tie every published number to its source, so that a release that invalidates a number breaks CI, the automated test pipeline.
In a market where nobody publishes a false-positive rate, publishing one was the only way for the claim “honest detector” to be more than an adjective. Publishing means giving the denominator, the date and the engine version. The real cost of that is not writing the post. It is building the bench that makes the post re-derivable. That cost is the product.
What the sequence inverts, deliberately
It’s worth spelling out what this playbook did not do, because each omission was a choice:
- There was no month of engine before the first possible charge. The day-1 engine had 10 signal families; today it has nearly double that per modality, and three engines. Depth came after the full pipeline existed. Every new family was born inside a system with deploys, billing, quotas, and tests waiting for it.
- There was no landing page before product. The day-1 free checker is the landing page: it demonstrates the product by doing the product.
- There was no “I’ll test it later”. The 111 day-1 tests were not decorative coverage. They were the engine contract, executable. The ratio held: ~15× more tests in 30 days, growing alongside the code, never behind it.
The sequencing checklist, for the next solo product
- Commit 1: the plan. Commit 2: the contract. Interface and stub before implementation. Everything else programs against the contract.
- Production in the first session. The pipeline is the instrument; without it, every subsequent decision is made against an imaginary environment.
- Billing verified with real money and a refund, in the first week. It is the subsystem fullest of external states; age does not improve it.
- One test linking displayed price to charged price. And a single source naming what charges.
- Local currency set by hand, decided by the request’s country, separate from language.
- Budget verifiability as a feature. Bench, measurements published with denominators, tests tying numbers to sources. It is what turns “trust me” into “check for yourself”.
Thirty days is not the impressive part. A late night and a small scope explain that. The part that transfers is that none of these six items depends on hurry: they are ordering decisions, and ordering is free.
Need a custom technical project?
Architecture, TypeScript, APIs and automation, from prototype to production. The person answering your email is the one writing the code, and the deadline I promise is the one I can meet.
Send me a message →