Docs: geo-distribution architecture β one URL, region-local speed, single source of truth - #185
Docs: geo-distribution architecture β one URL, region-local speed, single source of truth#185lopugit wants to merge 6 commits into
Conversation
β¦speed, single source of truth Research + proposal for serving AU/US/EU users with region-local compute and data while thingtime.com stays one URL and the dataset stays one logical source of truth. Three options analyzed against the everything-is-a-thing model (multi-region replica set with read-local/ write-global; + write forwarding via Build Output split-plane routing; zone-sharded Global Cluster), with the replica-set path recommended first and a six-phase staged plan with costs, verification steps, and open questions. Platform facts researched 2026-08-08 from official Vercel/MongoDB docs, the live Atlas pricing calculator, and measured Sydney<->us-east RTTs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
β¦egion-local speed, single source of truth
π¦ Lopu β claims verified against the code; one correction that strengthens Β§5.3For a research document the review that matters is whether the factual base holds, so I re-checked every checkable claim rather than commenting on structure. Everything verified:
Β§5.3's MongoDB reasoning is accurate and unusually well-scoped β unique indexes on a sharded collection must be shard-key-prefixed; Global Clusters need M30+ and fix the shard key at creation; a query without the shard key fans out scatter-gather. Mapping the "unsharded identity/reservation collection on the primary shard" mitigation onto the endpoint split the repo already has is the sharpest observation in the document. Β§4's "a social feed is global-content-read-heavy" is the right decision criterion and genuinely does select A over C. The one correctionConstraint Β§2.2 described Normally that'd be pedantry β but Β§5.3 builds its sharding argument on "this shape", and a multikey field cannot be part of a shard key in MongoDB. So Only PR in this batch with a fully green board β 18 check runs, nothing red. |
β Develop S3 preview ready
The alias passed the develop bucket CORS preflight and a final live PR/SHA fence. Generic Vercel Preview deployments use the shared development runtime; this controller adds the stable exact-SHA alias and marker-scoped cleanup. |
π¦ Lopu β the reasoning holds; the branch is 962 commits old and it showedThis branch was cut 2026-08-08 and What survived unchangedEvery code seam the argument rests on is still there and still behaves as described:
The reasoning I'd most want kept is Β§4: a social feed is global-content-read-heavy, so replication (every region holds everything) matches the workload while geo-sharding optimizes the wrong axis first. That's the load-bearing insight and it's right. So is Β§5.1's warning that all three electable nodes must stay in Sydney β spreading voters across oceans puts ~200ms inside every write's majority ack, which is precisely the config mistake that would make the migration a regression. And Β§5.3's honesty about Option C (shard key set once, never resharded; unique indexes must be shard-key-prefixed) is what stops someone buying a $980/mo cluster to fix a read-latency problem. What had drifted β corrected inline
I left the measurements, the three options, the cost table and the open questions alone β they're clearly scoped as "researched 2026-08-08", Β§7 already carries a One thing on Β§8The four open questions are the right ones, and the first ("park this until there's a US cohort?") is answerable cheaply now β Vercel Analytics already knows where visitors are. Worth pulling that number before Phase 1, since it also settles question four (which region second). All checks green at this head; Housekeeping note for whoever maintains the review harness: the trusted CodeQL snapshot for this PR is empty, but the alert-instances API shows alert #7 open on β π¦ Lopu, Thingtime's PR manager |
|
π€ Lopu β your re-verification checks out; the 6 extra CodeQL alerts are not yours This is a one-file documentation diff, so I spot-checked what the 2026-08-26 re-verification note claims against
All accurate. Β§7's vendor pricing being stamped "as of 2026-08-08, re-check before any purchase" is the right way to age a research figure instead of letting it rot silently. The core argument holds too β colocating compute with data means a remote user pays the ocean crossing once per request, not once per database round trip, which is exactly why Option A is the right next step and why Β§5.4's rejection of per-region independent databases belongs in the record. CodeQL: 22 alerts, but only 16 are the repository-wide baselineThe other 6 are worth explaining because a docs-only diff obviously did not introduce them. I read the cited code on both sides:
All six are stale-base artefacts: this branch was cut 2026-08-08 and still carries pre-fix copies of files I left the dispositions empty deliberately. None is a false positive (the sanitization really is incomplete in the code as it stands on this head, and the privileged checkout really is there) and none is test-only β dismissing them would be greening a check with a false statement. Nor did I "fix" them: Two small things
(The single red check is a cancellation, not a failure: |
|
π€ Lopu β the 4h58m red mark has a root cause now, and it was fixed upstream 6 hours after this run died Re-reviewing this head. Nothing to add on the document itself beyond my 09:15 pass β I re-checked the links against the merge commit ( What I can now add is the why behind the one red check, which I previously only characterised as "queued in the fleet group and drained without starting".
|
| On this head | On develop @ b7e2906 |
|
|---|---|---|
| #30, #31 | CommanderV2.tsx:152 is the escapedCommandValue block |
escapedCommandValue occurs 0 times; line 152 is commandIsAction |
| #35β#37 | CommanderV1Deprecated.tsx carries the same pattern |
the file is absent entirely |
| #75 | resolve-pr-conflicts.yml is the full implementation |
the file is 118 lines β the thin listener |
develop deleted that Commander block rather than fixing it, so re-implementing an escape here would only conflict with the deletion. All six retire on merge. Left open, not dismissed β on this exact head the cited code really is there.
Changed from my last pass: I have now dispositioned the 11 repository-wide baseline alerts (#7, #8, #14, #26β#29, #77β#80) with per-alert evidence β the dead userGenerateJWT stub whose uuid is never read, six client-side render/debug identifiers that are DOM ids, CSS animation names and React keys rather than credentials, and four verify-*.mjs developer scripts whose random suffix only uniquifies throwaway test accounts. Those are genuinely not applicable and were sitting open across every develop-based PR in this batch.
Still left open as real: #18/#19 (smarts/index.tsx merge() walks Object.keys(value2) and assigns without a __proto__ guard β JSON.parse yields __proto__ as an own enumerable key, so this is genuine), #17, #45, #49. The prototype-pollution one wants a dedicated PR: it rides #135/#185/#382/#405 identically, so four branch-local fixes would just collide on merge.
|
π€ Lopu β the red It is cancelled, and the job never ran a single step: Empty
It is systemic, not a one-off. Last 100 runs of that listener: 45 cancelled, 31 success, 24 pending. PR #395 carries the identical symptom, and on PR #413 the same backlog has left I deliberately did not change the control plane for this, because every candidate fix is an architecture decision rather than a repair: narrowing the listener's triggers means editing a workflow on @lopugit β your call, in increasing order of invasiveness:
The docs change itself is good and I have merged-in one small correction; details in my review comment. |
|
These examples are warning-only. They do not fail the build/API contexts or block this PR.
Sanitized tailnode:internal/modules/run_main:123
triggerUncaughtException(
^
AssertionError [ERR_ASSERTION]: all-branch.yml must stay retired; Lopu PR manager owns its former public triggers
true !== false
at file:///home/runner/work/thingtime/thingtime/remix/scripts/workflow-caller-contract.mjs:39:10
at ModuleJob.run (node:internal/modules/esm/module_job:343:25)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:681:26)
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:117:5) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: true,
expected: false,
operator: 'strictEqual',
diff: 'simple'
}
Node.js v22.23.2
|
|
π§βπ§ Lopu β the doc is accurate and needs no changes. The 22 CodeQL alerts on this head did need work. On the document: I checked the load-bearing claims rather than taking them on trust. On CodeQL: none of the 22 come from this PR β it adds one Markdown file β but they're attributed to this head, so I worked all of them. Ten fixed, ten dispositioned with evidence, two left open. The one worth your attention is prototype pollution in Also fixed: the Commander's escaping ahead of Dispositioned as not applicable: the UI-identifier Two I deliberately left open rather than dismiss:
|
Research + architecture notes for geo-distributing Thingtime: one
thingtime.comURL, region-local server + database speed for AU/US/EU users, one logical single-source-of-truth dataset. Docs only β nothing is built; this is a reading/decision document.What's inside (docs/architecture/geo-distribution.md)
withMongoTransaction, test==live parity.readPreference=nearest+ Atlas node tags. US reads drop ~200ms β ~5ms; search goes region-local too (coupled Atlas Search runs on read-only nodes). ~$112/mo (M10 + 1 US node, from the live Atlas calculator).methodsmatching and per-functionregions, so ONE deployment can send GETs to multi-region functions and writes to a syd1-pinned copy of the same Nitro bundle. Remote writes become a single hop. No second project, no middleware.mongodb/endpoint.tsalready draws), scatter-gather feeds/search, and an ~$980/mo M30 floor. The right eventual destination, not the next step.Notable existing-plumbing findings
mongodb/endpoint.ts's home-vs-data-plane split (identity pinned home, data plane resolved per request) is exactly the seam a regional data plane generalizes.anon=1cache warms per region and pairs with 2025/26 cache-tags + 300ms global purge for precise invalidation later.π€ Generated with Claude Code