CoinFlow는 단일 인스턴스 환경에서 지정가 주문 생성, 가격-시간 우선 매칭, 체결, 지갑 정산, 원장 기록까지 검증하는 암호화폐 거래소 코어 백엔드 MVP입니다.
이 프로젝트는 실시간 시세나 분산 인프라보다 주문과 자산 정합성을 우선합니다. 주문이 체결될 때 orders, trades, wallets, wallet_ledgers, domain_events가 일관되게 기록되는 것을 목표로 합니다.
- 회원가입, 로그인, JWT access token 인증
- 사용자별 지갑 자동 생성 및 데이터 분리
- 지정가
BUY/SELL주문 생성 - 주문 취소
- 가격 우선, 시간 우선 매칭
- 부분 체결, 완전 체결
- BUY 주문 quote asset 잠금, SELL 주문 base asset 잠금
- 체결 시 buyer/seller 지갑 정산
- append-only 지갑 원장 기록
- 시장, 오더북, 최근 체결, 사용자 fill, 지갑, 원장 조회
- 서버 시작 시 DB의 미체결 주문으로 인메모리 오더북 초기화
- 주문/체결/정산 도메인 이벤트 로그 저장
- 입금/출금
- 시장가 주문
- IOC/FOK/GTT, post-only, iceberg 주문
- 수수료
- refresh token, OAuth/social login, role/permission
- Kafka 기반 이벤트 발행
- WebSocket 실시간 체결/호가 push
- Redis, MQ, 서버 분리
- replay, redrive, reconciliation
- 관리자 페이지
일부 로컬 개발 편의를 위한 API와 인프라 기반은 존재하지만, 운영 기능 범위와 구분합니다. 예를 들어 dev/test 입금 보조 API는 prod 프로필에서 제외되며, Kafka 컨테이너는 로컬 인프라 기반일 뿐 현재 애플리케이션 코드에는 spring-kafka producer/consumer가 연결되어 있지 않습니다.
Phase 1 완료 이후 리뷰 과정에서 zero-quote 체결 방지, dust maker 자동 취소, 오더북 재빌드 같은 정합성 보강이 추가되었습니다.
| 주제 | 설계 |
|---|---|
| Source of truth | DB의 주문, 체결, 지갑, 원장을 기준 상태로 둡니다. |
| 인메모리 오더북 | 매칭 후보 조회와 호가 조회를 위한 파생 상태입니다. |
| 오더북 반영 | DB commit 이후에만 인메모리 오더북을 변경합니다. |
| 순차 처리 | 같은 시장의 주문 생성/취소는 market별 ReentrantLock으로 직렬화합니다. |
| DB 동시성 | sequence, wallet, maker order 갱신에 pessimistic lock을 사용합니다. |
| 지갑 모델 | available_balance와 locked_balance를 분리합니다. |
| 원장 | 모든 지갑 변경을 wallet_ledgers에 append-only로 기록합니다. |
| 이벤트 | domain_events를 내부 이벤트 로그로 저장하고, 이후 Outbox 확장 경계를 남깁니다. |
- Java 21
- Spring Boot 3.5
- Spring Web MVC
- Spring Security + OAuth2 Resource Server + JWT
- Spring Data JPA
- MySQL 8
- Flyway
- JUnit 5, AssertJ
- Testcontainers MySQL
- Actuator, Micrometer, Prometheus registry
- Docker Compose
docker compose up -d mysqldocker-compose.yml에는 Kafka 컨테이너도 포함되어 있지만, 현재 MVP 애플리케이션 실행에는 MySQL만 필요합니다.
./gradlew bootRun기본 DB 접속 정보는 다음과 같습니다.
spring.datasource.url=jdbc:mysql://localhost:3306/coinflow?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
spring.datasource.username=coinflow
spring.datasource.password=coinflow다른 포트를 사용해야 하면 파일을 수정하지 않고 환경 변수로 주입합니다.
DB_URL='jdbc:mysql://localhost:3307/coinflow?serverTimezone=Asia/Seoul&characterEncoding=UTF-8' ./gradlew bootRun애플리케이션 실행 후 Swagger UI에서 API를 확인할 수 있습니다.
http://localhost:8080/swagger-ui/index.html
전체 테스트는 다음 명령으로 실행합니다.
./gradlew test통합 테스트는 Testcontainers 기반 MySQL을 사용해 decimal, foreign key, transaction 경계와 핵심 정합성 시나리오를 실제 MySQL에 가깝게 검증합니다. 동시성 테스트와 부하 테스트는 다음 단계로 분리합니다.
주요 검증 범위:
- 회원가입, 로그인, JWT 인증
- BUY/SELL 주문 자산 잠금
- 가격 우선 매칭
- 부분 체결, 완전 체결
- BUY taker 가격 차이 환불
- SELL taker 정산
- 부분 체결 후 취소
- 자기 체결 거절
- 원장 기록
- 오더북 조회
- 도메인 이벤트 저장
- 지갑 잔고 음수 방지
| 문서 | 설명 |
|---|---|
| PRD | MVP 제품 범위, 포함/제외 기준, 성공 기준 |
| Plan | MVP 구현 순서와 설계 원칙 |
| API | REST API 계약과 에러 코드 |
| ERD | 테이블 구조와 관계 |
| Test Plan | 핵심 통합 테스트 시나리오 |
| Order Flow | 주문 생성부터 체결/정산/오더북 반영까지의 내부 흐름 |
| Issues | Phase 1 이후 코드 리뷰 이슈와 보강 내용 |
| Reference | 설계 판단 근거와 외부 거래소 API 레퍼런스 |
현재 구현 완료 범위는 Phase 1 MVP입니다. 다음 단계에서는 이벤트 발행과 실시간 전파를 별도 이슈로 확장합니다.
- OutboxPublisher 구현
domain_events.published=false이벤트 Kafka 발행- Kafka 발행 성공/실패 상태와 재시도 횟수 관리
- Kafka Consumer 기반 WebSocket 체결/오더북 broadcast
- 정산 Batch와 부하 테스트 추가
Kafka, WebSocket, Batch 정산은 아직 구현 완료 기능으로 표기하지 않습니다.