Skip to content
Team7 projects, up to 12 branches · 17 data modules · 610 files · 81 suites / 978 tests

Shared Package & CI Platform — Fork Realignment, 7-Project Upgrade Automation, Faster Test CI

Backend developer, then Platform Part lead · hands-on package migration, upgrade automation, and CI work

2026-02-01 — 2026-04-30

Realigned a game server's data-module fork that had drifted for 2+ years onto the shared npm package (610 files, 310+ imports migrated), automated upgrades across 7 projects with GitHub Actions (about 3 hours by hand → about 15 minutes), and cut the shared server kit's average test job time 61% (15m47s → 6m06s).

Performance Metrics

Average test job
Before: 15m47sAfter: 6m06s
61% faster · whole CI about 16 → 7 min
Package upgrade
Before: About 3h by handAfter: About 15 min automated
7-project matrix in parallel
Module alignment
Before: Fork drifted 2+ yearsAfter: npm version bump
610 files and 47 migrations deleted
Migration regression
Before: Live 500 errors reportedAfter: Hotfix in 82 min
9 related tasks tracked
Shared Package & CI Platform — Fork Realignment, 7-Project Upgrade Automation, Faster Test CI project cover image

Problem Solving

1

One game server had forked the shared data modules and gone 2+ years without realigning with upstream, so replacing its 17 internal modules with the evolving npm package meant moving 610 files and 310+ imports.

  1. Symptom: Fork 2+ years behind · 610 files · 310+ imports
  2. Fix: Module → package → latest version, in two steps
  3. Fix: Game-specific features kept in six thin wrappers
  4. Result: 610 files and 47 migrations deleted · features via version bump
Solution Process

Using the alignment approach other games already followed, I split the work into two stages: first switch the internal modules to the package, then bring it to the latest version with the same pattern and package-managed migrations. Game-specific features (localization, forbidden words, dynamic environments, and so on) stayed in six thin wrapper modules.

Result

Deleted the 610 internal-module files and 47 local migrations; new features can now come in with a package version bump. When the migration caused a regression that returned 500 errors in a live admin feature, a hotfix shipped 82 minutes after the report, and the work was tracked as 9 related tasks including the migration itself.

2

Every shared-package release meant upgrading the main/develop branches of 7 projects (up to 12 branches) by hand, taking about 3 hours plus the cost of context switching.

  1. Symptom: 7 projects · up to 12 branches by hand · ~3h
  2. Fix: workflow_dispatch + a 7-project matrix in parallel
  3. Result: ~15 min · skip/upgrade/downgrade in the Job Summary
Solution Process

Built a GitHub Actions workflow triggered by workflow_dispatch that processes the 7 projects in parallel with a matrix, recording each project's outcome as skip/upgrade/downgrade in the Job Summary.

Result

Upgrades went from about 3 hours by hand to about 15 minutes automated.

3

In the shared server kit, ts-jest compilation took about 15s per file, 53% of test time, so even pure unit tests took 15–19s.

  1. Symptom: Even pure unit tests took 15–19s
  2. Evidence: ts-jest compile: 53% of test time · ~15s per file
  3. Fix: isolatedModules · type checks moved to tsc --noEmit
  4. Result: Avg test job 15m47s→6m06s (61%) · 978 tests pass
Solution Process

Switched ts-jest to isolatedModules so each file is transformed on its own, leaving type checking to a separate tsc --noEmit step in CI. In this mode decorator metadata cannot see types from other files, so I declared column types explicitly on the 4 affected entities.

Result

Per-file compile 15s → 1–3s, average test job across 4 shards 15m47s → 6m06s (61% faster), whole CI including build and quality checks about 16 → about 7 minutes. All 81 suites / 978 tests passing.

Operating limits

Under isolatedModules the test step does no type checking, so type errors are caught by a separate tsc --noEmit step in CI.
Projects without the upgrade automation still needed manual rollouts; one of them was checked for backward compatibility by comparing 1,073 fields byte for byte, excluding comments.
The migration regression was found on live after deploy; pre-release tests did not catch it.

Project Description

One game server had forked the shared game data modules and gone 2+ years without realigning, shared-package upgrades were repeated by hand across 7 projects, and the shared server kit's tests spent their time in ts-jest compilation. I realigned the fork onto the npm package with package-managed migrations, automated upgrades with workflow_dispatch plus a matrix, and cut test compilation by switching to isolatedModules. The live regression during the migration and its recovery are included. Internal product and game names are replaced with generic names.

Highlights

  • Replaced 17 data modules in a game server that had drifted from upstream for 2+ years with the shared npm package: deleted 610 files and 47 local migrations, updated 310+ imports
  • Data-module features can now come in with a package version bump, and the schema follows a package-managed migration CLI
  • Parallelized upgrades across 7 projects (up to 12 branches) with workflow_dispatch and a matrix, reporting skip/upgrade/downgrade in the Job Summary: about 3 hours by hand → about 15 minutes
  • Switched ts-jest to isolatedModules: per-file compile about 15s → 1–3s, average test job 15m47s → 6m06s (61%), whole CI about 16 → about 7 minutes

Tech Decisions

  • ▶Realign with upstream instead of keeping the fork: game-specific differences live in wrapper modules and the rest belongs to the package, so later updates are just a version bump.
  • ▶Two-stage migration: switch the internal modules to the package first, then align patterns and migrations with the latest version, so fewer kinds of change land at once.
  • ▶Automate upgrades with a matrix: each project's result goes into the Job Summary, so skipped and failed projects show up on one screen.
  • ▶isolatedModules for tests: per-file transforms cut compile time, and the decorator type gap it creates is filled by explicit column types.

Lessons Learned

  • •A fork gets more expensive to realign the longer it lives; keep game-specific differences in wrappers and leave the rest to the shared package.
  • •Automate work that repeats once per project, and keep the results on one screen so gaps are visible.
  • •A check turned off for speed needs a new owner: type checking moved to a separate tsc step, and explicit column types filled the decorator-metadata gap.

Tech Stack

TypeScriptNestJSnpm packagesGitHub ActionsJest (ts-jest)TypeORM