---
task_id: task-2099
type: context
scope: task
created: 2026-04-22
updated: 2026-04-22
status: completed
---

# 맥락 노트: task-2099

**task**: task-2099

---

## 결정 근거

### 3 Step Why

**1st Why**: "왜 이 설계가 필요한가?"
- A: fetch()로 직접 Edge Function을 호출하면서 anon key를 Authorization으로 보내면, (1) Supabase가 apikey 헤더 누락으로 요청을 거부하거나, (2) JWT 파싱 실패로 사용자 인증이 안 되어 "failed to fetch" 에러가 발생한다.

**2nd Why**: "왜 session.access_token + apikey 헤더 방식이 최선인가?"
- B: supabase.functions.invoke()는 스트리밍(SSE)을 지원하지 않으므로 fetch()를 유지해야 한다. fetch() 유지하면서 올바른 인증을 위해 session.access_token(Authorization) + anon key(apikey 헤더)를 함께 보내는 것이 Supabase Edge Function의 공식 인증 패턴이다.

**3rd Why**: "왜 다른 대안보다 나은가?"
- C: 대안1(Edge Function CORS 수정)은 서버 측 변경이 필요하여 복잡성 증가. 대안2(스트리밍 포기)는 UX 저하. 현재 접근법은 프론트엔드 단일 파일 수정만으로 해결되며, 같은 파일의 suggest-topics(supabase.functions.invoke 사용)와 인증 패턴이 일관된다.
- A-B-C가 논리적으로 일관됨을 확인.

### 근본 원인 분석
- Generate.tsx line 147: `Authorization: Bearer ${import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY}` → anon key를 세션 토큰으로 오인
- Edge Function (generate-content/index.ts line 316-318): `anonClient.auth.getClaims(token)` → anon key로는 파싱 불가
- Supabase Edge Function은 apikey 헤더도 필수 요구

## 참조 자료

- Edge Function 코드: `supabase/functions/generate-content/index.ts`
- 프론트 API 설정: `src/config/api.ts`
- Codex gate 결과: `memory/events/task-2099.codex-gate`

## 주의사항

- 스트리밍(SSE) 때문에 supabase.functions.invoke() 대신 fetch() 사용 유지
- 403 에러의 error 코드가 Edge Function의 응답 형식과 일치하는지 배포 후 재확인 필요
- contentType이 label(예: "네이버 블로그")로 전송되므로, Edge Function의 allowed_channels와 매핑이 불일치할 수 있음 (별도 이슈로 추적 필요)
