Epic: Native Android app (chat_android) mirroring Hesychia web #111

Open
opened 2026-08-04 12:07:16 -07:00 by westfarn · 0 comments
Owner

Goal

Spike + plan a true native Android Hesychia client in a new repo chat_android (org: ai_ml_operations), feature-parity with chat_web_app / llm-fe, while reusing chat_backend APIs.

This epic lives here because product/UX/API contracts and the existing Capacitor shell are owned by chat_web_app. Implementation work for the native app lands in chat_android once that repo exists.

Current state (do not ignore)

Layer Today
Mobile ship path Capacitor 7 WebView wrapping CRA build/ (llm-fe/android/, app id ai.hesychia.chat) — see ANDROID.md / #20
Auth JWT REST + OAuth redirect flows; native SSO redirects still weak
Chat REST + WebSocket (REACT_APP_BACKEND_*)
Billing (web) Stripe Checkout + Customer Portal
Billing (Capacitor native) RevenueCat via @revenuecat/purchases-capacitorMONETIZATION.md, #100
UI React + MUI 5 + Emotion; tokens in llm-fe/src/llm-fe/ui-kit/assets/theme/ (palettes, colors, typography, breakpoints)

Decision to force early: keep Capacitor as interim Play track vs migrate users to a native APK/AAB under the same (or new) application id. Package-name / Play listing continuity matters for IAP and reviews.

Why native (vs Capacitor)

Capture explicit rationale so we do not rebuild for fashion:

  • Performance / streaming UX gaps in WebView (keyboard, scroll, markdown, charts)
  • Play Billing / IAP reliability or store policy friction with WebView
  • Native navigation, notifications, file/document pickers, offline
  • Long-term cost of dual Capacitor + web vs one Compose client + web

Proposed repo: chat_android

Create under ai_ml_operations:

  • Kotlin + Jetpack Compose + Material 3 (preferred default unless spike says otherwise)
  • Min/target SDK aligned with current Capacitor shell (min 23 / target 35) unless product bumps
  • Same backend base URLs / env flavours as .env.mobile / beta / prod
  • CI: unit tests + debug APK (and later signed AAB) on Gitea Actions
  • Secrets: upload keystore outside repo (same pattern as llm-fe/android/keystore.properties)

Out of scope for v1 unless justified: iOS twin (separate epic), full offline-first sync.


Workstream A — Discovery & architecture

  • Inventory screens / flows to mirror (from App.tsx routes + key components):
    • Sign in / sign up / password reset / SSO callback
    • Chat (conversations list, detail, streaming messages, citations, actions)
    • Account (usage, billing, theme prefs, delete account)
    • Document storage / drive connections (if still product-required on mobile)
    • Legal / account-deletion public URL expectations for Play (#103)
    • Analytics consent + Tianji parity (or deliberate mobile subset)
  • Map every FE call to chat_backend REST + WS contracts; note gaps (pagination, error shapes, auth headers)
  • Choose architecture: single-module vs feature modules; networking (OkHttp/Ktor); WS client; DI (Hilt); navigation
  • Decide app id / Play track strategy vs existing Capacitor ai.hesychia.chat
  • Write ADR in chat_android (or linked doc) covering Capacitor sunset / coexistence

Exit: architecture note + screen inventory + open questions list.


Workstream B — Visual parity / design system

Goal: Hesychia should feel like the same product, not a generic Material template.

  • Extract design tokens from web theme into a shareable format (JSON/YAML or Style Dictionary):
    • Color palettes (ui-kit/assets/theme/base/palettes.js, colors.js)
    • Typography scale / font families (license + Android font packaging)
    • Spacing, radii, elevation/shadows, dark/light + theme-color variants
    • Brand assets (hesychia-mark, icons, splash) — reuse llm-fe/assets/
  • Implement Compose HesychiaTheme (Material 3 color scheme + typography) from those tokens
  • Define parity bar: pixel-perfect vs recognizable brand (recommend: brand + layout rhythm parity; allow native platform patterns for nav/keyboard)
  • Side-by-side QA checklist (light/dark, primary palette variants) for: Sign-in, Chat compose, Account/Billing
  • Optional later: keep tokens in a tiny shared package or published artifact both web and Android consume

Risk: MUI component look ≠ Compose Material 3 defaults. Tokens alone are not enough — need component-level mapping (buttons, cards, drawers, message bubbles).

Exit: token file + Compose theme + screenshot comparison for 3 core screens.


Workstream C — Auth & session

  • JWT storage (EncryptedSharedPreferences / DataStore) parity with web token helpers
  • Email/password sign-in + sign-up against existing endpoints
  • Password reset deep links / Custom Tabs
  • Google / Microsoft SSO: Chrome Custom Tabs or App Auth; register redirect URIs with IdPs + chat_backend
  • Session restore, 401 handling, logout (incl. RevenueCat logOut when IAP wired)

Exit: authenticated user can open chat and survive process death.


Workstream D — Chat parity

  • Conversation list + create/select
  • Message history pagination / scroll
  • WebSocket connect / reconnect / background lifecycle (learn from WebSocketContext + #23)
  • Streaming partial tokens UI
  • Markdown / code blocks / citations rendering strategy (native libs vs WebView islands — decide deliberately)
  • Message actions parity where product still needs them

Exit: end-to-end chat on emulator + physical device matching web happy path.


Workstream E — In-app purchases (required)

Native Play must not use Stripe Checkout for digital subscriptions (Play policy). Align with existing RevenueCat path.

  • Integrate RevenueCat Android SDK (or Play Billing Library direct — prefer RC for parity with Capacitor + backend webhooks)
  • Same appUserID rules as MONETIZATION.md (Django user pk string)
  • Offerings / packages mapped to plan slugs (founders, etc.) — share product ids with Capacitor RC dashboard
  • Purchase, restore, entitlement refresh → hit /monetization/... APIs same as web BillingSection
  • UI: native Billing section (subscribe / restore / manage); no Stripe portal for Play-store subs; show provider badge (revenuecat + PLAY_STORE)
  • Sign-up path: after account create, trigger store purchase (mirror Capacitor SignUp / AuthCallback behaviour)
  • Backend: confirm RevenueCat webhook → invoice/payment tables already sufficient for Kotlin client; file chat_backend issues if not
  • Play Console: products, base plans, license testers, Data safety, account deletion URL

Exit: internal-test purchase + restore + entitlement visible in Account; web Stripe path unchanged.


Workstream F — Platform & store ops

  • Create chat_android repo + README + local run docs
  • Signing / Play upload pipeline (internal testing first)
  • Versioning policy (versionCode / versionName) vs web package.json
  • Push notifications? (defer unless product requires)
  • Crash reporting / analytics decision (Tianji vs Firebase / none)
  • Plan for Capacitor app: freeze, dual-ship, or replace listing

Workstream G — Cross-repo coordination

Track follow-on issues (create as children when scoped):

Repo Likely needs
chat_android All native implementation
chat_web_app Token export, API contract docs, Capacitor deprecation notes, shared brand assets
chat_backend SSO redirect URIs, any mobile-specific monetization / auth gaps
server-infra Only if new public mobile-specific endpoints / docs hosts

Suggested child issues (cut after discovery)

  1. Spike: Compose vs Flutter vs keep Capacitor — decision record
  2. Create chat_android repo scaffolding (Compose, CI, flavors)
  3. Export design tokens from ui-kit + Compose theme
  4. Auth + JWT session
  5. Chat REST + WebSocket MVP
  6. RevenueCat IAP + Account billing UI
  7. SSO deep links
  8. Play internal testing checklist + store listing
  9. Capacitor coexistence / migration plan

Acceptance criteria (epic done when)

  1. Written decision: proceed / defer native, with cost estimate (eng weeks) and Capacitor fate
  2. If proceed: chat_android exists, builds, signs, and completes auth → chat → IAP purchase/restore on internal testing
  3. Visual parity bar met for core screens (documented screenshots)
  4. Monetization remains consistent with MONETIZATION.md (RC on Play, Stripe on web)
  5. Remaining parity gaps filed as prioritized backlog, not hidden

References

  • llm-fe/ANDROID.md, llm-fe/MONETIZATION.md, llm-fe/android/README.md
  • Capacitor Android epic/context: #20, RevenueCat: #100, account deletion URL: #103
  • Backend: chat_backend
  • Product: Hesychia / hesychia.ai
## Goal Spike + plan a **true native Android** Hesychia client in a **new repo** `chat_android` (org: `ai_ml_operations`), feature-parity with `chat_web_app` / `llm-fe`, while reusing `chat_backend` APIs. This epic lives here because product/UX/API contracts and the existing Capacitor shell are owned by `chat_web_app`. Implementation work for the native app lands in `chat_android` once that repo exists. ## Current state (do not ignore) | Layer | Today | |-------|--------| | Mobile ship path | Capacitor 7 WebView wrapping CRA `build/` (`llm-fe/android/`, app id `ai.hesychia.chat`) — see `ANDROID.md` / `#20` | | Auth | JWT REST + OAuth redirect flows; native SSO redirects still weak | | Chat | REST + WebSocket (`REACT_APP_BACKEND_*`) | | Billing (web) | Stripe Checkout + Customer Portal | | Billing (Capacitor native) | RevenueCat via `@revenuecat/purchases-capacitor` — `MONETIZATION.md`, `#100` | | UI | React + MUI 5 + Emotion; tokens in `llm-fe/src/llm-fe/ui-kit/assets/theme/` (palettes, colors, typography, breakpoints) | **Decision to force early:** keep Capacitor as interim Play track vs migrate users to a native APK/AAB under the same (or new) application id. Package-name / Play listing continuity matters for IAP and reviews. ## Why native (vs Capacitor) Capture explicit rationale so we do not rebuild for fashion: - [ ] Performance / streaming UX gaps in WebView (keyboard, scroll, markdown, charts) - [ ] Play Billing / IAP reliability or store policy friction with WebView - [ ] Native navigation, notifications, file/document pickers, offline - [ ] Long-term cost of dual Capacitor + web vs one Compose client + web ## Proposed repo: `chat_android` Create under `ai_ml_operations`: - Kotlin + Jetpack Compose + Material 3 (preferred default unless spike says otherwise) - Min/target SDK aligned with current Capacitor shell (min 23 / target 35) unless product bumps - Same backend base URLs / env flavours as `.env.mobile` / beta / prod - CI: unit tests + debug APK (and later signed AAB) on Gitea Actions - Secrets: upload keystore **outside** repo (same pattern as `llm-fe/android/keystore.properties`) Out of scope for v1 unless justified: iOS twin (separate epic), full offline-first sync. --- ## Workstream A — Discovery & architecture - [ ] Inventory screens / flows to mirror (from `App.tsx` routes + key components): - Sign in / sign up / password reset / SSO callback - Chat (conversations list, detail, streaming messages, citations, actions) - Account (usage, billing, theme prefs, delete account) - Document storage / drive connections (if still product-required on mobile) - Legal / account-deletion public URL expectations for Play (`#103`) - Analytics consent + Tianji parity (or deliberate mobile subset) - [ ] Map every FE call to `chat_backend` REST + WS contracts; note gaps (pagination, error shapes, auth headers) - [ ] Choose architecture: single-module vs feature modules; networking (OkHttp/Ktor); WS client; DI (Hilt); navigation - [ ] Decide app id / Play track strategy vs existing Capacitor `ai.hesychia.chat` - [ ] Write ADR in `chat_android` (or linked doc) covering Capacitor sunset / coexistence **Exit:** architecture note + screen inventory + open questions list. --- ## Workstream B — Visual parity / design system Goal: Hesychia should feel like the same product, not a generic Material template. - [ ] Extract **design tokens** from web theme into a shareable format (JSON/YAML or Style Dictionary): - Color palettes (`ui-kit/assets/theme/base/palettes.js`, `colors.js`) - Typography scale / font families (license + Android font packaging) - Spacing, radii, elevation/shadows, dark/light + theme-color variants - Brand assets (`hesychia-mark`, icons, splash) — reuse `llm-fe/assets/` - [ ] Implement Compose `HesychiaTheme` (Material 3 color scheme + typography) from those tokens - [ ] Define **parity bar**: pixel-perfect vs recognizable brand (recommend: brand + layout rhythm parity; allow native platform patterns for nav/keyboard) - [ ] Side-by-side QA checklist (light/dark, primary palette variants) for: Sign-in, Chat compose, Account/Billing - [ ] Optional later: keep tokens in a tiny shared package or published artifact both web and Android consume **Risk:** MUI component look ≠ Compose Material 3 defaults. Tokens alone are not enough — need component-level mapping (buttons, cards, drawers, message bubbles). **Exit:** token file + Compose theme + screenshot comparison for 3 core screens. --- ## Workstream C — Auth & session - [ ] JWT storage (EncryptedSharedPreferences / DataStore) parity with web token helpers - [ ] Email/password sign-in + sign-up against existing endpoints - [ ] Password reset deep links / Custom Tabs - [ ] Google / Microsoft SSO: Chrome Custom Tabs or App Auth; register redirect URIs with IdPs + `chat_backend` - [ ] Session restore, 401 handling, logout (incl. RevenueCat logOut when IAP wired) **Exit:** authenticated user can open chat and survive process death. --- ## Workstream D — Chat parity - [ ] Conversation list + create/select - [ ] Message history pagination / scroll - [ ] WebSocket connect / reconnect / background lifecycle (learn from `WebSocketContext` + `#23`) - [ ] Streaming partial tokens UI - [ ] Markdown / code blocks / citations rendering strategy (native libs vs WebView islands — decide deliberately) - [ ] Message actions parity where product still needs them **Exit:** end-to-end chat on emulator + physical device matching web happy path. --- ## Workstream E — In-app purchases (required) Native Play must **not** use Stripe Checkout for digital subscriptions (Play policy). Align with existing RevenueCat path. - [ ] Integrate **RevenueCat Android SDK** (or Play Billing Library direct — prefer RC for parity with Capacitor + backend webhooks) - [ ] Same `appUserID` rules as `MONETIZATION.md` (Django user pk string) - [ ] Offerings / packages mapped to plan slugs (`founders`, etc.) — share product ids with Capacitor RC dashboard - [ ] Purchase, restore, entitlement refresh → hit `/monetization/...` APIs same as web BillingSection - [ ] UI: native Billing section (subscribe / restore / manage); **no** Stripe portal for Play-store subs; show provider badge (`revenuecat` + `PLAY_STORE`) - [ ] Sign-up path: after account create, trigger store purchase (mirror Capacitor SignUp / AuthCallback behaviour) - [ ] Backend: confirm RevenueCat webhook → invoice/payment tables already sufficient for Kotlin client; file `chat_backend` issues if not - [ ] Play Console: products, base plans, license testers, Data safety, account deletion URL **Exit:** internal-test purchase + restore + entitlement visible in Account; web Stripe path unchanged. --- ## Workstream F — Platform & store ops - [ ] Create `chat_android` repo + README + local run docs - [ ] Signing / Play upload pipeline (internal testing first) - [ ] Versioning policy (`versionCode` / `versionName`) vs web `package.json` - [ ] Push notifications? (defer unless product requires) - [ ] Crash reporting / analytics decision (Tianji vs Firebase / none) - [ ] Plan for Capacitor app: freeze, dual-ship, or replace listing --- ## Workstream G — Cross-repo coordination Track follow-on issues (create as children when scoped): | Repo | Likely needs | |------|----------------| | `chat_android` | All native implementation | | `chat_web_app` | Token export, API contract docs, Capacitor deprecation notes, shared brand assets | | `chat_backend` | SSO redirect URIs, any mobile-specific monetization / auth gaps | | `server-infra` | Only if new public mobile-specific endpoints / docs hosts | --- ## Suggested child issues (cut after discovery) 1. Spike: Compose vs Flutter vs keep Capacitor — decision record 2. Create `chat_android` repo scaffolding (Compose, CI, flavors) 3. Export design tokens from `ui-kit` + Compose theme 4. Auth + JWT session 5. Chat REST + WebSocket MVP 6. RevenueCat IAP + Account billing UI 7. SSO deep links 8. Play internal testing checklist + store listing 9. Capacitor coexistence / migration plan --- ## Acceptance criteria (epic done when) 1. Written decision: proceed / defer native, with cost estimate (eng weeks) and Capacitor fate 2. If proceed: `chat_android` exists, builds, signs, and completes **auth → chat → IAP purchase/restore** on internal testing 3. Visual parity bar met for core screens (documented screenshots) 4. Monetization remains consistent with `MONETIZATION.md` (RC on Play, Stripe on web) 5. Remaining parity gaps filed as prioritized backlog, not hidden ## References - `llm-fe/ANDROID.md`, `llm-fe/MONETIZATION.md`, `llm-fe/android/README.md` - Capacitor Android epic/context: `#20`, RevenueCat: `#100`, account deletion URL: `#103` - Backend: `chat_backend` - Product: Hesychia / `hesychia.ai`
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ai_ml_operations/chat_web_app#111