Cross-Platform Strategy
Approach
Native apps for iOS (Swift + SwiftUI) and Android (Kotlin + Jetpack Compose) for the mobile experience. Two separate Dioxus (Rust → WASM) web apps: an admin dashboard and a shooter-facing PWA. A shared core crate (public) provides client-safe business logic to all platforms. Server-only logic lives in the private server crate.
Why This Architecture
Shared Rust Core (Public/Private Split)
Client-safe logic — validation, scoring, data models, sync — lives in the shared core crate and ships everywhere:
- Server, dashboard, and PWA import core directly
- iOS and Android apps call core via UniFFI-generated native bindings
- Logic runs at native speed on all platforms with zero drift
Server-only logic — auth, billing, admin operations, DB queries — lives in the private server crate and never leaves the server.
Native Mobile
SwiftUI and Jetpack Compose provide the best on-range experience. Full access to platform APIs (camera, BLE, background sync, biometrics) without plugins or framework abstractions. Each app runs the Rust core locally — not a thin client.
Marketing Site
Static HTML + Tailwind CSS at the root domain. The public entry point for all users. Explains the product and provides clear paths:
- Admins/Instructors → link to dashboard login
- Shooters → app download links (iOS App Store, Google Play, or install PWA)
No framework — just HTML with Tailwind utility classes in source, built to minified CSS with Tailwind CLI. No JS runtime in production.
Dioxus for Web (Dashboard + PWA)
Two separate Dioxus apps, built and deployed independently:
- Dashboard (
apps/dashboard/) — admin web app for event management, drill building, roster management, org settings, score review. - PWA (
apps/pwa/) — shooter-facing, read-heavy fallback for users who can’t or won’t install the native app.
Both import the shared core crate (not the server crate). Fullstack integration with Axum provides SSR, server functions, and WebSocket support. Key advantages:
- ~65-70 KB WASM bundle (with WASM-Split, under 50 KB)
- Subsecond hot-reload for rapid UI iteration
- Zero-config Tailwind CSS integration
- WGPU-native architecture enables future canvas/WebGPU features (3D drill builder)
AI-Assisted Multi-Platform Development
Features are described once and implemented across Rust (core + web), Swift (iOS), and Kotlin (Android) in parallel. UniFFI-generated bindings ensure type safety between the Rust core and native apps.
Options Evaluated
TypeScript Web Frameworks (React, SvelteKit, Solid.js)
Would require a separate TypeScript shared core package, duplicating logic between Rust (mobile) and TypeScript (web). Dioxus eliminates this split — one language for all business logic.
Leptos (Rust → WASM)
Strong fullstack framework with mature SSR and streaming. Dioxus chosen over Leptos for: smaller WASM bundles (~65 KB vs ~145 KB), Subsecond hot-reload, zero-config Tailwind, and WGPU-native architecture for the future 3D drill builder.
Capacitor
Web app in a native WebView. Rejected in favor of fully native mobile apps. See Tauri vs Capacitor.
Tauri v2
Web app in native WebView with Rust core process. Rejected due to immature mobile support. See Tauri vs Capacitor.
React Native (Expo)
Native rendering via React. Rejected because AI-assisted development makes dual-native viable, eliminating framework dependency.
Flutter
Write Dart, compile everywhere. Moving away from Flutter/FlutterFlow is the whole point.
PWA Scope
The PWA (apps/pwa/) is a separate Dioxus app deployed independently from the dashboard. It is a capable scoring client at MVP but has inherent browser limitations compared to native apps.
MVP PWA features:
- View event details, drills, roster
- View personal score history
- Score entry (on-range, as RO)
- Offline score queue — scores queue locally in IndexedDB and flush when connectivity returns (while the app is open)
What the PWA does NOT support (browser limitations):
- Background sync — no OS-level queue flush when the app is closed (unlike BGTaskScheduler/WorkManager on native)
- Camera/BLE — no shot timer integration (native camera APIs and Bluetooth not available)
- Drill builder — admin tool, dashboard only
- Event/roster management — admin tool, dashboard only
PWA vs native onboarding: On PWA install, the app shows a brief explainer noting these limitations and linking to native app downloads for users who want the full experience. This educates without blocking — the PWA is fully functional for scoring.
Deplatforming resilience: The PWA provides an app-store-independent scoring client from day one. If app stores remove the native apps, users can continue scoring via the PWA with the only gap being background sync and shot timer integration.
Shot Timer Integration
Camera capture of the shot timer display + on-device OCR using native camera APIs on both platforms. Bluetooth Low Energy for direct timer pairing can be added later.
Future: 3D Drill Builder
Dioxus’s WGPU-native architecture enables embedding interactive 3D scenes (via Bevy) directly in the dashboard (apps/dashboard/). The same Bevy/Rust code can compile natively for iOS (Metal) and Android (Vulkan), embedded as views within SwiftUI and Jetpack Compose.