출시 전 약관·개인정보처리방침·동의 정책 확정 및 공개 — 끊긴 주소·미확정 문안·동의 없는 공개에서 v5 문서·항목별 동의·서버 공개 게이트까지 (2026-09-15)
- 기간: 2026-09-15 하루 (세션 2개 —
a7cc1832-698e-46c6-acc4-e9503c332e72Phase 1~4,019e6e30-4b0c-4c54-8313-bd1cdcee06a0Phase 5·v0.19.3 병합). 오너 지시 원문: "일단 진행해줘"(go, D1 = 필수) → "이거 CI 돌리지 말고 (전체 CI QA2로 이전 진행중) 필요한 작업만 먼저 구현하세요 그리고 v.0.19.3에 병합하세요". - 랜딩: 앱 PR #1636 →
release/v0.19.30dd2e474(Phase 3·4·5 + e2e 고정 수리; 마이그레이션20260915180000_apply_user_consents_v1·20260915190000_sharing_consent_gates_v1·20260915200000_consent_requirements_v5). 같은 Phase 3·4 코드는 PR #1631 →release/v0.20.06399b7e9에도 있다. 랜딩 Barbelic-landing PR #52be5a083(Production 배포). 문서 PR #95·#98(v5·동의문 3종 게시, Vercel 배포)·#99·#101(계약). staging·Production 미반영(승격 대기). - 설계서: 없음 — 계획은 이슈 #1625 본문(5 Phase, 예상 효과·개선사항 표, D1).
- 정본: 게시 문서
public/legal/terms-v5.html·privacy-v5.html·consent-sensitive-v1.html·consent-sharing-v1.html·consent-sharing-sensitive-v1.html·account/delete.html; 앱src/react/legalDocuments.ts(레지스트리·resolveConsentPlan), 서버onboarding_consent_requirements()(요구 목록),apply_user_consents_v1(재동의·설정 문),owner_shares_profile_v1/owner_shares_sensitive_v1(공개 판정),profile_feed_can_view_v1(팔로우 열람 단일 판정); 계약 친구 접근·화면 계약 (#99·#101). - 도구: 문서 저장소
check-legal-documents.mjs(동의문도 검사), 앱sql:candidate·schema:snapshot·db:model. - 게이트: pgTAP
apply_user_consents_v1(12 assert)·sharing_consent_gates_v1(23)·barbelic_legal_v4(v5 모양, 10)·팔로우·피드·검색·사진·리포트 픽스처 11개(공개 동의 부여). 로컬 사전검증npm run ci:precheck-local(2026-09-15 15:15 KST): static·unit-1 1756·unit-2 2140·db reset·스냅샷 --check·pgTAP 126파일/2535 assert 통과·DB 동시성 5묶음 통과. 브라우저 e2e는 로컬로 돌리지 않음(오너 지시). - 버그리포트: 없음.
- 계약: 친구 접근 계약에 공개 동의·민감정보 제공 동의 게이트(#101), 온보딩·재동의·개인정보 설정 화면 계약(#99), 유저 원본 불변 문서의 탈퇴·백업 문구(#98).
Phase 현황
| Phase | 내용 | 상태 |
|---|---|---|
| Phase 1 | 접속·연락 경로 수리 — www 법률문서·탈퇴 주소 → app 원문 308, App Store 제출 문서 URL·연락처 | ✅ 랜딩 PR #5 2be5a083 · docs PR #95 244988ef |
| Phase 2 | 정책 확정과 v5 최종 문안 게시 — 빈칸 16종 확정, 약관·처리방침 v5, 동의문 3종, 계정 삭제 안내 | ✅ docs PR #98 6e92b975, Vercel 배포 |
| Phase 3 | 앱 동의 구조 — 만 14세 확인, 서버 요구 기반 동의 단계, 종류별 저장·철회, 재동의 화면, 개인정보·공개 설정 | ✅ PR #1631(21219233·26790b1e) → v0.20.0, PR #1636 → v0.19.3 |
| Phase 4 | 공개 범위 서버 게이트 — 검색·팔로우·피드·세션 상세·사진 판정, 민감 필드 제외 | ✅ PR #1631(4fbe30af), PR #1636 |
| Phase 5 | 서버 요구 v5 전환 마이그레이션 + 픽스처 갱신 (운영 안내 갱신·ASC URL 안내·Production 조회는 릴리스 뒤) | ✅ PR #1636 0dd2e474 (release/v0.19.3) · 운영 안내 docs PR #102 열림 |
1. 배경
심사·출시 전 P0 7건(약관·처리방침 최종본, 민감정보 별도 동의, 프로필 사진 문구, 팔로우·공개·철회 정책, 탈퇴 후 데이터·백업 안내, URL 접속, 문의 메일 수신)이 하나도 완료 상태가 아니었다. 9/7 법률 검토(v5 문안)는 "별도 동의·철회·공개 통제가 구현된 상태"를 기준으로 쓰였고, 구현은 "확정 문안"을 기다리며 서로 보류돼 있었다. 9/15 도메인 분리(www = 랜딩, app = 앱)로 스토어·문서에 적어 낸 공개 URL이 랜딩 페이지로 열리게 됐고, 문의 메일 support@barbelic.com은 수신 설정(MX)이 없어 반송됐다.
2. 문제 제기
공개 URL 4개가 랜딩 페이지로 열렸다
www.barbelic.com/legal/terms-v4.html·privacy-v4.html·service-info.html·/account/delete.html이 HTTP 200이지만 랜딩 index.html(랜딩 vercel.json이 전 경로를 index로 되쓰기). 원문은 app.barbelic.com/legal/*에만 있었다.
문의 메일이 도착하지 않았다
barbelic.com DNS(Vercel DNS)에 MX 레코드가 없었다. 게시본 v4 문의처는 Gmail, 운영 안내는 support@ — 게시 문서끼리도 불일치.
민감정보에 별도 동의가 없었고, 팔로우 공개가 동의 없이 이뤄졌다
온보딩 동의는 약관·처리방침 필수 2건뿐. 체중·체성분·컨디션·메모(건강 정보)에 별도 동의 없음. 상대 승인 없는 일방 팔로우로 운동 상세·체중·컨디션·메모·PR·리포트·계획까지 열람. 서버 요구 목록 onboarding_consent_requirements()는 terms/privacy v4 + marketing v1(선택).
v5 문안은 자리표시자 16종이 비어 있었다
시행·공지일, 위탁·국외 이전 업체와 국가·보존 기간, 메일 처리자, 백업·이력 파기 규칙, 사진 문구.
3. 해결 방안
원칙 (오너 결정)
- D1 (2026-09-15): 민감정보(체중·체성분·컨디션·건강 관련 메모) 수집·이용 동의는 필수 — 별도 문서·별도 체크박스로 받되 동의하지 않으면 가입을 마칠 수 없고, 문서에 "서비스 제공에 필수"와 거부 시 불이익(가입 불가)을 명시. 채택.
- 2026-09-15 오후 지시: 전체 CI를 QA2로 이전 중이므로 이 트랙은 CI를 돌리지 않고 필요한 작업만 구현해
v0.19.3에 병합. 채택 — 목표 릴리스를 v0.20.0(minor)에서 v0.19.3으로 바꿨고, Phase 5 전환 마이그레이션을 "번들이 Production에 나간 뒤 별도 PR"이 아니라 같은 릴리스에 실었다(아래 접근).
접근
| 안 | 내용 | 판단 |
|---|---|---|
| 문안과 구현을 한 트랙으로 | Phase 1 접속·연락 → Phase 2 문안 확정·게시 → Phase 3 앱 동의 구조 → Phase 4 서버 게이트 → Phase 5 요구 전환 | 채택 — 서로 기다리던 구조를 순서로 풀었다 |
| 공개 동의를 UI 숨김으로만 | 화면에서 버튼만 숨김 | 기각 — RPC 직접 호출로 노출됨. 서버 판정 함수 1곳(profile_feed_can_view_v1) + 검색·팔로우·사진 정책에서 판정 |
| 전환 마이그레이션을 번들 배포 뒤 별도 릴리스로 | 배포 순서 계약(레지스트리 번들 먼저) 준수, 릴리스 2회 | Phase 4까지의 계획. 오너의 v0.19.3 지시로 같은 릴리스로 변경 — 비용: 마이그레이션 적용부터 새 번들 배포까지 몇 분과 옛 캐시 번들에서 신규 가입의 약관 단계만 실패(옛 번들이 미등재 v5에 예외). 기존 회원 이용은 영향 없음(온보딩 완료 판정은 동의 버전과 무관). 마이그레이션 머리말·PR 본문에 명시 |
| 기존 회원 팔로우 공개 유지(전원 동의 간주) | 재동의 없이 공개 유지 | 기각 — 9/7 검토 결론대로 재동의 화면에서 선택하기 전까지 비공개, 팔로우 관계는 유지·동의 즉시 복구 |
4. 적용한 내용
Phase 1 — 접속·연락 경로 수리 (랜딩 PR #5, docs PR #95)
랜딩 vercel.json에 /legal/:path*·/account/delete.html → https://app.barbelic.com/… 308. docs/platform/app-store-submission.md URL 5곳·연락처 2곳을 app 주소·support@로. 실측: www 4개 주소 → 308 → app 원문 200.
Phase 2 — 정책 확정과 v5 게시 (docs PR #98)
확정값: 공지·시행 2026-09-15(시행일 전 가입 회원은 v4의 30일 고지 약속에 따라 2026-10-15부터), Supabase(일본 도쿄 DB·백업 7일·로그 7일·싱가포르 법인), Vercel(미국, 로그 최대 1일), GitHub(미국, 사본 90일), 문의 메일 Google LLC(Google Workspace, MX 확인). 파기 완료 기준 = 계정 삭제 후 최대 90일(운영 DB·이력 즉시, 백업 7일, 사본 90일; 탈퇴 회원은 복구 대상 제외 — rollback.md 8-3). 프로필 사진: 업로드 기능 있음·공개 동의 시 로그인 회원에게 표시·메타데이터 미제거 안내. 검토본 7절(그룹·댓글 게시 시점 동의)은 앱에 화면이 없어 게시하지 않음. check-legal-documents.mjs가 동의문 3종(식별자 = user_consents.consent_type 값)도 검사.
Phase 3 — 앱 동의 구조 (PR #1631 21219233·26790b1e, 마이그레이션 20260915180000)
① 소셜 로그인 버튼 앞 "만 14세 이상입니다" 확인(확인 전 버튼 잠금) ② 약관 단계가 서버 요구 목록을 그대로 그린다(항목별 체크·전문 보기·"전체 동의(선택 포함)") ③ 항목별 체크 값이 그대로 저장, 필수 누락은 서버 호출 전 차단 ④ 필수 동의가 새 버전으로 바뀐 기존 회원에게 재동의 화면(2026-10-15 전 "나중에" 가능) ⑤ apply_user_consents_v1(본인 재동의·선택 동의 켜기/끄기, 필수 철회 거부) ⑥ 내 정보 › 개인정보·공개 설정 ⑦ 등재되지 않은 새 약관 버전도 파일명 규칙으로 열리게 해 "서버 요구 전환이 구 번들 온보딩을 깨뜨리던" 함정 제거(새 번들부터).
Phase 4 — 공개 범위 서버 게이트 (PR #1631 4fbe30af, 마이그레이션 20260915190000)
owner_shares_profile_v1·owner_shares_sensitive_v1(서버 요구 목록에 해당 유형이 없으면 종전대로 통과 → 데이터로 켜짐), profile_feed_can_view_v1(호출처 18곳)·검색·팔로우(동의 없음 = 차단과 같은 P0002)·팔로잉 목록·프로필 사진 저장소 정책에 판정 추가, 민감정보 제공 동의 없는 주인의 체중·컨디션·메모·리뷰·세트 메모를 팔로워 응답에서 null로(strip_session_detail_sensitive_v1). 팔로우 행·기록·동의 이력은 바꾸지 않는다.
Phase 5 — 서버 요구 v5 전환 (PR #1636, 마이그레이션 20260915200000)
onboarding_consent_requirements() → 약관·처리방침 v5 필수, sensitive_data_processing v1 필수(D1), profile_sharing·sensitive_sharing v1 선택, marketing 제거(기존 동의 이력은 그대로). 전환으로 Phase 4 게이트가 실제로 켜지면서 걸린 QA1 테스트를 고쳤다: 팔로우·피드·검색·사진·리포트 pgTAP 11개는 주인에게 공개 동의 2종을 픽스처로 부여, 온보딩 RPC 페이로드 4개는 v5+민감정보 동의, barbelic_legal_v4·apply_user_consents_v1·profileProvisioning 단언은 v5 모양, sharing_consent_gates_v1은 "전환 전" 구간을 v4 모양 재정의로, e2e 하네스는 서버가 선택으로 실은 공개 동의 2종도 수락(QA1 157be380). release/v0.19.3 기준으로 스냅샷·registry·db-objects 재생.
주요 결정과 그 근거
- 동의 유형·버전을 종류별로 독립 기록(약관 동의로 선택 동의를 추론하지 않음) — 이후 동의 추가가 마이그레이션 1개로 끝난다.
- 공개 판정은 데이터로 켜진다(요구 목록에 유형이 있을 때만) — Phase 3·4 코드가 먼저 배포돼도 화면 변화가 없고, 전환 마이그레이션 하나가 스위치.
- 판정 함수 두 개는 service_role 전용(엔진 등급) — SQL 층 규칙(엔진은 공개 함수를 부르지 않는다) 때문에 문(門)에서만 호출.
작업 중 드러난 것
- 사전 검증 누락(Phase 3): 로그인 e2e CASE-003·049·059·060이 소셜 버튼을 바로 눌러 만 14세 확인에 걸린다 — 브라우저 e2e는 precheck 범위 밖. QA1
d82746a0(확인 체크 선행)으로 수리해 #1636에 포함. 그 뒤 로컬 브라우저 실행(wt1625b, 오너 지시 전) 48건 중 34건 실패는 CASE-001 등 "새로고침 뒤 달력의 세션 카드 hidden" 모양으로 만 14세 확인과 무관해 보임 — 오너 지시로 더 돌리지 않음(미검증). - Phase 5 WIP 커밋에 정의 파일(
onboarding_consent_requirements.sql) v5 변경이 빠져 있었다 — 채움. - 전환을 켜자 사전검증 1회차 pgTAP 14파일 빨간불 — 전부 옛 픽스처가 게이트에 걸린 것, 앱 결함 0건. 픽스처 삽입 위치를 "첫
;"로 잡으면data:image/png;base64안의 세미콜론에 걸린다(profile_handle_v1). tests/db/statsSequentialReplayD07 1건이 stats workerbusy로 1회 실패 뒤 2·3회차 통과(환경 요인).- v0.19.3 기준 브랜치에 #1631을 합칠 때 충돌 5개(qa1.lock·deploymentManifest·db-objects·registry·schema.sql)는 전부 생성물 — 재생으로 해소. QA1 고정은 v0.19.3 고정(32c278bb)과 이 트랙 고정을 합친 커밋으로.
- 문서 사이트 자동 배포(Docs Deploy)는 변수 미설정으로 skipped — 게시는 pinned
vercel@59.11.7 deploy --prod --local-config .vercel-docs.generated.json(최신 CLI는 미로그인처럼 보임).
5. 적용 결과
| 항목 | 결과 |
|---|---|
| www 법률문서·탈퇴 주소 4개 | 랜딩 HTML → 308 → app 원문 200 (실측 2026-09-15) |
| 문의 메일 | MX 없음(반송) → Google Workspace MX 확인. 오너의 테스트 메일 수신 확인은 아직 |
| 게시 문서 문의처 | v4 Gmail / 안내 support@ 혼재 → v5·동의문·안내 모두 support@ (v4 원문은 불변) |
| 서버 요구 동의 | terms/privacy v4 + marketing → terms/privacy v5 + 민감정보 v1 필수 + 공개 동의 2종 선택 (release/v0.19.3, Production 미반영) |
| 공개 게이트 | 0 → 검색·팔로우·팔로잉 목록·피드·세션 상세·달력·PR·리포트·계획·사진 판정 + 민감 필드 4경로 null (pgTAP 23 assert) |
| 연령 확인 | OAuth 전 확인 없음 → 확인 1단계(모바일·데스크톱) |
| 기존 회원 16명 | 다음 로그인 때 재동의 화면 1회, 공개 동의 전까지 팔로워에게 비공개 — Production 반영 뒤 읽기 전용 조회로 저장 확인 필요 |
| 자동 검증 | precheck 3회차: pgTAP 126파일/2535 assert 통과, 단위 3896 통과. 브라우저 e2e 미검증 |
| 배포 창 위험 | 마이그레이션 적용~새 번들 배포 사이·옛 캐시 번들의 신규 가입 약관 단계 실패 — 전제로 수용(오너 지시), 기존 회원 영향 없음 |
6. 이번 개선으로 향상된 것
심사관과 가입 전 사용자가 스토어에 적힌 주소로 원문을 본다
스토어·검색엔진에 이미 나간 www 주소가 앱 주소 변경과 무관하게 원문으로 이어진다 — "법률문서 URL은 앱 주소가 아니라 문서 주소를 따른다"는 리다이렉트가 구조로 남는다.
건강 정보 처리에 별도 동의 근거가 생겼다
민감정보 수집·이용 동의가 약관과 분리된 문서·체크박스로 기록되고(이력 포함), 목적·항목·기간·거부 시 불이익이 문서에 있다.
기록 공개가 본인 선택이 됐다
팔로우당하는 쪽이 공개 여부와 민감 항목 제공 여부를 각각 정하고 언제든 끌 수 있으며, 서버가 판정한다. UI만 숨기는 방식이 아니라 RPC 직접 호출도 막힌다.
구조적으로 남는 것
동의 유형·버전을 종류별로 독립 기록하는 구조(마케팅 동의 등 추가 = 마이그레이션 1개), 공개 범위를 서버가 판정하는 함수 1곳, 동의문을 검사하는 문서 게이트, 탈퇴·백업·이력 처리가 문서와 절차(rollback.md 8-3)로 일치.
남은 것
- 릴리스 세션: release/v0.19.3 → staging → main. v0.19.3 Production 반영 뒤 ① Barbelic-docs PR #102(운영 안내 v5) 병합·CLI 게시 ② Production 읽기 전용 조회로 새 동의 유형(
sensitive_data_processing·profile_sharing·sensitive_sharing) 저장 확인 ③ 이슈 [v0.19.3 병합완료] → [v0.19.3 스테이징] → [v0.19.3 반영완료]. - 오너 손: support@barbelic.com 테스트 메일 수신 확인 1회. App Store Connect 개인정보 URL
https://app.barbelic.com/legal/privacy-v5.html·이용약관terms-v5.html·지원service-info.html·심사 노트 연락처support@barbelic.com. - 브라우저 e2e는 승격 후보 Full CI(QA2 이전 중)에서 확인. release/v0.20.0(#1631)은 v0.19.3이 main에 간 뒤 main을 반영하면 동일 내용이라 충돌 없음.
- 범위 밖: 프로필 사진 메타데이터 제거(약속하지 않음), 그룹·댓글 게시 시점 동의(화면 없음).