14 KiB
Meteor upgrade — 1.6.1.1 → 2.x (→ 3.x blocked)
Incremental, verified upgrade of todos-contra-el-fuego-web. Branch:
meteor3-upgrade (base tcef-master). Local commits only — no push until
authorized.
⚠️ Hard blocker for the final 3.x jump: MongoDB 3.2
Production runs against the shared replica set rsmain on MongoDB 3.2.11.
Meteor 3 ships the modern mongodb Node driver, which requires a server
≥ 4.2/4.4. Meteor 2.x still works against Mongo 3.2.
Therefore this branch lands on Meteor 2.5 — empirically the highest release
whose bundled mongodb driver still connects to Mongo 3.2 (2.6 bumps the driver
to 4.x and fails; see "Escala ceiling" below) — with everything green. The
meteor update --release 3.x step (and even 2.6+) is deliberately not taken
until the Comunes infra team upgrades rsmain (shared infra — coordinated in a
separate phase, not unilaterally). Server code should still be migrated to
async/await before the final 3.x jump so it is mechanical (tracked as debt).
⚠️ Deploy-ordering dependency: notifications cutover
The old push/email notification code was removed from the web (see the notifications commit) because it now lives in the tcef-notifications microservice. Production must not run this build until tcef-notifications is emitting in prod — otherwise users stop receiving notifications. The web deploy and the notifications cutover must be coordinated.
Safety net: REST smoke test
smoke/ is a standalone Node harness that calls every REST endpoint the Flutter
app consumes, against a seeded local dev server, and diffs the responses against
committed snapshots (smoke/snapshots/). See smoke/README.md.
Run after every escala — it must stay byte-identical:
docker run -d --name tcef-mongo32 -p 27018:27017 mongo:3.2 # once
export PATH="$HOME/.meteor:$PATH" MONGO_URL="mongodb://localhost:27018/fuegos"
meteor --settings settings-development.json --port 3100 & # dev server
./smoke/smoke.sh # seed + compare
Escalas
Baseline — Meteor 1.6.1.1 (starting point)
- Boots against Mongo 3.2 with
settings-development.json. - Dev-enabling changes (do not affect production behavior):
IPGeocoder.js: degrade gracefully when the MaxMind GeoLite2 DB is absent (provisioned by cron in prod) instead of crashing at boot.settings-development.json: added dev-onlyprivate.internalApiToken(dev-smoke-token) — the REST API only registers its routes when this is set.
- Notifications code removed (migrated to tcef-notifications): deleted
notificationsObserver.js,notificationsProcess.js, the "Process pending notif" SyncedCron job, and thenode-gcmdependency.subsUnion.jskept (it feedssubs-public-union, consumed by the app). - REST smoke baseline captured here. ✅ green.
Escala 1 — 1.6.1.1 → 1.8.3 ✅ green
meteor update --release 1.8.3
meteor npm install --save @babel/runtime@^7.26.0
Core packages bumped (highlights): meteor 1.8.6→1.9.3, ecmascript
0.10.7→0.13.2, modules 0.11.6→0.14.0, mongo 1.4.7→1.7.0, npm-mongo
2.2.34→3.2.0 (mongodb driver 3.x — still fine against Mongo 3.2 server),
webapp 1.5.0→1.7.5, standard-minifier-js →2.5.2. underscore auto-added
(1.7 dropped it from meteor-base), fetch + modern-browsers added.
Breaking change — Babel beta → stable. Boot failed with
Cannot find module '@babel/runtime/helpers/objectSpread2': the pinned
@babel/runtime@7.0.0-beta.44 predates helpers that 1.8's ecmascript emits.
Fixed by upgrading to stable 7.x (@babel/runtime@^7.29.7). Note: @latest
resolves to 8.x, which is too new for Meteor's 7-style helper layout — pin to
^7.
REST smoke test: byte-identical to baseline. ✅
Escala 2 — 1.8.3 → 1.11 (version resolution only)
meteor update --release 1.11
Resolution reached 1.11 (ecmascript 0.14.3, mongo 1.10.0, npm-mongo
3.8.0 — still Mongo-3.2-compatible, accounts-* 1.x, email 2.0). But this
release surfaced the two big blockers below. The app was ultimately driven to
2.3 (see next section); 1.11 was a transit point, not a landing.
Escala 3 — → Meteor 2.3 ✅ green (builds + runs against Mongo 3.2, smoke byte-identical)
.meteor/release = METEOR@2.3. npm-mongo 3.9.0 (mongodb driver 3.x) — the
last driver line that still speaks to a Mongo 3.2 server. Core bumps:
accounts-* 2.0, ecmascript 0.15.2, mongo 1.12.0, HMR added.
This escala was dominated by dead Atmosphere packages (the plan's #1 risk). Root causes and fixes, in the order they were hit:
-
arkham:comments-ui— no Meteor 2.x build. The vendored local package usedNpm.depends, and rebuilding a local package's npm deps crashes meteor-tool ≥1.11 on this host (node_contextify.cc … Assertion args[1]->IsString()→ SIGABRT; reproducible with anyNpm.depends, evenis-number). Switching to the Atmosphere isopack avoided the local rebuild but the package is abandoned: its newest 2.x-solvable version (0.2.15) pinsaccounts-password@1.0.1, conflicting with Meteor 2.0's accounts-password 2.0. Decision (user-approved): reimplement comments as a small React feature (imports/api/Comments/*,imports/ui/components/Comments/CommentsBox.js), dropping the package entirely. Fire-page comments only (the sole usage), with likes/dislikes, image/YouTube embed, owner edit/remove, and the "email other commenters" side-effect preserved. Comment text is now rendered as safe plain text (+ media embed) instead of markdown-to-HTML — a small scope reduction and a security improvement (no raw-HTML injection of user content). The old local fork is preserved in its nested git repo (commit4761da9). -
coffeescript@1.0.17build plugin — crashes the build. The samenode_contextifyassertion fired at build start on this host whenever the coffeescript compiler plugin loaded. It was pulled transitively by the dead test stack (meteortesting:mocha,practicalmeteor:chai,xolvio:cleaner) and by the old auto-downgradednimble:restivus@0.6.6(which needsiron:router). Removing those removed coffeescript and unblocked the build. A trivialmeteor createapp builds fine on the same tool, confirming the crash is package-specific, not a broken tool. -
nimble:restivus— the REST API package — pinsaccounts-password@1.3.3(incompatible with 2.x) and is CoffeeScript (needs the crashing plugin). Vendored aspackages/nimble-restivus: the.coffeesources were precompiled to plain JS (lib/restivus-all.js, single translation unit so theAuth/Route/Restivusclasses share scope;Restivusleft un-var'd so Meteor'sapi.exportpicks it up), andpackage.jsloosensaccounts-passwordto 2.x and drops the coffeescript dependency. This also let restivus resolve to 0.8.12 (json-routes based), which removed the wholeiron:routerstack. REST behavior unchanged (smoke byte-identical). -
maximum:server-transform(unused) removal brokeMeteor.publishTransformedinFalsePositives/server/publications.js; no transform was actually configured, so replaced with plainMeteor.publish. -
fourseven:scss4.5.4 → 4.14.1 —node-sass@4.5.3won't build on node 12 (Meteor ≥1.9); 4.14.1 uses a node-12-compatible node-sass with prebuilt binaries. (Meteor 1.8 built it on node 8.)4.15.0needs ecmascript ≥ 0.15.1 → too new for 1.11. -
less,markdownremoved — no.less/.mdsource files; their build plugins were dead weight.
⚠️ Local build-host caveat
Meteor-tool's bundled node (12.x/14.x) SIGABRTs (node_contextify assertion) on
this machine (kernel 6.12) when certain old build plugins load — this is an
environment interaction, not a code defect (the deploy host built these fine
historically). It was fully worked around by removing the dead build plugins
above. If a future escala hits it again, build in a container matching the
deploy target (Debian) rather than on this host.
Escalas 2.4 & 2.5 — ✅ green
meteor update --release 2.4, then --release 2.5. Both trivial; npm-mongo
stays at 3.9.1 (mongodb driver 3.x). REST smoke byte-identical against
mongo:3.2 on both.
Escala ceiling vs Mongo 3.2 — landing on Meteor 2.5 (empirically verified)
Meteor bumps the bundled mongodb Node driver to 4.3.1 at Meteor 2.6, which
requires server wire version ≥ 6 (MongoDB ≥ 3.6). Production's rsmain is
Mongo 3.2 (wire version 4). Verified directly by booting 2.6 against a real
mongo:3.2:
MongoCompatibilityError: Server at localhost:27018 reports maximum wire
version 4, but this version of the Node.js Driver requires at least 6
(MongoDB 3.6)
=> Exited with code: 1
So Meteor 2.5 is the highest release that runs against the production Mongo 3.2 (npm-mongo 3.9.1). That is where this branch lands: everything green, REST smoke byte-identical. Going past 2.5 (to 2.16 or 3.x) is gated on upgrading the shared rsmain replica set to Mongo ≥ 4.4 first — the same DB blocker as 3.x.
🚧 3.x — blocked (do not run meteor update --release 3.x)
Two independent blockers, both external/coordination:
- MongoDB 3.2 → ≥ 4.4. Meteor 3's driver requires it. Shared Comunes infra (rsmain) — coordinate the DB upgrade in a separate phase. This also gates Meteor 2.5+.
- Notifications cutover. The old notif code is already removed from this
branch; production must not run this build until
tcef-notificationsis emitting in prod.
When Mongo is ≥ 4.4 and the notifications service is live in prod, the remaining
3.x work is: meteor update --release 3.x, finish the async/await migration of
server code (collections/methods/publications *Async, no Fibers), React 18
render root, and re-run the smoke test.
3.x groundwork — done on branch meteor3-wip (in progress, not deployable)
To de-risk the eventual 3.x jump, the migration was driven as far as it goes
against a modern dockerized MongoDB (the "mongo superior" decision: give
fuegos its own Mongo 7 instead of the shared rsmain 3.2, which is what actually
unblocks Meteor 3's driver). This lives on meteor3-wip; meteor3-upgrade stays
at the deployable Meteor 2.5.
Modern Mongo (local, reproducible):
docker run -d --name tcef-mongo7 -p 27019:27019 mongo:7 --replSet rs0 --port 27019 --bind_ip_all
docker exec tcef-mongo7 mongosh --port 27019 --quiet --eval 'rs.initiate({_id:"rs0",members:[{_id:0,host:"localhost:27019"}]})'
export MONGO_URL="mongodb://localhost:27019/fuegos?replicaSet=rs0"
# meteor-tool node 22 needs this to reach warehouse.meteor.com (else Happy-Eyeballs
# picks an unreachable IPv6):
export NODE_OPTIONS="--dns-result-order=ipv4first --no-network-family-autoselection"
Reached METEOR@3.1 with all package-version conflicts resolved. Dead
packages swapped for Meteor-3 equivalents:
| Old (mongo@1.x / dead) | New |
|---|---|
mongo-livedata |
removed (deprecated alias) |
facts |
facts-base |
saucecode:timezoned-synced-cron |
quave:synced-cron |
aldeed:collection2-core |
aldeed:collection2@4.0.4 |
mys:fonts (pinned caching-compiler@1.0.0) |
removed |
fourseven:scss@4.14.1 (node-sass, fails on node 22) |
@5.0.0 (Dart Sass) + sass npm |
nimble:restivus (vendored) |
accounts-password loosened to 2.0.0 || 3.0.0 |
SCSS then compiles (Dart Sass; only @import/lighten/darken deprecation
warnings — cosmetic debt: migrate to @use + color.adjust).
Blocked at the client-bundle linker: Runtime is not available, but it uses features needing the runtime: underscore — one of the old client atmosphere
packages (bert / blaze-react / cookie-consent / meteor-status / bootstrap-4 /
etc.) needs replacing for Meteor 3's linker. Beyond that, the server
async/await migration is the main remaining effort (unavoidable for 3.x):
Rest.js+ its helpers (countRealFires,firesUnion,whichAreFalsePositives,fireFromHash,subscriptionsInsert,upsertFalsePositive) use sync Mongo (findOne,find().fetch()/.count(),insert/update/remove/upsert) → must become*Async.- The vendored restivus must be patched to
awaitasync endpoint handlers (its_callEndpointuses the return value synchronously). methods.js/publications.jsacross the app,subsUnion.js,migrations.js, the Comments feature, and startup files → async.cron.jsSyncedCronimport (quave export) andfacts.jsFactsimport (facts-base export).- React 16 → 18 render root (
createRoot) instartup/client/index.js.
This is a multi-hour migration; the smoke test (now mongosh-capable, see
smoke/smoke.sh on that branch) is the gate. Resume on meteor3-wip.
Dependency debt (tracked, to resolve in the noted escala)
| Dep | From | Target | Status |
|---|---|---|---|
| React / react-dom | 16.0 | 18 | debt — deferred; ancient react-* libs (react-bootstrap 0.31, reactstrap 5-alpha, react-leaflet 1.8) break on 18. React 16 works through Meteor 2.x/3.x. Own front-end project. |
| Server async/await | Fibers | *Async APIs |
pending — prep for 3.x; 2.x still runs on Fibers so not yet required. |
| raven / flowkey:raven | 2.4 | @sentry/node + @sentry/react | debt — DSN off until GlitchTip/Sentry back (sentry.comunes.org dead → harmless boot-log timeout noise) |
| nodemailer | 4 | 6+ | pending |
| Babel | 7 beta | 7 stable | ✅ done (escala 1) |
| i18next | 10 | current | debt — pin; not on the critical path |
| Leaflet | 1.3.1 | current | debt — pin; not on the critical path |
| arkham:comments-ui | 1.4.x | — | ✅ replaced with in-repo React feature |
| nimble:restivus | Atmosphere | vendored | ✅ local precompiled package, accounts-password 2.x |
| maximum:server-transform, meteorhacks:zones, less, markdown, test stack | — | — | ✅ removed (dead/unused) |
| fourseven:scss | 4.5.4 | 4.14.1 | ✅ node-12 compatible |
| node-gcm | 1.0.2 | — | ✅ removed (dead API, moved to microservice) |
Comments React feature — verification note
The server builds and the REST smoke test is green, and the client bundle compiles, but the comments UI itself is not exercised by the smoke test (it's not part of the Flutter REST contract). It needs manual staging verification: on a fire archive page — logged-in post/edit/remove, like/dislike, and image/YouTube embed.