feat: 약관 동의 관리 추가#135
Conversation
|
Warning Review limit reached
More reviews will be available in 21 minutes and 32 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthrough백엔드에서 약관 원문과 버전을 관리하고, 클라이언트는 동의 여부만 전송하는 약관 동의 시스템을 구현한다. 설정 기반 리소스 로딩, 공개 API, 로그인 시 검증, 인증 재동의 엔드포인트, 그리고 관련 정책 문서를 포함하는 완전한 스택. Changes백엔드 약관 동의 시스템
Sequence DiagramssequenceDiagram
participant Client
participant Backend
participant AgreementService
participant UserService
Note over Client,Backend: 신규 사용자 로그인
Client->>Backend: POST /auth/google/login (code, agreementsAccepted=true)
Backend->>UserService: findGoogleUser(providerId)
UserService-->>Backend: Optional.empty (신규 사용자)
Backend->>AgreementService: validateAccepted(true)
AgreementService-->>Backend: OK
Backend->>AgreementService: currentVersions()
AgreementService-->>Backend: AgreementVersions(v1.0, v1.0)
Backend->>UserService: getOrCreateGoogleUser(..., versions, now)
UserService-->>Backend: User created with agreement fields
Backend-->>Client: AccessToken + RefreshToken
Note over Client,Backend: 기존 사용자 재동의 필요
Client->>Backend: POST /auth/google/login (code, agreementsAccepted=true)
Backend->>UserService: findGoogleUser(providerId)
UserService-->>Backend: User found (v1.0 → v2.0)
Backend->>AgreementService: needsReacceptance(user)
AgreementService-->>Backend: true
Backend->>AgreementService: currentVersions()
AgreementService-->>Backend: AgreementVersions(v2.0, v2.0)
Backend->>UserService: acceptCurrentAgreements(userId, versions, now)
UserService-->>Backend: Updated
Backend-->>Client: AccessToken + RefreshToken
sequenceDiagram
participant Client
participant Backend
Note over Client,Backend: 공개 약관 조회
Client->>Backend: GET /api/agreements/current (인증 없음)
Backend-->>Client: 200 OK { items: [TOS, PrivacyPolicy] }
Note over Client,Backend: 인증 사용자 재동의
Client->>Backend: POST /api/users/me/agreements (Authorization, agreementsAccepted=true)
Backend-->>Client: 204 No Content
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/main/java/com/howaboutus/backend/common/config/SecurityConfig.java (1)
46-59: ⚡ Quick winWebSocket 허용 규칙을 일반 공개 엔드포인트와 분리해 명시해 주세요.
/ws/**가 현재 일반permitAll목록에 함께 들어가 있어 보안 정책 가시성이 떨어집니다. WebSocket 매처를 분리한 별도 블록(또는 별도requestMatchers호출)로 명확히 분리하는 편이 좋습니다.제안 수정안
.authorizeHttpRequests(authorize -> authorize .requestMatchers( "/v3/api-docs/**", "/swagger-ui.html", "/swagger-ui/**", "/springwolf/**", "/actuator/health", "/actuator/prometheus", "/actuator/caches", "/api/agreements/current", "/auth/google/login", "/auth/refresh", - "/auth/logout", - "/ws/**") + "/auth/logout") .permitAll() + .requestMatchers("/ws/**").permitAll() // WebSocket endpoint는 분리 명시 .anyRequest().authenticated())As per coding guidelines, "Explicitly allow WebSocket endpoints in Spring Security configuration separate from other endpoint permissions".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/howaboutus/backend/common/config/SecurityConfig.java` around lines 46 - 59, In SecurityConfig, separate the WebSocket allowance from the general permitAll list: remove "/ws/**" from the existing requestMatchers(...).permitAll() block and add a dedicated requestMatchers("/ws/**").permitAll() (or a distinct authorizeHttpRequests call) so the WebSocket rule is explicit and isolated; update the SecurityConfig class and the requestMatchers/permitAll chain references accordingly to keep other endpoints unchanged.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/java/com/howaboutus/backend/user/entity/User.java`:
- Around line 73-81: The convenience overload User.ofGoogle(String providerId,
String email, String nickname, String profileImageUrl) improperly injects
AgreementVersions("1.0","1.0") and Instant.EPOCH which can falsify consent
history; remove this 4-arg overload (or mark it test-only) and force callers to
use the full factory signature that accepts AgreementVersions and acceptedAt,
i.e., update/remove the ofGoogle(...) overload and ensure all call sites use the
ofGoogle(...) variant that takes agreementVersions and acceptedAt (references:
User.ofGoogle, AgreementVersions, Instant.EPOCH).
In `@src/main/resources/db/migration/V1__init.sql`:
- Around line 14-17: Revert the column additions from V1__init.sql back to the
original state and instead create a new migration file (e.g.,
V2__add_user_agreement_columns.sql) that runs ALTER TABLE users ADD COLUMN for
tos_version, tos_accepted_at, privacy_version, and privacy_accepted_at; include
comments/instructions in the new migration to perform any necessary backfill and
then apply ALTER TABLE ... SET NOT NULL if you need to enforce non-null
constraints later to avoid Flyway checksum mismatches and runtime breaks.
---
Nitpick comments:
In `@src/main/java/com/howaboutus/backend/common/config/SecurityConfig.java`:
- Around line 46-59: In SecurityConfig, separate the WebSocket allowance from
the general permitAll list: remove "/ws/**" from the existing
requestMatchers(...).permitAll() block and add a dedicated
requestMatchers("/ws/**").permitAll() (or a distinct authorizeHttpRequests call)
so the WebSocket rule is explicit and isolated; update the SecurityConfig class
and the requestMatchers/permitAll chain references accordingly to keep other
endpoints unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: eb252bb8-8ced-42cd-a777-ab8655146325
📒 Files selected for processing (38)
docs/ai/README.mddocs/ai/erd.mddocs/ai/features.mddocs/legal/policy-preparation.mddocs/policy/copyright-policy.mddocs/policy/operation-policy.mddocs/policy/operator-info.mddocs/policy/privacy-policy.mddocs/policy/terms-of-service.mddocs/superpowers/plans/2026-06-08-backend-agreements.mddocs/superpowers/specs/2026-06-08-backend-agreements-design.mdsrc/main/java/com/howaboutus/backend/agreements/config/AgreementProperties.javasrc/main/java/com/howaboutus/backend/agreements/controller/AgreementController.javasrc/main/java/com/howaboutus/backend/agreements/controller/dto/AgreementCurrentResponse.javasrc/main/java/com/howaboutus/backend/agreements/controller/dto/AgreementDocumentResponse.javasrc/main/java/com/howaboutus/backend/agreements/service/AgreementService.javasrc/main/java/com/howaboutus/backend/agreements/service/dto/AgreementDocumentResult.javasrc/main/java/com/howaboutus/backend/agreements/service/dto/AgreementVersions.javasrc/main/java/com/howaboutus/backend/auth/controller/AuthController.javasrc/main/java/com/howaboutus/backend/auth/controller/dto/GoogleLoginRequest.javasrc/main/java/com/howaboutus/backend/auth/service/AuthService.javasrc/main/java/com/howaboutus/backend/common/config/SecurityConfig.javasrc/main/java/com/howaboutus/backend/common/error/ErrorCode.javasrc/main/java/com/howaboutus/backend/user/controller/UserAgreementController.javasrc/main/java/com/howaboutus/backend/user/controller/dto/AcceptAgreementsRequest.javasrc/main/java/com/howaboutus/backend/user/entity/User.javasrc/main/java/com/howaboutus/backend/user/service/UserService.javasrc/main/resources/agreements/privacy-policy.mdsrc/main/resources/agreements/terms-of-service.mdsrc/main/resources/application.yamlsrc/main/resources/db/migration/V1__init.sqlsrc/test/java/com/howaboutus/backend/agreements/controller/AgreementControllerTest.javasrc/test/java/com/howaboutus/backend/agreements/service/AgreementServiceTest.javasrc/test/java/com/howaboutus/backend/auth/AuthIntegrationTest.javasrc/test/java/com/howaboutus/backend/auth/controller/AuthControllerTest.javasrc/test/java/com/howaboutus/backend/auth/service/AuthServiceTest.javasrc/test/java/com/howaboutus/backend/user/controller/UserAgreementControllerTest.javasrc/test/java/com/howaboutus/backend/user/service/UserServiceTest.java
| public static User ofGoogle(String providerId, String email, String nickname, String profileImageUrl) { | ||
| return new User(providerId, email, nickname, profileImageUrl, "GOOGLE"); | ||
| return ofGoogle( | ||
| providerId, | ||
| email, | ||
| nickname, | ||
| profileImageUrl, | ||
| new AgreementVersions("1.0", "1.0"), | ||
| Instant.EPOCH | ||
| ); |
There was a problem hiding this comment.
기본 오버로드가 동의 이력을 왜곡할 수 있습니다.
ofGoogle(... 4개 인자)가 AgreementVersions("1.0","1.0")와 Instant.EPOCH를 강제로 넣어 생성하면, 실제 동의 시점/서버 현재 버전과 불일치한 이력이 저장됩니다. 이 오버로드는 제거하거나 테스트 전용으로 제한하고, 프로덕션 경로에서는 agreementVersions와 acceptedAt를 반드시 명시적으로 받도록 강제하는 편이 안전합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/com/howaboutus/backend/user/entity/User.java` around lines 73 -
81, The convenience overload User.ofGoogle(String providerId, String email,
String nickname, String profileImageUrl) improperly injects
AgreementVersions("1.0","1.0") and Instant.EPOCH which can falsify consent
history; remove this 4-arg overload (or mark it test-only) and force callers to
use the full factory signature that accepts AgreementVersions and acceptedAt,
i.e., update/remove the ofGoogle(...) overload and ensure all call sites use the
ofGoogle(...) variant that takes agreementVersions and acceptedAt (references:
User.ofGoogle, AgreementVersions, Instant.EPOCH).
|



변경 내용
GET /api/agreements/current)와 약관 원문 리소스를 추가했습니다.users에 저장하고 재동의 API(POST /api/users/me/agreements)를 추가했습니다.docs/ai/features.md,docs/ai/erd.md를 갱신했습니다.변경 이유
테스트
./gradlew build/review-code-against-docs스킬로 검증/write-api-specs기준으로 REST 어노테이션/DTO 계약 확인,/checking-md-conflicts기준으로 Markdown 참조·중복 규칙 확인체크리스트
하네스 변경 체크리스트
Summary by CodeRabbit
릴리스 노트
새로운 기능
문서