Skip to content

CaQuick/caquick-be

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

342 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CaQuick Logo

케이퀵 - CaQuick Backend

시각 기반 올인원 맞춤 케이크 주문 플랫폼

케이크 디자인 탐색 → 디자인 수정 → 가게 매칭 → 주문·결제·픽업까지
단절된 모든 과정을 하나의 시각 기반 흐름으로 통합합니다.


License Node NestJS TypeScript

CI CodeQL codecov Last commit

📑 목차

🎯 기획 배경

케이크 디자인 주문은 본질적으로 맞춤형 상품이지만, 기존 플랫폼들은 이에 최적화되어 있지 않습니다.

채널 한계
인스타그램 디자인 영감은 풍부하지만 통합된 예약·주문·결제 흐름이 없음
네이버 가게 검색·예약 기능은 있지만 디자인 카탈로그·탐색 UX가 약함
카톡·DM 이미지 첨부는 가능하지만 정형 디자인 명세 양식이 없어 매번 캡처·설명·확인을 비정형으로 주고받아야 함

사용자는 결국 여러 플랫폼을 옮겨 다니며 캡처 + 편집 + 설명을 조합하는 비효율을 감내해야 합니다.

케이퀵은 이 단절된 과정을 시각 기반 단일 흐름으로 통합하는 서비스입니다.

🧱 기술 스택

Language & Runtime

TypeScript Node.js Yarn

  • TypeScript (strict) · Node.js 24.x · Yarn 4 (Corepack)

Framework & API

NestJS GraphQL Apollo Swagger

  • NestJS 11 — Modules · DI · Guards · Interceptors
  • GraphQL (schema-first SDL) · Apollo Server 5 · @nestjs/graphql
  • Doc / codegen 툴체인: GraphQL Code Generator (TS 타입 자동생성) · SpectaQL (GraphQL HTML 문서) · Swagger (REST /rest-docs, @nestjs/swagger)

Database & ORM

MySQL Prisma

  • MySQL 8 · Prisma 6 (ORM + Migrations) · Custom soft-delete extension

Auth & Validation

OpenID JWT Passport

  • OIDC (Google · Kakao) via openid-client
  • JWT (@nestjs/jwt + Passport) · Argon2 (자격 증명 해시)
  • class-validator · class-transformer 기반 DTO 검증

Testing

Jest Testcontainers

  • Jest + Testcontainers (Docker 컨테이너로 실 MySQL 자동 spin-up) + Supertest
  • DB mock 미사용 — 실 DB 통합 테스트 (→ 테스트 섹션)

Code Quality & Security

ESLint Prettier commitlint Codecov CodeQL Dependabot

  • ESLint (strict) · Prettier · Husky + lint-staged
  • commitlint (Conventional Commits 강제) · Codecov (patch threshold 80%)
  • CodeQL (GitHub Actions 기반 SAST) · Dependabot (의존성 자동 PR · 메이저는 ignore 정책)

DevOps & Infrastructure

AWS EC2 AWS RDS AWS S3 AWS CodeDeploy

Docker Terraform GitHub Actions PM2 Discord

  • AWS: EC2 (서버) · RDS MySQL (DB) · S3 + Presigned URL (미디어) · CodeDeploy (배포 자동화)
  • Docker (compose) — 로컬 개발 + testcontainers
  • Terraform으로 GitHub repository / branch protection 관리 (IaC)
  • GitHub Actions — pr-check · deploy · CodeQL · Dependabot
  • PM2 — EC2 프로세스 매니저
  • Discord webhook — PR · push · issue 이벤트 알림
  • Winston 구조화 로그 + x-request-id 상관관계 추적

🏗️ 아키텍처

레이어 의존성

요청은 항상 단방향으로 흐릅니다. Resolver/Service가 PrismaServicePrismaClient에 직접 접근하는 것은 금지되어 있으며, 모든 DB 접근은 Repository를 경유합니다.

flowchart LR
    Client[📱 Client]
    Resolver[🧩 GraphQL Resolver<br/>I/O 조립만]
    Service[⚙️ Service<br/>비즈니스 로직]
    Repo[🗄️ Repository<br/>쿼리/트랜잭션]
    Prisma[🔷 PrismaService]
    DB[(🛢️ MySQL)]

    Client -->|GraphQL Query/Mutation| Resolver
    Resolver --> Service
    Service --> Repo
    Repo --> Prisma
    Prisma --> DB

    classDef forbidden stroke:#E0234E,stroke-dasharray:5 5
    Resolver -. "❌ 직접 접근 금지" .-> Prisma:::forbidden
    Service -. "❌ 직접 접근 금지" .-> Prisma:::forbidden
Loading

Feature 모듈 구성

도메인별로 폴더가 분리되며 (src/features/*), 각 feature는 SDL · Resolver · Service · Repository · DTO · Constants를 colocate합니다. Feature 간에는 서로의 내부 파일을 직접 import하지 않고 Module export provider로만 주입받습니다.

flowchart TB
    subgraph features["src/features"]
        Auth[🔐 auth<br/>OIDC + JWT]
        User[👤 user<br/>마이페이지 · 프로필 · 알림 · 찜 · 리뷰 · 장바구니]
        Product[🎂 product<br/>케이크 상품 · 카테고리]
        Order[📦 order<br/>주문 · 결제 · 픽업]
        Seller[🏪 seller<br/>판매자 가게]
        Conversation[💬 conversation<br/>채팅]
        System[🩺 system<br/>health check]
        Core[🧬 core<br/>도메인 공통]
    end

    subgraph shared["공유 레이어"]
        Common[🛠️ common<br/>무의존 유틸]
        Global[🌐 global<br/>S3 · GraphQL context · Guards]
        Config[⚙️ config]
        PrismaMod[🔷 prisma<br/>PrismaService + soft-delete]
    end

    features --> shared
    Global --> Common
    Global --> Config
Loading

핵심 설계 원칙

  • 의존성 방향 강제: Resolver → Service → Repository → Prisma. 역방향/우회 금지
  • Schema-First GraphQL: SDL이 단일 소스 (*.graphql 파일). 변경 시 yarn graphql:codegen으로 타입 동기화
  • Domain Model 격리: Prisma model 타입을 Resolver/Service에 직접 노출하지 않고 domain 모델/DTO로 매핑
  • Soft-delete 일관성: prisma/soft-delete.middleware.ts Extension이 모든 READ 쿼리에 deleted_at: null 자동 주입 (의도적 우회 가능)
  • Fail-fast: 운영 환경에서 JWT 시크릿 누락 시 서버 부팅 차단. GraphQL Playground 운영에서 비활성

📁 디렉터리 구조

caquick-be/
├── src/
│   ├── main.ts                  # 부트스트랩 (NestFactory)
│   ├── app.module.ts            # 루트 모듈
│   ├── features/                # 도메인 모듈 (1 폴더 = 1 도메인)
│   │   ├── auth/                #   OIDC + JWT
│   │   ├── user/                #   마이페이지 · 프로필 · 알림 · 찜 · 리뷰 ...
│   │   ├── product/             #   케이크 상품
│   │   ├── order/               #   주문 · 결제 · 픽업
│   │   ├── seller/              #   판매자 가게
│   │   ├── conversation/        #   채팅
│   │   ├── system/              #   health check
│   │   └── core/                #   도메인 공통
│   ├── common/                  # 무의존 공용 유틸 (외부 의존 X)
│   ├── global/                  # 글로벌 (S3, Guards, GraphQL context)
│   ├── config/                  # 환경별 설정 · 검증
│   ├── prisma/                  # PrismaService · soft-delete extension
│   ├── graphql/                 # codegen 출력 (autogen, 수정 금지)
│   └── test/                    # 테스트 인프라 (factories · helpers)
├── prisma/
│   ├── schema.prisma            # DB 스키마 단일 소스
│   ├── migrations/              # 마이그레이션 히스토리
│   └── seed.ts                  # 시드 스크립트
├── terraform/                   # GitHub repo 설정 IaC
├── .github/
│   ├── workflows/               # GitHub Actions
│   ├── dependabot.yml           # 의존성 자동 업데이트
│   └── assets/                  # README 등 GitHub 노출용 자산
├── scripts/                     # CodeDeploy lifecycle hooks
└── public/                      # SpectaQL HTML 문서 출력

🚀 시작하기

Prerequisites

항목 버전 비고
Node.js 24.x nvm install 24 권장
Yarn 4.x (Corepack) corepack enable 한 번 실행
MySQL 8.x 로컬 또는 Docker (docker-compose.yml 제공)
Docker latest 통합 테스트에서 testcontainers가 MySQL 컨테이너를 띄움

설치 & 실행

# 1. 의존성 설치
corepack enable
yarn install

# 2. 환경 변수 (.env 직접 생성 — 아래 "필요 환경 변수" 표 참고)
touch .env

# 3. DB 마이그레이션
yarn prisma:migrate:dev

# 4. (선택) 시드 데이터 주입
yarn prisma:seed

# 5. 개발 서버 (watch mode)
yarn start:dev

기본 GraphQL endpoint: http://localhost:4000/graphql (PORT 환경변수로 변경 가능)

필요 환경 변수

.env.example은 보안상 레포에 포함되지 않습니다. 아래 키를 참고해 .env를 직접 작성해 주세요. 정확한 검증 스키마는 src/config/ 참고.

카테고리
서버 NODE_ENV, PORT, BACKEND_BASE_URL, FRONTEND_BASE_URL
DB DATABASE_URL
JWT / Auth JWT_ACCESS_SECRET, JWT_ACCESS_EXPIRES_SECONDS, AUTH_REFRESH_EXPIRES_DAYS, AUTH_COOKIE_DOMAIN, AUTH_COOKIE_SECURE
OIDC (Google) OIDC_GOOGLE_CLIENT_ID, OIDC_GOOGLE_CLIENT_SECRET, OIDC_GOOGLE_ISSUER_URL
OIDC (Kakao) OIDC_KAKAO_CLIENT_ID, OIDC_KAKAO_CLIENT_SECRET, OIDC_KAKAO_ISSUER_URL
OIDC (공통) OIDC_TEMP_COOKIE_MAX_AGE_MS
AWS S3 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, AWS_S3_BUCKET, S3_PRESIGN_EXPIRES_SECONDS
Docs (선택) DOCS_ACCESS_TOKEN

자주 쓰는 스크립트

명령 용도
yarn start:dev NestJS watch 모드
yarn build 프로덕션 빌드 (dist/)
yarn lint ESLint --fix
yarn test Jest (실 DB 통합 테스트 포함)
yarn test:cov 커버리지 측정
yarn prisma:migrate:dev DB 마이그레이션 생성/적용
yarn prisma:studio Prisma Studio (GUI DB 브라우저)
yarn graphql:codegen SDL → TypeScript 타입 생성
yarn graphql:docs SpectaQL HTML 문서 빌드 (public/)

🧬 GraphQL

Schema-First 방식을 채택합니다. .graphql SDL 파일이 단일 소스이며, 변경 시 codegen으로 TypeScript 타입을 동기화합니다.

# src/features/user/user-profile.graphql
extend type Query {
  """현재 로그인한 유저 정보 조회"""
  me: MePayload!
}

type MePayload {
  accountId: ID!
  email: String
  accountType: AccountType!
  profile: UserProfile!
  """연동된 소셜 로그인 식별자 목록(soft-deleted 제외, 최근 로그인 순)"""
  linkedIdentities: [LinkedIdentity!]!
}
# SDL 수정 후 항상 codegen 실행
yarn graphql:codegen
  • 각 도메인은 extend type Query / extend type Mutation 패턴으로 schema를 확장
  • 생성된 타입(src/graphql/graphql.types.ts)은 자동 생성물 — 직접 수정 금지
  • 운영 환경에서 Apollo Playground는 비활성 (introspection off)

🧪 테스트

DB는 mock하지 않습니다. 모든 통합 테스트는 Testcontainers로 실제 MySQL 컨테이너를 자동 spin-up한 뒤 Prisma 마이그레이션까지 적용해 검증합니다.

왜 실DB로?

  • Prisma 쿼리/관계/제약조건 동작이 mock과 미묘하게 다를 수 있어, mock이 통과해도 운영 마이그레이션이 깨지는 케이스를 사전에 잡습니다
  • soft-delete extension이 where에 자동 주입되는 동작 등 ORM 레이어 통합 동작을 검증
  • 트랜잭션 격리, 유니크 제약, 외래 키 cascade 동작까지 실제 DB 의미론으로 확인

테스트 레이어

레이어 목적
*.service.spec.ts 단위 + 실 DB. 분기/예외/도메인 로직
*.resolver.spec.ts Resolver ↔ Service ↔ Repository ↔ DB 전체 경로 통합 (1~2 happy/error 케이스)
*.repository.spec.ts Repository 단위에서만 도달 가능한 API contract
# 전체 실행 (testcontainers가 MySQL 컨테이너를 띄움 — Docker 필요)
yarn test

# 특정 도메인만
yarn test src/features/user

# 커버리지 (patch threshold 80%)
yarn test:cov

CI에서도 동일하게 testcontainers로 격리된 MySQL을 띄우므로 로컬과 환경 차이가 거의 없습니다.

⚙️ CI / CD

워크플로우

Workflow Trigger 역할
pr-check.yml PR (develop/main) lint · typecheck · 통합 테스트 · 커버리지
codeql.yml PR · push · 주간 GitHub CodeQL SAST
discord-notify.yml PR · push · issue Discord 알림
deploy.yml 수동 (workflow_dispatch) EC2 + RDS 인프라 비활성 기간 동안 자동 배포 중단

흐름

flowchart LR
    Dev[👨‍💻 Feature Branch]
    PR[🔀 PR to develop]
    Checks{CI Checks<br/>lint · test · coverage · CodeQL}
    Develop[🌿 develop]
    Release[🔀 Release PR<br/>develop → main]
    Main[🌲 main]
    Deploy[🚀 Deploy<br/>workflow_dispatch]
    AWS[☁️ AWS CodeDeploy → EC2]

    Dev --> PR --> Checks
    Checks -->|✅ pass| Develop
    Develop --> Release --> Main
    Main -.수동 실행.-> Deploy --> AWS
Loading

브랜치 보호

  • main: PR + CI 통과 필수. 직접 push 금지
  • develop: PR + CI 통과 권장. Repository Admin은 release sync 목적으로 fast-forward 직접 push 가능
  • 필수 status check: check, pr-title, coverage-report, Analyze (javascript-typescript)
  • 브랜치 보호 / 레포 설정은 terraform/에서 IaC로 관리

👤 팀

chanwoo7
chanwoo7

Backend Developer

📜 라이선스

이 프로젝트는 Business Source License 1.1 (BUSL-1.1) 으로 배포됩니다.

  • 비상업적 / 학습 / 평가 목적의 사용은 자유롭게 허용됩니다
  • 케이크 주문 플랫폼과 경쟁하는 상업 서비스로의 이용은 별도 라이선스 협의가 필요합니다
  • Change Date(2030-05-20) 이후 Apache License 2.0으로 자동 전환됩니다

전체 조항은 LICENSE 파일을 참고하세요.

Copyright © 2026 CaQuick. All rights reserved.

About

케이퀵(CaQuick) 백엔드 레포지토리

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages