Files
chocoadmin/AGENTS.md
T

7.3 KiB
Raw Blame History

This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ before writing any code. Heed deprecation notices.


Project: chocoadmin

Admin panel for the chocomae service (mouse-typing), extracted into a standalone Next.js 16 app. It shares the existing MariaDB database — do not modify the DB schema.

Critical rules

  • Never alter the DB schema. All tables are shared with the live chocomae service.
  • Race-condition guard for approve/cancel/reject: use a conditional updateMany({ where: { id, Status: REQUEST_STATUSES.REQUESTED }, data: { Status: <target> } }) as the first step inside a transaction. If count === 0, check existence to return 404 vs 409. Never use read-then-write (findUnique → check Status → update) — it allows double-processing under concurrent requests.
  • Wrap every mutation in a transaction: maestro, maestro_extension/maestro_upgrade, and maestro_log must be updated atomically.
  • Send email only after a successful commit, never inside the transaction.
  • Never use include: { maestro: true } when querying maestro_extension or maestro_upgrade. Always use select with only the needed columns to avoid logging the maestro Password field.
  • Admin password verification uses MariaDB PASSWORD() function — the existing admin table stores hashed passwords this way. Do not change this without a migration plan.
  • Extension approval date calculation happens server-side: if current expiry is in the past, use today +1 year; otherwise use current expiry +1 year.
  • Upgrade approval sets AvailableActivateDateTime = NOW() + 1 year. Do not change PlayerCount on upgrade.
  • When approving an extension or upgrade, close all other Status = 1 requests for the same MaestroID by setting them to Status = 2, then set the approved request to Status = 3.
  • Docker containers must set TZ: Asia/Seoul so that date calculations (setHours(0,0,0,0), formatDate) match the KST-based existing data in the shared MariaDB.

Authentication

  • NextAuth.js v5 (next-auth@5.0.0-beta.31) with Credentials Provider.
  • Config lives in auth.ts (project root), not inside app/.
  • Unauthenticated requests are caught by proxy.ts (middleware) and redirected to /login.
  • API routes must call auth() and return 401 if no session.

Key files

File Purpose
auth.ts NextAuth config (Credentials Provider, MariaDB PASSWORD verify)
proxy.ts Middleware — redirects unauthenticated users to /login
lib/db.ts Prisma Client singleton with SQL pretty-logging and result table logging
lib/logger.ts Structured logger — debug/info/warn/error, level controlled by LOG_LEVEL / APP_ENV
lib/errors.ts ApiError — unified error class with HTTP status code
lib/api-handler.ts withApiHandler — wraps route handlers with auth, timing, and error logging
lib/constants.ts Status code constants (ACTIVATE_STATUS, ACCOUNT_TYPE, REQUEST_STATUS); PAID_ACCOUNT_TYPE_VALUES (유료 계정 유형 배열 — 중복 정의 방지용 공용 상수)
lib/maestros.ts Maestro DB queries
lib/extension-requests.ts Extension request queries and approval logic
lib/upgrade-requests.ts Upgrade request queries and approval logic
prisma/schema.prisma Generated via prisma db pull — do not hand-edit model fields
docs/business-rules.md Full reference for existing chocomae business logic
docs/phase/phase9.md Log policy: levels, format, masking rules, Docker log operations

maestro_log conventions

Always record a log entry after a successful DB change. Use these Type values:

Type When
extension_maestro Extension approved
cancel_extension_maestro Extension cancelled (new type, not in original)
upgrade_maestro Upgrade approved
reject_upgrade_maestro Upgrade rejected (new type, not in original)
update_maestro_name Maestro name changed
update_maestro_email Maestro email changed
update_maestro_status ActivateStatus changed (admin, new)
update_maestro_account_type AccountType changed (admin, new)
update_maestro_available_date AvailableActivateDateTime changed (admin, new)
update_maestro_allow_enter_code AllowEditEnterCode changed (admin, new)

Remark column is char(100) — keep values under 100 characters.

Implemented phases (do not re-implement)

  • Phase 08: login, maestro list/detail, extension requests, upgrade requests, Docker setup, transaction safety, auth guards.
  • Phase 9 (substantially complete): structured logging (lib/logger.ts), withApiHandler wrapper (lib/api-handler.ts), ApiError class (lib/errors.ts), Prisma SQL pretty-logging and result table logging (lib/db.ts). Remaining: correlation IDs, stage/production log verification.
  • Phase 10: Maestro info edit form (PATCH /api/maestros/[id]) + student list with server-side pagination (GET /api/maestros/[id]/students).
  • Phase 11: Email auto-send via Nodemailer after extension/upgrade approval (lib/mail.ts). Upgrade email edge-case verification (trial→paid, paid→paid) still pending.
  • Phase 12: Admin-initiated extension/upgrade request registration from maestro detail page.
    • POST /api/maestros/[id]/extension-requests — inserts into maestro_extension using maestro's current AccountType read server-side; rejects trial account types.
    • POST /api/maestros/[id]/upgrade-requests — inserts into maestro_upgrade inside a transaction; validates requestedAccountType > maestro.AccountType.
    • ExtensionRequestsSection.tsx, UpgradeRequestsSection.tsx — client components with inline action UI; call router.refresh() on success.
    • PAID_ACCOUNT_TYPE_VALUES consolidated in lib/constants.ts — shared by lib/maestros.ts, lib/extension-requests.ts, lib/upgrade-requests.ts, and both new API routes.
  • Phase 13 (security/correctness fixes):
    • P0-1: getActionTarget in lib/extension-requests.ts replaced with inline select (no include: { maestro: true }) — prevents Password from appearing in debug result logs.
    • P0-2: Approve/cancel/reject flows in both lib/extension-requests.ts and lib/upgrade-requests.ts now use an atomic updateMany({ Status: REQUESTED → target }) guard; count === 0 triggers 404/409 — eliminates concurrent double-processing.
    • P0-3: docker-compose.yml and docker-compose.stage.yml now set TZ: Asia/Seoul; lib/maestros.ts date-change log remark uses formatDate() instead of toISOString().slice(0,10) for KST consistency.

Planned phases (not yet implemented)

이후 작업 후보는 docs/plan/project-plan.md Section 10 "MVP 이후 확장 후보" 참조.

Packages to know

  • mariadb + @prisma/adapter-mariadb — Prisma uses the mariadb driver directly (not mysql2)
  • @base-ui/react — used instead of Radix UI primitives for shadcn components
  • zod v4 — Zod v4 API differs from v3; check docs before writing schemas
  • next-auth v5 beta — API surface differs significantly from v4