diff --git a/README.md b/README.md index fd99dc1..857ff9a 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ cd deploy && docker compose up -d --build 자세한 절차는 [docs/11-deployment-ops.md](docs/11-deployment-ops.md). ## 관리자 -`/admin`. 슈퍼어드민은 디스코드 ID `293719842274541579`, `1352267557213573160`(환경 변수 `SUPERADMIN_DISCORD_IDS`), 어드민은 관리자 화면에서 디스코드 ID로 추가한다. 자세한 내용은 [docs/14-admin.md](docs/14-admin.md). +`/admin`. 슈퍼어드민은 서버의 `deploy/.env`에 있는 환경 변수 `SUPERADMIN_DISCORD_IDS`의 디스코드 ID(저장소에는 넣지 않음), 어드민은 관리자 화면에서 디스코드 ID로 추가한다. 자세한 내용은 [docs/14-admin.md](docs/14-admin.md). ## 구조 - `packages/engine` — 게임 공통 타입, 시드 난수, 테스트 도구 diff --git a/apps/server/src/admin.test.ts b/apps/server/src/admin.test.ts index d13d73c..939bbba 100644 --- a/apps/server/src/admin.test.ts +++ b/apps/server/src/admin.test.ts @@ -1,8 +1,8 @@ /** Admin site tests (docs/14-admin.md §9). */ import { afterEach, describe, expect, test } from 'bun:test'; -import { Client, api, boot, guest, sleep } from './test-utils'; +import { Client, TEST_SUPERADMINS, api, boot, guest, sleep } from './test-utils'; -const SUPER = '293719842274541579'; +const [SUPER, SUPER2] = TEST_SUPERADMINS; type Booted = ReturnType; const running: Booted[] = []; const clients: Client[] = []; @@ -47,7 +47,7 @@ describe('roles', () => { const me = await api(s.base, '/api/admin/me', { cookie: sup.cookie }); expect(me.body.role).toBe('superadmin'); expect((await api(s.base, '/api/me', { cookie: sup.cookie })).body.role).toBe('superadmin'); - const sup2 = await discordLogin(s, '1352267557213573160'); + const sup2 = await discordLogin(s, SUPER2); expect((await api(s.base, '/api/admin/me', { cookie: sup2.cookie })).body.role).toBe('superadmin'); }); @@ -60,7 +60,7 @@ describe('roles', () => { // Pre-register before the person ever logged in. const add = await api(s.base, '/api/admin/admins', { method: 'POST', cookie: sup.cookie, body: JSON.stringify({ discordId: adminDiscord, note: '친구1' }) }); expect(add.res.status).toBe(200); - expect(add.body.admins.map((a: any) => a.discordId)).toEqual([SUPER, '1352267557213573160', adminDiscord]); + expect(add.body.admins.map((a: any) => a.discordId)).toEqual([SUPER, SUPER2, adminDiscord]); const adm = await discordLogin(s, adminDiscord); expect((await api(s.base, '/api/admin/me', { cookie: adm.cookie })).body.role).toBe('admin'); expect((await api(s.base, '/api/admin/users', { cookie: adm.cookie })).res.status).toBe(403); diff --git a/apps/server/src/config.ts b/apps/server/src/config.ts index 3afacb9..438706f 100644 --- a/apps/server/src/config.ts +++ b/apps/server/src/config.ts @@ -14,9 +14,6 @@ export interface Config { loadTestNoHttpLimits: boolean; } -/** Superadmin Discord IDs, comma-separated (docs/14-admin.md §2). */ -export const DEFAULT_SUPERADMIN = '293719842274541579,1352267557213573160'; - export function loadConfig(env: Record = process.env): Config { const publicOrigin = (env.PUBLIC_ORIGIN ?? 'http://localhost:5173').replace(/\/$/, ''); const extra = (env.ALLOWED_ORIGINS ?? '').split(',').map((s) => s.trim()).filter(Boolean); @@ -36,6 +33,7 @@ export function loadConfig(env: Record = process.env secureCookies: publicOrigin.startsWith('https://'), trustProxy: env.TRUST_PROXY === '1', loadTestNoHttpLimits: env.LOADTEST_NO_HTTP_LIMITS === '1' && !publicOrigin.startsWith('https://'), - superadminDiscordIds: (env.SUPERADMIN_DISCORD_IDS ?? DEFAULT_SUPERADMIN).split(',').map((s) => s.trim()).filter(Boolean), + /** Superadmin Discord IDs, comma-separated (docs/14-admin.md §2). Only in deploy/.env, never in the repo. */ + superadminDiscordIds: (env.SUPERADMIN_DISCORD_IDS ?? '').split(',').map((s) => s.trim()).filter(Boolean), }; } diff --git a/apps/server/src/test-utils.ts b/apps/server/src/test-utils.ts index 601a72d..503ce13 100644 --- a/apps/server/src/test-utils.ts +++ b/apps/server/src/test-utils.ts @@ -7,6 +7,8 @@ import { loadConfig } from './config'; import { startServer, type StartOptions } from './server'; export const ORIGIN = 'http://localhost:5173'; +/** Made-up superadmin Discord IDs for tests (the real ones live only in deploy/.env). */ +export const TEST_SUPERADMINS = ['900000000000000001', '900000000000000002'] as const; export function tempDbPath(): string { const dir = mkdtempSync(join(process.env.TMPDIR ?? tmpdir(), 'bg-test-')); @@ -14,7 +16,7 @@ export function tempDbPath(): string { } export function boot(dbPath = tempDbPath(), extra: Partial = {}) { - const config = loadConfig({ PORT: '0', DB_PATH: dbPath, PUBLIC_ORIGIN: ORIGIN }); + const config = loadConfig({ PORT: '0', DB_PATH: dbPath, PUBLIC_ORIGIN: ORIGIN, SUPERADMIN_DISCORD_IDS: TEST_SUPERADMINS.join(',') }); const app = startServer({ config, log: () => {}, staticDir: null, stopWaitMs: 50, ...extra }); const base = `http://localhost:${app.server.port}`; return { ...app, base, dbPath, config }; diff --git a/apps/web/src/pages/admin/AdminApp.tsx b/apps/web/src/pages/admin/AdminApp.tsx index 3edfd37..97c4488 100644 --- a/apps/web/src/pages/admin/AdminApp.tsx +++ b/apps/web/src/pages/admin/AdminApp.tsx @@ -577,7 +577,7 @@ function Admins() {

어드민 추가