# 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. - **All mutating APIs must verify current `Status = 1` before acting** (idempotency guard, returns 409 if already processed). - **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. - 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`. ## 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 | `{prev} -> {new}` | | `update_maestro_email` | Maestro email changed | `{prev} -> {new}` | | `update_maestro_status` | ActivateStatus changed (admin, new) | `{prev} -> {new}` (numeric) | | `update_maestro_account_type` | AccountType changed (admin, new) | `{prev} -> {new}` (numeric) | | `update_maestro_available_date` | AvailableActivateDateTime changed (admin, new) | `{YYYY-MM-DD} -> {YYYY-MM-DD}` | | `update_maestro_allow_enter_code` | AllowEditEnterCode changed (admin, new) | `{prev} -> {new}` (0 or 1) | `Remark` column is `char(100)` — keep values under 100 characters. ## Implemented phases (do not re-implement) - Phase 0–8: 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. ## 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