Minbook
EN
코드는 됐는데 나머지가 안 됐다

코드는 됐는데 나머지가 안 됐다

MJ · · 6 분 소요

기능 구현(12%) 이후 론칭까지 추가로 소요된 3주간의 작업(결제 안정성, 보안, 법적 문서, SEO 등)을 통해 '코드 완료'와 '제품 완료'의 차이를 분석

3일 만에 MVP를 만들었습니다

WICHI의 첫 버전은 조코딩 해커톤에서 3일 만에 나왔습니다. Claude Code로 백엔드 API를 짜고, Lovable로 프론트엔드를 뽑았습니다. AI 코딩 도구 덕분에 전통적인 개발 사이클과는 완전히 다른 속도였습니다.

3일간의 기술 스택

레이어기술역할
백엔드FastAPI + PythonAI 검색 엔진 쿼리, 브랜드 분석, 점수 계산
프론트엔드React + Vite (Lovable)UI, 대시보드, 리포트 뷰
DBSupabase (PostgreSQL)사용자, 분석 결과, 크레딧 저장
인프라Railway + Lovable 호스팅서버 배포, 프론트 호스팅
인증Supabase Auth회원가입, 로그인, 세션 관리

해커톤 제출 시점에 작동했던 기능

  • AI 검색 엔진(ChatGPT, Perplexity, AI Overviews) 3개에 병렬 쿼리 전송
  • 브랜드 언급 여부 분석 및 GEO Score 계산
  • 9-Bucket 쿼리 프레임워크 기반 분석 실행
  • 사용자 가입, 로그인, 대시보드 접근
  • 결제 페이지 (Lemon Squeezy 연동)
  • 분석 리포트 생성 및 조회

코드는 됐습니다. 핵심 기능이 작동하는 제품이 있었습니다.

그런데 론칭은 안 됐습니다.


”작동한다”와 “론칭 가능하다”는 다릅니다

해커톤이 끝나고 상용화를 결정한 뒤에야, “작동하는 MVP”와 “돈을 받을 수 있는 제품” 사이에 거대한 갭이 있다는 걸 알게 됐습니다.

graph LR
    A["작동하는 MVP"] --> B["론칭 가능한 제품"]

    subgraph GAP["빠진 것들"]
        direction TB
        C["법적 고지"]
        D["결제 안정성"]
        E["보안 검증"]
        F["에러 모니터링"]
        G["SEO"]
        H["접근성"]
    end

    A -.->|"3일"| A
    B -.->|"+3주"| B
    A -->|"이 사이를 모름"| GAP
    GAP --> B

이 갭의 특징은 기술적으로 어려운 게 아니라, 존재 자체를 몰랐다는 것입니다. 아래에서 카테고리별로 정리합니다.


빠진 것들 — 카테고리별 상세

1. 법적 고지 — 개인정보처리방침, 이용약관

사용자 이메일을 수집하면서 어디에도 데이터 처리 방침을 고지하지 않았습니다. 결제를 받으면서 이용약관도 없었습니다.

구체적으로 빠져 있던 항목:

  • 개인정보처리방침 (/privacy) — 수집하는 데이터 항목, 이용 목적, 보존 기간, 제3자 제공 여부
  • 이용약관 (/terms) — 서비스 이용 조건, 책임 제한, 분쟁 해결 절차
  • 쿠키 동의 배너 — GA4, Supabase Auth, Lemon Squeezy 등 서드파티 쿠키 사용 고지
  • 환불 정책 — 크레딧 기반 서비스에서 환불 조건과 절차

결제가 붙는 순간 법적 고지는 선택이 아닙니다. 한국 개인정보보호법과 GDPR 모두 “서비스 이용 전 고지”를 요구합니다. 이걸 론칭 후에 알았습니다.

2. 결제 안정성 — Webhook, 멱등성, 트랜잭션

결제 페이지는 있었지만, 결제 이후의 흐름이 불완전했습니다.

sequenceDiagram
    participant User as 사용자
    participant App as WICHI
    participant LS as Lemon Squeezy
    participant DB as Database

    User->>App: 결제 요청
    App->>LS: Checkout 세션 생성
    LS->>User: 결제 페이지 리다이렉트
    User->>LS: 카드 결제 완료
    LS->>App: Webhook 전송

    Note over App: 여기서부터 문제

    App->>DB: 크레딧 충전
    Note over App,DB: 멱등성 미처리 → 중복 충전 가능
    Note over App,DB: 서명 검증 없음 → 위조 요청 가능
    Note over App,DB: 실패 시 재시도 로직 없음

구체적으로 빠져 있던 항목:

  • Webhook 서명 검증 — Lemon Squeezy에서 오는 요청이 실제로 Lemon Squeezy에서 온 건지 확인 안 함
  • 멱등성(Idempotency) 처리 — 같은 webhook이 두 번 오면 크레딧이 이중 충전될 수 있었음
  • 결제 실패 처리 — 카드 거절, 네트워크 오류 시 사용자에게 안내하는 흐름 없음
  • 크레딧 트랜잭션 안전성 — 분석 실행 중 서버 에러 발생 시 차감된 크레딧 복구 로직 없음

Webhook 멱등성이 없으면 실제로 돈이 이중 충전됩니다. 이건 이론이 아니라, 테스트 중에 실제로 발생한 문제입니다.

3. 보안 검증 — 입력 검증, 인젝션 방어

프론트엔드에서 기본적인 입력 길이 제한만 있었습니다. 백엔드에서는 사용자 입력을 거의 그대로 받아들이고 있었습니다.

구체적으로 빠져 있던 항목:

  • 백엔드 입력 검증 — allowlist 기반 필터링 없음. 브랜드명 입력 필드에 SQL이나 스크립트 삽입 가능
  • 프롬프트 인젝션 방어 — 사용자 입력이 LLM 프롬프트에 그대로 들어가는 구조. 의도하지 않은 지시를 삽입할 수 있었음
  • Rate Limiting — 동일 사용자가 무제한으로 분석 실행 요청 가능
  • CORS 설정 — 어떤 도메인에서든 API 호출 가능한 상태
# Before: 입력 그대로 사용
async def analyze(brand_name: str):
    prompt = f"Analyze the brand '{brand_name}' in AI search results"
    # brand_name에 프롬프트 인젝션이 들어갈 수 있음

# After: allowlist + 패턴 필터링
async def analyze(brand_name: str):
    if not re.match(r'^[a-zA-Z0-9가-힣\s\-\.]{1,100}$', brand_name):
        raise ValidationError("Invalid brand name")
    if contains_forbidden_patterns(brand_name):
        raise ValidationError("Forbidden input detected")
    prompt = f"Analyze the brand '{sanitize(brand_name)}' in AI search results"

무료 MVP에서는 누군가 이상한 입력을 넣어도 손해가 크지 않습니다. 결제가 붙는 순간 악의적 사용의 동기가 생깁니다. 크레딧 부정 사용, API 남용, 인젝션 공격이 실제 비용으로 연결됩니다.

4. 에러 모니터링 — Sentry, 알림

모니터링이 전혀 없었습니다. 분석 실행 중 LLM API 호출이 실패하면 사용자에게 빈 화면이 나왔습니다. 그리고 저는 그 사실을 몰랐습니다.

구체적으로 빠져 있던 항목:

  • 에러 추적 서비스 (Sentry 등) — 서버/클라이언트 에러 수집 없음
  • 업타임 모니터링 — 서버가 죽었는지 알 수 있는 방법 없음
  • 알림 채널 — 에러 발생 시 Slack/이메일/Telegram 알림 없음
  • 에러 발생 시 사용자 안내 — “분석 중 오류가 발생했습니다. 크레딧이 복구됩니다” 같은 피드백 없음

사용자가 직접 알려주기 전까지 에러가 있는지조차 알 수 없는 구조였습니다. 이건 유료 서비스의 구조가 아닙니다.

5. SEO — 검색에서 발견되지 않는 유료 서비스

robots.txt도, sitemap도, 메타 태그도, Open Graph 이미지도 없었습니다. 검색 엔진에 등록조차 하지 않았습니다.

구체적으로 빠져 있던 항목:

항목상태영향
robots.txt없음크롤러가 어떤 페이지를 인덱싱해야 하는지 모름
sitemap.xml없음검색엔진에 페이지 구조 전달 불가
메타 태그 (title, description)없음검색 결과에 의미 있는 정보 미표시
OG 이미지없음SNS 공유 시 깨진 링크 카드
canonical URL없음중복 페이지 문제 가능
구조화 데이터 (JSON-LD)없음Rich Snippet 기회 상실
Google Search Console 등록안 함인덱싱 상태 모니터링 불가

광고 없이 시작하는 초기 SaaS에서 오가닉 검색은 사실상 유일한 무료 유입 채널입니다. 이 채널이 완전히 닫혀 있었습니다.

6. 기타 — 작지만 빠뜨리면 안 되는 것들

  • GA4 연동 — 사용자 행동 데이터 수집 안 함. 전환율 측정 불가
  • 에러 페이지 (404, 500) — 기본 브라우저 에러 페이지 그대로 노출
  • 로딩 상태 — 분석 실행 중 로딩 인디케이터 없음 (3–5분 소요되는 작업인데)
  • 이메일 알림 — 분석 완료 시 이메일 알림 없음
  • 모바일 반응형 — 일부 페이지에서 모바일 레이아웃 깨짐

왜 몰랐나

AI 코딩 도구의 맹점

AI 코딩 도구는 “이 기능을 만들어줘”라는 요청에는 빠릅니다. Auth 시스템, 결제 연동, CRUD API — 구체적인 기능 요청에는 높은 품질의 코드를 빠르게 생성합니다.

하지만 “론칭 전에 뭘 빠뜨렸는지 알려줘”라는 질문에는 답하지 않습니다. 이건 도구의 결함이 아닙니다. AI 코딩 도구의 역할은 주어진 명세를 코드로 변환하는 것이지, 명세 자체의 완전성을 검증하는 것이 아닙니다.

graph TB
    subgraph AI_TOOL["AI 코딩 도구가 잘하는 것"]
        A1["기능 구현 요청 → 코드 생성"]
        A2["버그 수정 요청 → 패치 생성"]
        A3["리팩토링 요청 → 코드 개선"]
    end

    subgraph BUILDER["빌더가 직접 알아야 하는 것"]
        B1["론칭에 뭐가 빠졌는지"]
        B2["법적으로 뭐가 필요한지"]
        B3["보안적으로 뭐가 위험한지"]
        B4["비즈니스적으로 뭐가 먼저인지"]
    end

    AI_TOOL -.->|"이 영역은 커버 안 됨"| BUILDER

해커톤의 구조적 한계

해커톤은 “3일 안에 작동하는 것을 보여라”는 제약 조건입니다. 이 제약 조건 안에서는 법적 고지, 보안 검증, SEO 같은 항목이 우선순위에서 밀립니다. 당연합니다. 심사 기준에 “개인정보처리방침이 있는가”는 없습니다.

문제는, 해커톤이 끝난 후에도 그 우선순위가 머릿속에 남아 있다는 것입니다. “나중에 하면 되지”라고 미루다가, 론칭 직전에야 “이걸 안 하면 결제를 받을 수 없다”는 걸 깨닫습니다.


시간 분배 — 코드 15%, 나머지 85%

WICHI의 경우, 실제 시간 분배는 이랬습니다.

작업 카테고리소요 시간비율난이도
핵심 기능 코드 (AI 분석, 점수 계산)3일12%높음
결제 연동 + webhook 안정화3일12%중간
보안 강화 (입력 검증, 인젝션 방어)2일8%중간
i18n (한국어/영어 이중 언어)3일12%중간
SEO (메타, 사이트맵, Search Console)1일4%낮음
법적 문서 (개인정보처리방침, 약관)1일4%낮음
모니터링 (GA4, Sentry 연동)1일4%낮음
프론트엔드 마이그레이션 (Lovable → Vercel)1일4%낮음
샘플 시스템 (비로그인 데모)2일8%중간
테스트, 버그 수정, 엣지 케이스 처리4일16%중간
문서화, README, 배포 설정2일8%낮음
DNS, CORS, 환경변수, 기타 설정2일8%낮음
합계~25일100%
gantt
    title WICHI: MVP → 론칭 타임라인
    dateFormat  YYYY-MM-DD
    axisFormat  %m/%d

    section 해커톤 (3일)
    핵심 기능 코드         :done, h1, 2026-02-27, 3d

    section 상용화 전환 (~22일)
    결제 안정화             :done, c1, 2026-03-03, 3d
    보안 강화               :done, c2, 2026-03-05, 2d
    i18n                    :done, c3, 2026-03-06, 3d
    프론트엔드 마이그레이션 :done, c4, 2026-03-04, 1d
    샘플 시스템             :done, c5, 2026-03-09, 2d
    SEO + 법적 문서         :done, c6, 2026-03-07, 2d
    모니터링 연동           :done, c7, 2026-03-10, 1d
    테스트 + 버그 수정      :done, c8, 2026-03-11, 4d
    문서화 + 배포 설정      :done, c9, 2026-03-15, 2d
    기타 설정               :done, c10, 2026-03-17, 2d

코드 완성에 3일, 나머지에 약 22일. **비율로 보면 코드가 전체 작업의 12%**였습니다.

흥미로운 점은, 나머지 88%의 항목 중 기술적으로 어려운 것은 거의 없었다는 것입니다. 대부분 “해야 한다는 사실을 알기만 하면 반나절이면 끝나는 일”이었습니다.


이 경험에서 얻은 교훈 3가지

1. 코드 완성 ≠ 제품 완성

AI 코딩 도구가 빨라질수록 “코드가 다 됐으니 거의 끝났다”는 착각이 강해집니다. 실제로는 코드가 전체의 10–15%이고, 나머지 85–90%가 론칭 품질을 결정합니다.

2. 모르면 안 합니다

“비밀번호 리셋 플로우가 있는가?”라는 질문을 받으면 “아, 빠뜨렸다”고 바로 알 수 있습니다. 하지만 그 질문을 아무도 하지 않으면, 첫 고객이 비밀번호를 잊어버릴 때까지 모릅니다. 할 일 목록에 올라가지 않으면 하지 않습니다.

3. 체크리스트는 지식의 민주화입니다

경험 많은 개발자는 위 항목들을 “당연히 해야 하는 것”으로 압니다. 하지만 첫 SaaS를 만드는 사람은 모릅니다. 이 지식 격차를 메우는 가장 효율적인 방법은 코칭이나 멘토링이 아니라, 한 번 정리된 체크리스트입니다.


체크리스트의 시작

빠진 항목을 하나씩 고치면서, 동시에 기록하기 시작했습니다. 고친 항목, 고쳐야 할 항목, 나중에 해도 되는 항목. 처음에는 노션 페이지 하나에 불렛 리스트로 적었습니다.

적다 보니 양이 늘어났습니다. 보안, 결제, 법적 고지, SEO, 모니터링, 접근성, 테스팅, CI/CD. 한 카테고리에 20–40개씩 쌓였습니다.

WICHI에만 해당하는 항목도 있었지만, SaaS를 만드는 사람이라면 누구나 확인해야 하는 항목이 대부분이었습니다.

“이걸 나만 쓰면 아깝다”고 생각한 건 아닙니다. 정확히는, 이걸 다른 사람이 미리 정리해줬으면 나는 3주를 안 허비했을 텐데라는 생각이었습니다.

이 메모가 534개 항목이 되고, 15개 카테고리로 정리되고, CLI 도구가 되고, 결국 오픈소스 프로젝트가 된 과정은 다음 글에서 이야기합니다.

공유

관련 글