케이크 디자인 주문은 본질적으로 맞춤형 상품이지만, 기존 플랫폼들은 이에 최적화되어 있지 않습니다.
| 채널 | 한계 |
|---|---|
| 인스타그램 | 디자인 영감은 풍부하지만 통합된 예약·주문·결제 흐름이 없음 |
| 네이버 | 가게 검색·예약 기능은 있지만 디자인 카탈로그·탐색 UX가 약함 |
| 카톡·DM | 이미지 첨부는 가능하지만 정형 디자인 명세 양식이 없어 매번 캡처·설명·확인을 비정형으로 주고받아야 함 |
사용자는 결국 여러 플랫폼을 옮겨 다니며 캡처 + 편집 + 설명을 조합하는 비효율을 감내해야 합니다.
케이퀵은 이 단절된 과정을 시각 기반 단일 흐름으로 통합하는 서비스입니다.
- TypeScript (strict) · Node.js 24.x · Yarn 4 (Corepack)
- 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)
- MySQL 8 · Prisma 6 (ORM + Migrations) · Custom soft-delete extension
- OIDC (Google · Kakao) via
openid-client - JWT (
@nestjs/jwt+ Passport) · Argon2 (자격 증명 해시) class-validator·class-transformer기반 DTO 검증
- Jest + Testcontainers (Docker 컨테이너로 실 MySQL 자동 spin-up) + Supertest
- DB mock 미사용 — 실 DB 통합 테스트 (→ 테스트 섹션)
- ESLint (strict) · Prettier · Husky + lint-staged
- commitlint (Conventional Commits 강제) · Codecov (patch threshold 80%)
- CodeQL (GitHub Actions 기반 SAST) · Dependabot (의존성 자동 PR · 메이저는 ignore 정책)
- 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가 PrismaService나 PrismaClient에 직접 접근하는 것은 금지되어 있으며, 모든 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
도메인별로 폴더가 분리되며 (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
- 의존성 방향 강제:
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.tsExtension이 모든 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 문서 출력
| 항목 | 버전 | 비고 |
|---|---|---|
| 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/) |
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는 비활성 (
introspectionoff)
DB는 mock하지 않습니다. 모든 통합 테스트는 Testcontainers로 실제 MySQL 컨테이너를 자동 spin-up한 뒤 Prisma 마이그레이션까지 적용해 검증합니다.
- 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:covCI에서도 동일하게 testcontainers로 격리된 MySQL을 띄우므로 로컬과 환경 차이가 거의 없습니다.
| 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
- 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 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.

