회원 관리(admin) 화면을 백엔드부터 프론트까지 구현했다. user 테이블에 role/is_admin 컬럼이 없어, 마이그레이션 없이 ADMIN_EMAILS 환경변수 화이트리스트로 관리자를 가르는 쪽을 골랐다 — 관리자가 늘어나 화이트리스트가 아까워지는 시점이 오면 is_admin 컬럼으로 옮긴다.
만든 것
fastapi:GET /api/v1/admin/users(목록·검색·페이지네이션) ·GET /admin/users/{id}(상세 — 나간 팀 포함 소속 이력 + 카드 등록 여부) ·DELETE /admin/users/{id}(비밀번호 확인 없는 강제 탈퇴).user컨텍스트 안에 두되,card컨텍스트의player_card테이블을 확인하는has_card는 ORM을 임포트하지 않고table()/column()원시 쿼리로 읽었다 —app/core/deps.py가 토큰 버전을 읽는 것과 같은 방식으로, 컨텍스트 경계 (tests/test_architecture.py)를 지켰다. 계약은docs/api-contract.md3-2절.www:/admin/users·/admin/users/[id]화면. 로그인 게이트는 기존proxy.ts가 이미 맡고, 관리자 게이트는 백엔드가 403을 주면 화면에서/로 돌려보내는 식으로 얹었다.
확인하며 알게 된 것
www의 getBackend()는 아직 전부 mock이다(fastapiBackend 연결은 별도 작업으로 남아 있음 — src/server/backend/index.ts 주석 참고). 브라우저로 직접 눌러보다가, mock의 users Map이 Route Handler(route.ts)와 Server Component(page.tsx)에서 서로 다른 모듈 인스턴스로 로드돼 있어서, 회원가입 직후 만든 계정이 API 라우트(curl)에는 보여도 관리자 화면(페이지 컴포넌트)에는 안 보이는 현상을 봤다. 데모 계정(정적 시드 데이터)으로는 재현되지 않아 기존 화면들에서는 안 드러났던 것으로 보인다. mock 아키텍처의 기존 한계라 이번 범위에서 고치지 않았고, 실제 FastAPI+PostgreSQL로는 재현되지 않는다 — fastapiBackend 연결 작업에서 참고할 사항으로 남겨 둔다.
확인
cd fastapi && .venv/bin/python -m pytest -q→126 passed, 47 skippedcd www && npx vitest run→119 passed,npm run build성공www프로덕션 빌드를 띄워 브라우저(Playwright)로 목록 조회·검색·상세·강제 탈퇴까지 직접 눌러 확인 — 콘솔 에러 없음