An easy-to-host PDS on the ATProtocol, MacOS. Grandma-approved.

docs(MM-143): add apps/identity-wallet/CLAUDE.md with iOS developer setup

authored by malpercio.dev and committed by

Tangled 00d27722 b845958c

+123
+123
apps/identity-wallet/CLAUDE.md
··· 1 + # Identity Wallet Mobile App 2 + 3 + Last verified: 2026-03-14 4 + 5 + ## Purpose 6 + 7 + Tauri v2 iOS application — SvelteKit 2 + Svelte 5 frontend running in a native WKWebView, communicating with a Rust backend exclusively through Tauri's IPC bridge. First frontend code in the repository. 8 + 9 + ## Contracts 10 + 11 + ### Frontend (SvelteKit 2 + Svelte 5) 12 + 13 + **Exposes:** 14 + - `src/lib/ipc.ts` — typed wrappers for all Tauri IPC commands; import these instead of calling `invoke()` directly 15 + - `src/routes/+page.svelte` — root page (Greet IPC demo) 16 + 17 + **Guarantees:** 18 + - SSR is disabled globally (`ssr = false` in `src/routes/+layout.ts`); the frontend is a fully static SPA loaded from disk by WKWebView 19 + - Build output lands in `dist/` (configured via `out: 'dist'` in `svelte.config.js`) 20 + - Frontend calls Tauri commands only through `src/lib/ipc.ts` — no raw `invoke()` calls in page components 21 + 22 + **Expects:** 23 + - `pnpm install` has been run in `apps/identity-wallet/` 24 + - Node.js 22.x is in PATH (provided by the Nix dev shell) 25 + 26 + ### Rust Backend (src-tauri/) 27 + 28 + **Exposes:** 29 + - `src/lib.rs::greet(name: String) -> String` — registered Tauri IPC command callable from the frontend via `invoke('greet', { name })` 30 + 31 + **Guarantees:** 32 + - `crate-type = ["staticlib", "cdylib", "rlib"]` supports iOS (staticlib), Android (cdylib), and normal cargo builds (rlib) 33 + - `src/main.rs` is the desktop entry point; `src/lib.rs::run()` is the iOS/Android entry point (via `#[cfg_attr(mobile, tauri::mobile_entry_point)]`) 34 + - `tauri.conf.json` configures the bundle identifier, dev URL (`http://localhost:5173`), and frontend dist path (`../dist`) 35 + 36 + **Expects:** 37 + - `tauri.conf.json` exists in `src-tauri/` before `cargo build` runs — the config is read at compile time by `generate_context!()` 38 + - `cargo-tauri` is in PATH (provided by the Nix dev shell) 39 + - Xcode and iOS Simulator are installed on the developer's macOS machine 40 + 41 + ## Dependencies 42 + 43 + - Frontend → Rust backend (via Tauri IPC — `@tauri-apps/api/core` `invoke()`) 44 + - Rust backend → Cargo workspace (inherits `version`, `edition`, `publish` from root `Cargo.toml`) 45 + - `src-tauri/gen/` → NOT tracked in git; generated per-developer by `cargo tauri ios init` (gitignored) 46 + 47 + ## Prerequisites (macOS/iOS Development) 48 + 49 + 1. **macOS Ventura (13) or later** 50 + 51 + 2. **Xcode** (latest stable, from App Store) 52 + - After installing, open Xcode.app once to accept the license agreement — failing to do this causes `cargo tauri ios dev` to fail silently 53 + - Install the iOS Simulator platform: Xcode → Settings → Platforms → iOS 54 + 55 + 3. **Cocoapods** — Tauri's iOS build uses it to link native Apple frameworks: 56 + ```bash 57 + sudo gem install cocoapods 58 + ``` 59 + 60 + 4. **Apple Developer account** — optional for Simulator; required for physical device (TestFlight/App Store) builds 61 + 62 + ## First-Time Setup 63 + 64 + After cloning the repo, perform these steps once per developer machine: 65 + 66 + ```bash 67 + # 1. Enter the Nix dev shell (provides cargo-tauri, node 22, pnpm) 68 + nix develop --impure --accept-flake-config 69 + 70 + # 2. Install frontend dependencies 71 + cd apps/identity-wallet 72 + pnpm install 73 + 74 + # 3. Generate the Xcode project (output is in src-tauri/gen/apple/ — gitignored) 75 + cargo tauri ios init 76 + ``` 77 + 78 + Note: `src-tauri/gen/` contains a machine-specific Xcode project. It is gitignored and must be re-generated on each developer machine. Do not commit it. 79 + 80 + ## Development Workflow 81 + 82 + ```bash 83 + # Enter the dev shell if not already active 84 + nix develop --impure --accept-flake-config 85 + 86 + # Launch the app in the iOS Simulator 87 + # This starts pnpm dev + compiles the Rust crate for aarch64-apple-ios-sim + opens the Simulator 88 + cd apps/identity-wallet 89 + cargo tauri ios dev 90 + ``` 91 + 92 + For a non-iOS build (CI or any machine without Xcode): 93 + 94 + ```bash 95 + # From workspace root — builds all workspace crates including src-tauri for the host platform 96 + cargo build 97 + ``` 98 + 99 + ## Key Decisions 100 + 101 + - **`adapter-static` + `ssr = false`**: Tauri WebViews load files from disk — there is no web server. SSR is meaningless and globally disabled. 102 + - **`out: 'dist'` in svelte.config.js**: Matches `tauri.conf.json`'s `frontendDist: "../dist"`. 103 + - **`TAURI_DEV_HOST` for HMR**: Tauri v2 automatically sets this env var to the machine's LAN IP when running `cargo tauri ios dev`. The iOS simulator connects to the Vite dev server over LAN, not localhost. 104 + - **`generate_context!()` is compile-time**: `tauri.conf.json` must exist when `src-tauri/` is compiled — the macro embeds the config at compile time and will fail to compile if the file is missing. 105 + - **`src-tauri/gen/` is gitignored**: The Xcode project generated by `cargo tauri ios init` is machine-specific. Committing it causes merge conflicts and bloats the repo. 106 + - **`tauri` and `tauri-build` declared locally**: These crates are not in `[workspace.dependencies]` because no other workspace crate uses them. `serde` and `serde_json` use `{ workspace = true }` per the standard workspace pattern. 107 + 108 + ## Invariants 109 + 110 + - `src/lib/ipc.ts` is the only file that calls `invoke()` directly; page components import from `ipc.ts` 111 + - `tauri.conf.json` bundle identifier `dev.malpercio.identitywallet` must match the iOS provisioning profile for physical device builds 112 + - `src-tauri/gen/` is never committed — regenerate with `cargo tauri ios init` 113 + - `pnpm-lock.yaml` is committed and kept in sync with `package.json` 114 + 115 + ## Key Files 116 + 117 + - `src-tauri/tauri.conf.json` — Tauri config: bundle ID, devUrl, frontendDist, window settings 118 + - `src-tauri/src/lib.rs` — Tauri IPC commands and `run()` (mobile entry point) 119 + - `src-tauri/src/main.rs` — Desktop entry point (calls `lib::run()`) 120 + - `src/lib/ipc.ts` — Typed TypeScript wrappers for all Tauri IPC commands 121 + - `src/routes/+layout.ts` — `ssr = false; prerender = false` (global SPA config) 122 + - `svelte.config.js` — adapter-static with `out: 'dist'` (SPA mode, matches tauri.conf.json) 123 + - `vite.config.ts` — Tauri-compatible Vite server (clearScreen, HMR via TAURI_DEV_HOST, envPrefix)