|
| 1 | +--- |
| 2 | +title: "Refactoring for API Speed — a single-user app should boot in milliseconds, not a minute" |
| 3 | +lede: "Refreshing the page takes 60s+ for the logged-in workspaces to appear, and every microfrontend/microservice hop adds latency waiting for the others to respond or 'acknowledge' each other. There is ONE user. The distributed mesh — 7+ Railway services, per-remote WebSockets, NATS request/reply, a remote cloud DB, a separate auth service — imposes coordination cost that dwarfs the actual work. This is the diagnosis and the refactor design space, measure-first." |
| 4 | +date_created: 2026-08-02 |
| 5 | +date_modified: 2026-08-02 |
| 6 | +authors: |
| 7 | + - Michael Staton |
| 8 | +augmented_with: |
| 9 | + - Claude Code on Claude Opus 4.8 |
| 10 | +semantic_version: 0.0.0.1 |
| 11 | +tags: |
| 12 | + - Issue |
| 13 | + - Augment-It |
| 14 | + - Performance |
| 15 | + - Architecture |
| 16 | + - Refactor |
| 17 | + - Boot-Latency |
| 18 | +status: Open · Diagnosed · Refactor Backlog |
| 19 | +--- |
| 20 | + |
| 21 | +# Refactoring for API Speed |
| 22 | + |
| 23 | +## Why Care? |
| 24 | + |
| 25 | +On refresh, the workspaces the operator is logged into take **60s+** to appear. |
| 26 | +Interactions wait on microfrontends and microservices responding to — and |
| 27 | +"acknowledging" — each other. There is exactly **one user**. This should be |
| 28 | +milliseconds. The cost is not the work; it's the **coordination** between too |
| 29 | +many independently-deployed parts. |
| 30 | + |
| 31 | +## The topology being paid for (with one user) |
| 32 | + |
| 33 | +- **7+ separate Railway services**: `shell` (augment.didi.sh), `strategy-curator`, |
| 34 | + `chat` (+ other federation remotes: org-workbench, search-and-add, |
| 35 | + search-results…), `workspace-service` (WS gateway), `record-surrealdb-resolver`, |
| 36 | + `content-ingest`, `prompt-runner`. |
| 37 | +- **`id.didi.sh`** — a separate identity service (different repo/runtime) for |
| 38 | + JWKS verification + `/api/me` memberships. |
| 39 | +- **SurrealDB Cloud, aws-use1** (`wss://…surreal.cloud`) — every query is a |
| 40 | + network round-trip to AWS us-east. |
| 41 | +- Each **microfrontend opens its OWN WebSocket** to workspace-service and does |
| 42 | + its **own** auth handshake (shell App.svelte notes "each federation remote |
| 43 | + also connects, those instances are separate"). |
| 44 | +- Services talk **service→service over NATS request/reply**. |
| 45 | + |
| 46 | +Every one of those boundaries adds fixed latency: TLS, cold start, DB round |
| 47 | +trip, NATS hop, and — worst — **retry backoff**. |
| 48 | + |
| 49 | +## Root causes (code-grounded, ordered by leverage) |
| 50 | + |
| 51 | +1. **Retry-as-readiness is masking a boot race — the acute one.** The recent |
| 52 | + commit: *"retry `workspace.active.requested` up to ~60s before crashing."* |
| 53 | + `shell/src/App.svelte:375` also backs off 8× on `loadWorkspaces`. That ~60s is |
| 54 | + the shell **waiting for a dependency to become ready** (cold service, DB |
| 55 | + connection warming, NATS responder not yet registered), not doing work. |
| 56 | + Suspected to be most or all of the observed minute. |
| 57 | +2. **Cold starts, in series.** One boot call traverses shell → workspace-service |
| 58 | + → NATS → resolver → SurrealDB Cloud. A cold service anywhere on that path |
| 59 | + wakes on the request; multiple cold hops compound. |
| 60 | +3. **Sequential remote-DB round trips on boot.** Memberships, workspace list, |
| 61 | + active workspace, rows — each a separate cross-country round trip to aws-use1 |
| 62 | + if issued back-to-back. |
| 63 | +4. **Cross-service auth on every connect.** Each WS upgrade verifies the JWT and |
| 64 | + fetches `/api/me` from id.didi.sh (cached only ~60s, `didi.ts:96`) — and every |
| 65 | + remote repeats it. |
| 66 | +5. **Per-remote fan-out.** Boot cost multiplies by the number of microfrontends, |
| 67 | + each with its own transport + auth + initial capability calls. |
| 68 | +6. **NATS request/reply between co-located services** is pure serialization |
| 69 | + overhead when there's no concurrency to justify it. |
| 70 | + |
| 71 | +## The thesis |
| 72 | + |
| 73 | +The system is a distributed, multi-tenant-shaped mesh serving **one user**. The |
| 74 | +fix is to **right-size the architecture to actual scale** — reserve the mesh for |
| 75 | +when concurrency demands it, and until then collapse boundaries so calls are |
| 76 | +in-process and boot is deterministic. |
| 77 | + |
| 78 | +## Design space (measure first, then pick) |
| 79 | + |
| 80 | +**Step 0 — MEASURE, don't guess.** Instrument the boot path end to end (WS |
| 81 | +upgrade, auth verify, /api/me, workspace.list, workspace.active, per-remote |
| 82 | +connect) with timestamps. Confirm the minute is the retry race before |
| 83 | +refactoring anything. A [[No-User-Visibility-Into-State-Needs-A-State-Inspector]] |
| 84 | +surface / the live/not-live indicator work is the natural home for this. |
| 85 | + |
| 86 | +Then, by leverage: |
| 87 | + |
| 88 | +- **Kill retry-as-readiness.** Make services signal ready and the shell's first |
| 89 | + call succeed deterministically (or a fast, bounded wait) — turns 60s into ms. |
| 90 | +- **Keep the request-path services warm** (no scale-to-zero; a warm SurrealDB |
| 91 | + connection pool). Cheap, ops-level, big. |
| 92 | +- **One bootstrap call.** A single `workspace.bootstrap` capability returning |
| 93 | + memberships + workspaces + active + initial state, instead of N sequential |
| 94 | + DB/NATS round trips. |
| 95 | +- **Embed memberships/claims in the JWT** so auth needs zero cross-service |
| 96 | + `/api/me` fetch. |
| 97 | +- **Share one transport across remotes** (single WS, single auth verification) |
| 98 | + instead of per-remote handshakes. |
| 99 | +- **Collapse services.** For single-user / small-team scale, fold |
| 100 | + resolver + content-ingest + prompt-runner (and possibly the WS gateway) into |
| 101 | + fewer processes so NATS request/reply becomes function calls. Reserve split |
| 102 | + services for a real concurrency/scale trigger. |
| 103 | +- **Optimistic boot.** Render cached workspaces from localStorage instantly, |
| 104 | + revalidate in the background — perceived ms regardless of revalidation cost. |
| 105 | + |
| 106 | +## Explicitly NOT this issue |
| 107 | + |
| 108 | +- Not a call to abandon the distributed design permanently — it's a call to |
| 109 | + match it to current scale and make the boundaries cheap or absent until scale |
| 110 | + arrives. |
| 111 | +- Not the auth-persistence / cookie-partitioning bug |
| 112 | + ([[Workspace-And-Corpora-Connection-Slow-To-Hanging-And-Auth-Wont-Persist]]) — |
| 113 | + related surface, different root cause; cross-linked, not merged. |
| 114 | + |
| 115 | +## See also |
| 116 | + |
| 117 | +- [[Workspace-And-Corpora-Connection-Slow-To-Hanging-And-Auth-Wont-Persist]] — the production connection/auth issue on the same surface. |
| 118 | +- [[Live-Not-Live-Indicator-Tooling-And-Cross-Service-Error-Surfacing]] · [[No-User-Visibility-Into-State-Needs-A-State-Inspector]] — where boot instrumentation would live. |
0 commit comments