Files
math-quiz/AGENTS.md
T

169 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md
AI 에이전트(Claude Code 등)가 이 프로젝트에서 작업할 때 따라야 할 규칙과 맥락을 정의합니다.
---
## 프로젝트 개요
중학교 2학년 대상 **수학 실수 유형 반복 연습** 교육용 게임 서비스.
문제 생성은 AI 없이 자체 알고리즘 엔진으로 처리한다.
---
## 기술 스택 요약
| 레이어 | 기술 |
|---|---|
| 프레임워크 | Next.js 14 (App Router) + TypeScript 5 |
| 스타일 | Tailwind CSS 3 |
| 상태 관리 | Zustand |
| 수식 렌더링 | KaTeX |
| 애니메이션 | Framer Motion |
| 인증 | NextAuth.js 4 |
| ORM | Prisma (MariaDB 11) |
| 캐시 | Redis 7 |
| 유효성 검증 | Zod |
| 패키지 매니저 | pnpm |
| 테스트 | Vitest (단위) / Playwright (E2E) |
---
## 디렉토리 구조 및 파일 위치 규칙
```
app/ # Next.js App Router 루트
(game)/ # 게임 화면 라우트 그룹
select-type/ # 문제 유형 선택
select-mode/ # 게임 모드 선택
play/ # 문제 풀이
api/
auth/ # NextAuth.js 핸들러
problem/ # 문제 생성 API
record/ # 풀이 기록 저장 API
layout.tsx
page.tsx # 시작 화면
components/
math/ # KaTeX 수식 컴포넌트
game/ # 게임 UI 컴포넌트
lib/
engine/ # 문제 생성 알고리즘 엔진
prisma.ts # Prisma Client 싱글턴
redis.ts # Redis Client 싱글턴
store/
gameStore.ts # Zustand 전역 게임 상태
types/
*.d.ts # 타입 선언이 없는 서드파티 모듈 보강
prisma/
schema.prisma # MariaDB 모델 정의
.gitea/workflows/deploy.yml # CI/CD 워크플로우
```
---
## 코드 작성 규칙
### Next.js / React
- 페이지 컴포넌트는 반드시 `app/` 디렉토리에 위치한다.
- 클라이언트 컴포넌트에는 `'use client'` 지시어를 파일 최상단에 명시한다.
- 서버 컴포넌트가 기본값이므로, 클라이언트 기능(훅, 이벤트)이 필요할 때만 `'use client'`를 붙인다.
### 수식 렌더링
- 모든 수학 수식은 KaTeX로 렌더링한다. 일반 텍스트나 Unicode 수식 문자를 직접 사용하지 않는다.
- KaTeX 컴포넌트는 `components/math/` 하위에 위치한다.
### 상태 관리
- 전역 게임 상태(점수, 진행도, 선택한 모드·유형)는 `store/gameStore.ts`의 Zustand store로 관리한다.
- 컴포넌트 내부의 로컬 상태는 `useState`를 사용한다.
- Zustand selector 안에서 매번 새 객체·배열을 반환하는 함수(`score()` 등)를 호출하지 않는다. 필요한 파생값은 구독한 state를 기준으로 컴포넌트 내부에서 계산하거나 안정적인 selector로 분리한다.
- store에는 세션 원본 상태와 상태 변경 action을 우선 두고, 렌더링 전용 파생값은 컴포넌트 또는 별도 순수 유틸에서 계산한다.
### 컴포넌트 배치
- 게임 화면에서 재사용되는 입력, 피드백, 점수 요약 UI는 `components/game/` 하위에 둔다.
- 수식 렌더링 전용 컴포넌트는 `components/math/` 하위에 둔다.
- 라우트별 조립 컴포넌트(`PlayClient` 등)는 해당 `app/` 라우트 폴더에 둘 수 있다.
### API / 백엔드
- API는 `app/api/` 하위의 Route Handlers로만 구현한다. 별도의 백엔드 서버를 추가하지 않는다.
- 모든 API 요청 입력값은 Zod 스키마로 검증한다.
- DB 접근은 `lib/prisma.ts`의 Prisma Client 싱글턴을 통해서만 한다.
- Redis 접근은 `lib/redis.ts`의 Redis Client 싱글턴을 통해서만 한다.
### 문제 생성 엔진
- 문제 생성 로직은 `lib/engine/` 하위에 위치한다.
- 문제는 AI 호출 없이 알고리즘으로 생성한다. 외부 AI API를 문제 생성에 사용하지 않는다.
- 미지수의 계수는 항상 정수이어야 한다.
- 생성 파라미터: 숫자 자릿수, 괄호 깊이(`()` / `(){}` / `(){}[]`), 괄호 개수(13), 미지수(없음/x/x,y/x,y,z).
- 문제 세션에서 중복을 방지할 때는 랜덤 id가 아니라 수학적 문제 조건을 나타내는 안정적인 key를 기준으로 한다.
---
## 환경변수
새로운 환경변수를 추가할 때는 `.env.example`에 키 이름만 추가하고 값은 비워둔다.
`.env.local`은 절대 Git에 커밋하지 않는다.
```
DATABASE_URL=mysql://user:pass@mariadb:3306/mathgame
REDIS_URL=redis://redis:6379
NEXTAUTH_SECRET=your-secret
```
---
## 보안 규칙
- `.env.local`을 Git에 커밋하거나 코드에 하드코딩하지 않는다.
- MariaDB, Redis 포트는 컨테이너 내부 통신 전용이다. 외부 노출 설정을 추가하지 않는다.
- SQL 쿼리는 반드시 Prisma를 통해 실행한다. Raw query 사용 시 파라미터 바인딩을 반드시 사용한다.
- 사용자 입력은 API 경계에서 Zod로 검증한다. 클라이언트 측 검증만으로 보안을 의존하지 않는다.
---
## 게임 도메인 컨텍스트
### 문제 유형
1. **괄호 음수 분배**: 괄호 앞 음수 곱셈 시 괄호 내 부호 변경 (예: `-2 × (3 - 6)`)
2. **이항 부호 변경**: 등식의 항을 이항할 때 부호 반전 (예: `3x - 5y + 8 = -2x + 2y - 2`)
### 게임 모드
| 모드 | 설명 |
|---|---|
| 스피드 퀴즈 | 제한 시간 내 최대 문제 풀기, Redis Sorted Set 기반 실시간 점수판 |
| 일반 풀이 | 시간 제한 없음, 틀린 유형 반복 출제 |
### 화면 흐름
```
시작 화면 → 문제 유형 선택 → 게임 모드 선택 → 문제 풀이 → 결과 및 기록
```
---
## CI/CD
- `.gitea/workflows/deploy.yml`이 CI/CD 진입점이다. main 브랜치 push 시 자동으로 빌드·배포된다.
- 패키지 설치는 반드시 `pnpm`을 사용한다. `npm` / `yarn` 명령을 사용하지 않는다.
- 배포 환경: Synology NAS + Docker Compose + Nginx Proxy Manager.
---
## 작업 시 체크리스트
새 기능 또는 수정 작업 전에 다음을 확인한다.
- [ ] 클라이언트 컴포넌트에 `'use client'` 선언 여부
- [ ] 수식이 KaTeX로 렌더링되는지 여부
- [ ] API 입력값이 Zod로 검증되는지 여부
- [ ] DB 접근이 Prisma 싱글턴을 통하는지 여부
- [ ] 환경변수가 `.env.local`에만 존재하는지 여부 (`.env.example`에 키 이름 추가)
- [ ] 문제 생성 로직이 `lib/engine/` 내에서 알고리즘으로만 처리되는지 여부