SEOJing의 콘텐츠/커뮤니티 백엔드입니다. 첫 목표는 블로그 본문 MDX가 Cloudflare Worker 번들에 계속 누적되는 구조를 끊고, 글/개정/질문/댓글을 다룰 수 있는 공개 포트폴리오형 백엔드로 키우는 것입니다.
SEOJing은 지금까지 MDX 파일을 프런트엔드 Worker 번들 안으로 컴파일해 배포했습니다. 글이 늘면서 Worker gzip 업로드가 Cloudflare free-plan 3 MiB 제한 근처까지 커졌고, Day 6 study publish는 Worker exceeded the size limit of 3 MiB 오류로 보류되었습니다.
이 저장소는 MDX를 버리기 위한 저장소가 아닙니다. MDX를 authoring/import/export 형식으로 유지하되, 공개 본문 데이터와 커뮤니티 기능은 별도 백엔드가 소유하도록 분리합니다.
초기 스택은 다음처럼 잡습니다.
- Fastify + TypeScript
- PostgreSQL
- Prisma
- Zod 기반 환경 변수 검증
- OpenAPI 문서 스켈레톤
- Vitest / ESLint / TypeScript build
- Docker Compose 또는 Homebrew PostgreSQL 개발 DB
Cloudflare Worker는 seojing.com의 얇은 프런트엔드/캐시/SEO 레이어로 남기고, article body와 revision/community 데이터는 이 백엔드의 API에서 가져오는 방향으로 이동합니다.
첫 번째 성공 기준은 다음입니다.
- 기존
/blog/...URL은 유지한다. - article body를 Worker JS module로 계속 밀어 넣지 않는다.
- Worker gzip upload를 우선
<= 1800 KiB수준으로 낮출 수 있는 길을 만든다. - 이후 admin writing, block editor, GitHub OAuth comments/questions, Q&A/RAG, TTS를 같은 데이터 모델 위에 확장한다.
현재 백엔드 MVP 범위입니다.
GET /health/docsSwagger UI/openapi.jsonOpenAPI JSON- 환경 변수 스키마
- Prisma/PostgreSQL 기반 Article/Revision/Block/Asset schema
- idempotent seed article
- Homebrew PostgreSQL 기반 로컬 DB helper
- MDX ingest/render pipeline MVP
- Public Article API/cache contract
- GitHub OAuth-backed community comments/questions MVP
- Node-owned TTS and article Q&A public routes backed by the internal Python worker contract
- Node→Python internal worker contract for future TTS/Q&A/RAG
- lint/test/build/check scripts
api.seojing.com의 공개 경계는 Node/Fastify 서비스가 소유합니다. Python 구현은 TTS/Q&A/RAG 같은 장기 작업을 위한 loopback-only worker dependency이며, Cloudflare Tunnel이나 공개 reverse proxy에 직접 노출하지 않습니다.
corepack enable
pnpm install
cp .env.example .env
pnpm prisma:generate
pnpm devPostgreSQL을 함께 띄울 때:
# Homebrew postgresql@16 CLI 기반 로컬 DB를 .local/postgres-data에 띄웁니다.
pnpm db:local:start
DATABASE_URL='postgresql://seojing@localhost:5432/seojing_backend?schema=public' pnpm prisma:seed
pnpm devDB 통합 테스트까지 실행할 때:
pnpm db:local:start
DATABASE_URL='<postgres-url>' pnpm mdx:ingest --write-db --content-root ../SEOJing/apps/web/content ../SEOJing/apps/web/content/study/javascript-quizbook/day1.mdx기존 article을 갱신하면서 현재 revision까지 발행하려면 --publish를 함께 붙인다. --publish는 DB 상태를 바꾸므로 --write-db와 같이 써야 한다.
DATABASE_URL='<postgres-url>' pnpm mdx:ingest --write-db --publish --content-root ../SEOJing/apps/web/content ../SEOJing/apps/web/content/study/javascript-quizbook/day6.mdx지원 범위와 custom component 처리 정책은 docs/mdx-ingest-support.md에 정리했습니다.
Python worker contract:
# TTS/Q&A/RAG worker integration is disabled unless explicitly enabled.
PYTHON_WORKER_ENABLED=false
PYTHON_WORKER_BASE_URL=http://127.0.0.1:4037
TTS_AUDIO_ROOT=.seojing-worker/tts-audio
curl http://localhost:4000/health/readyNode→Python 내부 호출 계약과 운영 기준은 docs/python-worker-contract.md에 정리했습니다. 공개 노출 포트는 Node API만 두고 Python worker는 loopback 전용으로 둡니다.
Public API surfaces currently include:
GET /articles/:slugand related article metadata/body routesPOST /articles/:slug/qafor source-backed article Q&AGET /tts/summary,POST /tts/jobs,GET /tts/jobs/:jobId,GET /tts/audio/:jobId/community/*GitHub-authenticated comments/questions routes/docsand/openapi.json
Health check:
curl http://localhost:4000/healthOpenAPI:
open http://localhost:4000/docs
curl http://localhost:4000/openapi.jsonpnpm format:check
pnpm lint
pnpm test
pnpm build
pnpm openapi:checkMac mini 운영 라우팅은 docs/production-routing.md에 기록합니다. 현재 공개 API 경계는 https://api.seojing.com이고, 이 저장소의 launchd 서비스가 127.0.0.1:4027에서 받는 구조입니다. 기존 127.0.0.1:9101 FastAPI sidecar는 공개 API 경계가 아니며, SEOJing 공개 기능은 Node API가 소유합니다.
- Article/Revision/Block DB schema MVP
- Worker bundle size budget gate in SEOJing
- MDX ingest/render pipeline
- Public Article API and cache contract
- SEOJing frontend integration behind feature flag
- Study series migration
- Admin Writing MVP
- Block editor foundation
- GitHub OAuth comments/questions MVP