DuTaTo

Active learning app that prevents cognitive debt by using Claude as a Socratic AI tutor. Instead of giving direct answers, the AI enforces reflection, asks probing questions, and gates advanced features by mastery level.

Stack

Layer Technology
Frontend Flutter (iOS, Android, Web)
State Management Riverpod
Navigation GoRouter
Backend Supabase (PostgreSQL + Auth)
AI Claude Messages API (direct from client)
On-Device AI ONNX Runtime (embeddings) + SQLite vector search
Spaced Repetition SM-2 algorithm
Hosting Cloudflare Pages (web)

Core Concepts

  • Cognitive debt prevention — AI never gives direct answers; learners must think first
  • Mastery levels (0-5) — gate features by demonstrated knowledge
  • Kolb's learning cycle — track CE, RO, AC, AE phases per session
  • Mandatory reflection — sessions can't complete without it
  • 8 Claude interaction modes — Socratic dialogue, quiz, gated explanation, code review, practice problems, confused student (role reversal), review card generation, assessment

Architecture

Clean Architecture with 3 layers:

lib/
  domain/entities/       # Pure Dart classes, no dependencies
  data/
    models/              # JSON-serializable models (freezed)
    datasources/         # Supabase & Claude API clients
  presentation/
    providers/           # Riverpod providers
    screens/             # 15 screen categories
    widgets/             # Reusable UI components
  config/                # Routes, theme, API configs
  core/                  # Utils (SM-2), extensions, error handling

Screen categories: admin_onboarding, auth, backoffice, domains, goals, home, lesson, notes, onboarding, org, progress, review, settings, setup, tutor.

First-connection onboarding (Plan 49) routes freshly-signed-up users through display name → persona → pending invitations → Socratic learner tour (5 steps) → org admin wizard (4 steps) before the home screen. Replayable from Settings.

Content

The app is a platform for structured learning — it does not ship with pre-loaded content for all users. Domain owners create curricula (domains, books, topics, lessons) and control access via visibility settings (private, shared, public) and curriculum shares.

Content can be populated using the tooling in tools/:

  • pdf_pipeline/ — extracts and structures lessons from PDF textbooks
  • curriculum_creator/ — AI agent pipeline supporting PDFs, web pages, and code repos

Platforms

Platform Status Notes
iOS Primary Fully functional, all features
Android Supported Firebase requires real google-services.json (see below)
Web (Chrome) Supported Responsive desktop layout; on-device AI (ONNX/SQLite) disabled — falls back to Supabase-only retrieval

Web-specific behavior

Three native-only dependencies are isolated behind conditional-import barrels so the JS bundle never includes dart:io or native FFI code:

  • flutter_onnxruntime → no-op stub on web (local embeddings disabled)
  • sqlite3 / sqlite_vector → no-op stub on web (local vector store disabled)
  • flutter_local_notifications → no-op stub on web (push via FCM still works)

On wide screens (≥800px), the bottom NavigationBar is replaced by a side NavigationRail.

Android setup

The Android build requires a real google-services.json from Firebase Console placed at android/app/google-services.json (gitignored). Without it, Firebase initialization fails at runtime (caught gracefully — the app runs but push notifications are disabled).

Getting Started

# Install dependencies
flutter pub get

# Set up environment variables
cp .env.example .env  # Add your Supabase URL, anon key, and Claude API key

# Run the app (iOS)
flutter run

# Run the app (Web)
flutter run -d chrome

# Run the app (Android)
flutter run -d android

# Run code generation (after modifying models)
dart run build_runner build --delete-conflicting-outputs

Staging vs production

The app has two environments that ship side-by-side with separate bundle IDs (com.alienard.dutato for prod, com.alienard.dutato.staging for staging) and separate Supabase projects:

  • Staging auto-deploys on every merge to main via .github/workflows/ci.yml: schema migrations, Edge Functions, and web (→ dutato-staging.pages.dev) against the staging Supabase project. No local command needed.
  • Production deploys via ./dto release on your machine — web (→ dutato.pages.dev), iOS (TestFlight), Android (Firebase App Distribution), all tied to a git tag.

Both apps coexist on the same device so you can compare behavior side-by-side. Internal testers get the staging build first; once you're happy, ./dto release promotes the same commit to production.

Local release workflow

Releases run entirely from your machine — no GitHub Actions minutes consumed:

./dto release                        # Prod: bundle → commit drift → sync prod Supabase → bump → push → web → TestFlight → Firebase
./dto release --staging              # Staging apps only: staging iOS TestFlight + staging Android Firebase

The prod pipeline regenerates bundled assets, commits any drift, syncs the prod Supabase schema + Edge Functions, bumps pubspec.yaml, tags, pushes, deploys prod web to Cloudflare Pages, builds iOS for TestFlight, and builds Android for Firebase App Distribution. Each step aborts on failure; Supabase sync happens before the version bump so a broken sync never tags a release the prod instance can't serve; web/iOS/Android uploads happen after the tag is pushed so partial failures are recoverable with the individual ./dto deploy … commands.

The staging pipeline is lighter: it only builds and uploads the mobile apps because staging web + Supabase were already deployed by CI on merge to main.

Flags: --bump {patch,minor,major}, --skip-supabase, --skip-web, --skip-ios, --skip-android, --staging.

The underlying sub-commands (./dto schema bundle, ./dto deploy supabase [--env staging], ./dto version --push, ./dto deploy ios --testflight [--env staging], ./dto deploy android --distribute [--env staging], ./dto deploy web [--env staging]) are still available for debugging or one-off operations. The fallback .github/workflows/release.yml accepts an env input (prod/staging) and is manual-only (workflow_dispatch) so pushing tags never triggers an unused CI run.

Bring your own Supabase

The app ships with a setup screen that connects to a user-provided Supabase project. On first connect to a blank project, DuTaTo bootstraps the schema and the ai-proxy Edge Function automatically via Supabase's Management API using a one-time Personal (or Organization) Access Token — no CLI, no SQL Editor, no manual secret paste. The same PAT handles every step in one click:

  1. Apply the bundled schema (POST /v1/projects/<ref>/database/query)
  2. Fetch the project's anon + service role keys (GET /v1/projects/<ref>/api-keys)
  3. Deploy ai-proxy (POST /v1/projects/<ref>/functions/deploy?slug=ai-proxy)
  4. Set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY (POST /v1/projects/<ref>/secrets)
  5. Record the bundle hash in _schema_meta.functions_hash for drift detection

The token is never persisted; only the project URL and anon key are stored in flutter_secure_storage. Users who prefer not to create a token can use the manual fallback for schema (copy schema.sql to clipboard + deep-link to the Supabase SQL Editor); Edge Functions still require a one-time token.

Subsequent schema migrations apply silently on sign-in via the _apply_migration() RPC. Subsequent Edge Function updates surface as a "Dutato updates available" banner in the Settings screen — tapping it reopens the PAT dialog in "functions only" mode and redeploys just the function without touching the schema.

Licence revocation is contractual, not technical. See section 10 of the in-app Terms & Conditions (mirrored in docs/TERMS_OF_USE.md) for the scope of your licence and the Dutato operators' right to revoke.

See docs/SELF_HOST.md for the full walkthrough.

When adding a new migration under supabase/migrations/ or modifying supabase/functions/ai-proxy/, run ./dto schema bundle to regenerate assets/schema/schema.sql, assets/migrations/NNN.sql, assets/functions/ai-proxy/**, and lib/data/services/schema_version.g.dart. The CI lint job fails if the bundled artifacts are stale.

Documentation

The generated Dart API reference is published at dutato-docs.pages.dev on every merge to main (Cloudflare Pages, auto-deployed from CI). It covers the Flutter client (lib/) and is grouped into five categories: Overview, Architecture, Data Sources, Providers, Screens & Widgets. Category intros live in doc/categories/; the site is built with dart doc and configured via dartdoc_options.yaml.

./dto docs             # Build HTML into doc/api/ (gitignored)
./dto docs serve       # Serve doc/api/ on http://localhost:8081
./dto docs manifest    # Regenerate committed doc/api-manifest.json (CI drift gate)
./dto ci --docs        # Full CI + manifest drift check (run when touching public API)

The full HTML is never committed — only the lightweight doc/api-manifest.json, a deterministically-sorted list of every public symbol. When a PR changes the public surface, CI's docs-check job fails until the author regenerates and commits the manifest. The deploy job rebuilds HTML from scratch for every push to main.

Developer CLI (dto)

All project tooling is unified under the ./dto CLI (Python/Click, managed by uv). No manual install needed — uv auto-creates the venv on first run.

./dto --help          # List all commands
./dto <command> --help  # Command-specific help

Commands

Command Purpose
dto serve Build web release against local Supabase + Acme demo (default) and serve on localhost:8080. --prod to build against .env credentials instead.
dto screen Automated screenshot pipeline (audit, B2B pitch, App Store)
dto audit Responsiveness, accessibility, and performance audits
dto visual Pixel-level visual-regression baseline + diff (capture / diff / bless)
dto test Run tests (unit, integration, RLS, coverage)
dto ci Full pre-push CI checklist (format, analyze, test, coverage)
dto deploy Build release artifacts (iOS, Android, web). All subcommands accept --env {prod,staging}
dto version Bump version in pubspec.yaml, commit, and tag
dto seed Seed Acme demo org into local Supabase
dto db Database backup and restore
dto user User management (delete)
dto pipeline PDF-to-curriculum content pipeline
dto curriculum Curriculum creator (upload, condense, status)
dto schema Bundle supabase/migrations/ and supabase/functions/ai-proxy/ into Flutter assets
dto deploy supabase Sync prod (default) or staging (--env staging) Supabase with the bundled schema + Edge Functions
dto release Full prod release pipeline (bundle → prod Supabase → bump → web → TestFlight → Firebase)
dto release --staging Staging release: build & upload staging iOS TestFlight + Android Firebase only

Quick Reference

# Build & serve web locally
./dto serve                           # local Supabase + demo seed + serve :8080 (default)
./dto serve --prod                    # use prod credentials from .env instead
./dto serve --skip-build              # Just serve existing build

# Screenshots (default: local Supabase + Acme demo seed for populated screens)
./dto screen --all                    # Full pipeline (build + all screenshots)
./dto screen --audit                  # 43-screen audit (desktop + mobile)
./dto screen --b2b                    # 12 B2B pitch screenshots
./dto screen --audit --multi-role     # + role-gated variants as manager/member
./dto screen --audit --demo-user=manager  # Screenshot as a specific role

# Opt out of demo seed (build against remote Supabase from .env — gives empty/loader screens)
./dto screen --all --no-demo

# Audits (responsiveness, accessibility, performance) — demo mode default
./dto audit responsive                # 9 viewports × 16 routes, overflow + touch targets
./dto audit responsive --strict       # Same, but exits 1 on overflow / sub-44px tap targets (local-only gate; bundled into ./dto ci --responsive)
./dto audit a11y                      # Flutter semantics + axe + tab order + focus rings
./dto audit perf                      # Core Web Vitals + Flutter first-frame + Lighthouse
./dto audit all                       # Run all 3 with single build + seed
./dto audit perf --cold-only --skip-lighthouse  # Fastest perf run (no warm, no Lighthouse)

# Visual regression (baseline at test/visual/baseline/{desktop,mobile}/)
./dto visual diff                     # Re-capture + pixelmatch vs baseline (local check, exits 1 on regression)
./dto visual capture                  # First-time baseline capture (refuses if baseline exists)
./dto visual bless                    # Overwrite baseline after a deliberate UI change (alias for capture --force)
./dto visual diff --tolerance=0.01    # Loosen the 0.5% default fail threshold

# Testing
./dto test                            # Unit/widget tests
./dto test --integration              # Integration tests (starts local Supabase)
./dto test --all                      # Unit + integration
./dto test --rls                      # RLS Docker smoke tests
./dto test --coverage                 # Unit tests + 70% coverage gate
./dto ci                              # Full CI checklist (format → analyze → test → coverage)
./dto ci --rls                        # CI + RLS tests
./dto ci --responsive --visual        # CI + the local-only UI gates dropped from remote (responsive audit + pixelmatch)

# Build & deploy (prod is default; append `--env staging` for staging builds)
./dto deploy ios                      # Build prod IPA + install on device
./dto deploy ios --testflight         # Build + upload to prod TestFlight
./dto deploy ios --testflight --env staging  # Build + upload to staging TestFlight
./dto deploy android                  # Build prod APK + install via ADB
./dto deploy android --env staging    # Build staging APK + install via ADB
./dto deploy android --distribute     # Build prod APK + upload to Firebase App Distribution
./dto deploy web                      # Build prod web release (local)
./dto deploy web --env staging        # Build staging web release (local)
./dto deploy supabase                 # Sync prod Supabase (schema + Edge Functions)
./dto deploy supabase --env staging   # Sync staging Supabase (rarely needed — CI handles this)

# Version management
./dto version                         # Patch bump (0.1.3 → 0.1.4)
./dto version --minor                 # Minor bump
./dto version --push                  # Bump + push to origin

# Demo data
./dto seed                            # Seed Acme Learning Corp (17 users, 3 teams)

# Database
./dto db backup                       # Dump public schema + auth.users
./dto db restore                      # List available backups
./dto db restore backups/<timestamp>  # Restore specific backup

# User management
./dto user delete --email user@example.com
./dto user delete --email user@example.com --dry-run

# Content pipeline
./dto pipeline                        # Process all PDF books
./dto pipeline --file book.pdf --domain code --title "Clean Code" --author "R. Martin"
./dto pipeline extract book.pdf       # Extract text only
./dto pipeline upload --domain code   # Upload to Supabase
./dto pipeline embeddings             # Generate vector embeddings

# Curriculum creator
./dto curriculum status output/postgresql/
./dto curriculum upload --input output/postgresql/ --owner org --org-id <uuid>
./dto curriculum condense --input output/postgresql/ --plan <plan.json>
./dto curriculum setup-db --db-url postgresql://... --apply-migrations

Testing

CI runs 8 parallel jobs on PRs to main:

  1. Lint & Formatdart format + flutter analyze (~1min)
  2. Unit Tests — unit/widget tests with 70% coverage gate (~3min)
  3. Integration Tests — datasource tests against local Supabase with 80% coverage gate (~3min)
  4. RLS & RPC Tests — Dockerized PostgreSQL running RLS assertions and RPC smoke tests (~2min)
  5. BYO E2E Tests — Dockerized Supabase provisioner end-to-end smoke (~3min)
  6. Widget Goldens — Alchemist visual-regression snapshots for shared widgets (~1min)
  7. Docs Manifest Drift — fails if doc/api-manifest.json is stale (~2min)
  8. Web Build (staging) — Flutter web release build with staging Supabase secrets, uploaded as the deploy artifact (~3min)

The responsive audit (./dto audit responsive --strict, 9-viewport Playwright run) and the pixelmatch visual-diff (./dto visual diff) are intentionally not in PR CI: they hang unpredictably on GHA's headless Chromium and would burn ~22 runner minutes per PR. They run locally only — contributors must invoke them before pushing UI changes.

Native-config regressions (Android manifest intent-filter, iOS Info.plist OAuth scheme, project.pbxproj bundle-ID drift, xcconfig flavor wiring) are caught at the unit-test layer by test/platform/oauth_deep_link_config_test.dart, which parses the native files and cross-checks them against EnvConfig.deepLinkScheme. The full end-to-end Android APK + emulator smoke and iOS xcodebuild flavor build would add ~54min per PR (macOS minutes bill at 10× Linux) so they're not run in PR CI — contributors must run them locally before pushing native-config changes:

./dto ci --android-deeplink   # boot an Android emulator in another terminal first
./dto ci --ios                # requires Xcode

CLAUDE.md's pre-push checklist documents this contract.

On push to main, Deploy to Cloudflare Pages downloads the web-build artifact (no rebuild). Stale CI runs are auto-cancelled when new commits are pushed (concurrency.cancel-in-progress).

Demo Data (Sales Demos)

Seeds a realistic org ("Acme Learning Corp") with 17 users, 3 teams, manager hierarchy, assignments, learning paths, skills, certifications, XP/badges, notifications, and enterprise config against local Supabase.

./dto seed   # One command — starts Supabase if needed

Data persists across supabase stop/start. After supabase db reset, re-run ./dto seed. Login: alice.morgan@acme-demo.test / DemoPass123!. See tools/demo_seed/README.md for all accounts.

Project Structure

dutato/
  lib/                  # Flutter app source
  docs/                 # Methodology documentation
    methodology.md      # Learning theory, cognitive debt, mastery gating
    content-structure.md # Content inventory and topic tree design
    claude-prompts.md   # 8 Claude system prompts
    spaced-repetition.md # SM-2 algorithm and review card types
    RELEASE.md          # Release process
    SELF_HOST.md        # Self-hosting guide
  plans/                # Development milestones (plan-1 through plan-32)
  supabase/migrations/  # Database schema (60 migrations)
  assets/
    schema/             # Bundled schema.sql + version.txt (generated by ./dto schema bundle)
    migrations/         # Per-migration SQL used by SchemaMigrator at sign-in
  dto                   # CLI wrapper (run ./dto --help)
  tools/
    dto/                # CLI package (Python/Click)
    pdf_pipeline/       # Content extraction and processing
    curriculum_creator/ # AI agent-operated curriculum pipeline
    db_backup/          # Database backup and restore utilities
    demo_seed/          # Sales demo org (Acme Learning Corp, 17 users)
    visual/             # pixelmatch + diff.js (./dto visual harness)
  web/                  # Flutter web platform (index.html, manifest, icons)
  test/                 # 204 test files
    helpers/            # Shared mocks & Supabase test init
    visual/baseline/    # Committed PNG baselines for ./dto visual diff (local check)
    integration/        # 37 integration test files (tagged, require Supabase)
    rls/                # RLS policy + RPC smoke tests (Docker + PostgreSQL)
    platform/           # Native config guardrails (OAuth deep-link, bundle IDs)

Database

Supabase PostgreSQL with 62 migrations. Key table groups:

  • Content: domains (with owner_id, visibility), books, topics (hierarchical), content_chunks, curriculum_levels, curriculum_shares, domain_variants, reading_questions, reading_responses
  • User progress: profiles (with target_retention, fsrs_parameters, onboarding_step / onboarding_completed_at, admin_onboarding_step / admin_onboarding_completed_at, seen_tooltips), user_topic_progress, learning_sessions, conversation_messages, learning_objectives
  • Review system: review_cards (FSRS + SM-2 dual-algorithm), review_log (immutable per-event history), quizzes, assessments, mastery_overrides
  • Calibration: confidence_events, topic_retention_stats
  • Prerequisites: topic_prerequisites (required/recommended strength)
  • Goals & annotations: learning_goals, user_annotations, user_notes
  • Organizations: organizations, org_members, org_invitations, org_verified_domains, teams, team_members, curriculum_assignments (with status tracking), manager_assignments, platform_admins
  • Enterprise: certifications, user_certificates, compliance_requirements, skills, role_profiles, role_skill_expectations, member_role_assignments, org_sso_configs, org_api_keys, org_webhooks, webhook_deliveries, learning_paths, learning_path_steps, learning_path_enrollments
  • Native integrations: org_integrations (Slack / Notion / Lucca OAuth tokens, AES-GCM encrypted + REVOKE'd from PostgREST), org_integration_oauth_states (CSRF), integration_events (async delivery queue drained by pg_cron → slack-notify / notion-sync / lucca-sync). See docs/integrations/.
  • Billing: subscriptions (per-user or per-org, Stripe or RevenueCat), admin_grants (platform-admin overrides), billing_events (webhook receipts, append-only)
  • Gamification: user_xp, xp_events, badges, user_badges
  • Infrastructure: device_tokens, rate_limits (per-plan), sanitization_logs, user_quotas, audit_log (append-only visibility/share events for legal compliance)

Schema defined in supabase/migrations/. Row-Level Security (RLS) policies enforce access control — see test/rls/ for smoke tests, including rls_entitlements_test.sql which covers the per-plan gates on SSO, SCIM, webhooks, certifications, compliance, and learning paths.

Monetization & Plans

DuTaTo is a B2B learning platform with four plan tiers, resolved server-side by current_entitlements() (migrations 052/057/058):

Tier Audience Billing channel Key limits
Trial Auto-applied at signup, 14 days 1 domain, 50 AI messages total, no team features
Professional (€19/mo) Solo pros iOS/Android IAP via RevenueCat; web via Stripe Checkout Unlimited domains, 500 AI msgs/day
Team (€12/user/mo) 5–50 seat orgs, self-serve Stripe web only (Apple/Google enterprise exception) Team analytics, assignments, webhooks, Slack/Notion/Lucca integrations, learning paths, certifications
Enterprise (€15/user/mo) 50+ seats, self-serve or sales-assisted Stripe self-serve or Billing invoicing Everything + SSO, SCIM, org API keys, compliance

Entitlements are a flat key/value map (org.teams, org.sso, org.webhooks, org.integrations, ai.daily_cap, ai.total_cap, etc.). RLS policies on enterprise tables use org_has_entitlement() (migration 053) to gate writes, while SELECT policies remain permissive so downgraded users keep read access to their existing data.

AI usage is metered per user by the ai-proxy Edge Function against ai_limits_for_user() (migration 055, updated by 058 to include total_cap); usage meters and remaining-quota badges surface this state to the UI (lib/presentation/widgets/usage_meter_badge.dart). Trial users see a total-messages counter (e.g. "23/50") rather than daily/weekly quotas.

Billing architecture

  • Mobile (iOS/Android)purchases_flutter → StoreKit 2 / Google Play Billing → RevenueCat → revenuecat-webhook Edge Function → subscriptions table
  • Web (orgs & solo) → Stripe Checkout → stripe-webhook Edge Function → subscriptions table
  • Client entitlement provider reads current_entitlements() and invalidates on auth state change
  • Platform admins can comp users/orgs, extend trials, and boost AI caps via admin_grants rows (backoffice screens at /backoffice/users and the Billing & grants panel on the org detail screen)

BYOK AI: users supply their own Anthropic/OpenAI/Gemini key (existing architecture). The subscription monetizes the platform, not AI tokens.

Edge Functions in supabase/functions/:

  • stripe-webhook — processes Stripe events (signature-verified, idempotent via billing_events)
  • create-checkout-session — returns a Stripe Checkout URL (JWT-authenticated, org-admin-gated for org plans)
  • create-portal-session — returns a Stripe Billing Portal URL
  • revenuecat-webhook — processes RevenueCat events (shared-secret auth)

Libraries

config/ai_provider_config
config/env_config
config/mastery_ring
config/retrieval_config
config/review_stamp
config/routes
config/supabase_config
core/errors/error_mapper
core/errors/failures
core/errors/postgrest_error_helpers
core/extensions/datetime_ext
core/utils/calibration
core/utils/common_words
core/utils/deliberate_practice
core/utils/file_saver
core/utils/file_saver_barrel
core/utils/file_saver_web
core/utils/fsrs
core/utils/interleaving
core/utils/password_validator
core/utils/retention_tracker
core/utils/spaced_repetition
core/utils/streak_calculator
data/datasources/ai_datasource
data/datasources/billing_datasource
data/datasources/claude_datasource
data/datasources/entitlement_datasource
data/datasources/gemini_datasource
data/datasources/google_auth_service
data/datasources/grants_datasource
data/datasources/list_models_via_proxy
data/datasources/local_embedding_datasource
data/datasources/local_embedding_datasource_barrel
data/datasources/local_embedding_datasource_stub
data/datasources/local_vector_store
data/datasources/local_vector_store_barrel
data/datasources/local_vector_store_stub
data/datasources/openai_auth_service
data/datasources/openai_datasource
data/datasources/org_datasource
data/datasources/proxy_ai_datasource
data/datasources/revenuecat_datasource
data/datasources/revenuecat_datasource_barrel
data/datasources/revenuecat_datasource_stub
data/datasources/supabase_datasource
data/datasources/user_prefs_datasource
data/models/admin_grant_model
data/models/bookmark_model
data/models/certification_models
data/models/content_chunk_model
data/models/curriculum_assignment_model
data/models/curriculum_level_model
data/models/curriculum_share_model
data/models/domain_model
data/models/enterprise_integration_models
data/models/entitlement_model
data/models/gamification_models
data/models/learning_goal_model
data/models/learning_objective_model
data/models/learning_path_model
data/models/learning_session_model
data/models/manager_assignment_model
data/models/mastery_override_model
data/models/org_analytics_models
data/models/org_integration_model
data/models/org_invitation_model
data/models/org_member_model
data/models/org_notification_model
data/models/org_verified_domain_model
data/models/organization_model
data/models/profile_model
data/models/reading_question_model
data/models/review_card_model
data/models/review_log_model
data/models/skill_framework_models
data/models/subscription_model
data/models/team_model
data/models/team_progress_entry_model
data/models/topic_model
data/models/user_note_model
data/models/user_topic_progress_model
data/services/chunk_sync_service
data/services/content_retriever
data/services/fcm_service
data/services/fcm_service_barrel
Conditional-import barrel for FcmService. Native builds export the real implementation; web gets a no-op stub so firebase_messaging never reaches the JS bundle. Always import this barrel — never the underlying files.
data/services/fcm_service_stub
data/services/fcm_setup
data/services/fcm_setup_barrel
Conditional-import barrel for initFirebaseAndFcm. Native (iOS / Android) builds export the real implementation from fcm_setup.dart; web builds get the no-op stub from fcm_setup_stub.dart. Always import this barrel — never the underlying files — so platform branching stays invisible to callers and the firebase_* packages never reach the web JS bundle.
data/services/fcm_setup_stub
data/services/keyword_extractor
data/services/notification_service
data/services/notification_service_barrel
data/services/notification_service_stub
data/services/prerequisite_service
data/services/schema_migrator
data/services/schema_version.g
data/services/supabase_provisioner
domain/entities/admin_grant
domain/entities/bookmark
domain/entities/certification
domain/entities/content_chunk
domain/entities/curriculum_assignment
domain/entities/curriculum_level
domain/entities/curriculum_share
domain/entities/domain_entity
domain/entities/enterprise_integration
domain/entities/entitlement
domain/entities/gamification
domain/entities/learning_goal
domain/entities/learning_objective
domain/entities/learning_path
domain/entities/learning_session
domain/entities/manager_assignment
domain/entities/mastery
domain/entities/mastery_override
domain/entities/notification_preferences
domain/entities/org_analytics
domain/entities/org_integration
domain/entities/org_invitation
domain/entities/org_member
domain/entities/org_notification
domain/entities/org_verified_domain
domain/entities/organization
domain/entities/reading_question
domain/entities/review_card
domain/entities/review_log
domain/entities/skill_framework
domain/entities/subscription
domain/entities/team
domain/entities/team_progress_entry
domain/entities/topic
domain/entities/user_note
domain/services/domain_grouping
main
presentation/providers/auth_provider
presentation/providers/billing_providers
presentation/providers/bookmark_providers
presentation/providers/card_generation_provider
presentation/providers/entitlement_providers
presentation/providers/functions_status_provider
presentation/providers/grants_providers
presentation/providers/mfa_provider
presentation/providers/notification_providers
presentation/providers/onboarding_provider
presentation/providers/org_providers
presentation/providers/providers
presentation/providers/quota_providers
presentation/providers/revenuecat_providers
presentation/providers/user_prefs_provider
presentation/screens/admin_onboarding/admin_onboarding_curriculum_screen
presentation/screens/admin_onboarding/admin_onboarding_members_screen
presentation/screens/admin_onboarding/admin_onboarding_org_basics_screen
presentation/screens/admin_onboarding/admin_onboarding_org_picker_screen
presentation/screens/admin_onboarding/admin_onboarding_scaffold
presentation/screens/admin_onboarding/admin_onboarding_screens
Deferred-load barrel for the admin org-creation flow. Only shown to org admins on first sign-in after they accept an admin invite — regular learners never load this chunk.
presentation/screens/admin_onboarding/admin_onboarding_tour_screen
presentation/screens/auth/auth_screens
Deferred-load barrel for the auth flow (login, forgot, reset). Pulled in when an unauthenticated visitor lands on one of those routes — already-authenticated users on / never load this chunk.
presentation/screens/auth/forgot_password_screen
presentation/screens/auth/login_screen
presentation/screens/auth/mfa_enroll_screen
presentation/screens/auth/mfa_screens
Deferred-load barrel for the 2FA flow. Splits qr_flutter (used by the enroll screen for the TOTP QR code) out of the entry chunk — users without 2FA never download it.
presentation/screens/auth/mfa_verify_screen
presentation/screens/auth/reset_password_screen
presentation/screens/auth/terms_acceptance_screen
presentation/screens/backoffice/backoffice_org_detail_screen
presentation/screens/backoffice/backoffice_screen
presentation/screens/backoffice/backoffice_screens
Deferred-load barrel for the platform-admin backoffice. Gated by PlatformAdminGuard; non-admin users never reach these routes, so keeping them out of the entry chunk has zero UX cost for everyone else. Re-exports PlatformAdminGuard so it lives entirely in this chunk — routes.dart reaches it through the deferred prefix.
presentation/screens/backoffice/backoffice_users_screen
presentation/screens/bookmarks/bookmarks_screen
presentation/screens/domains/curriculum_creator_screen
presentation/screens/domains/curriculum_creator_screens
Deferred-load barrel for the content-authoring flows (/domains/curriculum-creator and /domains/upload-curriculum). Only opened by content creators; defers file_picker for everyone else.
presentation/screens/domains/domain_list_screen
presentation/screens/domains/domain_screens
Deferred-load barrel for the domains and topic-tree flow. Includes the bottom-nav target (DomainListScreen) and the topic tree shown when drilling into a domain. Defers anything domain-specific out of the entry chunk.
presentation/screens/domains/topic_tree_screen
presentation/screens/domains/upload_curriculum_screen
presentation/screens/goals/goals_list_screen
presentation/screens/home/home_screen
presentation/screens/lesson/lesson_screens
Deferred-load barrel for the lesson viewer. Reached from /domains/:slug/topics/:id/lesson — splits flutter_animate and the markdown-rendering stack out of the entry chunk.
presentation/screens/lesson/lesson_viewer_screen
presentation/screens/notes/note_detail_screen
presentation/screens/notes/notes_screens
Deferred-load barrel for the note detail screen. Reached only by editing a note from the progress dashboard or the lesson viewer.
presentation/screens/onboarding/onboarding_first_session_screen
presentation/screens/onboarding/onboarding_mastery_screen
presentation/screens/onboarding/onboarding_page_scaffold
presentation/screens/onboarding/onboarding_review_screen
presentation/screens/onboarding/onboarding_screens
Deferred-load barrel for the first-session onboarding flow. The six screens below are visited at most once per account; deferring them keeps that one-time content out of the entry chunk.
presentation/screens/onboarding/onboarding_welcome_screen
presentation/screens/onboarding/onboarding_why_screen
presentation/screens/onboarding/profile_completion_screen
presentation/screens/org/api_keys_screen
presentation/screens/org/assignment_detail_screen
presentation/screens/org/badges_screen
presentation/screens/org/certificate_view_screen
presentation/screens/org/certifications_screen
presentation/screens/org/compliance_dashboard_screen
presentation/screens/org/curriculum_assignment_screen
presentation/screens/org/gamification_settings_screen
presentation/screens/org/integrations_screen
presentation/screens/org/leaderboard_screen
presentation/screens/org/learning_paths_screen
presentation/screens/org/member_detail_screen
presentation/screens/org/member_management_screen
presentation/screens/org/notification_center_screen
presentation/screens/org/org_analytics_screen
presentation/screens/org/org_billing_screen
presentation/screens/org/org_dashboard_screen
presentation/screens/org/org_progress_report_screen
presentation/screens/org/org_screens
Deferred-load barrel for the org admin shell (Plan 50+). Holds 25+ screens that are only reachable from /org/:orgId/... routes — so learners on personal accounts never download this chunk. Includes the only consumers of fl_chart in the app (analytics, member detail, compliance dashboard) and the OrgShellScaffold wrapper itself, so the scaffold also stays out of the entry chunk.
presentation/screens/org/org_settings_screen
presentation/screens/org/path_detail_screen
presentation/screens/org/path_progress_screen
presentation/screens/org/role_profiles_screen
presentation/screens/org/skill_framework_screen
presentation/screens/org/skill_gap_screen
presentation/screens/org/sso_settings_screen
presentation/screens/org/team_management_screen
presentation/screens/org/webhooks_screen
presentation/screens/progress/learning_guide_screen
presentation/screens/progress/override_history_screen
presentation/screens/progress/progress_dashboard_screen
presentation/screens/progress/progress_extras
Deferred-load barrel for the progress / goals / bookmarks flow. Holds every screen reachable from the Progress and Library bottom-nav destinations — including the dashboards themselves, so the entry chunk only ships the home view + shell scaffold.
presentation/screens/review/card_proposals_screen
presentation/screens/review/review_extras
Deferred-load barrel for the review flow. Includes the main ReviewSessionScreen (bottom-nav target for /review) so the flutter_markdown_plus stack used by the answer renderer never reaches the entry chunk.
presentation/screens/review/review_session_screen
presentation/screens/settings/account_settings_screen
presentation/screens/settings/ai_settings_screen
presentation/screens/settings/change_password_screen
presentation/screens/settings/learning_settings_screen
presentation/screens/settings/notifications_settings_screen
presentation/screens/settings/privacy_settings_screen
presentation/screens/settings/settings_extras
Deferred-load barrel for the entire settings flow. Includes the landing page (SettingsScreen) plus the seven sub-screens, so the settings UI loads only when the user opens the Settings tab.
presentation/screens/settings/settings_screen
presentation/screens/settings/subscription_screen
presentation/screens/settings/widgets/oauth_section
presentation/screens/settings/widgets/section_header
presentation/screens/settings/widgets/test_connection_button
presentation/screens/setup/persona_screen
presentation/screens/setup/setup_screen
presentation/screens/setup/setup_screens
Deferred-load barrel for the one-time setup flow (setup connection + persona). Pulled in only when the user lands on /setup or /persona, not on first paint of /.
presentation/screens/tutor/chat_screen
presentation/screens/tutor/chat_screens
Deferred-load barrel for the tutor flow. Includes the main TutorModeScreen (bottom-nav target for /tutor) and the deeper ChatScreen, so the flutter_code_editor + flutter_highlight stack used by the in-chat code editor never reaches the entry chunk.
presentation/screens/tutor/tutor_mode_screen
presentation/widgets/access_token_dialog
presentation/widgets/active_goal_card
presentation/widgets/badge_popup
presentation/widgets/bookmark_button
presentation/widgets/brand_wordmark
presentation/widgets/chapter_mark
presentation/widgets/chat_bubble
presentation/widgets/chunk_image_builder
presentation/widgets/code_block_builder
presentation/widgets/code_editor_input
presentation/widgets/components/buttons
presentation/widgets/components/kpi_card
presentation/widgets/components/section_tabs
presentation/widgets/components/status_badge
presentation/widgets/deferred_screen
presentation/widgets/domain_manage_sheet
presentation/widgets/domain_stat_tile
presentation/widgets/due_today_card
presentation/widgets/dutato_markdown_style
presentation/widgets/editorial_row
presentation/widgets/empty_state
presentation/widgets/entitlement_bootstrap
presentation/widgets/forced_password_update_dialog
presentation/widgets/graduation_cap_icon
presentation/widgets/home_header
presentation/widgets/level_manage_sheet
presentation/widgets/mastery_progress_stepper
presentation/widgets/mode_tabs
presentation/widgets/mode_toggle_button
presentation/widgets/notification_bell
presentation/widgets/onboarding_gate
presentation/widgets/org_detail_scaffold
presentation/widgets/org_feature_gate
presentation/widgets/org_shell_scaffold
presentation/widgets/password_strength_indicator
presentation/widgets/path_stepper
presentation/widgets/pending_invitations_modal
presentation/widgets/platform_admin_guard
presentation/widgets/progress_ring
presentation/widgets/quick_note_sheet
presentation/widgets/reflection_form
presentation/widgets/role_gate
presentation/widgets/session_rubric
presentation/widgets/streak_indicator
presentation/widgets/streak_sparkline
presentation/widgets/suggested_actions
presentation/widgets/terms_gate
presentation/widgets/topic_tree_widget
presentation/widgets/tutor_bubble
presentation/widgets/upgrade_prompt
presentation/widgets/usage_meter_badge
presentation/widgets/visibility_change_modal
presentation/widgets/web_content_frame
presentation/widgets/xp_bar
theme