Skip to content

Commit 5c784c6

Browse files
committed
chore: Phase 15 cleanup — rules refresh, dead-script removal, untrack local settings
.claude/rules/: - architecture.md: rewrite around the transport-modular layer diagram (UI shells ⇆ transport adapters ⇆ crates/core). Adds the 12 rules-for-new-code list (no business logic in frontend, no transport types in core, all API calls via api-client, etc). - coding-standards.md: TS naming + Rust service pattern + DTO camelCase rule + no Result<T, String> + no #[allow(dead_code)] + no TODO markers + Tailwind v4 + design-token rules. .claude/commands/{check-types,review-security,troubleshoot}.md: update to reference the new transport-http / transport-cli / crates/core layout. scripts/ deletions — confirmed-dead artifacts: - capture-app.mjs — Puppeteer screenshot tool, never wired into CI / docs / marketing pipeline. - patch-for-distribution.{cjs,sh} — Nix-era binary-patcher for the old apps/desktop/ path that no longer exists. - test-themes{,-final,-manual}.mjs — three iterations of the same Puppeteer theme-cycler dev experiment. .claude/settings.local.json: stop tracking in git (was in .gitignore already but tracked from before the rule landed — removing from index keeps the working-tree copy as session-local state).
1 parent 90f9e5f commit 5c784c6

14 files changed

Lines changed: 208 additions & 704 deletions

.claude/commands/check-types.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Run type checking across the full stack:
2020

2121
3. **Rust** (desktop launcher):
2222
```bash
23-
cargo check --manifest-path apps/desktop/src-tauri/Cargo.toml
23+
cargo check --manifest-path apps/tauri/src-tauri/Cargo.toml
2424
```
2525

2626
If there are type errors:

.claude/commands/review-security.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ allowed-tools:
99
Perform a security review of the codebase focusing on:
1010

1111
## Tauri Security
12-
- [ ] Capabilities are minimal in `apps/desktop/src-tauri/capabilities/default.json`
13-
- [ ] CSP headers configured in `apps/desktop/src-tauri/tauri.conf.json`
12+
- [ ] Capabilities are minimal in `apps/tauri/src-tauri/capabilities/default.json`
13+
- [ ] CSP headers configured in `apps/tauri/src-tauri/tauri.conf.json`
1414
- [ ] No unnecessary Tauri permissions granted
1515

1616
## Server Security
@@ -40,7 +40,7 @@ Check files:
4040
- `server/src/services/encryption.rs` — encryption implementation
4141
- `server/src/services/path_validator.rs` — path validation
4242
- `server/src/services/oauth.rs` — OAuth token handling
43-
- `apps/desktop/src-tauri/capabilities/` — Tauri permissions
44-
- `apps/desktop/src-tauri/tauri.conf.json` — CSP headers
43+
- `apps/tauri/src-tauri/capabilities/` — Tauri permissions
44+
- `apps/tauri/src-tauri/tauri.conf.json` — CSP headers
4545

4646
Report any findings with severity and recommended fixes.

.claude/commands/troubleshoot.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Diagnose and troubleshoot common issues based on the type provided:
3131
- Check environment variables (SPIRITSTREAM_HOST, SPIRITSTREAM_PORT)
3232

3333
## Desktop (Tauri) Issues
34-
- Check Tauri sidecar configuration in `apps/desktop/src-tauri/tauri.conf.json`
34+
- Check Tauri sidecar configuration in `apps/tauri/src-tauri/tauri.conf.json`
3535
- Verify server binary exists in sidecar path
3636
- Check Tauri logs for launcher errors
3737
- Verify webview can connect to `http://127.0.0.1:8008`

.claude/rules/architecture.md

Lines changed: 127 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,133 @@
11
# SpiritStream Architecture
22

3-
## Monorepo Layout
4-
3+
## Layered architecture
4+
5+
```text
6+
┌──────────────────────────────────────────────────────────────────┐
7+
│ ONE React frontend, shipped through THREE shells │
8+
│ • Tauri 2 desktop (macOS, Linux, Windows) │
9+
│ • Tauri 2 mobile (iOS, Android) │
10+
│ • Docker / browser (HTTP) │
11+
│ Plus: spiritstream-cli (headless, integration-test substrate) │
12+
├──────────────────────────────────────────────────────────────────┤
13+
│ Transport adapters — implement core::traits::transport::Transport│
14+
│ • HttpTransport (Axum + utoipa, /api/v1/*) │
15+
│ • CliTransport (in-process dispatch) │
16+
│ • VeilidTransport (contract-validation spike; see BLOCKERS) │
17+
├──────────────────────────────────────────────────────────────────┤
18+
│ crates/core/spiritstream-core (Rust library, NO transport deps)│
19+
│ • services/, models/, traits/, errors/ │
20+
└──────────────────────────────────────────────────────────────────┘
521
```
22+
23+
**Frontends are thin.** UI-only concerns stay in React: focus management, animations, modal open/close, form input state during editing. Every business rule — validation, orchestration, side-effect decisions — lives in `crates/core`.
24+
25+
## Monorepo layout
26+
27+
```text
628
spiritstream/
7-
├── apps/web/ # React frontend (standalone)
8-
├── apps/desktop/ # Tauri 2.x launcher (minimal)
9-
├── server/ # Standalone Rust HTTP server (Axum 0.7)
10-
├── docker/ # Docker distribution
11-
├── themes/ # Theme files
12-
├── scripts/ # Build & utility scripts
13-
└── packages/ # Shared packages (future)
29+
├── apps/
30+
│ ├── web/ # React frontend
31+
│ └── tauri/ # Tauri 2 shell — desktop + mobile
32+
│ └── src-tauri/ # gen/apple + gen/android for mobile targets
33+
├── crates/
34+
│ ├── core/ # spiritstream-core (transport-agnostic library)
35+
│ ├── transport-http/ # Axum + utoipa adapter
36+
│ ├── transport-cli/ # spiritstream-cli binary
37+
│ └── transport-veilid/ # Contract-validation spike — see BLOCKERS.md
38+
├── server/ # Thin binary wiring core + transport-http
39+
├── packages/
40+
│ ├── types/ # Rust → TS via ts-rs (auto-generated)
41+
│ ├── api-client/ # ApiClient interface + HttpClient impl
42+
│ ├── validation/ # JSON Schemas from utoipa
43+
│ └── ui/ # Shared React primitives
44+
├── deploy/
45+
│ ├── docker/ # Docker image build context
46+
│ ├── compose/ # docker-compose with Caddy + Let's Encrypt
47+
│ └── helm/ # K8s Helm chart
48+
├── tests/
49+
│ ├── integration/ # CLI-driven golden-file tests
50+
│ ├── threat-model/ # Doxxing/EXIF/PII fixtures
51+
│ └── a11y/ # Playwright + axe-core
52+
├── docs/ # User and operator docs
53+
└── themes/ # Theme bundle data
1454
```
1555

16-
## Server (`server/`)
17-
18-
Rust + Axum 0.7 HTTP server. Single binary, no Tauri dependency.
19-
20-
**Entry**: `server/src/main.rs` — route definitions, middleware, server startup
21-
22-
**Routes**:
23-
- `POST /api/invoke/:command` — command dispatch (all business logic)
24-
- `GET /ws` — WebSocket for real-time events
25-
- `GET /health` / `GET /ready` — health checks
26-
- `POST /auth/login` / `POST /auth/logout` / `GET /auth/check` — cookie-based auth
27-
- `GET /api/files/browse` / `GET /api/files/home` / `POST /api/files/open` — file browser
28-
29-
**Services** (`server/src/services/`):
30-
- `profile_manager` — Profile CRUD, encryption
31-
- `ffmpeg_handler` — Stream process management
32-
- `ffmpeg_downloader` — FFmpeg binary download/update
33-
- `encryption` — AES-256-GCM, Argon2id key derivation
34-
- `settings_manager` — App settings persistence
35-
- `theme_manager` / `embedded_themes` — Theme management
36-
- `log_manager` — Logging, log rotation
37-
- `chat_manager` / `chat` — Multi-platform chat integration
38-
- `obs_websocket` — OBS WebSocket integration
39-
- `discord_webhook` — Discord notifications
40-
- `oauth` — OAuth 2.0 for multiple providers
41-
- `events` — Event bus, WebSocket broadcasting
42-
- `path_validator` — Path traversal prevention
43-
- `platform_registry` — Platform-specific utilities
44-
45-
**Models** (`server/src/models/`): Domain types with `#[derive(Serialize, Deserialize, Clone)]`
46-
47-
## Frontend (`apps/web/`)
48-
49-
React 19 + Zustand 5 + Tailwind CSS v4 + Vite 7 + i18next (11 locales)
50-
51-
**Key paths**:
52-
- `src/components/` — React components (ui/, layout/, stream/, modals/)
53-
- `src/stores/` — Zustand stores, one per domain
54-
- `src/lib/backend/` — Transport abstraction layer
55-
- `src/types/` — TypeScript type definitions
56-
- `src/locales/` — i18n translations (af, ar, de, en, es, fr, ja, ko, ru, uk, zh-CN)
57-
- `src/views/` — Page views
58-
59-
**Transport abstraction** (`src/lib/backend/`):
60-
- `api.ts` — selects `httpApi` (default) or `tauriApi` (legacy) based on detected mode
61-
- `httpApi.ts``POST /api/invoke/{command}` with `safeFetch()` + retry + cookie auth
62-
- `httpEvents.ts` — WebSocket event handler with auto-reconnect
63-
- `httpDialogs.ts` — File dialog abstraction for HTTP mode
64-
- `env.ts` — Mode detection, URL management, health checks
65-
66-
## Desktop (`apps/desktop/`)
67-
68-
Minimal Tauri 2.x wrapper. **No business logic**`generate_handler![]` is intentionally empty.
69-
70-
**Entry**: `apps/desktop/src-tauri/src/main.rs`
71-
- Spawns `spiritstream-server` sidecar binary
72-
- Waits for `/health` endpoint
73-
- Opens webview to `http://127.0.0.1:8008`
74-
75-
## Deployment Modes
76-
77-
| Mode | How it runs |
78-
|------|-------------|
79-
| **Desktop** | Tauri launcher spawns server sidecar, UI in embedded webview |
80-
| **Docker** | Server container, UI served or accessed via browser |
81-
| **Web browser** | Remote access to running server instance |
56+
## Rules for any new code
57+
58+
1. **No business logic in the frontend.** If the code answers "should this action happen?" it belongs in `crates/core`. The frontend answers "how should this look?"
59+
2. **No transport types in core.** `crates/core` must compile without `axum`, `tower`, `hyper`, `tauri`, `clap`, or any HTTP/CLI/Tauri crate.
60+
3. **All API calls through `@spiritstream/api-client`.** Never `fetch()` directly from a component.
61+
4. **Domain types live once.** Define in `crates/core/src/models/`, derive `ts_rs::TS`, consume from `@spiritstream/types`. Do not redeclare in TypeScript.
62+
5. **Errors are structured.** Use `CoreError` variants; do not return new `Result<T, String>` from core services.
63+
6. **Transports map errors.** `transport-http` maps `CoreError → HTTP status`; `transport-cli` maps `CoreError → exit code`. Mapping lives in the transport, not in core.
64+
7. **Every UI operation must be reachable from `spiritstream-cli`.** If it isn't, that's a contract bug — fix core first.
65+
8. **Mobile constraints inform core design.** Sidecar binaries are restricted on iOS/Android; the core links into the Tauri 2 mobile shell as a library and the in-process Axum binds `localhost:8008`.
66+
9. **No runtime fallback chains.** Where a primary/secondary impl exists (e.g., keyring vs. encrypted-file secret store), the choice is made once at startup via platform probe or env override and held for the process lifetime. Never `try_primary().or_else(secondary)` at the call site.
67+
10. **No legacy/transitional dual-mount.** Forward-only architecture. There are no unversioned URL aliases, no `/api/invoke/:command` fallback, no schema-version migration framework.
68+
11. **No `#[allow(dead_code)]`; no TODO/FIXME markers in source.** Adapters, fields, and helpers must have a live caller in the same change. Future work tracks in plans, issues, or `BLOCKERS.md`.
69+
12. **Per-transport security hardening is allowed even though business logic isn't.** CSRF, cookie attributes, and CORS are HTTP-shaped concerns that legitimately live in `transport-http`. The Veilid analogue (peer-keypair verification) would live in its transport. See `crates/transport-veilid/BLOCKERS.md` for the boundary discussion.
70+
71+
## Service catalog (`crates/core/src/services/`)
72+
73+
| Service | Responsibility |
74+
|---|---|
75+
| `profile_service` | Profile CRUD, validation, encryption boundaries (delegated to `SecretStore`). |
76+
| `stream_service` | Stream lifecycle, reconnection, retry policy. Uses `MediaProcessor` trait (FFmpeg on desktop; HaishinKit/RootEncoder follow-up branch on mobile). |
77+
| `chat_service` | Multi-platform chat connect/send/receive. Applies the PII filter on inbound and `check_outbound_pii` on outbound. |
78+
| `obs_service` | OBS WebSocket integration. Owns trigger orchestration state machine. |
79+
| `oauth_service` | OAuth 2.0 flows with token refresh. |
80+
| `settings_service` | Global settings persistence with bound-checked setters. |
81+
| `theme_service` | Theme catalog, install, hot-reload. |
82+
| `audit_log_service` | HMAC-chained append-only audit trail. `verify_chain()` detects tamper. |
83+
| `safety_service` | Panic disconnect, PII blocklist, EXIF stripping, anonymous-mode pseudonymizer. |
84+
| `auth` | Brute-force defense (exponential backoff + sliding-window lockout). |
85+
| `auth_surveillance` | OAuth refresh-frequency anomaly detection. |
86+
| `secret_store` | `KeyringSecretStore` or `EncryptedFileSecretStore`, selected once at startup. |
87+
| `encryption` | AES-256-GCM-SIV envelope (V2 writes, V1 read-only) under HKDF-derived keys. |
88+
| `pii_filter` | Strict + fuzzy matchers; returns `phrase_id` for audit, never the phrase. |
89+
| `pseudonymizer` | HMAC-SHA256 keyed-hash for anonymous mode. |
90+
| `media_sanitizer` | EXIF / IPTC / XMP / PNG-text strip, thumbnail removal. |
91+
| `confirm_token` | One-shot intent-scoped 30s-TTL tokens for destructive ops. |
92+
| `secure_io` | `write_owner_only_atomic` (temp + rename + 0600 on Unix). |
93+
94+
Each service is constructed once, held in `ServiceRegistry`, and shared as `Arc<...>` across all active transports.
95+
96+
## Transports
97+
98+
### `transport-http` (Axum + utoipa)
99+
100+
Versioned REST under `/api/v1/*`. utoipa annotations on every handler generate an OpenAPI spec served at `/api/v1/openapi.json`; `@hey-api/openapi-ts` consumes that to produce `@spiritstream/api-client`.
101+
102+
Middleware stack: `request_id_middleware``csrf_middleware` (Sec-Fetch-Site + Origin allow-list, WS upgrades guarded) → `rate_limit_middleware` (per-endpoint, keyed by SHA-256 hash of auth subject) → `auth_middleware` (cookie + Bearer, `verify_token` hashes before `ct_eq`).
103+
104+
Cookie attributes via `SessionCookieMode` enum: `SameOrigin` (Tauri webview), `CrossOrigin` (browser-served), `LocalhostDev`. Pure-function `detect(host, deploy_mode, explicit)` for parallel-test safety.
105+
106+
Cloud-mode startup guard `enforce_cloud_mode_preconditions(token, tls_declared)` refuses to start without TLS and a ≥32-char token.
107+
108+
WebSocket: `GET /api/v1/events`, one-way server-push only. CSRF guard runs on upgrade.
109+
110+
### `transport-cli`
111+
112+
`spiritstream-cli` binary calls into `ServiceRegistry` directly — **no HTTP shell-out**. JSON output by default, `--pretty` for humans, `--quiet` for scripting. Exit codes derived from `CoreError` variants. Integration tests under `tests/integration/` are CLI-driven and golden-compared.
113+
114+
### `transport-veilid` (contract-validation spike)
115+
116+
Stub implementing `Transport` to prove the contract holds for a non-HTTP transport. `VeilidTransport::serve` returns `CoreError::NotImplemented`. The deliverable is `crates/transport-veilid/BLOCKERS.md` — 10 enumerated HTTP-shaped contract gaps (the biggest is **URL paths → method namespace**) that a real Veilid implementation must close. The crate compiles against `crates/core` alone with no Axum, Tauri, or Veilid SDK.
117+
118+
## Deployment modes
119+
120+
| Mode | Shell | Transport | Notes |
121+
|---|---|---|---|
122+
| **Desktop** | Tauri 2 | HTTP sidecar (`server/` spawned as a subprocess) | macOS / Linux / Windows. |
123+
| **Mobile** | Tauri 2 | HTTP in-process (core linked into Tauri Rust shell; Axum on `localhost:8008`) | iOS / Android. Sidecars don't work on either. |
124+
| **Docker / browser** | None | HTTP | Same `server/` binary; serves UI bundle + API. Caddy + Let's Encrypt in front. |
125+
| **CLI** | None | In-process dispatch | First-class client; integration-test substrate. |
126+
127+
## Pointers
128+
129+
- Coding standards: `.claude/rules/coding-standards.md`
130+
- Git workflow: `.claude/rules/git-workflow.md`
131+
- Documentation rules: `.claude/rules/documentation.md`
132+
- Veilid contract gaps: `crates/transport-veilid/BLOCKERS.md`
133+
- Per-crate READMEs: `crates/*/README.md`

0 commit comments

Comments
 (0)