BioAI Market 1인 개발 회고 — 커밋 기록으로 다시 본 석 달
2025년 12월 19일 첫 커밋부터 2026년 3월까지, 웹 기반 오믹스 분석 플랫폼을 혼자 만들며 남긴 커밋 312개를 다시 읽었다. 시간이 어디에 들어갔는지, 다시 한다면 무엇을 다르게 할지 정리했다.
BioAI Market은 웹 브라우저에서 오믹스 데이터를 올리고 QC, DE, pathway 분석을 돌리는 플랫폼이다. 분석 파이프라인 설계는 프로테오믹스 분석 플랫폼을 직접 만들어봤다에 썼다. 이 글은 그 플랫폼을 혼자 만든 과정의 회고다.
예전에 다른 블로그에 회고를 한 편 올렸는데, 다시 보니 기억에 기대 쓴 숫자가 많았다. 함수 실행 시간, 실수한 횟수, AI가 코드의 몇 퍼센트를 썼는지 같은 것들이다. 코딩 도구 이름도 기록과 달랐다. 이번에는 기억 대신 git 기록을 다시 읽고 썼다. 이 글에 나오는 날짜와 숫자는 모두 커밋 기록에서 셌다.
무엇으로 만들었나
- 프론트와 API: Next.js(현재 16.1), React 19, TypeScript, Tailwind, shadcn/ui. Vercel에 배포.
- 인증과 DB: Supabase(PostgreSQL, pgvector).
- 분석 백엔드: Python FastAPI 서버. R 패키지(limma, clusterProfiler 등)는 rpy2로 불렀다.
- LLM: RTX 3090 서버의 Ollama. 기본 모델은 2월 15일부터
qwen3:30b. - 코딩 도구: Claude Code. 커밋 47개에 "Generated with Claude Code" 줄이 남아 있고, 12월 22일에는 세션이 바뀌어도 작업 맥락을 이어 가려고
claude.md를 저장소에 넣었다.
커밋 312개의 분포
| 달 | 커밋 수 |
|---|---|
| 2025년 12월 | 25 |
| 2026년 1월 | 23 |
| 2026년 2월 | 215 |
| 2026년 3월 | 39 |
| 2026년 4월 | 0 |
| 2026년 5월 | 10 |
첫 커밋은 2025년 12월 19일의 "Initial commit from Create Next App"이다. 다음 날 "BioAI Market 전체 기능 구현"이 올라간다. 커밋의 3분의 2가 2월 한 달에 몰려 있다. 2월 25일 하루에만 49개다. 앱 기능을 만들거나 고친 커밋은 3월 중순(3월 13일 에이전트, 3월 16일 메인 페이지 수정)이 마지막이다. 그 뒤로는 광고 스크립트 경고 수정, 페이지 정리, 검색엔진 설정 커밋만 있다.
3월 16일까지의 커밋 296개 가운데 147개가 "fix"로 시작한다. 2월만 보면 215개 중 120개다. 절반 가까이가 고치는 커밋이었다.
범위: 만든 것이 너무 많았다
12월과 1월 커밋 제목만 훑어도 이 정도다.
- 12월 20일: 플랫폼 전체 기능, 태그 필터, Python·NGS·AI 교육 과정 Level 1~4, 과정 소개 페이지
- 12월 22일: 블로그 관리 시스템, 바이오마커 DB, 분석 대시보드, 요금제, 서비스 소개, 웹툰(OmicsToon), 샘플 리포트
- 12월 30일: 근거 집계 시스템, 자동 주석(Auto-Annotation) 엔진, 관리자 사용자 관리
- 1월 1~2일: 상용 키트(assay) DB, RAG 시스템, AI 채팅, 패널 빌더
- 1월 9~16일: SSE 스트리밍 AI 에이전트와 PDF 리포트, 코드 실행 샌드박스가 붙은 자율 에이전트, Ensembl API 연동 에이전트
- 1월 28~29일: AI Co-Scientist 연구 플랫폼, OpenAI·Anthropic·Ollama 다중 LLM
2월과 3월에는 여기에 에이전트 V2(코드 인터프리터, 2월 27일)와 V3(도구 사용, 2월 28일), RNA-seq·대사체 파이프라인, 머신러닝 기반 탐색, 공개 DB 가져오기(3월 7~9일)가 더해진다. 결제 연동(Stripe) API도 있다.
에이전트는 두 달 사이에 세 번 새로 만들었다. 3월 13일 마지막 에이전트 커밋의 제목은 "Agent V3 API - simple and reliable implementation"이다. 결국 단순한 쪽으로 돌아왔다.
커밋 기록을 다시 보면 기능을 붙이는 속도가 그 기능을 검증하는 속도보다 빨랐다. 아래 문제들은 대부분 그 차이에서 나왔다.
시간이 들어간 곳 1: 서버리스 시간 제한
분석 API는 vercel.json에서 함수 실행 시간이 60초로 묶여 있었다. 프로테오믹스 분석을 웹 요청 하나 안에서 끝내려던 설계가 여기에 계속 걸렸다.
- 2월 18일: "split analysis into steps to avoid Vercel 60s timeout", 같은 날 비동기 작업 큐 도입
- 2월 24일: "step-by-step save to avoid 504 timeout", 진행 표시와 재시도를 붙인 작업 큐
- 2월 25일: 주석 처리를 GPU 서버 백엔드로 넘김("to avoid Vercel serverless timeout"), 큰 결과를 Vercel을 거쳐 전달하지 않게 바꿈
- 3월 13일: 작업 큐를 끔("disable job queue")
무거운 계산은 처음부터 별도 백엔드에서 돌리고, 웹은 작업 상태만 묻게 설계했어야 했다. 결국 그렇게 됐지만, 거기까지 가는 데 커밋이 많이 들었다.
시간이 들어간 곳 2: 데이터 저장소 두 곳
2월 24일부터 분석 결과와 바이오마커 데이터를 Supabase에서 GPU 서버의 로컬 PostgreSQL로 옮기기 시작했다("hybrid DB - local PostgreSQL for results, Supabase Cloud fallback"). 커밋이 가장 많았던 2월 25~26일이 이 작업이다. 한쪽에서 읽고 다른 쪽에 쓰는 경로가 섞이면서 이런 커밋이 줄줄이 나왔다.
- "handle PostgreSQL array strings in RTX biomarker response"
- "convert Decimal strings to numbers in annotation results API"
handle non-array diseases field from RTX DB (string '{}' → [])- "fetch project biomarker details from RTX local DB instead of Supabase Cloud JOIN"
같은 데이터가 두 곳에 있고, 두 곳의 드라이버가 같은 값을 다른 타입으로 돌려준다. 그러면 화면마다 방어 코드가 붙는다. 3월 9일에는 "comprehensive defensive fallbacks on all potentially undefined arrays"라는 커밋까지 나온다. 저장소는 하나로 정하고 시작하는 게 맞았다.
시간이 들어간 곳 3: 프론트엔드 상태
React 상태 관리에서도 시간이 많이 들었다. 전처리 옵션 컴포넌트(PreprocessingOptions)의 무한 렌더링을 2월 21일부터 23일까지 사흘 동안 커밋 아홉 개로 고쳤다.
- 2월 21일: "prevent useEffect infinite loop in PreprocessingOptions (useRef for callback)"
- 2월 21일: "remove useEffect render loop, revert sed variable renames, use direct config.* access"
- 2월 22일: "restore all config.* references broken by sed"
- 2월 22일: "use useRef+useCallback for preprocessing config to eliminate render loop entirely"
- 2월 23일: "move onOptionsChange out of setState updater to prevent infinite loop (React #185)"
- 2월 23일: "rewrite: PreprocessingOptions - simple Auto/Manual toggle, no expand/recommend, no useEffect"
(나머지 세 개도 같은 루프를 다른 방법으로 막으려던 커밋이다.) 중간에는 변수 이름을 sed로 일괄 변경했다가 참조가 깨져서 되돌린 일도 있다. 22일 커밋 제목에 "entirely"라고 썼지만 다음 날 커밋이 네 개 더 있다. 마지막 해법은 기능을 줄인 것이다. 추천과 펼치기 옵션을 없애고 자동/수동 토글 하나만 남겼다.
2월 14일에는 인증 컨텍스트가 사용자 정보를 네 번씩 중복 조회하던 것을 고쳤다("prevent 4x duplicate API calls"). 같은 날 페이지 미리 불러오기(prefetch)를 끄려고 Next.js Link를 일반 a 태그로 바꾸는 커밋도 여럿 있다. 2월 16일에는 대시보드가 계속 새로고침되는 루프를 고쳤다.
시간이 들어간 곳 4: 필드 이름
DE 결과는 log2FC, pValue로 저장되는데, TypeScript 쪽 여기저기서는 log2fc, pvalue, p_value를 읽었다. pathway 결과도 enrichedPathways와 enrichment_results가 섞였다. 2월 16일, 2월 27일에 같은 종류의 커밋이 반복된다. 지금 코드에도 흔적이 남아 있다.
// 저장소 src/lib/agents/tools/executors.ts 에서 발췌
log2fc: (r.log2FC as number) ?? (r.log2fc as number) ?? 0,
pvalue: (r.pValue as number) ?? (r.pvalue as number) ?? (r.p_value as number) ?? 1,
이 실수는 표시 오류로 끝나지 않았다. LLM에게 넘기는 프롬프트에 실제 값 대신 0과 N/A가 들어갔고, LLM은 그걸 보고 "분석 실패"라는 설명을 썼다. 이 이야기는 로컬 LLM에게 분석 결과 설명을 맡겼다가 템플릿으로 바꾼 이유에 따로 정리했다. 백엔드의 응답 형식을 한 곳에서 정의하고(예를 들어 FastAPI의 Pydantic 모델에서 OpenAPI 스키마를 뽑고, 거기서 TypeScript 타입을 생성하는 식), 프론트는 그 타입만 쓰게 했어야 했다.
시간이 들어간 곳 5: 데이터
바이오마커 DB는 1월 6일에 크게 늘렸다. 그날 커밋에는 같은 대량 삽입 마이그레이션이 네 벌(원본, FIXED, v2, v3) 들어 있다. 타입 변환 오류와 중복 삽입을 차례로 고친 흔적이다. 다시 읽어 보니 같은 날 들어간 연관 관계 마이그레이션 일부는 disgenet_score 같은 점수 칸을 random()으로 채우고 있었다. 이 점수가 나중에 결과 화면에 그대로 찍힐 수 있는 구조였다. 자세한 내용은 바이오마커 DB에 시맨틱 검색을 붙이며 배운 것에 적었다.
순서가 거꾸로였던 것
2월 15일 커밋에서 앱이 GPU 서버의 Ollama를 외부 주소로 부르도록 바꿨다. 그 앞단 프록시에서 API 키를 확인하게 한 커밋은 2월 20일이다("Add Ollama API key auth (X-API-Key header via Caddy proxy)"). 모델 서버를 바깥에서 부를 수 있게 하는 일과 인증을 붙이는 일은 같은 커밋에 들어갔어야 했다.
다시 한다면
- 기능 수를 정하고 시작한다. 교육 과정, 웹툰, 블로그, 요금제, 에이전트 세 벌을 분석 플랫폼과 같은 석 달에 만들 이유가 없었다. 분석 하나를 끝까지 검증하는 쪽을 먼저 했어야 했다.
- 무거운 계산은 처음부터 백엔드와 작업 큐로. 웹 요청 안에서 분석을 끝내려는 설계는 시간 제한에 계속 걸린다.
- 저장소는 하나. 같은 데이터를 두 곳에 두면 타입 변환과 폴백 코드가 화면마다 붙는다.
- 백엔드와 프론트가 같은 스키마를 쓴다. 필드 이름이 하나라도 다르면 그 오류가 LLM 출력까지 번진다.
- 시드 데이터를 코드처럼 검사한다. 점수 칸에 무엇이 들어 있는지, 넣으려던 건수와 들어간 건수가 같은지 확인한다.
- LLM이 내는 숫자는 쓰지 않는다. 숫자는 코드가 찍고, LLM 문단은 표시를 붙인다.
- AI 코딩 도구가 만든 변경도 내가 검증한다. 빨리 만들 수 있다는 것과 맞게 만들었다는 것은 다른 문제다.
커밋 기록으로 보면 이 프로젝트의 기능 개발은 3월 중순에 멈췄다. 그래도 석 달 동안 남긴 기록 덕분에, 기억으로 쓴 회고보다 정확한 회고를 쓸 수 있었다.
관련 글
바이오마커 DB에 시맨틱 검색을 붙이며 배운 것 — 임베딩 1,141개, pgvector, 그리고 시드 데이터
10월 11일 · 22 min read
Bioinformatics프로테오믹스 분석 플랫폼을 직접 만들어봤다
2월 23일 · 10 min read
AI/ML로컬 LLM에게 분석 결과 설명을 맡겼다가 템플릿으로 바꾼 이유
10월 11일 · 18 min read
BioinformaticsIt Almost Worked: Four Ways a Multi-Omics Pipeline Nearly Reported a False Success
8월 10일 · 19 min read