From 5f753412a68b5032d4c2dc4e35bbd1703b9fc3e2 Mon Sep 17 00:00:00 2001 From: byGalax Date: Wed, 13 May 2026 23:27:52 +0200 Subject: [PATCH] docs(mobile): roadmap + phase-0 deployment foundation design MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mobile shipping is decomposed into 5 phases: 0. Deployment Foundation — Netralax brand on a runnable dev build. 1. Auth + Chat MVP — magic-link login, conversation list, text send. 2. Messaging Features — attachments, voice messages, reactions. 3. Voice/Video Calls — LiveKit RN + CallKit/ConnectionService. 4. Polish + Store Submission — TestFlight, Play, signing. Phase 0 spec lays out the concrete file changes: * app.json rename to Netralax + cloud.netralax.app bundle/package. * New eas.json with development/preview/production profiles. * SafeAreaProvider + GestureHandlerRootView + ErrorBoundary in the root layout, Netralax landing screen with runtime app version. * sharedSmoke.ts runtime import to verify Metro can resolve @chat-app/shared (which already has CryptoBackend/SecretStore interfaces designed for mobile adapters). * README quickstart for `eas init` + first dev client build. No code changes here — just the planning surface. Implementation plan follows. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-05-13-mobile-deployment-roadmap.md | 91 +++++++++ ...-05-13-mobile-phase-0-foundation-design.md | 187 ++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-13-mobile-deployment-roadmap.md create mode 100644 docs/superpowers/specs/2026-05-13-mobile-phase-0-foundation-design.md diff --git a/docs/superpowers/specs/2026-05-13-mobile-deployment-roadmap.md b/docs/superpowers/specs/2026-05-13-mobile-deployment-roadmap.md new file mode 100644 index 0000000..8276122 --- /dev/null +++ b/docs/superpowers/specs/2026-05-13-mobile-deployment-roadmap.md @@ -0,0 +1,91 @@ +# Mobile Deployment Roadmap + +**Date:** 2026-05-13 +**Scope:** `apps/mobile` end-to-end ship to iOS App Store + Google Play +**Status:** Decomposition — each phase ships independently with its own spec. + +--- + +## Where we are today + +- `apps/mobile` is an Expo + React Native scaffold from the very first commit (`f7cfd2a initial`). It has the right deps (`expo-router`, `react-native-libsodium`, `expo-secure-store`, `expo-sqlite`, `expo-notifications`) but no real screens — just two placeholders ("ChatApp" landing, "Chats — placeholder"). +- Earlier mobile work (image attachments, voice messages, voice calls, reactions, profile editing, push wiring) lives on the archived `byGalax/chat-app` GitHub repo. It targets a pre-Tauri→Electron `packages/shared` API and is not directly portable; we treat it as reference material, not a merge source. +- `packages/shared` is platform-agnostic by design (`CryptoBackend` and `SecretStore` interfaces wait for mobile adapters), so the desktop's business logic is reusable verbatim once we plug in RN-flavoured implementations. +- The desktop reached `v0.17.5` with a Netralax rebrand, Discord-style call/chat UX, and an EAS-free electron-builder/electron-updater release pipeline pointed at `update.netralax.cloud`. + +## Goal + +Ship the Netralax mobile app to iOS App Store + Google Play with the core Discord-style chat + voice/video calls of the desktop, working over the same self-hosted Supabase + LiveKit backend. + +## Decomposition + +Five phases, each with its own design spec, plan, and ship gate. We brainstorm and execute one at a time; later phases only get fleshed out once their prerequisites land. + +### Phase 0 — Deployment Foundation +**Spec:** `2026-05-13-mobile-phase-0-foundation-design.md` +**Goal:** prove the pipeline. After Phase 0, `eas build` (or `expo run`) produces a runnable Netralax-branded shell on a real iPhone + Android device. No features yet — but every later phase ships through this same build pipeline. + +### Phase 1 — Auth + Chat MVP +**Why next:** smallest end-to-end vertical slice that's actually useful. Users can log in, see conversations, send/receive text. +- Mobile `CryptoBackend` adapter wrapping `react-native-libsodium`. +- Mobile `SecretStore` adapter wrapping `expo-secure-store`. +- Magic-link auth + device-key registration (reuse `packages/shared/auth`). +- Conversation list (DM + group) with last-message preview. +- Conversation view: decrypt + render text messages, send text. +- Push notifications via `expo-notifications` + the existing `notify-push` edge function. +- Minimal profile + logout. + +### Phase 2 — Messaging Features +**Why next:** mobile users expect parity with desktop on day-to-day messaging. +- Image attachments (camera roll + camera capture). +- File attachments (document picker). +- Voice messages (record + play). +- Reactions, edit, delete, reply, forward. +- Read receipts + delivery state. +- Typing indicator. +- Polls (optional / stretch). + +### Phase 3 — Voice/Video Calls +**Why now and not Phase 1:** RN LiveKit + native call UX (CallKit / ConnectionService) is the heaviest single feature. Hard to scope without the basic chat working first, and not blocking for an early TestFlight. +- LiveKit React Native SDK (`@livekit/react-native` + `@livekit/react-native-webrtc`). +- Incoming call notifications wake the app via CallKit (iOS) + ConnectionService (Android). +- Outgoing call flow. +- Voice + video tracks, mute/hangup, speaker/earpiece switch, headset routing. +- Screen sharing is explicitly out of scope on mobile. + +### Phase 4 — Polish + Store Submission +**Why last:** can't submit until the features are in. +- Privacy policy + Terms surfaced inside the app. +- Store-listing assets: screenshots, descriptions, age rating. +- Code signing: Apple Developer Program enrolment + provisioning, Android upload keystore. +- TestFlight internal + external testing. +- Google Play internal track → closed test → production. + +## Cross-cutting decisions (locked in here, no per-phase relitigation) + +| Topic | Decision | Rationale | +|---|---|---| +| Framework | Expo + React Native (existing scaffold) | Already set up; New Architecture enabled; managed-workflow gives EAS Build out of the box | +| Branding | Netralax everywhere | Matches the desktop rebrand released as v0.17.x | +| Bundle / package id | `cloud.netralax.app` (both iOS + Android) | Matches the desktop's AppUserModelId `cloud.netralax.desktop`; `com.meinname.chatapp` is dev-placeholder | +| Shared business logic | Consume `@chat-app/shared` verbatim | Designed for this; the only mobile-specific pieces are the `CryptoBackend` + `SecretStore` adapters | +| Old chat-app mobile sprints | Reference, do not merge | API drift since pre-Electron; cleaner to rewrite against current shared | +| Backend | Self-hosted Supabase at `update.netralax.cloud` + LiveKit | Unchanged from desktop | +| Push delivery | Expo Push Service for development; native APNS + FCM after EAS submit | Avoids managing certs in Phase 1 | +| State management | React local state + tiny context, same as desktop | Avoid Redux/Zustand bloat for a chat app | +| Persistent local store | `expo-sqlite` (already in deps) | Mirror desktop's better-sqlite3 schema | + +## Ship gates between phases + +A phase only ends — and the next one begins — when: +1. Manual verification of every spec'd flow passes on **both** an iOS device and an Android device. +2. The previous phase's release build still runs (no regression). +3. The phase's spec is reflected in the codebase (no straggling TODOs that were in scope). + +## Out of scope for the entire roadmap + +- Web build of the mobile app (Expo can technically emit one — not worth the bundle-cost double-duty since the Electron app already covers desktop). +- macOS / Windows React Native targets. +- Watch / TV / wearable apps. +- iPad-specific UI tuning beyond `"supportsTablet": true` (we ship the phone UI on tablet for now). +- Resurrecting any code from the archived `chat-app` mobile sprints. diff --git a/docs/superpowers/specs/2026-05-13-mobile-phase-0-foundation-design.md b/docs/superpowers/specs/2026-05-13-mobile-phase-0-foundation-design.md new file mode 100644 index 0000000..959638a --- /dev/null +++ b/docs/superpowers/specs/2026-05-13-mobile-phase-0-foundation-design.md @@ -0,0 +1,187 @@ +# Mobile Phase 0 — Deployment Foundation + +**Date:** 2026-05-13 +**Scope:** `apps/mobile` +**Roadmap context:** `2026-05-13-mobile-deployment-roadmap.md` + +--- + +## Problem + +We can't even smoke-test a Netralax-branded build on a real device today. The Expo scaffold says "ChatApp" everywhere, the EAS project ID is a literal string `REPLACE_WITH_EAS_PROJECT_ID`, and the iOS bundle id / Android package id is the placeholder `com.meinname.chatapp`. Every later phase ships through this build pipeline, so it needs to work end-to-end before we touch features. + +## Goal + +After Phase 0, a developer (or the user) can run a single command from the repo root and get an installable `.ipa` or `.apk` carrying the Netralax brand. No real features — just a launch screen that renders, plus the harness underneath: SafeArea, navigation root, error boundary, the `@chat-app/shared` package compiling and importable from the mobile app, version readout, EAS config. + +## Non-goals + +- Auth, chat, calls, push wiring (Phases 1–3). +- App Store / Play Store submission (Phase 4). +- Resurrecting the legacy mobile sprints from the archived `chat-app` repo. +- Code-signing certificates / provisioning profiles. Phase 0 produces development-signed builds via EAS managed credentials; production signing is Phase 4. + +## Design + +### 1. Branding rename in `apps/mobile/app.json` + +Replace every `ChatApp`/`com.meinname.chatapp` reference with the Netralax brand. Final values: + +```json +{ + "expo": { + "name": "Netralax", + "slug": "netralax", + "scheme": "netralax", + "version": "0.1.0", + "ios": { + "bundleIdentifier": "cloud.netralax.app", + "supportsTablet": true, + "infoPlist": { "ITSAppUsesNonExemptEncryption": false } + }, + "android": { + "package": "cloud.netralax.app", + "adaptiveIcon": { + "foregroundImage": "./assets/adaptive-icon.png", + "backgroundColor": "#0b0b0f" + } + }, + "extra": { "eas": { "projectId": "REPLACE_WITH_EAS_PROJECT_ID" } } + } +} +``` + +`extra.eas.projectId` stays as the placeholder string in source — the user runs `eas init` once locally, which fills it in and commits. Documented in the mobile README. + +### 2. App icon + splash + +Replace `assets/icon.png`, `assets/adaptive-icon.png`, `assets/splash.png` with placeholder Netralax variants (purple-on-dark `N` mark matching the sidebar avatar in the desktop). A single 1024×1024 master plus the 1024-Android-foreground and 1284×2778 splash is enough for Phase 0. Final art lives in `apps/mobile/assets/`. + +### 3. EAS configuration + +Create `apps/mobile/eas.json`: + +```json +{ + "cli": { "version": ">= 13.0.0" }, + "build": { + "development": { + "developmentClient": true, + "distribution": "internal", + "ios": { "simulator": true }, + "android": { "buildType": "apk" } + }, + "preview": { + "distribution": "internal", + "ios": { "simulator": false }, + "android": { "buildType": "apk" } + }, + "production": { + "ios": { "simulator": false }, + "android": { "buildType": "app-bundle" } + } + }, + "submit": { + "production": { + "ios": { "appleId": "REPLACE_WITH_APPLE_ID", "ascAppId": "REPLACE_WITH_ASC_APP_ID" }, + "android": { "serviceAccountKeyPath": "./play-service-account.json" } + } + } +} +``` + +`production`-submit credentials stay as placeholders — Phase 4 fills them in. The `development` profile produces a custom dev client + APK that can be installed and used with `expo start --dev-client`. + +### 4. Minimal app shell that doesn't crash + +Four changes to verify the runtime is healthy: + +- `app/_layout.tsx`: wrap the `` in `` from `react-native-safe-area-context`. Add `` outside it so future gesture-based UI is unblocked. Wrap everything in a top-level `` (new component, §4a) so an unhandled render error shows a readable fallback instead of a white-screen crash on a TestFlight build. +- `app/index.tsx`: render "Netralax" (not "ChatApp"), display the app version read from `expo-application` (`Application.nativeApplicationVersion`), and link to `/(app)/chats` via a placeholder button so navigation is proved. +- `app/(app)/chats.tsx`: same — render "Netralax — Chats coming soon" so the protected-stack mounts cleanly. + +#### 4a. Error boundary + +`apps/mobile/components/ErrorBoundary.tsx` is a small React class component that catches render errors and shows the error message + a "Reload" button. Same shape as the desktop's crash-recovery surface. Around 40 lines. + +### 5. Shared package smoke import + +Phase 0's gate is that `import { CryptoBackend } from '@chat-app/shared'` resolves and the Metro bundler doesn't choke on the shared package's exports. We don't *use* the import — just type it so a compile failure surfaces here, not later. + +Concretely: add `apps/mobile/lib/sharedSmoke.ts` that pulls a **runtime** value (not a type-only import — type imports are erased by the TS compiler and never reach Metro). `@chat-app/shared` re-exports its modules as namespaces (`crypto`, `auth`, `chat`, `friends`, `rtc`, `supabase`, `i18n`, `admin`), so we go through one of those: + +```ts +// Force-imports a runtime symbol from @chat-app/shared so Metro +// actually resolves the package on app boot. A type-only import would +// be erased and never surface a packaging problem. This file goes away +// once Phase 1's real crypto adapter lands and registers the backend +// for real. +import { crypto } from '@chat-app/shared'; + +// Pull the function into a runtime reference so the bundle keeps the +// import. Calling it without a backend would throw, so we just retain +// the reference. +export const sharedSmoke = { register: crypto.setCryptoBackend }; +``` + +Imported from `_layout.tsx` once, value unused. Phase 1 removes it. + +### 6. README + scripts + +`apps/mobile/README.md` gets a "Phase 0 quickstart" section that walks through `eas init` + the first development build + installing the dev client on a device. + +Root `package.json` gets convenience scripts only if they're missing: `mobile:dev`, `mobile:ios`, `mobile:android`, `mobile:typecheck` — all `pnpm --filter @chat-app/mobile ` wrappers. + +### 7. Typecheck + lint plumbing + +Verify `pnpm --filter @chat-app/mobile typecheck` already runs (the mobile `package.json` already declares it). If `eslint` is wired similarly, add it to a CI workflow stub — but actual CI integration is out of scope here. + +## File structure (after Phase 0) + +``` +apps/mobile/ +├── app/ +│ ├── _layout.tsx ← MODIFIED: SafeArea, GestureHandler, providers shell +│ ├── index.tsx ← MODIFIED: Netralax landing with version + nav link +│ └── (app)/ +│ ├── _layout.tsx ← unchanged +│ └── chats.tsx ← MODIFIED: "coming soon" placeholder text +├── assets/ +│ ├── icon.png ← REPLACED: Netralax 1024×1024 +│ ├── adaptive-icon.png ← REPLACED: foreground for Android adaptive +│ └── splash.png ← REPLACED: Netralax splash +├── lib/ +│ └── sharedSmoke.ts ← NEW: temporary import-canary +├── app.json ← MODIFIED: Netralax branding, ids +├── eas.json ← NEW: build profiles +├── package.json ← unchanged (deps stay) +└── README.md ← MODIFIED: Phase 0 quickstart +``` + +## Risks + +- **`react-native-libsodium` + New Architecture (Fabric / TurboModules).** `newArchEnabled: true` is in `app.json`. The library claims support, but past RN libsodium ports broke around the JSI migration. If the dev client crashes on require, fall back to disabling new arch in Phase 0 and re-enable in Phase 1 once the adapter is wired and tested. +- **`@chat-app/shared` Node-only paths.** The package was authored against Node + browser; the supabase client uses `fetch` and `WebSocket` which RN polyfills. If any export pulls `node:crypto` directly the Metro resolver may fail. The smoke import (§5) is the canary for this. +- **EAS account access.** `eas init` requires an Expo account. The user owns it; we treat the project ID slot as an external input. +- **Apple Developer enrolment.** Phase 0 builds for iOS need an Apple ID; EAS can generate dev certs automatically the first time `eas build --platform ios` runs against the user's Apple ID. No paid enrolment needed for the development profile (free signing). + +## Verification (run before declaring Phase 0 done) + +1. `pnpm --filter @chat-app/mobile typecheck` → exit 0. +2. `pnpm --filter @chat-app/mobile dev` (`expo start --dev-client` once a dev client is installed) → app boots on a real iPhone *and* a real Android device. +3. Landing screen shows "Netralax" + a non-empty version string read at runtime. +4. Tapping the placeholder nav link routes into `/(app)/chats` without crash. +5. `eas build --platform android --profile development` produces an APK that installs and launches on a physical Android device. +6. `eas build --platform ios --profile development` produces a `.tar.gz` (simulator build) **OR** an `.ipa` (device build, if free signing succeeded). +7. Optional: visual check that the icon + splash render as Netralax (not Expo's default) on both platforms. + +If any of those fail, Phase 0 isn't done — fix in this phase rather than rolling it into Phase 1. + +## Out of scope + +- Push notification token registration (Phase 1). +- Linking to the Supabase URL / env-var injection (Phase 1). +- Local SQLite schema (Phase 1). +- Any screen beyond Landing + Chats-coming-soon. +- Reanimated / gesture-based animations. +- Dark / light mode polish — system default is fine.