전체 코드, 구조 검토 - P0 코드 수정 진행

This commit is contained in:
2026-07-04 10:13:12 +09:00
parent 854a3e2bfb
commit 3c5848cdc5
9 changed files with 339 additions and 101 deletions
+7 -1
View File
@@ -11,13 +11,15 @@ Admin panel for the chocomae service (mouse-typing), extracted into a standalone
## 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).
- **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
@@ -74,6 +76,10 @@ Always record a log entry after a successful DB change. Use these `Type` values:
- `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)