πŸš€ 첫 λ°±μ—”λ“œ ν”„λ‘œμ νŠΈ λ§Œλ“€κΈ°: Expense Tracker API

λ°œν–‰: (2026λ…„ 3μ›” 8일 AM 09:36 GMT+9)
5 λΆ„ μ†Œμš”
원문: Dev.to

Source: Dev.to

Project Overview

Expense Tracker APIλŠ” μ‚¬μš©μžκ°€ λ‹€μŒμ„ ν•  수 μžˆλŠ” RESTful λ°±μ—”λ“œ μ„œλΉ„μŠ€μž…λ‹ˆλ‹€:

  • λΉ„μš© μΉ΄ν…Œκ³ λ¦¬ 생성 및 관리
  • λΉ„μš© μΆ”κ°€ 및 좔적
  • μΉ΄ν…Œκ³ λ¦¬λ³„ λΉ„μš© 정리
  • API μ—”λ“œν¬μΈνŠΈλ₯Ό ν†΅ν•œ CRUD μž‘μ—… μˆ˜ν–‰

λͺ¨λ°”일 μ•±, μ›Ή λŒ€μ‹œλ³΄λ“œ λ˜λŠ” 재무 관리 μ‹œμŠ€ν…œμ˜ λ°±μ—”λ“œ μ—”μ§„μœΌλ‘œ ν™œμš©λ  수 μžˆμŠ΅λ‹ˆλ‹€.

Tech Stack

  • Node.js – λŸ°νƒ€μž„ ν™˜κ²½
  • Express.js – API ꡬ좕을 μœ„ν•œ μ›Ή ν”„λ ˆμž„μ›Œν¬
  • PostgreSQL – κ΄€κ³„ν˜• λ°μ΄ν„°λ² μ΄μŠ€
  • Sequelize ORM – λ°μ΄ν„°λ² μ΄μŠ€ λͺ¨λΈλ§ 및 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜
  • Docker – μ»¨ν…Œμ΄λ„ˆν™”λœ 개발 ν™˜κ²½
  • TablePlus – λ°μ΄ν„°λ² μ΄μŠ€ 관리

이 도ꡬ듀은 ν˜„λŒ€ λ°±μ—”λ“œ μ‹œμŠ€ν…œμ΄ μ–΄λ–»κ²Œ κ΅¬μ‘°ν™”λ˜κ³  λ°°ν¬λ˜λŠ”μ§€λ₯Ό λ³΄μ—¬μ£ΌλŠ” 데 도움이 λ©λ‹ˆλ‹€.

Database Design

APIλŠ” 두 개의 μ£Όμš” μ—”ν„°ν‹°λ₯Ό μ€‘μ‹¬μœΌλ‘œ κ΅¬μΆ•λ©λ‹ˆλ‹€:

Categories

μΉ΄ν…Œκ³ λ¦¬λŠ” λΉ„μš©μ„ λ‹€μŒκ³Ό 같은 그룹으둜 μ‘°μ§ν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€:

  • Food
  • Transportation
  • Utilities
  • Entertainment

각 μΉ΄ν…Œκ³ λ¦¬λŠ” λ‹€μŒμ„ ν¬ν•¨ν•©λ‹ˆλ‹€:

  • id
  • name
  • createdAt
  • updatedAt

Expenses

ExpensesλŠ” κ°œλ³„ 재무 기둝을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€. 각 expenseλŠ” λ‹€μŒμ„ ν¬ν•¨ν•©λ‹ˆλ‹€:

  • id
  • title
  • amount
  • categoryId (foreign key)
  • createdAt
  • updatedAt

categoryIdλŠ” 각 expenseλ₯Ό μΉ΄ν…Œκ³ λ¦¬μ™€ μ—°κ²°ν•˜μ—¬ μ μ ˆν•œ λΆ„λ₯˜λ₯Ό 보μž₯ν•©λ‹ˆλ‹€.

API Endpoints

ν‘œμ€€ REST μ—”λ“œν¬μΈνŠΈκ°€ μ œκ³΅λ©λ‹ˆλ‹€.

Categories

  • POST /categories
  • GET /categories
  • GET /categories/:id
  • PUT /categories/:id
  • DELETE /categories/:id

Expenses

  • POST /expenses
  • GET /expenses
  • GET /expenses/:id
  • PUT /expenses/:id
  • DELETE /expenses/:id

이 μ—”λ“œν¬μΈνŠΈλ“€μ„ 톡해 재무 데이터λ₯Ό κ΄€λ¦¬ν•˜λŠ” 전체 CRUD κΈ°λŠ₯을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Key Things I Learned

이 ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ μ—¬λŸ¬ λ°±μ—”λ“œ κ°œλ…μ— λŒ€ν•œ 이해가 κΉŠμ–΄μ‘ŒμŠ΅λ‹ˆλ‹€.

Database Migrations

Sequelize λ§ˆμ΄κ·Έλ ˆμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©΄ μŠ€ν‚€λ§ˆ 변경을 버전 관리할 수 μžˆμ–΄ μˆ˜λ™μœΌλ‘œ ν…Œμ΄λΈ”μ„ 생성할 ν•„μš”κ°€ μ—†μ–΄μ‘ŒμŠ΅λ‹ˆλ‹€.

Model Relationships

μ™Έλž˜ν‚€λ₯Ό 톡해 expenseλ₯Ό μΉ΄ν…Œκ³ λ¦¬μ™€ μ—°κ²°ν•¨μœΌλ‘œμ¨ κ΄€κ³„ν˜• λ°μ΄ν„°λ² μ΄μŠ€κ°€ 데이터 무결성을 μ–΄λ–»κ²Œ κ°•μ œν•˜λŠ”μ§€ λͺ…ν™•νžˆ μ•Œ 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

API Architecture

ν”„λ‘œμ νŠΈλ₯Ό λ‹€μŒκ³Ό 같이 κ΅¬μ„±ν–ˆμŠ΅λ‹ˆλ‹€:

  • Routes
  • Controllers
  • Models
  • Migrations

μ΄λŸ¬ν•œ 뢄리 κ΅¬μ‘°λŠ” μ½”λ“œλ² μ΄μŠ€λ₯Ό κΉ”λ”ν•˜κ³  μœ μ§€λ³΄μˆ˜ν•˜κΈ° μ‰½κ²Œ λ§Œλ“€μ–΄ μ€λ‹ˆλ‹€.

Error Handling

주둜 마주친 λ¬Έμ œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€:

  • λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ μˆœμ„œ 였λ₯˜
  • λ°μ΄ν„°λ² μ΄μŠ€ μ—°κ²° 문제
  • 잘λͺ»λœ λͺ¨λΈ μ°Έμ‘°

μ΄λŸ¬ν•œ 디버깅 과정을 톡해 λ°±μ—”λ“œ λ™μž‘μ— λŒ€ν•œ 이해가 ν–₯μƒλ˜μ—ˆμŠ΅λ‹ˆλ‹€.

Using Docker for Development

DockerλŠ” 개발 ν™˜κ²½μ„ ν‘œμ€€ν™”ν•˜μ—¬ λŸ°νƒ€μž„, μ˜μ‘΄μ„± 및 섀정을 ν•¨κ»˜ νŒ¨ν‚€μ§•ν•¨μœΌλ‘œμ¨ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ λ‹€μ–‘ν•œ μ‹œμŠ€ν…œμ—μ„œ μΌκ΄€λ˜κ²Œ μ‹€ν–‰λ˜λ„λ‘ ν•©λ‹ˆλ‹€.

Future Improvements

μ˜ˆμ •λœ κ°œμ„  사항:

  • User authentication (JWT) – 이미 κ΅¬ν˜„λ¨
  • λ‚ μ§œλ³„ expense 필터링
  • λŒ€μš©λŸ‰ 데이터셋을 μœ„ν•œ νŽ˜μ΄μ§€λ„€μ΄μ…˜
  • expense 뢄석 μ—”λ“œν¬μΈνŠΈ
  • Swaggerλ₯Ό μ΄μš©ν•œ API λ¬Έμ„œν™”
0 쑰회
Back to Blog

κ΄€λ ¨ κΈ€

더 보기 Β»

MERN ν”„λ‘œμ νŠΈ 섀정에 μ§€μ³μ„œ μžλ™ν™”ν•˜λŠ” VS Code ν™•μž₯ ν”„λ‘œκ·Έλž¨μ„ λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€

μ™œ MERN DevBoostλ₯Ό λ§Œλ“€μ—ˆλŠ”κ°€? λ‚˜λŠ” λ§Žμ€ MERN μŠ€νƒ ν”„λ‘œμ νŠΈλ₯Ό λ§Œλ“€κ³  μžˆμ—ˆλŠ”λ°, 초기 섀정에 항상 30~40뢄이 κ±Έλ Έλ‹€. 각 ν”„λ‘œμ νŠΈλ§ˆλ‹€ λ‹€μŒμ΄ ν•„μš”ν–ˆλ‹€: - μ‹λ³„μž 생성…

Archify μ†Œκ°œ: μ•„ν‚€ν…μ²˜ μ•„μ΄λ””μ–΄μ—μ„œ Spring Boot μ½”λ“œκΉŒμ§€

문제 λͺ¨λ“  λ°±μ—”λ“œ κ°œλ°œμžλŠ” 이 μˆœκ°„μ„ κ²½ν—˜ν•΄ λ³Έ 적이 μžˆλ‹€: μƒˆλ‘œμš΄ ν”„λ‘œμ νŠΈλ₯Ό μ‹œμž‘ν•˜λ©΄μ„œ 이미 μ•„ν‚€ν…μ²˜λ₯Ό 염두에 λ‘κ³ β€”μ•„λ§ˆλ„ κ°„λ‹¨ν•œ REST μ„œλΉ„μŠ€μ™€ λͺ‡ 개의 μ—”λ“œν¬μΈνŠΈλ§Œμ„ μƒκ°ν•˜κ³ β€”μ‹œμž‘ν•œλ‹€. ν•˜μ§€λ§Œ ν”„λ‘œμ νŠΈκ°€ μ§„ν–‰λ μˆ˜λ‘ μš”κ΅¬μ‚¬ν•­μ΄ λŠ˜μ–΄λ‚˜κ³ , λ³΅μž‘λ„κ°€ κΈ‰κ²©νžˆ μ¦κ°€ν•œλ‹€. ### 원인 1. **초기 섀계 λΆ€μ‘±** - ν”„λ‘œμ νŠΈ μ΄ˆκΈ°μ— μΆ©λΆ„ν•œ 도메인 λͺ¨λΈλ§κ³Ό 데이터 흐름 섀계λ₯Ό ν•˜μ§€ μ•ŠμœΌλ©΄, λ‚˜μ€‘μ— ꡬ쑰λ₯Ό λ°”κΎΈλŠ” 데 큰 λΉ„μš©μ΄ λ“ λ‹€. 2. **κΈ°λŠ₯ 폭발** - μ΄ˆκΈ°μ—λŠ” β€œμ½κΈ° μ „μš©β€ API만 ν•„μš”ν–ˆμ§€λ§Œ, κ³§ μ“°κΈ°, 인증, κΆŒν•œ, μ‹€μ‹œκ°„ μ•Œλ¦Ό λ“± λ‹€μ–‘ν•œ κΈ°λŠ₯이 μΆ”κ°€λœλ‹€. 3. **기술 μŠ€νƒ λ³€ν™”** - μƒˆλ‘œμš΄ λΌμ΄λΈŒλŸ¬λ¦¬λ‚˜ ν”„λ ˆμž„μ›Œν¬κ°€ λ“±μž₯ν•˜λ©΄μ„œ κΈ°μ‘΄ μ½”λ“œλ₯Ό κ΅μ²΄ν•˜κ±°λ‚˜ 톡합해야 ν•˜λŠ” 상황이 λ°œμƒν•œλ‹€. ### ν•΄κ²°μ±… #### 1. 도메인 쀑심 섀계(Domain‑Driven Design) 적용 - **Bounded Context**λ₯Ό λͺ…ν™•νžˆ μ •μ˜ν•˜κ³ , 각 μ»¨ν…μŠ€νŠΈλ§ˆλ‹€ 독립적인 λͺ¨λΈκ³Ό μ„œλΉ„μŠ€ 계측을 λ§Œλ“ λ‹€. - **Entity**, **Value Object**, **Aggregate** 등을 ν™œμš©ν•΄ λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ μΊ‘μŠν™”ν•œλ‹€. #### 2. λ ˆμ΄μ–΄λ“œ μ•„ν‚€ν…μ²˜ λ„μž… - **Presentation Layer** (Controller / Handler) – HTTP μš”μ²­μ„ λ°›μ•„ DTO 둜 λ³€ν™˜ν•˜κ³ , μ„œλΉ„μŠ€μ— μœ„μž„ν•œλ‹€. - **Application Layer** – νŠΈλžœμž­μ…˜ 경계와 μ›Œν¬ν”Œλ‘œμš°λ₯Ό μ •μ˜ν•œλ‹€. - **Domain Layer** – 핡심 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직과 도메인 κ·œμΉ™μ„ κ΅¬ν˜„ν•œλ‹€. - **Infrastructure Layer** – DB, λ©”μ‹œμ§€ 브둜컀, μ™ΈλΆ€ API λ“± 기술적 μ„ΈλΆ€ 사항을 λ‹΄λ‹Ήν•œλ‹€. #### 3. μΈν„°νŽ˜μ΄μŠ€μ™€ μ˜μ‘΄μ„± μ—­μ „(Dependency Inversion) - μƒμœ„ λ ˆμ΄μ–΄κ°€ ν•˜μœ„ λ ˆμ΄μ–΄μ— μ˜μ‘΄ν•˜μ§€ μ•Šλ„λ‘ **Repository Interface**, **Service Interface** 등을 μ •μ˜ν•˜κ³ , κ΅¬ν˜„μ€ 인프라 λ ˆμ΄μ–΄μ— λ‘”λ‹€. - μŠ€ν”„λ§μ—μ„œλŠ” `@Autowired` λŒ€μ‹  **Constructor Injection**을 μ‚¬μš©ν•˜κ³ , ν…ŒμŠ€νŠΈ μ‹œμ—λŠ” **Mock** κ΅¬ν˜„μ²΄λ₯Ό μ£Όμž…ν•œλ‹€. #### 4. λͺ¨λ“ˆν™”와 λ§ˆμ΄ν¬λ‘œμ„œλΉ„μŠ€ μ „λž΅ - μ‹œμŠ€ν…œμ΄ 일정 규λͺ¨λ₯Ό λ„˜μ–΄κ°€λ©΄ **Domain‑Driven Microservices** ν˜Ήμ€ **Modular Monolith** 둜 μ „ν™˜ν•œλ‹€. - 각 λͺ¨λ“ˆ(λ˜λŠ” μ„œλΉ„μŠ€)은 독립적인 λ°μ΄ν„°λ² μ΄μŠ€ μŠ€ν‚€λ§ˆμ™€ 배포 νŒŒμ΄ν”„λΌμΈμ„ κ°–λŠ”λ‹€. #### 5. μžλ™ν™”λœ ν…ŒμŠ€νŠΈμ™€ CI/CD νŒŒμ΄ν”„λΌμΈ - **Unit Test**, **Integration Test**, **Contract Test**(예: Spring Cloud Contract) λ₯Ό λ ˆμ΄μ–΄λ³„λ‘œ μž‘μ„±ν•œλ‹€. - GitHub Actions, GitLab CI λ“±μœΌλ‘œ **λΉŒλ“œ β†’ ν…ŒμŠ€νŠΈ β†’ 배포** 흐름을 μžλ™ν™”ν•œλ‹€. #### 6. λ¬Έμ„œν™”μ™€ μ½”λ“œ κ·œμΉ™ - OpenAPI/Swagger 둜 API μŠ€νŽ™μ„ μ •μ˜ν•˜κ³ , **API‑First** 접근법을 μ±„νƒν•œλ‹€. - μ½”λ“œ μŠ€νƒ€μΌμ€ **Checkstyle**, **Spotless**, **EditorConfig** 둜 일관성을 μœ μ§€ν•œλ‹€. ### μ˜ˆμ‹œ μ½”λ“œ (Spring Boot) ```java // Domain Layer @Entity public class Order { @Id @GeneratedValue private Long id; private LocalDateTime orderDate; @Embedded private Money totalAmount; // λΉ„μ¦ˆλ‹ˆμŠ€ λ©”μ„œλ“œ public void addItem(Product product, int quantity) { … } } // Application Layer @Service @RequiredArgsConstructor public class OrderService { private final OrderRepository orderRepo; private final PaymentGateway paymentGateway; @Transactional public OrderDto placeOrder(CreateOrderCommand cmd) { Order order = new Order(); // 도메인 둜직 μˆ˜ν–‰ orderRepo.save(order); paymentGateway.charge(order.getTotalAmount()); return OrderMapper.toDto(order); } } // Infrastructure Layer @Repository public interface OrderRepository extends JpaRepository<Order, Long> {} // Presentation Layer @RestController @RequestMapping('/api/orders') @RequiredArgsConstructor public class OrderController { private final OrderService orderService; @PostMapping public ResponseEntity<OrderDto> create(@RequestBody @Valid CreateOrderCommand cmd) { OrderDto result = orderService.placeOrder(cmd); return ResponseEntity.status(HttpStatus.CREATED).body(result); } } ``` ### 마무리 ν”„λ‘œμ νŠΈ μ΄ˆκΈ°μ— **μ•„ν‚€ν…μ²˜ 섀계**와 **도메인 λͺ¨λΈλ§**에 μΆ©λΆ„ν•œ μ‹œκ°„μ„ νˆ¬μžν•˜λ©΄, 이후 κΈ°λŠ₯ μΆ”κ°€λ‚˜ 기술 ꡐ체가 훨씬 μˆ˜μ›”ν•΄μ§„λ‹€. λ ˆμ΄μ–΄λ“œ μ•„ν‚€ν…μ²˜μ™€ DDD 원칙을 μ μš©ν•˜κ³ , μ˜μ‘΄μ„± μ—­μ „ 및 μžλ™ν™”λœ ν…ŒμŠ€νŠΈλ₯Ό 기반으둜 ν•˜λ©΄, λ³΅μž‘λ„κ°€ 증가해도 μœ μ§€λ³΄μˆ˜ κ°€λŠ₯ν•œ μ½”λ“œλ₯Ό μœ μ§€ν•  수 μžˆλ‹€. **핡심 포인트** - 초기 섀계에 투자 β†’ μž₯κΈ° λΉ„μš© 절감 - λ ˆμ΄μ–΄μ™€ μΈν„°νŽ˜μ΄μŠ€λ‘œ μ±…μž„ 뢄리 - ν…ŒμŠ€νŠΈμ™€ CI/CD 둜 λ³€κ²½ μœ„ν—˜ μ΅œμ†Œν™” - ν•„μš” μ‹œ λ§ˆμ΄ν¬λ‘œμ„œλΉ„μŠ€ ν˜Ήμ€ λͺ¨λ“ˆν˜• λͺ¨λ…Έλ¦¬μ‹μœΌλ‘œ ν™•μž₯

μ˜¬λ°”λ₯Έ Razorpay 결제 흐름 (κ°„λ‹¨νžˆ μ„€λͺ…)

λ§Žμ€ 결제 톡합 λ¬Έμ œλŠ” κ°œλ°œμžλ“€μ΄ Razorpay 결제 라이프사이클이 μ‹€μ œλ‘œ μ–΄λ–»κ²Œ μž‘λ™ν•˜λŠ”μ§€λ₯Ό μ˜€ν•΄ν•˜κΈ° λ•Œλ¬Έμ— λ°œμƒν•©λ‹ˆλ‹€. μ˜¬λ°”λ₯Έ 흐름을 λ”°λ₯΄λŠ” 것은 λ³΄μ•ˆμ„ 보μž₯ν•©λ‹ˆλ‹€.

textlens vs text-readability vs natural: ν…μŠ€νŠΈ 뢄석을 μœ„ν•œ npm νŒ¨ν‚€μ§€λŠ”?

Node.js용 ν…μŠ€νŠΈ 뢄석 νŒ¨ν‚€μ§€ ν…μŠ€νŠΈ 뢄석이 ν•„μš”ν•œ Node.js ν”„λ‘œμ νŠΈλΌλ©΄ npm이 μˆ˜μ‹­ κ°€μ§€ μ˜΅μ…˜μ„ μ œκ³΅ν•©λ‹ˆλ‹€. κ°€μž₯ 일반적인 μ‚¬μš© 사둀λ₯Ό λ‹€λ£¨λŠ” μ„Έ κ°€μ§€ νŒ¨ν‚€μ§€κ°€ μžˆμŠ΅λ‹ˆλ‹€.