diff --git a/AGENTS.md b/AGENTS.md index 6d4107d..b43ddb8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,152 +1,358 @@ -# Repository Guidelines +# core2026 작업 지침 -## Project Goal (Rewrite) +## 적용 범위와 목표 -- This repository is transitioning from the legacy PHP codebase to a TypeScript-based monorepo using pnpm workspaces. -- The legacy game remains the current active source under `legacy/` while the rewrite is prepared alongside it. -- Legacy data under `legacy/` is for migration only; once DB migration is complete, - the runtime will no longer depend on legacy data. +이 파일은 `core2026/` 전체에 적용됩니다. 하위 디렉터리에 더 가까운 +`AGENTS.md`가 생기면 사용자 지시, 가까운 파일, 이 파일, 상위 작업공간 +지침 순으로 적용합니다. -## Project Naming +목표는 `../ref/sam`의 PHP 서비스를 TypeScript 런타임으로 호환 이관하는 +것입니다. 내부 구조를 더 깔끔하게 만드는 일보다 기존 결과, 상태 전이, 권한, +화면과 운영 경계를 보존하는 일이 우선입니다. -- Official name: 삼국지 모의전투 HiDCHe -- Common nicknames: 삼모, 삼모전, 힏체섭 -- Short forms in code/docs: sammo, hidche -- TypeScript rewrite working name: sammo-ts +## 현재 기준과 저장소 경계 -## Project Structure & Module Organization +- `core2026/`은 제품 구현 저장소입니다. gateway/game frontend·API, game engine, + 공통 package, Prisma와 검증 도구가 실제로 존재합니다. +- PHP 기준 구현은 이 저장소 내부 `legacy/`가 아니라 `../ref/sam`입니다. + `devel`은 변경하지 않는 기준선이고 비교 fixture·계측은 `ng_compare`에만 + 두어 주세요. +- 아키텍처 매핑과 보고서는 별도 상위 저장소의 + `../docs/ref-core2026-mapping.md`, `../report/`에 있습니다. 두 Git 경계의 + commit과 상태를 혼동하지 말아 주세요. +- 이미지의 운영 소유자는 외부 Caddy의 `/image/*`입니다. 제품 저장소에 무단 + 복제하거나 앱 경로로 rewrite하지 말아 주세요. -- `legacy/` contains the application source. This is the active codebase. -- PHP entry points live under `legacy/` and `legacy/hwe/` (for example `legacy/index.php`, `legacy/hwe/index.php`). -- `legacy/src/sammo/` contains core utility classes for the `sammo\\` namespace. -- Core PHP domain logic lives under `legacy/hwe/sammo/` (also part of the `sammo\\` namespace). -- Frontend TypeScript/Vue sources are in `legacy/hwe/ts/` with shared components in `legacy/hwe/ts/components/`. -- Styles are split between `legacy/css/` and SCSS in `legacy/hwe/scss/`. -- Tests: PHPUnit in `legacy/tests/`, TypeScript tests in `legacy/hwe/test-ts/`. -- Static data/assets: scenarios in `legacy/hwe/scenario/`, templates in `legacy/hwe/templates/`. -- Image storage listing (ls -R dump): `docs/image-storage.md`. +작업 시작과 종료에 최소한 다음을 확인해 주세요. -## Legacy Endpoint Patterns +```sh +git status --short --branch +git remote -v +git rev-parse HEAD +``` -- JSON API handlers: `legacy/hwe/j_*.php`. -- Vue multi-entry pages: `legacy/hwe/v_*.php`. -- Legacy PHP + jQuery pages: `legacy/hwe/b_*.php` with POST handlers in `legacy/hwe/c_*.php`. -- Modern API router: `legacy/hwe/api.php` accepts a path argument and dispatches to `legacy/hwe/API/` modules. +상위 매핑/보고서를 바꾸면 상위 저장소에서도 같은 검사를 별도로 수행해 주세요. +dirty 파일은 사용자의 변경일 수 있으므로 관련 없는 수정, 정리, stage, +commit 또는 삭제를 하지 말아 주세요. -## Planned Monorepo Layout (TypeScript Rewrite) +## 완료 상태를 해석하는 법 -- `/packages/common`: shared utilities and type definitions. - - Frequently used utility functions should be registered here and utilized. -- `/packages/infra`: Prisma/Redis connectors and other runtime infra. -- `/packages/logic`: pure game logic with DI/interfaces for external dependencies. -- `/app/gateway-frontend`: Gateway UI application. -- `/app/gateway-api`: Gateway backend service. -- `/app/game-frontend`: Game UI application. -- `/app/game-api`: Game backend service per server+scenario profile. -- `/app/game-engine`: Game engine / turn daemon per server+scenario profile. -- `/tools/build-scripts`: build and deployment scripts. +2026-07-27의 백엔드 누락 감사에서는 현재 `main`에서 재현 가능한 구체적 +미구현·미병합 항목을 찾지 못했습니다. 이를 “이관 전체 완료”로 해석하지 말아 주세요. -## Planned Runtime & Tooling +- 새 차등 fixture가 mismatch를 드러내면 다시 제품 결함으로 분류해 주세요. +- green unit test는 ref 호환, 실제 DB transaction, Chromium geometry 또는 + 운영 장애 복구를 자동으로 증명하지 않습니다. +- 환경 변수가 없는 기본 test에서 skip된 integration은 실행된 검증이 아닙니다. +- local/mock prefix E2E와 실제 외부 Caddy·host/firewall 검증은 별도입니다. +- report 제목의 `완료`보다 현재 코드, Git ancestry, 실행 경로와 재현 결과를 + 우선합니다. -- TypeScript: `6.0.2` (workspace-wide fixed version) - - TypeScript 7 is temporarily excluded because compiler/tooling APIs required - by this repository and its toolchain are not yet available or compatible. - - Keep `app/*`, `packages/*`, and `tools/*` on the same exact TypeScript - version. Do not add a package-local TypeScript 5 or 7 override. - - Upgrade to TypeScript 7 only after the required APIs and dependent tooling - are available and the repository-wide typecheck, lint, build, tests, and - comparison tools pass. See `docs/architecture/typescript-version.md`. -- Backend: Node.js + Fastify, with Prisma ORM. -- Turn daemon: turn scheduler/resolver service for game ticks. -- Turn daemon and API server communicate via Redis Stream or Redis pub/sub. -- API server and frontend may use SSE for live updates. -- API: tRPC + zod. -- Frontend: Vue 3, Pinia, Vue Router, TailwindCSS, Vite. -- Data: PostgreSQL; sessions backed by Redis. -- Testing: Vitest. -- Package manager: pnpm (workspace-based monorepo). -- Build output: server builds emitted to `/dist/{profileName}` per profile. +기능 작업 전에 관련 매핑 항목과 최신 report를 읽고, 오래된 결론은 현재 +코드와 commit으로 다시 확인해 주세요. -## Suggested Monorepo Scripts (Proposal) +## 실제 구조와 책임 -These are placeholders to align teams; adjust once packages exist. +- `app/gateway-frontend`: 가입·로그인, 로비, 계정, 관리자 운영 UI +- `app/gateway-api`: 계정·세션·profile 정책, operation queue와 PM2 + orchestration +- `app/game-frontend`: profile별 게임 SPA와 ref 호환 UI +- `app/game-api`: tRPC/SSE, 조회·입력 API와 battle/auction/tournament worker +- `app/game-engine`: turn daemon, scheduler, 월간 lifecycle와 DB flush +- `packages/common`: 타입, 직렬화, RNG와 공통 유틸리티 +- `packages/logic`: 전투·명령·월간 action 등 도메인 로직 +- `packages/infra`: gateway/game Prisma schema, migration과 client +- `tools/integration-tests`: PostgreSQL/Redis 및 ref↔core 차등 +- `tools/frontend-legacy-parity`: 실제 Chromium 비교 +- `tools/legacy-db-migration`: 장기보존 데이터 CLI 이관 -- `pnpm install`: install all workspace dependencies. -- `pnpm typecheck`: run TypeScript type checks in all packages (via turbo). -- `pnpm lint`: lint all packages (via turbo). -- `pnpm test`: run all unit tests (via turbo). -- `pnpm build`: build all packages/apps (via turbo). -- `pnpm dev`: run dev servers where applicable (via turbo). -- `pnpm --filter ./app/game-frontend dev`: run a single app by filter. -- `pnpm --filter ./app/game-api dev`: run a single service by filter. -- `pnpm --filter ./app/game-engine dev`: run a single service by filter. +`tools/build-scripts/build-server.mjs`는 현재 profile resource 복사 +placeholder입니다. 이를 완성된 배포 bundle이나 검증된 profile build로 설명하지 +않습니다. 운영 build/reset/open은 gateway operation, commit별 worktree와 +orchestrator 실행 경로를 조사해 주세요. -## Development Checklist (AI) +## 레거시 매핑과 비교 -- After code changes, the AI MUST run `CI=1 pnpm typecheck`. -- When changes require unit tests, run the relevant tests. - - For game engine changes, run (example): - `pnpm --filter @sammo-ts/game-engine test npcNationUprisingUnification`. - - Do NOT insert `--` after `test` when passing a Vitest file/name filter; it breaks the filter here. - Use `pnpm --filter @sammo-ts/game-engine test npcNationTechResearch.test.ts` (no `--`). -- When migrating existing functionality, keep text and log output identical to the legacy behavior unless there is a technical blocker. +기능을 변경하기 전에 다음을 end-to-end로 연결해 주세요. -## Build Profiles (Proposal) +1. ref entry point와 호출 순서 +2. PHP domain class, SQL read/write, template/CSS/JS와 사용자 출력 +3. core service/router/action/loader/flush와 frontend 호출부 +4. session/auth, validation, transaction, 비동기 경계와 오류 복구 +5. RNG 생성·소비와 persistence 순서 -- A build profile is a server+scenario pair; scenario selection is required even if a default exists. -- Server builds should accept a profile (server variant) plus an explicit scenario file input. -- Recommended pattern: `pnpm build:server --profile che --scenario default`. -- Prefer environment variables for CI/CD (`PROFILE=che SCENARIO=default pnpm build:server`) and a small wrapper script for local usage. -- Build output stays in `/dist/{profileName}` per profile to keep deployments predictable. -- Profile selection can target different git branches or specific commits; server operators decide the compatibility baseline. -- The scenario file determines unit sets and DB settings that must be prepared before build output is emitted. +`../docs/ref-core2026-mapping.md`에는 1:1 대응을 억지로 만들지 말고 1:N/N:1 +소유권과 변환 지점을 기록해 주세요. `확인`, `부분 확인`, `가설`, `미구현`, +`의도적 차이`를 근거와 함께 사용해 주세요. 문서와 코드가 다르면 먼저 양쪽 기준 +commit과 실제 실행을 확인하고 사실관계를 고쳐 주세요. -## Server Profiles (Planned) +ref 계측이 필요하면 다음을 지켜 주세요. -- Server IDs: `che`, `kwe`, `pwe`, `twe`, `nya`, `pya` -- Each build/run profile combines a server ID with a scenario selection. +- `devel`에 test, endpoint, fixture나 debug 코드를 commit하지 말아 주세요. +- 기존 `ng_compare` 이력과 분기 기준을 조사하고 reset/overwrite하지 말아 주세요. +- 계측은 최소·deterministic·가능하면 read-only로 두고 test 환경 guard를 + 사용해 주세요. +- 계측 유무가 결과, RNG 소비, DB mutation과 출력 순서를 바꾸지 않는지 + 확인해 주세요. +- ref와 core 변경은 서로 다른 저장소와 commit으로 관리해 주세요. -## Game Domain Notes (Behavioral Context) +## 호환성 우선순위 -- Turn-based multiplayer loop with configurable tick length (historically 120/60/30/20/10/5/2/1 min; experimental day/night schedules). -- Core stats: leadership, strength, intelligence with effects on internal affairs and combat. -- Traits and modifiers apply via the Trigger system, evaluated by priority; "attempt" then "execute". -- Scenarios define maps, NPCs, initial resources; scenario loading separated to allow future modding. -- "Unit packs" bundle unit graphics, audio, and special effects per scenario. +1. 전투 결과, 계산식, 판정·반올림·정렬과 RNG 소비 순서 +2. 턴/명령 조건, 자원 변화, DB 상태 전이와 권한 +3. API 요청·응답·오류, session과 인증 +4. 문구, 로그, 화면 흐름과 룩앤필 +5. 내부 구현 세부사항 -## Randomness Policy (Verifiable RNG) +레거시의 이상해 보이는 동작도 계약일 수 있습니다. 보안 또는 데이터 손상 위험이 +아니면 우선 같은 동작을 재현하고 개선 제안은 분리해 주세요. 허용하는 차이는 +사용자 경험, 저장 상태와 후속 턴 결과에 영향이 없다는 근거를 mapping/report에 +남겨 주세요. -- All game-impacting randomness must be verifiable and reproducible from a deterministic seed. -- Prefer using the existing TypeScript implementations: `packages/common/src/util/LiteHashDRBG.ts`, `packages/common/src/rng.ts`(interface) and `packages/common/src/util/RandUtil.ts`. -- Seed composition should include a hidden base seed plus action context (action type, time, actor, target) so results can be re-validated later. -- Do not introduce ad-hoc randomness in game logic; allow non-deterministic randomness only for non-gameplay, cosmetic, or UI-only cases. +## 인증과 권한 -## Coding Style & Naming Conventions +- actor, general과 archive owner는 인증 session/token에서 서버가 결정합니다. + client가 보낸 user ID, general ID, owner, role을 권한 근거로 신뢰하지 말아 주세요. +- game token의 profile, role, sanction과 장수 생성 정책을 world mutation보다 + 먼저 확인해 주세요. +- 새 browser flow는 `x-session-token` 또는 현재 session transport를 사용하고 + token을 query string이나 로그에 노출하지 말아 주세요. +- 실패한 logout에서 client token을 먼저 버려 서버 revoke 실패를 숨기지 말아 주세요. +- 비밀번호 원문·OAuth credential·global salt·private key·session token을 + Git, CLI argument, build log, report 또는 screenshot에 넣지 말아 주세요. +- `VITE_*`는 공개값입니다. 비밀값은 Git 제외 파일이나 `/run/secrets/...`를 + 사용해 주세요. -- Follow repo lint/format configuration once it exists; keep diffs consistent within a file. -- Indentation: 4 spaces for TypeScript, JSON, and Vue SFCs. -- Prefer explicit types for public APIs; avoid `any` and narrow `unknown`. -- Vue components: PascalCase filenames; composables use `useX` naming. -- Use `camelCase` for variables/functions and `PascalCase` for classes/types. -- Legacy concepts may use Korean identifiers; preserve Korean naming when it improves maintainability. -- Hybrid naming is acceptable (e.g., `use전투규칙`, `use도시상태`) when the prefix is conventional but the domain term is Korean. -- For classes, commands, and domain logic, add clear Korean comments to support Korean readers and future maintainers. -- Use strong type conventions in TypeScript. Any is not allowed, and you should also be careful about using unknown. -- Avoid dangerous casting, such as `as unknown as Something`. +API를 변경하면 성공뿐 아니라 무인증, 다른 사용자, sanction/role, 잘못된 +입력과 경계값을 검사해 주세요. 권한 테스트는 router mock만으로 끝내지 않고 위험도에 +따라 실제 HTTP transport까지 확인해 주세요. -## Commit & Pull Request Guidelines +## 턴, transaction과 RNG -- Git history is minimal and does not define a strict convention; use short, imperative messages (e.g., "Fix map cache loading"). -- PRs should include a concise description, testing notes/commands, and screenshots for UI changes. +현재 gameplay mutation의 내구성 기준은 PostgreSQL `input_event`입니다. -## Architecture References +```text +API request + -> input_event accept/idempotency + -> daemon claim + lease/fencing 확인 + -> in-memory action/turn/monthly handlers + -> world/log/queue/result flush + -> input_event 완료를 같은 transaction으로 commit + -> realtime 알림 +``` -- Overview: `docs/architecture/overview.md`. -- Legacy engine map: `docs/architecture/legacy-engine.md`. -- TypeScript rewrite plan: `docs/architecture/rewrite-plan.md`. -- Runtime and build profiles: `docs/architecture/runtime.md`. +- Redis pub/sub은 best-effort fan-out이며 mutation commit의 source of truth가 + 아닙니다. +- daemon lease/fencing을 우회하거나 이전 owner의 stale transaction을 + commit 가능하게 만들지 말아 주세요. +- 예약 queue의 revision/CAS, repeat/bulk 직렬화와 API/daemon race를 보존해 주세요. +- 새 persistence field는 Prisma schema, 새 migration, domain/model type, + loader, in-memory dirty state, transaction flush와 reload test까지 연결해 주세요. +- 기존 migration 파일이나 checksum을 수정하지 말아 주세요. +- 전투·명령·월간 action의 호출, state patch, 로그와 RNG 소비 순서를 + 리팩터링 편의로 바꾸지 말아 주세요. -## Documentation Workflow +게임 난수는 기존 `packages/common/src/util/LiteHashDRBG.ts`, `RNG.ts`, +`RandUtil.ts` 흐름을 사용해 주세요. `Math.random()` 같은 임의 경로를 gameplay에 +추가하지 말아 주세요. 후보가 하나뿐인 선택, 실패 분기, fallback에서도 ref가 +소비하는 RNG call을 생략하지 말아 주세요. -- When AI proposes future improvements or expansions, record them in - `docs/architecture/todo.md` with an "AI suggestion" label. +전투/RNG 변경에는 fixed seed 결과뿐 아니라 RNG trace, 로그, 전체 state +side effect와 실패 경로의 ref 비교가 필요합니다. comparator ignore를 늘리기 +전에 canonical snapshot에서 누락된 field가 없는지 확인해 주세요. + +## 프론트엔드와 룩앤필 + +새 디자인 시스템이나 현대적 재해석을 임의로 도입하지 말아 주세요. 보존 범위는 +layout, font, line-height, 줄바꿈, 색상, texture, border, shadow, opacity, +이미지 natural size/aspect ratio/object-fit과 표시 순서입니다. + +- gateway `/gateway/`, game `/che/`와 `/hwe/` prefix에서 direct navigation, + refresh, tRPC, SSE와 asset URL을 확인해 주세요. +- `kwe`, `twe`, `nya`, `pya`, `pwe`가 코드에 있어도 외부 route가 활성화된 + 것으로 가정하지 말아 주세요. +- `/image/*`를 frontend build artifact로 가져오거나 root 배포 URL로 + 하드코딩하지 말아 주세요. +- 공통화는 동일한 렌더링 계약이 확인된 token/shell에 한합니다. `.error`, + `.stack`처럼 이름만 같은 page selector를 전역화하지 말아 주세요. +- `v-html`은 입력 source와 sanitization/allowlist를 확인해 주세요. 기존 warning을 + 일괄 disable하지 말아 주세요. + +UI를 변경하면 실제 Chromium을 사용해 주세요. + +- ref와 core에 같은 Chromium, viewport, device scale, zoom, locale, font, + image와 로그인/test data를 사용해 주세요. +- 전체·영역 screenshot과 `getBoundingClientRect()`, + `getComputedStyle()`을 수집해 주세요. +- `hover()`, focus, pointer down/up, checked/selected/disabled, dropdown, + modal과 transition 상태를 실제 interaction으로 만들어 주세요. +- pixel diff mask는 시간·난수 등 불가피한 영역만 최소화하고 이유를 기록해 주세요. +- auth redirect만 확인하고 visual parity라고 주장하지 말아 주세요. +- 민감정보가 보이는 artifact는 저장하거나 report에 넣지 말아 주세요. + +CSS layer와 selector 경계는 `docs/frontend-css-architecture.md`, 비교 실행은 +`docs/frontend-legacy-parity.md`를 따라 주세요. + +## DB와 레거시 데이터 이관 + +Gateway는 기본 `public`, game은 profile별 PostgreSQL schema를 사용합니다. +schema 변경 후 최소한 다음을 위험도에 맞게 확인해 주세요. + +- 빈 DB migration 전체 적용 +- 두 번째 deploy가 no-op인지 +- 기존 설치에서 증분 적용되는지 +- unique/FK/index와 runtime query 일치 +- rollback 또는 backup/restore 경로 + +`prisma db push`는 격리된 fixture에서 scoped schema 확인용으로만 사용하고 +정식 migration chain을 대신하지 말아 주세요. + +레거시 DB 이관은 `tools/legacy-db-migration` CLI만 사용해 주세요. + +- dry-run이 기본이며 실제 쓰기는 명시적 `--apply`가 필요합니다. +- DB URL과 secret은 환경/secret file로 전달해 주세요. +- PostgreSQL advisory lock, stable legacy key와 idempotent upsert를 보존해 주세요. +- 현 시즌 `general/city/nation`, queue, message, market, log와 seasonal + storage를 장기보존 이관에 섞지 말아 주세요. +- 운영 apply 전 backup, maintenance mode, source/target count와 rollback + 절차를 다시 확인해 주세요. +- dump에 우연히 있는 table이 아니라 ref schema와 사용자 범위를 기준으로 + 삼아 주세요. + +## 환경과 배포 + +`.env` 또는 secret key를 추가하기 전에 `.gitignore`와 `.env.example`을 +함께 갱신해 주세요. example은 모든 필수 key와 명백한 placeholder를 포함하되 실제 +비밀을 담지 말아 주세요. + +전체 작업공간의 개발 PostgreSQL/Redis는 +`../docker_compose_files/development/`에서 worktree별로 격리할 수 있습니다. +통합 fixture는 schema truncate와 Redis 초기화를 수행할 수 있으므로 병렬 +worktree가 같은 instance를 공유하지 않도록 해 주세요. volume 삭제 명령은 사용자가 +명시적으로 데이터 폐기를 요청하지 않으면 실행하지 말아 주세요. + +현재 외부 호스트 계약은 `0.0.0.0` bind와 `/gateway/`, `/che/`, `/hwe/` +prefix입니다. Caddy는 외부 인프라로 취급하고 요청 없이 설정 변경을 전제하지 +않습니다. local preview/mock 성공을 외부 HTTPS 성공으로 보고하지 말아 주세요. + +Gateway preview를 검증할 때 최소 계약은 다음과 같습니다. + +```sh +VITE_APP_BASE_PATH=/gateway \ +VITE_GATEWAY_API_URL=/gateway/api/trpc \ +VITE_GAME_API_URL_TEMPLATE='/{profile}/api/trpc' \ +VITE_GAME_WEB_URL_TEMPLATE='/{profile}/' \ +pnpm --filter @sammo-ts/gateway-frontend build +``` + +profile별 정확한 포트와 game frontend/API 변수는 +`docs/e2e-caddy-routing.md`에서 확인하고 현재 인프라와 대조해 주세요. + +## 개발과 검증 절차 + +1. 현재 branch/status/remote, 사용자 변경과 가까운 지침을 확인해 주세요. +2. 관련 mapping/report와 ref/core 호출 경로를 조사해 주세요. +3. 보존할 계약, 허용할 차이와 검증 범위를 먼저 정합니다. +4. 코드와 함께 type/schema/migration/fixture/mapping을 갱신해 주세요. +5. 좁은 단위 test → typecheck/lint/build → DB integration → ref 차등 → + Chromium E2E 순으로 위험에 맞게 넓혀 주세요. +6. 명령, 결과, skip/미검증과 baseline failure를 분리해 report에 기록해 주세요. +7. 양쪽 Git diff/status와 필요한 ancestry를 다시 확인해 주세요. + +기본 정적 검사는 실제 루트 script를 사용해 주세요. + +```sh +CI=1 pnpm typecheck +pnpm lint +pnpm test +pnpm build +``` + +- 모든 코드 변경 후 `CI=1 pnpm typecheck`를 실행해 주세요. +- `pnpm test`의 skip 수를 pass처럼 보고하지 말아 주세요. +- Vitest file/name filter는 package script 뒤에 불필요한 `--`를 넣지 말아 주세요. + 예: `pnpm --filter @sammo-ts/game-engine test monthlyCoreEventHandler.test.ts` +- frontend package의 `test` placeholder를 실제 UI 검증으로 오해하지 말아 주세요. + 해당 Playwright script 또는 legacy parity suite를 사용해 주세요. +- 전체 lint/test의 기존 실패가 있으면 targeted 결과와 baseline 재현 결과를 + 구분하고, 관련 없는 기대값을 완화해 숨기지 말아 주세요. + +외부 서비스 없는 기본 integration: + +```sh +pnpm test:integration +``` + +전용 PostgreSQL/Redis를 준비한 조건부 전체 경계: + +```sh +pnpm test:integration:conditional +``` + +ref 명령과 UI entry point: + +```sh +pnpm check:legacy:general +pnpm check:legacy:nation +pnpm test:e2e:frontend-legacy +``` + +각 command가 요구하는 ref checkout, Docker, DB URL, secret과 fixture는 관련 +docs에서 확인해 주세요. 존재하지 않는 명령을 오래된 report나 제안 문서만 보고 +실행하지 말아 주세요. + +## 코드 스타일 + +- TypeScript는 workspace 전체에서 정확히 `6.0.2`를 사용해 주세요. package-local + 다른 버전을 추가하지 말아 주세요. +- TypeScript/JSON/Vue SFC는 기존 4-space 스타일을 유지해 주세요. +- public API는 명시적 타입을 사용하고 `any`, 불필요하게 넓은 `unknown`, + `as unknown as` 우회를 피해 주세요. +- Vue component는 PascalCase, composable은 `useX`, 변수/함수는 camelCase, + type/class는 PascalCase를 사용해 주세요. +- 한국어 domain identifier와 설명은 의미가 더 명확할 때 유지해 주세요. +- action/command/전투 코드에는 한국 독자가 side effect와 ref 근거를 이해할 + 수 있는 주석을 남기되 코드의 반복 설명은 피해 주세요. +- 기능 이관과 무관한 대규모 formatting/refactor를 같은 변경에 섞지 말아 주세요. + +## 문서와 보고서 + +기능·운영·호환성에 의미 있는 변경은 코드와 같은 작업에서 다음을 갱신해 주세요. + +- `README.md`: 사용자가 알아야 할 현재 구조, 시작점과 운영 경계 +- 이 `AGENTS.md`: 반복 작업 규칙과 검증 계약 +- `docs/*`: core2026 내부 구현·운영 상세 +- `../docs/ref-core2026-mapping.md`: ref↔core 근거와 상태 +- `../report/YYYY-MM-DD-간결한-작업명.md`: 재현 가능한 인수인계 + +보고서에는 목적/범위, 조사한 ref, 변경 파일, 보존 계약, 명령과 결과, +skip/미검증, 알려진 차이, 후속 작업과 저장소별 commit을 포함합니다. commit +전이면 `커밋 전`으로 기록하고 서로 다른 저장소의 hash를 명확히 구분해 주세요. + +## Git, worktree와 commit + +- 중·장기 작업은 전용 branch/worktree와 고유 DB/Redis instance에서 합니다. +- 최신 `main`을 통합하고 회귀를 확인한 뒤 요청된 범위에 따라 local `main`에 + 병합해 주세요. 원격 push는 별도 요청 없이는 하지 말아 주세요. +- 관련 없는 사용자 변경을 stage/commit/revert하지 말아 주세요. +- ref 비교 변경과 core 제품 변경, 상위 mapping/report 변경은 각 Git + 저장소에서 별도 commit해 주세요. +- 생성물, `.env`, DB volume, log, coverage, screenshot, test-results와 + secret을 commit하지 말아 주세요. +- worktree 정리는 clean status와 + `git merge-base --is-ancestor HEAD `을 모두 확인한 뒤 non-force + 제거해 주세요. 이름, 나이 또는 uncommitted 여부만으로 삭제하지 말아 주세요. +- 사용자가 commit을 요청하지 않은 일반 작업은 diff와 권장 commit 경계를 + 준비하되 임의로 commit하지 말아 주세요. + +## Qwen 보조 분석 + +Qwen은 대규모 파일 목록, diff·로그 분류, 반복 추출과 누락 후보 재검색에만 +사용해 주세요. 필요한 최소 발췌만 전달하고 secret, 개인정보와 환경 파일 값을 +보내지 말아 주세요. + +- 아키텍처·보안·DB mutation·전투/RNG 판단과 최종 검증을 위임하지 말아 주세요. +- 결과는 파일, Git, test 또는 실제 trace로 독립 검증해 주세요. +- 응답 budget은 128–4096 token 범위로 제한해 주세요. +- 실패하면 health 확인 후 일시 오류일 때 한 번만 재시도하고, 선택적 작업이면 + 로컬 분석을 계속해 주세요. diff --git a/README.md b/README.md index b059353..92d21f6 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,214 @@ -# 삼국지 모의전투 HiDCHe (sammo-ts) +# 삼국지 모의전투 HiDCHe — core2026 -삼국지 모의전투 HiDCHe(삼모/삼모전/힏체섭)의 레거시 PHP 코드베이스를 TypeScript 기반 pnpm 모노레포로 재작성하는 저장소입니다. -현재 운영 중인 소스는 `legacy/` 아래에 있으며, 새 런타임은 단계적으로 전환 중입니다. +`core2026`은 삼국지 모의전투 HiDCHe(삼모/삼모전/힏체섭)의 PHP 서비스를 +TypeScript로 호환 이관하는 pnpm 모노레포입니다. 기준 구현은 이 저장소 안의 +`legacy/`가 아니라 작업공간의 `../ref/sam`이며, 제품 동작·저장 상태·화면은 +그 기준과 실제 실행 결과를 대조합니다. -## 목표 +## 현재 상태 -- 레거시 PHP 기반 런타임을 TypeScript 기반 모노레포로 전환 -- 게임 로직을 순수 모듈로 분리하고 API/엔진/프론트를 서비스 단위로 구성 -- 서버+시나리오 프로파일별 빌드 및 배포 흐름 정립 +2026-07-27의 `main` 기준으로 gateway, game API/프론트엔드, turn daemon과 +주요 게임 명령·월간 이벤트가 구현되어 있습니다. 최근 백엔드 누락 감사에서 +재현 가능한 구체적 미구현 또는 미병합 항목은 남지 않았지만, 이것이 전체 +호환성이나 운영 준비 완료를 뜻하지는 않습니다. -## 구조 +현재 열린 경계는 주로 다음과 같습니다. -- `legacy/`: 현재 운영 중인 PHP 런타임 -- `packages/common`: 공유 유틸 및 타입 정의 -- `packages/infra`: Prisma/Redis 커넥터 등 런타임 인프라 -- `packages/logic`: 순수 게임 로직 (DI/인터페이스 기반) -- `app/gateway-frontend`: 게이트웨이 UI -- `app/gateway-api`: 게이트웨이 API -- `app/game-frontend`: 게임 UI -- `app/game-api`: 게임 API -- `app/game-engine`: 턴 엔진/데몬 -- `tools/build-scripts`: 빌드 및 배포 스크립트 +- 아직 fixture가 없는 명령 실패값·조합과 live 출병 조합의 차등 범위 확대 +- 실제 배포 profile에서 worker의 장시간 소비, 재시작, host/firewall 장애 검증 +- 인증 fixture가 필요한 화면과 남은 페이지의 Chromium 룩앤필 비교 +- 외부 Caddy의 `/gateway/`, `/che/`, `/hwe/` 경로에서 tRPC, SSE, 자산, + 새로고침과 로그인 인계의 반복 검증 +- 운영 DB 이관 전 backup/restore, maintenance mode와 dry-run count 재확인 -## 개발 도구 및 스크립트 +테스트가 통과했다는 사실만으로 PHP 기준과의 호환성이 증명되지는 않습니다. +기능별 근거와 남은 범위는 작업공간의 `../docs/ref-core2026-mapping.md`와 +`../report/`를 함께 확인해 주세요. -- 패키지 매니저: pnpm 워크스페이스 -- TypeScript: 워크스페이스 전체에서 정확히 `6.0.2`를 사용합니다. - TypeScript 7은 저장소와 도구가 요구하는 API 및 생태계 지원이 준비될 때까지 - 사용하지 않습니다. 적용 범위와 7로 올리는 조건은 - [`docs/architecture/typescript-version.md`](docs/architecture/typescript-version.md)를 - 참고하십시오. -- 현재 개발 호스트는 `fnm`으로 Node.js와 pnpm을 관리한다. 대화형 zsh가 - 아닌 환경에서 `pnpm`을 찾지 못하면 아래 형태로 실행한다. +## 구성 - ```sh - /home/letrhee/.local/share/fnm/fnm exec --using=default -- pnpm - ``` +| 경로 | 역할 | +| ------------------------------ | ------------------------------------------------- | +| `app/gateway-frontend` | 가입·로그인, 로비, 계정과 관리자 운영 UI | +| `app/gateway-api` | 계정·세션·profile 정책과 PM2 운영 orchestration | +| `app/game-frontend` | 게임 SPA와 ref 룩앤필 호환 화면 | +| `app/game-api` | profile별 tRPC/SSE, 조회·입력 API와 비동기 worker | +| `app/game-engine` | 턴 scheduler/daemon, 월간 처리와 DB flush | +| `packages/common` | 공통 타입, 직렬화, 결정적 RNG와 유틸리티 | +| `packages/logic` | 전투·명령·월간 action 등 게임 도메인 로직 | +| `packages/infra` | game/gateway Prisma schema, migration과 client | +| `packages/tools-scripts` | resource schema 생성·검증 도구 | +| `tools/integration-tests` | PostgreSQL/Redis 및 ref↔core 통합·차등 테스트 | +| `tools/frontend-legacy-parity` | 실제 Chromium 기반 화면·상호작용 비교 | +| `tools/legacy-db-migration` | 레거시 장기보존 데이터 CLI 이관 | +| `docs` | 런타임, 테스트, 배포 prefix와 운영 문서 | - 2026-07-25 확인 기준 default는 Node.js `v24.18.0`, pnpm은 `11.17.0`이다. -- 초기 개발기간 동안 npm 패키지는 가능한 최신버전을 유지 -- 공통 스크립트 - - `pnpm install` - - `pnpm lint` - - `pnpm test` - - `pnpm build` - - `pnpm typecheck`: turbo를 통해 전체 패키지 타입 체크 실행 - - `pnpm dev` -- 서버 빌드 - - `pnpm build:server --profile --scenario ` - - 예: `pnpm build:server --profile che --scenario default` +런타임의 영속 입력은 PostgreSQL `input_event`가 담당합니다. game API가 +요청을 기록하고 turn daemon이 claim한 뒤, 게임 상태·로그·예약 턴·결과와 +event 완료를 transaction으로 commit합니다. Redis는 session, realtime fan-out, +battle simulation 등 해당 기능의 계약에만 사용하며 게임 mutation의 영속 +성공 여부를 대신하지 않습니다. 자세한 흐름은 +[`docs/architecture/runtime.md`](docs/architecture/runtime.md)와 +[`docs/architecture/turn-daemon-lifecycle.md`](docs/architecture/turn-daemon-lifecycle.md)에 +있습니다. -## 빌드 프로파일(예정) +## 도구 체인 -- 프로파일은 서버+시나리오 조합이며, 시나리오 파일 지정은 필수(기본값은 별도 정의). -- 시나리오 파일에 따라 유닛 세트, DB 세팅 등의 사전 준비가 달라짐. -- 서버 ID: `che`, `kwe`, `pwe`, `twe`, `nya`, `pya` -- 빌드 출력: `/dist/{profileName}` +- pnpm workspace와 Turbo +- TypeScript `6.0.2` 고정 +- Node.js + Fastify + tRPC + zod +- Vue 3 + Pinia + Vue Router + Vite +- PostgreSQL + Prisma, Redis +- Vitest와 Playwright/Chromium -## 난수 정책 (Verifiable RNG) +package manager 버전은 루트 `package.json`의 `packageManager`를 따릅니다. +현재 값은 `pnpm@11.17.0`입니다. 저장소는 Node `engines`를 고정하지 않으므로 +개발 호스트의 임의 버전을 README 계약으로 간주하지 말고, lockfile 설치와 +전체 검증 결과로 호환성을 확인해 주세요. -게임 로직에 영향을 주는 모든 난수는 재현 가능해야 합니다. -현 구현을 사용합니다: `packages/common/src/util/LiteHashDRBG.ts`, `packages/common/src/util/RNG.ts`. +## 로컬 시작 -## 문서 +```sh +pnpm install --frozen-lockfile +cp .env.example .env +pnpm --filter @sammo-ts/infra prisma:generate +CI=1 pnpm typecheck +``` -- `docs/architecture/overview.md` -- `docs/architecture/legacy-engine.md` -- `docs/architecture/rewrite-plan.md` -- `docs/architecture/runtime.md` -- `docs/architecture/typescript-version.md` +`.env`는 Git에서 제외됩니다. `.env.example`의 placeholder를 실제 비밀값으로 +바꾸되 secret을 커밋, 명령행, 로그, 스크린샷 또는 `VITE_*` 변수에 넣지 +말아 주세요. -## 참고 +PostgreSQL과 Redis가 필요합니다. 전체 `sam_rebuild` 작업공간에서는 +`../docker_compose_files/development/README.md`의 worktree별 격리 stack을 +사용할 수 있습니다. standalone checkout이라면 `.env.example` 계약에 맞는 +별도 PostgreSQL/Redis를 준비해 주세요. -레거시 데이터(`legacy/`)는 마이그레이션용으로만 유지되며, DB 이전 이후에는 런타임 의존성을 제거합니다. +작업공간 helper를 사용하는 기본 예시는 다음과 같습니다. + +```sh +cd ../docker_compose_files/development +./scripts/prepare-instance.sh main 15433 16379 ../../core2026 +./scripts/compose.sh main up -d --wait + +cd ../../core2026 +pnpm --filter @sammo-ts/infra prisma:generate +pnpm test:integration +``` + +`prepare-instance.sh`는 ignored `.env`와 `.env.ci`를 생성합니다. 통합 테스트는 +schema를 truncate하거나 Redis를 비울 수 있으므로 다른 worktree나 개발 +데이터와 DB/Redis instance를 공유하지 말아 주세요. volume 삭제는 명시적으로 +데이터 폐기를 결정한 경우에만 수행해 주세요. + +## 자주 쓰는 명령 + +```sh +pnpm lint +pnpm test +CI=1 pnpm typecheck +pnpm build +pnpm dev +``` + +`pnpm test`의 일부 PostgreSQL/Redis 테스트는 전용 환경 변수가 없으면 +의도적으로 skip됩니다. 외부 서비스가 필요한 경계까지 실행하려면 격리된 +instance를 준비한 뒤 다음을 사용해 주세요. + +```sh +pnpm test:integration +pnpm test:integration:conditional +``` + +레거시 명령의 정적 계약과 실제 Chromium 화면 비교는 각각 다음 entry +point를 사용해 주세요. + +```sh +pnpm check:legacy:general +pnpm check:legacy:nation +pnpm test:e2e:frontend-legacy +``` + +이 명령들은 ref checkout, fixture, 로그인 상태 또는 별도 서비스가 필요할 +수 있습니다. 실행 조건과 coverage는 +[`docs/integration-tests.md`](docs/integration-tests.md)와 +[`docs/frontend-legacy-parity.md`](docs/frontend-legacy-parity.md)를 따라 주세요. + +프론트엔드나 개별 서비스만 실행할 때는 workspace filter를 사용해 주세요. + +```sh +pnpm --filter @sammo-ts/gateway-frontend dev +pnpm --filter @sammo-ts/gateway-api dev +pnpm --filter @sammo-ts/game-frontend dev +pnpm --filter @sammo-ts/game-api dev +pnpm --filter @sammo-ts/game-engine dev +``` + +## DB schema와 migration + +Gateway는 기본적으로 PostgreSQL `public` schema를 사용하고, 게임은 +`PROFILE`별 schema를 사용합니다. + +```sh +pnpm --filter @sammo-ts/infra prisma:migrate:status:game +pnpm --filter @sammo-ts/infra prisma:migrate:deploy:game +pnpm --filter @sammo-ts/infra prisma:migrate:deploy:gateway +``` + +새 영속 필드는 Prisma schema와 migration만 추가해서 끝내지 말아 주세요. runtime +model/type, loader, transaction flush와 실제 PostgreSQL 검증까지 연결해 주세요. +기존 migration 파일이나 checksum을 고치지 말아 주세요. + +레거시 장기보존 데이터 이관은 HTTP 기능이 아닌 CLI입니다. 기본 동작은 +dry-run이며 실제 쓰기에는 `--apply`가 필요합니다. + +```sh +pnpm migrate:legacy -- --help +``` + +현재 기수의 `general`, `city`, `nation`, queue, 시장, 메시지 등은 이관 +범위가 아닙니다. 운영 적용 절차와 table별 범위는 +[`docs/legacy-db-migration.md`](docs/legacy-db-migration.md)와 +[`tools/legacy-db-migration/README.md`](tools/legacy-db-migration/README.md)를 +따라 주세요. + +## 배포 경로와 자산 + +현재 외부 계약의 활성 경로는 gateway `/gateway/`, game `/che/`와 `/hwe/`입니다. +프론트 build와 API는 같은 prefix의 tRPC/SSE/direct navigation 계약을 +지켜야 합니다. `/image/*`는 외부 Caddy가 별도 파일 시스템에서 제공하므로 앱이 +rewrite하거나 복제하지 말아 주세요. + +`kwe`, `twe`, `nya`, `pya`, `pwe` 같은 profile 이름이 코드나 계획 문서에 +존재하더라도 외부 route가 활성화됐다는 뜻은 아닙니다. 실제 포트와 build-time +환경 변수는 [`docs/e2e-caddy-routing.md`](docs/e2e-caddy-routing.md)를 +현재 인프라와 다시 대조해 주세요. + +루트의 `build:server` 스크립트는 현재 profile resource를 `dist/`로 +복사하기 위한 placeholder이며, API·daemon·frontend의 완전한 배포 bundle을 +만들지 않습니다. 운영 build는 gateway operation/orchestrator와 profile별 +worktree 흐름을 사용합니다. + +## 호환성 원칙 + +- 전투 결과, 판정·반올림·정렬과 RNG 소비 순서를 최우선으로 보존합니다. +- actor와 archive owner는 인증 session에서 서버가 결정합니다. client가 보낸 + general ID나 owner 값을 권한 근거로 신뢰하지 않습니다. +- gameplay 난수는 `packages/common/src/util/LiteHashDRBG.ts`, + `RNG.ts`, `RandUtil.ts`의 기존 흐름을 사용합니다. +- ref와 같은 viewport, Chromium, font, image, 로그인 fixture에서 geometry와 + hover/focus/active/disabled 상태를 비교합니다. +- 동일한 CSS class 이름만으로 page별 layout을 합치지 않습니다. 공통 token과 + shell의 기준은 [`docs/frontend-css-architecture.md`](docs/frontend-css-architecture.md)입니다. +- mock/local E2E 성공과 외부 Caddy·운영 데이터 검증을 구분합니다. + +## 핵심 문서 + +- [테스트 정책](docs/testing-policy.md) +- [테스트 suite 감사](docs/test-suite-audit.md) +- [통합 테스트](docs/integration-tests.md) +- [프론트엔드 ref 호환 검증](docs/frontend-legacy-parity.md) +- [Caddy prefix E2E](docs/e2e-caddy-routing.md) +- [레거시 DB 이관](docs/legacy-db-migration.md) +- [TypeScript 버전 정책](docs/architecture/typescript-version.md) +- [저장소 작업 지침](AGENTS.md)