Development

비전공자가 바이오 AI 플랫폼을 만들 수 있을까 — 1인 개발 회고

프로테오믹스 전문가이지만 웹 개발 비전공자인 내가 BioAI Market을 2주 만에 1인 개발한 회고. 기술 스택, 어려웠던 점, AI 코딩의 위력을 공유한다.

·10 min read
#1인개발#BioAI#Next.js#Supabase#회고#AI코딩

Developer working alone at night with multiple screens

배경: 나는 누구인가

나는 프로테오믹스/바이오인포매틱스 전문가다. R, Python으로 데이터 분석은 수천 번 했고, 질량분석 데이터의 전처리부터 통계 분석, 시각화까지 도메인 지식은 탄탄하다. SQL도 15년 넘게 써왔다.

하지만 웹 개발은 처음이었다.

HTML/CSS를 조금 안다는 것과 React 기반 풀스택 웹 애플리케이션을 만드는 것은 차원이 다른 이야기다. useState, useEffect, Context API, Server Components, API Routes — 이런 개념들이 낯설었다.

그런데 BioAI Market이라는 아이디어가 너무 확실했다. 프로테오믹스 분석을 웹에서 바로 할 수 있는 플랫폼. R이나 Python 환경 설정 없이, 데이터만 올리면 DE 분석, 시각화, 바이오마커 검증까지. 이 아이디어를 실현하려면 웹 개발을 해야 했다.

기술 스택 선택

Next.js — React 경험 없이 시작

npx create-next-app@latest bioai-market --typescript --tailwind --app

React를 한 번도 쓴 적 없는 상태에서 Next.js를 선택한 건 모험이었다. 하지만 이유가 있었다:

  1. Vercel 무료 배포git push만 하면 배포 완료
  2. 풀스택 — 프론트엔드 + API Routes로 백엔드까지 한 프레임워크에서
  3. 커뮤니티 — 문서와 예제가 풍부해서 AI 어시스턴트가 잘 도와줄 수 있음

Supabase — SQL은 알지만 BaaS는 처음

import { createClient } from '@supabase/supabase-js';

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);

SQL은 익숙했으니 Supabase의 PostgreSQL이 자연스러웠다. 하지만 Row Level Security(RLS), Auth, Realtime 같은 BaaS 기능은 처음이었다. 특히 RLS 정책 작성에서 시간을 많이 잡아먹었다.

-- 이 정책 하나 때문에 반나절 디버깅
CREATE POLICY "Users can view own data" ON analysis_results
  FOR SELECT USING (auth.uid() = user_id);

-- 에러: "new row violates row-level security policy"
-- 원인: INSERT 정책을 안 만들어놓고 INSERT를 시도
CREATE POLICY "Users can insert own data" ON analysis_results
  FOR INSERT WITH CHECK (auth.uid() = user_id);

Vercel — git push = 배포

무료 플랜의 60초 함수 실행 시간 제한이 가장 큰 제약이었다. 프로테오믹스 데이터 분석에 60초는 턱없이 부족하다. 500개 단백질의 DE 분석에 2~3분이 필요한데.

해결책: Python 분석 백엔드를 별도 서버(Railway 또는 로컬)에 두고, Vercel의 API Route에서 프록시하는 구조로 우회했다.

가장 어려웠던 것: 프론트엔드 상태 관리

React의 상태 관리가 가장 큰 벽이었다.

useEffect 무한 루프

// ❌ 이렇게 하면 무한 루프
useEffect(() => {
  const data = fetchAnalysisResults();
  setResults(data);  // state 변경 → 리렌더링 → useEffect 재실행 → ...
});

// ✅ 의존성 배열 추가
useEffect(() => {
  const data = fetchAnalysisResults();
  setResults(data);
}, []);  // 빈 배열: 마운트 시 1번만 실행

이 실수를 5번 이상 반복했다. 콘솔에 수천 개의 API 호출이 찍혀나가는 걸 보고 식은땀이 났다. Supabase 무료 플랜의 일일 API 호출 제한에 한 번 걸릴 뻔했다.

AuthContext 리렌더링 문제

// ❌ 모든 인증 상태 변경이 전체 앱 리렌더링 유발
const AuthContext = createContext<AuthState | null>(null);

function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    const { data: { subscription } } = supabase.auth.onAuthStateChange(
      (event, session) => {
        setUser(session?.user ?? null);  // 모든 이벤트에서 state 변경
        setLoading(false);
      }
    );
    return () => subscription.unsubscribe();
  }, []);
  
  // 이 value가 바뀔 때마다 모든 consumer가 리렌더링
  return (
    <AuthContext.Provider value={{ user, loading }}>
      {children}
    </AuthContext.Provider>
  );
}

useMemo로 value를 메모이제이션하고, 불필요한 state 변경을 줄여서 해결했다. 이런 건 도메인 지식이 아니라 React 경험에서 오는 감각인데, 나한테는 없었다.

가장 쉬웠던 것: 백엔드 분석 파이프라인

반면 분석 로직은 놀라울 정도로 쉬웠다. 도메인 지식이 있으니 로직이 머릿속에 이미 그려져 있었다.

# DE 분석 파이프라인 — 도메인 지식이 있으면 30분이면 작성
def run_de_analysis(data: pd.DataFrame, groups: dict) -> pd.DataFrame:
    results = []
    for protein in data.index:
        group1_values = data.loc[protein, groups['control']]
        group2_values = data.loc[protein, groups['treatment']]
        
        # log2 fold change
        log2fc = np.mean(np.log2(group2_values + 1)) - np.mean(np.log2(group1_values + 1))
        
        # Welch's t-test
        stat, pval = stats.ttest_ind(group1_values, group2_values, equal_var=False)
        
        results.append({
            'protein': protein,
            'log2FC': log2fc,
            'p_value': pval,
        })
    
    df = pd.DataFrame(results)
    df['adj_p_value'] = multipletests(df['p_value'], method='fdr_bh')[1]
    return df

15년간 해온 일이니까. 검정 방법 선택, 정규화, FDR 보정 — 이런 건 손이 기억하고 있었다.

AI 어시스턴트(OpenClaw)의 위력

솔직히 말하면, AI 어시스턴트 없이는 불가능했을 것이다. OpenClaw를 활용해서:

  1. 코드 생성: React 컴포넌트, API Route, 타입 정의 등을 자연어로 설명하면 코드 생성
  2. 디버깅: 에러 메시지를 보여주면 원인과 해결책 제시
  3. 배포 자동화: Vercel 설정, 환경 변수, 빌드 에러 해결
  4. 문서화: README, API 문서 자동 생성

체감상 AI가 코딩의 70% 이상을 담당했다. 내 역할은 "뭘 만들지" 결정하고, AI가 만든 코드를 도메인 지식으로 검증하는 것이었다.

1인 개발의 현실

기능 추가 30% vs 버그 수정 70%

이게 현실이었다. 새 기능을 하나 추가하면 버그가 세 개 생겼다. 특히 프론트엔드와 백엔드의 데이터 형식 불일치, 인증 상태에 따른 조건부 렌더링, 에러 핸들링 누락 등이 시간을 잡아먹었다.

// 이런 에러가 매일 나왔다
TypeError: Cannot read properties of undefined (reading 'map')
// 원인: API 응답이 null인데 바로 .map() 호출
// 해결: optional chaining + fallback
const items = data?.results ?? [];

무료 스택의 한계와 타협

서비스제한타협
Vercel함수 60초Python 백엔드 분리
Supabase500MB 저장벡터 DB 최적화 (3.5MB)
Ollama환각템플릿 기반 렌더링
무료 도메인없음Vercel 기본 도메인 사용

전부 합쳐서 월 운영비 ₩0. 도메인 비용만 별도.

배운 교훈

  1. "완벽한 코드보다 동작하는 프로덕트" — 리팩토링은 나중에. 일단 동작하게 만들어야 한다.
  2. "도메인 전문성 + AI 코딩 = 강력한 조합" — 코딩은 AI가 해결하고, 내가 해결해야 하는 건 "무엇을 만들지"와 "결과가 맞는지 검증"이다.
  3. "사용자에게 보여줘야 피드백이 온다" — 혼자 완성도를 높이는 것보다, 빨리 배포하고 피드백 받는 게 낫다.

다음 목표

  • 사용자 확보: 프로테오믹스 연구자 커뮤니티에 홍보
  • 유료 기능: 대용량 데이터 분석, 커스텀 리포트, 팀 협업
  • Blood Top-Down Proteomics 분석 모듈 추가

2주 만에 0에서 프로덕트까지 왔다. 갈 길이 멀지만, 시작했다는 것 자체가 가장 큰 성과다.

💡 무료 스택으로 SaaS를 운영하는 방법은 bric.pe.kr의 월 0원 SaaS 구축기에서 다루었다. 프로테오믹스 분석 플랫폼의 기술적 세부사항은 sbmlab.com에서 확인할 수 있다.

Next.js 공식 문서Supabase 공식 문서가 이 여정에서 가장 많이 참고한 자료다.