| 1 | --- |
| 2 | name: sigit-app |
| 3 | description: Use when working on the "siGit Code & Deploy" Tauri desktop app (repo ~/Repositories/sigit-app), especially account management — login, signup, email verification, password reset, me, logout, remove account — and keeping account feature parity with the sigit-si web app. Covers the src-tauri account command set, the AccountStatus/ErrorResponse contract, token storage, the settings/account React views, and the decision about whether the app talks to smbCloud Auth directly or through sigit.si/api/v1. |
| 4 | --- |
| 5 | |
| 6 | # siGit Code & Deploy desktop app (sigit-app) |
| 7 | |
| 8 | > **Product map:** siGit Code (local agent) · siGit Code Cloud (hosted chat + Cloud Sessions) · siGit Code Cloud Agent (autonomous task → PR; planning). `sigit.si` is Git hosting; `code.sigit.si` is the home of siGit Code. Full taxonomy: [product-overview](../../../docs/product/product-overview.md). |
| 9 | |
| 10 | `sigit-app` is the **Tauri desktop client** for siGit (repo |
| 11 | `~/Repositories/sigit-app`). It is a **public client** (a shipped binary), so the |
| 12 | public-client security rules apply — see |
| 13 | `smbcloud-cli/.agents/skills/smbcloud-auth/SKILL.md`. This file is the |
| 14 | sigit-app-specific view; keep its account features at **parity with the sigit-si |
| 15 | web account page** (`sigit-si/.agents/skills/smbcloud-auth/SKILL.md`). |
| 16 | |
| 17 | ## Account command set |
| 18 | |
| 19 | Rust commands in `src-tauri/src/account/` (registered in `mod.rs`), each a |
| 20 | `#[tauri::command]`: |
| 21 | |
| 22 | - `command_login` → `login(app, env, username, password)` |
| 23 | - `command_signup` → `signup(...)` |
| 24 | - `command_me` → `me(...)` |
| 25 | - `command_logout` → `logout(...)` |
| 26 | - `command_remove_account` → `remove_account(app, env, client, access_token)` |
| 27 | - `command_resend_confirmation_email` |
| 28 | - `command_reset_password` |
| 29 | - `command_resend_reset_password_instructiont` (note: existing misspelled name — |
| 30 | match it exactly when wiring the frontend; don't "fix" it without renaming the |
| 31 | invoke call sites too) |
| 32 | - `command_check_email_oauth` |
| 33 | |
| 34 | ### Current data flow |
| 35 | |
| 36 | Today the commands call the **Rust auth SDK directly**, not an HTTP API: |
| 37 | |
| 38 | ``` |
| 39 | smbcloud_auth::login::login(env, client(), username, password) |
| 40 | smbcloud_model::{ error_codes::{ErrorCode, ErrorResponse}, login::AccountStatus } |
| 41 | smbcloud_network::environment::Environment // Dev | Production |
| 42 | ``` |
| 43 | |
| 44 | - success returns `AccountStatus`; on `AccountStatus::Ready { access_token }` the |
| 45 | token is persisted via `crate::store::store_token` |
| 46 | - preserve the `AccountStatus` contract end to end: |
| 47 | `NotFound` · `Ready { access_token }` · `Incomplete { status }` |
| 48 | - failures return `ErrorResponse::Error { error_code, message }` |
| 49 | (`ErrorCode` from `smbcloud_model`) |
| 50 | - `env: Environment` is passed from the frontend (`useEnvironment().current`) |
| 51 | |
| 52 | ## Frontend |
| 53 | |
| 54 | `src/components/sidebar/settings/`: |
| 55 | |
| 56 | - `account.tsx` — signed-in view: email, **Anthropic API key** field (stored |
| 57 | locally on-device via `get_setting`/`update_setting`, used by the Claude ACP |
| 58 | agent — not an auth credential), Logout, Remove Account |
| 59 | - `login-form.tsx`, `signup.tsx`, `verify-email-form.tsx`, |
| 60 | `set-password-form.tsx`, `logged-out-view.tsx`, `debug-setting-view.tsx` |
| 61 | |
| 62 | Frontend calls Rust via `invoke("<command>", { env, accessToken, ... })`. The |
| 63 | env switch is gated through `useEnvironment`; keep production/dev switching behind |
| 64 | debug controls. |
| 65 | |
| 66 | ## Integration decision: direct SDK vs sigit.si/api/v1 |
| 67 | |
| 68 | The current architecture is **app → Rust SDK → smbCloud Auth**. The active goal |
| 69 | is to route desktop auth through **`sigit.si/api/v1`** instead (app → sigit.si → |
| 70 | smbCloud Auth). Before implementing, settle this explicitly: |
| 71 | |
| 72 | - **Direct SDK (status quo):** fewer hops, but the desktop binary needs smbCloud |
| 73 | app credentials and bypasses sigit-si entirely. |
| 74 | - **Via sigit.si/api/v1 (goal):** sigit-si becomes the trust boundary, holds the |
| 75 | confidential `app_secret` server-side, and the desktop app only ever sees a |
| 76 | bearer token. Better for the public-client rule; requires building the JSON API |
| 77 | in sigit-si first (see the sigit-si smbcloud-auth skill). |
| 78 | |
| 79 | If switching to the API path, change the command bodies to call |
| 80 | `sigit.si/api/v1/*` and keep the **same** `AccountStatus` / `ErrorResponse` |
| 81 | shapes so the frontend and token storage are unaffected. |
| 82 | |
| 83 | ## Git operations (repos) |
| 84 | |
| 85 | Git uses **Smart HTTP with token auth — no SSH.** Live commands in |
| 86 | `src-tauri/src/repos/` (registered in `lib.rs`): |
| 87 | |
| 88 | - `clone_repo` · `publish_repo` · `push_repo` / `pull_repo` · `list_repos` |
| 89 | |
| 90 | Two-token flow — **never use the account access token as a git credential**: |
| 91 | |
| 92 | 1. login → **account access token** persisted via `crate::store::store_token` |
| 93 | 2. `repos::api::fetch_git_token(env, access_token)` POSTs `sigit.si` → |
| 94 | `git_credentials` (bearer = access token) → returns a **short-lived scoped |
| 95 | `git_token`** |
| 96 | 3. git2 credential callback authenticates over HTTPS via HTTP Basic: |
| 97 | `Cred::userpass_plaintext("x-access-token", git_token)` — username is the |
| 98 | literal string `x-access-token`, password is the scoped git token |
| 99 | 4. `repos::api::create_remote_repo` POSTs `repos` (bearer = access token) to |
| 100 | create the bare repo before first publish |
| 101 | |
| 102 | This is in-process libgit2 (`git2` / `gix`, vendored) over HTTPS — no subprocess, |
| 103 | no key files — so it works inside the **sandboxed App Store build** and the |
| 104 | container-stored-repo model. |
| 105 | |
| 106 | ### Legacy SSH path (deprecated — do not extend) |
| 107 | |
| 108 | `src/_git/{clone_project,desktop_deploy}.rs`, |
| 109 | `src/project/command_clone_frontend_app.rs`, and |
| 110 | `src/ssh/command_generate_ssh_key.rs` still use `Cred::ssh_key` and remain |
| 111 | registered (`clone_project`, `clone_frontend_app`, `ssh_clone`, |
| 112 | `generate_ssh_key`), but SSH-based git is **no longer the model** — new work uses |
| 113 | the Smart HTTP path above. `desktop_deploy.rs` also hardcodes |
| 114 | `/Users/setoelkahfi/.ssh/...`, which is dead in any non-author or sandboxed |
| 115 | build. Candidates for removal, not extension. |
| 116 | |
| 117 | ## Validation |
| 118 | |
| 119 | - `cargo check` in `src-tauri` |
| 120 | - `pnpm build` (or the app's package script) when the frontend changed |
| 121 | - exercise login → verify email → me → logout → remove against the dev environment |
| 122 | - confirm token storage and session restore (`me`) still work |
| 123 | |
| 124 | ## Common mistakes |
| 125 | |
| 126 | - Breaking the `AccountStatus` contract the frontend depends on |
| 127 | - Renaming a command without updating its `invoke(...)` call sites (esp. the |
| 128 | misspelled `..._instructiont`) |
| 129 | - Treating the Anthropic API key field as an auth credential — it is local-only |
| 130 | - Shipping smbCloud `app_secret` in the binary and assuming it is confidential |
| 131 | - Diverging account features from the sigit-si web account page |
| 132 | - Reaching for SSH credentials / `generate_ssh_key` for git auth — the live path |
| 133 | is Smart HTTP over HTTPS (`repos::*`), not `Cred::ssh_key` |
| 134 | - Using the account access token directly as the git credential — always |
| 135 | exchange it for a short-lived scoped `git_token` via `fetch_git_token` first |