Skip to content

백엔드 아키텍처

apps/api NestJS REST API 구조입니다.

기술 스택

영역기술
프레임워크NestJS 11
HTTPExpress (@nestjs/platform-express)
ORMPrisma 7 (@prisma/client)
DBPostgreSQL 17 (Docker)
인증Passport (Google OAuth 2.0, JWT)
테스트Jest + Supertest
공유 타입@repo/api workspace 패키지

진입점

apps/api/src/main.ts:

typescript
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
app.use(cookieParser());
app.enableCors({
  origin: ['http://localhost:3001'],
  credentials: true,
});
await app.listen(3000);
  • 포트: 3000
  • CORS: web 앱(http://localhost:3001)만 허용, 쿠키(credentials) 지원

모듈 구조

src/
├── main.ts
├── app.module.ts
├── prisma/
│   ├── prisma.module.ts      # @Global() PrismaService
│   └── prisma.service.ts
├── auth/
│   ├── auth.module.ts
│   ├── auth.controller.ts
│   ├── auth.service.ts
│   ├── guards/jwt-auth.guard.ts
│   └── strategies/
│       ├── google.strategy.ts
│       └── jwt.strategy.ts
├── users/
│   ├── users.module.ts
│   ├── users.controller.ts
│   ├── users.service.ts
│   └── dtos/user.dto.ts
├── workspaces/
│   ├── workspaces.module.ts
│   ├── workspaces.controller.ts
│   ├── workspaces.service.ts
│   ├── dtos/
│   └── utils/slug.ts
└── links/                    # CRUD 예제 (레거시 스캐폴딩)

Prisma

스키마: apps/api/prisma/schema.prisma
클라이언트 출력: apps/api/generated/prisma/
설정: apps/api/prisma.config.ts

데이터 모델 (요약)

워크스페이스 바로 아래에 노드가 붙는 플랫 구조입니다.

prisma
model User { ... }

model Workspace {
  id, name, slug, ownerId
  members WorkspaceMember[]
  nodes   Node[]
}

model WorkspaceMember {
  workspaceId, userId, role  // owner, admin, editor, viewer 등
}

model Node {
  id          String   @id      // 클라이언트 UUID
  workspaceId Int
  sortOrder   Int
  kind        String             // text 등
  data        Json               // CanvasNodeState 전체
}

상세 ERD는 apps/api/README.md를 참고하세요.

마이그레이션은 apps/api/prisma/migrations/에 관리됩니다.

DB 초기화 (Docker)

bash
pnpm docker:db:setup
# = prisma generate + migrate deploy

로컬(Docker 없이):

bash
cd apps/api
DATABASE_URL=postgresql://postgres:example_password@localhost:5432/mydb \
  pnpm exec prisma generate
DATABASE_URL=postgresql://postgres:example_password@localhost:5432/mydb \
  pnpm exec prisma migrate deploy

인증 흐름

  1. web /login에서 VITE_API_URL/auth/google로 이동
  2. Google OAuth 완료 후 JWT를 access_token httpOnly 쿠키로 설정
  3. 이후 API 요청은 credentials: 'include'로 쿠키 전송
  4. JwtStrategy가 쿠키에서 JWT 추출, JwtAuthGuard로 보호 엔드포인트 검증

API 엔드포인트

인증·사용자

메서드경로인증설명
GET/auth/googleGoogle OAuth 시작
GET/auth/google/callbackOAuth 콜백, 쿠키 설정 후 리다이렉트
POST/auth/logoutaccess_token 쿠키 삭제
GET/users/meJWT현재 로그인 사용자 조회

워크스페이스·노드 (JWT 필수)

메서드경로설명
POST/workspaces워크스페이스 생성 (owner 멤버십 자동 추가)
GET/workspaces내 워크스페이스 목록
GET/workspaces/:id워크스페이스 조회 (멤버만)
GET/workspaces/:id/nodes노드 문서 조회 { nodes, nodeOrder }
PUT/workspaces/:id/nodes노드 문서 동기화 (upsert + 삭제)

접근 제어

  • 워크스페이스 미존재 → 404
  • 멤버가 아님 → 403
  • syncNodesnodeOrder 순서대로 sortOrder를 갱신하고, payload에 없는 노드는 삭제합니다.

links 모듈은 NestJS 스캐폴딩 예제로 남아 있으며, DTO/엔티티 타입은 @repo/api 패키지에서 import합니다.

공유 패키지 (@repo/api)

packages/api/src/:

links/
├── dto/
│   ├── create-link.dto.ts
│   └── update-link.dto.ts
└── entities/
    └── link.entity.ts

User·Workspace DTO는 현재 apps/api/src/에 api 앱 로컬로 정의되어 있습니다.

환경 변수

변수설명
DATABASE_URLPostgreSQL 연결 문자열
NODE_ENVdevelopment / production
GOOGLE_CLIENT_IDGoogle OAuth 클라이언트 ID
GOOGLE_CLIENT_SECRETGoogle OAuth 클라이언트 시크릿
JWT_SECRETJWT 서명 시크릿

Docker dev 환경:

env
DATABASE_URL=postgresql://postgres:${DB_PASSWORD}@db:5432/mydb
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
JWT_SECRET=...

Google Cloud Console에서 OAuth 리디렉션 URI를 http://localhost:3000/auth/google/callback로 등록해야 합니다.

Docker

  • Dockerfile: apps/api/Dockerfile.dev
  • DB healthcheck 후 api 기동 (depends_on: condition: service_healthy)
  • 최초 기동 후 pnpm docker:db:setup으로 스키마 적용
  • DB 브라우징: pnpm docker:prisma:studiohttp://localhost:5555

현재 상태 & 향후 확장

구현됨

  • Google OAuth 로그인 + JWT 쿠키 세션
  • User 조회 (/users/me)
  • Workspace CRUD (목록·생성·조회)
  • Node 문서 동기화 (워크스페이스 직속, JSON data 필드)
  • WorkspaceMember 기반 접근 제어

향후

  • 초대(Invitation), 역할별 세분 권한
  • 노드 단위 PATCH / 실시간 협업(WebSocket)
  • 이미지 업로드 등 자산 API

테스트

bash
pnpm --filter api test        # unit
pnpm --filter api test:e2e    # e2e

관련 문서

Canvas — 시각적 프로토타입 에디터