AppHub 프로젝트 구조 재설계

몇 달 전 시작했다가 멈췄던 AppHub 프로젝트를 처음부터 다시 시작한다. docs만 남기고 전체 초기화 후, 5개의 Docker 컨테이너(Traefik, PostgreSQL+pgvector, Redis, ai-service, web)와 Bun 기반 Monorepo 구조로 재구성. Python은 uv, TypeScript는 Bun을 사용하며, LangGraph 기반 블로그 검색 기능을 ai-service에 통합하는 방식으로 설계했다.

프로젝트 구조 한눈에 보기

Docker 컨테이너 (총 5개)

services:
  traefik       # 리버스 프록시 (포트 80, 443, 8080)
  postgres      # PostgreSQL 16 + pgvector (포트 5432)
  redis         # 캐시 & 세션 (포트 6379)
  ai-service    # Python LangGraph (포트 8000)
  web           # Next.js 15 (포트 3000)

디렉토리 구조

apphub/
├── apps/
│   ├── web/              # Next.js 15 + React 19 (TypeScript)
│   └── ai-service/       # Python LangGraph + FastAPI
├── packages/
│   ├── ui/               # ShadCN 공통 컴포넌트
│   ├── database/         # SQL 스키마 정의
│   ├── eslint-config/    # ESLint 공유 설정
│   └── typescript-config/ # TypeScript 공유 설정
├── docker/
│   ├── compose.yaml      # Docker Compose 설정
│   └── configs/          # 서비스별 설정 파일
└── docs/                 # 기획 문서

기술 스택

컴포넌트기술
FrontendNext.js 15 + React 19 + Bun
BackendPython 3.11 + LangGraph + uv
DatabasePostgreSQL 16 + pgvector
CacheRedis 7
ProxyTraefik v2
MonorepoTurborepo + Bun workspaces

개발 환경

# Docker로 인프라 실행
docker compose up -d postgres redis traefik
 
# 앱은 로컬에서 실행
cd apps/web && bun dev                      # localhost:3000
cd apps/ai-service && uv run langgraph dev  # localhost:8000
 
# 또는 전체 Docker로 실행
docker compose up -d  # 전체 스택

데이터 흐름

User → Traefik
         ↓
    ┌────┴────┐
    ↓         ↓
   web    ai-service
    ↓         ↓
    └─→ PostgreSQL ←┘
         ↓
      pgvector (블로그 검색)

프로젝트 현황

기존 상태

  • 기획 문서만 업데이트된 상태
  • 이전 코드는 pnpm 기반 (문서와 불일치)
  • 프로젝트 구조가 명확하지 않음

결정: 전체 초기화

docs 폴더만 남기고 전부 삭제하고 다시 시작하기로 결정.

이유:

  • 기획이 크게 바뀜 (Bun, 최신 기술 스택)
  • 깔끔한 시작이 더 빠름
  • 명확한 구조로 재설계

Docker 컨테이너 설계

필요한 컨테이너 (총 5개)

services:
  traefik       # 리버스 프록시 (80, 443, 8080)
  postgres      # PostgreSQL 16 + pgvector (5432)
  redis         # 캐시 & 세션 (6379)
  ai-service    # Python LangGraph (8000)
  web           # Next.js 15 (3000)

컨테이너별 역할

traefik

  • Nginx 대신 선택 (자동 SSL, Docker 통합)
  • 라우팅: / → web, /api → ai-service
  • 대시보드: localhost:8080

postgres

  • PostgreSQL 16 + pgvector 확장
  • 블로그 포스트 메타데이터
  • 벡터 임베딩 저장 (RAG용)

redis

  • 세션 관리 (better-auth)
  • API 응답 캐싱
  • LangGraph 체크포인트

ai-service

  • Python + LangGraph + FastAPI
  • 블로그 검색 기능 내장
  • OpenAI API 호출

web

  • Next.js 15 + React 19
  • ShadCN UI
  • AI 챗봇 UI

프로젝트 디렉토리 구조

apphub/
├── apps/
│   ├── web/              # Next.js 웹 앱
│   └── ai-service/       # Python AI 서비스
│
├── packages/
│   ├── ui/               # 공통 UI 컴포넌트
│   ├── database/         # SQL 스키마
│   ├── eslint-config/    # ESLint 설정
│   └── typescript-config/ # TS 설정
│
├── docker/
│   ├── compose.yaml      # Docker Compose
│   └── configs/          # 설정 파일들
│
└── docs/                 # 기획 문서 & 개발 로그

구조 설계 원칙

1. Monorepo (Turborepo)

  • apps: 독립 실행 가능한 애플리케이션
  • packages: 공유 코드/설정

2. 명확한 분리

  • Frontend (web) ↔ Backend (ai-service)
  • TypeScript ↔ Python
  • 각자 독립적으로 개발 가능

3. 공유 최소화

  • database만 SQL 스키마 공유
  • 나머지는 각 앱에서 관리

기술 스택 최종 확정

레이어기술이유
패키지 매니저Bun최신 기술 경험 + 속도
MonorepoTurborepoNext.js 팀 제작
FrontendNext.js 15 + React 19최신 안정 버전
BackendPython 3.11 + uvAI 생태계 + 빠른 패키지
AI FrameworkLangGraph Platform세밀한 제어 가능
DatabasePostgreSQL 16pgvector 지원
ProxyTraefik자동화, 간편함

개발 환경 구성

Python (ai-service)

# uv로 패키지 관리
uv sync
 
# LangGraph Platform으로 실행
uv run langgraph dev

TypeScript (web)

# Bun으로 패키지 관리
bun install
 
# Next.js 개발 서버
bun dev

Docker (전체 스택)

# 전체 실행
docker compose up -d
 
# 로그 확인
docker compose logs -f

데이터 흐름 설계

User Request
    ↓
Traefik (Reverse Proxy)
    ↓
┌───────────┬─────────────┐
↓           ↓             ↓
web     ai-service    Traefik Dashboard
(3000)     (8000)         (8080)
    ↓           ↓
    └─→ PostgreSQL ←┘
         (5432)
            ↓
        pgvector
    (블로그 검색)

블로그 검색 아키텍처 결정

고민: MCP 분리 vs ai-service 통합

MCP 서버로 분리

  • ✅ Claude Desktop/Cursor에서 재사용 가능
  • ❌ 복잡도 증가, 개발 시간 증가

ai-service에 통합

  • ✅ 단순함, 빠른 개발
  • ✅ 직접 함수 호출 (낮은 오버헤드)
  • ❌ 외부에서 재사용 불가

결정: 통합

이유:

  1. 빠른 MVP 검증이 우선
  2. 나중에 필요하면 분리 쉬움
  3. YAGNI 원칙 (You Aren’t Gonna Need It)

블로그 검색 기능 설계

LangGraph Tools (ai-service 내장)

# src/tools/blog_search.py
 
@tool
async def search_blog_by_meaning(query: str, limit: int = 5):
    """의미 기반 벡터 검색"""
    pass
 
@tool
async def search_blog_by_keyword(keywords: str):
    """키워드 전문 검색"""
    pass
 
@tool
async def search_blog_by_tags(tags: list[str]):
    """태그 필터링"""
    pass
 
@tool
async def get_recent_posts(limit: int = 10):
    """최신 글 목록"""
    pass

데이터베이스 스키마

-- blog_posts: 메타데이터
CREATE TABLE blog_posts (
  id SERIAL PRIMARY KEY,
  slug VARCHAR(255) UNIQUE,
  title TEXT,
  content TEXT,
  published_at DATE,
  tags TEXT[],
  url TEXT,
  search_vector TSVECTOR  -- 전문 검색용
);
 
-- blog_embeddings: 벡터 검색용
CREATE TABLE blog_embeddings (
  id SERIAL PRIMARY KEY,
  post_id INTEGER REFERENCES blog_posts(id),
  chunk_text TEXT,
  embedding VECTOR(1536)  -- OpenAI embedding
);

다음 단계

  1. ✅ 프로젝트 구조 설계 완료
  2. ⏭️ Bun + Turborepo 초기화
  3. ⏭️ Next.js 15 프로젝트 생성
  4. ⏭️ Python + uv + LangGraph 설정
  5. ⏭️ Docker Compose 작성
  6. ⏭️ PostgreSQL 스키마 생성
  7. ⏭️ 기본 개발 환경 테스트

회고

잘한 점

  • 기획 먼저 확실히 정리
  • 처음부터 다시 시작하는 용기
  • 명확한 구조 설계

배운 점

  • 기술 선택에 일관성 중요 (Bun vs pnpm)
  • 복잡도보다 속도 (MCP 분리 → 통합)
  • docs 남기는 습관 (나중에 큰 도움)

다음 목표

프로젝트 초기화 후 1주일 안에 기본 챗봇 동작까지 완성하기!


개발 철학

“완벽한 계획보다 동작하는 코드가 먼저다. 하지만 명확한 구조 없이 시작하면 나중에 더 고생한다.”

관련 문서