0. 요약 (TL;DR)
어드민 지연은 단일 버그가 아니라 “DB에서 전체 row를 끌어와 JS로 집계”하는 데이터 접근 패턴이 깔린 구조적 문제다. 이 JS 집계는 주로 백엔드(서버 Node.js) API 핸들러에서, 일부는 프론트엔드(브라우저)에서 일어난다. 데이터가 커질수록 선형으로 악화된다.
_shared.fetchAllPages()로 OFFSET 페이지네이션을 돌려 최대 5만 row를 메모리에 적재한 뒤 JS에서 filter/reduce 집계한다. 대시보드 초기 진입 시 이런 핸들러 5개가 동시에 터지면서 3–5초 지연을 만든다. (CLAUDE.md의 “OFFSET 금지·keyset 사용” 원칙 정면 위반)
analytics_cache 테이블 + getCacheShared + RPC admin_overview_agg)와 dynamic import·TanStack Query는 이미 갖춰져 있다. 문제는 일부 핸들러만 이 모범 패턴을 쓴다는 것 — 나머지로 확산만 하면 큰 비용 없이 대부분 해결된다.
1. 어드민 페이지가 느린 이유 — 종합
근본 원인 순위(WSJF: 영향 ÷ 수정비용). 각 항목은 아래 상세 절의 코드 근거로 이어진다.
- 전량 fetch + JS 집계 (DB층) — analytics 핸들러가 OFFSET로 최대 5만 row를 끌어와 앱에서 집계. 대시보드 3–5s 주범 상
_shared.ts:254-289,heatmap.ts,page-metrics.ts,day-detail.ts - 마운트 시 API 5개 동시 발사 + 캐시 불일치 (FE층) — 대시보드 진입 즉시 5요청 burst, 그중 4개는 raw
fetch+useState라 TanStack 캐시 밖 → 뷰 왕복마다 재요청. 상
AdminDashboard.tsx:288-544 - SSR 게이트의 직렬 인증 왕복 (TTFB) — 매 진입 시
getServerSideProps에서 SupabasegetUser()→cms_users조회를 직렬 await. TTFB가 인증 2회 왕복에 묶임. 상
admin/index.tsx:132-138 - 전체 게시글
select("*")무제한 + JS 페이징 (DB·FE 공통) —getPosts()가 content 포함 전 row 로드, VisitorList도 전 방문자 받아 클라에서slice. 상
storage.ts:393-398,VisitorList.tsx:124-155 - 요청 경로의 외부 LLM/API 동기 블로킹 — AI 개선·트렌드 리포트·Buffer 발행을 요청 핸들러에서 동기 await(최대 16K 토큰 비스트리밍). 상
ai-improve.ts:68-95,posts/[id]/index.ts:109-162 - mutation마다 카테고리 전체 재집계 + 루프 UPDATE — 글 저장/상태토글 등 모든 변경이 전 테이블 재집계 트리거. 상
storage.ts:586-605 - recharts eager import → 초기 번들 비대 — 기본 뷰 대시보드가 recharts 전체(d3 의존) 동기 로드. 중
AdminDashboard.tsx:3-15 - 비가상화 + memo 부재 → 렌더 랙 — VisitorList 매 렌더 Set/sort 재계산, AdminDashboard map 45곳 vs memo 4개, 15초 heartbeat가 거대 컴포넌트 전체 리렌더. 중
VisitorList.tsx:134-155,AdminDashboard.tsx - 집계 캐싱 누락 + 무한 폴링 — funnel/analytics/queue-status 등은 매 요청 재계산, heartbeat 15s·auth 5m 폴링이 탭 비활성에도 지속. 중
funnel.ts:77-85,AdminDashboard.tsx:523-544
2. 프론트엔드 성능
어드민은 단일 URL /admin(SSR) + 인증 후 클라 상태로 뷰 전환되는 SPA. 컴포넌트 29파일 12,398 LOC, 최대 HeatmapView.tsx 2,042 LOC.
번들 / 코드 크기
F1. AdminDashboard가 recharts를 eager import 상
기본 뷰가 대시보드인데 recharts 전체(AreaChart/BarChart/ResponsiveContainer, d3 의존)를 동기 import → 인증 직후 초기 JS 청크 비대, TTI 지연.
AdminDashboard.tsx:3-15 · index.tsx:10
→ 차트 wrapper를 next/dynamic({ssr:false})로 분리하거나 recharts v3로 교체(트리셰이킹 개선). React 19면 React.lazy+Suspense.
F2. AnalyticsOverview만 dynamic import 누락 중
8개 무거운 뷰는 이미 dynamic인데 analytics 트리(6개 서브차트)만 정적 import → 대시보드만 보는 사용자도 전체 번들 부담.
index.tsx:11 · analytics/AnalyticsOverview.tsx:21-26
→ 나머지처럼 dynamic(..., {ssr:false})로 통일.
F3. CommandPalette가 레이아웃에 항상 로드 하 · F4 긍정: 8개 뷰는 이미 dynamic 처리됨 ✔
⌘K 트리거 전까지 지연 로드 가능. 한편 HeatmapView·SupportBot 등 가장 무거운 뷰가 이미 lazy인 점은 적절.
AdminLayout.tsx:20 · index.tsx:17-55
데이터 패칭 워터폴 / 폴링
F5. 마운트 시 5개 API 동시 발사 + 캐시 불일치 상
overview(useQuery) + sections + plan-diagnosis + marketing-events + heartbeat 5개 동시. 4개는 raw fetch+useState라 dedup·캐시 없음 → 뷰 재진입마다 재요청, 무거운 집계 API에 burst.
AdminDashboard.tsx:288-300, 440, 492, 508, 527 (파일 내 fetch 20회)
→ 전부 useQuery로 이관(staleTime·자동 dedup). 가능하면 서버에서 합쳐 1요청으로 축소.
F6. 전역 QueryClient defaultOptions 미설정 중
new QueryClient()가 옵션 없이 생성 → 누락 쿼리는 staleTime=0(매번 stale)·focus refetch on.
_app.tsx:98
→ defaultOptions:{queries:{staleTime:60_000, gcTime:300_000, refetchOnWindowFocus:false}}
F7. heartbeat 15초 폴링 (visibility 가드 없음) 중
탭이 백그라운드여도 15초마다 polling 지속, 모달 토글마다 인터벌 재생성.
AdminDashboard.tsx:523-544
→ document.visibilityState 가드 또는 SSE 전환(프로젝트에 SSE 패턴 존재). 최소 refetchInterval useQuery로 통합.
F9. 모달 오픈 시 중첩 fetch 체인(일부 순차 await) 중
방문자/전환 모달에서 이미 받은 데이터를 재fetch, 일부 순차.
AdminDashboard.tsx:1082-1332
→ useQuery(enabled:isOpen) 캐시·dedup, 마운트 데이터 재사용.
렌더링 · SSR
F10. VisitorList 전량 fetch + 비가상화 + 매 렌더 재계산 상
기간 내 전체 방문자를 한 번에 받아 클라에서 filter→50개씩 slice. filtered/options를 useMemo 없이 매 렌더 재계산(Set 생성·정렬·전체 순회). 가상화 라이브러리 프로젝트 전체 부재.
VisitorList.tsx:124, 134, 151-155
→ keyset cursor 서버 페이지네이션 + useInfiniteQuery + IntersectionObserver(=CLAUDE.md 대규모 조회 패턴), @tanstack/react-virtual 도입, options useMemo.
F12. AdminDashboard memo 커버리지 부족 중
map 45곳 vs memo 4개. state 30+개 집중, 15초 heartbeat setState가 차트 포함 전체 리렌더.
AdminDashboard.tsx:305-397
→ 차트/리스트 섹션 분리 후 React.memo, 고빈도 state 하위 격리.
F13 / F14. SSR 게이트 직렬 인증 왕복 — 어드민에 SSR 자체가 불필요 상
매 요청 getServerSideProps에서 getUser()→cms_users 직렬 await로 TTFB가 인증에 묶임. 어드민은 SEO 불필요·데이터 전부 CSR이라 SSR 이점 0.
admin/index.tsx:113-148
→ 정적 셸 + 클라 인증 게이트로 전환, IP 제한은 middleware.ts/엣지로 이전 → Supabase 왕복 제거, 셸 즉시 응답.
3. 백엔드 · DB 쿼리분석
핸들러 본문 + supabase/migrations 인덱스 정의를 직접 대조. DB는 자체호스팅 Supabase/Postgres(단일 supabaseAdmin 클라이언트).
supabase.ts:20). ② 캐시 인프라(analytics_cache+getCacheShared+RPC)는 우수하나 overview/sections/visitors만 적용, 나머지 analytics 핸들러는 미적용. ③ 다수 핸들러가 “전량 fetch → JS 집계” 패턴.
3.1 최우선 쿼리 병목 (영향도 상)
| ID | 증상 | 근거(file:line) | 권장 |
|---|---|---|---|
| N1.1 | getPosts() blog_posts 전체 select("*") 무제한 + JS 정렬·검색·페이징. analytics/posts/queue-status/seo-audit 공유 | blog/storage.ts:393-398, 401-432 | WHERE/ORDER BY/keyset를 DB 위임, 목록은 content 제외, 검색 trgm GIN |
| N1.2 | page_analytics를 limit 없이 select → Supabase 기본 1000행 silent 절단 (성능+정확성 동시 버그: 전환율·퍼널 부정확) | admin/ai/analyze.ts:26-29, 117-121, 269-272 | 집계를 SQL/RPC로 이관(행 fetch 불필요). getHours() TZ 버그도 동반 |
| N1.3 | fetchAllPages가 OFFSET로 최대 5만 row 적재 후 JS filter/reduce. heatmap/page-metrics/day-detail/events/plan-diagnosis 의존 대시보드 주범 | admin/analytics/_shared.ts:254-289 | 잔여 핸들러 전부 RPC 이관, 행 필요 시 keyset cursor |
| N1.4 | heatmap 7개 OFFSET 풀fetch 동시 + JS 그리드 집계, L2 캐시 없음 | analytics/heatmap.ts:347-368, 451-708 | 단일 RPC(width_bucket+GROUP BY)로 버킷팅, getCacheShared 적용 |
| N1.5 | page-metrics/day-detail 전기간 fetchAllPages + JS 다중패스, 캐싱 없음 | page-metrics.ts:49-259 · day-detail.ts:128-309 | RPC GROUP BY. day-detail 과거날짜 불변→긴 TTL |
| N1.6 | 모든 post mutation마다 전 테이블 재집계 + 카테고리별 루프 UPDATE (무관 수정도 트리거) | blog/storage.ts:586-605 | category/status 변경 시에만, UPDATE...SELECT count 단일 SQL 또는 트리거 |
| N1.7 | queue-status 전 posts+채널매핑 로드 후 채널수×글수 JS filter (위젯 폴링 핫패스) | cms/queue-status.ts:43-76 | 채널×상태 DB GROUP BY + Redis 단기 캐시 |
| N1.8 | utm/stats 기간 내 utm_visits 전량 fetch 후 JS 집계 + count:exact | cms/utm/stats.ts:35-138 | DB GROUP BY+date_trunc RPC, 상위 N만, 5분 캐시 |
3.2 요청 경로의 외부 LLM/API 동기 블로킹
| 핸들러 | 근거 | 외부호출 | 영향 |
|---|---|---|---|
| ai-improve | cms/ai-improve.ts:68-95 (16K토큰 비스트리밍) | Anthropic | 상 |
| trends/report | cms/trends/report.ts:118-122 (maxDuration 120s) | Anthropic | 상 |
| utm/insights/refresh | cms/utm/insights/refresh.ts:33-35 (+전량 fetch) | Anthropic | 상 |
| posts/[id] 발행 | cms/posts/[id]/index.ts:109-162 (for-loop await) | Buffer 순차 | 상 |
| persona | admin/analytics/persona.ts:96-115 (캐시 없음, 구버전 모델ID) | Claude | 중 |
| 썸네일/인라인 생성 | cms/generate-thumbnail.ts:14-67 등 | Gemini | 중 |
| git-log | admin/git-log.ts:21-24 execSync (이벤트루프 블록) | — | 하 |
→ 모두 BullMQ/waitUntil 큐화 + 202 즉시 반환 + SSE/폴링 진행률. (schedule-generate·ai-generate는 이미 큐 모범패턴.)
3.3 OFFSET + count:exact 페이지네이션 (CLAUDE.md 위반)
대상: media/list.ts, utm/visits.ts, audit-log.ts, trends/index.ts, admin/analytics/events.ts, support-chat-conversations, post-counts.ts(7× count head). → (created_at, id) keyset cursor, count→estimated, post-counts는 단일 GROUP BY status.
3.4 인덱스 갭 (핸들러 쿼리 vs 마이그레이션 정의 대조)
| 테이블 | 누락 인덱스 | 쿼리 근거 |
|---|---|---|
| utm_visits | created_at(기간·정렬), source/medium/campaign 복합, search 4컬럼 GIN trgm | utm/stats.ts, utm/visits.ts (content/keyword idx만 존재) |
| support_chat_conversations / messages | 테이블·인덱스 정의가 마이그레이션에 전무(런타임/외부 생성 추정) | admin/support-chat-conversations/* |
| cms_media | filename/created_at, 테이블 정의 마이그레이션 없음 | media/list.ts |
| blog_posts | title/content 검색용 trgm GIN (category/status/slug/published_at은 있음) | posts.ts JS substring 검색 |
| cms_audit_log.action | prefix like용 text_pattern_ops | audit-log.ts:74 |
RLS는 병목 아님 — service_role(supabaseAdmin)은 RLS 우회. page_analytics(053)·trend_items(042)·click_heatmap 등은 인덱스 양호.
3.35.240.227:8788)에 직접 접속 시도했으나 외부 IP 화이트리스트로 차단(ETIMEDOUT)되어 불가. 위 분석은 핸들러 코드 + 마이그레이션 SQL 정적 대조 기반이다. 실측이 필요하면 화이트리스트 IP나 SSH 터널 경유로 EXPLAIN (ANALYZE, BUFFERS) 재실행 권장.
4. 환경변수 · 설정 감사
.env.local 27개 변수. 시크릿의 NEXT_PUBLIC 유출 없음, .env.local git 추적 안전(check-ignore 확인).
| 변수 | 범주 | 용도 | 사용 | 클라노출 |
|---|---|---|---|---|
| ANTHROPIC / GEMINI _API_KEY | AI | Claude·Gemini | ✅ | ✕ |
| OPENAI_API_KEY | AI | 번역도구(tools/) | ⚠️ orphan | ✕ |
| DATABASE_URL / DIRECT_DATABASE_URL | DB | Postgres pooled/direct | ✅ | ✕ |
| SUPABASE_SERVICE_ROLE_KEY | DB/Auth | 관리자(서버전용) | ✅ | ✕ |
| NEXT_PUBLIC_SUPABASE_URL / _ANON_KEY | 공개 | Supabase 클라(정상 공개) | ✅ | ✅ |
| FIREBASE_PROJECT_ID / CLIENT_EMAIL / PRIVATE_KEY | Auth | Firebase admin | ✅ | ✕ |
| CMS_AUTH_SECRET / CRON_SECRET / RECAPTCHA_SECRET_KEY | Auth | CMS·cron·reCAPTCHA | ✅ | ✕ |
| CMS_LICENSE_KEY | 외부API | CMS 라이선스 | ⚠️ orphan | ✕ |
| BUFFER / PEXELS / PIXABAY / UNSPLASH / YOUTUBE _KEY | 외부API | SNS·이미지·영상 | ✅ | ✕ |
| NEXT_PUBLIC_GA_ID / GTM_ID / OTEL / PRICING_API_URL / SITE_URL | Analytics·공개 | 측정·URL | ✅ | ✅ |
| VERCEL_OIDC_TOKEN | 인프라 | Vercel CLI 자동생성 | ⚠️ auto | ✕ |
설정 관찰
- 중
NODE_ENV=production이 로컬.env.local에 박힘 → dev 빌드 동작 오염 위험. 검토 권장. - 중
next.config.images.remotePatternshostname**전면 개방(http+https 전체) → 외부 이미지 임의 프록시(SSRF성 리스크·비용). 도메인 화이트리스트로 축소. - 중 CSP가 Report-Only(미차단) +
unsafe-inline/unsafe-eval허용 → enforce 전환 시 XSS 방어 약함. HSTS 헤더 부재. - 하 성능 옵션 누락:
compiler.removeConsole,experimental.optimizePackageImports미설정.target:ES2017(→ES2022 권장). - 하
vercel.jsoncrons 15개 중 다수* * * * *(매분) → 함수 호출비·콜드스타트 고려. - 정보 코드 사용하나
.env.local누락(배포 환경에만 존재):SLACK_*,LANDING_API_KEY,ADMIN_ALLOWED_IPS,REDDIT_*등 → 로컬에서 해당 기능 호출 시 실패 가능.
4S. 슬랙(Slack) 연동 구성
두 개의 독립 서브시스템이 공존한다 — (A) Hermes/Threads 봇(bot token + 서명검증 + 모달·홈·버튼, 풀 인터랙티브) / (B) Incoming Webhook 알림(리드·문의·CMS 단방향 통보, 서명검증·봇토큰 없음).
구성 요약
| 엔드포인트 / 모듈 | 방향 | 용도 | 트리거 · 대상 |
|---|---|---|---|
api/slack-command.ts | In | 슬래시 /threads → 작성 모달 open | trigger_id→views.open, 빈 200 ack |
api/slack-interaction.ts | In+Out | 단축키·모달제출·버튼 처리 | shortcut / view_submission / block_actions |
api/slack-events.ts | In | url_verification, App Home 열림 | app_home_opened→publishHome (waitUntil) |
lib/hermes/slack-bot.ts | Out | bot token API: postMessage·views.open·views.publish | SLACK_BOT_TOKEN |
lib/hermes/slack-verify.ts | 검증 | HMAC-SHA256 서명 + 5분 replay 차단 | A 그룹 3개 엔드포인트 전용 |
lib/cms/slack.ts (notifySlack) | Out | CMS webhook (발행·트렌드·cron 알림, prod-only) | SLACK_CMS_WEBHOOK_URL |
contact / preview / pack / community / financial | Out | 리드·문의·상담 신청 알림 (+ claim 버튼) | SLACK_WEBHOOK_URL |
chatbot-inquiry-slack.ts | Out | 챗봇 문의 알림 + claim, 3회 재시도 | webhook |
api/cron/threads-monitor.ts | Out | Threads mock run 모니터 결과 게시 | CRON_SECRET 인증 |
Inbound 버튼 액션: threads_recheck/stop(모니터 재확인·종료), threads_publish(mock 발행, waitUntil), threads_home_new/refresh, claim_inquiry(문의 담당자 지정 — 버튼 블록을 “제가 담당할게요” 텍스트로 교체).
시크릿
| 시크릿 | 종류 | 검증/인증 | 사용처 |
|---|---|---|---|
| SLACK_BOT_TOKEN | Bot OAuth | Bearer | Hermes 봇(메시지·모달·홈) |
| SLACK_SIGNING_SECRET | 서명 검증키 | HMAC — fail-open | A 그룹 inbound 검증 |
| SLACK_WEBHOOK_URL | Incoming Webhook | 없음(outbound) | 리드·문의·상담 채널 |
| SLACK_CMS_WEBHOOK_URL | Incoming Webhook | 없음(outbound) | CMS 발행·트렌드·cron |
| HERMES_THREADS_SLACK_CHANNEL | 채널 ID | — | 기본 C0B85Q2ULSJ, 4개 파일 하드코딩 중복 |
성능 · 보안 관찰
- 양호 3초 ack 룰 준수(Hermes) — LLM 생성·발행·홈 publish 등 무거운 작업은
waitUntil()로 ack 이후 비동기 실행. (BullMQ는 없고 VercelwaitUntil사용) - 중 Webhook 알림이 사용자 요청 경로에서 동기 블로킹 —
contact.ts:452·chatbot-inquiry.ts:46이 Slack 전송을 응답 전await. chatbot은 최대 3회 지수백오프까지 동기 대기 → 워스트 ~900ms+ 사용자 지연 누적. →waitUntil/큐로 분리 권장. - 중 서명 검증 fail-open —
SLACK_SIGNING_SECRET미설정 시 검증이{ok:true}반환(slack-verify.ts:34). 미설정이면 위조 요청으로 모달·봇·홈 publish 트리거 가능. 이 정적 게이트가 유일 방어선이므로 env 설정 필수. - 하 잔여물 —
cms/test-slack.ts에 “확인 후 삭제할 것” 주석이 남은 채 프로덕션에 실제 알림 발송 가능(CMS_AUTH 보호). 채널 ID 하드코딩 4곳은 SSOT 위반 → env 단일화.
5. 의존성 최신버전 조사
pnpm@9.12.2 / Node ≥22. transitive 취약점은 overrides로 이미 핀 고정됨. major 갭 + 어드민 성능 ROI 중심.
| 패키지 | 현재 | 최신 | 이점 / 비고 | 우선 |
|---|---|---|---|---|
| recharts | 2.15.4 | 3.8.1 | v3 렌더성능·트리셰이킹 개선. 어드민 차트 핵심, 사용처 2곳뿐이라 범위 좁음 | 상 |
| sanitize-html | 2.17.3 | 2.17.5 | XSS 패치 — 즉시 적용 | 상 |
| dompurify | 3.4.2 | 3.4.11 | XSS 패치. sanitize-html과 중복 사용 → 통일 검토 | 상 |
| @supabase/supabase-js | 2.98.0 | 2.108.2 | 버그픽스·타입 minor | 중 |
| @google/genai | 1.46.0 | 2.8.0 | v2 major, Gemini 최신 모델 | 중 |
| @anthropic-ai/sdk | 0.81.0 | 0.105.0 | 신규 모델/툴 API (0.x minor=breaking 주의) | 중 |
| firebase-admin | 13.6.0 | 14.0.0 | v14 보안·SDK 갱신 | 중 |
| @types/node | 20.x | 25.x | 런타임 Node22인데 타입 20 → 22로 정합 | 중 |
| tailwindcss | 3.4.6 | 4.3.1 | v4 Oxide 빌드 10×, CSS-first(큰 마이그레이션, tailwind-merge v3·framer v12 동반) | 중 |
| next | 15.5.15 | 16.2.9 | Turbopack prod 안정화·빌드속도. 단 v16 legacy i18n 제거 → Pages+내장 i18n 구조라 마이그레이션 부담 | 하 |
| typescript | 5.9.3 | 6.0.3 | v6 major, 급하지 않음 | 하 |
Next 15.5 + React 19 — 적용 가능한 2026 패턴
- ROI 상 Turbopack dev(
next dev --turbo) 즉시 도입(저위험 HMR 가속) · recharts v3 · next/imageremotePatterns축소 + LCPpriority· GTM을@next/third-parties/google로 이전(메인스레드 부하↓). - 제약 RSC / PPR / Server Actions는 불가 — Pages Router + 내장
i18n이라 App Router 전환(next-intl 등 대공사) 없이는 미지원. - 기보유 dynamic import(어드민 9개)·ISR(홈)·TanStack Query·next/image(61파일, avif/webp)는 이미 적용 중.
6. 실행 플랜 (WSJF 우선순위)
Phase 1 — 즉시 (저비용·고효과, 어드민 체감 직결)
- 잔여 analytics 핸들러(heatmap·page-metrics·day-detail·funnel)를 기존 RPC +
getCacheShared패턴으로 이관 —fetchAllPages제거. 대시보드 3–5s → 수백 ms - 대시보드 마운트 raw fetch 4종 →
useQuery+ 전역QueryClient.defaultOptions(staleTime 60s, focus off). F5·F6 admin/ai/analyze.ts1000행 절단 버그 수정(집계 RPC화) — 정확성+성능. N1.2- recharts/AnalyticsOverview dynamic import + recharts v3, heartbeat visibility 가드. F1·F2·F7
- sanitize-html·dompurify 보안 patch. 즉시
Phase 2 — 구조 개선
getPosts()select("*")제거 + keyset cursor, VisitorList 서버 페이지네이션 +useInfiniteQuery+ 가상화. N1.1·F10- 요청 경로 외부 LLM/Buffer 동기호출 → BullMQ 큐화 + 202 + SSE 진행률. §3.2
updateCategoryCounts증분 갱신/트리거화. N1.6- 어드민 SSR 게이트 제거 → 정적 셸 + 미들웨어 인증. F13·F14
- 누락 인덱스 추가(utm_visits.created_at·trgm, blog_posts trgm, audit_log text_pattern_ops). §3.4
Phase 3 — 인프라/장기
- OLTP / analytics DB 분리(readonly role, work_mem 256MB) — 무거운 집계 격리.
- CSP enforce 전환·HSTS·
remotePatterns화이트리스트. - tailwind v4 / next 16 (i18n 마이그레이션 동반, 별도 트랙).
부록 — 분석 방법
- 대상 커밋 rinda-landing
alpha(HEADc3eb0d3f), 2026-06-19 pull 최신. - 방법 4개 서브에이전트 병렬 정적분석(FE 성능 / 백엔드·DB / env·config / 의존성) +
supabase/migrations인덱스 정의 직접 대조 + 의존성 최신버전npm view조회. - 라이브 쿼리분석 시도했으나 DB IP 화이트리스트로 외부 접속 차단(ETIMEDOUT) → 정적 대조로 대체. EXPLAIN 실측은 화이트리스트/SSH 터널 필요.
- 근거 표기 모든 발견은
file:line원본 코드 위치 동반.