본문으로 건너뛰기

Migration Readiness

Status

Active

Date

2026-04-28

Owners

  • Platform Backend

Last Verified Commit

Use git log -- <this file> for current last-touch history; this field is intentionally not pinned to a static hash so it does not become stale after unrelated commits.

Goal

Track whether servers_v2 can replace the legacy servers/ runtime without user-visible or external-integration-visible regressions.

Current Decision

servers_v2 is ready for slice-based cutover in several areas, but it is not yet ready for a full one-shot replacement of the entire servers/ tree.

Readiness Matrix

Legacy Scopeservers_v2 ReplacementCurrent StateEvidence
web_server player routesgateway + domain servicesready for controlled cutovergateway route parity review and contract tests
agent_serveragent_serviceready for controlled cutoverroute parity review and test_agent_integration.py
game_servergame_serviceready for controlled cutoverroute parity review and test_legacy_contracts.py
middle_server recon slicerecon_service + admin_service top-info aggregationready for controlled cutoverrecon service routes, admin top-info aggregation tests, local Docker validation
middle_server web CMS sliceremoved by ADR-009; callers must migrate or retirenot readylegacy web routes were deleted from admin_service
wallet_server split domain behaviorwallet_service + rolling_service + promotion_serviceoperationally strong, but depends on caller cutoverworker and contract tests
whole legacy back-office sidecar scopepartially admin_service, partially unmappednot readydocs/runbooks/legacy-middle-server-retirement.md (per-prefix migration plan); 410-Gone + Sunset stubs in servers_v2/admin_service/app/api/routes/legacy_sunset.py fail loud for any forgotten caller

What Is Already Strong

  • player-facing gateway compatibility is documented and covered by route contract tests
  • agent-facing compatibility exists with zero old-only route gaps in the current comparison
  • provider callback surface exists with zero old-only route gaps in the current comparison
  • recon extraction is now documented, implemented, workerized, and locally Docker-tested
  • admin top-info can aggregate recon counts without reintroducing the deleted legacy recon route surface
  • worker health and settlement semantics now align with production expectations better than the legacy stack

What Still Blocks Full Legacy Retirement

The main blocker is not the player, agent, or provider path. It is the remaining middle_server scope that still has active or potentially active frontend callers:

  • /api/admin/role/*
  • /api/admin/menu/*
  • /api/admin/config/*
  • /api/admin/i18n/*
  • /api/admin/bi/*
  • /coin/*
  • generic catch-all forwarding behavior from legacy POST /{path:path}

/api/admin/web/* was previously not a blocker as of the 2026-04-22 admin compatibility migration; under ADR-009 (2026-04-27) the legacy web content compatibility surface (legacy_web_content.py) is deleted together with the rest of the staff-coupled legacy files. Any bo/admin consumer that still depends on /api/admin/web/rules/*, /api/admin/web/faq/*, or /api/admin/web/config/* must be migrated or retired before that deletion lands.

Compatibility evidence for this slice:

  • servers_v2/admin_service/tests/test_admin_integration.py
  • docs/runbooks/legacy-middle-server-retirement.md — per-prefix migration plan, owners, effort estimates, cut-over sequence
  • servers_v2/admin_service/app/api/routes/legacy_sunset.py — 410-Gone + Sunset + Deprecation stubs so forgotten callers fail loud instead of silent-404
  • servers_v2/admin_service/tests/test_legacy_sunset.py — guard test locking the 410 + header + auth contract so a regression cannot re-add a 200 OK to a retired prefix

Posture Summary (2026-05-06)

servers_v2 is production-ready for slice-based cutover of the following surfaces. Each item below is shipping-grade as of this posture entry — they have route parity, contract tests, and operational runbooks.

  • player gateway traffic
  • agent service traffic
  • provider callbacks
  • recon worker
  • multi-brand isolation (Phase 16 hard-flip closed)

servers_v2 does NOT cover the following surfaces and they remain on the legacy servers/ runtime until a named migration or retirement project is chartered, implemented, and validated:

  • /api/admin/role/*
  • /api/admin/menu/*
  • /api/admin/config/*
  • /api/admin/i18n/*
  • /api/admin/bi/*
  • /coin/*
  • legacy back-office catch-all POST /{path:path}

There is no in-flight project to migrate the surfaces above. Any document or release announcement that claims "full replacement of the legacy servers/ tree" is incorrect and must be corrected. The honest posture is: servers_v2 plus residual servers/ middle_server slice, co-deployed.

If a future project is chartered to migrate any of these surfaces, the corresponding bullet above should be moved into the readiness matrix and this section updated to reflect the new shipping-grade scope.

Production Claim Guardrails

Use these statements when preparing release notes, migration plans, or operator handoff docs:

ClaimCurrent StatusRequired Wording
servers_v2 can receive selected production traffictrue for listed slices"production-ready for controlled slice-based cutover of player gateway, agent, provider callbacks, recon worker, and Phase-16 multi-brand isolation"
servers_v2 fully replaces legacy servers/falsedo not claim; residual middle_server sidecar must co-exist
legacy middle_server can be retiredfalsedo not claim; the seven-prefix retirement runbook is planning-only
service data ownership is independently deployablefalsedo not claim; services share PostgreSQL and one Alembic chain, and wallet still writes legacy player-balance compatibility fields
all emitted events are consumedfalsedo not claim; several wallet, rolling, player, and agent events are producer-only

A full-platform production closure announcement requires all four gates to be green at the same time: legacy route retirement, frontend caller migration, data-ownership exit gates, and event-consumer closure gates. Slice readiness does not imply any of the other three.

Non-Closure Gate Matrix

This matrix is the release-note and operator-handoff source of truth for what is still not closed. A row can move to true only in the same change that updates the governing architecture doc, service doc, implementation evidence, and guard tests.

GateCurrent StatusBlocking EvidenceExit Condition
Full legacy replacementfalsemiddle_server web CMS is removed, whole back-office sidecar scope is still partially unmapped, and the seven residual prefixes remain planning-only.Every remaining legacy route family is migrated or explicitly retired, frontend callers are proven migrated by replay/access logs, and the legacy sidecar is no longer required.
Data ownership closurefalseServices still share PostgreSQL and one Alembic chain; wallet_service still writes legacy player-balance compatibility fields; agent-domain money writes still bypass the final owner boundary.Per-service migration ownership/deploy order is tested, legacy player-balance compatibility writes are removed or projection-only, and agent-domain money writes move behind the replacement owner command path.
Event graph closurefalseDEPOSIT_APPROVED, WITHDRAW_APPROVED, and ROLLING_COMPLETED_CONFIRMED are emitted but producer-only; rolling/player/agent stream events are future projection surfaces unless named in event-catalog.md.Every production-significant emitted event has an active consumer group, deployed worker, idempotency/inbox handling, health signals, and dispatch-path tests, or is intentionally documented as producer-only.
Agent-money Single Money Writer closurefalseadmin_service and agent_service still directly mutate agent.balance / agent.coupon while emitting agent_balance_legacy_write_total; ADR-010 is a proposed multi-phase migration, not an implemented closure.agent_balance_legacy_write_total == 0 for the required observation window, legacy direct write call sites are removed, and agent money commands terminate in the wallet-owned command path.

Multi-Brand Migration Readiness

Per ADR-009, multi-brand isolation is implemented as a forward migration, not a separate cutover:

  • a default brand is seeded at migration time and every existing row is backfilled into it via column-level DEFAULT (see plan Phase 2);
  • the existing single-brand environment continues to operate against the default brand throughout every implementation phase;
  • gateway JWT/domain enforcement was staged through observe mode during the rollout; the repository compose default is now enforce after the Phase 16 in-repo closure.

Multi-brand readiness is tracked separately from the legacy-cutover matrix above. A second brand is enabled only after the multi-brand runbook's release gate (docs/runbooks/multi-brand/multi-brand-isolation-rollout.md) passes.

Cutover Guidance

Safe current cutover candidates:

  • player web traffic to gateway
  • agent frontend traffic to agent_service
  • provider callbacks to game_service
  • recon shooter/pushbullet workflows to admin_service + recon_service

Do not declare full legacy replacement complete until:

  1. every remaining middle_server route family is either migrated or explicitly retired
  2. bo/admin no longer depends on unmapped legacy route families
  3. the team chooses whether any generic forwarding behavior is intentionally removed or must be replaced explicitly
  4. migration runbooks are updated to reflect the final target state
  5. data-ownership docs confirm no blocking legacy write boundary remains for the claim being made
  6. event-catalog docs confirm every event needed by the claim has an active consumer or is intentionally producer-only