17
Chapter 17

Lessons That
Cost Me Time

Every lesson here was learned the hard way. Some cost hours, some cost days, one cost me three days of lost revenue. None of them are in any tutorial. If this chapter saves you even one of these mistakes, the whole guide was worth reading.

15 min read|Story|Shaen Hawkins
payment-webhook.ts — the three-day bug
// Stripe webhook handler
const event = stripe.webhooks.constructEvent(body, sig, secret);

if (event.type === 'checkout.session.completed') {
  const session = event.data.object;
  
  // Update subscription status
  const { error } = await supabase
    .from('subscriptions')
    .update({ status: 'active' })
  .eq('stripe_id', session.custmer_id)  // typo: custmer_id
  
  // No rows matched. Error is null. Stripe gets 200.
  // Database unchanged. User never activated.
  // Three days before anyone noticed.
  
  return new Response('ok', { status: 200 });  // "success"
}

Silent Failures Are the Most Expensive Kind

When something breaks loudly — an error message, a crash screen, a red warning — you notice immediately and fix it. Problem solved in minutes. The dangerous failures are the ones that look fine on the surface but are quietly doing the wrong thing underneath.

I had a payment webhook that received notifications from my payment processor, returned a "success" code (so the processor thought everything was handled), but did not actually update my database because of a typo in a variable name. Users were paying for subscriptions and not getting access. The payment dashboard showed successful transactions. My database showed nothing.

The disconnect went unnoticed for three days until a user emailed asking why their account was not upgraded. Three days of broken payments because the system looked fine from every angle. The fix was one line of code.

"Never trust that something works just because it does not fail visibly. Verify the complete chain."

Do Not Chain Risky Actions Together

Computers follow instructions literally. If you tell a computer "check if this file exists, then copy it somewhere" and the file does not exist, the computer might proceed to the copy step anyway and create an empty file — or crash in a way that is hard to diagnose.

Break complex operations into separate steps and check the result of each step before proceeding. Do not assume step 1 succeeded just because step 2 started running. Computers do not have common sense. They execute the next instruction regardless.

When your AI writes a sequence of commands, make sure each one includes a check for the previous one's success. "Copy the file. Then verify the copy exists before doing anything with it." This feels paranoid until the first time it saves you from cascading failure.

CASCADING FAILURE Step 1: Copy file FILE NOT FOUND x continues Step 2: Process EMPTY FILE = BAD DATA Step 3: Save to DB PRODUCTION CORRUPTED No checkpoint. No rollback. Data gone.
SAFE SEQUENCE Step 1: Copy file Verify: exists? Step 2: Process Verify: valid? Step 3: Save to DB Each step verified. Failure caught early.

Pick One Source of Truth for Everything

When the same information lives in two places, eventually those two places will disagree. It is not a question of if — it is when. Decide upfront which system is the boss.

Payment Status

Your payment processor is the boss. Your database follows it, not the other way around.

User Profiles

Your database is the boss. The single authority for user data.

External API Configs

Your external API provider is the boss. Database mirrors it, never the reverse.

Write this down. When two systems disagree, you look at the source of truth first.

Apple Will Reject You — Plan For It

Your first rejection feels personal. It is not — it is standard process. Build the review timeline into your plan. Do not schedule a launch date until you are approved. Read rejections carefully, address exactly what they flagged — nothing more, nothing less. Do not sneak in extra changes, because it resets the review.

AI Is Confidently Wrong on a Regular Basis

It Invents APIs

"Just use the .autoSync() method." There is no autoSync method. If something sounds too convenient, verify it exists before building on top of it.

It Contradicts Itself

Recommends architecture A, then fifty messages later recommends B. Your written documentation survives longer than AI's conversational memory.

It Adds Complexity to Hide Uncertainty

Sometimes the right answer is "I do not know" but AI builds an elaborate workaround instead. If a solution feels over-engineered, push back: "Is there a simpler approach?"

It Loses Context

Around message 30-40, understanding degrades. Start fresh conversations with your documentation rather than pushing through a degrading thread.

Money Saves Time, Always

Every significant time loss I experienced had a "pay a little to avoid this" option that I skipped.

The ProblemCost of SkippingCost of Fixing
Slow builds on free tierHours of waiting per month$99/mo EAS Pro
No monitoringHalf a day per incident, 2-3x/monthHalf a day setup (free)
No documentation20 min re-explaining, 5x/day1 hour of writing

The math is always the same: spend a little upfront, save multiples downstream.

"The builders who ship successfully are not the ones who never make mistakes. They are the ones who build systems that catch mistakes before they reach users."

What Comes Next

This guide will keep growing. AI tools evolve every month. New platforms emerge. Best practices change. Chapters will be updated and new ones added as the landscape shifts.

If you have read this far, you know more about building an AI product alone than 99% of people who talk about it. The gap between knowing and doing is just one step: start. Pick your stack (Chapter 2). Open your first AI conversation (Chapter 4). Build something small. Break it. Fix it. Document what you learned (Chapter 6). Repeat.

That is the whole game. Welcome to it.

Topics Covered
Silent FailuresWebhook DebuggingChained OperationsSource of TruthApp Store RejectionsAI Hallucination PatternsContext DegradationTime vs Money Trade-offsDocumentation