JK
>로딩 중 // 로딩 중
뷰 초기화 중
NestJS, PostgreSQL, Docker를 활용하여 독립적인 상품/주문 서비스를 중앙 API Gateway로 관리하는 실전 마이크로서비스 아키텍처.
라우팅(Gateway), 도메인 로직(각 서비스), 데이터베이스 간의 관심사를 분리하여 개별 배포 및 수평 확장이 가능한 구조를 제공합니다.
| 기술 | 버전 | 목적 | 선택 이유 |
|---|---|---|---|
| TypeScript | ^5.7.3 | Primary language for all services | Type safety, NestJS ecosystem standard |
| NestJS | ^11.0.1 | Application framework | Modular architecture, dependency injection, TypeScript-first |
| TypeORM | ^0.3.27 | ORM for PostgreSQL access | Active Record/Repository pattern, NestJS integration |
| PostgreSQL | 15 | Primary database | JSONB support, ACID compliance, reliability |
| Docker | — | Containerization for all services | Consistent environments, reproducible deployments |
| Turborepo | ^2.5.8 | Monorepo task orchestration | Fast parallel builds, caching, npm workspaces integration |
| GitHub Actions | — | CI/CD pipeline execution | Free for public repos, tight Git integration |
| Jest | ^30.0.0 | Unit testing framework | NestJS default, snapshot support |
| Swagger | ^11.2.0 | API documentation | Auto-generates OpenAPI from decorators |
| 메서드 | 경로 | 목적 |
|---|---|---|
| GET | /products | List all products |
| GET | /products/:id | Get product by ID |
| POST | /products | Create product |
| PATCH | /products/:id | Update product |
| DELETE | /products/:id | Delete product |
| GET | /orders | List all orders |
| GET | /orders/:id | Get order by ID |
| POST | /orders | Create order |
| 메서드 | 경로 | 목적 |
|---|---|---|
| POST | /products | Create product |
| GET | /products | List all products |
| GET | /products/:id | Get product by ID |
| PATCH | /products/:id | Update product |
| DELETE | /products/:id | Delete product |
| 메서드 | 경로 | 목적 |
|---|---|---|
| POST | /orders | Create order |
| GET | /orders | List all orders |
| GET | /orders/:id | Get order by ID |
| 컬럼 | 유형 | 비고 |
|---|---|---|
| idPK | SERIAL | Auto-generated primary key |
| code | VARCHAR | Product SKU/code |
| name | VARCHAR | Product display name |
| description | VARCHAR | Product description |
| price | DECIMAL | Product price |
| image | VARCHAR | Image URL |
No explicit indexes beyond primary key. No unique constraints on code.
| 컬럼 | 유형 | 비고 |
|---|---|---|
| idPK | SERIAL | Auto-generated primary key |
| customer | JSONB | Stores {name, phone} |
| products | JSONB | Array of {id, name, rate, qty} |
| totalAmount | DECIMAL | Total order amount |
Products stored as JSONB snapshot — intentional denormalization. No foreign keys to product table.
No foreign key relationships. Order.products is a JSONB snapshot — orders are self-contained records that do not reference the product table. Product price changes do not affect existing orders.
결정: Both services connect to the same PostgreSQL instance and database (procura_db)
이유: Simplifies development and deployment — one database to manage
이점: Simpler infrastructure, lower resource usage, easier local development
트레이드오프: Violates database-per-service principle, creates hidden coupling, makes independent scaling harder
결정: Order entity stores product data as JSONB rather than foreign key references
이유: Decouples order data from product lifecycle — orders are immutable snapshots
이점: Orders are self-contained, product changes don't affect historical orders
트레이드오프: No referential integrity, data duplication, no automatic product validation on order creation
결정: Simple static API key in x-api-key header, compared against environment variable
이유: Simplest possible authentication for demonstration purposes
이점: Minimal implementation, no token management, no state
트레이드오프: No user identity, no fine-grained permissions, key is static and shared
결정: API Gateway communicates with downstream services via synchronous HTTP (Axios)
이유: Simplest approach for synchronous request-response pattern
이점: Easy to understand, debug, and test; standard HTTP tooling
트레이드오프: Synchronous coupling, no retry/circuit breaker, no async processing
결정: Each service uses a 3-stage Dockerfile (deps → builder → runner)
이유: Minimizes final image size and attack surface
이점: Production images contain only runtime dependencies and compiled code
트레이드오프: Build time for each stage, no layer caching optimization for src changes
결정: Both services use synchronize: true in TypeORM config
이유: Auto-creates/updates database schema from entities during development
이점: No migration files needed, schema stays in sync with code
트레이드오프: Dangerous in production — can cause data loss on schema changes