16 KiB
16 KiB
| phase | agent | agent_version | generated_at | workstream | concerns | concerns_checked | self_verification | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| requirements | requirements-advisor | 1 | 2026-06-23T00:41:35Z | W1-거버넌스/RBAC |
|
true |
|
W1 — 거버넌스 / RBAC 요구사항
원 요청 (로드맵 §W1 인용)
관리자(전체 권한) / 부관리자(허용된 권한만 = 권한부여형) 모델 / 관리자 콘솔 — 부관리자 임명 + 권한 토글 / 권한 체크 인터셉터 / 권한 토글 항목 예시: 게임잼관리, 포스팅작성(=포스터 권한). 의존 없음. 공유자원 users, security/, 세션/인증.
§0. RBAC 권한 생명주기 맵 (end-to-end — 구조적 gap-hunt)
순차 상태 전이가 내포된 개념(부관리자 임명→권한 토글→권한 회수/강등, role 변경→세션 반영)이 있으므로 표면 요구 너머의 단절을 적극 헌트한다. 각 단계에 현재 코드 상태 + 단절 여부를 표기.
| 단계 | 전이 | 현재 코드 상태 | 단절 |
|---|---|---|---|
| L0 | 가입 → USER 부여 | UserController:295 전원 setRole("USER") |
OK |
| L1 | 최초 ADMIN 부트스트랩 | 경로 없음 — signup 전원 USER, 승격 수단 0 | 단절 — 갭 G1 |
| L2 | ADMIN → 부관리자(SUBADMIN) 임명 | 콘솔/임명 API 0 | 단절 — 갭 G2 |
| L3 | 부관리자에게 권한 토글 부여 | 권한 저장 구조 0 (role 단일 String) | 단절 — 갭 G3 |
| L4 | 요청 시 권한 게이트 통과 검사 | Interceptor 0, addInterceptors 0 |
단절 — 갭 G4 (QG-1 핵심) |
| L5 | 권한 토글 회수(역방향) | 회수 API·세션 무효화 0 | 단절 — 갭 G5 (역방향 전이) |
| L6 | 부관리자 → USER 강등/해임(종료) | 강등 경로 0 | 단절 — 갭 G6 (종료 전이) |
| L7 | role/권한 변경 후 세션 반영 | 세션에 role attr 박제(:508), 변경 전파 0 → stale 권한 |
단절 — 갭 G7 (2차 단절·보안) |
happy-path(L0~L4)만이 아니라 회수/강등/세션 무효화(L5~L7)를 반드시 W1 스코프에 포함한다. 권한을 줄 수만 있고 회수·전파가 없으면 거버넌스로서 미완이며 보안 결함(권한 회수 후에도 세션 유효)이 된다.
복수 이벤트 조건 대칭 점검 (병렬 분기)
- 권한 부여 시 / 권한 회수 시 세션 반영이 대칭이어야 한다. 부여만 즉시 반영하고 회수는 다음 로그인까지 지연되면 보안 비대칭(회수 우회). → 결정축에 반영(아래 결정7).
- 임명(승격) 시 / 해임(강등) 시 감사 로그 기록이 대칭이어야 한다. → NFR-보안 감사로그.
기능 요구 (FR)
권한 모델·저장
- FR-1: 사용자는 ADMIN / SUBADMIN / USER 중 하나의 기본 role을 가진다. (
users.role재사용, 값 집합 확장) - FR-2: SUBADMIN(부관리자)은 0개 이상의 개별 권한(permission)을 부여받을 수 있다. ADMIN은 전 권한을 암묵적으로 보유한다(권한 토글 무관). USER는 권한 0.
- FR-3: 권한 카탈로그는 최소
GAME_JAM_MANAGE(게임잼관리),POST_WRITE(포스팅작성/포스터)를 포함한다. 모더레이션 권한(CONTENT_MODERATE)을 추가 후보로 둔다(결정4 연계).
관리자 콘솔 (L1~L6)
- FR-4: ADMIN은 콘솔에서 사용자를 SUBADMIN으로 임명(승격)할 수 있다. (G2)
- FR-5: ADMIN은 콘솔에서 SUBADMIN의 각 권한을 **토글(부여/회수)**할 수 있다. (G3, G5 — 부여·회수 대칭)
- FR-6: ADMIN은 SUBADMIN을 USER로 강등/해임할 수 있고, 강등 시 부여 권한은 전부 회수된다. (G6)
- FR-7: 콘솔은 현재 운영진(ADMIN/SUBADMIN) 목록과 각자의 권한 상태를 조회한다.
- FR-8: ADMIN 권한 자체는 콘솔에서 부여하지 않는다(최초 ADMIN은 부트스트랩 전용 — 결정3). 콘솔에서 다루는 임명 대상은 SUBADMIN과 그 권한에 한정한다.
권한 체크 인터셉터 (L4 — QG-1 선행)
- FR-9:
HandlerInterceptor구현 +addInterceptors등록으로 보호 경로 진입 시 권한을 검사한다. - FR-10: 보호 대상 — (a) 관리자 콘솔 경로 전체(ADMIN only), (b) 게임잼관리 액션(
GAME_JAM_MANAGE보유자 — W2 소비), (c) 포스팅 작성 액션(POST_WRITE보유자 — W3-3 소비). 미보유 시 거부(미인증=401/로그인 리다이렉트, 인증·미인가=403). - FR-11: 인터셉터는 세션 식별값(
userId)을 기준으로 권한을 판정한다. 세션 role attr 단독 신뢰 여부는 결정7(세션 stale)에 종속.
부트스트랩 (L1)
- FR-12: 최초 ADMIN은 운영 DB seed/수동 승격으로 지정한다(결정3 권장안). 코드 자동 승격 경로는 두지 않는다.
기존 임시 ADMIN 흡수 (결정4)
- FR-13: comment/review 모더레이션 체크(
GameCommentController:201,GameReviewController:419의ROLE_ADMIN.equals(role))를 W1 권한 게이트(운영자 판정)로 대체한다. ADMIN +CONTENT_MODERATE보유 SUBADMIN이 통과하도록 재정의한다. (권장안 — 사용자 확정 시)
세션·권한 전파 (L7 — 2차 단절)
- FR-14: role/권한 변경(임명·토글·회수·강등) 후, 대상 사용자의 후속 요청에서 새 권한이 반영되어야 한다. (부여·회수 대칭 — 결정7)
비기능 요구 (NFR)
- NFR-보안(CSRF): 콘솔의 모든 상태변경(임명/토글/회수/강등)은
CsrfTokens.isValid검증 적용. (기존 패턴 — comment/review/UserController 일관) - NFR-보안(SQL): 권한 조회·갱신 MyBatis SQL은
#{}바인딩만 사용,${}금지. - NFR-보안(인가 경계): 권한 판정은 서버측 인터셉터/컨트롤러에서 수행. 클라이언트(JSP) 노출은 표시용일 뿐 게이트 아님. 콘솔 진입·임명 API는 ADMIN 이외 도달 시 403.
- NFR-보안(세션 무결성): 권한 변경 시 stale 세션 권한 방지(FR-14). 권한 상승은 즉시, 회수는 즉시 반영을 목표(비대칭 금지). 세션 고정 방어(
changeSessionId— 로그인 시 이미 존재)는 보존. - NFR-보안(감사 로그): 임명/강등/권한 토글은 누가·누구를·언제·무엇을 변경했는지 기록(감사 추적). 임명·해임 대칭 기록.
- NFR-운영(롤백/마이그레이션): 신규 권한 스키마는 schema.sql + 적용 DDL로 제공, 기존 데이터(전원 role='USER')와 호환(추가만, 파괴 없음). 롤아웃 순서: 스키마 적용 → 부트스트랩 ADMIN 지정 → 인터셉터 배포.
- NFR-호환성: 기존
users.role컬럼·세션 role attr·comment/review 동작을 보존하거나 명시적으로 대체(FR-13). USER 기존 사용자에 영향 없음. - NFR-i18n: 콘솔 UI 문자열은 기존 JSP 한국어 직접 출력 패턴 따름(별도 i18n 프레임워크 없음 — 해당 없음 수준).
- NFR-접근성: 콘솔은 관리자 전용 내부 화면 — 표준 폼/키보드 조작 보장 외 특별 요건 없음(해당 최소).
- NFR-성능: 권한 체크는 요청당 1회 발생 — 권한 조회 캐시/세션 캐싱 여부는 design 결정(stale 트레이드오프와 결합, 결정7). 상한 요구 없음.
6개 핵심 결정의 확정값 (권장안 + 트레이드오프)
AskUserQuestion이 서브에이전트에서 불가하여, 각 결정에 권장안을 명시하고 사용자 확정이 필요한 항목은 [확정필요]로 표기했다. design 진입 전 orchestrator가 사용자에게 확인.
결정1 — 권한 모델 형태 [확정필요·권장 (a)]
- 권장 (a):
users.role(ADMIN/SUBADMIN/USER) 유지 +user_permissionsjoin 테이블(user_id × permission). 부관리자별 개별 토글을 직접 표현. - 근거: 기존
.equals(role)(comment/review) + 세션 role attr 코드를 호환 보존하면서 부분집합을 추가. 변경 표면 최소. - 트레이드오프: 판정이 role 분기 + permission 조회 2단계. (b)보다 모델이 약간 복잡.
- (b) user↔permission 직접: role 개념 제거 — 기존 ADMIN 체크/세션 전면 교체 비용. 기각.
- (c) role↔permission 매핑: 역할 단위라 "부관리자 개인별 토글" 요구와 불일치. 기각.
결정2 — 초기 permission 카탈로그 [권장 확정: DB 카탈로그 + 2~3권한]
- 권장:
GAME_JAM_MANAGE,POST_WRITE출시 포함 + (결정4 채택 시)CONTENT_MODERATE. 카탈로그를 DB 테이블(permissions)로 관리해 운영자 추가·향후 W2-2(심사위원)/W4(배지)와 분리 흡수 가능. - 트레이드오프: DB 카탈로그는 코드 enum 대비 타입 안전성↓, 권한 키 오타 가능 → permission 키는 코드 상수와 DB 시드를 동기화하는 계약 필요(design).
- 대안: 코드 enum(단순·타입안전, 추가 시 배포). W1 권한이 2~3개로 적어 enum도 무리 없음 — [확정필요] 여지.
결정3 — 관리자 부트스트랩 [확정필요·권장: DB seed/수동 승격]
- 권장: 운영 DB에서 특정 user.role을 ADMIN으로 직접 UPDATE(seed 스크립트 또는 1회 수동 maintenance). 코드 변경·설정 노출 없음.
- 근거: 가장 안전(공격면 0), 순환문제(콘솔 임명은 ADMIN 선존 필요) 회피.
- 트레이드오프: 운영 수동 절차 1회 필요 → maintenance 문서화 동반.
- 대안: 설정 기반 자동 승격(이메일 목록) — 설정 노출·관리 부담으로 비권장.
결정4 — 기존 임시 ROLE_ADMIN 흡수 [확정필요·권장: 권한 게이트로 통일]
- 권장: comment/review 모더레이션을 ADMIN +
CONTENT_MODERATE보유자 통과로 재정의(FR-13). 부관리자도 모더레이션 권한 토글 가능. - 근거: 임시 산물(W3-2)을 W1 체계로 흡수해 권한 일원화. 미루면 ADMIN 하드코딩 분산 유지.
- 2차 단절 점검: 변경 시 기존 ADMIN 통과 동작이 끊기면 안 됨 → ADMIN은 모든 권한 암묵 보유(FR-2)로 회귀 방지. W3-2 모더레이션 테스트 회귀 확인 필요(concern).
- 대안: 현행
.equals("ADMIN")호환만 유지(부관리자 모더레이션 불가, 최소 변경) — W1 일원화 목적엔 미달.
결정5 — 인터셉터 보호 범위 (QG-1) [확정필요·권장 범위 확정]
- 권장: W1 출시에 인터셉터 포함 확정(W3-3가 이를 선행 의존 — QG-1). 보호 대상:
- 관리자 콘솔 경로 전체 → ADMIN only.
- 게임잼관리 액션 →
GAME_JAM_MANAGE(W2가 경로 확정 시 등록, W1은 게이트 인프라 제공). - 포스팅 작성 액션 →
POST_WRITE(W3-3 소비).
- 근거: QG-1에서 "W3-3은 W1 완료 후 착수(임시 체크 안 함)" 이미 확정 → 인터셉터가 W1 산출에 반드시 포함.
- 트레이드오프: 보호 경로 매핑 방식(URL 패턴 vs 어노테이션 vs 핸들러 메타) = design 결정. 미인증(401/리다이렉트) vs 미인가(403) 응답 정책 = design 확정.
결정6 — 관리자 콘솔 범위 [권장 최소 범위]
- 권장 최소: (1) 운영진 목록 조회(FR-7), (2) 부관리자 임명(FR-4), (3) 권한 토글 부여/회수(FR-5), (4) 강등/해임(FR-6). 4개 액션. 모두 CSRF 보호.
- 제외(후속): 권한 변경 이력 열람 UI, 일괄 작업, 사용자 검색 고도화.
결정7 (신규 — gap-hunt 산물) — 세션 권한 전파(stale) [확정필요·권장: 즉시 반영, 부여·회수 대칭]
- 배경: 세션에
roleattr 박제(UserController:508). 인터셉터가 세션 role만 신뢰하면 권한 변경이 다음 로그인까지 미반영 → 회수 우회 보안 결함(L7/G7). - 권장: 인터셉터는 권한 판정 시 권위 소스(DB user_permissions 또는 세션과 동기화된 캐시)를 신뢰. 변경 시 부여·회수 대칭 즉시 반영.
- 트레이드오프: 매 요청 DB 조회(성능) vs 세션 캐시(stale 위험). design에서 캐시 TTL/무효화 전략 결정. 단 회수의 즉시성은 비기능 보안 요구로 양보 불가.
스코프
- 포함: ADMIN/SUBADMIN/USER role 확장, user_permissions 저장, 권한 카탈로그(2~3개), 관리자 콘솔 4액션(임명·토글·회수·강등 — 부여/회수 대칭), 권한 체크 인터셉터(QG-1), 부트스트랩 절차, 기존 ADMIN 흡수(결정4 채택 시), 세션 권한 전파(결정7).
- 제외: 심사위원 역할(W2-2), 리뷰어/기술자 배지(W4), 게임잼관리 액션의 실제 비즈니스(W2 — W1은 게이트만 제공), 포스팅 작성 기능 본체(W3-3 — W1은 권한만 제공), 권한 변경 이력 UI·일괄작업(후속).
가정 / 추측
- (가정)
users.role컬럼(varchar(30), DEFAULT 'USER')을 그대로 재사용해 값 집합만 확장 — schema.sql:35 근거. role 컬럼 자체 신규 추가 아님. - (가정) 세션 고정 방어(
changeSessionId)는 로그인에 이미 존재(UserController:160)하므로 W1은 보존만, 재구현 불필요. - (가정) comment/review의 CSRF·canModify 패턴이 W1 콘솔의 참조 표준(동일
CsrfTokens.isValid). - (추측→concern) RBAC 도입은 신규 DB 스키마를 강제함 → schema.sql + DDL 적용 + maintenance 문서 동반 변경. concerns에 이관.
확정 필요 (오픈 질문 — orchestrator 경유 사용자 확인)
서브에이전트 AskUserQuestion 불가로 권장안 채택을 전제하되, 아래는 사용자 명시 확정이 바람직한 항목. 미응답 시 권장안을 design 가정으로 진행 가능(파괴적 결정 아님).
- Q1 (결정1): 권한 모델 = role + user_permissions join (권장 a) 채택 확인.
- Q2 (결정3): 부트스트랩 = DB seed/수동 승격 (권장) 채택 확인.
- Q3 (결정4): 기존 ADMIN 흡수 = 권한 게이트로 통일(
CONTENT_MODERATE) 채택 확인. 미채택 시 comment/review 현행 유지. - Q4 (결정5): 인터셉터 W1 포함 + 보호범위(콘솔 ADMIN / 잼관리 / 포스팅) 확인. (QG-1상 사실상 포함 확정이나 범위 동의 필요)
- Q5 (결정2): 권한 카탈로그 저장 = DB vs 코드 enum 택1.
- Q6 (결정7): 권한 회수 즉시 반영(부여/회수 대칭) 요구 동의 — 보안상 강한 권고.
Acceptance Criteria 후보 (design이 만족시킬 목표)
- AC-1: ADMIN이 임명한 SUBADMIN에게
POST_WRITE를 토글하면, 해당 사용자가 포스팅 작성 액션에 통과한다. - AC-2: 위 권한을 회수하면, 다음 요청부터 동일 액션이 403으로 거부된다(즉시·세션 잔류 없음 — 결정7).
- AC-3: SUBADMIN을 강등하면 모든 권한이 회수되고 콘솔 운영진 목록에서 SUBADMIN으로 표시되지 않는다.
- AC-4: 비-ADMIN이 관리자 콘솔 경로에 접근하면 403/리다이렉트로 차단된다(인터셉터 게이트).
- AC-5: 콘솔의 모든 상태변경 요청은 CSRF 토큰 없으면 403.
- AC-6: 부트스트랩 절차로 지정된 최초 ADMIN만 콘솔에 진입 가능(자동 승격 경로 부재).
- AC-7: (결정4 채택 시) comment/review 모더레이션이 ADMIN +
CONTENT_MODERATE보유자에게 통과하고, 기존 ADMIN 통과 동작은 회귀 없이 보존(W3-2 테스트 PASS 유지). - AC-8: 임명/토글/회수/강등이 감사 로그에 대칭 기록된다.
- AC-9: 권한 관련 SQL에
${}동적 치환이 없다.
design-advisor 전달 단절 목록 (명시 인계)
- G1 부트스트랩, G2 임명, G3 권한토글부여, G4 인터셉터(QG-1), G5 권한회수(역방향), G6 강등/해임(종료), G7 세션 권한 전파(2차 단절·보안).
- 병렬 대칭: 권한 부여/회수 세션 반영 대칭, 임명/해임 감사로그 대칭.