Weekly Update
Date: 2026-06-29 To: Isaac Botkin
Summary
The data migration hit its biggest milestone yet: for the first time, our real production data ran through the same machinery we’ll use for the actual cutover and into the new app — I signed in with my own existing account and watched my real scores and drills come across, and a change I made in the old app synced through to the new one automatically. This was the relational data only — photos and a short list of data-gap fixes are still ahead. Even so, it’s the most important de-risking step to date: the riskiest moment of the whole project — moving our ~70,000 existing users onto the new platform — now has a real run-through of the actual cutover mechanism, against real data, behind it. That machinery runs entirely inside our own cluster, so production data never touches a laptop. The media side — carrying photos and drill images across — is built and tested on its own; its first run against real media comes next, once we provision the storage bucket and credentials. And the remaining feature differences from the old app are now all mapped and filed; a set of migration data-decisions still has to be settled before cutover, but no gap is untracked.
On a personal note — it was a shorter week for me: I took a few days of personal time to pack up the house and family for our move out to T.REX’s office in Tennessee. Starting next week I should be in-office and in the local area for good — no more remote.
Environments
Staging
- Marketing: https://staging.range-day.app/
- Dashboard: https://staging-dashboard.range-day.app
- PWA: https://staging-my.range-day.app
Production
- Marketing: https://range-day.app/
- Dashboard: https://dashboard.range-day.app (WIP)
- PWA: https://my.range-day.app (WIP)
Beta Program & Discovery
- The pipeline held at five training organizations — no new orgs, none dropped — in a quieter week, with one real development: Patriot Academy’s first reply landed.
- Signal this week:
- A strong measurement-fit data point — Patriot Academy. Jesse “Taiyo” Nelson (Senior Instructor / Pro Shop Manager / TX LTC Instructor at Patriot Academy, Dripping Springs) sent a warm, detailed first reply — NDA complete, confirmed as one of ~four PA testers. He came up through Patriot’s scored classes (repeatedly top of the class) into instructing, and prizes student progress over time — proudest of mentoring a student into an instructor in eight months. That’s squarely the “track progress over time” user RDP is built for. His stated drag is the non-teaching grind (he also runs the pro shop); specifics still TBD.
- Status by org:
- Patriot Academy (Jesse “Taiyo” Nelson) — first reply in, NDA complete; a follow-up (how they track student progress over time) is drafted, to send.
- Cry Havoc Training (Neil Meyers) — warm wind-down; graceful close drafted, to send.
- Code Red Solutions (Ann Marie Suter) — awaiting reply since 6/17.
- Go Outside And Train (GOAT) (Jeremiah) — ball with him since 6/17; open threads: the “Thunderdome” duel idea + the email-validation bug (routed to the app devs).
- XMTG Firearms Training Academy (James Ferguson) — awaiting reply; was traveling.
Last Week
- Ran our real production data through the cutover machinery, end to end, into the new app — the relational data, in staging. The same in-cluster mechanism we’ll use for the real cutover read our live production data and migrated it into staging — roughly 70,000 users, 75,000 scores, 16,000 drills, and 26,000 hit-factor records in about 20 minutes, with production left read-only and untouched. I signed into the new app on my own existing account and saw my real scores and drills, and a change I made in the old app synced through automatically; then we tore it all down cleanly. Media and the remaining data-gap fixes are still ahead — but it’s the first real run-through of the cutover mechanism against real data.
- Built the migration to run entirely inside our own cluster — one container carrying both tools, an on-demand job for the existing-data move and a continuous service for ongoing changes, credentials kept isolated, with an operator runbook — so no production data ever runs on a laptop.
- Hardened the mechanism from what the rehearsal surfaced — fixed a false-failure in the run’s status check, made the migration steps individually selectable (so the media pass can run on its own), added a heartbeat check so we can tell if the live-sync process stalls, and added a data-integrity check that flags loudly on any mismatch and can be set to hard-stop the run.
- Finished the media migration code — photos and drill images, built and tested on its own. It hasn’t run against real media yet; that first run needs the storage bucket and credentials provisioned, and it’s next up.
- Mapped and filed the last feature-parity gaps from the forensic re-audit — friend profiles, qualifier/assessment categories, community-drill browsing, score-history trend charts, and a few smaller ones — with the remainder dispositioned as already-handled or out of scope, so nothing is left untracked before cutover.
- Extended the graceful “an update is available” message to the iPhone and Android apps (the web apps already had it), so an older phone app degrades gracefully against a newer server.
- Continued the playground exploration with a data-driven 3D drill viewer.
- The system is now backed by 974 automated tests, all passing — up from 971 the week prior. The small bump is by design: after weeks of adding tests alongside new features, this shorter week was mostly about running what we’d already built — the staging rehearsal and its checks — so the three new tests are all hardening for the migration machinery the rehearsal put under load.
This Week
- Run the media migration against real data in staging — provision the storage bucket + credentials, carry existing photos and drill images over, and confirm a new upload in the old app mirrors into the new one.
- Keep closing the feature-parity gaps — starting with course leaderboards (completing the match-scoring set), then the highest-value filed gaps.
- Work through the remaining migration product decisions the audit surfaced (the ten owed) so the gap fixes land before cutover.
- Begin reshaping the app’s UI toward a “discipline-first” layout — the home screen becomes a “what are you doing today?” launcher where the shooter picks a discipline (dry-fire, drills, flat-range, long-range, challenges) and the app tailors its tools and scoring to that, rather than one screen trying to score everything. We’re still waiting on formal design guidance, but this direction stays closest to the legacy app shooters already know while opening up new room in the interface for the features we’re adding — so it’s the best interim path to start moving on.
- Flip production crash reporting over to Sentry Cloud — pending the iOS symbol-upload step so crash reports stay readable.
Changelog
New since the 2026-06-22 update.
Data Migration — First End-to-End Run of the Cutover Machinery in Staging (relational data)
- Built the in-cluster migration mechanism: one container image carrying both the migration tool and the sync service; an on-demand one-shot job for the existing-data move and a continuous sync service for ongoing changes; credentials kept in a separate, least-privilege place; on-demand controls that are never part of the automatic deploy; and an operator runbook
- Ran it live against the real production dataset, writing into staging (production read-only, untouched): ~70k users / 75k scores / 16k drills / 26k hit-factor records in ~20 minutes; confirmed by signing into the new app on an existing account and seeing the real data, plus a live edit in the old app syncing through
- Hardened from the rehearsal: bounded the run’s result check to the job’s deadline (a long real run had been false-failing); made the migration step a selectable input (so the media pass runs on its own); added a heartbeat check for the live-sync process; added a data-integrity check that always warns on a mismatch and can be set to hard-stop the run
- Parked the one follow-up the rehearsal exposed (an in-cluster re-migrate/reset path) as a tracked, post-MVP item
Media Migration — Built, Tested in Isolation
- Finished the media path: the live-sync now refreshes its heartbeat once per photo, so a heavy batch can’t trip the health check and false-restart the process mid-transfer
- The existing-media backfill and the ongoing-media forwarding are both built and tested on their own; the remaining work is operational — provisioning the storage bucket and credentials — not code. (Badges aren’t part of this transfer — the new app shows built-in badge icons, and the old badge art was already saved off separately.)
Feature Parity — Final Gaps Mapped & Filed
- Ran a fresh per-gap review of the remaining differences from the old app and filed the build-worthy ones as tracked work items (friend profile view, qualifier category, community-drill browsing, score-history trends & grouping, range-bag suggested items + packing checklist, par-timer randomize)
- Dispositioned the rest as already-deferred or not-a-gap and recorded them, plus fixed two stale roadmap claims and flagged a dormant achievement — so every parity gap is mapped and filed (the open migration decisions are tracked separately — see This Week)
Mobile & Client Polish
- Forward-compatibility “update available” banner now on iOS and Android (matching the web apps) — an older app shows a graceful message instead of misbehaving on data from a newer server
- The shared proto-JSON forward-compatibility work is now complete across all three clients
Playground
- Data-driven 3D drill viewer — stages from data, a selector, and a fly-through camera (continued exploration; not on the parity path)
Tests & Docs
- 974 automated tests, all passing (up from 971); roadmap kept current — parity gaps filed and dispositioned, rehearsal and cutover-plan docs updated, the post-rehearsal follow-up parked