← 문서 묶음 · 기술 명세서 · 출시·운영

bruni · 게임개발 환경·인프라 명세서
GitHub / CI / Infra / State

브루니 키우기: 바랜 섬
개발 환경·인프라 명세서

만든 날 2026-10-13 · 고친 날 2026-10-15 — 깃 이력에서 자동으로 박혀요

저장소 · 자동 검사 · 비밀값 · 서버 · 상태 관리 · 새 컴퓨터 세팅

항목내용
문서 성격아직 만들지 않은 것의 설계도입니다. 개발을 시작하는 날 이 문서대로 세팅합니다 (2026-10-13 주인 지시 — 미리 작업하지 않고 문서로만)
기준 문서기술 명세서(폴더·오토로드·서버 엔드포인트·D1 테이블) · 게임 개발 사양서(스토어·비용·행정)
원칙모든 것은 깃에 — 코드·데이터·서버 설정·DB 구조·작업 진행까지. 주인은 언제든 다른 컴퓨터로 옮길 수 있어야 합니다
현재 준비이 맥에 Godot 4.7.2 설치 완료(2026-10-13, Homebrew). 나머지는 미설치 — 11장 순서대로
bruni01
bruni · 게임개발 환경·인프라 명세서
Overview / Contents

문서 개요 및 목차

게임 코드를 어디에 두고, 누가(사람·AI·자동 검사) 무엇을 확인하고, 비밀값을 어디에 숨기고, 서버를 어떻게 올리고, 게임·서버·인프라·작업 진행의 「지금 상태」를 무엇으로 관리하는지 정합니다.

장내용
01 저장소 구성저장소 2개의 역할 · 폴더 · 설계 데이터가 게임으로 흘러가는 길
02 브랜치·커밋·버전1인 개발 규칙 · 태그 · 버전 번호
03 자동 검사·빌드 (CI)GitHub Actions 워크플로 4개 · 단계 · 실패 시
04 비밀값키스토어·API 키·서명 키 — 어디에 두고 어떻게 백업하나
05 인프라 구성도기기 · Cloudflare · 스토어 · 깃허브
06 인프라 상태 관리wrangler 설정·D1 마이그레이션 = 코드 · 환경 3개
07 게임 상태 관리저장 상태 한 곳 · 바꾸는 입구 · 시그널 · 화면 갱신
08 서버가 진실인 것기기와 서버 중 어느 쪽 값을 믿나
09 콘텐츠 데이터 상태설계 JSON → 게임 데이터 → 공개 차수
10 작업 진행 상태이슈 · 마일스톤 · 라벨 · 세션 규칙
11 새 컴퓨터 세팅설치 순서와 명령어 전부
12 비용·한도무료 한도와 유료 전환 기준
13 첫날 세팅 순서개발 시작하는 날 하는 일 · 미확인
bruni02
bruni · 게임개발 환경·인프라 명세서
01 / Repositories

저장소 구성

저장소공개담는 것진실의 자리
bruni-world (기존)비공개설계 문서(/me/idle-rpg) · game-design/ (바이블·조사·설계 데이터·생성 스크립트)기획·수치·이름의 기준
bruni-idle (새로)비공개Godot 프로젝트 · 서버(server/) · 도구(tools/) · CI실행되는 코드의 기준

bruni-idle 최상위 폴더

bruni-idle/
  project.godot  export_presets.cfg    ← 키스토어 비밀번호는 넣지 않음(환경변수)
  autoload/  core/  scenes/  ui/  shaders/  assets/  addons/  android/
  data/                ← tools/export_data.py 산출물. 직접 고치지 않음
  tests/unit  tests/golden  tests/save
  tools/               ← export_data.py · validate_data.py · prob_publish.py · bump_version.py
  server/              ← Cloudflare Worker (src/*.ts · migrations/*.sql · wrangler.jsonc)
  design/              ← bruni-world/game-design/data 복사본 (export 입력)
  .github/workflows/   ← ci.yml · android.yml · server.yml · data-sync.yml
  CLAUDE.md            ← 이 저장소에서 일하는 AI 를 위한 규칙 (10장)
  docs/STATE.md        ← 지금 어디까지 했나 한 장 (10장)
bruni-worldgame-design/data
복사
bruni-idledesign/
export_data.py
bruni-idledata/*.json
왜 두 저장소인가기술 명세서 2장의 결정입니다. 게임 코드는 빌드·바이너리·플러그인이 커지고 CI 가 돌아서 문서 저장소와 섞으면 둘 다 무거워집니다. 대신 설계 데이터의 원본은 bruni-world 하나로 두고, 게임 저장소에는 복사본과 복사한 커밋 해시를 남깁니다(9장). 서버는 게임과 같이 바뀌므로 같은 저장소 server/에 둡니다.
bruni03
bruni · 게임개발 환경·인프라 명세서
02 / Branch & Version

브랜치·커밋·버전

항목규칙
브랜치main 하나. 1인 개발이라 풀 리퀘스트 절차는 두지 않습니다. 큰 실험만 try/이름 브랜치 → 끝나면 main 에 합치고 지움
main 의 약속main 은 항상 CI 통과 상태. 깨진 채로 하루를 넘기지 않음
커밋작업 한 덩어리마다 커밋 + 바로 푸시. 메시지 앞머리: feat · fix · data · server · ci · docs
앱 버전1.0.3 꼴. tools/bump_version.py 가 project.godot 의 version 과 Android versionCode 를 같이 올림
앱 태그v1.0.3 — 이 태그를 밀면 android.yml 이 AAB 를 만듦 (3장)
서버 태그server-v12 — 이 태그를 밀면 server.yml 이 D1 마이그레이션·배포 (3장)
데이터 버전data/manifest.json 의 data_ver = 날짜 + 원본 커밋 해시 (9장)
저장 형식 버전저장 파일 version — 형식이 바뀔 때만 +1, core/save_migrate.gd 에 이전 함수 추가 (7장)
버전 넷을 섞지 않는다앱 버전 · 서버 태그 · 데이터 버전 · 저장 형식 버전은 따로 움직입니다. 이벤트 기록 공통 필드에 ver(앱)과 data_ver(데이터)가 같이 실려서, 문제가 생기면 어느 쪽이 바뀌어서인지 기록만 보고 가를 수 있습니다.
bruni04
bruni · 게임개발 환경·인프라 명세서
03 / CI

자동 검사·빌드 (GitHub Actions)

워크플로언제 돌아가나하는 일실패하면
ci.ymlmain 에 푸시할 때마다① validate_data.py 데이터·스키마 검사 ② Godot 4.7.2 헤드리스로 프로젝트 가져오기 ③ GUT 테스트(단위·골든 전투·저장 이전) ④ 서버 tsc 타입 검사 + vitest(모집 분포 100만 회 포함)main 빨간불 — 그날 안에 고침
android.ymlv* 태그키스토어를 비밀값에서 복원 → --export-release "Android" → AAB 를 아티팩트로 보관(90일)태그 지우고 다시
server.ymlserver-v* 태그 또는 수동wrangler d1 migrations apply → wrangler deploy → GET /v1/time 응답 확인직전 태그로 되돌려 배포
data-sync.yml수동bruni-world 의 game-design/data 를 design/ 로 복사 → export → 검사 → 커밋 (9장)복사 취소, 원본에서 고침

ci.yml 뼈대

on: { push: { branches: [main] } }
jobs:
  game:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: python3 tools/validate_data.py
      - name: Godot 4.7.2 받기
        run: |   # 공식 빌드 저장소 godotengine/godot-builds 의 4.7.2-stable 리눅스 판
          curl -sSLo g.zip "https://github.com/godotengine/godot-builds/releases/download/4.7.2-stable/Godot_v4.7.2-stable_linux.x86_64.zip"
          unzip -q g.zip && mv Godot_v4.7.2-stable_linux.x86_64 godot
      - run: ./godot --headless --import
      - run: ./godot --headless -s addons/gut/gut_cmdln.gd -gdir=res://tests -gexit
  server:
    runs-on: ubuntu-latest
    defaults: { run: { working-directory: server } }
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npx tsc --noEmit && npx vitest run
iOS 는 CI 에서 빌드하지 않는다GitHub 의 macOS 실행기는 비공개 저장소 무료 시간을 빨리 씁니다(12장). iOS 는 이 맥에서 Xcode 26 으로 보관·서명·업로드합니다 — 사양서 4장.
bruni05
bruni · 게임개발 환경·인프라 명세서
04 / Secrets

비밀값

비밀값어디에누가 씀잃어버리면
업로드 키스토어 (.jks)GitHub Secrets ANDROID_KEYSTORE_B64 + 비밀번호 3개android.ymlPlay Console 에서 업로드 키 재설정 요청 (며칠 걸림). 백업 2곳 필수
Cloudflare API 토큰GitHub Secrets CLOUDFLARE_API_TOKEN · CLOUDFLARE_ACCOUNT_IDserver.yml대시보드에서 새로 발급
모집 서명 비밀 키 (Ed25519)wrangler secret put GACHA_SIGN_KEYWorker새 키 + 앱 공개 키 교체 = 앱 업데이트 필요
Play 서비스 계정 JSONwrangler secret put PLAY_SA_JSONWorker 영수증 검증Google Cloud 에서 새로 발급
App Store Server API 키wrangler secret put APPLE_*Worker 영수증 검증App Store Connect 에서 새로 발급
저장 서명 양념 (APP_PEPPER)GitHub Secrets → 빌드 때 상수로 주입앱 저장 HMAC바꾸면 기존 저장이 안 열림 — 바꾸지 않음
AdMob 앱 id·광고 단위 id저장소에 넣어도 됨 (공개값)앱—
깃에 절대 안 들어가는 것키스토어 파일·비밀번호·API 토큰·서명 비밀 키·서비스 계정 JSON. .gitignore 에 *.jks · *.keystore · .dev.vars · *.p8 를 첫 커밋부터 넣습니다. 비밀값 목록과 자리는 이 표처럼 깃에 적고, 값은 적지 않습니다.
키스토어 백업① 암호화한 압축 파일을 주인 클라우드 드라이브에 ② 같은 파일을 오프라인 저장장치에. 비밀번호는 비밀번호 관리자에만. 업로드 키는 잃어도 재설정이 되지만 그동안 업데이트를 못 냅니다.
bruni06
bruni · 게임개발 환경·인프라 명세서
05 / Infrastructure

인프라 구성도

실행 중

게임 앱Godot · 기기
HTTPS
Cloudflare Worker/v1/* 13개
SQL
D1테이블 8개
Play Billing · StoreKit 2결제
토큰
Worker영수증 검증
Google API · Apple
지급 결정우편함
Play RTDN · Apple 알림환불
웹훅
Worker/v1/notify/*
갱신
D1 purchases미사용분 회수

만들고 올리는 길

이 맥Godot · Claude Code
git push
GitHubbruni-idle
Actions
검사·AAB·서버 배포
AABandroid.yml 아티팩트
수동 업로드
Play Console내부 → 비공개 → 프로덕션
—
스토어
부품자리비고
WorkerCloudflare — 게임 전용 계정 (바이블 12-2)기존 bruni-world 계정과 분리. 결제·개인정보가 걸린 서비스라 권한을 나눔
D1같은 계정, DB 이름 bruni-idle · bruni-idle-staging6장
원격 설정GET /v1/config — Worker 안 상수 + 정적 JSON이벤트 달력·배너·최소 버전·기능 스위치
확률 공개 페이지Cloudflare Pages 정적 페이지 (prob_publish.py 산출물)게임 안 확률 화면과 같은 원본에서 생성
bruni07
bruni · 게임개발 환경·인프라 명세서
06 / Infra State

인프라 상태 관리

서버 쪽 「지금 무엇이 어떻게 설정돼 있나」를 대시보드에서 손으로 바꾸지 않고, 전부 저장소의 파일로 둡니다. 파일이 곧 상태입니다.

대상상태를 담는 파일바꾸는 법
Worker 코드·바인딩·라우트·환경server/wrangler.jsonc파일 수정 → 커밋 → server-v* 태그
D1 테이블 구조server/migrations/0001_init.sql, 0002_….sql … (번호 순, 지우지 않음)새 번호 파일 추가 → 배포 때 migrations apply가 아직 안 한 것만 적용
적용된 마이그레이션 기록D1 안 d1_migrations 표 (wrangler 가 관리)직접 고치지 않음
비밀값 이름 목록server/SECRETS.md (이름만)값은 wrangler secret put
원격 설정server/src/config.ts + 정적 JSON커밋·배포

환경 세 개

환경어디D1언제
로컬wrangler dev (이 맥)로컬 SQLite (.wrangler/, 깃 제외)개발 중 항상
스테이징bruni-idle-staging.*.workers.devbruni-idle-staging내부·비공개 테스트 빌드가 바라봄
프로덕션정식 도메인bruni-idle스토어 빌드가 바라봄
Terraform 같은 도구는 쓰지 않는다부품이 Worker 1개 · D1 2개 · Pages 1개뿐이고 wrangler 설정 파일과 마이그레이션 파일만으로 「무엇이 있어야 하나」가 깃에 다 남습니다. 부품이 늘어 손으로 맞추는 일이 생기면 그때 다시 판단합니다.
bruni08
bruni · 게임개발 환경·인프라 명세서
07 / Game State

게임 상태 관리

게임의 「지금 상태」는 저장 데이터 하나(Save.data, 기술 명세서 12장의 43개 필드)뿐입니다. 화면은 상태를 들고 있지 않고, 보여 주기만 합니다.

화면버튼 누름
요청
도메인 오토로드Wallet · Missions …
수정
Save.data유일한 상태
Save.data
mark_dirty()
2초 뒤 저장원자적 쓰기
Bus 시그널
화면다시 그림
규칙내용왜
한 곳상태는 Save.data 에만. 화면 스크립트에 재화·진행 값을 복사해 두지 않음두 곳에 두면 언젠가 어긋남
입구 하나재화는 Wallet.add/spend, 미션은 Missions, 모집 결과는 core/gacha_apply 로만 바꿈. 화면이 Save.data 를 직접 고치면 안 됨변경마다 기록·검증·시그널이 빠지지 않게
알림은 Bus바뀐 뒤 Bus 시그널(과거형: wallet_changed, stage_cleared). 화면은 구독해서 다시 그림화면끼리 직접 부르지 않음
저장 시점mark_dirty() 2초 모아 쓰기 + 앱이 내려갈 때 즉시 쓰기잦은 쓰기 방지 · 강제 종료에도 안전
계산 값은 저장 안 함전투력·미션 진행 중 max/has 유형은 저장값에서 다시 계산 (Missions.recheck_all)저장 크기·불일치 방지
형식 바뀜version +1 과 _v{n}_to_{n+1} 이전 함수를 같은 커밋에. tests/save 에 옛 샘플 추가옛 사용자 저장이 안 깨지게
전투는 따로전투 중 상태는 BattleCtx(메모리)에. 끝나면 결과만 Save 에 반영판정·그리기 분리, 헤드리스 시험 가능
bruni09
bruni · 게임개발 환경·인프라 명세서
08 / Authority

서버가 진실인 것

값믿는 쪽기기의 역할
현재 시각서버 (GET /v1/time)오프라인이면 기기 시계 + 상한 24시간, 다음 접속 때 대조(꺼 둔 동안 진행은 앱을 켤 때 30분 칸으로 재생)
유료 빛구슬서버 (gem_ledger)보여 주기·차감 보고. 복구 때 서버 잔액으로 맞춤
모집 결과·천장서버 (gacha_pulls·gacha_state)서명 확인 후 적용만. 서버 연결 없으면 모집 버튼 비활성
결제 지급서버 (purchases)검증 성공 뒤 우편으로만
그 밖의 진행 전부기기 (save.json)서버에는 하루 2회 + 결제·장 완료 직후 백업
백업 충돌누적 플레이 시간이 긴 쪽 (기술 명세서 12장)복구 코드로 기기 변경
왜 이렇게 나누나돈이 걸린 것(유료 재화·모집·결제)과 시간만 서버가 쥡니다. 나머지를 서버에 두면 요청이 늘어 무료 한도를 빨리 넘고(12장), 오프라인 플레이가 막힙니다. 방치 게임은 오프라인 플레이가 핵심입니다.
bruni10
bruni · 게임개발 환경·인프라 명세서
09 / Content Data

콘텐츠 데이터 상태

game-design/databruni-world · 원본
data-sync.yml
design/복사본 + 원본 커밋 해시
export_data.py --wave
data/*.json게임이 읽는 17개
항목규칙
원본수치·이름·대사는 bruni-world game-design/data 에서만 고침. 게임 저장소의 data/ 를 손으로 고치지 않음
복사 기록design/SOURCE 파일에 복사한 bruni-world 커밋 해시 한 줄
데이터 버전data/manifest.json 의 data_ver = 2027-01-15+a1b2c3d (날짜 + 원본 해시)
공개 차수--wave W0~W6 — 아직 공개 안 한 동료·장·이벤트는 빌드에서 빼거나 잠금. 서버 원격 설정의 wave 로 열기
검사export 직후 validate_data.py — 기술 명세서 11장의 35개 검사 + 스키마
확률 공개모집·항아리 확률표는 data/gacha.json 하나에서 게임 화면·공개 페이지·서버 모집 판정이 같이 만들어짐. 숫자를 코드에 적지 않음
bruni11
bruni · 게임개발 환경·인프라 명세서
10 / Work State

작업 진행 상태

「어디까지 했고 다음에 뭘 하나」도 깃에 둡니다. 주인이 다른 컴퓨터로 옮기거나 다른 AI 세션이 이어받아도 같은 곳에서 출발하게 합니다.

도구쓰는 법
GitHub 마일스톤1차판 · 완성판 두 개. 출시·운영 사양서의 작업 목록을 이슈로 옮겨 마일스톤에 묶음
GitHub 이슈작업 하나 = 이슈 하나. 커밋 메시지에 #12 를 적어 연결, 끝나면 fixes #12
라벨영역: battle · growth · gacha · story · ui · server · data · art / 종류: bug · task · idea
docs/STATE.md한 장짜리 현황 — 마지막으로 된 것 · 지금 하는 것 · 막힌 것 · 다음 3개. 세션을 끝낼 때마다 고침
CLAUDE.md이 저장소 AI 규칙 — 7장 상태 규칙 · 9장 데이터 원본 규칙 · 4장 비밀값 규칙 · 「작업마다 커밋·푸시」 · 「STATE.md 갱신」
세션 시작① git pull ② STATE.md 읽기 ③ 열린 이슈 확인 ④ CI 빨간불이면 그것부터
GitHub Projects 보드는 쓰지 않는다1인 개발에 보드까지 두면 관리 일이 늘어납니다. 마일스톤의 이슈 수(열림/닫힘)가 진척률을 대신합니다.
bruni12
bruni · 게임개발 환경·인프라 명세서
11 / New Machine

새 컴퓨터 세팅

맥 기준입니다. 위에서부터 순서대로 하면 개발·빌드·서버 배포까지 됩니다.

# 1. 기본 도구
xcode-select --install
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install git gh node python@3.12

# 2. 깃허브 로그인 + 저장소 받기
gh auth login && gh auth setup-git
git clone https://github.com/<계정>/bruni-world ~/dev/hey
git clone https://github.com/<계정>/bruni-idle   ~/dev/bruni-idle

# 3. Godot 4.7.2
brew install --cask godot          # 버전 확인: Godot --version → 4.7.2.stable

# 4. Android 빌드 도구
brew install openjdk@17
brew install --cask android-commandlinetools
sdkmanager "platform-tools" "platforms;android-36" "build-tools;«Godot 4.7 문서 기준 버전»"
#   Godot 편집기 → 편집기 설정 → 내보내기 → Android: SDK 경로·Java 경로 지정
#   프로젝트 → Android 빌드 템플릿 설치 (android/ 폴더 — 이미 깃에 있으면 생략)

# 5. iOS (출시 단계에서)
#   App Store 에서 Xcode 26 설치 → sudo xcode-select -s /Applications/Xcode.app

# 6. 서버
cd ~/dev/bruni-idle/server && npm ci
npx wrangler login                 # 게임 전용 Cloudflare 계정으로
npx wrangler dev                   # 로컬 서버 + 로컬 D1

# 7. 키스토어 (빌드할 기기만) — 백업에서 복원, 경로는 환경변수로
export GODOT_ANDROID_KEYSTORE_RELEASE_PATH=~/secure/bruni-upload.jks

# 8. 깊게 시키기 스킬
ln -sfn ~/dev/hey/.claude/skills/deep ~/.claude/skills/deep
한 줄로 시키기새 컴퓨터의 Claude Code 에 「bruni-idle 개발 환경 세팅해 줘 — /me/idle-rpg/infra 11장대로」라고 하면 이 순서를 따릅니다. 로그인(gh·wrangler)과 키스토어 복원만 사람이 합니다.
bruni13
bruni · 게임개발 환경·인프라 명세서
12 / Cost & Limits

비용·한도

항목무료 범위넘으면판단
GitHub 비공개 저장소무료 계정 — Actions 월 2,000분(리눅스 기준, macOS 는 더 빨리 소모)유료 플랜 또는 분 단위 과금ci.yml 한 번 수 분 — 하루 수십 번 돌려도 여유. 정확한 한도는 GitHub 요금 페이지에서 확인(미확인)
Cloudflare Workers하루 요청 10만Workers Paid $5/월기술 명세서 15장: 하루 요청 7만(≈DAU 4,965)에서 전환
Cloudflare D1저장 용량 무료 한도 안같은 유료 플랜기술 명세서 15장: 4GB(≈DAU 3,096, 90일 보관 기준)에서 전환
Godot · GUT · 플러그인무료(MIT 등)——
Google Play · Apple—$25 1회 · 연 129,000원사양서 5장
전환 규칙D1 4GB 또는 하루 요청 7만 중 먼저 닿는 쪽에서 Workers Paid($5/월)로 바꿉니다(기술 명세서 15장 계산값). 이벤트 기록이 용량을 가장 많이 먹으니, 그 전에 90일 지난 기록을 지우는 정리 작업을 먼저 붙입니다.
bruni14
bruni · 게임개발 환경·인프라 명세서
13 / Day One

첫날 세팅 순서

순서할 일끝났다는 기준
1GitHub 에 비공개 저장소 bruni-idle 생성 · .gitignore(Godot·비밀값) · CLAUDE.md · docs/STATE.md첫 커밋 푸시
2Godot 프로젝트 생성 — 렌더러 Compatibility · 720×1280 · 오토로드 14개 빈 파일 · boot/main 씬편집기에서 실행해 빈 화면
3GUT 설치 · 테스트 1개(PCG32 벡터) · ci.ymlActions 초록불
4design/ 복사 · export_data.py · validate_data.pydata/ 17개 생성 + 검사 통과
5server/ — GET /v1/time 하나 + 0001_init.sql · wrangler dev로컬에서 시각 응답
6Save · Wallet · Bus · Clock 네 오토로드 실제 구현 (7장 규칙)재화 +1 → 저장 → 재실행 후 유지
7GitHub 마일스톤 2개 · 라벨 · 1차판 작업을 이슈로이슈 목록 완성
미확인 — 세팅 날 확인할 것① Godot 4.7.2 리눅스 빌드 파일 이름(3장 URL) ② Godot 4.7 이 요구하는 Android build-tools 버전 ③ GitHub Actions 무료 분 수 ④ 게임 전용 Cloudflare 계정을 새로 만들지(바이블 12-2) 기존 계정에 둘지 — 결제 정보가 걸리니 주인 결정
근거: 기술 명세서(game-design/data/tech.json, 2026-10-13 — 폴더·오토로드·엔드포인트·D1·예산·빌드 단계) · 바이블 12장 · 게임 개발 사양서 · 이 맥 실측(Godot 4.7.2.stable.official 설치, 2026-10-13).
bruni15