diff --git a/docs/business-rules.md b/docs/business-rules.md new file mode 100644 index 0000000..a56f466 --- /dev/null +++ b/docs/business-rules.md @@ -0,0 +1,354 @@ +# 기존 관리자 비즈니스 규칙 + +작성일: 2026-06-09 + +## 1. 개요 + +이 문서는 기존 `mouse-typing` 관리자 기능을 조사해 신규 `choco-admin`에서 재현해야 할 비즈니스 규칙을 정리한 것이다. + +조사 대상: + +- 기존 서비스: `/Users/jisangs/work/jinaju/git/web/mouse-typing` +- 관리자 화면: `src/web/admin/` +- 관리자 서버: `src/web/server/admin/` +- 공통 로그 유틸: `src/web/server/lib/maestro_log.php` +- 계정 표시/계산 유틸: `src/web/js/lib/account_info.js`, `src/web/js/maestro_available_date.js` + +중요 결론: + +- 관리자 비밀번호는 MariaDB `PASSWORD()` 함수로 검증한다. +- 연장 승인은 기존 만료일 기준 1년 연장하되, 만료된 계정은 오늘 기준 1년 연장한다. +- 기존 연장 승인 서버는 날짜를 직접 계산하지 않고 화면에서 전달한 `new_available_date`를 저장한다. +- 업그레이드 승인은 `AccountType`, `ActivateStatus`, `AvailableActivateDateTime`만 변경하고 `PlayerCount`는 변경하지 않는다. +- 기존 관리자에는 연장 취소/업그레이드 거절 버튼이 없다. 승인 처리 중 같은 마에스트로의 다른 요청을 `Status=2`로 닫는 동작만 있다. +- 기존 변경 처리에는 명시적 트랜잭션이 없다. + +## 2. 기존 관리자 파일 맵 + +| 기존 화면 | 서버 파일 | 역할 | 신규 `choco-admin` 매핑 | +|---|---|---|---| +| `admin/login.html` | `server/admin/login.php` | 관리자 로그인 | `/login`, NextAuth Credentials Provider | +| `admin/admin_all_list.html` | `server/admin/maestro_all_list.php` | 전체 마에스트로 목록 조회 | `/maestros`, `GET /api/maestros` | +| `admin/admin_register_list.html` | `server/admin/maestro_registered_list.php`, `server/admin/register_maestro.php` | 미승인 마에스트로 조회 및 등록 승인 | MVP 외 또는 상세 보조 규칙 | +| `admin/admin_extension_list.html` | `server/admin/maestro_extension_list.php`, `server/admin/extension_maestro.php` | 연장 요청 조회 및 승인 | `/extension-requests`, `PATCH /api/extension-requests/[id]` | +| `admin/admin_upgrade_list.html` | `server/admin/maestro_upgrade_list.php`, `server/admin/upgrade_maestro.php` | 업그레이드 요청 조회 및 승인 | `/upgrade-requests`, `PATCH /api/upgrade-requests/[id]` | +| `admin/admin_expiration_list.html` | 없음 | 정적 골격만 존재, 실제 조회 로직 없음 | MVP 제외 | +| `admin/admin_send_email.html` | `server/mail/send_mail_test.php` | 테스트 메일 발송 화면 | MVP 제외 | +| `admin/admin_header.html` | 없음 | 관리자 메뉴 링크 | 공통 사이드바/헤더 | + +## 3. 상태값 코드표 + +### `maestro.AccountType` + +| 값 | 의미 | 정원 | 금액 | +|---:|---|---:|---:| +| 1 | 20명 | 20 | 10,000 | +| 2 | 50명 | 50 | 20,000 | +| 3 | 100명 | 100 | 30,000 | +| 4 | 500명 | 500 | 40,000 | +| 5 | 1,000명 | 1,000 | 50,000 | +| 100 | 학생체험 | - | - | +| 101 | 마에체험 | - | - | + +### `maestro.ActivateStatus` + +| 값 | 기존 표시 | 의미 | +|---:|---|---| +| 0 | 미승인 / 입금대기 | 가입 후 관리자 승인 전 | +| 1 | 체험 | 체험 계정 | +| 2 | 활성화 | 유료 활성 계정 | +| 100 | 등록 취소 / 환불 | 등록 취소 또는 환불 상태 | + +### `maestro_extension.Status` + +| 값 | 기존 표시 | 의미 | +|---:|---|---| +| 1 | 요청 | 연장 요청 | +| 2 | 취소 | 닫힌 요청 | +| 3 | 업그레이드 적용 | 코드상 공통 표시 문구이나 실제 의미는 연장 적용 | + +### `maestro_upgrade.Status` + +| 값 | 기존 표시 | 의미 | +|---:|---|---| +| 1 | 요청 | 업그레이드 요청 | +| 2 | 취소 | 닫힌 요청 | +| 3 | 업그레이드 적용 | 업그레이드 적용 | + +## 4. 로그인/관리자 인증 규칙 + +기존 흐름: + +1. `login.html`에서 `admin_name`, `password`를 `server/admin/login.php`로 POST한다. +2. `get_admin_id($adminName)`에서 `admin.Name = ?` 조건으로 관리자 존재 여부를 먼저 확인한다. +3. `login($adminName, $password)`에서 `admin.Name = ? AND admin.Password = PASSWORD(?)` 조건으로 검증한다. +4. 응답 데이터로 `adminID`, `accountType`, `activateStatus`를 반환한다. + +실패 조건: + +| 조건 | error_code | message | +|---|---|---| +| `Name`에 해당하는 관리자 없음 | `not_registered_id` | 등록되지 않은 서비스 관리자 아이디입니다. | +| 비밀번호 검증 결과 없음 | `no_data` 또는 `wrong_password` | 로그인하지 못했습니다. / 비밀번호가 틀렸습니다. | +| `ActivateStatus === 0` | `not_activated` | 서비스 관리자 계정이 아직 활성화되지 않았습니다. | + +신규 구현 규칙: + +- 기존 계정 호환을 위해 최초 구현은 MariaDB `PASSWORD()` 함수를 이용해 검증한다. +- NextAuth 세션에는 최소 `adminID`, `accountType`, `activateStatus`를 포함한다. +- `ActivateStatus = 0` 관리자는 로그인시키지 않는다. +- `PASSWORD()`는 보안상 낡은 방식이므로, 해시 업그레이드는 별도 마이그레이션 과제로 분리한다. + +## 5. 마에스트로 목록 조회 규칙 + +### 전체 목록 + +기존 서버: `server/admin/maestro_all_list.php` + +검색어가 없을 때: + +- 테이블: `maestro` +- 컬럼: `MaestroID`, `Name`, `AccountType`, `ActivateStatus`, `AvailableActivateDateTime`, `AcceptClausesDateTime`, `PlayerCount` +- 정렬: `MaestroID DESC` + +검색어가 있을 때: + +- 조건: `Name LIKE CONCAT('%', ?, '%')` +- 정렬: `MaestroID DESC` +- 주의: 기존 검색 쿼리는 `AvailableActivateDateTime`을 조회하지 않는데 화면은 해당 값을 사용한다. 신규 구현에서는 전체/검색 결과 모두 동일 컬럼을 반환해야 한다. + +기존 화면 표시: + +- 상태 텍스트는 `accountStatus(accountType, activateStatus)`로 계산한다. +- `AvailableActivateDateTime`이 `0`으로 시작하면 빈 문자열로 표시한다. +- 비활성화 버튼은 disabled 상태이며 동작하지 않는다. + +신규 구현 규칙: + +- `Name`, `Email`, `MaestroID` 검색을 지원하되 기존 기본 정렬은 `MaestroID DESC`로 시작한다. +- 전체/검색 결과의 반환 컬럼 차이를 만들지 않는다. + +### 미승인 등록 목록 + +기존 서버: `server/admin/maestro_registered_list.php` + +- 테이블: `maestro` +- 조건: `ActivateStatus = 0` +- 검색 조건: `Name LIKE CONCAT('%', ?, '%') AND ActivateStatus = 0` +- 컬럼: `MaestroID`, `Name`, `AccountType`, `AcceptClausesDateTime` +- 정렬: `MaestroID DESC` + +## 6. 등록/활성화 처리 규칙 + +기존 서버: `server/admin/register_maestro.php` + +처리 순서: + +1. `maestro.ActivateStatus = 1`로 변경한다. +2. `maestro.AvailableActivateDateTime = '2022-07-31 23:59:59'`로 변경한다. +3. `player`에 테스트 플레이어 `Name='마에스트로'`, `EnterCode=''`, `AccountType=1`을 추가한다. +4. 추가된 테스트 플레이어를 `maestro.MaestroTestID`에 저장한다. +5. `app.Status = 1`인 앱을 모두 `active_app`에 추가한다. +6. 샘플 학생 4명을 `player.AccountType = 0`으로 추가한다. +7. `player.AccountType = 0` 학생 수를 세어 `maestro.PlayerCount`에 저장한다. +8. 등록 완료 메일을 발송한다. +9. `maestro_log`에 `register_maestro` 로그를 기록한다. + +주의: + +- 코드에는 `DATE_ADD(NOW(), INTERVAL 1 YEAR)`와 `DATE_ADD(NOW(), INTERVAL 14 DAY)`가 주석으로 남아 있지만 실제 실행 쿼리는 고정일 `2022-07-31 23:59:59`다. +- 현재 MVP의 핵심 변경 기능은 연장/업그레이드이므로 등록 승인은 별도 범위로 둘 수 있다. + +## 7. 연장 신청 조회/승인 규칙 + +### 요청 생성 + +기존 서버: `server/maestro/request_extension_maestro.php` + +- `maestro_extension`에 `AccountType`, `RequestedDateTime = NOW()`, `Status = 1`, `MaestroID`를 INSERT한다. +- 같은 마에스트로의 기존 요청 중복 여부는 검사하지 않는다. +- INSERT 후 `MaestroID` 기준 전체 연장 요청 수가 1개 이상인지 단순 확인한다. +- 입금 안내 메일을 발송한다. + +### 관리자 목록 조회 + +기존 서버: `server/admin/maestro_extension_list.php` + +검색어가 없을 때: + +- 테이블: `maestro_extension E`, `maestro M` +- 조건: `E.Status < 2 AND E.MaestroID = M.MaestroID` +- 컬럼: `E.MaestroExtensionID`, `E.MaestroID`, `M.Name`, `E.AccountType`, `E.RequestedDateTime`, `M.AvailableActivateDateTime`, `E.Status` +- 정렬: `E.MaestroExtensionID DESC` + +검색어가 있을 때: + +- 조건: `M.Name LIKE CONCAT('%', ?, '%') AND E.MaestroID = M.MaestroID` +- 주의: 검색 쿼리에는 `E.Status < 2` 조건이 없다. 신규 구현에서는 기본 정책에 맞게 상태 필터를 명시적으로 제공해야 한다. + +### 관리자 승인 + +기존 화면: `admin/admin_extension_list.html` + +- `availableActivateDateTime`의 날짜 부분을 기준으로 새 만료일을 계산한다. +- 계산 유틸: `src/web/js/maestro_available_date.js` +- 현재 만료일이 지났으면 오늘 기준 1년 후 날짜를 사용한다. +- 현재 만료일이 지나지 않았으면 기존 만료일 기준 1년 후 날짜를 사용한다. +- 서버에는 `new_available_date` 문자열을 POST한다. + +기존 서버: `server/admin/extension_maestro.php` + +처리 순서: + +1. `maestro.ActivateStatus = 2`, `maestro.AvailableActivateDateTime = DATE_FORMAT(?, '%Y-%m-%d')`로 변경한다. +2. 같은 `MaestroID`의 `maestro_extension.Status = 1` 요청을 모두 `Status = 2`로 변경한다. +3. 선택한 `MaestroExtensionID` 요청을 `Status = 3`으로 변경한다. +4. 연장 완료 메일을 발송한다. +5. `maestro_log`에 `extension_maestro` 로그를 기록한다. + +로그: + +- `Type`: `extension_maestro` +- `Remark`: `{maestro_name}({registered_account_type})` + +신규 구현 규칙: + +- 날짜 계산은 클라이언트가 아니라 서버에서 수행한다. +- 기존 규칙과 동일하게 만료 전이면 기존 만료일 기준 +1년, 만료 후면 현재일 기준 +1년으로 계산한다. +- `AvailableActivateDateTime` 저장 시 기존 서버는 날짜만 저장하므로 시간은 DB 기본 파싱 결과를 고려해야 한다. 신규 구현에서는 일관성을 위해 `YYYY-MM-DD 00:00:00` 또는 기존 호환 형식을 명시한다. +- 승인 전 선택한 요청이 `Status = 1`인지 확인한다. +- 트랜잭션 안에서 `maestro`, `maestro_extension`, `maestro_log`를 함께 처리한다. +- 같은 마에스트로의 다른 `Status = 1` 요청을 `Status = 2`로 닫은 뒤 선택 요청을 `Status = 3`으로 적용하는 기존 동작을 재현한다. + +## 8. 업그레이드 신청 조회/승인 규칙 + +### 요청 생성 + +기존 서버: `server/maestro/request_upgrade_maestro.php` + +- `maestro_upgrade`에 `RegisteredActivateStatus`, `RegisteredAccountType`, `RequestedAccountType`, `RequestedDateTime = NOW()`, `Status = 1`, `MaestroID`를 INSERT한다. +- 같은 마에스트로의 기존 요청 중복 여부는 검사하지 않는다. +- INSERT 후 `MaestroID` 기준 전체 업그레이드 요청 수가 1개 이상인지 단순 확인한다. +- 체험 계정이면 체험 업그레이드 입금 안내 메일, 그 외에는 일반 업그레이드 입금 안내 메일을 발송한다. + +### 관리자 목록 조회 + +기존 서버: `server/admin/maestro_upgrade_list.php` + +검색어가 없을 때: + +- 테이블: `maestro_upgrade U`, `maestro M` +- 조건: `U.Status < 2 AND U.MaestroID = M.MaestroID` +- 컬럼: `U.MaestroUpgradeID`, `U.MaestroID`, `M.Name`, `U.RegisteredActivateStatus`, `U.RegisteredAccountType`, `U.RequestedAccountType`, `U.RequestedDateTime`, `M.AvailableActivateDateTime`, `U.Status` +- 정렬: `U.MaestroUpgradeID DESC` + +검색어가 있을 때: + +- 조건: `M.Name LIKE CONCAT('%', ?, '%') AND U.MaestroID = M.MaestroID` +- 주의: 검색 쿼리에는 `U.Status < 2` 조건이 없다. 신규 구현에서는 상태 필터를 명시적으로 제공해야 한다. + +### 관리자 승인 + +기존 화면: `admin/admin_upgrade_list.html` + +- `Status = 1`인 요청만 승인 버튼을 표시한다. +- 체험 계정(`RegisteredActivateStatus = 1`)은 기존 요금제를 `trialAccountType`으로 표시하고 추가 금액은 요청 요금제 전체 금액으로 계산한다. +- 그 외 계정은 추가 금액을 `RequestedAccountType` 금액 - `RegisteredAccountType` 금액으로 계산한다. + +기존 서버: `server/admin/upgrade_maestro.php` + +처리 순서: + +1. `maestro.AccountType = upgrade_account_type`으로 변경한다. +2. `maestro.ActivateStatus = 2`로 변경한다. +3. `maestro.AvailableActivateDateTime = DATE_ADD(NOW(), INTERVAL 1 YEAR)`로 변경한다. +4. 같은 `MaestroID`의 `maestro_upgrade.Status = 1` 요청을 모두 `Status = 2`로 변경한다. +5. 선택한 `MaestroUpgradeID` 요청을 `Status = 3`으로 변경한다. +6. 체험 계정이면 체험 업그레이드 완료 메일, 그 외에는 일반 업그레이드 완료 메일을 발송한다. +7. `maestro_log`에 `upgrade_maestro` 로그를 기록한다. + +로그: + +- `Type`: `upgrade_maestro` +- `Remark`: `{registered_account_type} -> {upgrade_account_type}` + +확정 사항: + +- `PlayerCount`는 변경하지 않는다. +- `AvailableActivateDateTime`은 기존 만료일 기준이 아니라 승인 시점 `NOW()` 기준 1년 후로 설정한다. + +신규 구현 규칙: + +- 승인 전 선택한 요청이 `Status = 1`인지 확인한다. +- 트랜잭션 안에서 `maestro`, `maestro_upgrade`, `maestro_log`를 함께 처리한다. +- 같은 마에스트로의 다른 `Status = 1` 요청을 `Status = 2`로 닫은 뒤 선택 요청을 `Status = 3`으로 적용하는 기존 동작을 재현한다. +- `PlayerCount`는 업그레이드 승인에서 변경하지 않는다. + +## 9. 취소/거절 규칙 + +기존 관리자 UI/서버에서 확인된 사실: + +- 연장 신청에 대한 별도 취소 버튼이나 취소 API는 없다. +- 업그레이드 신청에 대한 별도 거절 버튼이나 거절 API는 없다. +- `Status = 2`는 승인 처리 중 같은 마에스트로의 다른 미처리 요청을 닫기 위해 사용된다. +- 화면 유틸 `status()`는 `Status = 2`를 "취소"로 표시하지만, 관리자가 명시적으로 취소/거절하는 흐름은 구현되어 있지 않다. + +신규 구현 판단: + +- `docs/plan/project-plan.md`의 취소/거절 기능은 기존 관리자 재현이 아니라 신규 보완 기능이다. +- 취소/거절 API를 만들 경우 `Status = 1`인 단일 요청만 `Status = 2`로 변경하고 `maestro_log`에 별도 로그를 남기는 방식으로 정의해야 한다. +- 기존 `maestro_log.Type`에는 취소/거절 전용 타입이 없으므로 신규 타입을 도입할지 기존 타입에 `Remark`로 표현할지 결정이 필요하다. + +권장 신규 로그 타입: + +- `cancel_extension_maestro` +- `reject_upgrade_maestro` + +## 10. `maestro_log` 기록 규칙 + +공통 함수: `src/web/server/lib/maestro_log.php` + +```sql +INSERT INTO maestro_log (Type, MaestroID, LogDateTime, Remark) +VALUES (?, ?, NOW(), ?) +``` + +확인된 로그 타입: + +| Type | 발생 위치 | Remark 형식 | +|---|---|---| +| `add_maestro` | `server/maestro/add_maestro.php` | `{maestro_name} / {email} / {account_type}` | +| `register_maestro` | `server/admin/register_maestro.php` | `{name} / {email}` | +| `extension_maestro` | `server/admin/extension_maestro.php` | `{maestro_name}({registered_account_type})` | +| `upgrade_maestro` | `server/admin/upgrade_maestro.php` | `{registered_account_type} -> {upgrade_account_type}` | +| `update_maestro_name` | `server/maestro/update_maestro_info.php` | `{previous_name} -> {new_name}` | +| `update_maestro_email` | `server/maestro/update_maestro_info.php` | `{previous_email} -> {new_email}` | + +확인 결과: + +- `update_maestro` 타입은 코드 검색에서 확인되지 않았다. +- 로그에는 관리자 ID나 관리자 이름이 포함되지 않는다. +- 로그 시간은 DB 서버의 `NOW()`를 사용한다. +- `Remark` 컬럼은 `char(100)`이므로 신규 구현에서도 길이 초과에 주의한다. + +## 11. 신규 `choco-admin` 구현 시 반드시 지켜야 할 규칙 + +- 운영 DB 스키마는 변경하지 않는다. +- 관리자 로그인은 기존 `admin.Name`과 `admin.Password = PASSWORD(?)` 호환 검증을 지원한다. +- 모든 변경 API는 서버에서 현재 상태를 다시 조회하고 `Status = 1`인지 확인한다. +- 승인/취소/거절 같은 변경 작업은 트랜잭션으로 묶는다. +- 연장 승인은 서버에서 새 만료일을 계산한다. +- 업그레이드 승인은 `PlayerCount`를 변경하지 않는다. +- 연장/업그레이드 승인 시 같은 마에스트로의 다른 요청을 `Status = 2`로 닫고 선택 요청을 `Status = 3`으로 적용한다. +- 기존 목록 검색 쿼리의 상태 필터 누락은 그대로 복제하지 말고 명시적 필터로 보완한다. +- 메일 발송은 트랜잭션 커밋 이후 수행하는 것이 안전하다. 기존 코드는 DB 변경 후 메일을 발송한다. + +## 12. 기존 코드에는 없지만 신규 구현에서 보완할 사항 + +- 명시적 트랜잭션: 기존 관리자 변경 로직에는 `BEGIN`, `COMMIT`, `ROLLBACK`이 없다. +- 중복 처리 방지: 기존 승인 서버는 요청의 현재 `Status`를 먼저 검증하지 않는다. +- 서버 사이드 날짜 계산: 기존 연장 승인은 클라이언트 계산값을 신뢰한다. +- 검색 필터 일관성: 연장/업그레이드 검색 쿼리에 `Status < 2` 조건이 빠져 있다. +- 목록 컬럼 일관성: 전체 마에스트로 검색 쿼리에 `AvailableActivateDateTime`이 빠져 있다. +- 취소/거절 정의: 기존에는 별도 액션이 없으므로 신규 기능으로 명세화해야 한다. +- 감사성 강화: 기존 `maestro_log`에는 관리자 식별자가 없으므로 세션 기반 감사 로그가 필요하면 별도 설계가 필요하다. 단, DB 스키마 변경 없이 구현하려면 `Remark`에 관리자 정보를 포함하는 방식만 가능하다. diff --git a/docs/phase/phase0.md b/docs/phase/phase0.md new file mode 100644 index 0000000..5aaa3e8 --- /dev/null +++ b/docs/phase/phase0.md @@ -0,0 +1,285 @@ +# Phase 0 작업 계획 + +## 1. 목적 + +`docs/plan/project-plan.md`의 `9. 개발 단계 계획 > Phase 0. 기존 관리자 코드 조사`를 수행하기 위한 실행 계획이다. + +Phase 0의 목표는 기존 `mouse-typing` 관리자 기능의 비즈니스 규칙을 확인하고, 신규 `choco-admin`에서 동일하게 재현해야 할 규칙을 `docs/business-rules.md`에 문서화하는 것이다. + +## 2. 조사 대상 + +기존 서비스 경로: + +- `/Users/jisangs/work/jinaju/git/web/mouse-typing` + +우선 조사 디렉터리: + +- `/Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/admin/` +- `/Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/admin/` + +주요 서버 파일: + +- `login.php` +- `maestro_all_list.php` +- `maestro_registered_list.php` +- `maestro_extension_list.php` +- `extension_maestro.php` +- `maestro_upgrade_list.php` +- `upgrade_maestro.php` +- `register_maestro.php` +- `activate_stage.php` + +주요 화면 파일: + +- `login.html` +- `admin_all_list.html` +- `admin_register_list.html` +- `admin_extension_list.html` +- `admin_upgrade_list.html` +- `admin_expiration_list.html` +- `admin_header.html` + +## 3. 확인해야 할 핵심 질문 + +### 3-1. 관리자 라우트와 기능 구조 + +- 관리자 화면별 HTML 파일과 서버 PHP 파일의 호출 관계를 확인한다. +- 각 화면의 목록 조회 조건, 검색 조건, 정렬 기준, 상태 필터를 확인한다. +- 신규 `choco-admin`의 화면/API 구조와 직접 매핑 가능한 기능 목록을 정리한다. + +산출물: + +- 기존 화면 -> 기존 서버 파일 -> 신규 화면/API 매핑표 + +### 3-2. 연장 승인 규칙 + +- `extension_maestro.php`에서 연장 승인 처리 흐름을 확인한다. +- `maestro_extension.Status` 변경값과 변경 조건을 확인한다. +- `maestro.AvailableActivateDateTime` 계산 방식을 확인한다. +- `maestro.ActivateStatus` 변경 여부와 값을 확인한다. +- 실패/중복 처리 조건이 있는지 확인한다. + +현재 `docs/plan/project-plan.md`에 기록된 가정: + +- 계정 유형별 차이 없이 1년 연장 + +검증 기준: + +- 기존 코드에서 날짜 계산 로직이 `+1 year`, `+12 month`, 고정 일수 중 무엇인지 확인한다. +- 만료일이 과거인 경우 기준일이 현재일인지 기존 만료일인지 확인한다. + +### 3-3. 업그레이드 승인 규칙 + +- `upgrade_maestro.php`에서 업그레이드 승인 처리 흐름을 확인한다. +- `maestro_upgrade.Status` 변경값과 변경 조건을 확인한다. +- `maestro.AccountType` 변경 기준을 확인한다. +- `maestro.PlayerCount`를 즉시 변경하는지 확인한다. +- 거절 처리 시 변경되는 테이블과 로그를 확인한다. + +현재 `docs/plan/project-plan.md`에 기록된 가정: + +- `AccountType`만 변경 +- `PlayerCount`는 변경하지 않음 + +검증 기준: + +- 승인 SQL에 `PlayerCount` 업데이트가 포함되는지 확인한다. +- 목록 조회 시 `RegisteredAccountType`, `RequestedAccountType`을 어떻게 표시하는지 확인한다. + +### 3-4. 관리자 비밀번호 검증 방식 + +- `login.php`에서 `admin.Password` 검증 SQL을 확인한다. +- MariaDB `PASSWORD()` 함수 사용 여부를 확인한다. +- 세션에 저장되는 관리자 식별자와 권한 정보를 확인한다. +- 실패 응답 형식과 비활성 관리자 처리 여부를 확인한다. + +현재 `docs/plan/project-plan.md`에 기록된 가정: + +- MariaDB `PASSWORD()` 함수로 저장/검증 + +검증 기준: + +- `WHERE Password = PASSWORD(?)` 형태인지 확인한다. +- `ActivateStatus`, `AccountType` 같은 추가 조건이 있는지 확인한다. + +### 3-5. `maestro_log` 기록 형식 + +- 관리자 변경 액션이 `maestro_log`에 기록되는 모든 지점을 찾는다. +- `Type` 값 목록을 확인한다. +- `Remark` 문자열 형식과 포함 정보, 날짜 형식을 확인한다. +- 로그 작성 시 관리자 ID/이름이 포함되는지 확인한다. + +현재 `docs/plan/project-plan.md`에 기록된 `Type` 후보: + +- `add_maestro` +- `update_maestro` +- `register_maestro` +- `update_maestro_name` +- `extension_maestro` +- `upgrade_maestro` +- `update_maestro_email` + +검증 기준: + +- 중복 기재된 값과 실제 미사용 값을 정리한다. +- 각 액션별 `Remark` 예시를 코드 기준으로 문서화한다. + +## 4. 작업 순서 + +### Step 1. 파일 인벤토리 작성 + +- 관리자 HTML/PHP 파일 목록을 확정한다. +- 각 파일의 역할을 한 줄로 요약한다. +- AJAX 호출 URL, form action, query parameter를 찾는다. + +완료 기준: + +- `docs/business-rules.md`에 "기존 관리자 파일 맵" 섹션 초안 작성 + +### Step 2. 로그인 로직 조사 + +- `login.html`과 `login.php`를 연결해 인증 흐름을 추적한다. +- DB 조회 조건, 비밀번호 검증 방식, 세션 키를 기록한다. +- 신규 NextAuth Credentials Provider에서 재현해야 할 조건을 정리한다. + +완료 기준: + +- `admin.Password` 검증 방식 확정 +- 로그인 성공/실패 조건 문서화 + +### Step 3. 목록 조회 로직 조사 + +- 전체 마에스트로 목록, 등록 신청 목록, 연장 신청 목록, 업그레이드 신청 목록 SQL을 확인한다. +- 조인 테이블, 상태 필터, 기본 정렬, 표시 컬럼을 정리한다. +- 신규 API 쿼리 설계에 필요한 컬럼 목록을 분리한다. + +완료 기준: + +- 신규 목록 API별 필수 SQL 조건 문서화 + +### Step 4. 등록/활성화 처리 조사 + +- `register_maestro.php`와 `activate_stage.php`의 상태 변경 로직을 확인한다. +- `maestro.ActivateStatus`, `AvailableActivateDateTime`, `maestro_log` 처리 규칙을 기록한다. +- MVP 범위에 직접 포함되지 않더라도 상세 화면과 로그 해석에 필요한 규칙을 정리한다. + +완료 기준: + +- 마에스트로 상태값 변경 규칙 문서화 + +### Step 5. 연장 승인/취소 처리 조사 + +- `maestro_extension_list.php`에서 목록 조회 조건을 확인한다. +- `extension_maestro.php`에서 승인/취소 처리 SQL을 순서대로 기록한다. +- 트랜잭션 사용 여부와 중복 처리 방지 조건을 확인한다. +- 신규 구현에서 보완해야 할 원자성/중복 방지 항목을 별도로 표시한다. + +완료 기준: + +- 연장 승인 시 날짜 계산 기준 확정 +- 연장 취소 시 상태값과 로그 형식 확정 + +### Step 6. 업그레이드 승인/거절 처리 조사 + +- `maestro_upgrade_list.php`에서 목록 조회 조건을 확인한다. +- `upgrade_maestro.php`에서 승인/거절 처리 SQL을 순서대로 기록한다. +- `AccountType`, `PlayerCount`, `maestro_upgrade.Status`, `maestro_log` 변경 규칙을 확인한다. +- 신규 구현에서 보완해야 할 원자성/중복 방지 항목을 별도로 표시한다. + +완료 기준: + +- 업그레이드 승인 시 변경 컬럼 확정 +- 업그레이드 거절 시 상태값과 로그 형식 확정 + +### Step 7. 비즈니스 규칙 문서 작성 + +`docs/business-rules.md`를 생성하고 다음 구조로 정리한다. + +- 개요 +- 기존 관리자 파일 맵 +- 상태값 코드표 +- 로그인/관리자 인증 규칙 +- 마에스트로 목록 조회 규칙 +- 등록/활성화 처리 규칙 +- 연장 신청 조회/승인/취소 규칙 +- 업그레이드 신청 조회/승인/거절 규칙 +- `maestro_log` 기록 규칙 +- 신규 `choco-admin` 구현 시 반드시 지켜야 할 규칙 +- 기존 코드에는 없지만 신규 구현에서 보완할 사항 + +완료 기준: + +- Phase 1 이후 구현자가 기존 PHP 코드를 다시 열지 않아도 핵심 규칙을 확인할 수 있어야 한다. + +## 5. 조사 방법 + +권장 검색 명령: + +```bash +rg -n "maestro_log|extension_maestro|upgrade_maestro|PASSWORD|AvailableActivateDateTime|PlayerCount|ActivateStatus|AccountType|Status" /Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/admin +``` + +파일별 상세 확인: + +```bash +sed -n '1,240p' /Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/admin/login.php +sed -n '1,260p' /Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/admin/extension_maestro.php +sed -n '1,260p' /Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/server/admin/upgrade_maestro.php +``` + +HTML 호출부 확인: + +```bash +rg -n "ajax|fetch|XMLHttpRequest|form|server/admin|extension_maestro|upgrade_maestro|login.php" /Users/jisangs/work/jinaju/git/web/mouse-typing/src/web/admin +``` + +## 6. 완료 산출물 + +Phase 0 완료 시 저장소에 다음 문서가 있어야 한다. + +- `docs/business-rules.md` + - 기존 관리자 비즈니스 규칙의 최종 문서 +- `docs/phase/phase0.md` + - Phase 0 수행 계획 문서 + +필요하면 다음 보조 자료를 `docs/` 아래에 추가한다. + +- `docs/admin-file-map.md` + - 파일 매핑이 길어질 경우 분리 +- `docs/sql-notes.md` + - 기존 SQL 원문 기록이 길어질 경우 분리 + +## 7. 완료 체크리스트 + +- [x] `src/web/admin/` 화면 파일과 `src/web/server/admin/` 처리 파일의 연결 관계를 정리했다. +- [x] 연장 승인 시 `AvailableActivateDateTime` 계산 방식을 코드 기준으로 확정했다. +- [x] 연장 승인/취소 시 변경되는 테이블, 컬럼, 상태값, 로그 형식을 정리했다. +- [x] 업그레이드 승인 시 `PlayerCount` 갱신 여부를 코드 기준으로 확정했다. +- [x] 업그레이드 승인/거절 시 변경되는 테이블, 컬럼, 상태값, 로그 형식을 정리했다. +- [x] `admin.Password` 저장/검증 방식을 코드 기준으로 확정했다. +- [x] `maestro_log.Type` 값과 `Remark` 형식을 액션별로 정리했다. +- [x] 기존 코드에 트랜잭션/중복 처리 방지가 부족한 지점을 신규 구현 보완사항으로 표시했다. +- [x] 조사 결과를 `docs/business-rules.md`에 문서화했다. +- [x] `docs/plan/project-plan.md`의 Phase 0 체크리스트를 완료 처리할 수 있는 상태가 되었다. + +## 8. 리스크와 주의사항 + +- 기존 PHP 코드가 트랜잭션 없이 여러 SQL을 순차 실행할 수 있다. 신규 서비스는 기존 결과는 동일하게 유지하되, 변경 액션은 트랜잭션으로 보완한다. +- 기존 코드에 중복 처리 방지 조건이 없더라도 신규 API는 `Status = 1` 조건 확인 후 변경해야 한다. +- MariaDB `PASSWORD()` 함수는 최신 인증용 해시로 적합하지 않다. Phase 0에서는 기존 검증 방식을 정확히 재현하고, 해시 업그레이드는 별도 후속 과제로 분리한다. +- 운영 DB 스키마는 임의 변경하지 않는다. +- 문서화 시 추측과 코드로 확인된 사실을 구분해 적는다. + +## 9. 예상 일정 + +| 순서 | 작업 | 예상 소요 | +|---|---|---:| +| 1 | 파일 인벤토리와 호출 관계 정리 | 30분 | +| 2 | 로그인/인증 로직 조사 | 20분 | +| 3 | 목록 조회 SQL 조사 | 40분 | +| 4 | 등록/활성화 처리 조사 | 30분 | +| 5 | 연장 승인/취소 처리 조사 | 40분 | +| 6 | 업그레이드 승인/거절 처리 조사 | 40분 | +| 7 | `docs/business-rules.md` 작성 및 검토 | 60분 | + +총 예상 소요: 약 4시간 diff --git a/docs/plan/project-plan.md b/docs/plan/project-plan.md index 94bfda1..1931a5b 100644 --- a/docs/plan/project-plan.md +++ b/docs/plan/project-plan.md @@ -289,12 +289,12 @@ choco-admin/ > 기존 서비스 비즈니스 규칙을 파악해 재현 실수를 방지한다. -- [ ] `mouse-typing` 관리자 라우트와 처리 로직 분석 (`src/web/admin/`, `src/web/server/admin/`) -- [ ] 연장 승인 시 `AvailableActivateDateTime` 계산 방식 확인 (몇 개월/년 연장인지) -- [ ] 업그레이드 승인 시 `PlayerCount` 갱신 여부 확인 -- [ ] `admin.Password` 검증 방식 확인 (평문 / MD5 / bcrypt 등) -- [ ] `maestro_log` 기록 형식(`Type`, `Remark`) 확인 -- [ ] 조사 결과를 `docs/business-rules.md`에 문서화 +- [x] `mouse-typing` 관리자 라우트와 처리 로직 분석 (`src/web/admin/`, `src/web/server/admin/`) +- [x] 연장 승인 시 `AvailableActivateDateTime` 계산 방식 확인 (몇 개월/년 연장인지) +- [x] 업그레이드 승인 시 `PlayerCount` 갱신 여부 확인 +- [x] `admin.Password` 검증 방식 확인 (평문 / MD5 / bcrypt 등) +- [x] `maestro_log` 기록 형식(`Type`, `Remark`) 확인 +- [x] 조사 결과를 `docs/business-rules.md`에 문서화 ### Phase 1. 프로젝트 초기화