# UI ↔ backend contract The Svelte UI (`src/`) talks to the Rust backend (`src-tauri/`) only through the Tauri commands and events below. `src/lib/backend.ts` is the single place that calls them. When the page runs outside Tauri (a plain browser, for design work), it falls back to a mock with the same shapes. All names are snake_case on the wire (serde defaults), and timestamps are Unix seconds. ## Types ```ts type Phase = | "idle" // nothing running | "checking" // probing the site | "signing_in" // browser sign-in in progress | "installing" // downloading + verifying a version | "restoring" // loading the database snapshot into local Postgres | "launching" // starting Postgres → API → tile server → Odian.exe | "running" // Odian.exe is open | "error"; // the last long operation failed; see `error` interface Status { online: boolean; // the site's update service answered /v1/health site: { url: string; name: string | null }; operator: string | null; // last signed-in ODIAN username (cached; valid offline) signed_in: boolean; // this PC remembers the operator's site sign-in until Sign out: the // launcher renews the short Engine token by itself (launcher session) installed: string | null; // installed version, e.g. "0.51.0" available: string | null; // the site's CURRENT version (online only) update_required: boolean; // online && installed !== null && available !== null && installed !== available // (never true when nothing is installed: that is a first install) can_launch: boolean; // installed && !update_required && phase is idle or error phase: Phase; error: string | null; // set with phase "error"; cleared by the next command or `refresh` install_dir: string; // e.g. "D:\\ODIAN" } interface Settings { site_url: string; // e.g. "http://192.168.1.41:30097" mcp_url: string; // site MCP, for Keycloak sign-in install_dir: string; } interface InstallProgress { stage: "manifest" | "app" | "db" | "src" | "tiles" | "restore" | "finalize"; stage_index: number; // 1-based stage_count: number; done_bytes: number; // within the current stage total_bytes: number; // of the current stage; 0 when unknown done_items: number; // within the current stage total_items: number; bytes_per_sec: number; message: string | null; // e.g. "tiles dark/protomaps_20260423: 412/1402 blocks" } interface StackEvent { component: "postgres" | "api" | "tiles" | "odian"; state: "starting" | "ready" | "stopped" | "failed"; message: string | null; } interface LogEvent { level: "info" | "warn" | "error"; message: string; at: number } ``` ## Commands (`invoke`) | Command | Args | Returns | Notes | |---|---|---|---| | `get_status` | — | `Status` | cheap; no network | | `refresh` | — | `Status` | re-probes the site (2 s timeout); also clears an `error` phase | | `sign_in` | — | `{ username: string }` | opens the system browser (MCP desktop flow) and waits for the loopback callback. Rejects with "Sign-in was cancelled." after `cancel_sign_in` (phase returns to idle, not error). | | `cancel_sign_in` | — | `void` | abandons a sign-in that is waiting for the browser | | `sign_out` | — | `Status` | forgets the operator on this PC: the site sign-in, its launcher session (ended on the site when reachable) and the cached operator. **Offline launch needs a new sign-in afterwards**, so the UI confirms first | | `get_notes` | `{ version?: string }` | `string` | Markdown. From the site when online; the cached copy of the installed version offline. **Untrusted: the UI must sanitize.** | | `open_external` | `{ url: string }` | `void` | opens an `http`/`https` link in the system browser (links in patch notes); anything else is refused | | `start_install` | — | `void` | installs or updates to `available`; needs `signed_in` (the site checks the token); progress arrives as events | | `start_install_from_drive` | `{ path: string }` | `void` | same, reading an ODIAN drive (SSD) instead of the site; no sign-in needed | | `cancel_install` | — | `void` | stops at the next file boundary; everything already verified is kept | | `launch` | — | `void` | starts the local stack; `stack` events follow | | `stop` | — | `void` | stops Odian.exe's stack cleanly | | `get_stack` | — | `StackEvent[]` | the latest event per component of the current or last launch (for a reloaded UI) | | `get_settings` | — | `Settings` | | | `set_settings` | `{ settings: Settings }` | `Status` | | | `pick_folder` | — | `string \| null` | native folder picker | Errors reject the promise with a string message. Planned, not yet available: the size of `available` for the Install button, and inspecting a drive (its version and size) before installing from it. ## Events (`listen`) | Event | Payload | When | |---|---|---| | `status` | `Status` | whenever any field changes | | `install-progress` | `InstallProgress` | at most ~10 per second while installing | | `stack` | `StackEvent` | on each component state change | | `log` | `LogEvent` | notable backend messages, for the activity panel |