# freecodecamp/mobile architecture

> Architecture diagram of the GitHub repository freecodecamp/mobile, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-26). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/freecodecamp/mobile
- Repository: https://github.com/freecodecamp/mobile

## Overview

1. This repository is a two-part mobile system: a Flutter client app in `mobile-app/` and a small Node/TypeScript backend in `mobile-api/`. The app is the primary product; the backend mainly supports podcast data ingestion and API serving.

2. The Flutter app is the main presentation and orchestration layer. Its structure is organized by feature area under `lib/ui/views/` with a shared app bootstrap in `lib/main.dart` and `lib/app/`. Navigation, dependency wiring, and logging are centralized there rather than spread through features.

3. The app’s major user-facing subsystems are:
   - Learn/curriculum delivery
   - News/tutorial reading and bookmarking
   - Podcasts and audio playback
   - Profile/settings/auth-related flows
   - Code radio and miscellaneous utility screens
   Each subsystem has its own view and viewmodel pairings, suggesting an MVVM-style Flutter architecture.

4. The Learn subsystem is the most complex and is built for offline curriculum use. It combines packaged curriculum assets, local databases, file-based content, and a dedicated “test runner” asset bundle for executing curriculum challenge tests inside the app. The learn area has many specialized templates for different challenge types, block content, chapters, daily challenges, and scene assets.

5. Local data is a major boundary in the app. The repository includes bundled SQLite databases under `assets/database/`, SQL migration/reset scripts under `assets/sql/`, JSON learning content, and a generic file store service. This indicates the app can operate with local/offline data and migrates legacy content rather than relying entirely on live backend calls.

6. News is a separate content subsystem backed by an API service and bookmark persistence. The app includes views for feeds, search, tutorials, image viewing, author pages, and bookmark management. There is explicit legacy SQLite bookmark migration logic, so the app has evolved from local persistence to a newer storage path while preserving old user data.

7. Podcasts are handled as another distinct feature boundary. On the client side there are podcast list, episode list, episode detail, download, audio, and notification services. The presence of podcast database assets and legacy migration code shows a similar evolution from older local storage to current services. Podcast playback and download management are part of the app, not the backend.

8. The `mobile-api/` backend is a lightweight data service, not a general-purpose application server. It contains database connectivity, Podcast and Episode models, route definitions, and a scheduled job to update podcasts from feed URLs. The `podcast-feed-urls.json` file and the update job make clear that the backend periodically ingests external podcast feeds and serves normalized data to the mobile app.

9. External services and platform integrations are important in the app architecture. Firebase is used for analytics, remote config, and platform-specific app configuration. Android and iOS native projects are included, along with push/notification-related services, quick actions, and audio integrations. These are app-side concerns rather than centralized server-side infrastructure.

10. The app’s state and service layer is separated from UI. Services under `lib/service/` encapsulate authentication, Dio-based networking, Firebase access, locale management, navigation shortcuts, learn content loading, news APIs/bookmarks, podcast downloads/notifications, and JSON file storage. UI components generally depend on these services through injected viewmodels.

11. Testing is layered by scope. The backend has Jest tests for podcast behavior, while the Flutter app has unit tests, service tests, widget tests, and integration tests under `test/` and `integration_test/`. There is also a dedicated integration runner for the curriculum/test-runner experience, reflecting the importance of validating in-app coding challenges.

12. CI/CD is split by platform and concern. GitHub Actions cover API build/test/deploy, Flutter unit tests, Flutter CI/deploy, curriculum e2e tests, and Crowdin translation sync. Mobile release tooling is also present via Codemagic and Fastlane, which indicates the app is built and shipped as native Android/iOS binaries.

13. The main architectural data flows are:
   - Curriculum and learn content flow from bundled assets/local DBs into the Learn UI and test runner.
   - News content flows from remote APIs into the News UI, with bookmarks stored locally and migrated if needed.
   - Podcast metadata flows from external feeds into the backend, then into the app for listing, playback, and downloads.
   - Firebase services cross-cut the app for analytics, config, and platform integration.

14. Overall, this is an offline-friendly, content-heavy mobile learning platform with a thin supporting backend. The strongest architectural boundary is between the Flutter client, which owns most user experience and local persistence, and the Node backend, which mainly curates and serves podcast data.

Main entry points: [`mobile-app/lib/app/app.dart`](https://github.com/freecodecamp/mobile/blob/main/mobile-app/lib/app/app.dart) (App shell), [`mobile-app/lib/ui/views/learn`](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/ui/views/learn) (Learn hub), [`mobile-app/lib/service`](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/service) (Shared services), [`mobile-api/src/index.ts`](https://github.com/freecodecamp/mobile/blob/main/mobile-api/src/index.ts) (API entry)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_client["Flutter app"]
  node_app_bootstrap["App bootstrap<br/>flutter entry<br/>[main.dart]"]
  node_app_shell["App shell<br/>router/locator<br/>[app.dart]"]
  node_learn_ui["Learn hub<br/>mvvm feature"]
  node_learn_templates["Challenge views<br/>learn ui"]
  node_learn_services["Learn services<br/>content/offline"]
  node_learn_assets[("Curriculum assets<br/>bundled data")]
  node_learn_runner["Test runner<br/>curriculum runtime<br/>[test_runner.dart]"]
  node_news_ui["News hub<br/>mvvm feature"]
  node_news_services["News services<br/>api/bookmarks"]
  node_podcast_ui["Podcasts<br/>mvvm feature"]
  node_podcast_services["Podcast services<br/>audio/download"]
  node_profile_settings["Profile & settings<br/>account/ui"]
  node_shared_services["Shared services<br/>app services"]
  node_firebase["Firebase<br/>platform integration"]
  node_native_platform["Native platforms<br/>android/ios"]
end

subgraph group_backend["Node API"]
  node_api_entry["API entry<br/>node server<br/>[index.ts]"]
  node_api_routes["API routes<br/>http routes<br/>[routes.ts]"]
  node_podcast_models["Podcast models<br/>data models"]
  node_podcast_job["Feed updater<br/>scheduled job<br/>[update-podcasts.ts]"]
end

subgraph group_delivery["Delivery"]
  node_ci_cd["CI/CD<br/>automation<br/>[workflows]"]
end

node_app_bootstrap -->|"boots"| node_app_shell
node_app_shell -->|"navigates"| node_learn_ui
node_app_shell -->|"navigates"| node_news_ui
node_app_shell -->|"navigates"| node_podcast_ui
node_app_shell -->|"navigates"| node_profile_settings
node_learn_ui -->|"renders"| node_learn_templates
node_learn_ui -->|"loads"| node_learn_services
node_learn_services -->|"reads"| node_learn_assets
node_learn_ui -->|"executes"| node_learn_runner
node_news_ui -->|"fetches"| node_news_services
node_news_services -->|"uses"| node_shared_services
node_podcast_ui -->|"plays"| node_podcast_services
node_podcast_services -->|"uses"| node_shared_services
node_profile_settings -->|"depends on"| node_shared_services
node_shared_services -->|"integrates"| node_firebase
node_native_platform -->|"configures"| node_firebase
node_api_entry -->|"serves"| node_api_routes
node_api_entry -->|"connects"| node_podcast_models
node_podcast_job -->|"updates"| node_podcast_models
node_podcast_job -->|"feeds"| node_api_routes
node_ci_cd -.->|"builds/tests"| node_app_bootstrap
node_ci_cd -.->|"builds/tests"| node_api_entry

click node_app_bootstrap "https://github.com/freecodecamp/mobile/blob/main/mobile-app/lib/main.dart"
click node_app_shell "https://github.com/freecodecamp/mobile/blob/main/mobile-app/lib/app/app.dart"
click node_learn_ui "https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/ui/views/learn"
click node_learn_templates "https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/ui/views/learn/challenge/templates"
click node_learn_services "https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/service/learn"
click node_learn_assets "https://github.com/freecodecamp/mobile/tree/main/mobile-app/assets"
click node_learn_runner "https://github.com/freecodecamp/mobile/blob/main/mobile-app/lib/ui/views/learn/test_runner.dart"
click node_news_ui "https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/ui/views/news"
click node_news_services "https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/service/news"
click node_podcast_ui "https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/ui/views/podcast"
click node_podcast_services "https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/service/podcast"
click node_profile_settings "https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/ui/views/profile"
click node_shared_services "https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/service"
click node_firebase "https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/service/firebase"
click node_native_platform "https://github.com/freecodecamp/mobile/tree/main/mobile-app/android"
click node_api_entry "https://github.com/freecodecamp/mobile/blob/main/mobile-api/src/index.ts"
click node_api_routes "https://github.com/freecodecamp/mobile/blob/main/mobile-api/src/routes.ts"
click node_podcast_models "https://github.com/freecodecamp/mobile/tree/main/mobile-api/src/models"
click node_podcast_job "https://github.com/freecodecamp/mobile/blob/main/mobile-api/src/jobs/update-podcasts.ts"
click node_ci_cd "https://github.com/freecodecamp/mobile/blob/main/.github/workflows"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_app_bootstrap,node_app_shell,node_learn_ui,node_learn_templates,node_learn_services,node_learn_assets,node_learn_runner,node_news_ui,node_news_services,node_podcast_ui,node_podcast_services,node_profile_settings,node_shared_services,node_firebase,node_native_platform toneBlue
class node_api_entry,node_api_routes,node_podcast_models,node_podcast_job toneAmber
class node_ci_cd toneMint
```

## Components

### Flutter app

Primary offline-friendly mobile client and its local service layer.

- [App bootstrap](https://github.com/freecodecamp/mobile/blob/main/mobile-app/lib/main.dart): flutter entry · Main app startup, dependency wiring, navigation, and logging. · `mobile-app/lib/main.dart`
- [App shell](https://github.com/freecodecamp/mobile/blob/main/mobile-app/lib/app/app.dart): router/locator · Central app composition with router, service locator, and logger. · `mobile-app/lib/app/app.dart`
- [Learn hub](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/ui/views/learn): mvvm feature · Curriculum landing, chapters, daily challenges, and test runner entry. · `mobile-app/lib/ui/views/learn`
- [Challenge views](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/ui/views/learn/challenge/templates): learn ui · Specialized block and challenge templates for interactive curriculum content. · `mobile-app/lib/ui/views/learn/challenge/templates`
- [Learn services](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/service/learn): content/offline · Loads packaged curriculum assets, local content, scene assets, and notifications. · `mobile-app/lib/service/learn`
- [Curriculum assets](https://github.com/freecodecamp/mobile/tree/main/mobile-app/assets): bundled data · Local databases, SQL scripts, JSON content, and the test runner bundle. · `mobile-app/assets`
- [Test runner](https://github.com/freecodecamp/mobile/blob/main/mobile-app/lib/ui/views/learn/test_runner.dart): curriculum runtime · Embedded integration runner used to execute in-app coding challenges. · `mobile-app/lib/ui/views/learn/test_runner.dart`
- [News hub](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/ui/views/news): mvvm feature · Feeds, search, tutorials, authors, image viewing, and bookmarks. · `mobile-app/lib/ui/views/news`
- [News services](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/service/news): api/bookmarks · Remote news API access plus bookmark persistence and migration. · `mobile-app/lib/service/news`
- [Podcasts](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/ui/views/podcast): mvvm feature · Podcast listing, episode browsing, detail, download, and playback screens. · `mobile-app/lib/ui/views/podcast`
- [Podcast services](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/service/podcast): audio/download · Podcast retrieval, legacy migration, downloads, and notifications. · `mobile-app/lib/service/podcast`
- [Profile & settings](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/ui/views/profile): account/ui · Profile, login, settings, and account deletion flows. · `mobile-app/lib/ui/views/profile`
- [Shared services](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/service): app services · Authentication, Dio networking, locale, navigation shortcuts, storage, and developer helpers. · `mobile-app/lib/service`
- [Firebase](https://github.com/freecodecamp/mobile/tree/main/mobile-app/lib/service/firebase): platform integration · Analytics, remote config, and app configuration integration. · `mobile-app/lib/service/firebase`
- [Native platforms](https://github.com/freecodecamp/mobile/tree/main/mobile-app/android): android/ios · Android and iOS host apps, manifests, signing, and push/app setup. · `mobile-app/android`

### Node API

Lightweight podcast ingestion and serving backend.

- [API entry](https://github.com/freecodecamp/mobile/blob/main/mobile-api/src/index.ts): node server · Backend bootstrap, routing, and database connection startup. · `mobile-api/src/index.ts`
- [API routes](https://github.com/freecodecamp/mobile/blob/main/mobile-api/src/routes.ts): http routes · Server route definitions exposed to the mobile app. · `mobile-api/src/routes.ts`
- [Podcast models](https://github.com/freecodecamp/mobile/tree/main/mobile-api/src/models): data models · Podcast and episode database models used by the backend. · `mobile-api/src/models`
- [Feed updater](https://github.com/freecodecamp/mobile/blob/main/mobile-api/src/jobs/update-podcasts.ts): scheduled job · Periodic job that ingests external podcast feeds and normalizes data. · `mobile-api/src/jobs/update-podcasts.ts`

### Delivery

Build, test, and release automation across mobile and API.

- [CI/CD](https://github.com/freecodecamp/mobile/blob/main/.github/workflows): automation · GitHub Actions, Codemagic, and Fastlane build/test/deploy pipelines. · `.github/workflows`

## Connections

- App bootstrap → App shell: boots · Main entry initializes the composed app shell and routing.
- App shell → Learn hub: navigates · Router sends users into the learn experience.
- App shell → News hub: navigates · Router exposes the news experience.
- App shell → Podcasts: navigates · Router exposes the podcast experience.
- App shell → Profile & settings: navigates · Router exposes profile, login, and settings flows.
- Learn hub → Challenge views: renders · Learn screens compose challenge and block templates.
- Learn hub → Learn services: loads · Learn UI depends on offline curriculum and scene services.
- Learn services → Curriculum assets: reads · Curriculum services consume bundled databases, JSON, SQL, and test assets.
- Learn hub → Test runner: executes · Curriculum test runner validates in-app coding challenges.
- News hub → News services: fetches · News screens use API and bookmark services.
- News services → Shared services: uses · News services reuse networking and storage primitives.
- Podcasts → Podcast services: plays · Podcast screens rely on download and audio services.
- Podcast services → Shared services: uses · Podcast services reuse storage and networking primitives.
- Profile & settings → Shared services: depends on · Auth, locale, navigation, and storage support profile/settings flows.
- Shared services → Firebase: integrates · Shared app services connect to analytics and remote config.
- Native platforms → Firebase: configures · Android and iOS hosts provide native Firebase setup.
- API entry → API routes: serves · Server entry mounts HTTP routes.
- API entry → Podcast models: connects · Backend initializes persistence and model access.
- Feed updater → Podcast models: updates · Scheduled ingestion populates podcast and episode data.
- Feed updater → API routes: feeds · Ingested podcast data is made available to the API.
- CI/CD → App bootstrap: builds/tests · Mobile pipelines cover Flutter tests and releases.
- CI/CD → API entry: builds/tests · API pipelines cover backend build, test, and deploy.
