Files
ChatApp/docs/superpowers/specs/2026-05-13-mobile-phase-0-foundation-design.md
T
byGalax 5f753412a6 docs(mobile): roadmap + phase-0 deployment foundation design
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) <noreply@anthropic.com>
2026-05-13 23:27:52 +02:00

9.5 KiB
Raw Blame History

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 13).
  • 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:

{
  "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:

{
  "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 <Stack> in <SafeAreaProvider> from react-native-safe-area-context. Add <GestureHandlerRootView style={{ flex: 1 }}> outside it so future gesture-based UI is unblocked. Wrap everything in a top-level <ErrorBoundary> (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:

// 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 <cmd> 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.