Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/CORE_LOOP_EVAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ upload role R&R → tag people → year-round dossier

| Step | Status | Notes |
|------|--------|--------|
| Encrypted workspace unlock/lock | Done | AES vault; seed password `workbench`; `.session` is token-only (re-unlock after API restart) |
| Encrypted workspace unlock/lock | Done | AES vault; demo seed password `workbench` (demo only — never a silent API default); `.session` is token-only (re-unlock after API restart) |
| Encrypted backup / restore | Done | Settings → one-click snapshot under `data/backups`; restore replaces live DB while unlocked |
| People list + CSV / manual add | Done | `POST /api/people/import` + Team paste/file; template download |
| Role catalog + assign + author | Done | Seeded ladder; Roles page add/edit/delete; CSV/markdown or AI extract from R&R doc |
Expand All @@ -39,7 +39,7 @@ upload role R&R → tag people → year-round dossier
| Promotion packets | Done | Next-role marks + AI case draft |
| Backfill + MCP bulk load | Done | Thin = ach+fb+docs+goals < 2; MCP needs explicit unlock / `PRM_PASSWORD` |
| Settings → AI | Done | Private notes / meeting / document extract egress **enforced** on cloud paths |
| Desktop CSP / launch token / API sidecar | Done | CSP set; shell IPC removed; packaged Node + `prm-api.mjs` spawned by Tauri; CI builds Linux/macOS/Windows on `main` |
| Desktop CSP / launch token / API sidecar | Done | CSP set; shell IPC removed; packaged Node + `prm-api.mjs` spawned by Tauri; desktop installers via Actions **Run workflow** (not every merge) |

## Remaining gaps (honest)

Expand Down
35 changes: 20 additions & 15 deletions docs/DELIVERY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,27 @@ Aligned to [TRUST_MODEL.md](./architecture/TRUST_MODEL.md).

## Phase 0 — Foundations & safety

**Status:** Implemented in-repo (browser+API; Tauri shell compiles).
**Status:** Vertical slice shipped (browser + API; Tauri shell + Node sidecar). Several Phase 0 *targets* remain open — see below.

**Outcome:** Signed-capable app skeleton that can hold real data safely.
**Outcome:** App skeleton that can hold real data safely **when locked**, with honest threat-model docs.

- Tauri + Vite UI + IPC (spike: no naked HTTP API)
- Encrypted SQLite + app-data layout; sync-folder warning
- Single Account; keychain + Linux fallback
- `Person` / EmploymentRecord / manager tree
- CSV import
- ActivityEvent hash chain
- Workspace backup/restore (SQLite backup API)
- Synthetic 12-person seed org (demo + AI fixtures later)
- CI matrix spike on one primary OS, then expand; signing keys process started
- Design-partner outreach (data-handling agreement)
**Shipped**
- Tauri shell + Vite UI + Node Hono API on `127.0.0.1` (launch token in packaged desktop)
- AES-256-GCM seal of SQLite + files on lock; sync-folder hard-warn
- Single Account; workspace-password vault (API keys encrypted with workspace secret — not OS keychain yet)
- `Person` / manager tree + CSV import (requires EM)
- ActivityEvent hash chain + HMAC export
- Encrypted workspace backup/restore
- Synthetic **8-person** demo seed (rolling relative cycle dates)
- CI: unit tests on every `main` PR; desktop installers on manual `workflow_dispatch`

**Exit:** App runs encrypted workspace on at least one OS; backup/restore verified; trust model reflected in UI copy.
**Still open (do not claim done)**
- OS keychain for API keys
- SQLCipher / Rusqlite-primary path
- Signed / notarized installers + auto-update
- IPC-only topology without Node sidecar

**Exit (partial):** App runs encrypted-at-rest workspace on supported OS targets; backup/restore verified; trust model reflected in UI copy. Signing + keychain remain follow-ups.

---

Expand Down Expand Up @@ -111,8 +116,8 @@ docs/
|-------|----------|
| Product mode | Solo EM workbench |
| Collaboration | Import bundles |
| Stack | Tauri + Vite/React + SQLite encrypted |
| Stack | Tauri + Vite/React + SQLite (AES seal on lock) + Node Hono sidecar |
| Upward / live anonymity / adverse impact | Hosted-only |
| next_level_gap | Conditional |
| Local retention | Current + previous cycle (+ export to SoR) |
| AI keys | In-app Settings → keychain |
| AI keys | In-app Settings → encrypted with workspace secret (keychain target) |
44 changes: 23 additions & 21 deletions docs/architecture/LOCAL_STACK.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,39 @@ Primary target: installable app on **Linux, Windows, macOS**. No Docker/Postgres

| Layer | Choice | Notes |
|-------|--------|-------|
| Shell | **Tauri 2** | dmg / msi|NSIS / AppImage|deb |
| Shell | **Tauri 2** | dmg / msi|NSIS / AppImage|deb (manual CI `workflow_dispatch`) |
| UI | **React + TypeScript + Vite** | |
| Backend bridge | **Prefer Tauri IPC commands** for DB/FS/keychain/HTTP; optional thin Hono only if needed | Avoid unauthenticated TCP |
| If HTTP sidecar used | Hono on `127.0.0.1` + **per-launch capability token** + origin checks | Or Unix socket / named pipe |
| DB | **SQLite** via **Rusqlite in Rust** (preferred) or one pinned JS driver | Pick one in Phase 0; enables SQLCipher path |
| ORM / migrations | Drizzle or sqlx migrations — single choice in Phase 0 | |
| Files | OS app-data directory | |
| Backend (shipped) | **Node Hono sidecar** on `127.0.0.1` + session token; desktop adds **per-launch capability token** | Prefer migrating privileged ops to Tauri IPC over time |
| Backend (target) | Tauri IPC commands for DB/FS/HTTP without a long-lived TCP sidecar | Aspirational |
| DB (shipped) | **SQLite** via **better-sqlite3** + Drizzle; AES-GCM file seal when locked | Plaintext on disk while unlocked |
| DB (target) | Rusqlite / SQLCipher path | Aspirational |
| Files | OS app-data directory (desktop) or `PRM_DATA_DIR` / `./data` (dev) | |
| Search | SQLite FTS5 | |
| Jobs | Durable `jobs` table + run-while-open worker | Reminders don’t fire when app closed — documented |
| Auth | Single Account; OS keychain for API keys | Linux: Secret Service or app-password-wrapped key file fallback |
| AI | Settings → AI; BYO keys + Ollama | |
| Encryption | **Required** for real data: SQLCipher or authenticated encryption of DB+files | Phase 0/1 gate |
| Packaging | Code signing + notarization (Apple) + Windows Authenticode | Phase 0 infrastructure |
| Jobs | In-process while app open | Reminders don’t fire when app closed — documented |
| Auth | Single Account; workspace password vault | API keys encrypted with workspace secret (keychain still a target) |
| AI | Settings → AI; BYO keys + Ollama + Cursor gateway | |
| Encryption | **Required** for real data: authenticated encryption of DB+files on lock | |
| Packaging | Unsigned CI artifacts today; code signing + notarization still needed | |

---

## Topology

```
┌──────────────────────────────────────────┐
│ Tauri (Win / Mac / Linux) │
│ React UI ── IPC ── Rust commands │
│ │ │
│ SQLite (encrypted) │
│ App-data files (encrypted) │
│ OS keychain │
│ Tauri (Win / Mac / Linux) [optional] │
│ React UI ── HTTP ── Node Hono sidecar │
│ │ (127.0.0.1) │
│ SQLite (sealed on lock) │
│ App-data files (sealed) │
│ Workspace-secret crypto │
└───────────┬──────────────────┬───────────┘
▼ ▼
Cloud AI (opt-in) Ollama (opt)
```

**Dev browser mode:** Vite UI + `pnpm dev:api` (no launch token). Anyone on the same OS account who can reach loopback and guess/know the password owns the vault.

**Rejected as v1 primary:** Electron (fallback only), Docker-only UX, Next.js SSR, naked Postgres.

---
Expand All @@ -58,9 +60,9 @@ Same OS paths as before (`Application Support` / `%APPDATA%` / `~/.local/share/.
backups/
```

- **Refuse or hard-warn** if path is under Dropbox/iCloud/OneDrive/Google Drive sync folders.
- Backup: SQLite Online Backup API / `VACUUM INTO`, then encrypt zip; verify restore.
- Portability: versioned workspace archive with schema version + forward migrations.
- **Hard-warn** if path is under Dropbox/iCloud/OneDrive/Google Drive sync folders (status + unlock UI).
- Backup: encrypted `.sqlite.enc` snapshots under `backups/`; verify restore while unlocked.
- Portability: versioned workspace archive with schema version + forward migrations (partial).

---

Expand All @@ -74,7 +76,7 @@ Same OS paths as before (`Application Support` / `%APPDATA%` / `~/.local/share/.

## AI configuration

Fully in-app **Settings → AI** (see Features §8). Keys never in SQLite. Dev env overrides allowed for `pnpm dev` only.
Fully in-app **Settings → AI** (see Features §8). Keys are encrypted with the workspace secret in SQLite. Dev env overrides allowed for `pnpm dev` only. OS keychain storage remains a target, not current behavior.

---

Expand Down
12 changes: 6 additions & 6 deletions docs/architecture/SYSTEM.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ Hosted multi-tenant SaaS is a **separate track**, not a config switch.

## Stack

See [LOCAL_STACK.md](./LOCAL_STACK.md). Summary: Tauri 2, React/Vite, SQLite encrypted, IPC-first, app-data files, keychain, BYO AI + Ollama.
See [LOCAL_STACK.md](./LOCAL_STACK.md). Summary: Tauri 2 (optional shell), React/Vite, SQLite via better-sqlite3 with AES-GCM seal on lock, Node Hono on loopback (+ launch token in desktop), app-data files, BYO AI + Ollama. OS keychain and IPC-only topology remain targets.

---

## Topology

```
Tauri → React UI → IPC/commands → SQLite + files + keychain
↓
Cloud AI / Ollama (opt-in)
Tauri (optional) → React UI → HTTP (127.0.0.1 Hono) → SQLite + files + workspace crypto
↓
Cloud AI / Ollama (opt-in)
```

---
Expand All @@ -37,7 +37,7 @@ Tauri → React UI → IPC/commands → SQLite + files + keychain
| Workspace Account (EM) | Full read/write on workspace; export subject packets; configure AI |
| Person (no Account) | Not an actor in-app; appears in exports the EM creates |

Export redaction (`packages/policy`) strips `em_only` fields from subject packets. This is **share-time policy**, not protection from the EM.
Export redaction strips `em_only` fields from subject packets (implemented in API export paths). This is **share-time policy**, not protection from the EM.

---

Expand Down Expand Up @@ -70,7 +70,7 @@ Conceptual routes — implemented as Tauri commands or authenticated localhost:
- Link evidence; snapshots on finalize

### AI
- Settings get/set (keychain)
- Settings get/set (API keys encrypted with workspace secret)
- `evidenceDigest`, `draftSection`, `roleGapAnalysis`, `promotionDraft`, `biasLint`
- Returns `generation_id`; client accepts into draft

Expand Down
17 changes: 12 additions & 5 deletions docs/architecture/TRUST_MODEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,17 @@ No anonymity theater: imported peer text is attributed to the named peer for the

## Security baseline (v1)

- Encrypt SQLite + `files/` at rest (workspace password / OS key material) — **required before real employee data**
- Local API authenticated per launch (capability token) **or** Tauri IPC only (no naked TCP)
- API keys in OS keychain (with documented Linux fallback)
- Refuse/warn if app-data path is inside Dropbox/iCloud/OneDrive
- Consistent backup via SQLite backup API + encrypted archive
### Shipped today
- Encrypt SQLite + `files/` at rest with the workspace password (scrypt + AES-256-GCM seal on **Lock & encrypt**)
- Local API bound to `127.0.0.1`; session token after unlock; packaged desktop adds a per-launch capability token
- Integration / AI secrets stored encrypted in SQLite under the workspace secret (not returned in plaintext from settings GETs)
- Hard-warn when the data directory looks like Dropbox / iCloud / OneDrive / Google Drive
- Encrypted backup / restore under `data/backups`

### Not shipped yet (do not market as done)
- OS keychain custody for API keys (keys ride the workspace secret today)
- SQLCipher / Rusqlite-in-Rust as the primary DB path (Node `better-sqlite3` + file seal is what runs)
- Signed auto-update / notarized installers (desktop artifacts are manual CI builds)
- Background jobs when the app is closed

See [LOCAL_STACK.md](./LOCAL_STACK.md) and [SYSTEM.md](./SYSTEM.md).