···11+# Identity Wallet Mobile App
22+33+Last verified: 2026-03-14
44+55+## Purpose
66+77+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.
88+99+## Contracts
1010+1111+### Frontend (SvelteKit 2 + Svelte 5)
1212+1313+**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)
1616+1717+**Guarantees:**
1818+- SSR is disabled globally (`ssr = false` in `src/routes/+layout.ts`); the frontend is a fully static SPA loaded from disk by WKWebView
1919+- Build output lands in `dist/` (configured via `out: 'dist'` in `svelte.config.js`)
2020+- Frontend calls Tauri commands only through `src/lib/ipc.ts` — no raw `invoke()` calls in page components
2121+2222+**Expects:**
2323+- `pnpm install` has been run in `apps/identity-wallet/`
2424+- Node.js 22.x is in PATH (provided by the Nix dev shell)
2525+2626+### Rust Backend (src-tauri/)
2727+2828+**Exposes:**
2929+- `src/lib.rs::greet(name: String) -> String` — registered Tauri IPC command callable from the frontend via `invoke('greet', { name })`
3030+3131+**Guarantees:**
3232+- `crate-type = ["staticlib", "cdylib", "rlib"]` supports iOS (staticlib), Android (cdylib), and normal cargo builds (rlib)
3333+- `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)]`)
3434+- `tauri.conf.json` configures the bundle identifier, dev URL (`http://localhost:5173`), and frontend dist path (`../dist`)
3535+3636+**Expects:**
3737+- `tauri.conf.json` exists in `src-tauri/` before `cargo build` runs — the config is read at compile time by `generate_context!()`
3838+- `cargo-tauri` is in PATH (provided by the Nix dev shell)
3939+- Xcode and iOS Simulator are installed on the developer's macOS machine
4040+4141+## Dependencies
4242+4343+- 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)
4646+4747+## Prerequisites (macOS/iOS Development)
4848+4949+1. **macOS Ventura (13) or later**
5050+5151+2. **Xcode** (latest stable, from App Store)
5252+ - After installing, open Xcode.app once to accept the license agreement — failing to do this causes `cargo tauri ios dev` to fail silently
5353+ - Install the iOS Simulator platform: Xcode → Settings → Platforms → iOS
5454+5555+3. **Cocoapods** — Tauri's iOS build uses it to link native Apple frameworks:
5656+ ```bash
5757+ sudo gem install cocoapods
5858+ ```
5959+6060+4. **Apple Developer account** — optional for Simulator; required for physical device (TestFlight/App Store) builds
6161+6262+## First-Time Setup
6363+6464+After cloning the repo, perform these steps once per developer machine:
6565+6666+```bash
6767+# 1. Enter the Nix dev shell (provides cargo-tauri, node 22, pnpm)
6868+nix develop --impure --accept-flake-config
6969+7070+# 2. Install frontend dependencies
7171+cd apps/identity-wallet
7272+pnpm install
7373+7474+# 3. Generate the Xcode project (output is in src-tauri/gen/apple/ — gitignored)
7575+cargo tauri ios init
7676+```
7777+7878+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.
7979+8080+## Development Workflow
8181+8282+```bash
8383+# Enter the dev shell if not already active
8484+nix develop --impure --accept-flake-config
8585+8686+# Launch the app in the iOS Simulator
8787+# This starts pnpm dev + compiles the Rust crate for aarch64-apple-ios-sim + opens the Simulator
8888+cd apps/identity-wallet
8989+cargo tauri ios dev
9090+```
9191+9292+For a non-iOS build (CI or any machine without Xcode):
9393+9494+```bash
9595+# From workspace root — builds all workspace crates including src-tauri for the host platform
9696+cargo build
9797+```
9898+9999+## Key Decisions
100100+101101+- **`adapter-static` + `ssr = false`**: Tauri WebViews load files from disk — there is no web server. SSR is meaningless and globally disabled.
102102+- **`out: 'dist'` in svelte.config.js**: Matches `tauri.conf.json`'s `frontendDist: "../dist"`.
103103+- **`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.
104104+- **`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.
105105+- **`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.
106106+- **`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.
107107+108108+## Invariants
109109+110110+- `src/lib/ipc.ts` is the only file that calls `invoke()` directly; page components import from `ipc.ts`
111111+- `tauri.conf.json` bundle identifier `dev.malpercio.identitywallet` must match the iOS provisioning profile for physical device builds
112112+- `src-tauri/gen/` is never committed — regenerate with `cargo tauri ios init`
113113+- `pnpm-lock.yaml` is committed and kept in sync with `package.json`
114114+115115+## Key Files
116116+117117+- `src-tauri/tauri.conf.json` — Tauri config: bundle ID, devUrl, frontendDist, window settings
118118+- `src-tauri/src/lib.rs` — Tauri IPC commands and `run()` (mobile entry point)
119119+- `src-tauri/src/main.rs` — Desktop entry point (calls `lib::run()`)
120120+- `src/lib/ipc.ts` — Typed TypeScript wrappers for all Tauri IPC commands
121121+- `src/routes/+layout.ts` — `ssr = false; prerender = false` (global SPA config)
122122+- `svelte.config.js` — adapter-static with `out: 'dist'` (SPA mode, matches tauri.conf.json)
123123+- `vite.config.ts` — Tauri-compatible Vite server (clearScreen, HMR via TAURI_DEV_HOST, envPrefix)