---
task_id: task-1955
type: context
scope: task
created: 2026-04-19
updated: 2026-04-19
status: completed
---

# 맥락 노트: task-1955

**task**: task-1955

---

## 결정 근거

### isAdmin 가드 패턴 선택
- AdminNotices.tsx의 기존 패턴(useIsAdmin hook + 조기 반환)을 그대로 적용
- 대안: 라우터 레벨에서만 가드 → 기각 (페이지 직접 URL 접근 시 노출)
- 이중 방어(라우터 adminOnly + 페이지 isAdmin) 채택

### CustomerChat rate limit 구현 위치
- 클라이언트 측 state 기반 rate limit 구현 (서버 측은 Supabase RLS에 의존)
- 대안: Supabase Edge Function에 서버 rate limit → Phase 1으로 미룸 (범위 초과)
- 5회 실패 시 5분 잠금이 무차별 대입 방지에 충분

### Dashboard 깨진 라우트 수정 방침
- 미존재 라우트 10개 → 실존 라우트 6개로 축소 매핑
- 유사 기능이 없는 항목(AI 건강진단분석기 등)은 제거

## 3 Step Why

**1st Why**: "왜 이 설계가 필요한가?"
→ 전수조사에서 CRITICAL 4건 발견. test@test.com 하드코딩은 누구나 관리자 계정으로 로그인 가능. Admin 페이지 가드 누락은 일반 사용자가 관리 기능 접근 가능.

**2nd Why**: "왜 각 파일 직접 패치가 최선인가?"
→ 이슈가 개별 페이지 컴포넌트에 국한. routes.ts에 adminOnly 플래그는 존재하나 페이지 자체 가드가 누락. 라우터+페이지 이중 방어가 올바른 접근.

**3rd Why**: "왜 이중 방어가 다른 대안보다 나은가?"
→ 단일 레이어 의존 시 설정 변경으로 가드 해제 위험. 이중 방어로 한 레이어 실패 시에도 보호.

## 참조 자료

- 전수조사: `memory/research/insuro-page-audit.md`
- isAdmin 패턴: `src/hooks/use-is-admin.ts`
- 라우트 정의: `src/config/routes.ts`

## 주의사항

- CustomerChat의 rate limit은 클라이언트 측이므로 우회 가능. Phase 1에서 서버 측 보완 필요.
- expires_at 컬럼이 DB에 없을 수 있으므로 optional 체크 사용.
