Files
playuniare.sori.studio/AGENTS.md

9.4 KiB

Play Uniare AI 작업 지침

1. 문서 목적

이 파일은 사람과 AI 작업자가 같은 기준으로 프로젝트를 이해하고 변경하기 위한 최상위 작업 규칙이다. 작업 시작 전에 이 파일과 docs/의 관련 문서를 반드시 읽는다.

2. 프로젝트 목표

  • 기존 UA Deck Builder가 전달한 덱 데이터로 카드 시뮬레이터를 제공한다.
  • 게임 규칙을 자동 판정하지 않는다.
  • 사용자가 카드 이동, 뒤집기, 탭, 덱·손패·무덤 이동을 직접 수행한다.
  • 혼자 연습하는 로컬 모드와 방 코드 기반 2인 세션을 제공한다.
  • 각 플레이어는 자신이 소유한 카드만 조작한다.
  • 상대 효과로 내 카드가 제거되는 경우에도 내 카드 소유자가 직접 처리한다.

3. 기술 기준

  • 프런트엔드: Vue 3 Composition API와 <script setup>
  • 빌드 도구: Vite
  • 스타일: Tailwind CSS 우선
  • 상태 관리: Pinia 도입 예정
  • 화면 이동: Vue Router 도입 예정
  • 실시간 통신: Socket.IO 도입 예정
  • 배포: Docker Compose와 Nginx
  • 운영 환경: UGREEN NAS

새 라이브러리를 추가하기 전에는 기존 기술로 해결 가능한지 확인하고, 추가 이유와 영향을 docs/history.md에 기록한다.

4. 작업 시작 절차

  1. AGENTS.md를 읽는다.
  2. docs/spec.md, docs/map.md, docs/todo.md를 읽는다.
  3. git status로 기존 변경 사항을 확인한다.
  4. 관련 코드와 기존 패턴을 확인한다.
  5. 작업 범위를 작게 정하고 구현한다.
  6. 빌드와 관련 검증을 수행한다.
  7. 변경 성격에 맞는 문서를 업데이트한다.
  8. 작업 결과 형식에 맞춰 보고한다.

5. 코드 작성 규칙

5.1 공통

  • 기존 패턴을 우선하며 최소 범위만 수정한다.
  • 하나의 컴포넌트는 하나의 분명한 역할을 갖는다.
  • 반복되는 값은 상수, 설정 또는 데이터 모델로 분리한다.
  • 서버 주소, 이미지 원본 주소, 포트, 비밀값을 코드에 하드코딩하지 않는다.
  • 임시 이름과 의미 없는 자리표시자 이름을 사용하지 않는다.
  • 검증 없이 작업을 완료 처리하지 않는다.

5.2 네이밍

  • 의미가 드러나는 영문 이름을 사용한다.
  • 축약어를 남용하지 않는다.
  • temp, tmp, test1, data1, foo, bar, aaa 같은 임시 이름을 금지한다.
  • Vue 컴포넌트 파일은 PascalCase를 사용한다.
  • 함수와 변수는 camelCase를 사용한다.
  • 상수는 의미가 분명한 경우 UPPER_SNAKE_CASE를 사용한다.
  • 이벤트 이름은 발생한 사실을 나타내는 kebab-case를 사용한다.
  • 불리언 값은 is, has, can, should 접두어를 우선한다.

5.3 Vue

  • Composition API와 <script setup>을 사용한다.
  • 화면 컴포넌트는 src/views/, 재사용 컴포넌트는 src/components/에 둔다.
  • 비즈니스 상태를 컴포넌트 내부에 중복 저장하지 않는다.
  • props를 직접 변경하지 않는다.
  • 외부 효과와 구독은 컴포넌트 해제 시 반드시 정리한다.

5.4 스타일

  • Tailwind CSS 유틸리티를 기본으로 사용한다.
  • 반복되는 디자인 패턴은 컴포넌트로 추출한다.
  • 임의 픽셀값은 게임 보드 좌표처럼 필요한 경우에만 사용하고 이유를 문서화한다.
  • 카드 위치는 화면 픽셀이 아니라 보드 기준 정규화 좌표 또는 영역 기반으로 저장한다.
  • 인라인 style은 드래그 좌표, 회전처럼 동적 계산이 필요한 경우에만 허용한다.

5.5 주석

  • 함수와 클래스 앞에는 한국어 JSDoc 문서화 주석을 작성한다.
  • 주석은 코드가 무엇을 하는지 반복하기보다 이유, 제약, 입력·출력을 설명한다.
  • 복잡한 타입은 @typedef, 함수 입력은 @param, 반환은 @returns를 쓴다.
/**
 * 덱 빌더에서 전달된 카드 목록을 실제 카드 인스턴스로 확장한다.
 *
 * @param {ImportedDeckCard[]} importedCards 수량이 포함된 덱 카드 목록
 * @returns {GameCard[]} 고유 식별자가 부여된 카드 인스턴스 목록
 */
function createGameCardInstances(importedCards) {
  return []
}

6. 상태 관리 원칙

6.1 상태 구분

  • 서버 권위 상태: 방, 플레이어, 카드 소유권, 카드 영역, 덱 순서
  • 공유 게임 상태: 필드 카드 좌표, 앞뒷면, 탭 상태, 무덤, 공개 영역
  • 개인 비공개 상태: 내 손패 카드 식별 정보
  • 로컬 UI 상태: 선택 카드, 드래그 중 여부, 메뉴 열림, 확대 상태

서버 권위 상태를 UI 컴포넌트의 로컬 상태만으로 확정하지 않는다.

6.2 카드 모델

카드는 덱 원본 정보와 플레이 중 인스턴스를 구분한다.

{
  instanceId: 'player-1-card-17',
  ownerId: 'player-1',
  cardNumber: 'EX01BT/HTR-2-001',
  imageFileName: 'EX01BT_HTR-2-001.png',
  zone: 'deck',
  position: { x: 0.5, y: 0.5 },
  isFaceUp: false,
  isTapped: false,
  stackOrder: 17
}
  • instanceId는 같은 카드 여러 장을 구분하는 고유값이다.
  • 소유권은 게임 시작 후 임의로 변경하지 않는다.
  • 카드 조작 요청은 요청자와 ownerId가 같은지 서버에서 확인한다.
  • 상대 손패에는 카드 번호와 이미지 정보를 전송하지 않는 방향을 우선한다.

6.3 실시간 이벤트

  • 상태 전체를 매번 전송하기보다 명시적인 이벤트와 필요한 변경값을 전송한다.
  • 이벤트 이름은 card-moved, card-flipped, deck-shuffled처럼 작성한다.
  • 재접속 시에는 서버의 최신 전체 스냅샷으로 복구한다.
  • 같은 이벤트가 중복 수신되어도 상태가 망가지지 않도록 설계한다.

7. 데이터 처리 원칙

  • 기존 덱 빌더 쿼리는 초기 덱 불러오기 용도로만 사용한다.
  • 외부 입력은 신뢰하지 않고 스키마 검사 후 사용한다.
  • 카드 이미지 URL은 환경변수의 원본 주소와 파일 경로를 조합한다.
  • NAS 운영 환경에서는 /volume1/docker/projects/apps/uniare/config/www/images를 컨테이너에 읽기 전용으로 연결하고 /card-assets 경로로 제공한다.
  • 기존 Uniare의 config/www/images에는 쓰기 작업을 수행하지 않는다.
  • NAS 카드 파일 소유자 UID가 1000이므로 Nginx 워커는 cardreader 사용자(UID 1000)로 실행한다. 이 기준을 바꾸기 전에는 실제 NAS 파일 소유자를 다시 확인한다.
  • 로컬 Socket.IO 서버 기본 포트는 31873을 사용한다.
  • 운영 환경에서는 Socket.IO 포트를 브라우저에 직접 노출하지 않고 같은 도메인의 /socket.io 경로로 리버스 프록시한다.
  • 컨테이너 내부 포트 중복은 허용되지만 NAS 호스트 공개 포트 중복은 금지한다.
  • 테스트·운영 HTTP 호스트 포트는 Compose에 숫자를 직접 추가하지 않고 PLAYUNIARE_TEST_HTTP_PORT, PLAYUNIARE_PRODUCTION_HTTP_PORT 환경변수로 관리한다.
  • URL 길이 문제를 고려해 장기적으로 덱 코드 또는 deckId 방식을 도입한다.
  • URL, 로그, Git에 사용자 토큰이나 비밀값을 남기지 않는다.
  • 오류가 있는 카드 한 장 때문에 전체 덱 불러오기가 중단되지 않도록 오류 목록을 사용자에게 명확히 보여준다.

8. 문서 업데이트 기준

  • 기능 변경 → docs/spec.md
  • 버그 수정 → docs/update.md
  • 이슈 발견 → docs/todo.md
  • 구조·기술·의사결정 변경 → docs/history.md
  • 화면 변경 → docs/map.md
  • 배포 변경 → docs/deploy.md
  • 개발 명령 변경 → docs/development.md

문서 업데이트 누락을 금지한다.

9. 금지 사항

  • 기존 스타일과 구조를 확인하지 않은 변경
  • 요청 범위를 벗어난 대규모 리팩터링
  • 서버 주소, 포트, API 키와 비밀번호 하드코딩
  • .env, 인증서, 개인키, NAS 계정 정보 커밋
  • 조작 권한 검증을 클라이언트에만 의존
  • 상대의 비공개 손패 정보를 클라이언트로 전송
  • 테스트 또는 빌드 검증 없이 완료 처리
  • 관련 문서 업데이트 누락

10. 의사결정 원칙

  1. 기존 패턴 우선
  2. 최소 수정
  3. 유지보수 용이성
  4. 구조 파악 용이성
  5. 사용자가 직접 운영할 수 있는 단순성
  6. 비공개 정보와 카드 소유권의 안전성

11. 단계별 개발 계획

1단계: 로컬 싱글 플레이

  • 덱 쿼리 파싱과 검증
  • 카드 인스턴스 생성
  • 덱 셔플과 드로우
  • 카드 이동, 뒤집기, 탭
  • 손패, 필드, 무덤, 공개 영역
  • 덱 위·아래 이동과 위에서 N장 공개

2단계: 2인 세션

  • 로비와 방 생성·참가
  • 플레이어 좌석과 소유권
  • Socket.IO 서버
  • 실시간 카드 이벤트 동기화
  • 상대 손패 비공개 처리
  • 연결 종료와 재접속 복구

3단계: 운영 안정화

  • NAS Docker 배포
  • 상태 저장소 도입 검토
  • 모바일·태블릿 조작 개선
  • 오류 로그와 상태 복구
  • 관전자와 게임 기록은 별도 검토

구체적인 미완료 항목은 docs/todo.md에서 관리한다.

12. 작업 결과 보고 형식

  • 수정 내용
  • 변경 파일
  • 검증 내용
  • 문서 반영 여부
  • 남은 이슈

13. 최종 체크리스트

  • AGENTS.md와 관련 docs/ 확인
  • 코드 수정 완료
  • 네이밍과 JSDoc 규칙 확인
  • 빌드 또는 관련 검증 수행
  • 변경 성격에 맞는 문서 반영
  • 민감 정보 포함 여부 확인
  • 남은 이슈를 docs/todo.md에 기록