Junkyard Watchdog hero
in progress published Sep 04, 2025 featured

Junkyard Watchdog

Smart alerts for salvage-yard treasure hunters iOS app.

Laravel 12 MySQL Expo / React Native Tailwind CSS Stripe Mailgun Cloudinary

~/overview

Why

Junkyard Watchdog keeps a pulse on self-service junkyards across the nation so you never miss the donor you have been chasing. It ingests inventory on a tight cadence, normalises the data, and delivers actionable alerts when something hitting your watchlists lands on the yard.

What's inside

  • Laravel 12 + MySQL backend with Sanctum auth, notification scheduling, and real-time ingest health dashboards
  • Expo/React Native client (iOS + web) with garage management, watchlist creation, and digest controls
  • Admin tooling for sources, locations, digests, and operational telemetry
  • Stripe-powered monetization, Mailgun email, and push notifications wired through Expo

Launch track

Currently build 1.0.0 is being review in App Store Connect, and hope to be live asap!

~/timeline

2025

Hit Submit!

Wrapped up the last blockers and finally shipped the 1.0 build off to App Review. Knocked out the 12.9" iPad screenshots, answered the App Privacy questionnaire in detail (every data type, why we store it, and where...

App Store Prep Marathon

Today was all about teeing things up for App Review. Locked in the App Store copy (subtitle, keywords, privacy/support URLs) and mirrored the final text in docs/launch/app-store-prep.md so we don’t lose it later. Seeded...

Launch Freeze Mode

Pulled the lever on the feature freeze today. Logged the policy, ran every automated test we have (Laravel, lint, Jest, Playwright against staging and prod), and rotated the last batch of production secrets for good meas...

Production Housekeeping

Checklist day! I spun up the jw-prod-01 droplet, installed the usual suspects (PHP 8.4, nginx, MySQL, Redis, Supervisor), and pointed the domain so we’ve got real HTTPS before launch week kicks in. Secrets got rotated, t...

Watchlist Polish Party

Spent the day sanding down the last rough edges on watchlist and garage cards. The old tinted backgrounds were fighting dark mode, so I rolled them back to the base surface palette and let a bold unread border do the hea...

Making The Watchlist Form Feel Nice

The watchlist dialog had been giving off total panic energy—every time I typed a name the cursor hopped around like it drank six espressos. On Sep 22 at 9:06 PM EDT (commit b8957ec) I finally called it: time to build my...

My Car-Part Rabbit Hole

I went into Sunday promising myself “just a little recon.” By 4:05 PM EDT (commit a61e61d) I had accidentally built an importer. Classic. The plan was to poke around Car-Part’s mobile site, scribble some notes, and keep...

Mailgun & Deploy Triage

I thought the day would be quiet, then staging decided digest emails should fail in the queue. Turns out the deploy script was writing literal "null" strings into the SMTP env vars—good times. I rolled the work...

Stripe Checkout, But Make It Chill

I woke up thinking I’d sneak in a “quick Stripe tweak” before lunch. You already know how that goes. Around 1:10 PM EDT I pushed commit 4bf5cc7, which basically means I finally admitted the native app needed a friendly l...

Cashier Weekend Warrior

Spent Saturday getting serious about billing. Pulled in Laravel Cashier, let Stripe own the subscriptions, and added the migrations so users carry real plan records instead of our homemade enums. The new BillingManager h...

Admin Refresh & Future Plans

Gave the admin area a well-deserved spa day. Every page—from Sources to Client Logs—now shares the same layout, and the quick actions are where your thumb expects them. While the polish dried, I queued up the welcome and...

Staging, Steady As She Goes

Quick check-in day. Staging’s humming on DigitalOcean with the deploy workflow rolled back to the stable script, production deploys now require a manual green light, and the admin UI finally feels like it belongs to the...

Staging Sprint

Infrastructure day. I wired up Terraform apply/destroy workflows, scripted the “provision an existing droplet” flow, and taught GitHub how to run diagnostics on demand. Staging now knows how to restart Supervisor, renew...

Digest Controls & Dev Rhythm

Today was short and sweet. I knocked out the TypeScript warning in the skeleton loader (React Native’s percent units are picky), then jumped into the admin digest tools. You can now preview a digest for any user, resend...

Dialing In Radius & Digests

Started the day babysitting the U-Pull-&-Pay job—added friendlier logging, cached the make IDs, and made sure we can recover from weird HTML without nuking memory. Once that calmed down, I turned to location stuff: A...

Garage Love & Better Logs

Today was all about making the garage tab feel like a place you actually want to hang out. I tightened up the list layout, styled the matches drill-down, and dropped in a lightweight Home screen that bubbles up nearby fi...

Night Shift Notifications

Couldn’t sleep, so I wired up the rest of the notification stack. Account now shows your devices, lets you yank stale tokens, and even fires a local test push so you know Expo heard you. On the backend I started pruning...

Types, Clarity, and Calling It

After the Tamagui experiment, I put the UI back on Paper and went hunting for the TypeScript warnings that CI kept grumbling about. TanStack Query v5 changed how keepPreviousData works, so I swapped it for placeholderDat...

Autocomplete Jam Session

Coffee in hand, I dove straight into the make/model picker. The goal: make it feel like a native app, not a busted spreadsheet. I sketched out aliases so “Chevy” and “Chevrolet” finally hug it out, added indexes so the s...

Afternoon UI Glow-Up

Post-lunch energy went straight into sanding rough edges. Every screen got the compact PageHeader treatment so titles stop screaming, the inventory list moved to Paper’s List.Item with that little NEW chip tucked in the...

The Tamagui Detour

I couldn’t resist seeing what Tamagui felt like in the app, so I took a hard left and ported everything for a day. New tokens, new provider, new buttons—the whole nine. The dialog turned into a barebones modal, autocompl...

Late-Night Wrap-Up

I should’ve closed the laptop, but the app was so close to feeling cohesive that I kept going. I ripped out the goofy Theme tab, tucked the switcher onto the Account screen where it actually belongs, and made sure every...

Kicking The Tires

First day back in the garage and everything creaked. The admin sync endpoint was wide open, the scraper still had a rogue dd() hiding inside, and the frontend was glued to a hard-coded API URL. I spent the morning doing...