Roadmap — Legacy App Replacement
This track has a single, finite goal: replace the legacy Flutter app with our new native apps at full feature parity, and migrate existing users’ data — so today’s free Range Day users can move over without losing anything. A migrating user lives entirely in the new native app.
Only once parity ships do we expand into new surfaces and the paid layer — all of that lives in Roadmap — Pro & New Features. This file also holds the shared platform foundation the parity app (and everything after) builds on. Each work item links to its full spec in items/.
Target customer segment: church security teams. See Product Overview and Customer Segments.
Shared Foundation
Platform the parity app — and everything after — builds on.
Foundation
These block everything else. No feature work starts until the skeleton is in place.
- ✅ Monorepo Scaffold — Cargo workspace, directory structure, CI skeleton
- ✅ Core Crate — models, validation, scoring profiles, sync protocol, offline queue
- ✅ Proto Definitions — ConnectRPC service and message .proto files, buf config
- ✅ DB Schema — Postgres migrations for all entities
Auth & Identity
- ✅ Auth Module — registration, login, JWT, password reset, invite flow
- ✅ Email Normalization Index — case-insensitive unique index on
lower(email) - ✅ Auth Integration Tests — HTTP/Postgres smoke tests for auth RPCs via ConnectRPC
Infrastructure
- ✅ Deployment Pipeline — CI/CD, container builds, tagged releases
- ✅ Observability Setup — tracing, logging, metrics, Grafana stack
- ✅ File Storage — DO Spaces setup for user-uploaded media
- ✅ Push Infrastructure — APNs certificates, push delivery service setup
- Spaces CORS Config — repo-checked bucket CORS applied by workflow (browser presigned-PUTs; staging hand-applied 2026-07-13, prod on the cutover checklist)
- ✅ Push Service — push notification delivery (APNs + platform push), event/challenge/social notifications
Platform & Verification
Per-deployment configuration and store-readiness foundation (accepted decisions, not yet scheduled).
- Native App Platform Configuration — bundle ID revert to
com.range.day, permissions, targetSdk 36, Firebase, deep-link infra (in-place update of the ~70k-user listings) - ✅ Instance Verification & Licensing — user-configurable server URL + signed
GetInstanceInfohandshake; the per-deployment config channel (branding, capabilities,web_origin) and white-label DRM foundation
Feature Parity
Match the existing free Flutter app, feature for feature, in the new native apps.
Server APIs
- ✅ Score API — ConnectRPC service for score submission, querying, live streaming
- ✅ Drill API — ConnectRPC service for drill CRUD, visibility, copying, favorites
- ✅ User API — ConnectRPC service for user profiles, friends, social graph, user search
- ✅ Challenge API — ConnectRPC service for challenge CRUD, invitations, results
- ✅ Leaderboard API — ConnectRPC service for per-drill, per-org, friends leaderboards
- ✅ Achievement API — ConnectRPC service for badge definitions, user achievement tracking
- ✅ Achievement Triggers — server-side achievement evaluation on score submission, idempotent award
- ✅ Achievement Drill ID Criteria — migrate achievement criteria from drill-name keys to drill_id (drill renames break unlocks)
- ✅ Media API — ConnectRPC service for file upload/download, presigned URLs (DO Spaces)
- ✅ Media Multi-Upload — lift one-per-kind constraint, allow n-number photos/videos per score
- ✅ Location API — ConnectRPC service for reusable locations (ranges, facilities), org/user/public visibility
- ✅ Range Bag API — ConnectRPC service for gear/equipment tracking
- ✅ Content Feed API — ConnectRPC service for dynamic content/announcements, read tracking
- ✅ Dry Fire Score Submission — submit dry fire timer sessions as scores so dry_fire_drill_count achievement can unlock
- ✅ Personal Range Day Sharing — allow personal range days to be shared with friends via roster
Mobile (iOS + Android)
- ✅ UniFFI Setup — Swift + Kotlin binding generation pipeline
- ✅ Mobile Auth — login, registration, password reset UI
- ✅ On-Range Scoring — single-shooter, single-drill score entry, offline queue, foreground sync (multi-shooter + course scoring were deferred at MVP build — re-opened as parity gaps under “Scoring & Calculator Parity” below)
- ✅ Event View — view event details, drills, roster (read-only event visibility is part of the replacement app; event creation/admin/org workflows are Pro — see Roadmap — Pro & New Features)
- ✅ Score History — personal score history across orgs (trend chart + grouping parity → score-history-trends)
- ✅ Friends & Social — friend requests, friends list, user search
- ✅ Challenges — create, complete, and compare challenges with friends
- ✅ Leaderboards — per-drill and friends hit factor rankings
- ✅ Range Bag — gear/equipment tracking
- ✅ Achievements — badge display, progress tracking
- ✅ Favorites — bookmark drills and courses
- ✅ Media Capture — photos/videos attached to scores
- ✅ Push Notifications — receive and display event/challenge/social notifications
- ✅ Dry Fire Training — dry fire drill browsing, recommended par times, built-in par timer
- ✅ Personal Scheduled Range Days — personal range day planning with date, time, location, and drill selection
- ✅ Content Feed — server-driven announcements, tips, and content without app store updates
Friend Discovery (parity follow-ups)
Parity gaps kept alive by the Friend Discovery Parity decision — follow-ups, not cutover blockers.
- ✅ Friend Discovery — Username Search + QR Invite — make the migrated
usernamesearchable; restore the legacy QR add-by-scan flow (native-first, opaque revocable code) - ✅ Unified Friend QR Payload — one URL-form payload across PWA/iOS/Android, origin sourced from
InstanceInfo(leaf of instance-verification)
Scoring & Calculator Parity (re-opened by the 2026-06-15 parity audit)
Legacy scoring features the new app deferred at MVP build (see 2026-06-15-mvp-parity-audit). The server already supports N-shooter scoring; the gaps are the entry UI (web + native) + course-run grouping + the deferred leaderboards.
- ✅ Squad Scoring Entry — instructor/RO scores N shooters against one drill in a batch, on every surface (PWA + dashboard + iOS + Android), org-member or event-roster sourced. Closes the
mobile-scoringmulti-shooter deferral (all-surfaces close-out 2026-07-12). - ✅ Course Scoring — multi-stage course run + aggregate standing on every surface (PWA + iOS + Android: live run, squad run, past-run browsing, resume); the one piece that needed new schema/proto (course-run grouping +
ListCourseRuns). Migrated legacy runs browse-able, recorder-owned by design (all-surfaces close-out 2026-07-13). - ✅ MSD & Course Leaderboards — rank squad-recorded scores + course standings (lifts the
leaderboard-apideferrals). Closed 2026-07-13: squad scores verified already ranking (verify-only); per-drill boards reworked to legacy parity (self-recorded scores rank, public boards world-visible, friends boards cross-org) with migrated scores carved from All-Users boards; course boards decided-against — within-run standings (shipped with course-scoring) are the legacy parity bar, cross-run boards parked on ROADMAP-PRO. - ✅ Hit-Factor Calculator + Log — rebuild the USPSA calculator and the saved performance log on the Training hub, and migrate the 26,380 legacy
hit_factorsentries 1:1 intohit_factor_entries(Scope B, Decision #3). PWA shipped 2026-06-20; native → mobile-track.
Authoring & Content Creation Parity (re-opened by the 2026-06-15 parity audit)
Legacy let any shooter create content from their phone; the new app only authors on the dashboard. See 2026-06-15-mvp-parity-audit.
- ✅ Shooter-Side Drill Authoring — let shooters create/edit custom drills (with photo stage-image) on PWA + native, not just the dashboard (~16k legacy custom drills).
- Stage-Diagram Builder — rebuild the legacy vector stage editor (templated targets, drag/rotate/resize, undo/redo); backup-verified 2,362 drills / 990 authors drew vector designs (~5× the flat-photo path). MVP-vs-fast-follow is an open scope call; vector-only storage means these don’t display without a renderer.
Media Display Parity (migration-media client follow-ups)
Avatar + drill-image display on the clients — the user-facing side of migration-media (PR-4 shipped the web/dashboard surfaces).
- Native Avatar Display — profile photos on iOS + Android
- Native Drill Image Display — drill main / stage / hits-needed images on iOS + Android
- PWA Avatar Social Surfaces — avatars across PWA social surfaces (leaderboard etc.); fast-follow
Round-2 Parity Gaps (filed from the 2026-06-15 forensic sweep)
Gaps surfaced by the 2026-06-15-mvp-parity-audit round-2 sweep, triaged with fresh per-gap agents and filed 2026-06-25. The remaining F-gaps were dispositioned as already-deferred or not-a-gap (recorded in the audit note, not re-filed).
- View a Friend’s Profile — tap a friend → their shared drills/courses + achievements; the friend-graph payoff (F1)
- Assessment Category — catalog split + “Past Quals” score filter; the server side already exists (F2)
- Community-Drill Browsing — browse public/published drills; data layer done, browse UI missing (F3)
- Score-History Trends & Grouping — trend chart (F5, reopens the mobile-score-history overclaim) + group-by-drill (F6)
- ✅ Range-Bag Suggested Items — curated gear picker + store links; fast-follow (F7)
- Range-Bag Packing Checklist — per-item check-off + reset; resolves the orphaned
range_bag_completeachievement; fast-follow (F8) - ✅ Par-Timer Randomize — randomize the par window for anti-anticipation; fast-follow (F11)
Migration (from the existing app)
- Migration ETL — one-time Supabase to new Postgres data migration
- ⚠️ Migration Completeness Audit (2026-06-22) — source-exhaustive pre-cutover audit of the ETL: 82 gaps (7 high-severity silent drops), the skip-list/spec corrected in place, 10 product decisions owed. Cutover-readiness gate for migration-etl.
- One-Way Sync — Supabase to new DB listener during coexistence period
- ✅ Migration: Media — Supabase Storage → DO Spaces; new-system support for avatars + drill images (build complete — PR-1…5; the live transfer + sync forwarding are creds-gated)
- ✅ Migration: No-Shoot Zone — carry legacy no-shoot counts into migrated score breakdowns (re-grades
migration-etlfinding #6; done #103) - ✅ Staging E2E Test Suite + Shared API Client — API-level migration validation against deployed staging, via a shared
rangeday-api-clientcrate the apps and tests both consume (suite live + armed deploy-smoke proven green 2026-07-12)