---
title: "작업보고 — 가입 온보딩 동의·동의 이력 + 소셜 OAuth 전용 로그인/회원가입 흐름 + 로그인 브랜딩 복귀 (PR#77·78·79)"
category: "report"
document_type: "작업보고"
source_status: "generated"
knowledge_group: "03_history"
priority: "High"
purpose: "로드맵(plan-97) 「가 — 베타 배포까지 남은 작업 ①CC가 칠 코드」의 '회원가입 첫 진입 동의 + 동의 이력 관리'를 실제 구현한 기록. OAuth 최초 로그인 시 표준 고객동의(이용약관·개인정보 수집이용·개인정보처리방침 확인·건강정보 별도동의 필수4 + 마케팅 선택)를 강제하는 온보딩 게이트, 자체 ID/PW 미구현 원칙에 따른 소셜 전용 회원가입/계정찾기 안내 페이지, Gmail→Google 표기, 로그인 후 리다이렉트 보존, user_consent 동의이력 테이블(oauth_provider 포함). 더불어 데모빌드에서 바뀐 로그인 타이틀·파비콘 복귀와 약관링크 정렬도 함께. 무엇이 어디까지 동작하고 사장님 잔여 액션(마이그레이션 1런·실 OAuth 라이브확인)이 무엇인지의 기준 기록."
read_when: ["온보딩동의","회원가입","계정찾기","소셜OAuth","약관동의","동의이력","user_consent","로그인","파비콘","리다이렉트","RLS","작업보고"]
updated: "2026-06-11"
work_timestamp: "20260610_131500"
context: "달록본레포CC (D:\\dallog\\dallog_git) — 로드맵 plan-97 가-① 실행. 직전 workreport-97(코치 저장/기억) 계승. PR#77(온보딩 동의+브랜딩)·#78(소셜 전용 흐름+동의 강제)·#79(건강 필수 복귀+마케팅 선택) 3건 squash 머지. Codex 협업(사전공유+사후검수 다회 루프). 작업 2026-06-10~06-11."
source_of_truth: "https://dallog-tools.hansbridge.co.kr/knowledge/"
---

# 작업보고 — 가입 온보딩 동의 + 소셜 OAuth 전용 로그인 흐름 + 로그인 브랜딩 복귀

> **상위/계승** — 실행 근거: 로드맵(#/doc/plan-97) 「가-① CC가 칠 코드 = 회원가입 첫 진입 동의 + 동의 이력 (당연히 해야 하는 작업으로 확정)」. 직전 작업보고(#/doc/workreport-97) 「코치 저장/기억 활성화」의 동의·privacy 흐름을 계승·확장.
> **코드** — 달록 본레포 PR#77·#78·#79 (main, 2026-06-10~06-11). 전 PR `npm run build` 통과 · Codex 협업 검수 · MCP 라이브 검증(데스크탑·모바일).

---

## 0. 한 줄 요약

로드맵이 "당연히 해야 하는 작업"으로 못 박은 **가입 동의 게이트**를 실제로 깔았다. 이제 카카오·네이버·Google로 **처음 로그인하면 약관 동의 화면을 반드시 한 번 거치고**(필수4 + 선택 마케팅), 동의 기록이 있는 사람은 바로 이용한다. 자체 아이디/비밀번호 회원가입·계정찾기는 만들지 않고 **소셜 전용 안내 페이지**로 정리했으며, 데모빌드에서 바뀌어 있던 로그인 **타이틀·파비콘**을 원래대로 되돌리고 약관링크 정렬도 고쳤다.

---

## 1. 무엇이 완성됐나 (비개발 사장님 해설)

### 🔐 가입할 때 약관 동의를 받는다 (핵심)
- 그동안 달록은 OAuth 로그인하면 **동의 절차 없이 바로** 앱으로 들어갔다. 이제 **처음 로그인한 사람은 동의 화면에 갇히고**, 동의해야만 들어간다.
- **필수 4개** — ① 서비스 이용약관 ② 개인정보 수집·이용 ③ 개인정보처리방침 확인 ④ 건강정보(운동·체성분 같은 민감정보) 별도 동의. 4개 다 체크해야 "시작하기" 버튼이 켜진다.
- **선택 1개** — 마케팅·이벤트 수신. 안 해도 가입된다. 설정에서 나중에 켜고 끌 수 있다.
- 동의를 안 하면 못 들어가고 **로그아웃만** 가능하다(서비스가 건강 민감정보를 다루므로 필수 동의 없이는 이용 불가).
- **이미 OAuth로 써본 계정도** 동의 기록이 없으면 다음 접속 때 이 화면을 한 번 거친다. 한 번 동의하면 다음부터는 안 뜬다.

### 🧾 동의 기록이 남는다
- 누가·언제·어느 약관 버전에·어느 소셜(카카오/네이버/Google)로 동의했는지 **표(user_consent)에 차곡차곡** 쌓인다.
- 이 기록은 **고쳐 쓸 수 없다**(append-only). 마음이 바뀌면 "새 줄"로 쌓이지, 과거 기록을 덮어쓰지 않는다 → 나중에 분쟁·삭제요청에 대응할 근거가 된다.
- 약관이 개정돼서 버전이 올라가면 **전원 자동으로 재동의**를 받는 구조(버전 숫자만 올리면 됨).

### 🆔 자체 회원가입은 안 만든다 — 소셜 전용 안내
- 달록은 아이디/비밀번호 회원가입·본인인증을 두지 않는다(소셜 OAuth 신뢰). 그래서 **회원가입·계정찾기 버튼을 누르면** 자체 가입화면이 아니라 **"소셜로만 이용 가능합니다" 안내 페이지**로 간다.
- 안내 페이지에는 **돌아가기 + 카카오/네이버/Google로 계속하기** 버튼이 있고, 이 버튼들은 기존 로그인 화면과 **똑같은 로그인 기능**을 쓴다.
- 로그인 화면 표기에서 "Gmail"이라는 말을 빼고 **"Google"**로 통일했다.

### 🎨 로그인 화면 정리
- 브라우저 탭 제목이 `달록 (demoversion)`으로 바뀌어 있던 걸 **`달록 — PaceLog`**로 되돌렸다.
- 파비콘(탭 아이콘)이 핫핑크로 바뀌어 있던 걸 **원래 라임색**으로 되돌렸다. (버전 회귀가 아니라 제목·아이콘 2개만)
- 로그인 카드 오른쪽으로 삐져나와 있던 "개인정보처리방침·이용약관" 링크를 **카드 아래 중앙**으로 정렬했다(데스크탑·모바일 둘 다).
- 카드 바깥, 약관링크 위에 **회원가입 | 계정찾기 배경박스**를 새로 넣었다.

### 🔁 로그인 후 원래 가려던 곳으로
- 로그인 안 한 상태에서 어떤 보호 페이지로 들어가려다 로그인 화면으로 튕겨도, 로그인(+동의) 끝나면 **원래 가려던 페이지로** 돌려보낸다(없으면 홈).

---

## 2. PR별 상세 (개발 기록)

### PR #77 — 가입 온보딩 동의 + 동의 이력 + 로그인 브랜딩 복귀
- **DB** `migrations/2026-06-10_user_consent.sql` — `user_consent` 테이블(append-only·RLS 본인만·UPDATE/DELETE 정책 없음=변조금지). 탈퇴 시 CASCADE.
- **lib/consent.ts** — 약관 버전 상수(`CONSENT_POLICY_VERSION='2026-06-05'`, LegalPage 시행일과 동일)·동의 조회/기록·필수동의 완료 판정(`isOnboardingComplete`).
- **OnboardingConsent.tsx** — 동의 게이트 화면.
- **useOnboardingConsent.ts** — `getSession()` 기반 게이트. 세션 없음(로컬 테스트세션·데모)=우회('na'), 조회 실패=fail-closed('needed'=동의화면).
- **ConsentHistory.tsx** — 설정>계정 동의 이력.
- **App.tsx** — 로그인↔동의↔앱 분기 배선.
- **로그인 브랜딩(fix 커밋)** — index.html title/og:title `달록 (demoversion)`→`달록 — PaceLog`, favicon `black_on_hotpink.svg`→`black_on_lime.svg`. index.css `.login-panel` flex **row→column**(약관링크 정렬).
- **Codex** 사후검수 2사이클: getSession 전환(게이트 우회 차단)·id 보조정렬·{latest,error} 반환·busy 가드·source CHECK.
- **이슈/해결** — 사장님이 SQL을 SQL Editor에 붙일 때 장식 박스선(`-- ───`) 주석 줄이 `--`와 어긋나 `syntax error at or near ───` 발생 → 장식선·DO블록 제거한 **복붙 안전 SQL**로 교체.

### PR #78 — 소셜 OAuth 전용 로그인/회원가입 흐름 + 약관 동의 강제
- **SocialAuthInfoPage.tsx(신규)** — `/signup`(회원가입 안내)·`/find-account`(계정찾기 안내). 소셜 전용 안내문 + 돌아가기 + 카카오/네이버/Google 계속하기(기존 OAuth 함수 재사용). GuestRouter 공개 라우트.
- **LoginPage.tsx** — "Gmail로 로그인"→"Google로 로그인"(버튼·오류문구). 카드 외부 하단(약관링크 위)에 회원가입/계정찾기 배경박스.
- **consent.ts** — 이 시점 필수항목을 3종(terms·privacy·privacy_policy)으로 재정의(사장님 새 스펙). `recordConsents`에 **oauth_provider** 캡처(app_metadata→user_metadata→합성이메일 fallback). 저장필드 매핑: terms_version=terms행 policy_version / privacy_version=privacy행 policy_version / agreed_at=created_at.
- **postLoginRedirect.ts(신규)** — 비로그인이 가려던 보호경로 저장→콜백서 복원. **내부 경로만 허용**(`//` 외부·`/auth`·`/login`·`/signup`·`/find-account`·약관경로 제외) = open-redirect 차단.
- **콜백 3종(google/kakao/naver)** — 고정 홈→의도경로 복원. **네이버 state 검증 신규 추가**(카카오 패리티), 카카오·네이버 state **누락 시도 차단 강화**(`savedState && savedState !== state`).
- **migration** — `user_consent`에 `oauth_provider` 컬럼 + `consent_type` CHECK에 `privacy_policy` 추가(멱등: ADD COLUMN IF NOT EXISTS + DROP/ADD CONSTRAINT, 기존 health/marketing 값 보존).
- **ConsentHistory** — 동의 이력 읽기전용(이 시점 마케팅 토글 제거).
- **Codex** 사전공유(§7-1) + 사후검수 2사이클. 반영: state 누락차단·Gmail 오류문구·migration source/user_agent 멱등 ADD·oauth_provider fallback. **미반영**: RLS 직접 INSERT 우회(자기영향 한정 → [보류] 후속 하드닝), MasterLoginForm/공개패스워드(사장님 확정 mster 테스트계정 → [반려] 유지).
- **SQL 가이드 HTML** — `docs/sql/260610_user_consent_가이드.html`(1 copy=1 run·메타5종·KEEP/DELETE 분리).

### PR #79 — 동의 항목 조정 (건강 필수 복귀 + 마케팅 선택)
- 사장님 지시로 **건강정보 별도동의를 필수에 다시 포함**(REQUIRED_CONSENTS 필수4: terms·privacy·privacy_policy·health), **마케팅(선택) 동의도 수집**(온보딩 선택 체크박스 — 완료버튼은 필수4만 게이트, 설정 마케팅 토글 복원, LegalPage 약관 예시 글 정합화).
- ConsentHistory 마케팅 토글의 busy 해제 시점을 reload 완료 후로(try/finally) — 연속클릭 중복기록 방지(Codex 증분 검수 반영).
- migration은 이미 health·marketing 허용이라 **추가 SQL 없음**.

---

## 3. 최종 동작 상태 (이 보고 시점 = main)

| 동의 항목 | 구분 |
|---|---|
| 서비스 이용약관 | 필수 |
| 개인정보 수집·이용 | 필수 |
| 개인정보처리방침 확인 | 필수 |
| 건강정보(민감정보) 별도 동의 | 필수 |
| 마케팅·이벤트 수신 | 선택 |

- 가입 화면: 필수4 모두 체크 시 "동의하고 시작하기" 활성. 마케팅은 게이트에 영향 없음.
- 설정>계정: 동의 이력(필수4) 읽기전용 + 마케팅 수신 토글.
- 약관 페이지(`/health-consent`) 하단 "동의 확인 문구" 예시도 실제 온보딩과 동일하게 정합.

---

## 4. 검증

- **빌드** — PR#77/#78/#79 전부 `npm run build`(tsc+vite) 통과.
- **MCP 라이브 검증(playwright)** — 로그인(회원가입/계정찾기 박스·"Google로 로그인"), `/signup`·`/find-account` 안내문·버튼, 돌아가기→/login, `/health-consent` 예시글(필수4+선택1), 타이틀 `달록 — PaceLog`, 파비콘 lime 200 OK, 약관링크 데스크탑·모바일 카드하단 중앙정렬.
- **Codex 협업** — PR#78 사전공유 1 + 사후검수 2사이클, PR#77 사후 2사이클, PR#79 증분 1사이클. 4분류 처리·미반영 사유 기록.
- **미검증(사장님 몫)** — 실 OAuth 로그인→동의→재로그인 스킵의 라이브 흐름은 마이그레이션 적용 + 실제 소셜 로그인 필요.

---

## 5. ⚠ 사장님 잔여 액션

1. **마이그레이션 먼저 적용** — `docs/sql/260610_user_consent_가이드.html`의 STEP1(KEEP) 1회 실행 → STEP2 검증 3개. **프론트(CF 자동배포)보다 먼저** 적용해야 동의 저장이 동작한다(없으면 `oauth_provider`·`privacy_policy` 부재로 INSERT 실패). 추가 SQL 없음(건강·마케팅 값 이미 허용).
2. **라이브 확인** — 본인 OAuth 로그인 → 동의 화면 1회 → 동의 후 진입 / 재로그인 시 스킵 / 동의 안 하면 로그아웃만.

---

## 6. 판단·열린 결정 (사장님 확정/대기)

- **건강정보 별도동의** — 처음엔 새 스펙의 필수3에 없어 제외했으나, Codex가 개인정보보호법 §23 민감정보 별도동의 리스크를 지적 → 사장님 확정으로 **필수에 재포함**(필수4). /health-consent 문서·코치 저장동의는 그대로 보존.
- **마케팅** — 처음엔 "지금 안 만듦"으로 제거했다가, 사장님 지시로 **선택 동의로 복원**(온보딩 선택 + 설정 토글).
- **RLS 직접 INSERT 우회** — 인증 사용자가 클라이언트에서 동의 행을 직접 넣어 UI 동의를 우회할 이론적 여지. 위협이 "본인이 자기 동의를 스스로 위조"(자기영향 한정)이고 서버권위 consent(RPC/Edge)는 큰 구조변경이라 현 단계(표준약관·변호사 없이) **후속 하드닝**으로 보류.

---

## 7. 동시 반영된 운영 지침 (메모리 갱신)

이 스레드에서 사장님 지시로 확정·기록한 운영 원칙(코드 외):
- **"마스터 계정" 워딩 금지** — `mster`는 ID오타+공개패스워드 테스트계정(MCP 브라우징용)일 뿐. 진짜 마스터 관리는 추후 가이드.
- **Codex 협업 §7-1 전체 준수** — 사전공유(원문·의도·예정·범위·보호기준·리스크) + 사후검수 다항목 + 완료보고 "Codex 협업 검토 결과" 섹션 + 비개발자 검수전가 금지.
- **git 자동성 기본값** — 코드 완성·검증 시 커밋·push·PR·머지까지 묻지 않고 자동 완주.
- **SQL 발행 = 가이드 HTML + 1 copy=1 run** — 채팅 코드블록 직접 발행 금지(이번에 1차 위반→정정).
