Skip to content

Commit c5bd573

Browse files
mpstatonclaude
andcommitted
issue(deployment): move the rest of the app to remote hosting — prod falls back to localhost
Only the client-facing surfaces (Corpus Builder + Augment-from-DB + chat) were deployed as hosted remotes; the other 12 micro-frontends are hardcoded to localhost:3XXX in shell/rsbuild.config.ts, so the prod shell tries to fetch them from the visitor's machine at boot (fail, and can hang on a TCP timeout). A deliberate shortcut to get client collaboration live and defer the deploy-the-whole-federation refactor. Full inventory + two tracks: (A) host the rest, (B) interim env-aware config so prod never fetches localhost. Surfaced by the API-speed measurement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018UYTYu4MAFZ7iyr2VTo2kq
1 parent 1a7a9fb commit c5bd573

1 file changed

Lines changed: 129 additions & 0 deletions

File tree

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
---
2+
title: "Move the rest of the app to remote hosting — prod still falls back to localhost for every undeployed remote"
3+
lede: "Only the client-facing surfaces (Corpus Builder + Augment-from-DB) were deployed as hosted remotes; the other 12 micro-frontends are hardcoded to http://localhost:3XXX in the production shell build, so augment.didi.sh tries to fetch them from the visitor's own machine at boot — they fail, and on some networks hang on a TCP timeout. This was a deliberate shortcut to get client collaboration live and defer the big refactor. Now the rest of the app needs to graduate to remote hosting."
4+
date_created: 2026-08-03
5+
date_modified: 2026-08-03
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+
- Module-Federation
15+
- Deployment
16+
- Shell
17+
- Remote-Hosting
18+
status: Open · Diagnosed
19+
---
20+
21+
# Move the rest of the app to remote hosting
22+
23+
## Why Care?
24+
25+
On augment.didi.sh, the production shell tries to load a dozen micro-frontends
26+
from **`http://localhost:3002…3015/remoteEntry.js`** — the *visitor's* own
27+
machine, not a hosted server. They fail every boot (visible in the console as
28+
`Loading failed for the <script> …`), and on some network configs those fetches
29+
**hang on a TCP connect timeout** — the residual boot noise the operator felt as
30+
part of the "minute" (see [[Refactoring-for-API-Speed]]'s measured finding). If a
31+
collaborator happens to have local dev servers on those ports, it's worse: the
32+
prod shell silently mounts *their laptop's* dev code.
33+
34+
## How we got here (the deliberate shortcut)
35+
36+
The priority was getting **client collaboration** live: the **Corpus Builder**
37+
(strategy-curator) and the **Augment-from-DB** flow (org-workbench +
38+
search-and-add + search-results), plus **chat**. Those surfaces were deployed as
39+
hosted Railway services with real `PUBLIC_*_REMOTE` URLs. Everything else — the
40+
original CSV-first pipeline and the resolver micro-frontends — was left pointing
41+
at its dev `localhost` port, on the theory that a humain-vc/client deploy never
42+
opens those Flows so it wouldn't matter. It was a knowing shortcut to avoid the
43+
big "deploy the whole federation" refactor. This issue is the debt coming due.
44+
45+
## The exact mechanism
46+
47+
In `shell/rsbuild.config.ts` the `remotes` map has **two tiers**:
48+
49+
- **Environment-aware (5, deployed):** `process.env.PUBLIC_*_REMOTE || 'http://localhost:…'`
50+
— a prod build injects the hosted URL via the shell Dockerfile's `ARG`/`ENV`.
51+
- **Hardcoded localhost (12, undeployed):** e.g.
52+
`recordCollector: 'recordCollector@http://localhost:3002/remoteEntry.js'`
53+
**no env branch at all**, so the value ships verbatim in the production bundle.
54+
55+
And they load **at boot, not lazily**, because the shell's **default Flow is
56+
Record Collector** (`recordCollector`, undeployed) and its peek-deck rotations
57+
reference other undeployed remotes (`recordDbResolver`, `personDbResolver`,
58+
`affiliationRatingResolver`) — so mounting the default surface fetches their
59+
`localhost` entries immediately.
60+
61+
## Inventory — every remote, hosting status
62+
63+
| Remote | Port | Deployed as a Railway service? | Config tier |
64+
|---|---|---|---|
65+
| chat | 3006 | ✅ yes | env-aware |
66+
| org-workbench | 3014 | ✅ yes | env-aware |
67+
| search-and-add | 3016 | ✅ yes | env-aware |
68+
| strategy-curator (Corpus Builder) | 3017 | ✅ yes | env-aware |
69+
| search-results | 3018 | ✅ yes | env-aware |
70+
| **record-collector** | 3002 | ❌ no | **hardcoded localhost** |
71+
| **prompt-template-manager** | 3003 | ❌ no | **hardcoded localhost** |
72+
| **request-reviewer** | 3004 | ❌ no | **hardcoded localhost** |
73+
| **response-reviewer** | 3005 | ❌ no | **hardcoded localhost** |
74+
| **enhanced-records-list** | 3007 | ❌ no | **hardcoded localhost** |
75+
| **record-db-resolver** | 3008 | ❌ no | **hardcoded localhost** |
76+
| **pack-runner** | 3009 | ❌ no | **hardcoded localhost** |
77+
| **person-db-resolver** | 3010 | ❌ no | **hardcoded localhost** |
78+
| **records-surface** | 3011 | ❌ no | **hardcoded localhost** |
79+
| **affiliation-rating-resolver** | 3012 | ❌ no | **hardcoded localhost** |
80+
| **sort-filter-lens** | 3013 | ❌ no | **hardcoded localhost** |
81+
| **person-enrichment** | 3015 | ❌ no | **hardcoded localhost** |
82+
83+
Twelve undeployed remotes, all shipping `localhost` in prod.
84+
85+
## What "move to remote hosting" means — two tracks
86+
87+
### Track A — the real goal: host the rest of the app
88+
Graduate each remaining micro-frontend to a hosted remote, the same way the five
89+
client-facing ones already are:
90+
1. Add a Railway service per remote (its `Dockerfile`, a Railway-generated or
91+
`*.didi.sh` domain).
92+
2. Add a `PUBLIC_<REMOTE>_REMOTE` build ARG to `shell/Dockerfile` + set it as a
93+
shell service variable, and switch the `rsbuild.config.ts` line to
94+
`process.env.PUBLIC_<REMOTE>_REMOTE || 'http://localhost:<port>'`.
95+
3. Sequence by what a client/collaborator actually needs next (the CSV pipeline —
96+
record-collector, response-reviewer, enhanced-records-list — is the obvious
97+
first cluster; the resolvers next).
98+
99+
Note: this is exactly the "deploy the whole federation" refactor the shortcut
100+
deferred — so it wants its own **plan** with a sequencing decision, not a
101+
one-shot.
102+
103+
### Track B — the interim safety net (cheap, do regardless)
104+
Even before all twelve are hosted, prod should **never fetch `localhost`**:
105+
1. Make the remotes map **environment-aware** — in a production build, **omit**
106+
any remote without a real hosted URL, so Module Federation never tries it.
107+
2. **Guard the mount path** and pick a **deployed default Flow** in prod
108+
(strategy-curator / Corpus Builder, what humain-vc actually uses) so boot
109+
never mounts an undeployed remote.
110+
111+
Track B stops the boot noise and the hang-on-a-collaborator's-network failure
112+
mode immediately; Track A is the durable "the whole app is hosted" end state.
113+
114+
## Acceptance
115+
116+
- Loading augment.didi.sh (or any client deploy) produces **zero**
117+
`localhost:3XXX` fetch attempts in the console.
118+
- No boot mounts an undeployed remote; the default Flow is a deployed one.
119+
- Each remote intended for a client deploy resolves to a hosted `remoteEntry.js`.
120+
121+
## See also
122+
123+
- [[Refactoring-for-API-Speed]] — the measurement that surfaced this (backend
124+
was ~543ms; these localhost loads were the residual).
125+
- `DEPLOYMENT.md` — the shell build-args + per-service deploy pattern the five
126+
hosted remotes already follow.
127+
- [[Augment-From-DB-Flow]] · [[Strategy-Curator-Entry-Point-for-Augment-It]]
128+
the two surfaces that WERE prioritized and hosted.
129+
- Boot instrumentation (gh #80) — how the localhost loads became visible.

0 commit comments

Comments
 (0)