Native Mobile App — Product Requirements Document
Native Mobile App — Product Requirements Document
Version: 1.0 Date: 2026-01-31 Status: Draft Related ADRs: ADR-009 (Native Mobile App), ADR-010 (Passwordless-First Auth), ADR-008 (Frontend Framework & SSR) Tracking: Epic #4
1. Executive Summary
The Agile Network currently serves mobile users through an Ionic/Angular web-view wrapper (peeq-mono). This approach suffers from poor native performance, limited access to device APIs, and an app-store experience indistinguishable from a slow website.
This PRD defines a Fan-facing MVP built with React Native + Expo (per ADR-009) that delivers a truly native mobile experience. The MVP targets The Agile Network brand only, while the architecture supports all 5 brands (The Agile Network, Court Report, Chalk Talk, In the Lab, Ring Savvy) via config-driven theming.
Key constraints: - Fan-only MVP; Expert features deferred to Phase 2+ (per ADR-009 phasing) - Single brand (The Agile Network) ships first; multi-brand architected but not deployed day 1 - Sprint 0 must resolve two blockers before development begins: Apple IAP compliance and GraphQL aggregation layer - 14 sprints across 4 phases, preceded by Sprint 0 prerequisites
2. User Personas
2.1 Primary: Fan (Consumer)
| Attribute | Detail |
|---|---|
| Role | Sports fan who follows professional athletes |
| Goals | Discover experts, consume video/article content, subscribe to experts, receive personalized updates |
| Pain points | Current Ionic app is slow, crashes, poor video playback, no push notifications |
| Devices | iPhone (iOS 16+), Android (API 26+) |
| Technical comfort | Moderate — expects app-store install, biometric login, smooth video |
2.2 Deferred: Expert (Creator)
Expert features (content upload, broadcast management, analytics dashboard, wallet/earnings) are explicitly out of scope for this MVP. Experts continue using the web platform. Expert mobile features are planned for a subsequent phase per ADR-009.
3. User Journey Maps
3.1 First-Time User
App Store → Download → Onboarding carousel → Sign up (email + Magic Link) →
Browse experts → View expert profile → Watch free content →
Prompted to subscribe → Subscribe (IAP/Stripe) → Access premium content →
Enable push notifications → Receive personalized updates
3.2 Returning User
Open app → Biometric/auto auth → Home feed (followed experts' new content) →
Tap content → Watch/read → Share to social → Push notification received →
Deep link opens specific content
3.3 Subscription Lifecycle
Free browsing → Subscribe to Expert A (monthly) →
Content unlocked → Manage subscription in profile →
Cancel → Grace period → Downgrade to free → Re-subscribe prompt
4. Feature Specifications
4.1 Authentication (Keycloak PKCE + Magic Link)
Description: Passwordless-first authentication using Keycloak as the identity provider. OAuth2 PKCE flow via expo-auth-session with Magic Link as the primary login method (per ADR-010).
Feature: Fan Authentication
As a fan
I want to sign in with a magic link
So that I can access my subscriptions without remembering a password
Scenario: First-time sign up with magic link
Given I am on the sign-in screen
When I enter my email address "fan@example.com"
And I tap "Send Magic Link"
Then I should see a confirmation message "Check your email"
And I should receive an email with a magic link
When I tap the magic link on my phone
Then the app should open and I should be signed in
And I should see the home feed
Scenario: Returning user with biometric auth
Given I have previously signed in
And I have biometric authentication enabled
When I open the app
Then I should be prompted for Face ID or fingerprint
When I authenticate successfully
Then I should see the home feed with my followed experts
Scenario: Magic link on different device
Given I requested a magic link on my phone
When I tap the magic link on a different device
Then I should see a message "Please open this link on the device where you requested it"
Scenario: Session expiry
Given my session token has expired
When I open the app
Then the app should attempt a silent token refresh
And if refresh fails, I should be prompted to sign in again
4.2 Expert Discovery (Browse, Search, Follow)
Description: Fans browse, search, and follow professional athletes. Content sourced from existing celebrity/expert GraphQL APIs.
Feature: Expert Discovery
As a fan
I want to browse and search for athletes
So that I can find experts I want to follow
Scenario: Browse experts by category
Given I am on the Explore tab
When I select the "Basketball" category
Then I should see a list of basketball experts
And each expert card should show their photo, name, sport, and subscriber count
Scenario: Search for an expert by name
Given I am on the Explore tab
When I tap the search bar
And I type "Jordan"
Then I should see search results matching "Jordan"
And results should update as I type (debounced 300ms)
Scenario: Follow an expert
Given I am viewing an expert's profile
And I am signed in
When I tap the "Follow" button
Then the button should change to "Following"
And the expert's content should appear in my home feed
Scenario: View expert profile
Given I tap on an expert card
Then I should see the expert's full profile
Including their bio, stats, subscriber count, and content library
And I should see tabs for "Videos", "Articles", and "About"
4.3 Content Viewing (Articles, Mux Video, Entitlement Gating)
Description: Fans view articles and videos. Premium content requires an active subscription. Video playback via Mux React Native SDK.
Feature: Content Viewing
As a fan
I want to watch videos and read articles from experts I follow
So that I can learn from their expertise
Scenario: Watch free video content
Given I am viewing an expert's content library
And the video "Training Tips Vol 1" is marked as free
When I tap the video
Then the Mux video player should load
And the video should play with native controls (play/pause, seek, fullscreen)
Scenario: Attempt to view premium content without subscription
Given I am not subscribed to Expert A
And I tap a premium video from Expert A
Then I should see a preview thumbnail with a lock icon
And a prompt "Subscribe to Expert A to unlock this content"
And a "Subscribe" call-to-action button
Scenario: View premium content with active subscription
Given I have an active subscription to Expert A
When I tap a premium video from Expert A
Then the video should play without any gate
And I should see the full content
Scenario: Read an article
Given I tap an article from an expert
Then I should see the article rendered with proper formatting
Including headings, images, and embedded media
And a progress indicator showing how much I have read
Scenario: Video playback quality adaptation
Given I am watching a video on a cellular connection
When the network quality degrades
Then the video player should automatically reduce quality
And display a quality indicator
4.4 Subscriptions & Payments
Description: Fans subscribe to experts via In-App Purchase (iOS) or Stripe (Android). The payment path depends on the Sprint 0 IAP decision (blocker).
Feature: Subscriptions and Payments
As a fan
I want to subscribe to experts
So that I can access their premium content
Scenario: Subscribe to an expert on iOS
Given I am on an expert's profile on an iOS device
And I am signed in
When I tap "Subscribe - $9.99/month"
Then the Apple In-App Purchase sheet should appear
And I should be able to confirm with Face ID or password
When the purchase completes
Then I should see "Subscribed" confirmation
And premium content should be unlocked immediately
Scenario: Subscribe to an expert on Android
Given I am on an expert's profile on an Android device
And I am signed in
When I tap "Subscribe - $9.99/month"
Then the payment flow should initiate (Stripe or Google Play)
When the purchase completes
Then I should see "Subscribed" confirmation
And premium content should be unlocked immediately
Scenario: View active subscriptions
Given I have active subscriptions
When I navigate to Profile > Subscriptions
Then I should see a list of my active subscriptions
Including expert name, price, next billing date, and status
Scenario: Cancel a subscription
Given I have an active subscription to Expert A
When I navigate to Profile > Subscriptions
And I tap "Manage" on Expert A's subscription
Then I should see options to cancel
When I confirm cancellation
Then I should see "Your subscription will end on [date]"
And I should retain access until the billing period ends
Scenario: Subscription restoration after reinstall
Given I previously purchased a subscription on iOS
And I have reinstalled the app
When I sign in with my account
Then the app should restore my purchases
And my premium content access should be restored
4.5 Push Notifications
Description: Fans receive push notifications for new content, subscription events, and personalized updates via expo-notifications.
Feature: Push Notifications
As a fan
I want to receive notifications about new content
So that I don't miss updates from experts I follow
Scenario: Opt in to push notifications
Given I have just signed in for the first time
When the app prompts me to enable notifications
And I tap "Enable Notifications"
Then the OS permission dialog should appear
When I allow notifications
Then my push token should be registered with the server
Scenario: Receive notification for new content
Given I follow Expert A
And I have push notifications enabled
When Expert A publishes a new video
Then I should receive a push notification
With the title "[Expert Name]" and body "New video: [Title]"
When I tap the notification
Then the app should open directly to that video
Scenario: Manage notification preferences
Given I am on Profile > Notification Settings
Then I should see toggles for notification categories
Including "New Content", "Subscription Updates", and "Promotions"
When I disable "Promotions"
Then I should no longer receive promotional notifications
4.6 Deep Linking
Description: Universal Links (iOS) and App Links (Android) allow external URLs to open specific content in the app.
Feature: Deep Linking
As a fan
I want to tap a link shared on social media
So that it opens directly in the app
Scenario: Deep link to expert profile
Given the app is installed
When I tap a link "https://theagilenetwork.com/expert/john-doe"
Then the app should open
And navigate directly to John Doe's expert profile
Scenario: Deep link to content
Given the app is installed
When I tap a link "https://theagilenetwork.com/content/abc123"
Then the app should open
And navigate directly to that content item
Scenario: Deep link with app not installed
Given the app is NOT installed
When I tap a link "https://theagilenetwork.com/expert/john-doe"
Then I should be redirected to the App Store or Play Store
And after installing and opening, I should land on John Doe's profile
Scenario: Magic link deep link
Given I requested a magic link for sign-in
When I tap the magic link in my email
Then the app should open
And I should be authenticated and redirected to the home feed
4.7 Multi-Brand Theming
Description: The app architecture supports 5 brands via config-driven theming. MVP ships The Agile Network only.
Feature: Multi-Brand Theming
As a platform operator
I want the app to support multiple brand configurations
So that we can launch additional brands without code changes
Scenario: App launches with The Agile Network brand
Given the app is configured for "The Agile Network"
When I open the app
Then I should see The Agile Network logo
And the primary color should be dark teal (#18504D)
And the accent color should be green (#09AE6D)
And the typography should use the brand fonts
Scenario: Theme tokens drive all UI elements
Given the app uses a theme configuration file
Then all colors, fonts, spacing, and icons should be derived from the theme
And no hardcoded brand values should exist in component code
5. Technical Architecture
5.1 Monorepo Structure
nexgen/
├── apps/
│ ├── mobile/ # React Native + Expo app
│ └── web/ # Future Next.js web app
├── packages/
│ ├── types/ # Shared TypeScript types
│ ├── graphql/ # Apollo Client, queries, mutations, codegen
│ ├── auth/ # Keycloak PKCE, token management, Magic Link
│ ├── business-logic/ # Domain logic (subscriptions, entitlements)
│ └── ui/ # Shared UI components (future web+mobile)
├── turbo.json
└── pnpm-workspace.yaml
5.2 Key Technology Choices
| Layer | Technology | Rationale |
|---|---|---|
| Framework | React Native 0.76+ | ADR-009 approved; shared code with future web |
| Build system | Expo SDK 52+ | Managed workflow, EAS Build, OTA updates |
| Monorepo | Turborepo + pnpm | Task caching, workspace dependencies |
| State | Zustand | Lightweight, TypeScript-first |
| Data fetching | Apollo Client + GraphQL Codegen | Matches existing backend GraphQL APIs |
| Navigation | Expo Router (file-based) | Convention-based, deep link support built-in |
| Auth | expo-auth-session + Keycloak | PKCE flow, token refresh, Magic Link support |
| Video | @mux/mux-player-react-native | Native Mux SDK for adaptive streaming |
| Notifications | expo-notifications | FCM (Android) + APNs (iOS) abstraction |
| Analytics | TBD (Amplitude, Mixpanel, or PostHog) | Event tracking, user segmentation |
| Crash reporting | Sentry (sentry-expo) | Real-time crash monitoring, breadcrumbs |
| Testing | Jest + React Native Testing Library | Unit + component tests |
| E2E testing | Maestro | Cross-platform mobile E2E |
5.3 BFF / GraphQL Aggregation Layer
The existing backend exposes 24+ separate GraphQL endpoints (celebrity, fan, content, media, subscription, etc.). Mobile clients cannot efficiently query all of these directly — especially on cellular connections where latency per round-trip is high.
Options under evaluation (Sprint 0 PoC):
- Apollo Federation Gateway — Compose all subgraphs into a single supergraph. Mobile queries one endpoint.
- BFF (Backend-for-Frontend) — A lightweight Node.js service that aggregates and reshapes data for mobile-specific queries.
- Client-side batching — Apollo Client’s query batching with persistent queries. Lowest effort but may not solve latency.
5.4 Authentication Flow
Mobile App → expo-auth-session → Keycloak (PKCE) → Access Token + Refresh Token
↓
Mobile App → Magic Link request → Email service → Email with deep link
↓
User taps link → Universal Link / App Link → App opens → Token exchange → Authenticated
6. Non-Functional Requirements
6.1 Performance
| Metric | Target |
|---|---|
| Cold start (app launch to interactive) | < 3 seconds |
| Time to first meaningful paint | < 1.5 seconds |
| Video playback start | < 2 seconds (Wi-Fi), < 4 seconds (4G) |
| API response (aggregated) | < 500ms p95 |
| JS bundle size | < 5 MB (initial) |
| App binary size | < 50 MB (iOS), < 40 MB (Android) |
| Frame rate | 60 fps for scrolling and animations |
| Memory usage | < 300 MB peak |
6.2 Accessibility (WCAG 2.1 AA)
- All interactive elements must have accessible labels
- Minimum contrast ratio 4.5:1 for text, 3:1 for large text
- Support for Dynamic Type (iOS) and font scaling (Android)
- Screen reader compatibility (VoiceOver/TalkBack) for all screens
- Touch targets minimum 44x44 points
- No information conveyed by color alone
6.3 Security
- All network traffic over TLS 1.2+
- Tokens stored in secure storage (Keychain/Keystore)
- Certificate pinning for API endpoints
- No sensitive data in logs or crash reports
- Biometric authentication for token access
- Jailbreak/root detection with graceful degradation
6.4 Analytics & Crash Reporting
- Sentry integration for crash reporting from Sprint 1
- Event tracking for: screen views, content plays, subscription events, search queries
- Funnel tracking: onboarding completion, subscribe conversion, content engagement
- Performance monitoring: screen load times, API latency, video start time
6.5 Offline Strategy
- Offline-first for cached content (read-only)
- Graceful degradation when offline: show cached data, disable actions requiring network
- Queue actions (follow/unfollow) for replay when connectivity returns
- No offline downloads in MVP (out of scope)
7. Multi-Brand Strategy
The app is architected for 5 brands but ships The Agile Network only in MVP.
7.1 Brand Configuration
Each brand is defined by a configuration file:
interface BrandConfig {
id: string; // "the-agile-network"
name: string; // "The Agile Network"
theme: {
colors: { primary, accent, dark, bg, text };
typography: { heading, body };
spacing: { ... };
};
assets: {
logo: ImageSource;
splash: ImageSource;
icon: ImageSource;
};
deepLink: {
scheme: string; // "theagilenetwork://"
universalLinkDomain: string; // "theagilenetwork.com"
};
keycloak: {
realm: string;
clientId: string;
};
}
7.2 Phased Brand Rollout
- MVP: The Agile Network only. Single app binary, single App Store listing.
- Phase 2+: Additional brands via either (a) build-time config switching with separate App Store listings per brand, or (b) runtime brand selection within a single app. Decision deferred.
8. Development Phases
Sprint 0 — Prerequisites (Before Development Starts)
| Story | Description | Blocker? |
|---|---|---|
| IAP decision spike | Evaluate RevenueCat vs react-native-iap vs hybrid. Business decision on 30% Apple cut. | Yes |
| BFF/Gateway PoC | Stand up Apollo Federation or BFF prototype against 3 existing subgraphs. Measure latency. | Yes |
| Magic Link PoC | Test expo-auth-session + Keycloak Magic Link + Universal Links end-to-end. | No |
| Payment architecture spike | Map current coin/wallet/BPM flow. Determine mobile payment path. | No |
Phase 1 — Foundation + Auth (Sprints 1-4)
- Monorepo scaffolding (Turborepo + pnpm + Expo)
- Expo configuration (app.config.ts, EAS Build profiles)
- Navigation structure (Expo Router, tab bar, stack navigators)
- Keycloak PKCE authentication
- Magic Link deep link handling
- CI/CD pipeline (EAS Build → TestFlight + Play Internal)
- Sentry crash reporting integration
- Analytics SDK integration
- Brand theming foundation (config-driven)
- Basic E2E test framework (Maestro)
Phase 2 — Content + Discovery (Sprints 5-8)
- Expert browse/search screens
- Expert profile view
- Follow/unfollow functionality
- Content feed (home tab)
- Article rendering
- Mux video player integration
- Content entitlement gating
- Search with filtering
- Infinite scroll / pagination
Phase 3 — Payments + Push (Sprints 9-11)
- Subscription management screens
- IAP integration (iOS) / Stripe integration (Android)
- Purchase restoration
- Push notification registration
- Notification preference management
- Deep link routing for all content types
Phase 4 — Polish + Deploy (Sprints 12-14)
- Accessibility audit and remediation
- Performance profiling and optimization
- App Store screenshot generation
- App Store metadata and listing
- TestFlight beta distribution
- Play Internal testing track
- Final E2E test coverage pass
- Launch readiness review
9. CI/CD & Deployment
9.1 Build Pipeline
git push → GitHub Actions → Lint + Type Check + Unit Tests →
EAS Build (iOS + Android) → Automated E2E (Maestro) →
TestFlight (iOS) / Play Internal (Android)
9.2 OTA Updates
EAS Update enables over-the-air JavaScript bundle updates without App Store review. Used for: - Bug fixes - Content/copy changes - Non-native feature additions
Native binary updates (new SDKs, native modules) require full App Store review.
9.3 Environment Strategy
| Environment | Purpose | Distribution |
|---|---|---|
| Development | Local Expo dev client | Developer devices |
| Preview | PR-specific builds | Internal team via EAS |
| Staging | Pre-release testing | TestFlight / Play Internal |
| Production | Public release | App Store / Play Store |
10. Risk Register
| # | Risk | Severity | Probability | Impact | Mitigation |
|---|---|---|---|---|---|
| R1 | Apple IAP compliance — Apple rejects the app for using Stripe for digital subscriptions | Critical | High | Blocks iOS launch | Sprint 0: Make IAP decision. Implement RevenueCat or react-native-iap for iOS. Budget 30% revenue share. |
| R2 | GraphQL aggregation latency — 24+ endpoints cause unacceptable cold-start times on cellular | Critical | High | Poor UX, user churn | Sprint 0: BFF/Federation PoC with latency benchmarking. Must achieve <500ms p95 aggregated. |
| R3 | Magic Link deep linking — Universal Links / App Links fail silently on some devices | High | Medium | Auth flow broken for some users | Sprint 0: PoC across iOS 16-18 and Android 10-15. Fallback to email+code if deep link fails. |
| R4 | Payment architecture complexity — Coin/wallet/BPM system doesn’t map cleanly to IAP | High | Medium | Payment integration delayed | Sprint 0: Architecture spike. May need server-side adapter between IAP receipts and existing coin system. |
| R5 | Expo managed workflow limitations — Native module needed that isn’t supported | Medium | Low | Must eject to bare workflow | Use Expo development builds (custom dev client) which support native modules without full ejection. |
| R6 | Multi-brand URL scheme conflicts — 5 brands with 5 deep link domains cause routing issues | Medium | Medium | Deep links open wrong brand | Design URL scheme registry in Sprint 0. Test with 2 brands before committing to 5. |
11. Open Questions
| # | Question | Owner | Deadline | Impact |
|---|---|---|---|---|
| Q1 | Apple IAP: Use RevenueCat, react-native-iap, or hybrid? What is the revenue impact of 30% cut? | Product / Business | Sprint 0 | Blocks payment development |
| Q2 | BFF vs Apollo Federation vs client-side batching — which aggregation approach? | Engineering | Sprint 0 | Blocks API integration pattern |
| Q3 | How does mobile payment map to existing coin/wallet/BPM system? Can we bypass coins? | Engineering / Product | Sprint 0 | Affects payment architecture |
| Q4 | Tamagui or React Native Paper for UI components? Which supports 5-brand theming? | Engineering | Sprint 0 | Affects all UI development |
| Q5 | Single app with brand selector or separate App Store listings per brand? | Product | Before Phase 2 | Affects app architecture and distribution |
| Q6 | Analytics provider: Amplitude, Mixpanel, or PostHog? | Product / Engineering | Sprint 1 | Affects event tracking implementation |
12. Out of Scope (MVP)
The following features are explicitly excluded from the MVP:
- Live streaming / broadcasts — Complex Mux/Jitsi integration, Expert-facing
- Real-time chat — Requires new infrastructure
- Shoutouts — Personalized video requests, Expert-facing workflow
- Events — Tixr ticketing integration, complex booking flow
- Expert features — Content upload, analytics dashboard, earnings/wallet
- Offline downloads — DRM and storage management complexity
- Social features — Comments, likes, sharing within the app
- In-app messaging — Fan-to-Expert direct messaging
- SEU/PDU tracking — Continuing education credit tracking
- Admin features — Content moderation, user management
13. Success Metrics
| Metric | Target | Measurement |
|---|---|---|
| App Store rating | >= 4.5 stars | App Store Connect / Google Play Console |
| Crash-free rate | >= 99.5% | Sentry |
| Cold start time | < 3 seconds | Performance monitoring |
| Onboarding completion rate | >= 70% | Analytics funnel |
| Day-7 retention | >= 30% | Analytics cohort |
| Day-30 retention | >= 15% | Analytics cohort |
| Subscribe conversion (free → paid) | >= 5% of active users | Analytics + payment provider |
| Video completion rate | >= 60% for videos < 10 min | Mux Data |
| Push notification opt-in | >= 60% | expo-notifications metrics |
| Accessibility score | WCAG 2.1 AA compliant | Manual audit + automated checks |