---
task_id: task-2982
scope: task
role: 모리건(Morrigan) - dev3 테스트/QA
date: 2026-08-20
status: verified (read-only)
---

# task-2982: 인슈로 개인정보처리방침/동의 실브라우저 실측 검증

## S — 상황
"인슈로 화면에서 개인정보 처리방침·동의가 실제로 사용자 눈에 보이는가"를 실 브라우저(Playwright)로 검증. 프로덕션(`https://insuro.biz/`)과 로컬 preview(`http://localhost:5173`, 동일 dist 정적 서빙)를 대상으로 read-only 검증만 수행. 앱 코드/배포는 수정하지 않음.

## ★ 핵심 답변
**"비로그인 사용자가 인슈로에서 개인정보처리방침을 볼 수 있는가?" → NO.**

근거:
1. `/login`, `/reset-password`(무효 리다이렉트), 회원가입(이메일/구글) 화면 전체에 "개인정보", "처리방침", "약관", "동의" 문자열이 **단 하나도 렌더되지 않음** (`page.evaluate` 로 `document.body.innerText` 전수 grep, 4개 화면 모두 4개 키워드 전부 `false`).
2. `/privacy`, `/privacy-policy`, `/terms`, `/policy` 라우트가 **애초에 라우터에 정의되어 있지 않음**(`src/config/routes.ts` 56개 라우트 전수 확인, 매치 0건). 존재하지 않는 경로이므로 렌더될 여지 자체가 없음.
3. 위 4개 경로 + 임의 404 경로(`/xxxx-not-exist`)는 전부 `/login`으로 강제 리다이렉트됨. 원인은 404가 아니라 `src/components/AuthGuard.tsx`가 `Routes` 전체를 감싸고 있고, `PUBLIC_PATHS=["/login","/reset-password"]` / `PUBLIC_PREFIXES=["/chat/","/namecard/"]` 외 모든 경로에 대해 미인증 시 `/login`으로 `Navigate` 시키기 때문. 즉 NotFound(404) 컴포넌트조차 비로그인 사용자는 절대 볼 수 없음(라우트 매칭보다 인증 가드가 먼저 개입).
4. 공개 라우트(`/namecard/:agentId`, `/chat/:token`)는 실명(이름)+전화번호(연락처)를 수집하는 폼을 갖고 있지만(`src/pages/DigitalNamecard.tsx`, `src/pages/CustomerChat.tsx`), 두 파일 전체(342줄, 308줄)를 grep한 결과 "개인정보/처리방침/이용약관/동의" 문자열이 **0건**. 즉 실명+전화번호라는 PII를 비로그인 방문자로부터 수집하면서 어떤 형태의 개인정보 수집 동의 고지도 화면에 존재하지 않음.
5. 빌드 산출물(`dist/`) 전체 grep 결과 "개인정보 수집" 문자열은 `AdminCrmConfig-*.js`, `CrmCustomerDetail-*.js` 2개 번들에서만 발견되며, 둘 다 로그인 후 접근 가능한 내부 CRM 화면(에이전트가 오프라인으로 받은 고객 동의 상태를 수기 기록하는 `ConsentTab.tsx` 기능)이다. 이는 **최종 고객이 보는 동의 화면이 아니라, 설계사가 자체적으로 고객 동의 여부를 로그로 남기는 내부 관리 도구**임 — 근본적으로 성격이 다름.

## 시나리오별 결과표

| # | 대상 | 결과 | 스크린샷(절대경로) | 육안 확인 |
|---|------|------|---------------------|-----------|
| ①-1 | `https://insuro.biz/` 루트 접속 | `/login` 으로 즉시 리다이렉트 | `/home/jay/workspace/memory/reports/task-2982-screenshots/01-root-redirect-login.png` | InsuRo 랜딩+로그인 스플릿 화면. "로그인" 헤딩, Google 버튼, "이메일로 계속", "회원가입" 링크, 푸터 "© 2026 InsuRo. All rights reserved." — **처리방침/약관 링크 전무** |
| ①-2 | `/login` 로그인 폼 | 로그인 폼에 정책/동의 요소 없음 | 위와 동일(01) | 위와 동일 |
| ①-2b | 이메일 로그인 폼 확장 | 이메일/비밀번호 입력란만 존재 | `06-login-email-form.png` | 이메일/비밀번호 필드 + "로그인" 버튼. 정책 링크·체크박스 없음 |
| ①-2c | 회원가입(이메일/구글) 폼 | 실제 계정 생성 화면에도 없음 | `07-signup-form.png` | "회원가입" 헤딩, "카드 등록 없이 바로 사용 가능" 문구, Google 가입 버튼, "이메일로 계속" 링크. **개인정보 수집·이용 동의 체크박스, 이용약관 동의 체크박스 등 회원가입 표준 요소가 전혀 없음** |
| ①-3 | `/privacy` | `/login`으로 리다이렉트(라우트 미정의) | `02-privacy-redirect-login.png` | 로그인 화면과 동일 (라우트 자체가 존재하지 않아 AuthGuard가 즉시 가로챔) |
| ①-3 | `/privacy-policy` | 동일(라우트 미정의 → `/login`) | (동일 화면, 별도 스샷 생략 — 소스 코드로 라우트 부재 확정) | 코드 확인: `routes.ts` 56개 라우트에 매치 0건 |
| ①-3 | `/terms` | 동일 | 〃 | 〃 |
| ①-3 | `/policy` | 동일 | 〃 | 〃 |
| ①-4 | 페이지 텍스트 grep(`개인정보/처리방침/약관`) | 로그인/가입 4개 화면 전부 **미검출** | `page.evaluate(innerText.includes(...))` 실행 결과 첨부 | 4개 키워드 x 4개 화면 = 16개 체크 전부 `false` |
| ②-1 | `/namecard/<임의ID>` (존재하지 않는 agentId) | "프로필을 찾을 수 없습니다." | `03-namecard-invalid-id.png` | 빈 화면 + PWA 설치 팝업만, 정책 링크 없음 |
| ②-1b | `DigitalNamecard.tsx` 소스 전수 검토 (342줄) | 실명+전화번호 상담신청 폼 존재하나 동의 문구/링크 **0건** — 어떤 프로필 상태(로딩/없음/불완전/완전)에서도 동일 | 코드 근거: 파일 전체 grep 매치 0 | 유효 agentId를 얻지 못해 "완전한 프로필" 렌더 상태는 스크린샷 미확보(아래 한계 참조). 단, 조건부 렌더 4개 분기 전부에 동의 텍스트가 JSX에 존재하지 않으므로 어떤 실제 agentId를 넣어도 결과는 동일 |
| ②-2 | `/chat/<임의 token>` (무효 토큰) | "본인 확인" 화면(이름+연락처 재입력 요구) | `04-chat-invalid-token.png` | "본인 확인" 헤딩, "상담을 시작하려면 이름과 연락처를 입력해주세요" 문구, 이름/연락처 입력란. **정책 링크·동의 문구 없음** |
| ②-3 | 푸터 처리방침 링크(namecard/chat) | 없음 | 03, 04 스샷 | 두 화면 모두 "Powered by InsuRo" 외 푸터 텍스트 없음 |
| ③ | 업로드·분석 플로우(로그인 필요) | **인증게이트로 확인 불가** — AuthGuard가 비공개 라우트 전부를 `/login`으로 가로챔 (정직 기록) | — | dist 문자열 대체 검증으로 보완 |
| ③(대체) | `grep -ro "개인정보처리방침\|개인정보 수집\|처리방침\|이용약관" dist/` | 매치 2건: `AdminCrmConfig-*.js`(관리자 설정), `CrmCustomerDetail-*.js`(CRM 고객상세, `ConsentTab.tsx` 소스) | — | 둘 다 로그인 후 내부 CRM 전용 — 설계사가 고객의 오프라인 동의 상태(동의/거절/철회/만료)를 수기 기록하는 도구. **최종 고객에게 노출되는 동의 화면이 아님** |
| ④ | `/xxxx-not-exist` (존재하지 않는 라우트) | NotFound 컴포넌트가 아니라 `/login`으로 리다이렉트 | `05-404-not-exist.png` | 로그인 화면과 동일. AuthGuard가 라우트 매칭보다 먼저 개입하여 진짜 404 화면은 비로그인 상태에서 절대 렌더되지 않음. 정책 링크 당연히 없음 |
| 로컬(5173) vs 프로덕션 | 루트 리다이렉트 동작 비교 | 완전 동일 (`http://localhost:5173/` → `http://localhost:5173/login`) | — | 동일 dist 정적 서빙이므로 결과 동일. 별도 차이 없음 |

## 코드 근거 (읽기 전용 확인, 수정 없음)
- `/home/jay/projects/InsuRo/src/App.tsx` — 라우팅: `"/" → Navigate("/intro")`, `"*" → NotFound`, 전체가 `<AuthGuard>` 로 감싸짐
- `/home/jay/projects/InsuRo/src/components/AuthGuard.tsx` — `PUBLIC_PATHS=["/login","/reset-password"]`, `PUBLIC_PREFIXES=["/chat/","/namecard/"]` 외 전부 미인증 시 `/login` 강제 이동. **NotFound보다 AuthGuard가 우선순위 높음**
- `/home/jay/projects/InsuRo/src/config/routes.ts` — 56개 라우트 전수 확인, `privacy/terms/policy` 관련 경로 0건
- `/home/jay/projects/InsuRo/src/pages/DigitalNamecard.tsx` (342줄) — PII(이름·연락처) 수집 폼 존재, 동의/정책 텍스트 0건
- `/home/jay/projects/InsuRo/src/pages/CustomerChat.tsx` (308줄) — "본인 확인" PII 재확인 폼, 동의/정책 텍스트 0건
- `/home/jay/projects/InsuRo/src/components/AuthForm.tsx` — 로그인/회원가입 폼(이메일+비밀번호), 동의/정책 텍스트 0건
- `/home/jay/projects/InsuRo/src/pages/ResetPassword.tsx` — `#type=recovery` 해시 없으면 `/login`으로 자체 리다이렉트(AuthGuard 문제 아님, 앱 로직)
- `/home/jay/projects/InsuRo/src/components/crm/ConsentTab.tsx` — 내부 CRM 동의 "기록" 도구(설계사가 수기 입력), 최종고객 노출 화면 아님

## 한계/정직 기록
- `/namecard/<agentId>` 의 "완전한 프로필" 렌더 상태(모든 필드 채워진 실제 설계사 명함)는 유효한 agentId를 확보하지 못해 실제 화면 스크린샷을 얻지 못함. 대신 `DigitalNamecard.tsx` 전체 소스를 읽어 4개 조건부 렌더 분기(로딩/프로필없음/불완전/완전) 전부에서 동의·정책 관련 JSX가 존재하지 않음을 코드 레벨로 확인함 — 스크린샷 부재가 판정을 흔들지 않음.
- 시나리오 ③(업로드·분석 플로우)은 지시대로 인증게이트로 실제 접근 불가하며, 서명 JWT 위조나 가짜 토큰 생성은 금지 규정에 따라 시도하지 않음. `dist/` 문자열 검증으로 대체함.
- 프로덕션과 로컬(5173)은 완전히 동일한 정적 dist 결과물이므로 별도 차이 없음(둘 다 동일 빌드 서빙 확인).

## 종합 결론
비로그인 사용자는 인슈로의 어떤 화면(랜딩/로그인/회원가입/공개 상담폼/공개 채팅/404)에서도 개인정보처리방침이나 이용약관 링크, 개인정보 수집·이용 동의 체크박스를 볼 수 없다. 특히:
- 실제 계정을 만드는 **회원가입 화면 자체에 법정 필수 요소인 개인정보 수집·이용 동의 체크박스가 없음** (스크린샷 07 확인).
- 비로그인 방문자로부터 실명+전화번호를 직접 수집하는 두 공개 라우트(`/namecard/*`, `/chat/*`)에도 어떤 형태의 개인정보 수집 고지도 없음.
- `/privacy` 등 정책 페이지 경로 자체가 라우터에 존재하지 않아, 설사 사용자가 URL을 직접 입력해도 볼 방법이 없음.
- 내부 CRM에 있는 "개인정보 수집" 관련 문구는 최종고객이 아닌 로그인한 설계사만 보는 동의 기록 도구이므로 이번 점검의 답이 될 수 없음.
