Files
joke-app/docs/14-admin.md

106 lines
7.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 14. 관리자 사이트
## 1. 목표
- 게임 규칙과 사이트 설정을 코드 수정 없이 관리자 화면에서 **하나도 빠짐없이** 바꿀 수 있다.
- 권한은 디스코드 ID로 관리한다. 슈퍼어드민은 고정, 일반 어드민은 슈퍼어드민이 디스코드 ID로 추가한다.
- 관리자가 무엇을 바꿨는지 모두 기록한다.
## 2. 권한
| 등급 | 누가 | 할 수 있는 것 |
|---|---|---|
| 슈퍼어드민 | 디스코드 ID `293719842274541579` (설정 `SUPERADMIN_DISCORD_IDS`, 기본값이 이 ID) | 모든 것: 아래 어드민 권한 + 사용자 관리 + 어드민 추가/삭제 |
| 어드민 | 슈퍼어드민이 디스코드 ID로 등록한 사람 | 관리자 사이트 보기, 게임 설정, 사이트 설정, 방 관리, 기록 보기 |
| 일반 | 그 외(게스트 포함) | 관리자 사이트 접근 불가(관리자 주소로 들어오면 "권한이 없어요") |
- 권한은 **요청마다** 그 사용자에게 연결된 디스코드 ID로 계산한다. 그래서 어드민 등록·해제가 즉시 반영된다.
- 게스트는 디스코드 ID가 없으므로 어드민이 될 수 없다. 관리자는 반드시 디스코드로 로그인해야 한다.
- 아직 사이트에 한 번도 들어온 적 없는 사람도 디스코드 ID로 미리 어드민 등록할 수 있다(처음 로그인하는 순간부터 어드민).
- 설정 파일에 있는 슈퍼어드민은 관리자 화면에서 삭제할 수 없다.
## 3. 화면 구성 (`/admin`, 관리자 화면 코드는 관리자만 내려받는 별도 묶음)
| 탭 | 어드민 | 슈퍼어드민 | 내용 |
|---|---|---|---|
| 대시보드 | ○ | ○ | 접속 수, 진행 중 방, 오늘/전체 판 수, 사용자 수(게스트/디스코드), 서버 가동 시간·메모리 |
| 게임 | ○ | ○ | 게임별 설정(4절) |
| 방 | ○ | ○ | 열린 방 목록(코드, 게임, 상태, 자리, 관전 수, 만든 시각), 방 닫기 |
| 사이트 | ○ | ○ | 사이트 설정(5절) |
| 사용자 | × | ○ | 검색(닉네임/ID/디스코드 ID), 상세(전적·로그인 방식·접속 시각), 닉네임 변경, 이용 제한/해제, 모든 기기 로그아웃, 삭제 |
| 관리자 | × | ○ | 어드민 목록, 디스코드 ID로 추가(메모 포함), 삭제 |
| 기록 | ○ | ○ | 관리자 작업 기록(누가, 언제, 무엇을, 바꾸기 전/후) |
계정 페이지(`/me`)에 관리자에게만 [관리자 페이지] 버튼을 보여 준다.
## 4. 게임 설정 (게임마다)
| 항목 | 설명 |
|---|---|
| 사용 | 끄면 새 방을 만들 수 없고 목록에서 숨김. 진행 중인 방은 그대로 끝까지 |
| 표시 이름 / 한 줄 설명 / 안내문 | 홈·게임 화면에 보이는 글. 안내문은 규칙 화면 위에 표시 |
| 인원 범위 | 원작 최소~최대 안에서만 좁힐 수 있음 |
| 기본 규칙 | 그 게임의 **모든 옵션**(게임 모듈의 `optionsSchema` 전체)을 기본값으로 지정 |
| 방장 변경 금지(잠금) | 옵션마다 잠그면 방장이 대기실에서 바꿀 수 없고 관리자 값으로 고정 |
| 초기화 | 코드 기본값으로 되돌리기 |
- 화면의 입력 칸은 게임 모듈의 옵션 스키마(zod → JSON Schema)에서 **자동으로 만든다**. 새 옵션이 생기면 관리자 화면에 자동으로 나타나므로 빠지는 항목이 없다.
- 그래서 모든 게임 모듈은 옵션마다 한국어 제목과 선택지 이름을 `meta`로 붙인다(`09-game-engine.md` 2절). 게임 규칙 안에 숫자로 박혀 있던 값(예: 오목 자동 착수 허용 횟수, 무승부 재제안 간격)도 옵션으로 꺼내서 관리자가 바꿀 수 있게 한다.
- 저장할 때 스키마로 검사하고, 통과하지 못하면 저장하지 않는다.
- 바꾼 설정은 **새로 만드는 방과 새로 시작하는 판**부터 적용된다. 진행 중인 판의 규칙은 중간에 바뀌지 않는다(공정성).
## 5. 사이트 설정
| 항목 | 기본값 | 효과 |
|---|---|---|
| 사이트 이름 | 같이 놀자 보드게임 | 홈 제목, 브라우저 탭 제목 |
| 공지 | 없음 | 모든 화면 위에 띠로 표시 |
| 점검 모드 | 꺼짐 | 켜면 새 방 만들기·빠른 시작을 막고 공지 표시. 진행 중인 게임은 계속 |
| 금지어 | 없음(내장 목록 외 추가) | 채팅 가림, 닉네임 거부 |
| 사용자당 동시 방 수 | 3 | 방 만들기 제한 |
| 서버 전체 방 수 | 2000 | 방 만들기 제한 |
| 연결 끊김 유예(초) | 60 | 새 방의 기본값 |
| 채팅 기본값 | 켜짐 / 필터 켜짐 | 새 방의 기본값 |
## 6. 사용자 관리 (슈퍼어드민)
- **이용 제한**: 사유와 함께 설정. 즉시 그 사용자의 모든 세션 삭제와 접속 종료. 제한된 디스코드 계정은 다시 로그인할 수 없다("이용이 제한된 계정이에요"). 해제하면 다시 로그인 가능.
- **닉네임 변경**: 관리자가 바꾸면 하루 변경 횟수 제한을 무시.
- **삭제**: `05-accounts-auth.md`의 계정 삭제와 같음(전적 익명화).
- 슈퍼어드민 자신은 제한·삭제할 수 없다.
## 7. 저장 (`08-data-model.md`에 추가)
```sql
CREATE TABLE admins (discord_id TEXT PRIMARY KEY, note TEXT, added_by TEXT, added_at INTEGER NOT NULL);
CREATE TABLE game_settings (game_id TEXT PRIMARY KEY, json TEXT NOT NULL, updated_by TEXT, updated_at INTEGER NOT NULL);
CREATE TABLE site_settings (key TEXT PRIMARY KEY, json TEXT NOT NULL, updated_by TEXT, updated_at INTEGER NOT NULL);
CREATE TABLE admin_audit (id INTEGER PRIMARY KEY AUTOINCREMENT, actor_id TEXT NOT NULL, action TEXT NOT NULL,
target TEXT, before_json TEXT, after_json TEXT, at INTEGER NOT NULL);
ALTER TABLE users ADD COLUMN banned_at INTEGER;
ALTER TABLE users ADD COLUMN banned_reason TEXT;
```
- 설정은 서버 메모리에 캐시하고, 저장할 때 DB와 캐시를 같이 바꾼다.
## 8. API (`/api/admin/*`, 모두 로그인 + 권한 검사, 바꾸는 요청은 Origin 검사 + 기록)
| 메서드 | 경로 | 권한 |
|---|---|---|
| GET | `/api/admin/me` | 어드민+ |
| GET | `/api/admin/overview` | 어드민+ |
| GET | `/api/admin/games` | 어드민+ (게임별 현재 설정 + 옵션 JSON Schema + 코드 기본값) |
| PUT | `/api/admin/games/:id` | 어드민+ |
| POST | `/api/admin/games/:id/reset` | 어드민+ |
| GET / PUT | `/api/admin/site` | 어드민+ |
| GET | `/api/admin/rooms` | 어드민+ |
| POST | `/api/admin/rooms/:code/close` | 어드민+ |
| GET | `/api/admin/audit` | 어드민+ |
| GET | `/api/admin/users?q=&page=` | 슈퍼어드민 |
| GET / PATCH / DELETE | `/api/admin/users/:id` | 슈퍼어드민 |
| POST | `/api/admin/users/:id/logout` | 슈퍼어드민 |
| GET / POST | `/api/admin/admins` | 슈퍼어드민 |
| DELETE | `/api/admin/admins/:discordId` | 슈퍼어드민 |
## 9. 테스트
- 게스트·일반 디스코드 사용자는 모든 관리자 API가 403.
- 슈퍼어드민 디스코드 ID로 로그인하면 슈퍼어드민. 어드민 추가 후 그 디스코드 사용자가 바로 어드민이 되고, 삭제하면 바로 403.
- 어드민은 사용자/관리자 API 403, 게임·사이트 설정은 가능.
- 게임 기본 규칙 저장 → 새 방의 옵션에 반영. 잠근 옵션은 방장이 바꿔도 관리자 값 유지. 잘못된 값은 400.
- 게임 끄기 → 새 방 만들기 거부, 목록에서 숨김.
- 점검 모드 → 방 만들기 거부. 금지어 → 채팅 가림.
- 이용 제한 → 세션 삭제, 접속 종료, 디스코드 재로그인 거부.
- 모든 변경이 기록에 남음.
- 관리자 화면 E2E: 게임 설정 저장 → 새 방 대기실 요약에 반영.