refactor(modules)!: move the UO server half out to module-uo (phase 3, slice 1) #137
Reference in New Issue
Block a user
No description provided.
Delete Branch "feature/module-extract-server"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Core's half of slice 1. Merge after Module-uo#3, per §2.7.1's merge order — that way
edgeserves these routes from core right up to the moment this lands, and never sits missing them.40 files and ~9,674 lines leave, along with 27 of 68 tables and 25 of 82 test files. Core no longer contains anything that knows what a shard is.
No URL moved
routes.manifest.jsongoes 228 → 158 public routes here, and the 70 that left reappear byte-identical once the module is loaded. Verified by generating the manifest against core+module and diffing it against the pre-extraction file: zero missing, zero added, androutes.guards.jsonidentical across all 228 — so no auth gate moved either. That is the one manifest diff the workstream allows (API §5.3).Three commits, readable in order
feat(modules)— the contract additions (API 1.0.0 → 1.1.0)refactor(modules)!— the deletion and rewiringtest— re-pointing core's suite at what core still ownsThe contract additions, and why none could be avoided
ctx.activity.log— an admin action a module performs has to land in core's one audit log, or the trail has a hole exactly where a module operates the game. A module keeping its own log is a second place to look, which in practice means a place nobody looks.ctx.users.getById— one function for one caller: theadmin.users.detailslot router needs the user its prefix names.ctx.site.baseUrl— §2.7 forbids a module reading core'sAPP_BASE_URL. A getter, not a captured string, so it cannot go stale against the env.ctx.middleware.rateLimit(core'smakeLimiter) plusaccountChangeLimiterhanded over whole. A module states its own window and cap because it knows what its endpoints cost, and takes the plumbing from core so there is oneexpress-rate-limitin the process and one place a breach is logged.accountChangeLimiteris shared policy —/auth/meand/player/accountsit behind the same counter — so a module's account-change route must land in it, not beside it.marketLimiterwas UO policy living in core's file and leaves with the route it guards.registerPostHook— the last thing binding core to the moduleCore's post controller called
newsGump.syncPostdirectly: core's CMS naming a UO file. It now publishes what it already knows ({ post, transition }on save,{ post, id }on delete) and a subscriber decides what to do with it. Deliberately not folded intoregisterAnnounceLeg, which fires on the same transition — a leg is a one-shot delivery with retry and classification, while a post hook maintains idempotent state, runs on delete as well as save, and refreshes silently on an edit.A real loader defect the extraction exposed
Schema table names were matched against the raw file, so a fragment whose header says "every CREATE TABLE carries IF NOT EXISTS" was rejected for a prefix violation on a table called
carries. module-uo's fragment hit exactly that on its first real load. Both scans now read split statements, which strip comments — the same class of bug as a boundary check failing on its own documentation, which is where slice 0 found it.The one test that stayed, and why
playerRouteAccess.test.jsguards a real past bug — an admin 403'd off their own characters — through/player/shard/accounts, now module-owned. The guarantee is core's, though:/player/*is role-agnostic self-service, staff are a superset of players. So it stays and asserts that through/player/appeals, a core route with the same gate. Moving it would have left core with no test of its own tier rule, which is precisely what regressed once before.Verified
616 server tests, 160 client tests, both green. Against a running server with the module installed: it loads, mounts five prefixes, replays 35 statements, reaches
started; public shard/atlas answer 200 with real data, admin and player answer 401 from core's tier gates, the extension slot answers. Core's own SPA renders the shard and atlas pages unchanged, no console errors, no CSP reports. Core also boots and passes with no module installed, which is what the schema split had to preserve — no core table ever referenced a module table.