mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-16 19:29:26 +02:00
docs(mobile): establish independence rules and tech-stack baseline
- Refactor root CLAUDE.md sharing rules into a single Sharing Principles section, replacing scattered mentions across 10 places with one source of truth + minimal "(web + desktop)" qualifiers on existing sections - Add apps/mobile/CLAUDE.md with locked tech-stack baseline: Expo SDK 54, React Native 0.81, NativeWind 4 + Tailwind 3.4, react-native-reusables, TanStack Query 5, Zustand, expo-secure-store - Mobile pins React directly (does NOT track root catalog:) so the Expo SDK / RN release schedule isn't blocked by web/desktop upgrades - Visual tokens are mobile-owned (transcribed from packages/ui/styles/ tokens.css by hand, not imported); Tailwind v3.4 vs v4 mismatch makes file sharing impractical anyway - Document mobile build/release pipeline (main CI excludes mobile, separate mobile-verify and mobile-release workflows, EAS Update for OTA) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
38
CLAUDE.md
38
CLAUDE.md
@@ -32,11 +32,14 @@ Multica is an AI-native task management platform — like Linear, but with AI ag
|
||||
- `server/` — Go backend (Chi router, sqlc for DB, gorilla/websocket for real-time)
|
||||
- `apps/web/` — Next.js frontend (App Router)
|
||||
- `apps/desktop/` — Electron desktop app (electron-vite)
|
||||
- `packages/core/` — Headless business logic (zero react-dom, all-platform reuse)
|
||||
- `apps/mobile/` — Expo / React Native iOS app. See `apps/mobile/CLAUDE.md`.
|
||||
- `packages/core/` — Headless business logic (zero react-dom)
|
||||
- `packages/ui/` — Atomic UI components (zero business logic)
|
||||
- `packages/views/` — Shared business pages/components (zero next/* imports, zero react-router imports)
|
||||
- `packages/tsconfig/` — Shared TypeScript configuration
|
||||
|
||||
What lives where for sharing purposes is documented in *Sharing Principles* below — read it once.
|
||||
|
||||
### Key Architectural Decisions
|
||||
|
||||
**Internal Packages pattern** — all shared packages export raw `.ts`/`.tsx` files (no pre-compilation). The consuming app's bundler compiles them directly. This gives zero-config HMR and instant go-to-definition.
|
||||
@@ -52,7 +55,7 @@ Multica is an AI-native task management platform — like Linear, but with AI ag
|
||||
The architecture relies on a strict split between server state and client state. Mixing them is the most common way to break it.
|
||||
|
||||
- **TanStack Query owns all server state.** Issues, users, workspaces, inbox — anything fetched from the API lives in the Query cache. WS events keep it fresh via invalidation; no polling, no `staleTime` workarounds.
|
||||
- **Zustand owns all client state.** UI selections, filters, drafts, modal state, navigation history. Stores live in `packages/core/` (never in `packages/views/`) so both apps share them.
|
||||
- **Zustand owns all client state.** UI selections, filters, drafts, modal state, navigation history. Stores live in `packages/core/` (never in `packages/views/`) so they're shared.
|
||||
- **React Context** is reserved for cross-cutting platform plumbing — `WorkspaceIdProvider`, `NavigationProvider`. Don't reach for it for general state.
|
||||
- **Auth and workspace stores are the only stores allowed to call `api.*` directly**, because they manage critical state that must exist before queries can run. They're created via factory + injected dependencies, registered by the platform layer.
|
||||
|
||||
@@ -69,6 +72,17 @@ The architecture relies on a strict split between server state and client state.
|
||||
- Selectors must return stable references. Returning a freshly built object or array on every call (e.g. `s => ({ a: s.a, b: s.b })` or `s => s.items.map(...)`) triggers infinite re-renders. Either select primitives separately or use shallow comparison.
|
||||
- Hooks that need workspace context should accept `wsId` as a parameter, not call `useWorkspaceId()` internally — this lets them work outside the `WorkspaceIdProvider` (e.g. in a sidebar that renders before workspace is loaded).
|
||||
|
||||
## Sharing Principles
|
||||
|
||||
The monorepo splits into two share zones:
|
||||
|
||||
- **Web and desktop** share business logic, components, hooks, stores, and views through `packages/core/`, `packages/ui/`, and `packages/views/`. Existing model — keep using it.
|
||||
- **Mobile (`apps/mobile/`) is independent.** It shares only **types and pure functions** from `@multica/core/`, with `import type` for types (zero runtime coupling). UI, state, hooks, providers, i18n, React version, build pipeline, release cadence — all mobile-owned.
|
||||
|
||||
Mobile is locked to the React version that Expo SDK / React Native ships (which lags React main by 6-12 months). Coupling mobile to the root `catalog:` React would block mobile from upgrading on its own schedule.
|
||||
|
||||
See `apps/mobile/CLAUDE.md` for the mobile rules and tech-stack baseline.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
@@ -183,17 +197,17 @@ When adding a `Queries.Delete*` or `Queries.Update*` call, ask: "Where did this
|
||||
|
||||
These are hard constraints. Violating them breaks the cross-platform architecture:
|
||||
|
||||
- `packages/core/` — zero react-dom, zero localStorage (use StorageAdapter), zero process.env, zero UI libraries. **All shared Zustand stores live here**, even view-related ones (filters, view modes) — stores are pure state, not UI.
|
||||
- `packages/core/` — zero react-dom, zero localStorage (use StorageAdapter), zero process.env, zero UI libraries. **Shared Zustand stores live here**, even view-related ones (filters, view modes) — stores are pure state, not UI.
|
||||
- `packages/ui/` — zero `@multica/core` imports (pure UI, no business logic).
|
||||
- `packages/views/` — zero `next/*` imports, zero `react-router-dom` imports, zero stores. Use `NavigationAdapter` for all routing.
|
||||
- `apps/web/platform/` — the only place for Next.js APIs (`next/navigation`).
|
||||
- `apps/desktop/src/renderer/src/platform/` — the only place for react-router-dom navigation wiring.
|
||||
|
||||
### The No-Duplication Rule
|
||||
### The No-Duplication Rule (web + desktop)
|
||||
|
||||
**If the same logic exists in both apps, it must be extracted to a shared package.**
|
||||
**If the same logic exists in both web and desktop, it must be extracted to a shared package.**
|
||||
|
||||
This applies to everything: components, hooks, guards, providers, utility functions. The decision process:
|
||||
This applies to everything between web and desktop: components, hooks, guards, providers, utility functions. The decision process:
|
||||
|
||||
1. Does this code depend on Next.js or Electron APIs? → Keep in the respective app.
|
||||
2. Does it depend on `react-router-dom` or `next/navigation`? → Keep in app's `platform/` layer.
|
||||
@@ -201,9 +215,9 @@ This applies to everything: components, hooks, guards, providers, utility functi
|
||||
|
||||
When the two apps need different behavior for the same concept (e.g., different loading UI), extract the shared logic into a component with props/slots for the differences. Don't duplicate the logic.
|
||||
|
||||
### Cross-Platform Development Rules
|
||||
### Cross-Platform Development Rules (web + desktop)
|
||||
|
||||
When adding a new page or feature:
|
||||
When adding a new page or feature for web/desktop:
|
||||
|
||||
1. **New page component** → add to `packages/views/<domain>/`. Never import from `next/*` or `react-router-dom`.
|
||||
2. **Wire it in both apps** → add a route in `apps/web/app/` (Next.js page file) AND in the desktop router. **Exception**: pre-workspace transition flows (create workspace, accept invite) are NOT routes on desktop — they're `WindowOverlay` state. See *Desktop-specific Rules → Route categories*.
|
||||
@@ -212,14 +226,18 @@ When adding a new page or feature:
|
||||
5. **Platform-specific UI** → if a feature is web-only or desktop-only, keep it in the respective app. Use props slots (`extra`, `topSlot`) on shared layout components to inject platform-specific UI.
|
||||
6. **New hooks that need workspace context** → accept `wsId` as parameter instead of reading from `useWorkspaceId()` Context, so they work both inside and outside `WorkspaceIdProvider`.
|
||||
|
||||
### CSS Architecture
|
||||
### CSS Architecture (web + desktop)
|
||||
|
||||
Both apps share the same CSS foundation from `packages/ui/styles/`.
|
||||
Web and desktop share the same CSS foundation from `packages/ui/styles/`.
|
||||
|
||||
- **Design tokens** → use semantic tokens (`bg-background`, `text-muted-foreground`). Never use hardcoded Tailwind colors (`text-red-500`, `bg-gray-100`).
|
||||
- **Shared styles** → `packages/ui/styles/`. Never duplicate scrollbar styling, keyframes, or base layer rules in app CSS.
|
||||
- **`@source` directives** → both apps scan shared packages so Tailwind sees all class names.
|
||||
|
||||
## Mobile-specific Rules
|
||||
|
||||
Rules for `apps/mobile/` live in `apps/mobile/CLAUDE.md`. Read it before touching anything in `apps/mobile/` — it covers what may be imported from `@multica/core/`, the React version policy, the build/release pipeline, and the locked tech-stack baseline.
|
||||
|
||||
## Desktop-specific Rules
|
||||
|
||||
These rules apply to `apps/desktop/` only. Web has different constraints (URL bar, SSR, no tabs) and doesn't share these concerns. Every rule in this section was added after a concrete bug — treat them as enforced, not suggestions.
|
||||
|
||||
42
apps/mobile/CLAUDE.md
Normal file
42
apps/mobile/CLAUDE.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Mobile App Rules (apps/mobile/)
|
||||
|
||||
For cross-app sharing rules, see the root `CLAUDE.md` *Sharing Principles* section. This file documents the locked tech-stack baseline and the few mobile-specific rules — so AI doesn't suggest outdated alternatives.
|
||||
|
||||
## What mobile may import from `packages/`
|
||||
|
||||
- `import type` from `@multica/core/types/*` (zero runtime coupling)
|
||||
- Pure functions from `@multica/core/`
|
||||
|
||||
Everything else, mobile writes its own.
|
||||
|
||||
## Tech-stack baseline (locked)
|
||||
|
||||
Start minimal. Add to this list when actually adopted — do NOT pre-list libraries.
|
||||
|
||||
- **Expo SDK 54**
|
||||
- **React Native 0.81**
|
||||
- **React 19.x** — whatever Expo SDK 54 ships. Pinned in `apps/mobile/package.json` directly, NOT via root `catalog:`.
|
||||
- **TypeScript** strict
|
||||
- **Expo Router 6** — file-based routing
|
||||
- **NativeWind 4** + **Tailwind 3.4** — NativeWind 5 is unstable and doesn't support Expo Go; stay on v4. (Note: web/desktop use Tailwind v4 — versions intentionally differ.)
|
||||
- **react-native-reusables (RNR)** — the shadcn equivalent for React Native. Uses NativeWind + RN-Primitives + CVA. Component API mirrors shadcn.
|
||||
- **TanStack Query 5** — mobile owns its `QueryClient` with `AppState` focus listener + `NetInfo` online listener.
|
||||
- **Zustand** — mobile-local state only.
|
||||
- **expo-secure-store** — auth token persistence.
|
||||
|
||||
When upgrading any of these, update this list.
|
||||
|
||||
## Visual tokens (separate from web)
|
||||
|
||||
Mobile maintains its own design tokens in `apps/mobile/tailwind.config.js`. You MAY reference `packages/ui/styles/tokens.css` (web/desktop tokens) as inspiration, but **do not import or symlink the file**. Tokens are transcribed by hand and may diverge for mobile (touch-friendly spacing, no hover states, native typography).
|
||||
|
||||
Tailwind version mismatch (mobile v3.4 vs web v4) makes file sharing impractical anyway — this isolation is intentional.
|
||||
|
||||
## Build & release
|
||||
|
||||
- **Main CI** (`.github/workflows/ci.yml`) excludes mobile via `--filter='!@multica/mobile'`. Mobile failures do NOT block web/desktop PRs.
|
||||
- **Mobile verify** (`.github/workflows/mobile-verify.yml`): triggered on `apps/mobile/**` or `packages/core/types/**` changes — runs typecheck/lint/test only, no IPA build.
|
||||
- **Mobile release** (`.github/workflows/mobile-release.yml`): triggered by `mobile-v*.*.*` tag → `eas build` + `eas submit`.
|
||||
- **OTA** — EAS Update for JS-only fixes that don't change the runtime version. Manual / on-demand push to preview/production channels.
|
||||
|
||||
Mobile release cadence is decoupled from main `v*.*.*` tags (server / CLI / desktop).
|
||||
Reference in New Issue
Block a user