Files
core2026/docs/developer/first-steps.md
T

7.1 KiB

코드가 처음인 사람을 위한 구조 안내

함수, 변수, 조건문은 알지만 웹 서버나 큰 프로젝트는 처음인 독자를 위한 글입니다. 이 문서를 읽고 나면 화면을 바꿀 파일, 게임 규칙을 바꿀 파일, 결과를 저장할 파일을 구분할 수 있습니다. 설치 전에 읽어도 됩니다.

먼저 게임을 한 문장으로 이해하기

플레이어는 장수 한 명의 행동을 미리 예약합니다. 서버는 장수의 차례가 되면 행동을 실행하고, 자원·도시·전투 결과를 저장합니다. 여러 플레이어와 컴퓨터 장수가 같은 세계에 참여하므로, 브라우저를 닫아도 세계는 계속 진행될 수 있습니다. 게임 자체가 낯설다면 플레이어 첫 안내를 먼저 읽으세요.

화면과 서버는 다른 프로그램입니다

프론트엔드는 브라우저에서 실행되어 화면을 그리고 버튼 입력을 받는 프로그램입니다. 백엔드는 서버에서 실행되어 로그인과 권한을 확인하고 데이터를 읽거나 바꾸는 프로그램입니다. 버튼을 눌렀다고 브라우저가 직접 병력을 늘리는 것은 아닙니다. 브라우저는 서버에 요청하고, 서버가 허용한 결과를 받아 표시합니다.

API는 두 프로그램이 요청과 응답을 주고받는 약속입니다. 이 프로젝트는 TypeScript 타입으로 호출 형태를 연결하는 tRPC를 사용합니다. 타입이 맞더라도 사용자 권한과 실제 자원은 서버가 다시 검사해야 합니다.

예를 들어 “모병을 예약”하는 과정은 다음과 같습니다.

브라우저: 병종과 수량을 고른다
    ↓ 저장 요청
게임 API: 로그인과 입력을 검사하고 예약 변경을 처리한다
    ↓ 예약 목록에 반영
턴 데몬: 내 차례가 되면 모병 조건을 다시 검사한다
    ↓ 실행 결과
데이터베이스: 병력, 자원, 로그와 남은 예약을 저장한다
    ↓ 알림을 받고 다시 조회
브라우저: 실제 결과를 보여 준다

예약 저장과 모병 실행은 서로 다른 일입니다. 예약 이후 돈을 쓰거나 도시를 잃었다면 실행에 실패할 수 있습니다. API를 읽을 때도 “요청을 받았다”와 “게임 행동이 끝났다”를 구분해야 합니다.

다섯 곳을 먼저 익히세요

위치 역할 찾아볼 때
app/game-frontend Vue 화면과 사용자 입력 예턴 입력창이나 도시 화면을 이해하고 싶을 때
app/game-api 로그인·권한 검사, 조회·변경 요청 접수 누가 어떤 정보를 볼 수 있는지 궁금할 때
app/game-engine 시간에 맞춘 실행, 세계 상태와 저장 예약한 행동이 언제 실행되는지 궁금할 때
packages/logic 모병·내정·전투 등 게임 규칙 비용이나 성공 조건을 찾을 때
packages/infra 데이터베이스 구조와 연결 무엇을 영구히 저장하는지 찾을 때

app은 실행하는 프로그램, packages는 여러 프로그램이 함께 쓰는 코드 묶음입니다. 한 저장소에 여러 프로그램과 묶음이 있는 구성을 모노레포라고 합니다. pnpm은 이 묶음들의 설치와 명령 실행을 관리합니다.

resources에는 지도, 병종, 시나리오 설정이 있습니다. 규칙 코드가 같아도 선택한 설정이 다르면 다른 게임이 됩니다. tools에는 검사·변환 같은 개발 도구가, docs에는 지금 읽고 있는 문서가 있습니다.

로비와 게임을 나누는 이유

Gateway는 회원 계정과 로비를 담당합니다. 하나의 계정으로 여러 게임 서버에 들어갈 수 있지만, 각 게임의 장수·국가·진행 시점은 다릅니다. 운영 대상 게임을 코드에서는 **프로필(profile)**이라고 부릅니다. 프로필은 개인 프로필 사진과 다른 뜻입니다. 시나리오는 그 게임에 적용할 시작 조건·지도·규칙 묶음입니다.

Gateway의 화면과 API는 app/gateway-frontend, app/gateway-api에 있습니다. 게임 업데이트와 실행 관리도 필요하므로 운영용 프로그램이 추가로 있습니다. 처음부터 이들을 모두 읽을 필요는 없습니다. 전체 구조를 읽을 때 게임 진행 경로와 운영 경로를 나눠 보세요.

데이터는 어디에 남나요?

메모리는 실행 중인 프로그램이 빠르게 사용하는 작업 공간입니다. 프로그램을 다시 시작하면 사라질 수 있습니다. PostgreSQL은 세계 상태와 기록을 영구히 보관하는 데이터베이스입니다. Prisma는 코드에서 데이터베이스를 다루기 위한 도구이며, packages/infra/prisma/game.prisma는 게임 데이터 구조를 정의합니다.

턴 데몬은 세계를 메모리에 읽어 와 계산합니다. 계산이 끝나면 바뀐 값과 로그를 **트랜잭션(transaction)**으로 묶어 저장합니다. 모병으로 돈만 줄고 병력은 늘지 않는 식의 반쪽 저장을 막기 위한 경계입니다. 저장에 실패하면 메모리 상태도 되돌려야 다음 행동이 잘못된 세계에서 실행되지 않습니다.

Redis는 세션이나 작업 전달·알림 등에 쓰는 별도의 저장·통신 도구입니다. 게임 진행이 확정됐는지는 PostgreSQL 저장 결과를 기준으로 판단합니다. SSE는 서버가 열린 브라우저로 변경 알림을 보내는 연결입니다. 알림이 늦었다고 곧바로 행동이 실패한 것은 아니므로 최신 데이터를 다시 조회합니다.

파일 하나에서 시작하는 읽기 연습

  1. packages/logic/src/actions/turn/general/che_모병.ts를 엽니다. 입력값, 조건, 결과를 나눠 봅니다. 지금은 모든 계산을 외우지 않아도 됩니다.
  2. app/game-engine/src/turn/reservedTurnHandler.ts를 읽으며 예약 행동이 실행되는 곳을 찾습니다. 규칙 파일과 실행 담당 파일이 다른 이유를 확인합니다.
  3. app/game-api/src/router/turns/에서 예약을 바꾸는 요청을 찾습니다. 예약과 실행 사이에 시간이 흐른다는 점을 다시 확인합니다.
  4. 파일 지도로 화면과 저장 담당 위치를 이어 봅니다.

파일명 뒤 .ts는 TypeScript 코드, .vue는 Vue 화면 구성요소, .json은 설정 데이터, .prisma는 데이터베이스 구조, .test.ts는 검증 코드입니다. import는 다른 파일의 기능을 가져오는 선언입니다. 함수를 읽다가 모르는 이름을 만나면 선언 위치로 이동해 입력과 반환값부터 확인하세요.

다음은 개발자 핸드북의 경험자 경로입니다. 실행 환경을 준비할 때는 저장소 README.md의 개발 환경과 테스트 정책을 따릅니다.