> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuturuuu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Mobile Drive, CRM, And Education

> What the mobile app supports for workspace Drive, CRM, Education, and the Apps hub shell.

## Overview

The mobile app now ships first-party workspace surfaces for:

* Drive at `Routes.drive`
* CRM at `Routes.crm`
* Education at `Routes.education`

Both modules are registered in the Apps hub and available through the mini-app navigation system.

The mobile Apps hub now uses a single-column list of equal-priority app cards instead of the older grid treatment. Keep module ordering explicit in the hub view rather than relying on registry insertion order. For workspace modules that need dense controls, prefer the same shell-owned chrome used by Calendar:

* `ShellMiniNav` for mode or section switching
* `ShellChromeActions` for quick actions such as filters, create, sort, and view toggles
* A finance-style overview hero card inside the page body for stats and search
* Compact panel sections in the page body instead of raw admin `Card/ListTile` stacks, so module pages read like first-class mobile products rather than direct dashboard ports

Background warmups for optional products should also respect access state before fetching. Do not let Apps hub or boot-time cache warmups call product endpoints blindly; skip the warmup when the corresponding access cubit is not loaded and enabled, and fail soft on opportunistic `404` responses.

## Mobile App Lock And Web QR Approval

The mobile app supports a device-level app lock from Settings > Session. The
setting is stored in secure storage and uses the OS local authentication prompt
with device PIN/passcode fallback allowed. When enabled, the app locks on an
authenticated cold launch and after at least 30 seconds in the background.

QR session handoff approval is gated by this setting:

* The scanner lives at `Routes.settingsQrLoginScan`.
* The scanner only accepts `tuturuuu://auth/qr-login` payloads from trusted
  Tuturuuu or local development origins.
* The QR challenge must have been created by the same account that is active in
  the mobile app. Public unauthenticated QR sign-in is not supported because it
  would let an attacker poll a victim-approved challenge.
* Before approval, mobile runs local authentication and then calls
  `/api/v1/auth/qr-login/challenges/:id/approve` with the current Bearer
  session.

If a user wants to approve QR session handoff for a different account, both the
creator session and the mobile app must be using that account before scanning.

The mobile app can approve web MFA challenges when the active mobile Supabase
session is already at `aal2`:

* The web MFA screen creates an `/api/v1/auth/mfa/mobile/challenges` request and
  shows a pair code.
* `MobileMfaApprovalListener` is mounted at the app shell and polls
  `/api/v1/auth/mfa/mobile/approvals` while the user is authenticated, the app is
  in the foreground, and app lock is not covering the UI.
* Pending pair codes open an app-level approval dialog. The Settings > Session
  tile remains a manual fallback surface for the same pending approvals.
* Mobile approves through
  `/api/v1/auth/mfa/mobile/challenges/:id/approve`.
* The web poller consumes the approved challenge and sets an HTTP-only
  `ttr_mfa_mobile_approval` cookie. The central auth proxy accepts that cookie
  only for the same user, the hidden web challenge secret, and an unexpired
  consumed `mfa_mobile_approval` challenge.
* After a mobile TOTP challenge succeeds, `AuthCubit.verifyMfa` must sync the
  refreshed `aal2` Supabase session into the active multi-account store. Without
  that sync, later mobile API calls can restore/send an older `aal1` token and
  the approvals endpoint will respond with `requiresMobileMfa`.
* Multi-account removal and all-account logout must treat Supabase
  `auth.signOut()` as required before clearing the local account store or
  emitting an unauthenticated Cubit state. Google/provider logout and stored
  refresh-token revocation can be best-effort, but a failed Supabase logout must
  leave the account visible with an error so the persisted session cannot
  silently reappear later.
* Auth account models may serialize refresh tokens and session JSON only for the
  encrypted secure-storage store. Do not include those raw secrets in
  `Equatable.props`, `toString`, or other Cubit/Bloc state debug output because
  the global Bloc observer logs state changes during development.

## Mobile Drive Coverage

The Drive screen in `apps/mobile` supports the main dashboard Drive flow:

* Workspace permission-gated loading
* Storage analytics summary
* Folder navigation and breadcrumb-style path movement
* Search, sort, grid/list toggle, and pagination
* Folder creation, rename, delete, bulk delete, and upload
* File preview, external open, share, and path copy
* Folder export-link generation and sharing

The mobile implementation talks to the same authenticated workspace storage routes used by the web product:

* `/api/v1/workspaces/:wsId/storage/list`
* `/api/v1/workspaces/:wsId/storage/analytics`
* `/api/v1/workspaces/:wsId/storage/folders`
* `/api/v1/workspaces/:wsId/storage/rename`
* `/api/v1/workspaces/:wsId/storage/object`
* `/api/v1/workspaces/:wsId/storage/share`
* `/api/v1/workspaces/:wsId/storage/export-links`
* `/api/v1/workspaces/:wsId/storage/upload-url`
* `/api/v1/workspaces/:wsId/storage/finalize-upload`

## Mobile CRM Coverage

The CRM screen in `apps/mobile` supports:

* Workspace permission-gated users and audit tabs
* Search, filters, pagination, and audit range filters
* Create, edit, and delete user records
* Avatar upload during create/edit flows
* Feedback create/update/delete flows
* Duplicate detection and merge flows
* CSV import with preview and deduping by email
* CSV export of the currently filtered users dataset

The mobile CRM uses the existing authenticated routes:

* `/api/v1/workspaces/:wsId/users/database`
* `/api/v1/workspaces/:wsId/users`
* `/api/v1/workspaces/:wsId/users/:userId`
* `/api/v1/workspaces/:wsId/users/groups`
* `/api/v1/workspaces/:wsId/users/feedbacks`
* `/api/v1/workspaces/:wsId/users/audit-logs`
* `/api/v1/workspaces/:wsId/users/duplicates/detect`
* `/api/v1/workspaces/:wsId/users/merge`
* `/api/v1/workspaces/:wsId/users/bulk-import`
* `/api/v1/workspaces/:wsId/users/avatar`

For CRM list and duplicate/merge routes, keep workspace resolution request-aware on the web side. Mobile calls authenticate with Bearer tokens rather than dashboard cookies, so routes that resolve the workspace with cookie-only helpers can fail as `Workspace not found` even for valid workspace members.

## Mobile Education Coverage

The Education screen in `apps/mobile` supports:

* An overview dashboard with counts for courses, quizzes, quiz sets, flashcards, and attempts
* Course search, create, edit, delete, and paginated browsing
* Library management for quizzes, quiz sets, and flashcards
* Quiz authoring with answer options, correctness flags, and explanations
* Attempt browsing with status and quiz-set filters plus attempt-detail review

The mobile Education module uses authenticated workspace routes from `apps/web`:

* `/api/v1/workspaces/:wsId/courses`
* `/api/v1/workspaces/:wsId/courses/:courseId`
* `/api/v1/workspaces/:wsId/quizzes`
* `/api/v1/workspaces/:wsId/quizzes/:quizId`
* `/api/v1/workspaces/:wsId/quiz-sets`
* `/api/v1/workspaces/:wsId/quiz-sets/:setId`
* `/api/v1/workspaces/:wsId/flashcards`
* `/api/v1/workspaces/:wsId/flashcards/:flashcardId`
* `/api/v1/workspaces/:wsId/education/attempts`
* `/api/v1/workspaces/:wsId/education/attempts/:attemptId`

For mobile-facing collection APIs, keep list routes request-aware and list-shaped. A cookie-only helper or `.single()` response on a collection endpoint can work in the web dashboard but break mobile Bearer-token callers or pagination assumptions.

The mobile endpoint registry is guarded by `bun check:mobile-api-mappings`.
The check extracts Flutter `/api/*` templates from `api_config.dart` and the
production endpoint catalog used by the `ttr` CLI SDK. It verifies that both
legacy clients still resolve to a canonical owner in a checked-in Next
satellite, the legacy route wrappers, or the Rust/TanStack migration manifest.
The `Mobile API Mappings` workflow runs whenever either client catalog, an app
API route, or the migration manifest changes. If a route is migrated or
removed, update Flutter and the CLI SDK in the same change instead of leaving a
legacy client to discover the break in production.

## Mobile Inventory And Storefront Coverage

Inventory is a native mobile workspace with overview, product CRUD, checkout,
sales, setup, audit-log access, and storefront management. Storefronts support
create/edit/delete, status and visibility controls, public preview, product
listing CRUD, stock-row selection, pricing, and per-order limits through the
same authenticated inventory satellite APIs:

Mobile sales also support workspace sales periods. Operators can create a
season or event such as `Summer 2026` or `TuCon 2026`, filter the mixed
invoice/checkout history by that period, and assign the period during sale
creation or editing. Archiving preserves historical reporting.

* `/api/v1/workspaces/:wsId/inventory/storefronts`
* `/api/v1/workspaces/:wsId/inventory/storefronts/:storefrontId`
* `/api/v1/workspaces/:wsId/inventory/storefronts/:storefrontId/listings`
* `/api/v1/workspaces/:wsId/inventory/storefronts/:storefrontId/listings/:listingId`

Keep Storefront in the five-item Inventory mini navigation. Audit logs remain
discoverable from Inventory Manage so compact phones retain a stable native
navigation bar.

When an Education mobile list needs derived counts from workspace-protected join tables such as `course_module_quiz_sets`, verify workspace membership first with the request-scoped client, then run the joined read on an admin-backed client. Also select real join columns such as `module_id`; do not assume those bridge tables expose a synthetic `id`.

## Import And Export Format Notes

* The web CRM page still has richer spreadsheet tooling, including XLSX-oriented flows.
* Mobile import and export currently use CSV plus native share sheets.
* Keep the server contract for bulk import as a raw JSON array of `{ email, fullName }` rows.

This format choice is intentional for now: the current Flutter dependency graph in `apps/mobile` does not accept a stable XLSX package cleanly without conflicts, so mobile should prefer CSV/share flows unless spreadsheet generation is moved server-side later.

## Verification

For Drive, CRM, or Education mobile changes:

1. Update `apps/mobile/lib/l10n/arb/*.arb` for every new user-facing string.
2. Run `flutter gen-l10n`.
3. Run `bun check:mobile`.
