diff --git a/README.md b/README.md index f9de523..67751ca 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ pnpm docs:preview - [플레이어 가이드](docs/user/index.md) - [아키텍처 개요](docs/architecture/overview.md) - [런타임 아키텍처](docs/architecture/runtime.md) +- [릴리스 운영 매뉴얼](docs/release-operations.md) - [차등 검증](docs/architecture/turn-state-differential-testing.md) - [Caddy prefix 계약](docs/e2e-caddy-routing.md) - [레거시 DB 이관](docs/legacy-db-migration.md) diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 87159fc..73fbc78 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -13,6 +13,7 @@ export default defineConfig({ { text: '개발자', link: '/developer/' }, { text: '플레이어', link: '/user/' }, { text: '아키텍처', link: '/architecture/overview' }, + { text: '릴리스 운영', link: '/release-operations' }, ], sidebar: { '/developer/': [ @@ -22,6 +23,7 @@ export default defineConfig({ { text: '시작하기', link: '/developer/' }, { text: '아키텍처 개요', link: '/architecture/overview' }, { text: '런타임 아키텍처', link: '/architecture/runtime' }, + { text: '릴리스 운영 매뉴얼', link: '/release-operations' }, { text: '요청·턴·저장 흐름', link: '/developer/request-turn-persistence' }, { text: '도메인 로직과 핵심 클래스', link: '/developer/domain-and-classes' }, { text: '파일 지도와 변경 절차', link: '/developer/code-map' }, diff --git a/docs/developer/index.md b/docs/developer/index.md index 940af07..16ad2fb 100644 --- a/docs/developer/index.md +++ b/docs/developer/index.md @@ -2,15 +2,16 @@ ## 읽기 순서 -| 작업 | 문서 | 코드 시작점 | -| --------------------- | --------------------------------------------------------------- | ----------------------------- | -| 전체 구조 | [아키텍처 개요](../architecture/overview.md) | `app/`, `packages/`, `tools/` | -| process·worker·daemon | [런타임 아키텍처](../architecture/runtime.md) | app server와 CLI | -| 파일 위치 | [파일 지도](./code-map.md) | router, handler, schema | -| 명령·전투·효과 | [도메인과 조립](./domain-and-classes.md) | `packages/logic` | -| mutation·flush | [요청·턴·저장](./request-turn-persistence.md) | game API, game engine | -| action module | [행동 모듈 프로토콜](../architecture/action-module-protocol.md) | `actionModules/` | -| ref 비교 | [차등 검증](../architecture/turn-state-differential-testing.md) | `tools/integration-tests` | +| 작업 | 문서 | 코드 시작점 | +| --------------------- | --------------------------------------------------------------- | ------------------------------ | +| 전체 구조 | [아키텍처 개요](../architecture/overview.md) | `app/`, `packages/`, `tools/` | +| process·worker·daemon | [런타임 아키텍처](../architecture/runtime.md) | app server와 CLI | +| profile·Gateway 배포 | [릴리스 운영 매뉴얼](../release-operations.md) | Admin GUI와 release-controller | +| 파일 위치 | [파일 지도](./code-map.md) | router, handler, schema | +| 명령·전투·효과 | [도메인과 조립](./domain-and-classes.md) | `packages/logic` | +| mutation·flush | [요청·턴·저장](./request-turn-persistence.md) | game API, game engine | +| action module | [행동 모듈 프로토콜](../architecture/action-module-protocol.md) | `actionModules/` | +| ref 비교 | [차등 검증](../architecture/turn-state-differential-testing.md) | `tools/integration-tests` | ## 경계 diff --git a/docs/index.md b/docs/index.md index ff0285c..a53475c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,6 +12,9 @@ hero: - theme: alt text: 플레이어 가이드 link: /user/ + - theme: alt + text: 릴리스 운영 + link: /release-operations features: - title: 시스템 구조 @@ -27,7 +30,8 @@ features: 개발자는 [개발자 핸드북](./developer/index.md)과 [아키텍처 개요](./architecture/overview.md)에서 시작해 주세요. 플레이어는 [시간과 턴](./user/time-and-turns.md)과 -[커맨드 목록](./user/command-catalog.generated.md)을 확인해 주세요. +[커맨드 목록](./user/command-catalog.generated.md)을 확인해 주세요. Profile과 +Gateway 배포는 [릴리스 운영 매뉴얼](./release-operations.md)을 따라 주세요. 세부 문서는 다음 책임으로 나뉩니다. diff --git a/docs/release-operations.md b/docs/release-operations.md new file mode 100644 index 0000000..58220c3 --- /dev/null +++ b/docs/release-operations.md @@ -0,0 +1,165 @@ +# 릴리스 운영 매뉴얼 + +이 문서는 Core2026의 profile 서버와 Gateway를 Git commit 단위로 배포하고 +되돌리는 현재 운영 경계를 설명합니다. Profile은 Gateway orchestrator가, +Gateway 전체는 별도 release-controller가 처리합니다. + +## 구성과 권한 + +| 대상 | 요청 경로 | 실행자 | 영속 상태 | +| --------------------------------- | ------------------- | ----------------------- | ------------------------------------------------ | +| `che`, `hwe` 등 profile | Gateway 관리자 화면 | Gateway orchestrator | `GatewayOperation`, `GatewayProfile` | +| Gateway API·frontend·orchestrator | Gateway 관리자 화면 | 외부 release-controller | `GatewayReleaseOperation`, `GatewayReleaseState` | +| release-controller 자체 | 별도 CLI process | self-upgrade CLI | PM2 `sammo:release-controller` | + +관리자 화면은 `/gateway/admin/server-operations`입니다. Profile 작업에는 해당 +profile의 `admin.profiles.manage` 권한이 필요합니다. Gateway 전체 릴리스에는 +profile 범위 권한과 별개인 전역 `admin.releases.manage` 권한이 필요합니다. +일반 사용자와 권한이 없는 관리자는 Gateway 릴리스 영역을 사용할 수 없습니다. + +운영 전에 다음을 확인해 주세요. + +- 대상 branch 또는 전체 commit SHA가 Core2026 저장소에 존재합니다. +- 대상 commit의 `release-manifest.json`에 필요한 component와 현재 migration + head가 들어 있습니다. +- Gateway PostgreSQL, profile PostgreSQL, Redis와 PM2가 준비되어 있습니다. +- controller가 `GATEWAY_DATABASE_URL`, `GATEWAY_DB_SCHEMA`, workspace와 + worktree 경로를 올바르게 읽습니다. +- migration 이후 이전 애플리케이션으로 돌아갈 때 schema 하위 호환성이 + 유지됩니다. + +## Profile 배포 + +관리자 화면에서 profile과 branch 또는 commit을 선택합니다. Branch는 worker가 +작업을 claim할 때 commit으로 해석하며, commit 입력은 전체 SHA로 고정됩니다. +같은 profile에는 `QUEUED` 또는 `RUNNING` 작업을 동시에 하나만 둘 수 있습니다. + +### DB 유지 배포 + +`DB 유지 배포`는 현재 시즌을 계속 운영하면서 코드를 교체할 때 사용합니다. + +1. 대상 commit의 game frontend, API, engine과 worker artifact를 빌드합니다. +2. 기존 profile PM2 process를 정지합니다. +3. profile game schema에 `prisma migrate deploy`를 실행합니다. +4. Scenario seed를 실행하지 않고 frontend, API, daemon과 worker를 시작합니다. +5. HTTP와 모든 PM2 role의 readiness가 확인된 뒤 build commit을 게시합니다. + +이 모드는 현재 scenario, status와 인게임 DB를 유지합니다. Migration이 +데이터를 변환할 수 있으므로 대상 migration의 운영 데이터 영향은 배포 전에 +별도로 검토해 주세요. + +### DB 초기화 배포 + +`DB 초기화 배포`는 새 시즌이나 새 scenario로 현 시즌 데이터를 교체할 때 +사용합니다. Source와 scenario를 먼저 불러온 뒤 turn 간격, 가오픈·정식 오픈, +NPC와 자동 진행 설정을 확인하고 요청해 주세요. + +이 모드는 build와 migration 후 scenario seeder를 실행합니다. 현 시즌의 장수, +국가, 도시, command queue와 시장·경매 등은 새 scenario 기준으로 교체됩니다. +다음 장기보존 자료는 reset 범위 밖에 있으므로 기수를 넘어 유지됩니다. + +- `hall`, `ng_games` 명예의 전당과 게임 이력 +- 연감과 과거 장수·국가 기록 +- 왕조·상속 자료 +- legacy storage와 진단·오류 기록 + +초기화 작업은 되돌릴 수 있는 앱 rollback과 다릅니다. 운영 DB backup과 새 +scenario 설정을 확인한 뒤 실행해 주세요. + +### Profile 실패와 재시도 + +Build는 현재 runtime을 멈추기 전에 수행합니다. Migration 또는 새 process +readiness가 실패하면 작업은 `FAILED`가 되며 orchestrator는 이전 worktree의 +process 복구를 시도합니다. 관리자 화면의 오류와 PM2 process 상태를 확인한 +뒤 원인을 해결하고 실패한 작업을 재시도해 주세요. 재시도는 처음 고정된 commit을 +사용합니다. + +## Gateway 전체 배포 + +Gateway는 자기 process를 직접 교체하지 않습니다. 관리자 화면에서 `Gateway +배포`를 요청하면 외부 `sammo:release-controller`가 다음 순서로 처리합니다. + +1. Source ref를 commit SHA로 고정하고 commit worktree를 준비합니다. +2. Release manifest의 protocol, component와 migration head를 검증합니다. +3. Gateway API와 frontend를 빌드하고 gateway migration을 적용합니다. +4. `sammo:gateway-api`, `sammo:gateway-frontend`, + `sammo:gateway-orchestrator`를 새 worktree definition으로 전환합니다. +5. Gateway API `/healthz`, `/gateway/`와 세 PM2 process의 `online` 상태를 + 확인합니다. +6. 모두 준비된 경우에만 현재·이전 commit과 workspace를 게시합니다. + +Gateway 전체에는 활성 릴리스 작업을 동시에 하나만 둘 수 있습니다. 화면의 +릴리스 이력에서 요청 source, 고정 commit, 상태와 오류를 확인할 수 있습니다. + +### Gateway rollback + +`이전 Gateway로 rollback`은 `GatewayReleaseState`에 기록된 바로 이전 commit을 +다시 배포합니다. 새 Gateway의 readiness가 실패하면 controller는 이전 세 +process definition을 복구합니다. + +Prisma migration은 역방향으로 적용하지 않습니다. 따라서 rollback 대상 앱이 +이미 적용된 새 gateway schema를 읽을 수 있어야 합니다. Schema 호환성이 +확인되지 않은 릴리스는 GUI rollback에 의존하지 말고 backup·restore를 포함한 +별도 복구 절차를 준비해 주세요. + +## Release-controller CLI + +CLI는 repository 루트에서 Git에 포함되지 않은 안전한 환경 변수 또는 secret +주입 상태로 실행합니다. 실제 database URL이나 credential을 명령행, 로그 또는 +문서에 남기지 말아 주세요. + +현재 릴리스 상태와 최근 작업을 확인합니다. + +```sh +pnpm --filter @sammo-ts/release-controller status +``` + +대기 중인 Gateway 작업을 한 건만 처리하고 종료합니다. + +```sh +pnpm --filter @sammo-ts/release-controller run-once +``` + +운영 daemon은 `app/release-controller/dist/index.js daemon`을 +`sammo:release-controller` PM2 process로 실행합니다. 상세한 최초 설치와 환경 +변수는 저장소의 `app/release-controller/README.md`를 확인해 주세요. + +### Controller self-upgrade + +Self-upgrade는 실행 중인 controller daemon과 다른 shell/CLI process에서 +실행해 주세요. 대상 worktree를 준비하고 build와 gateway migration을 마친 뒤 +controller PM2 definition만 전환합니다. + +```sh +pnpm --filter @sammo-ts/release-controller build +pnpm --filter @sammo-ts/release-controller self-upgrade -- BRANCH main +# 또는 +pnpm --filter @sammo-ts/release-controller self-upgrade -- COMMIT +``` + +새 controller가 제한 시간 안에 `online`이 되지 않으면 이전 definition을 +복구합니다. Self-upgrade 중에도 migration downgrade는 수행하지 않습니다. + +## 운영 확인 목록 + +배포 전: + +- Source commit과 `release-manifest.json`을 확인합니다. +- DB backup, migration 영향과 rollback schema 호환성을 확인합니다. +- 대상 profile과 Gateway의 현재 commit·workspace를 기록합니다. +- controller, PostgreSQL, Redis와 PM2 상태를 확인합니다. + +배포 후: + +- 작업이 `SUCCEEDED`이고 고정 commit이 요청한 commit과 같은지 확인합니다. +- PM2의 cwd와 script가 게시된 worktree를 가리키는지 확인합니다. +- `/gateway/` 또는 대상 profile prefix에 직접 접속하고 새로고침합니다. +- API health, tRPC, SSE와 정적 자산 경로를 확인합니다. +- DB 유지 배포에서는 현재 season/scenario와 핵심 게임 상태가 유지됐는지 + 확인합니다. +- DB 초기화 배포에서는 새 시즌 상태와 명예의 전당·연감 등 장기보존 자료를 + 함께 확인합니다. + +Local unit, 격리 DB integration과 fixture Chromium 통과는 운영 PM2, 외부 +Caddy/HTTPS, 방화벽과 실제 운영 DB 전환을 증명하지 않습니다. 운영 배포에서는 +위 확인 목록을 실제 서비스 경로에서 다시 수행해 주세요.