codingstairs
노트에듀라이프연락
⌕검색⌘K
koen

Navigation

  • Intro
  • Blog
  • Life

연락하기

로그인 없이도 보낼 수 있어요. 답변이 필요하면 이메일을 함께 적어 주세요.

  • 익명 폼으로 의견 남기기 →
  • ✉ warragon112@gmail.com
  • 카카오톡 오픈채팅 ↗

© 2026 codingstairs

  • 노트
  • 에듀
  • 검색
  • 라이프
  • 연락
  • 약관
  • RSS
  • GitHub
에듀›모노레포 · SSOT · 계층 분리 사고›3단계

3단계

폴더를 계약으로

0회 조회

폴더를 계약으로

"여기에 파일 두면 무엇이 자동으로 된다" 를 약속으로 고정. Next.js · FastAPI 라우트는 이미 이 철학이지만, 더 넓게 적용 가능.

1. "URL = 폴더" 정합 (Next.js App Router)

src/app/
├── posts/
│   ├── page.tsx                    → /posts
│   └── [id]/
│       └── page.tsx                → /posts/:id
├── admin/
│   └── settings/
│       └── page.tsx                → /admin/settings

파일 경로 읽으면 URL 유추 가능. 반대도 가능. grep 한 번으로 "어떤 파일이 이 URL 을 담당?".

2. 하이픈 금지 · 복합 단어 금지

src/app/
├── admin/pryzeet/                    ✓
├── admin/pryzeet-users/              ✗ (URL 에 하이픈은 OK, 폴더 구조는 depth 로)

폴더 구조가 의미 계층을 표현 · URL 에 하이픈 합성을 하면 grep 이 어려움.

3. 파일명 규약

kebab-case.ts           → 일반 모듈
camelCase.ts            → 사용자 정의 훅 (useX)
PascalCase.tsx          → React 컴포넌트
__tests__/*.test.ts     → 테스트 (vitest 규약)
*.spec.ts               → Playwright E2E

한 프로젝트 안에서 일관. 두 스타일 섞이면 혼란.

4. "진입점 안정화" — barrel export

src/shared/lib/
├── index.ts                ← 공개 API 만 re-export
├── db.ts
├── auth/
│   ├── index.ts           ← auth/ 공개 API
│   ├── session.ts
│   └── oauth.ts

외부에서는 import from "@/shared/lib" 만. 내부 구현 파일 경로는 refactor 자유.

5. 공용 코드 배치

src/shared/lib/      → 도메인 무관 (db · logger · fmt)
src/shared/ui/       → 시각 요소 (Button · Table)
src/shared/types/    → 타입 전용
src/domains/*/       → 도메인 코드

"shared = N 군데서 쓰이는 것" · "domains = 1 도메인 전용".

6. 테스트 폴더 위치

두 학파:

  • 코드 옆 — src/lib/foo.ts + src/lib/foo.test.ts
  • 분리 — src/lib/foo.ts + tests/lib/foo.test.ts

코드 옆이 실용적 (grep 쉬움 · 이동 시 같이). 분리는 큰 프로젝트.

7. 실전 — warragon docs 폴더 계약

docs/
├── RULES.md                  — 전역 규칙 (변경 주기 분기 이하)
├── shared/*.md               — 기술 규칙 (분기별)
├── agent/{svc}/              — Claude agent 전용 지시
│   ├── README.md             — 진입점
│   ├── rules.md              — 서비스 고유 규칙
│   └── features/             — 기능별 세부
└── service/{svc}/            — 제품 · 운영 문서
    ├── prd.md                — 제품 요구사항
    ├── api.md                — API 레퍼런스
    └── improvements.md       — 개선 · 기술부채

파일 이름 하나로 "여기서 뭘 볼 수 있는지" 즉답 가능. 새 팀원 · AI agent 가 빠르게 읽음.

8. _ prefix — private

src/
├── pages/
├── components/
├── _legacy/          ← 제거 예정 · import 금지
├── _scripts/         ← 일회성 마이그 스크립트

Python 은 _ prefix 가 관례, JS/TS 는 관례 약함 → 주석 + eslint 룰.

9. 자주 걸리는 자리

  • 폴더 깊이 과잉 — src/lib/utils/helpers/string/format.ts 는 찾기 어려움. 3~4 depth 권장
  • utils/ 만능 폴더 — 무엇을 담는지 불명. 도메인별로 분리
  • 순환 의존 — A 폴더가 B import, B 가 A import. 공통을 별도 추출
  • 규약 혼재 — 한 프로젝트에 kebab · camel · Pascal 섞임

10. ESLint 로 강제

// eslint.config.mjs
import boundaries from "eslint-plugin-boundaries";

export default {
  plugins: { boundaries },
  rules: {
    "boundaries/element-types": ["error", {
      rules: [
        { from: "frontend", disallow: ["backend"] },
        { from: "shared", disallow: ["domains"] },
      ],
    }],
  },
};

경계 위반을 린트 단계에서 차단.

하고픈 말

폴더 구조는 "남이 찾기 좋은 방식" 이 정답. 내 기억에 의존한 이름 · 깊이는 3 개월 뒤 나 자신도 못 찾습니다.

Next

  • 04-sql-as-ssot

← 2단계

SSOT — 어디에 두는가

4단계 →

SQL = SSOT