Documentation

Native Mobile App — Product Requirements Document

Last updated: 2026-02-01 | Knowledge Base

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

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):

  1. Apollo Federation Gateway — Compose all subgraphs into a single supergraph. Mobile queries one endpoint.
  2. BFF (Backend-for-Frontend) — A lightweight Node.js service that aggregates and reshapes data for mobile-specific queries.
  3. 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)

6.3 Security

6.4 Analytics & Crash Reporting

6.5 Offline Strategy


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

  1. MVP: The Agile Network only. Single app binary, single App Store listing.
  2. 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)

Phase 2 — Content + Discovery (Sprints 5-8)

Phase 3 — Payments + Push (Sprints 9-11)

Phase 4 — Polish + Deploy (Sprints 12-14)


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:


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