Files
jaengseung-made/docs/superpowers/specs/2026-06-02-nas-selfhost-migration-design.md

6.8 KiB

쟁승메이드 NAS 풀 self-host 전환 — 설계 (Spec)

상태: 설계 합의 완료 (2026-06-02). 다음 단계 = 단계별 마이그레이션 계획(writing-plans). 목표: Vercel + Supabase(클라우드) + GitHub public → NAS 자체 호스팅 + self-host Supabase 스택 + 개인 Gitea(비공개) 로 전환.


1. 배경 & 동기

  • 결정 동기 (박재오, 2026-06-02): ① 데이터 주권·통합 운영(사주 등 민감 데이터를 내 NAS에 보관, 기존 NAS 서비스들과 한곳에서 관리), ② 벤더 종속 회피(Vercel/Supabase 정책·가격·계정정지 리스크 탈피). 비용 절감·학습은 부차.
  • 접근 확정: A. 풀 self-host — Supabase 스택을 통째로 NAS에 올려 코드 변경을 최소화. (대안 B 슬림 self-host=Auth 전면 재작성 비용 과다, C 하이브리드=구조적으로 어정쩡 → 모두 기각.)
  • 핵심 통찰: Gitea 이전과 NAS self-host는 한 묶음 — Vercel은 Gitea 자동배포를 지원하지 않으므로 Gitea 이전 시 self-host가 자연 귀결.

2. 현재 결합도 (이전 비용 분석)

의존 결합도 비고
Supabase Auth 매우 높음 이메일+OAuth 로그인, 세션 미들웨어(utils/supabase/middleware.ts), 13개 API가 auth.getUser(), RLS가 auth.uid() 기반
Supabase DB(Postgres)+RLS 높음 전 기능 의존, Postgres 자체는 이식 가능
Supabase Storage 중간 pack-files 서명 URL (/api/packs/sign-link, list-mine, lib/supabase/pack-files.ts)
Vercel 낮음 전 route runtime='nodejs'next start self-host 가능. maxDuration=60app/api/saju/analyze 1곳(Vercel 전용)
Gemini·Portone·Resend 없음 외부 API — 호스팅 위치 무관

풀 self-host(A)의 핵심 이점: supabase-js의 endpoint(URL)와 키만 self-host로 교체하면 Auth·RLS·storage 코드가 거의 그대로 동작.

3. 목표 아키텍처 (NAS docker-compose)

[인터넷] → DDNS(gahusb.synology.me → jaengseung-made.com)
   → 포트포워딩 443 → nginx (기존, SSL 종단 · Let's Encrypt)
        ├─ / , /api/*           → next-app (next start, output: standalone)
        └─ /auth /rest /storage → supabase-kong (게이트웨이)
             ├─ gotrue        (Auth: 이메일 + Google OAuth)
             ├─ postgrest     (supabase-js REST 대상)
             ├─ storage-api   (pack-files)
             └─ postgres      (전용 인스턴스 — 기존 NAS 서비스 DB와 분리)
  • 격리: 기존 NAS 스택(redis·lotto·stock·music-lab 등 15+ 컨테이너)과 별도 compose 프로젝트. Postgres는 전용 컨테이너로 기존 서비스 DB와 분리.
  • 리소스: NAS RAM 18,432MB(18GB) 확보됨 → 메모리 차단요소 해소. CPU(Celeron J4025 2코어)·디스크·동시 부하는 Phase 0에서 실측.

4. 컴포넌트 설계

4.1 코드 변경 (최소)

  • .env: NEXT_PUBLIC_SUPABASE_URL → NAS 도메인, ANON_KEY/SERVICE_ROLE_KEY → self-host 발급 JWT 키로 교체.
  • next.config.ts: output: 'standalone' 추가, 빌드에 sharp(next/image) 포함.
  • maxDuration=60 제거(self-host에선 무의미 — Node 프로세스가 직접 처리).
  • 그 외 앱 로직(supabase-js 호출, RLS 의존 코드)은 무수정 목표.

4.2 데이터 마이그레이션

  • pg_dump(Supabase 클라우드 전체: auth 스키마 + public 테이블 + RLS 정책 + storage 메타) → NAS Postgres restore.
  • Storage 객체(pack-files 실파일) 복사.
  • 검증: 테이블별 행수 대조, 로그인/세션/RLS 동작, 서명 URL 다운로드, 결제·구독 흐름.

4.3 Auth (GoTrue)

  • Google OAuth: redirect URL에 NAS 도메인 추가, 세션 쿠키 도메인 정렬.
  • GoTrue 메일 발송: 기존 Resend를 SMTP 자격증명으로 연결(또는 이메일 확인 비활성 정책 — Phase에서 택1).
  • JWT secret 자체 발급 → anon/service_role 키 재생성.

4.4 배포 파이프라인 (GitHub public → Gitea)

  • 코드 저장소를 개인 Gitea로 이전(비공개).
  • 빌드는 로컬 PC에서 수행(NAS Celeron 빌드 금지 규칙 — workspace CLAUDE.md). standalone 산출물/도커 이미지를 NAS로 전송.
  • 배포는 기존 webpage-deployer와 분리된 별도 배포 방식 차용(이 사이트 전용 파이프라인). 구체 방식(예: 로컬 빌드→이미지 레지스트리 push→NAS pull, 또는 Gitea Actions/별도 webhook 수신기)은 계획 단계에서 확정.

4.5 네트워킹·SSL·백업

  • DNS: jaengseung-made.com → NAS 공인 IP(DDNS). 443 포워딩. Let's Encrypt 자동 갱신.
  • 백업: Postgres 일일 pg_dump cron + Storage 백업. 기본 모니터링(헬스체크).

4.6 컷오버·롤백

  • Vercel+Supabase를 병행 운영하며 NAS 스택 안정화 → 데이터 최종 동기 → DNS 전환으로 컷오버.
  • 문제 발생 시 DNS만 되돌리면 즉시 롤백. NAS 안정 확인 후 클라우드 자원 해지.

5. 선결 차단요소 & 리스크

항목 상태 대응
NAS RAM 해소 (18GB)
CPU/디스크/동시부하 🔍 Phase 0 실측 부족 시 컨테이너 리소스 제한·우선순위 조정
가용성 다운그레이드 ⚠️ 수용 공개 사이트가 가정 전기·인터넷·동적IP·단일HW·DDoS에 노출. 동기(주권)상 수용하되 백업·DNS 롤백으로 완화
GoTrue 메일/OAuth 전환 리스크 Resend SMTP 연결 + OAuth redirect 검증
self-host Supabase 운영 지속 부담 버전 업그레이드·백업 루틴 문서화

6. 결정 사항 (확정)

  1. 접근 = A. 풀 self-host.
  2. GoTrue 메일 = Resend SMTP 연결(이메일 확인 유지) 기본, 운영 복잡 시 확인 비활성 대안.
  3. 컷오버 = Vercel/Supabase 병행 후 DNS 전환, DNS 롤백.
  4. Phase 0 = NAS 리소스 실측을 첫 관문(RAM은 해소, CPU/디스크/부하 확인).
  5. 빌드 = 로컬 빌드 후 NAS 배포(Celeron 빌드 금지). 배포 파이프라인은 기존 webpage-deployer와 분리된 별도 방식(구체안 계획에서 확정).

7. 범위 밖 (Non-goals)

  • 외부 API(Gemini/Portone/Resend) 자체 대체 — 하지 않음(호스팅 위치 무관).
  • 기존 NAS 다른 서비스(lotto/stock 등) 변경 — 무관.
  • 사주 별도 도메인 분리(P5, 도메인 미구매) — 별개 트랙.

8. 다음 단계

이 spec 승인 후 writing-plans로 단계별 마이그레이션 계획 작성:

  • Phase 0 리소스 실측 → Phase 1 NAS Supabase 스택 기동 → Phase 2 데이터 이전·검증 → Phase 3 Next self-host·코드 env 전환 → Phase 4 Gitea 이전·배포 파이프라인 → Phase 5 도메인/SSL/병행→컷오버 → Phase 6 백업·운영·클라우드 해지.