Files
math-quiz/AGENTS.md
T
2026-05-25 19:01:09 +09:00

7.3 KiB
Raw Blame History

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/ 하위에 위치한다.
  • 현재 수식 컴포넌트는 katex.renderToString()을 직접 사용한다. 별도 래퍼 라이브러리를 추가하기 전에 Next.js App Router 클라이언트 번들에서 런타임 문제가 없는지 확인한다.

상태 관리

  • 전역 게임 상태(점수, 진행도, 선택한 모드·유형)는 store/gameStore.ts의 Zustand store로 관리한다.
  • 컴포넌트 내부의 로컬 상태는 useState를 사용한다.
  • Zustand selector 안에서 매번 새 객체·배열을 반환하는 함수(score() 등)를 호출하지 않는다. 필요한 파생값은 구독한 state를 기준으로 컴포넌트 내부에서 계산하거나 안정적인 selector로 분리한다.
  • store에는 세션 원본 상태와 상태 변경 action을 우선 두고, 렌더링 전용 파생값은 컴포넌트 또는 별도 순수 유틸에서 계산한다.

컴포넌트 배치

  • 게임 화면에서 재사용되는 입력, 피드백, 점수 요약, 진행 단계 UI는 components/game/ 하위에 둔다.
  • 수식 렌더링 전용 컴포넌트는 components/math/ 하위에 둔다.
  • 라우트별 조립 컴포넌트(PlayClient 등)는 해당 app/ 라우트 폴더에 둘 수 있다.

접근성 / 키보드 조작

  • 문제 풀이 화면은 키보드만으로 진행할 수 있어야 한다.
  • 새 문제가 표시되면 첫째 항 입력 칸에 focus를 둔다.
  • 첫째 항에서 Enter를 누르면 둘째 항 입력 칸으로 focus를 이동한다.
  • 둘째 항에서 Enter를 누르면 제출 동작을 실행한다.
  • 정답·오답 피드백이 표시되면 다음 진행 버튼에 focus를 둔다.
  • 최종 결과 화면이 표시되면 다시 시작 버튼에 focus를 둔다.
  • 아이콘이나 기호만으로 상태를 표시할 때는 aria-label, sr-only 텍스트 등으로 의미를 함께 제공한다.

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/ 내에서 알고리즘으로만 처리되는지 여부