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

7.5 KiB
Raw Blame History

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에 추가)

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