--- phase: implementation agent: implementation-advisor agent_version: 1 generated_at: 2026-06-23T00:00:00Z workstream: W1-거버넌스/RBAC concerns: [] concerns_checked: true workers_spawned: 22 planned_workers: 24 actual_workers: 22 self_verification: checklist_passed: true unused_diagnostics: 0 full_test: "BUILD SUCCESS — 65 tests, 0 failures, 0 errors, 0 skipped" --- # W1 구현 로그 — 거버넌스/RBAC ## 구현 순서 (설계 의존 준수) U-SCHEMA → U-DOMAIN → U-GATE(+verifier) → {U-CONSOLE, U-ABSORB, U-SESSION} → 테스트. 의존 있는 파일(PermissionGate 소비 컨트롤러/테스트)은 선행 완료 후 spawn(병렬 충돌 0). ## worker 분할 (1파일 1worker, 소유권 겹침 0) | worker | 파일 | 유형 | 결과 | |---|---|---|---| | w-001 migration-writer | docs/rbac-ddl.sql, db/bootstrap-admin.sql, db/schema.sql | create×2/modify | OK (멱등 DDL, 글롭 분리 검증) | | w-002 | security/PermissionKeys.java | create | OK (3멤버+isValid) | | w-003 | security/Roles.java | create | OK | | w-004 | data/PermissionData.java | create | OK | | w-005 | data/OperatorView.java | create | OK | | w-006 | mapper/PermissionsMapper.java | create | OK (alias 큰따옴표, ON CONFLICT) | | w-007 | mapper/UserPermissionsMapper.java | create | OK (#{} only) | | w-008 | mapper/RbacAuditMapper.java | create | OK | | w-009 | mapper/UsersMapper.java | modify | OK (epoch/role/listOperators, alias 큰따옴표) | | w-010 | config/PermissionCatalogVerifier.java | create | OK (+advisor null-guard 보강) | | w-011 | security/PermissionGate.java | create | OK (+advisor isAdmin/isAuthenticated 추가) | | w-012 | security/RbacInterceptor.java | create | OK (401/403/redirect 분기) | | w-013 | config/InterceptorConfig.java | create | OK (/admin/**) | | w-014 | controller/AdminConsoleController.java | create | OK (5엔드포인트, CSRF×3, bump×3, audit 4종) | | w-015 | webapp/.../admin-console.jsp | create | OK (scriptlet+HtmlUtils escape, CSRF) | | w-016 | controller/api/GameCommentController.java | modify | OK (흡수, isOperator/ROLE_ADMIN/sessionRole 삭제) | | w-017 | controller/api/GameReviewController.java | modify | OK (흡수, 동일) | | w-018 | controller/api/UserController.java | modify | OK (세션 권한 스냅샷, 생성자 +UserPermissionsMapper) | | w-019 | data/UserData.java | modify | OK (permissionsEpoch) | | w-020 | test/BibimbapApplicationTests.java | modify | OK (@MockBean ×4 추가) | | w-021 | test/AdminConsoleControllerTest.java | create | OK (13 케이스) | | w-022 | test/security/PermissionGateTest.java | create | OK (7 케이스, AC-2 회수) | | w-023 | test/GameCommentControllerTest.java | modify | OK (게이트 mock + SUBADMIN 신규) | | w-024 | test/GameReviewControllerTest.java | modify | OK (동일) | ## advisor 직접 처리 (worker 미spawn — planned 24 vs actual 22) 1. **PermissionGate.isAdmin/isAuthenticated 추가** (w-011 산출 후 advisor Edit): 인터셉터가 ADMIN-only 게이트를 epoch 모델로 단일 소스화하려면 게이트에 메서드가 필요. 단일 파일·소수 라인 편집이라 신규 worker spawn 불필요(계량: 1파일 <20줄). 2. **PermissionCatalogVerifier null-guard** (advisor Edit): mock listActiveKeys() null 반환 시 contextLoads NPE 방지. 1파일 3줄. 3. **UserControllerCsrfTest 생성자 인자 보정** (advisor Edit): 영향 맵 밖 발견 파일(discovered dependency). UserController 생성자 변경(+UserPermissionsMapper)으로 기존 테스트 `new UserController(2-arg)` 컴파일 깨짐 → 3-arg + @Mock 추가. 2파일 위치 <4줄 기계적 수정 → advisor 직접(계량: <500줄, 파일<8). ## Bash 단계 (advisor 직접) - `./mvnw -o compile` (중간 검증, U-DOMAIN+gate 후) → EXIT 0. - `./mvnw -o test` (full) → **BUILD SUCCESS, 65 tests, 0 fail/error/skip**. - PermissionGateTest 7, AdminConsoleControllerTest 13, GameCommentControllerTest 18, GameReviewControllerTest 21, UserControllerCsrfTest 5, BibimbapApplicationTests(contextLoads) 1. - 빌드 경고: `@MockBean` deprecation(Spring Boot 3.4+)만 — 기존 8필드에도 이미 존재하는 프로젝트 관례. unused/dead 경고 0. - 환경: JAVA_HOME=/opt/homebrew/opt/openjdk@21 (셸 PATH 미설정 → export 로 해결). ## 설계 concerns 처리 결과 (구현 점검 항목) 1. **시그니처 inflate(concern 1)**: PermissionGate `has`/`canModerate` 의 `request` 파라미터 **제거 확정**. 게이트는 boolean 만 반환, 거부응답은 호출자(인터셉터/컨트롤러)가 작성. 흡수 호출지점 `permissionGate.canModerate(session)` (request 없음). `HttpServletRequest` import 0 (grep 확인). dead parameter 0. 2. **@MockBean / full-test(concern 2)**: BibimbapApplicationTests 에 PermissionsMapper/UserPermissionsMapper/RbacAuditMapper/PermissionGate @MockBean 4개 등록. full `./mvnw -o test` 실행 — contextLoads NoSuchBeanDefinitionException 없음(verifier null-guard 로 ApplicationRunner NPE 도 방지). 3. **DB-방언 L2(concern 3)**: 신규 매퍼 camelCase alias 전부 큰따옴표(`AS "permissionKey"` 등). `${}` 0건(PermissionsMapper/UserPermissionsMapper/RbacAuditMapper/UsersMapper 신규분 grep). dev DB contract 실행 검증은 verification-advisor + DDL 적용 후 가능(기존 open item). 4. **users 스키마 권위 수준(concern 4)**: DDL 멱등(IF NOT EXISTS / DO $$ guard). docs/rbac-ddl.sql 권위, db/schema.sql 사본 반영. bootstrap seed 는 글롭 밖(db/bootstrap-admin.sql) 수동 전용. ## 정적 AC 게이트 (구현 시점 self-check — 최종 판정은 verification) - AC-T1: PermissionKeys 멤버 3 (grep -c = 3). - AC-T2: AdminConsoleController CsrfTokens.isValid = 3 (appoint/toggle/demote). - AC-T4: bumpPermissionsEpoch = 3 (동일 핸들러). - AC-T3/AC-8: audit action 리터럴 APPOINT/DEMOTE/GRANT/REVOKE 4종 전수. - AC-T5/AC-9: 신규 매퍼 4파일 `${` = 0. ## DDL 적용 대기 (orchestrator 게이트 필요) - `db/apply-local-ddl.sh` **미실행**(금지 준수). docs/rbac-ddl.sql 작성까지만. - orchestrator 가 게이트 후: `db/apply-local-ddl.sh docs/rbac-ddl.sql` (자동 글롭) + 최초 ADMIN 은 `psql -v admin_email=... -f db/bootstrap-admin.sql` 수동. ## 미해결 이슈 없음. 컴파일·full test 통과. DDL 실DB 적용/방언 L2 실행 검증은 orchestrator 게이트 + verification-advisor 영역.