feat(app): GCP OAuth 동의 화면 검증을 위한 랜딩 페이지 및 사이트 인증 추가#783
feat(app): GCP OAuth 동의 화면 검증을 위한 랜딩 페이지 및 사이트 인증 추가#783
Conversation
- / 경로에 공개 랜딩 페이지 추가 (Sign In/Sign Up 버튼, 브랜드명 h1, 개인정보 처리방침 링크) - /about 페이지 h1을 동적 브랜드 이름으로 변경 (usePublicAuthConfig) - Google Site Verification HTML 파일 확인 방식 지원 (BrandingController) - system_settings에 google_site_verification 컬럼 추가 (Flyway) - 시스템 설정 일반 수정 API에 googleSiteVerification 필드 추가 - i18n: 랜딩 페이지 키 추가 (en/ko/ja) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
좋은 방향으로 보입니다. 다만 코드 레벨에서는 몇 가지를 같이 보면 더 좋을 것 같습니다. 큰 흐름 자체는 이해되고, 특히 Google verification file을 public host에서 응답하게 만드는 방향은 타당해 보입니다. 다만 지금 구현은 핵심은 이 정도로 이해했습니다.
예를 들면 저장 위치는 sealed class OAuthProviderConfig {
data class Google(
val websiteVerification: WebsiteVerification? = null,
) : OAuthProviderConfig() {
data class WebsiteVerification(
val metaVerificationToken: String? = null,
val htmlVerificationFileName: String? = null,
)
}
}이렇게 두면:
HTML file verification 응답도 현재처럼 root path 공개 응답이 필요한 점은 맞고, 다만 @RestController
@PreAuthorize("permitAll()")
class GoogleSiteVerificationController(
private val oauthProviderQuery: OAuthProviderQuery,
) {
@GetMapping("/{filename:google[a-z0-9]+\\.html}")
fun verify(
@PathVariable filename: String,
): ResponseEntity<String> {
val snapshot = oauthProviderQuery.getGoogleSiteVerification()
?: return ResponseEntity.notFound().build()
val expected = snapshot.htmlVerificationFileName
?: return ResponseEntity.notFound().build()
if (filename != expected) {
return ResponseEntity.notFound().build()
}
return ResponseEntity
.ok()
.contentType(MediaType.TEXT_PLAIN)
.body("google-site-verification: $expected")
}
}이 예시에서 특히 좋다고 느낀 부분은:
또
즉, 이번 PR에서는 현재 구조로 가더라도 괜찮아 보이지만,
|
- isu_001 (backend/iam/src/main/kotlin/io/deck/iam/controller/BrandingController.kt:45): Google 파일 검증은 반환된 토큰 문자열 전체를 파일명으로 그대로 써야 하는데, 여기서는 저장값 앞뒤에 google 과 .html 을 다시 붙여 기대 파일명을 만듭니다. 그래서 운영자가 Google이 준 값(google12cfc68677988bb4.html 형태)을 그대로 저장하면 실제 요청 URL은 항상 404가 나고 사이트 검증이 실패합니다. - isu_002 (frontend/app/src/pages/landing/landing.page.tsx:55): 랜딩의 회원가입 버튼이 /invite 로 연결되는데, 이 페이지는 token 쿼리가 없으면 즉시 Invalid invitation link. 오류 화면으로 떨어집니다. 신규 사용자를 위한 CTA가 실제 가입 흐름이 아니라 깨진 초대 수락 페이지로 연결되어 첫 진입 경험이 막힙니다. - isu_003 (backend/iam/src/main/kotlin/io/deck/iam/domain/SystemSettingEntity.kt:118): update() 메서드에서 googleSiteVerification 파라미터의 기본값이 null이고, null이 전달되면 기존 값을 무조건 덮어씁니다. 현재 프론트엔드의 일반 설정 수정 폼에는 googleSiteVerification 필드가 없으므로(후속 PR 예정), 관리자가 브랜드명이나 연락처 이메일만 수정해도 요청 본문에 googleSiteVerification이 포함되지 않아 Jackson이 null로 역직렬화하고, 저장된 Google Site Verification 토큰이 삭제됩니다.
- SystemSettingEntity에서 googleSiteVerification 필드를 제거합니다 - OAuthProviderConfig.Google에 WebsiteVerification 데이터 클래스를 추가합니다 - BrandingController에서 분리하여 GoogleSiteVerificationController를 생성합니다 - OAuthProviderQuery에 getGoogleSiteVerification() 메서드를 추가합니다 - system_settings 테이블의 컬럼 migration을 삭제합니다 (oauth_providers.config JSON 활용) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- isu_005 (backend/iam/src/main/kotlin/io/deck/iam/controller/OAuthProviderDtos.kt:61): Google 업데이트 요청을 항상 OAuthProviderConfig.Google()로 변환하면, 인증 설정 저장 시 기존 websiteVerification 값이 매번 빈 객체로 덮어써집니다. 프론트의 설정 화면은 enabled/clientId/clientSecret/domain만 PUT하므로 auth 설정을 한 번만 저장해도 저장돼 있던 htmlVerificationFileName이 삭제되고, /google*.html 검증 엔드포인트가 404로 바뀝니다.
|
[debate-review][sha:ee990de93c82697ebf4669b835ee0fa0b58c5f6a] Consensus reached after 7 rounds. Debate Summary
Applied Fixes
Withdrawn Findings
|
Description
/경로에 공개 랜딩 페이지 추가 (기존/login리다이렉트 → 랜딩 페이지)프론트엔드
LandingPage컴포넌트: SaaS 스타일 랜딩 (Sign In/Sign Up 버튼, 브랜드명 h1, 서비스 소개, 법적 링크)/dashboard자동 리다이렉트AboutPageh1: 하드코딩 i18n →usePublicAuthConfig().brandName(동적)백엔드
OAuthProviderConfig.Google에WebsiteVerification데이터 클래스 추가 (meta/HTML 검증 토큰)GoogleSiteVerificationController:GET /{filename:google[a-z0-9]+\.html}공개 엔드포인트 (BrandingController에서 분리)OAuthProviderQuery에getGoogleSiteVerification()메서드 추가oauth_providers.configJSON에 저장 (별도 컬럼/migration 없음)참고
/google*.html패턴만 백엔드로 프록시하도록 nginx 설정 필요Added/updated tests?
app.test.tsx업데이트 (AppShell 테스트 경로를/dashboard로 변경)GoogleSiteVerificationControllerTest신규 추가Additional notes
metaVerificationToken필드도 구조에 포함하여 후속 meta tag verification 지원 가능