Select the types of activity you want to include in your feed.
docs: update identity-wallet CLAUDE.md for MM-144 onboarding implementation
Reflects new contracts added during the mobile onboarding flow: create_account IPC command, keychain/http modules, onboarding components, and cross-crate crypto dependency.
···12121313**Exposes:**
1414- `src/lib/ipc.ts` — typed wrappers for all Tauri IPC commands; import these instead of calling `invoke()` directly
1515-- `src/routes/+page.svelte` — root page (Greet IPC demo)
1515+- `src/lib/components/onboarding/` — five onboarding screen components (WelcomeScreen, ClaimCodeScreen, EmailScreen, HandleScreen, LoadingScreen)
1616+- `src/routes/+page.svelte` — root page: five-screen onboarding state machine (welcome -> claim_code -> email -> handle -> loading -> did_ceremony)
16171718**Guarantees:**
1819- SSR is disabled globally (`ssr = false` in `src/routes/+layout.ts`); the frontend is a fully static SPA loaded from disk by WKWebView
1920- Build output lands in `dist/` (configured via `pages: 'dist'` in `svelte.config.js`)
2021- Frontend calls Tauri commands only through `src/lib/ipc.ts` — no raw `invoke()` calls in page components
2222+- Relay error codes from `create_account` are mapped back to the originating screen (e.g. EXPIRED_CODE -> claim_code step, EMAIL_TAKEN -> email step)
21232224**Expects:**
2325- `pnpm install` has been run in `apps/identity-wallet/`
···2628### Rust Backend (src-tauri/)
27292830**Exposes:**
2929-- `src/lib.rs::greet(name: String) -> String` — registered Tauri IPC command callable from the frontend via `invoke('greet', { name })`
3131+- `src/lib.rs::greet(name: String) -> String` — Tauri IPC command (demo, still registered)
3232+- `src/lib.rs::create_account(claim_code: String, email: String, handle: String) -> Result<CreateAccountResult, CreateAccountError>` — Tauri IPC command: generates P-256 keypair, stores private key in Keychain, POSTs to relay `/v1/accounts/mobile`, stores tokens in Keychain on success
3333+- `src/keychain.rs` — iOS Keychain abstraction (`store_item`, `get_item`) under service `"ezpds-identity-wallet"`
3434+- `src/http.rs` — `RelayClient` with compile-time base URL (localhost:8080 debug, relay.ezpds.com release)
30353136**Guarantees:**
3237- `crate-type = ["staticlib", "cdylib", "rlib"]` supports iOS (staticlib), Android (cdylib), and normal cargo builds (rlib)
3338- `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)]`)
3439- `tauri.conf.json` configures the bundle identifier, dev URL (`http://localhost:5173`), and frontend dist path (`../dist`)
4040+- `create_account` maps relay HTTP error codes to typed `CreateAccountError` variants (EXPIRED_CODE, REDEEMED_CODE, EMAIL_TAKEN, HANDLE_TAKEN, NETWORK_ERROR, UNKNOWN) serialized as `{ code: "SCREAMING_SNAKE" }` for the frontend
4141+- Private key is stored in Keychain before any network call (fail-safe ordering)
35423643**Expects:**
3744- `tauri.conf.json` exists in `src-tauri/` before `cargo build` runs — the config is read at compile time by `generate_context!()`
3845- `cargo-tauri` is in PATH (provided by the Nix dev shell)
3946- Xcode and iOS Simulator are installed on the developer's macOS machine
4747+- Relay must be running at the compile-time URL for `create_account` to succeed at runtime
40484149## Dependencies
42504343-- Frontend → Rust backend (via Tauri IPC — `@tauri-apps/api/core` `invoke()`)
4444-- Rust backend → Cargo workspace (inherits `version`, `edition`, `publish` from root `Cargo.toml`)
4545-- `src-tauri/gen/` → NOT tracked in git; generated per-developer by `cargo tauri ios init` (gitignored)
5151+- Frontend -> Rust backend (via Tauri IPC -- `@tauri-apps/api/core` `invoke()`)
5252+- Rust backend -> Cargo workspace (inherits `version`, `edition`, `publish` from root `Cargo.toml`)
5353+- Rust backend -> `crates/crypto` (workspace dep: P-256 key generation for `create_account`)
5454+- Rust backend -> relay `/v1/accounts/mobile` endpoint (via `reqwest` HTTP at runtime)
5555+- Rust backend -> iOS Keychain (via `security-framework` crate)
5656+- `src-tauri/gen/` -> NOT tracked in git; generated per-developer by `cargo tauri ios init` (gitignored)
46574758## Prerequisites (macOS/iOS Development)
4859···129140- **`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.
130141- **`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.
131142- **`src-tauri/.cargo/config.toml` committed**: Overrides `CC`, `AR`, and `linker` for iOS and macOS-host targets to use Xcode's unwrapped clang instead of the Nix cc-wrapper. Without this, Nix's clang wrapper injects macOS-specific flags (`-mmacos-version-min`, macOS sysroot) that are incompatible with iOS cross-compilation. See the Troubleshooting section for the full explanation.
143143+- **Compile-time relay URL**: `http.rs` uses `#[cfg(debug_assertions)]` to switch between localhost:8080 (debug) and relay.ezpds.com (release). No runtime configuration needed for the base URL.
144144+- **Keychain-before-network ordering**: `create_account` stores the private key in Keychain before POSTing to the relay -- if the network call fails, the key is already persisted and can be reused on retry.
145145+- **reqwest with rustls-tls**: Uses `default-features = false` + `rustls-tls` to avoid linking OpenSSL. On iOS, rustls handles TLS natively without additional system deps.
132146133147## Invariants
134148135149- `src/lib/ipc.ts` is the only file that calls `invoke()` directly; page components import from `ipc.ts`
136150- `tauri.conf.json` bundle identifier `dev.malpercio.identitywallet` must match the iOS provisioning profile for physical device builds
137137-- `src-tauri/gen/` is never committed — regenerate with `cargo tauri ios init`
151151+- `src-tauri/gen/` is never committed -- regenerate with `cargo tauri ios init`
138152- `pnpm-lock.yaml` is committed and kept in sync with `package.json`
153153+- Keychain service name is always `"ezpds-identity-wallet"` (constant `keychain::SERVICE`); changing it orphans previously stored credentials
154154+- `CreateAccountError` variant names serialize as SCREAMING_SNAKE_CASE to the frontend -- the TypeScript `CreateAccountError.code` union must match exactly
139155140156## Key Files
141157142142-- `src-tauri/tauri.conf.json` — Tauri config: bundle ID, devUrl, frontendDist, window settings
143143-- `src-tauri/src/lib.rs` — Tauri IPC commands and `run()` (mobile entry point)
144144-- `src-tauri/src/main.rs` — Desktop entry point (calls `lib::run()`)
145145-- `src-tauri/.cargo/config.toml` — Cargo toolchain overrides for iOS cross-compilation (CC, AR, linker per target)
146146-- `src/lib/ipc.ts` — Typed TypeScript wrappers for all Tauri IPC commands
147147-- `src/routes/+layout.ts` — `ssr = false; prerender = false` (global SPA config)
148148-- `svelte.config.js` — adapter-static with `pages: 'dist'` (SPA mode, matches tauri.conf.json)
149149-- `vite.config.ts` — Tauri-compatible Vite server (clearScreen, HMR via TAURI_DEV_HOST, envPrefix)
158158+- `src-tauri/tauri.conf.json` -- Tauri config: bundle ID, devUrl, frontendDist, window settings
159159+- `src-tauri/src/lib.rs` -- Tauri IPC commands (`greet`, `create_account`) and `run()` (mobile entry point)
160160+- `src-tauri/src/main.rs` -- Desktop entry point (calls `lib::run()`)
161161+- `src-tauri/src/keychain.rs` -- iOS Keychain abstraction (store_item, get_item)
162162+- `src-tauri/src/http.rs` -- RelayClient with compile-time base URL
163163+- `src-tauri/.cargo/config.toml` -- Cargo toolchain overrides for iOS cross-compilation (CC, AR, linker per target)
164164+- `src/lib/ipc.ts` -- Typed TypeScript wrappers for all Tauri IPC commands (greet, createAccount)
165165+- `src/lib/components/onboarding/` -- Five onboarding screen components
166166+- `src/routes/+page.svelte` -- Onboarding state machine (welcome -> claim_code -> email -> handle -> loading -> did_ceremony)
167167+- `src/routes/+layout.ts` -- `ssr = false; prerender = false` (global SPA config)
168168+- `svelte.config.js` -- adapter-static with `pages: 'dist'` (SPA mode, matches tauri.conf.json)
169169+- `vite.config.ts` -- Tauri-compatible Vite server (clearScreen, HMR via TAURI_DEV_HOST, envPrefix)
150170151171## Troubleshooting
152172