추가 작업 계획

This commit is contained in:
2026-06-14 23:17:27 +09:00
parent b28e88db66
commit bcd0ef2af3
3 changed files with 303 additions and 26 deletions
+70 -2
View File
@@ -1,5 +1,73 @@
<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know # 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. 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.
<!-- END:nextjs-agent-rules -->
---
# 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 |
| `lib/constants.ts` | Status code constants (`ACTIVATE_STATUS`, `ACCOUNT_TYPE`, `REQUEST_STATUS`) |
| `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 |
## 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 |
`Remark` column is `char(100)` — keep values under 100 characters.
## Implemented phases (do not re-implement)
- Phase 08 are complete: login, maestro list/detail, extension requests, upgrade requests, Docker setup, transaction safety, auth guards.
## Planned phases (not yet implemented)
- **Phase 9** — Structured logging (`lib/logger.ts`, correlation IDs, Prisma query logging)
- **Phase 10** — Maestro info edit form + student list with pagination (`PATCH /api/maestros/[id]`, `GET /api/maestros/[id]/students`)
- **Phase 11** — Email auto-send via Nodemailer after extension/upgrade approval (`lib/mail.ts`)
## 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
+118 -21
View File
@@ -1,36 +1,133 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). # chocoadmin
## Getting Started chocomae(mouse-typing) 서비스의 관리자 기능을 독립 Next.js 서비스로 분리한 웹 애플리케이션이다.
First, run the development server: ## 기술 스택
| 구분 | 기술 |
|---|---|
| 프레임워크 | Next.js 16 (App Router) |
| 언어 | TypeScript |
| 패키지 매니저 | pnpm |
| UI / CSS | Tailwind CSS v4 + shadcn/ui (Base UI) |
| Table | TanStack Table v8 |
| ORM | Prisma v7 (MariaDB adapter) |
| 인증 | NextAuth.js v5 (admin 테이블 기반) |
| 유효성 검증 | Zod v4 |
| 이메일 | Nodemailer |
| DB | MariaDB 10.11 (기존 chocomae DB 공유) |
## 구현된 기능
- 관리자 로그인 (기존 `admin` 테이블 / MariaDB `PASSWORD()` 호환)
- 마에스트로 전체 목록 — 검색(이름·이메일·ID), 상태/계정유형 필터, 페이지네이션
- 마에스트로 상세 보기 — 기본 정보, 연장/업그레이드 이력, 처리 로그
- 연장 신청 목록 — 승인 / 취소 (트랜잭션 + `maestro_log`)
- 업그레이드 신청 목록 — 승인 / 거절 (트랜잭션 + `maestro_log`)
- 비인증 접근 차단 (`proxy.ts`, API route `auth()` 검사)
## 개발 환경 설정
### 1. 의존성 설치
```bash ```bash
npm run dev pnpm install
# or
yarn dev
# or
pnpm dev
# or
bun dev
``` ```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. ### 2. 환경변수 설정
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. ```bash
cp .env.example .env.local
```
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. `.env.local`을 열어 실제 값으로 교체한다.
## Learn More ```env
DATABASE_URL="mysql://USER:PASSWORD@127.0.0.1:3306/chocomae"
AUTH_SECRET="..."
NEXTAUTH_SECRET="..."
AUTH_URL="http://localhost:3000"
NEXTAUTH_URL="http://localhost:3000"
```
To learn more about Next.js, take a look at the following resources: ### 3. DB 연결 확인
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. ```bash
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. pnpm db:check
```
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! ### 4. 개발 서버 실행
## Deploy on Vercel ```bash
pnpm dev
```
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. [http://localhost:3000](http://localhost:3000) 에서 확인한다.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. ## 환경변수 전체 목록
| 변수 | 필수 | 설명 |
|---|---|---|
| `DATABASE_URL` | ✅ | MariaDB 연결 문자열 (`mysql://...`) |
| `AUTH_SECRET` | ✅ | NextAuth 세션 암호화 키 |
| `NEXTAUTH_SECRET` | ✅ | NextAuth 호환용 (동일 값) |
| `AUTH_URL` | ✅ | 서비스 기본 URL |
| `NEXTAUTH_URL` | ✅ | NextAuth 호환용 (동일 값) |
| `APP_ENV` | — | `local` \| `stage` \| `production` (Phase 9) |
| `LOG_LEVEL` | — | `debug` \| `info` \| `warn` \| `error` (Phase 9) |
| `MAIL_FROM_NAME` | — | 발송자 이름 (Phase 11) |
| `MAIL_FROM_ADDRESS` | — | 발송자 주소 (Phase 11) |
| `MAIL_BCC_ADDRESS` | — | BCC 주소 (Phase 11) |
| `MAIL_SMTP_HOST` | — | SMTP 호스트 (Phase 11) |
| `MAIL_SMTP_PORT` | — | SMTP 포트 (Phase 11) |
| `MAIL_SMTP_SECURE` | — | TLS 여부 (Phase 11) |
| `MAIL_SMTP_USER` | — | SMTP 인증 계정 (Phase 11) |
| `MAIL_SMTP_PASSWORD` | — | SMTP 인증 비밀번호 (Phase 11) |
| `MAIL_SEND_ENABLED` | — | `true` \| `false` 발송 활성화 (Phase 11) |
## 배포 (Synology NAS Docker)
```bash
# 이미지 빌드 및 컨테이너 시작
docker compose up -d --build
```
`docker-compose.yml``environment` 섹션에 위 환경변수를 설정한다. 상세 절차는 [`docs/deployment.md`](docs/deployment.md)를 참고한다.
## 프로젝트 구조
```
chocoadmin/
├── app/
│ ├── (auth)/login/ # 관리자 로그인
│ ├── (admin)/ # 인증 필요 화면
│ │ ├── maestros/ # 마에스트로 목록·상세
│ │ ├── extension-requests/
│ │ └── upgrade-requests/
│ └── api/ # API routes
├── components/
│ ├── data-table/ # TanStack Table 기반 테이블
│ ├── forms/
│ └── ui/ # shadcn/ui 컴포넌트
├── lib/
│ ├── db.ts # Prisma Client 싱글톤
│ ├── constants.ts # 상태값 상수
│ ├── maestros.ts # 마에스트로 DB 쿼리
│ ├── extension-requests.ts
│ └── upgrade-requests.ts
├── prisma/
│ └── schema.prisma # DB introspection 결과
├── docs/
│ ├── business-rules.md # 기존 서비스 비즈니스 규칙 조사
│ ├── deployment.md
│ └── plan/project-plan.md # 전체 개발 계획
├── auth.ts # NextAuth 설정
├── proxy.ts # 미인증 접근 차단 미들웨어
└── .env.example
```
## 문서
- [`docs/plan/project-plan.md`](docs/plan/project-plan.md) — 전체 개발 단계 계획
- [`docs/business-rules.md`](docs/business-rules.md) — 기존 chocomae 비즈니스 규칙
- [`docs/deployment.md`](docs/deployment.md) — NAS 배포 절차
+115 -3
View File
@@ -37,6 +37,7 @@
| ORM | Prisma (기존 DB introspection 방식으로 활용) | | ORM | Prisma (기존 DB introspection 방식으로 활용) |
| 유효성 검증 | Zod | | 유효성 검증 | Zod |
| 인증 | NextAuth.js v5 (기존 `admin` 테이블 활용) | | 인증 | NextAuth.js v5 (기존 `admin` 테이블 활용) |
| 이메일 발송 | Nodemailer (기존 `mouse-typing` SMTP 설정을 환경변수로 이관) |
| 환경변수 관리 | `.env.local` / `.env.production` | | 환경변수 관리 | `.env.local` / `.env.production` |
### Prisma vs Drizzle ORM ### Prisma vs Drizzle ORM
@@ -170,7 +171,9 @@ chocoadmin/
│ ├── auth/[...nextauth]/ │ ├── auth/[...nextauth]/
│ ├── maestros/ │ ├── maestros/
│ │ ├── route.ts # GET: 목록 │ │ ├── route.ts # GET: 목록
│ │ └── [id]/route.ts # GET: 상세, PATCH: 상태 변경 │ │ └── [id]/
│ │ ├── route.ts # GET: 상세, PATCH: 정보 수정
│ │ └── students/route.ts # GET: 학생 목록
│ ├── extension-requests/ │ ├── extension-requests/
│ │ └── [id]/route.ts # PATCH: 승인/취소 │ │ └── [id]/route.ts # PATCH: 승인/취소
│ └── upgrade-requests/ │ └── upgrade-requests/
@@ -184,6 +187,7 @@ chocoadmin/
├── lib/ ├── lib/
│ ├── db.ts # Prisma Client 싱글톤 │ ├── db.ts # Prisma Client 싱글톤
│ ├── auth.ts # NextAuth 설정 │ ├── auth.ts # NextAuth 설정
│ ├── mail.ts # chocomae SMTP 메일 발송 모듈
│ ├── validators/ # Zod 스키마 │ ├── validators/ # Zod 스키마
│ └── constants.ts # 상태값 상수 │ └── constants.ts # 상태값 상수
├── types/ ├── types/
@@ -222,7 +226,17 @@ chocoadmin/
### 7-3. 마에스트로 상세 정보 (`/maestros/[maestroId]`) ### 7-3. 마에스트로 상세 정보 (`/maestros/[maestroId]`)
- 기본 계정 정보 (이름, 이메일, 계정 유형, 상태, 만료일, 약관 동의일) - 기본 계정 정보 (이름, 이메일, 계정 유형, 상태, 만료일, 약관 동의일)
- 플레이어(학생) 목록 요약 - 기본 계정 정보 수정 및 저장
- 이름: 저장 시 다른 마에스트로 계정에서 이미 사용 중인지 검사하고, 중복이면 저장 실패 처리
- 이메일
- 상태: 콤보박스 (`maestro.ActivateStatus`)
- 계정유형: 콤보박스 (`maestro.AccountType`)
- 사용 가능일 (`maestro.AvailableActivateDateTime`)
- 입장코드 수정: 콤보박스 기반 입력/선택 UI
- 정보 수정 및 저장 성공 시 `maestro_log`에 처리 이력 기록
- 플레이어(학생) 전체 목록
- 서버 사이드 페이지네이션
- 이름 검색
- 연장 신청 이력 - 연장 신청 이력
- 업그레이드 신청 이력 - 업그레이드 신청 이력
- 관리자 처리 로그 (`maestro_log`) - 관리자 처리 로그 (`maestro_log`)
@@ -240,6 +254,12 @@ chocoadmin/
4. `maestro.AvailableActivateDateTime` 연장, `maestro.ActivateStatus → 2` (기존 서비스 로직 확인 후 동일 적용) 4. `maestro.AvailableActivateDateTime` 연장, `maestro.ActivateStatus → 2` (기존 서비스 로직 확인 후 동일 적용)
5. `maestro_log` 기록 5. `maestro_log` 기록
6. 트랜잭션 커밋 6. 트랜잭션 커밋
7. 커밋 후 연장 완료 이메일 자동 발송
**연장 완료 이메일:**
- 기존 호출 위치: `/Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/admin/extension_maestro.php:29`
- 제목: `[초코마에] {마에스트로명} - 마에스트로 계정 유효기간 연장 완료`
- 내용: 유효기간 +1년 연장 완료, 새 유효기간 안내
**취소 처리 순서:** **취소 처리 순서:**
1. `maestro_extension.Status = 1` 인지 확인 1. `maestro_extension.Status = 1` 인지 확인
@@ -261,6 +281,12 @@ chocoadmin/
4. `maestro.AccountType → RequestedAccountType` 변경 (PlayerCount 갱신 정책은 기존 서비스 확인 후 동일 적용) 4. `maestro.AccountType → RequestedAccountType` 변경 (PlayerCount 갱신 정책은 기존 서비스 확인 후 동일 적용)
5. `maestro_log` 기록 5. `maestro_log` 기록
6. 트랜잭션 커밋 6. 트랜잭션 커밋
7. 커밋 후 업그레이드 완료 이메일 자동 발송
**업그레이드 완료 이메일:**
- 기존 호출 위치: `/Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/admin/upgrade_maestro.php:30`
- 제목: `[초코마에] {마에스트로명} - 마에스트로 계정의 요금제 업그레이드 완료 알림`
- 내용: 기존 요금제에서 상위 요금제로 변경 완료, 유효기간 오늘부터 1년
**거절 처리 순서:** **거절 처리 순서:**
1. `maestro_upgrade.Status = 1` 인지 확인 1. `maestro_upgrade.Status = 1` 인지 확인
@@ -280,6 +306,7 @@ chocoadmin/
5. 배포 DB 계정은 chocoadmin 전용 계정으로 분리하고 최소 권한(SELECT + 필요한 테이블만 UPDATE)을 적용한다. 5. 배포 DB 계정은 chocoadmin 전용 계정으로 분리하고 최소 권한(SELECT + 필요한 테이블만 UPDATE)을 적용한다.
6. AWS EC2 보안그룹에서 MariaDB 포트(3306)를 NAS 외부 IP로만 허용한다. 6. AWS EC2 보안그룹에서 MariaDB 포트(3306)를 NAS 외부 IP로만 허용한다.
7. 관리자 전용 서비스이므로 외부에 직접 노출하지 않고 VPN 또는 NAS 내부 포트로 접근하는 방식을 권장한다. 7. 관리자 전용 서비스이므로 외부에 직접 노출하지 않고 VPN 또는 NAS 내부 포트로 접근하는 방식을 권장한다.
8. SMTP/API 인증 정보, 발송자 주소, BCC 주소는 환경변수 또는 배포 시크릿으로 관리하고 코드에 하드코딩하지 않는다.
--- ---
@@ -401,6 +428,91 @@ chocoadmin/
- [ ] production 설정에서 결과 전체가 출력되지 않고 summary/slow query 중심으로 출력되는지 확인 - [ ] production 설정에서 결과 전체가 출력되지 않고 summary/slow query 중심으로 출력되는지 확인
- [ ] 로그에 비밀번호, token, cookie, secret, DB password가 노출되지 않는지 확인 - [ ] 로그에 비밀번호, token, cookie, secret, DB password가 노출되지 않는지 확인
### Phase 10. 마에스트로 정보 수정 및 학생 목록 고도화
> `/maestros/[maestroId]` 상세 화면에서 관리자 계정 정보 수정과 학생 목록 조회를 완성한다.
- [ ] 기존 `mouse-typing` 마에스트로 정보 수정 로직 조사
- [ ] 이름 변경 시 중복 검사 기준 확인 (`maestro.Name`, 자기 자신 제외)
- [ ] 이메일 변경 처리와 로그 형식 확인
- [ ] 입장코드 수정 대상 컬럼과 기존 값 생성/검증 규칙 확인
- [ ] `maestro_log.Type` / `Remark` 형식을 기존 서비스와 맞춤
- [ ] 마에스트로 정보 수정 API 구현 (`PATCH /api/maestros/[id]`)
- [ ] Zod 요청 스키마 정의: 이름, 이메일, 상태, 계정유형, 사용 가능일, 입장코드
- [ ] 관리자 인증 및 권한 검증
- [ ] 이름 중복 검사: 다른 계정이 사용 중이면 저장 실패 응답
- [ ] 트랜잭션으로 `maestro` 정보 수정
- [ ] 변경 전/후 값을 포함해 `maestro_log` 기록
- [ ] 변경 없음, 유효하지 않은 상태값, 존재하지 않는 마에스트로에 대한 응답 정책 정리
- [ ] 마에스트로 상세 화면 수정 폼 구현
- [ ] 이름/이메일 입력
- [ ] 상태 콤보박스
- [ ] 계정유형 콤보박스
- [ ] 사용 가능일 입력
- [ ] 입장코드 수정 콤보박스
- [ ] 저장 전 확인, 저장 중 비활성화, 성공/실패 토스트
- [ ] 학생 목록 API 구현 (`GET /api/maestros/[id]/students`)
- [ ] 전체 학생 목록 조회
- [ ] 서버 사이드 페이지네이션
- [ ] 이름 검색
- [ ] 정렬 기준과 기본 page size 정의
- [ ] 학생 목록 UI 구현
- [ ] 이름 검색 입력
- [ ] 페이지네이션 컨트롤
- [ ] 빈 목록/검색 결과 없음 상태
- [ ] 검증
- [ ] 이름 중복 저장 실패 확인
- [ ] 정보 수정 성공 시 DB 반영과 `maestro_log` 기록 확인
- [ ] 학생 목록 페이지네이션/검색 동작 확인
- [ ] 비인증 접근 차단 확인
### Phase 11. 이메일 발송 환경 및 자동 발송
> 기존 `chocomae` 서비스의 관리자 승인 완료 메일을 `chocoadmin`에서도 동일하게 발송한다.
- [ ] 기존 이메일 발송 설정 이관 준비
- [ ] 기존 서비스 파일 확인: `/Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/mail/send_jinaju_mail.php`
- [ ] 기존 서비스 파일 확인: `/Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/mail/mail_contents.php`
- [ ] 기존 서비스 파일 확인: `/Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/mail/mail_setting.php`
- [ ] 발송자 이름/주소, BCC, SMTP host/port/security/auth 설정을 환경변수로 정리
- [ ] 기존 코드의 하드코딩된 SMTP/API 키를 신규 서비스 코드에 복사하지 않고 `.env` / 배포 시크릿으로 분리
- [ ] 메일 발송 모듈 구현 (`lib/mail.ts`)
- [ ] 공통 메일 클라이언트 생성
- [ ] 발송자, 수신자, BCC, 제목, HTML/텍스트 본문 구성
- [ ] 메일 발송 성공/실패 로그 기록
- [ ] 운영에서 민감정보가 로그에 남지 않도록 마스킹
- [ ] 연장 완료 이메일 템플릿 구현
- [ ] 호출 기준: `/Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/admin/extension_maestro.php:29`
- [ ] 제목: `[초코마에] {마에스트로명} - 마에스트로 계정 유효기간 연장 완료`
- [ ] 내용: 유효기간 +1년 연장 완료, 새 유효기간 안내
- [ ] 관리자가 연장 승인하고 DB 커밋이 정상 완료된 후 자동 발송
- [ ] 업그레이드 완료 이메일 템플릿 구현
- [ ] 호출 기준: `/Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/admin/upgrade_maestro.php:30`
- [ ] 제목: `[초코마에] {마에스트로명} - 마에스트로 계정의 요금제 업그레이드 완료 알림`
- [ ] 내용: 기존 요금제에서 상위 요금제로 변경 완료, 유효기간 오늘부터 1년
- [ ] 관리자가 업그레이드 승인하고 DB 커밋이 정상 완료된 후 자동 발송
- [ ] 승인 API에 이메일 자동 발송 연결
- [ ] `PATCH /api/extension-requests/[id]` 승인 완료 후 연장 완료 메일 발송
- [ ] `PATCH /api/upgrade-requests/[id]` 승인 완료 후 업그레이드 완료 메일 발송
- [ ] 메일 발송 실패 시 승인 결과 롤백 여부를 정책으로 확정하고 구현
- [ ] 동일 승인 건 재호출 시 이메일 중복 발송 방지 정책 정리
- [ ] 환경변수 추가
- [ ] `MAIL_FROM_NAME`
- [ ] `MAIL_FROM_ADDRESS`
- [ ] `MAIL_BCC_ADDRESS`
- [ ] `MAIL_SMTP_HOST`
- [ ] `MAIL_SMTP_PORT`
- [ ] `MAIL_SMTP_SECURE`
- [ ] `MAIL_SMTP_USER`
- [ ] `MAIL_SMTP_PASSWORD`
- [ ] `MAIL_SEND_ENABLED`
- [ ] 문서화 및 검증
- [ ] `.env.example` 또는 배포 문서에 메일 환경변수 설명 추가
- [ ] local/stage에서 테스트 수신자 또는 sandbox 설정으로 발송 테스트
- [ ] 연장 승인 완료 후 이메일 제목/본문/수신자/BCC 확인
- [ ] 업그레이드 승인 완료 후 이메일 제목/본문/수신자/BCC 확인
- [ ] 메일 발송 실패 로그와 관리자 화면 응답 확인
--- ---
## 10. MVP 범위 ## 10. MVP 범위
@@ -414,8 +526,8 @@ chocoadmin/
- Docker 기반 NAS 배포 - Docker 기반 NAS 배포
**MVP 이후 확장 후보:** **MVP 이후 확장 후보:**
- 마에스트로 상태 직접 변경
- 학생 목록 상세 관리 - 학생 목록 상세 관리
- 이메일 발송 이력/재발송 관리
- 데이터 내보내기 (CSV) - 데이터 내보내기 (CSV)
- 처리 통계 대시보드 - 처리 통계 대시보드
- 감사 로그 전용 화면 - 감사 로그 전용 화면