오픈소스로 다 공개한 코코아 제작기

한상훈·2025년 2월 19일

안녕하세요. 벨로그에 오랜만에 글을 적내요. 개발자 겸 회사 대표 겸 강사 겸 작가로 살고 있는 한상훈입니다. 2월 4일 저녁부터 개발을 유튜브 라이브로 공개적으로 시작해서 오늘로 한 2주 정도 개발한 사이트가 있습니다. 바로 코코아입니다.

코코아는 코인코인코리아의 줄임말로 해외 거래소를 통해 거래를 할 때 어떤 코인으로 송금하는게 가장 손실이 적을지(김치 프리미엄과 수수료가 적게 발생하면서 송금이 되는지) 알고 싶어서 만든 서비스입니다. 그런데 그냥 만들면 재미가 없어서 유튜브 라이브 방송 켜고 개발을 진행했습니다.

제 유튜브 채널 정책상 라이브 방송하고 며칠 지나면 유료 맴버들 공개로 전환되긴 해서 지금은 감춰져있지만, 이번 글에서는 이 프로젝트가 어떻게 개발됐는지 영상보다 자세하게 설명드리고자 합니다.

그런데 왜 오픈소스인가?

코코아를 공개하기에 앞서 제가 처음에 개발을 시작했을 때 이야기를 잠깐 해보고 싶네요. 2015년 저는 창업을 하고 모바일 게임을 만들기 시작했습니다. 그 당시에 서버를 구현하는데 사용한 기술은 PHP였어요. 그 당시 서버 구축에 대한 지식이 없던 제가 PHP로 서버를 만들 생각을 했던 건 다름 아닌 어떤 외국 개발자가 상세히 공유해준 블로그 글과 오픈소스 덕분이었습니다.

10년 전 외국 개발자가 공유해준 오픈소스에는 기본적인 CRUD가 다 포함되어 있었고 저는 그 코드를 바탕으로 제가 원하는 서버를 구축할 수 있었습니다. 큰 골격은 가져오고 디테일한 부분만 수정하면서 개발을 했고, 그게 전혀 모르던 언어도 배울 수 있게 해준 훌륭한 시작점이 됐습니다.

시간이 한참 지나 2025년인 지금이 되서 저는 개발자이면서 회사 대표, 강사, 작가로 살고 있지만 제가 배운 지식들이 누군가가 무료로 공개해준 지식들과 경험들 덕분에 얻은 것이란 걸 알고 있습니다. 무료로 강의를 공유해주신 생활코딩님이나 수많은 개발 블로그, 공개된 라이브러리 등이 다 선생님이셨던 것이죠. 그런 이유에서 저도 제가 쓰는 코드를 풀스택으로 한 번쯤 통째로 공유하고자 했고 이번 계기로 풀스택 프로젝트를 오픈 소스로 공개하게 됐습니다.

구조 및 실행

소스코드: https://github.com/joshephan/cocoa

  • 프론트엔드: Next.js
  • UI 라이브러리: Tailwind
  • DTO: zod
  • 상태관리: Zustand
  • API 서버: Nest.js
  • ORM: Drizzle
  • 데이터베이스: Postgres
  • 기타 환경: Docker + Redis + Web Socket

구조는 JS와 도커만 사용할 수 있으면 되는 간단한 프레임워크 구조입니다.

서비스를 실행해보기 위해서는 먼저 client와 server에 있는 환경 변수를 .env 파일을 생성해서 자신만의 값으로 넣어주어야 합니다. 이후 도커를 설치합니다.

도커는 도커 홈페이지에서 바로 다운로드 버튼을 눌러 설치하시면 됩니다.

그렇게 환경 변수 설정, 도커 설치, client와 server 각각의 모듈을 설치하고 나면 도커 환경을 실행하시면 됩니다.

도커 환경 실행은 server에만 종속성이 있으니 server 디렉터리에서

docker-compose up --build

명령을 통해 데이터베이스, 레디스, API 서버를 백그라운드에서 실행할 수 있습니다.

서버를 실행하고 도커 대시보드를 통해 실행되고 있는 도커 컨테이너를 확인하면 이미지와 같이 실행된 모습을 보실 수 있을 겁니다. 이 중에서 API 서버의 경우에는 계속 켜두고 보셔도 되지만 개발 환경에서 수정하면서 로그를 보고 싶으시다면 이미지에서 처럼 cocoa-api에 대해서 도커는 중지시키고, IDE 터미널에서 실행해서 확인해보면 됩니다.(제 경우에는 개발을 할 때 DB와 Redis는 도커에 켜두고 API 서버만 IDE에서 관리하는 방식을 선호합니다.)

이것으로 구조와 실행하는 방법은 아주 간단히 끝나게 됩니다.

추가로 데이터베이스의 변경이 생기거나 데이터베이스가 반영되지 않은 상태에서는 drizzle을 통해 DB를 업데이트해줘야할 필요가 있습니다. 이때는 server 디렉터리에서

pnpm db:genrerate
pnpm db:migrate
pnpm db:push

이 명령을 실행하면 됩니다. 서버를 다루는 기본적인 지식이 있는 분들은 아시겠지만 필요에 따라서 마이그레이션과 푸시를 사용하시면 되고, 스키마 변경이 됐다면 generate는 필요합니다.

도커를 사용 안해보신 분들은 개념적으로 어렵게 느껴지실 수 있지만 사실 파일 2개 정도만 주의깊게 한 번 보면 쉬워집니다. 이 프로젝트에서는 server/Dockerfile과 server/docker-compose.yml 파일입니다.

Dockerfile을 살펴보면 도커가 실행된 환경을 먼저 정의합니다. 제 경우엔 node 22.13.0 버전에 해당합니다. 그리고 실행될 디렉터리에 파일을 옮기고 빌드한 후 실행하는 순서로 명령이 발생합니다.

docker-compose.yml 파일은 각 서비스의 구체적인 정보를 담고 있습니다. 가령 컨테이너의 이름이나 실행되어야 하는 포트, 환경 변수 등을 명시적으로 선언해줄 수 있습니다.

만약 여러분이 DB를 외부 인스턴스를 통해 호출해서 docker로 구현할 필요가 없거나 redis도 마찬가지로 외부로 빼는 경우라면 docker-compose.yml에서 해당 부분을 통째로 삭제하시면 됩니다.

구체적인 패턴

코드를 보시면 아시겠지만 서버의 경우엔 일반적인 Nest.js의 service, controller 구조를 띄고 있습니다. 한가지 차이점이 있다면 TypeORM이나 Prisma의 경우에는 repository 파일을 만들어 관리하는 경우가 많습니다. drizzle의 경우에도 똑같이 repository를 만들어 구현해도 되지만 제 경우에는 굳이 파일을 만드느니 service 코드에 inject 하는 방식으로 간단하게 구현한 경우가 있습니다.

물론 이 패턴은 빠르게 만들기 위함이고 나중에 코드가 더 커지고, 구조화가 필요한 경우라면 repository.ts 파일을 별도로 만들어 관리하는게 조금 더 좋은 구조라 생각합니다.

레디스의 경우에는 여러 목적으로 사용되고 있습니다. 웹 소캣으로 전달되어야 하는 데이터를 취합하거나 실시간 채팅 등에 사용됩니다. 레디스는 redis.service.ts를 통해 서비스로 관리되고, server 디렉터리 전역에서 사용됩니다.

AI 및 크롤링

이 프로젝트에는 Open AI와 뉴스 데이터 및 환율 정보 크롤링이 포함되어 있습니다. News API를 통해 취합된 최신 뉴스를 Open AI 모듈을 통해 프롬프트를 입력해 뉴스를 생성합니다. 이 과정에서 Open AI의 API Key를 사용해도 되지만 저는 기존에 Open Router를 계속 사용 중이어서 키를 Open Router로 설정했습니다. 큰 차이는 없으니 취향것 설정하시면 됩니다.

크롤링의 경우에는 환율을 가져올 때 실시간 정보를 제공하는 API가 별로 없어 구글 환율 페이지를 일정 시간마다 불러오는 방식으로 구현됐습니다. 그 밖에도 실시간 한강 수온을 표시하기로 했는데, 이건 어제 라이브 방송 때 시청자 분이 말씀 주신걸 바로 적용해봤습니다.

가격 예측 게임

사용자 분들이 재밌게 즐길만한게 없을까 싶어 가격 예측 게임을 만들어봤습니다. 가상의 게임 머니인 코코아 머니를 매일 1,000달러씩 얻을 수 있고 이를 바탕으로 가상의 거래를 해볼 수 있습니다. 당연히 실제 제품과 교환되거나 돈으로 코코아 머니를 살 수 있는 구조는 아닙니다.(그러면 불법입니다)

막상 구현하고 해보니 꽤 재밌기도 한데 보상이 전혀 없으니 심심한 맛이 있어 이벤트를 하기로 했습니다. 상위 50명까지는 커피 기프티콘, 상위 3명은 치킨 기프티콘을 드리는 이벤트입니다. 이벤트는 이 서비스가 운영되는 동안 계속 할 거 같습니다. 지금이야 제 사비로 다 지출하고 있지만 이게 좀 커지면 후원해주시는 기업도 생기지 않을까 싶네요.

송금 계산기

이 서비스의 가장 근본이자 최초의 목적인 송금 계산기도 구현이 됐습니다. 코인의 경우엔 동일한 코인도 거래소마다 가격이 다르고, 거래소마다 송금시에 필요한 코인의 개수도 다르다보니 어떤 코인으로 송금을 하는게 가장 좋은 것인지 알기 어렵습니다.

송금 계산기는 앞서 만든 기능들을 바탕으로 거래소의 실시간 가격과 이미 저장된 거래소의 코인별 송금 수수료를 바탕으로 최적의 송금 경로를 알려주도록 개발됐습니다.

컨트렉트 위험성 스캐너

컨트렉트가 위험한지 어떻게 할 수 있을까요? 코인과 토큰의 유통량이나 소스코드의 위험성 등을 측정하기 어렵습니다. 이를 측정하고 검증해주는 서비스가 있습니다. Scamscanner라는 서비스로 Uppsala security라는 크립토 보안 기업에서 제공 중인 서비스입니다. 아직 퍼블릭 공개는 안된 기술인데 제가 개인적으로 연락을 해서 API Key를 받아와서 구현해봤습니다. 아마 이 프로젝트에서 거의 유일하게 환경 변수 키를 구할 수 없는 게 해당 기능일 겁니다.

위험성 스캐너는 4가지 팩터로 위험도를 검증해 신뢰할만한 프로젝트와 아닌 프로젝트를 점수로 표현해줍니다.

DeFi 수익률

디파이 수익률은 데이터베이스에 저장하여 캐싱해 가져오는 방식으로 구현되었습니다. 수익률 데이터는 전세계에서 가장 많이 사용되는 디파이 통계 플랫폼인 Defillama의 공개 API를 사용해 데이터를 얻습니다. 워낙 거대한 데이터라 매번 fetch 하는 것은 상당히 느리고 부담스럽기 때문에 청크 사이즈로 나눠 저장하고, 매일 오전 6시에 업데이트 하는 방식을 택했습니다.

오픈소스

이렇게 만든 코코아는 오픈소스입니다. 이 소스 코드가 수정할 필요가 없는 완벽한 소스코드는 절대 아니고, 저도 계속 개발하면서 개발과 리팩터링을 반복하는 그런 프로젝트입니다. 이 소스코드를 통해서 제가 바라는건 제가 과거에 이름 모를 어떤 개발자의 블로그 글과 소스코드로 도움을 얻었던 것처럼 개발자 분들이 다른 개발자는 이런식으로 개발하는구나 확인해보고, 모르는 부분은 배울 수 있었으면 좋겠습니다.

또한 오픈소스이기 때문에 어떠한 형태의 기여도 환영합니다. 더 좋은 패턴이나 제가 귀찮아서 적용 안한 패턴들도 있는데 여러 형태로 커밋이나 이슈를 통해 기여해주시면 이 프로젝트가 더 완성도 있게 발전할 수 있으리라 생각합니다.

코코아 바로가기: https://coincoin.kr
소스코드 확인하기: https://github.com/joshephan/cocoa

profile
서른살 때부터 포르쉐 타다 쫄딱 망한 사람

5개의 댓글

comment-user-thumbnail
2025년 2월 27일

저는 여러분께 "코코아 (CoinCoinKorea)" 프로젝트를 소개하고자 합니다. 이 프로젝트는 해외 거래소를 통해 거래할 때 어떤 암호화폐를 이용하여 송금할 때 손실이 가장 적은지를 알아내기 위해 만들어졌습니다 (김치 프리미엄과 거래 수수료를 고려하여).
choice advantages

왜 만들었을까요? 처음에는 단순히 송금 손실을 최소화하는 것에 대해 호기심이 생겨 시작했습니다. 하지만 이 과정을 더 재미있고 흥미롭게 만들기 위해 유튜브 라이브 방송을 켜고 개발을 진행했습니다. 제 유튜브 채널 정책상 라이브 방송 후 며칠이 지나면 유료 멤버들에게만 공개되지만, 이 스레드에서는 개발 과정을 더욱 자세히 설명드리고자 합니다.

2개의 답글
comment-user-thumbnail
2025년 2월 27일

이정도 작업을 오픈소스로 공개해주시다니 정말 흥미롭네요 ! 송금 계산기 기능을 아주 유용하게 활용할 수 있을 것 같아요. 한국에도 자체 코인마켓캡이 생긴 것 같아서 너무 좋습니다. 응원해요 🥳

1개의 답글