Skip to content
Saegida
Go back

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

Note

코드부터 시키지 마세요. 클로드 코드(Claude Code)에게 곧장 “로그인 기능 만들어줘”라고 하면, 그 순간의 빈약한 컨텍스트로 코드를 짜냅니다. 결과는 매번 달라지고, 뒤로 갈수록 앞뒤가 안 맞습니다.

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

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

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

문서가 곧 컨텍스트다

[설계 문서] [가드레일] 요구사항 → ER → 화면정의 → API명세 → 테스트명세 ESLint + lint │ ↑ └──────────────→ CLAUDE.md (디렉토리별) ─────────┘ ↓ Prisma 스키마 → 코드 생성 → 테스트 통과

Tip

핵심 원칙 ”코드를 짜라”가 아니라 “이 문서를 기준으로 코드를 짜라”로 지시한다. 문서는 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
    }

> [!tip]
> **"문서만"을 명시하라**  
> 설계 단계에서 코드까지 같이 쏟아내면 검토가 어려워집니다. 단계마다
> `코드는 작성하지 마`를 붙여 산출물을 한정하세요.

## 3 화면 정의서 (Markdown)

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

docs/screens/post-list.mdmarkdown

화면: 글 목록 (PostList)

경로 /posts

구성 요소

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

동작

상태


> [!note]
> **화면 ↔ 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’


> [!tip]
> **스펙 → 타입 자동화**  
> OpenAPI가 있으면 `openapi-typescript` 같은 도구로 프론트 타입을 자동 생성할 수 있습니다.
> 명세와 코드가 어긋날 일이 줄어듭니다.

## 5 테스트 명세서

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

docs/test-spec.mdmarkdown

API: GET /api/posts

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

인증: POST /api/login

ID케이스입력기대 결과
TC-10성공올바른 자격200 + 토큰
TC-11비번 오류틀린 비번401

> [!note]
> **"완료"를 검증 가능하게**  
> "로그인 되게 해줘"는 약한 목표입니다. "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/ 에 있다. 코드 작성 전 반드시 참고할 것.

세부 규칙은 각 디렉토리의 CLAUDE.md 를 따른다.


apps/api/CLAUDE.mdmarkdown

백엔드 규칙


> [!tip]
> **한 파일 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 가 완료 조건


> [!warning]
> **린트는 "완료 조건"으로**  
> 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 를 작성해줘.


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()) }


> [!note]
> **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 스키마 | `Prisma` | ER → schema.prisma |
| 테스트 | `Vitest` | 테스트 명세서 기반 |
| 가드레일 | `ESLint` | 완료 조건에 lint 포함 |
| 배포 | `Vercel` 등 | 프로젝트 상황에 맞게 |

> [!tip]
> **스택을 적어두면 일탈이 준다**  
> 명시가 없으면 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`로 **최신 라이브러리 문법**을 따른다

> [!tip]
> **요점**  
> 클로드 코드를 "코드 짜주는 도구"가 아니라 **"문서를 코드로 옮기고, 가드레일로 스스로 검증하는
> 파트너"**로 쓰는 것. 좋은 컨텍스트(문서)와 명확한 완료 조건(테스트·린트)을 갖추면, 시스템 구성이
> 훨씬 일관되고 재현 가능해집니다.

Share this post:

Previous Post
오픈소스 라이선스 한눈에 — MIT·Apache·GPL부터 AGPL까지
Next Post
Syncthing으로 여러 PC 동기화 — TrueNAS 허브 + Tailscale