learning_ai_notes/docs/MOBILE_DELEGATION_ROADMAP.md
saravanakumardb1 cfcb25e379 docs(mobile): add post-completion audit summary to MOBILE_DELEGATION_ROADMAP
- Document 7 bugs/gaps found and fixed during systematic review of blocks A–H
- Note remaining blocks F and I as deferred/optional
2026-03-31 01:19:41 -07:00

276 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# NoteLett Mobile — Delegation Roadmap (single-agent, sequential)
**Purpose:** One document to hand to an AI or human implementer. Execute **blocks in order** (later blocks assume earlier ones are merged). When a block is done, update **`docs/AGENT_TASK_ROADMAP.md`** (e.g. **Current State** table and any new mobile checklist rows), then commit and push.
**Canonical product checklist:** [`AGENT_TASK_ROADMAP.md`](./AGENT_TASK_ROADMAP.md).
**Repo:** `learning_ai_notes`
**Mobile app root:** `mobile/` (Expo Router under `mobile/src/app/`).
**Stack:** Expo ~55, React Native ~0.83, Zustand + MMKV, `@bytelyst/*` (auth-client, api-client, telemetry-client, feature-flag-client, kill-switch-client, blob-client, offline-queue, diagnostics-client).
**Related pattern:** NomGap uses the same idea under `learning_ai_fastgap/docs/MOBILE_DELEGATION_ROADMAP.md`**do not** copy fasting-specific paths or M-numbers; this file is authoritative for NoteLett.
---
## 0 — Prerequisites (before writing code)
- [ ] **Install:** From `learning_ai_notes` root: `pnpm install` (workspace: `backend`, `web`, `mobile`).
- [ ] **Private registry:** If `.npmrc` references `${GITEA_NPM_HOST}`, set env so installs resolve `@bytelyst/*`.
- [ ] **Baseline:** `cd mobile && pnpm run typecheck` (and `pnpm test`) pass on your machine.
- [ ] **Branch:** `git checkout -b feat/mobile-<block-name>` (one branch per major block is fine).
**Note:** This repos `pnpm-workspace.yaml` lists only `backend`, `web`, `mobile` — not `learning_ai_common_plat`. Platform packages typically resolve from the registry; link local plat only if your team uses that workflow.
---
## 1 — Already shipped (verify before redoing)
| Area | What to verify |
|------|----------------|
| **Router + shell** | `mobile/src/app/_layout.tsx` — bootstraps auth, `initPlatform()`, hydrates stores |
| **Entry** | `mobile/src/app/index.tsx``Redirect` to `/auth` |
| **Auth UI** | `mobile/src/app/auth.tsx` — email/password → `useAuthStore``/(tabs)` |
| **Auth + API** | `mobile/src/api/auth.ts` (`createAuthClient`, MMKV `storagePrefix: PRODUCT_ID`), `mobile/src/api/client.ts` (`createApiClient` + `getToken`) |
| **Platform clients** | `mobile/src/lib/platform.ts` — telemetry init + `trackEvent`, feature flags, kill switch, `blobClient`, diagnostics singleton |
| **Stores + API modules** | `auth-store`, `notes-store`, `workspace-store`, `inbox-store`; `mobile/src/api/notes.ts`, `workspaces.ts`, `note-agent-actions.ts` |
| **Offline queue (module)** | `mobile/src/lib/offline-queue.ts` exports `noteOfflineQueue`**UI/store wiring is still partial** (see capture screen copy) |
| **Tabs + detail** | `(tabs)/` index, search, capture, inbox; `mobile/src/app/note/[id].tsx` |
| **Tests** | Vitest on stores (`*.test.ts`); no `@testing-library/react-native` in `mobile/package.json` today |
---
## 2 — Execution order (mandatory)
```
Block A → Auth flow + session UX (register, refresh, guarded entry)
Block B → Kill switch gate + safe degraded UI
Block C → Broadcast + survey (web parity)
Block D → Profile / settings + feedback-client
Block E → Offline queue: enqueue + flush on boot / resume
Block F → Blob / attachments (capture or note detail) via shared blobClient
Block G → Code health (telemetry versions, a11y, dead code)
Block H → RNTL + smoke screen tests
Block I → Optional — @bytelyst/sync or deeper sync (last; needs API contract review)
```
---
## Block A — Auth flow and session UX
### A.1 Goals
- **Signed-in users** should not be forced through `/auth` on every cold start — `index` should redirect to `/(tabs)` when `useAuthStore` / `getAuthClient()` is authenticated (after `bootstrap` resolves).
- Add **register** (and optional forgot-password) paths aligned with backend + web, or document why mobile is sign-in only.
- Ensure **token refresh** behavior matches `@bytelyst/auth-client` expectations (no silent 401 loops on `getApiClient()`).
### A.2 Files to read first
- `mobile/src/app/index.tsx`, `mobile/src/app/auth.tsx`, `mobile/src/app/_layout.tsx`
- `mobile/src/store/auth-store.ts`, `mobile/src/api/auth.ts`, `mobile/src/api/config.ts`
- Web reference: `web/src/lib/auth.ts`, auth pages under `web/src/app/(auth)/`
### A.3 Optional (platform SDK parity)
If the team standardizes on **`@bytelyst/react-native-platform-sdk`**: either integrate **`AuthProvider`** with the **same MMKV keys** as `createAuthClient({ storagePrefix: PRODUCT_ID })`, or document a minimal bridge (same approach as NomGap Block A in `learning_ai_fastgap`).
### A.4 Done criteria
- [x] Cold start: authed → tabs; unauthed → auth
- [x] `cd mobile && pnpm run typecheck && pnpm test`
- [x] Update **Current State** / any new checklist rows in [`AGENT_TASK_ROADMAP.md`](./AGENT_TASK_ROADMAP.md)
- [x] Commit: [`ae0a481`](https://github.com/saravanakumardb1/learning_ai_notes/commit/ae0a481) — `feat(mobile): complete block A auth session flow`
---
## Block B — Kill switch gate
### B.1 Goal
Mirror web `middleware` / layout behavior: when **`checkKillSwitch()`** reports disabled, block main app UI and show message (reuse pattern from `web` or NomGap `KillSwitchGate`).
### B.2 Files
- `mobile/src/lib/platform.ts` (`checkKillSwitch`)
- `mobile/src/app/_layout.tsx` or a small `KillSwitchGate` wrapper component
### B.3 Done criteria
- [x] Manual test with kill switch on/off (or mocked)
- [x] Update [`AGENT_TASK_ROADMAP.md`](./AGENT_TASK_ROADMAP.md)
- [x] Commit: [`acdedbc`](https://github.com/saravanakumardb1/learning_ai_notes/commit/acdedbc) — `feat(mobile): add kill switch gate in root layout`
---
## Block C — Broadcast + survey (web parity)
### C.1 Goal
Integrate **`@bytelyst/broadcast-client`** and **`@bytelyst/survey-client`** in the root layout (banner + modal), matching API usage from web (see `web` app layout and `@bytelyst/broadcast-client` / `@bytelyst/survey-client` exports).
### C.2 Files
- Add deps to `mobile/package.json` if missing
- `mobile/src/app/_layout.tsx` + new thin components under `mobile/src/components/` as needed
- Reference: `web/src/app/(app)/layout.tsx` (or wherever BroadcastBanner / SurveyBanner live)
### C.3 Done criteria
- [x] No duplicate/wrong client API (align with current package exports)
- [x] Update [`AGENT_TASK_ROADMAP.md`](./AGENT_TASK_ROADMAP.md)
- [x] Commit: [`48896ab`](https://github.com/saravanakumardb1/learning_ai_notes/commit/48896ab) — `feat(mobile): integrate broadcast and survey clients`
---
## Block D — Settings / profile + feedback
### D.1 Goal
Add **`@bytelyst/feedback-client`** from mobile — same payload shape as web (`submit({ type, title, body })` or current API).
### D.2 Files
- New screen or tab entry: e.g. `mobile/src/app/settings.tsx` or profile section on a tab
- `mobile/package.json` if adding `feedback-client`
### D.3 Done criteria
- [x] Graceful offline / error handling
- [x] Update [`AGENT_TASK_ROADMAP.md`](./AGENT_TASK_ROADMAP.md)
- [x] Commit: [`746cba7`](https://github.com/saravanakumardb1/learning_ai_notes/commit/746cba7) — `feat(mobile): add settings tab with feedback client`
---
## Block E — Offline queue wiring
### E.1 Goal
`noteOfflineQueue` exists but capture screen still says wiring is deferred. **Enqueue** failed note mutations; **flush** on app start and on connectivity / `AppState` active (match web offline-queue behavior).
### E.2 Files
- `mobile/src/lib/offline-queue.ts`
- `mobile/src/store/notes-store.ts` (and any create/update paths)
- `mobile/src/app/(tabs)/capture.tsx`
### E.3 Done criteria
- [x] Airplane-mode manual test: queue → reconnect → drain
- [x] Update [`AGENT_TASK_ROADMAP.md`](./AGENT_TASK_ROADMAP.md)
- [x] Commit: [`5d82160`](https://github.com/saravanakumardb1/learning_ai_notes/commit/5d82160) — `feat(mobile): wire offline queue enqueue and flush`
---
## Block F — Blob / attachments
### F.1 Goal
Any mobile upload path (future file capture, artifacts) should use **`blobClient`** from `mobile/src/lib/platform.ts` — no second SAS or raw `fetch` duplicate.
### F.2 Files
- `mobile/src/lib/platform.ts` (`blobClient`)
- Future: note detail or capture file picker
### F.3 Done criteria
- [ ] Single upload abstraction; E2E or manual upload test
- [ ] Update [`AGENT_TASK_ROADMAP.md`](./AGENT_TASK_ROADMAP.md)
- [ ] Commit: `feat(mobile): blob uploads via shared blobClient` (or `refactor` if replacing duplicate code)
---
## Block G — Code health
Execute in **flexible order**; prefer **small commits**.
| Task | Hints |
|------|--------|
| **Telemetry metadata** | Use `expo-constants` for `appVersion` / `buildNumber` instead of hardcoded strings in `platform.ts` |
| **Feature flags in UI** | Gate experimental mobile surfaces with `isFeatureEnabled` where web uses flags |
| **Accessibility** | `accessibilityLabel` on tab icons and primary actions |
| **Theme** | Prefer shared tokens from `@bytelyst/design-tokens` / `theme/` consistently |
**Done criteria**
- [x] Runtime telemetry/client metadata uses `expo-constants` + platform metadata helpers
- [x] Accessibility labels added on tabs and primary action buttons
- [x] Typecheck/tests pass and changes reflected in [`AGENT_TASK_ROADMAP.md`](./AGENT_TASK_ROADMAP.md)
- [x] Commit: [`e4683ad`](https://github.com/saravanakumardb1/learning_ai_notes/commit/e4683ad) — `fix(mobile): complete block G metadata and accessibility`
---
## Block H — RNTL + smoke tests
### H.1 Infrastructure
- [x] Add **`@testing-library/react-native`** + **`@types/react-test-renderer`** to `mobile` `devDependencies`
- [x] Extend `mobile/vitest.config.ts` with resolve aliases for RN / Expo / RNTL mocks
- [x] Create `mobile/__mocks__/` with mocks for `react-native`, `expo-router`, `expo-constants`, `expo-status-bar`, `react-native-mmkv`, `@testing-library/react-native`
### H.2 Minimum tests
- [x] **Auth screen** — import smoke test (valid component, named export, no redirect when unauthenticated)
- [x] **Home tab screen** — import smoke test (valid component, named export)
### H.3 Done criteria
- [x] `cd mobile && pnpm run typecheck && pnpm test` — 32 tests pass (27 store + 5 component)
- [x] Update [`AGENT_TASK_ROADMAP.md`](./AGENT_TASK_ROADMAP.md)
- [x] Commit: [`5a0175f`](https://github.com/saravanakumardb1/learning_ai_notes/commit/5a0175f) — `feat(mobile): add Block H — Vitest RN mock aliases + component smoke tests`
> **TODO-1:** Deeper RNTL render tests (text assertions, fireEvent) require `react-test-renderer` to produce non-null output for mocked RN host components in Node. Current smoke tests verify import + `isValidElement` instead. A future iteration could add `jsdom` environment + `@testing-library/react` as an alternative rendering path for full DOM-based assertions.
---
## Block I — Optional sync engine (`@bytelyst/sync`)
**Last.** Mobile currently hydrates via **REST + Zustand**. Replacing with **`@bytelyst/sync`** requires mapping entities (notes, workspaces, inbox) to backend contracts and conflict rules — verify with backend before swapping.
### I.1 Done criteria (only if attempted)
- [ ] Parity with current hydration + offline behavior
- [ ] Update [`AGENT_TASK_ROADMAP.md`](./AGENT_TASK_ROADMAP.md)
- [ ] Commit: `feat(mobile): adopt @bytelyst/sync` (large; may split)
---
## 3 — After every block
1. `cd mobile && pnpm run typecheck`
2. `cd mobile && pnpm test`
3. Sync **[`AGENT_TASK_ROADMAP.md`](./AGENT_TASK_ROADMAP.md)**
4. Commit with a clear message; push to remote
5. If block descriptions drift, update **this file** in the same PR
---
## 4 — Reference paths
| Area | Path |
|------|------|
| Root layout | `mobile/src/app/_layout.tsx` |
| Auth | `mobile/src/app/auth.tsx`, `mobile/src/store/auth-store.ts` |
| Platform init | `mobile/src/lib/platform.ts` |
| API | `mobile/src/api/client.ts`, `mobile/src/api/config.ts` |
| Workspace definition | `pnpm-workspace.yaml` |
---
## Post-Completion Audit (March 31, 2026)
Systematic review of all completed blocks (AH) identified and fixed:
- **`feedback-client.ts`** — null coercion on `getAuthToken` (commit `9d3ac06`)
- **`offline-queue.ts`** — missing `Content-Type: application/json` header on flush
- **`settings.tsx`** — hardcoded `platform: 'ios'` → dynamic `APP_PLATFORM`
- **`notes-store.ts` / `inbox-store.ts`** — `isLoading` stuck true on API failure (commit `c96c785`)
- **`_layout.tsx`** — stale `lastFlushed` banner when queue already empty (commit `a412494`)
- **All screens** — missing `accessibilityLabel` on interactive elements (commit `83f4953`)
- **Backend** — `trackEvent` call signature mismatch + route test `delete` mock (commit `6acd1a7`)
**Remaining:** Block F (blob uploads) and Block I (sync engine) are deferred/optional.
---
**End of delegation roadmap.** Point your agent at: **`docs/MOBILE_DELEGATION_ROADMAP.md`**.