Claude Code · 워크플로우

클로드 코드로 시스템 만들기
— 요구사항·문서부터 가드레일까지

⏱ 약 13분 🧩 Spec-driven 개발 🛠 Claude Code · Prisma · ESLint 📅 2026-06-21
📝
코드부터 시키지 마세요.
클로드 코드(Claude Code)에게 곧장 "로그인 기능 만들어줘"라고 하면, 그 순간의 빈약한 컨텍스트로 코드를 짜냅니다. 결과는 매번 달라지고, 뒤로 갈수록 앞뒤가 안 맞습니다.

해법은 단순합니다. 먼저 설계 문서를 만들게 하고, 그 문서를 기준(spec)으로 코드를 생성하는 것. 요구사항 → ER 다이어그램 → 화면 정의서 → API 명세 → 테스트 명세서를 문서로 고정하면, LLM은 매번 같은 출처를 보고 일관된 코드를 냅니다. 이 글은 그 절차를 처음부터 끝까지 정리합니다.

1 왜 "문서 먼저"인가 — Spec-driven 개발

LLM은 컨텍스트가 좋을수록 좋은 코드를 냅니다. 반대로 컨텍스트가 비어 있으면 그럴듯하지만 일관성 없는 결과를 만듭니다. 그래서 "어떤 시스템인지"를 먼저 문서로 고정해 두고, 코드를 생성할 때마다 그 문서를 근거로 삼게 하는 것이 핵심입니다.

문서가 곧 컨텍스트다

[설계 문서] [가드레일] 요구사항 ER 화면정의 API명세 테스트명세 ESLint + lint └──────────────→ CLAUDE.md (디렉토리별) ─────────┘ Prisma 스키마 코드 생성 테스트 통과
💡
핵심 원칙
"코드를 짜라"가 아니라 "이 문서를 기준으로 코드를 짜라"로 지시한다. 문서는 docs/에 두고, 각 단계 산출물을 다음 단계의 입력으로 넘긴다.

2 요구사항 정의 + ER 다이어그램

가장 먼저 무엇을 만들 것인가를 정리합니다. 기능 목록과 핵심 엔터티(데이터)를 뽑고, 엔터티 간 관계를 ER 다이어그램으로 그립니다. Mermaid로 그리면 마크다운에 그대로 박혀 깃에서 렌더링되고, 나중에 Prisma 스키마의 근거가 됩니다.

클로드 코드에 줄 프롬프트

Claude Code 프롬프트prompt
블로그 시스템을 만들 거야. 다음을 docs/requirements.md 에 작성해줘.

1. 기능 요구사항 — 사용자/관리자 시나리오 단위로 목록화
2. 핵심 엔터티와 속성 정의
3. 엔터티 관계를 Mermaid erDiagram 으로 작성

지금은 문서만 만들고 코드는 작성하지 마.

산출물 — ER 다이어그램 (Mermaid)

docs/requirements.mdmermaid
```mermaid
erDiagram
    USER ||--o{ POST : writes
    USER ||--o{ COMMENT : writes
    POST ||--o{ COMMENT : has
    POST }o--o{ TAG : tagged

    USER {
      string id PK
      string email
      string name
      datetime createdAt
    }
    POST {
      string id PK
      string title
      string body
      string authorId FK
      datetime publishedAt
    }
```
💡
"문서만"을 명시하라
설계 단계에서 코드까지 같이 쏟아내면 검토가 어려워집니다. 단계마다 코드는 작성하지 마를 붙여 산출물을 한정하세요.

3 화면 정의서 (Markdown)

각 화면이 어떤 데이터를 보여주고, 어떤 동작을 하며, 어떤 API를 호출하는지를 마크다운으로 정의합니다. 화면 정의서는 프론트엔드 컴포넌트와 API 명세를 잇는 다리 역할을 합니다.

docs/screens/post-list.mdmarkdown
# 화면: 글 목록 (PostList)

## 경로 `/posts`

## 구성 요소
| 영역 | 내용 | 데이터 출처 |
|------|------|------------|
| 헤더 | 검색 입력, 태그 필터 | - |
| 목록 | 카드(제목·요약·작성자·날짜) | `GET /api/posts` |
| 페이지네이션 | 이전/다음 | `?page`, `?size` |

## 동작
- 카드 클릭 → `/posts/:id` 이동
- 태그 클릭 → `?tag=` 필터 적용

## 상태
- 로딩 / 빈 목록 / 에러 각각의 UI 정의
ℹ️
화면 ↔ API 연결을 표로
"어떤 영역이 어떤 API를 쓰는지"를 표로 박아두면, 다음 단계인 API 명세 작성이 거의 기계적으로 진행됩니다. 빠진 API도 이 단계에서 드러납니다.

4 API 명세 (OpenAPI)

화면 정의서에서 끌어낸 엔드포인트를 OpenAPI(Swagger) 스펙으로 정리합니다. OpenAPI는 사람이 읽기도 좋지만, 타입/클라이언트/목 서버를 자동 생성할 수 있어 표준으로 두기 좋습니다.

docs/openapi.yamlyaml
paths:
  /api/posts:
    get:
      summary: 글 목록 조회
      parameters:
        - name: page
          in: query
          schema: { type: integer, default: 1 }
      responses:
        '200':
          description: 목록
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PostList'
💡
스펙 → 타입 자동화
OpenAPI가 있으면 openapi-typescript 같은 도구로 프론트 타입을 자동 생성할 수 있습니다. 명세와 코드가 어긋날 일이 줄어듭니다.

5 테스트 명세서

마지막 문서는 테스트 명세서입니다. "이 기능이 끝났다"의 정의를 케이스 단위로 적어두면, 클로드 코드가 이 명세를 보고 실제 테스트 코드(Vitest 등)를 작성하고, 통과를 완료 기준으로 삼습니다.

docs/test-spec.mdmarkdown
## API: GET /api/posts

| ID | 케이스 | 입력 | 기대 결과 |
|----|--------|------|-----------|
| TC-01 | 기본 목록 | page 없음 | 200, 최신순 10건 |
| TC-02 | 페이지네이션 | `?page=2` | 200, 11~20번째 |
| TC-03 | 태그 필터 | `?tag=js` | 200, 해당 태그만 |
| TC-04 | 잘못된 page | `?page=-1` | 400 검증 에러 |

## 인증: POST /api/login
| ID | 케이스 | 입력 | 기대 결과 |
|----|--------|------|-----------|
| TC-10 | 성공 | 올바른 자격 | 200 + 토큰 |
| TC-11 | 비번 오류 | 틀린 비번 | 401 |
ℹ️
"완료"를 검증 가능하게
"로그인 되게 해줘"는 약한 목표입니다. "TC-10/11이 통과하게 해줘"는 강한 목표입니다. 테스트 명세서가 있으면 클로드 코드가 스스로 통과할 때까지 반복(loop)할 수 있습니다.

6 CLAUDE.md — 디렉토리별로 쪼개기

CLAUDE.md는 클로드 코드가 작업할 때 자동으로 읽는 프로젝트 지침서입니다. 여기에 위에서 만든 문서들의 위치를 알려주면, 매번 같은 컨텍스트로 작업합니다. 그런데 모든 규칙을 루트 한 파일에 몰아넣으면 점점 비대해지고, 프론트 작업 중에 백엔드 규칙까지 통째로 읽히는 비효율이 생깁니다.

해법 — 각 디렉토리에 배치

소스 코드가 위치한 디렉토리마다 그 영역에 맞는 CLAUDE.md를 두면, 클로드 코드는 해당 폴더에서 작업할 때 그 파일을 함께 참고합니다. 프론트 작업엔 프론트 규칙만, 백엔드 작업엔 백엔드 규칙만 — 컨텍스트가 가벼워지고 관리가 쉬워집니다.

CLAUDE.md 공통 규칙 + 문서 위치(docs/) 안내 docs/ requirements.md 요구사항 + ER screens/ 화면 정의서 openapi.yaml API 명세 test-spec.md 테스트 명세 apps/web/CLAUDE.md 프론트 규칙(컴포넌트·Tailwind·상태관리) apps/api/CLAUDE.md 백엔드 규칙(라우팅·Prisma·검증)
CLAUDE.md (루트)markdown
# 프로젝트 지침

설계 문서는 docs/ 에 있다. 코드 작성 전 반드시 참고할 것.
- 요구사항·ER: `docs/requirements.md`
- 화면 정의서: `docs/screens/`
- API 명세: `docs/openapi.yaml`
- 테스트 명세: `docs/test-spec.md`

세부 규칙은 각 디렉토리의 CLAUDE.md 를 따른다.
apps/api/CLAUDE.mdmarkdown
# 백엔드 규칙

- DB 접근은 Prisma Client 로만. raw SQL 금지.
- 모든 입력은 zod 로 검증 후 처리.
- 응답 스키마는 `docs/openapi.yaml` 과 일치시킬 것.
- 새 엔드포인트는 `docs/test-spec.md` 케이스를 먼저 통과시킬 것.
💡
한 파일 vs 분산
규칙이 적을 땐 루트 한 파일로 충분합니다. 프론트/백엔드 규칙이 갈라지기 시작하면 디렉토리별로 쪼개세요. "그 폴더에서 일할 때 필요한 규칙만 읽힌다"가 핵심 이점입니다.

7 가드레일 — ESLint + Lint 체크

LLM이 생성한 코드는 자동 검증 장치(가드레일)로 한 번 걸러야 합니다. 가장 기본은 린터입니다. ESLint 설정을 추가하고, 작업이 끝날 때마다 lint 체크를 돌리게 하면 스타일 붕괴와 흔한 실수를 코드가 쌓이기 전에 잡습니다.

eslint.config.mjsjavascript
import js from '@eslint/js';
import ts from 'typescript-eslint';

export default [
  js.configs.recommended,
  ...ts.configs.recommended,
  {
    rules: {
      'no-unused-vars': 'error',
      'no-console': 'warn',
      '@typescript-eslint/no-explicit-any': 'error',
    },
  },
];
터미널bash
$ npm install -D eslint @eslint/js typescript-eslint
$ npx eslint . # 작업 후 매번 실행 → 0 errors 가 완료 조건
⚠️
린트는 "완료 조건"으로
CLAUDE.md에 작업을 마치면 npx eslint . 를 실행하고 에러가 0이어야 한다고 적어두세요. 그러면 클로드 코드가 스스로 돌려보고, 걸린 부분을 고친 뒤에야 작업을 끝냅니다. 린트 + 타입체크 + 테스트, 이 셋이 LLM 코드의 기본 가드레일입니다.

8 ER → Prisma 스키마 (use context7)

2단계에서 만든 ER 다이어그램을 근거로 Prisma 스키마를 생성합니다. ER이 이미 엔터티·관계를 정의해 두었으므로, 스키마 작성은 거의 번역에 가깝습니다.

use context7 — 최신 문서를 끌어오기

라이브러리는 빠르게 바뀝니다. LLM의 학습 시점 지식은 종종 낡아 있어서, 옛 문법으로 스키마를 짜기도 합니다. Context7은 라이브러리의 최신 공식 문서를 그 자리에서 가져다주는 MCP 서버입니다. 프롬프트 끝에 use context7을 붙이면, 클로드 코드가 현재 버전의 Prisma 문법을 참고해 스키마를 만듭니다.

Claude Code 프롬프트prompt
docs/requirements.md 의 ER 다이어그램을 참고해서
prisma/schema.prisma 를 작성해줘.

- 관계(1:N, N:M)를 정확히 반영
- id 는 cuid, 타임스탬프 필드 포함
- 최신 Prisma 문법으로. use context7
prisma/schema.prismaprisma
model Post {
  id          String    @id @default(cuid())
  title       String
  body        String
  author      User      @relation(fields: [authorId], references: [id])
  authorId    String
  comments    Comment[]
  tags        Tag[]
  publishedAt DateTime?
  createdAt   DateTime  @default(now())
}
ℹ️
Context7이란?
MCP(Model Context Protocol) 서버 중 하나로, 라이브러리 이름과 버전을 받아 최신 문서 스니펫을 주입해 줍니다. Prisma·Next.js·Tailwind처럼 버전에 민감한 도구를 다룰 때 특히 유용합니다. use context7 한 줄이면 "지금 버전" 기준으로 코드를 짜게 됩니다.

9 기술 스택을 문서로 박제하기

마지막으로, 프로젝트가 쓰는 기술을 한 곳에 명시합니다. 이걸 CLAUDE.md(또는 docs/tech-stack.md)에 적어두면, 클로드 코드가 임의의 다른 라이브러리를 끌어오지 않고 정해진 스택 안에서 일합니다.

영역선택비고
언어TypeScript프론트·백엔드 공통
프레임워크Next.js / Express웹 / API
UI 컴포넌트Tailwind CSS유틸리티 우선 스타일
API 스키마OpenAPI스펙 우선, 타입 자동생성
DB 스키마PrismaER → schema.prisma
테스트Vitest테스트 명세서 기반
가드레일ESLint완료 조건에 lint 포함
배포Vercel프로젝트 상황에 맞게
💡
스택을 적어두면 일탈이 준다
명시가 없으면 LLM은 그때그때 다른 라이브러리를 끌어옵니다(상태관리 하나에 매번 다른 라이브러리…). "이 스택만 쓴다"를 박아두면 의존성이 깔끔하게 유지됩니다.

10 정리 — 전체 흐름 한눈에

클로드 코드로 시스템을 만드는 절차의 핵심은 "문서로 컨텍스트를 고정하고, 가드레일로 검증한다"입니다.

  1. 요구사항 + ER 다이어그램무엇을 만들지 정의하고 데이터 관계를 Mermaid로 그린다.
  2. 화면 정의서 (Markdown)각 화면의 구성·동작·호출 API를 표로 정리한다.
  3. API 명세 (OpenAPI)화면이 부르는 엔드포인트를 스펙으로 고정한다.
  4. 테스트 명세서"완료"의 정의를 케이스로 적어 검증 가능하게 만든다.
  5. CLAUDE.md 분산 배치문서 위치를 알리고, 프론트/백엔드 규칙은 각 디렉토리에 둔다.
  6. 가드레일 (ESLint + lint)린트·타입·테스트를 완료 조건으로 걸어 LLM 코드를 검증한다.
  7. ER → Prisma (use context7)최신 문법으로 스키마를 생성한다.
  8. 기술 스택 기록언어·프레임워크·UI·API·DB·테스트·배포를 한 곳에 박제한다.

✓ 이 절차가 주는 것

  • 세션이 바뀌어도 같은 문서를 보고 일관된 코드를 낸다
  • 테스트 명세 + 린트가 완료의 정의를 명확히 한다
  • CLAUDE.md 분산으로 필요한 컨텍스트만 읽혀 가볍다
  • use context7최신 라이브러리 문법을 따른다
💡
요점
클로드 코드를 "코드 짜주는 도구"가 아니라 "문서를 코드로 옮기고, 가드레일로 스스로 검증하는 파트너"로 쓰는 것. 좋은 컨텍스트(문서)와 명확한 완료 조건(테스트·린트)을 갖추면, 시스템 구성이 훨씬 일관되고 재현 가능해집니다.