106 lines
7.5 KiB
Markdown
106 lines
7.5 KiB
Markdown
# 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: 게임 설정 저장 → 새 방 대기실 요약에 반영.
|