Cursor Rules Upgrade Plan
📊 현재 상태 분석
섹션 제목: “📊 현재 상태 분석”현재 구조의 문제점
섹션 제목: “현재 구조의 문제점”1. 디렉토리 구조 문제
섹션 제목: “1. 디렉토리 구조 문제”현재:src/├── routes/ # HTTP 라우트├── services/ # 비즈니스 로직 (Cloudflare 의존성 포함)├── schemas/ # Zod 스키마└── lib/ # 유틸리티 (Cloudflare 코드 + 도메인 로직 혼재) ├── d1.ts # Cloudflare D1 코드 ├── r2.ts # Cloudflare R2 코드 ├── queue.ts # Cloudflare Queue 코드 ├── domain.ts # 도메인 로직 └── liveness.ts # 도메인 로직문제:
- Cloudflare 코드와 도메인 로직이 혼재 (
lib/디렉토리) /utils,/helpers같은 의미 없는 디렉토리 없지만,/lib이 비슷한 역할- 디렉토리가 “조직도”가 아님 (책임이 명확하지 않음)
2. 파일 크기 규칙 부재
섹션 제목: “2. 파일 크기 규칙 부재”- 현재 파일들이 200-400줄을 넘는 경우 다수
- 함수 크기 제한 없음
- Worker entry point가 300줄 이상
3. 의존성 방향 문제
섹션 제목: “3. 의존성 방향 문제”현재 의존성:routes → services → lib (Cloudflare 코드 포함) ↓ Cloudflare API 직접 사용문제:
- Business Logic이 Edge를 알고 있음
- 테스트 불가능한 구조
- Cloudflare를 다른 인프라로 교체 불가능
4. 이름 규칙 문제
섹션 제목: “4. 이름 규칙 문제”현재:- lib/queue.ts # 너무 일반적- lib/d1.ts # 인프라 이름- services/research.service.ts # 행동이 아닌 명사문제:
- 파일 이름이 행동을 나타내지 않음
- 함수 이름이 일반적 (
process(),handle())
5. Entry Point 문제
섹션 제목: “5. Entry Point 문제”// 현재 index.ts (300줄 이상)export default { fetch: app.fetch, scheduled: async (event, env, ctx) => { // 로직이 포함됨 }, queue: async (batch, env, ctx) => { // 로직이 포함됨 }};문제:
- Entry point에 로직이 포함됨
- 얇지 않음
🎯 목표 구조 (실리콘밸리 표준)
섹션 제목: “🎯 목표 구조 (실리콘밸리 표준)”새로운 디렉토리 구조
섹션 제목: “새로운 디렉토리 구조”src/├── apps/ # Entry Points (Workers)│ ├── api/ # HTTP Worker│ │ └── index.ts # 얇은 진입점 (120 lines max)│ ├── queue/ # Queue Consumer Workers│ │ ├── research.ts # Research Queue Handler (150 lines max)│ │ ├── contract.ts # Contract Queue Handler│ │ └── liveness.ts # Liveness Queue Handler│ └── cron/ # Cron Workers│ └── metadata-sync.ts # Metadata Sync Cron (150 lines max)│├── domain/ # 순수 비즈니스 로직 (Cloudflare-free)│ ├── research/ # Research 도메인│ │ ├── discoverUrls.ts # URL 발견 로직 (200 lines max)│ │ ├── validateDataset.ts│ │ └── index.ts│ ├── seed/ # Seed 도메인│ │ ├── createSeedContract.ts│ │ ├── validateSeed.ts│ │ └── index.ts│ ├── liveness/ # Liveness 도메인│ │ ├── checkDomainHealth.ts│ │ ├── calculateLivenessStatus.ts│ │ └── index.ts│ └── metadata/ # Metadata 도메인│ ├── saveDatasetMetadata.ts│ ├── queryMetadata.ts│ └── index.ts│├── infra/ # 인프라 어댑터│ └── cloudflare/ # Cloudflare 전용 코드│ ├── d1/ # D1 어댑터│ │ ├── saveDatasetMetadata.ts│ │ ├── queryMetadata.ts│ │ └── index.ts│ ├── r2/ # R2 어댑터│ │ ├── storeDataset.ts│ │ ├── retrieveDataset.ts│ │ └── index.ts│ ├── kv/ # KV 어댑터│ │ ├── getDomainCache.ts│ │ ├── setDomainCache.ts│ │ └── index.ts│ ├── queue/ # Queue 어댑터│ │ ├── enqueueResearchJob.ts│ │ ├── enqueueContractJob.ts│ │ └── index.ts│ └── logpush/ # Logpush 어댑터│ ├── logDeployment.ts│ ├── logRequest.ts│ └── index.ts│├── schema/ # Zod 스키마만 (계약 정의)│ ├── research.ts # Research 스키마 (100 lines max)│ ├── seed.ts # Seed 스키마│ ├── queue.ts # Queue 메시지 스키마│ └── index.ts│├── lib/ # Cross-domain 유틸리티│ ├── crypto/ # 암호화│ ├── hash/ # 해시│ ├── time/ # 시간 유틸리티│ └── errors/ # 에러 타입│└── db/ # Drizzle ORM (향후) ├── tables.ts # 테이블 정의 └── queries.ts # 쿼리 함수
.github/└── scripts/ # CI/CD 스크립트 ├── ci.sh └── deploy.sh📋 주요 변경 사항
섹션 제목: “📋 주요 변경 사항”1. 파일 크기 규칙 (신규 추가)
섹션 제목: “1. 파일 크기 규칙 (신규 추가)”| 대상 | 최대 라인 수 | 초과 시 조치 |
|---|---|---|
| Worker entry point | 120 lines | 분해 필수 |
| Queue consumer | 150 lines | 분해 필수 |
| Domain module | 200 lines | 분해 필수 |
| Infra adapter | 150 lines | 분해 필수 |
| Zod schema | 100 lines | 분해 필수 |
| Library/util | 200 lines | 분해 필수 |
| Test file | 300 lines | 분해 권장 |
규칙:
- 200줄 초과 = 설계 실패
- 300줄 초과 = 즉시 분해
2. 함수 크기 규칙 (신규 추가)
섹션 제목: “2. 함수 크기 규칙 (신규 추가)”| 종류 | 최대 라인 수 | 초과 시 조치 |
|---|---|---|
| 일반 함수 | 30 lines | 분해 필수 |
| 비즈니스 로직 함수 | 50 lines | 분해 필수 |
| 핫패스 함수 | 20 lines | 분해 필수 |
규칙:
- 50줄 넘는 함수 = 두 개 이상의 책임
- 화면에 한 번에 보여야 함
3. 이름 규칙 강화
섹션 제목: “3. 이름 규칙 강화”파일 이름
섹션 제목: “파일 이름”// ❌ 현재lib/queue.tsservices/research.service.ts
// ✅ 개선infra/cloudflare/queue/enqueueResearchJob.tsdomain/research/discoverUrls.ts함수 이름
섹션 제목: “함수 이름”// ❌ 현재process()handle()run()
// ✅ 개선verifyInvoiceChecksum()storeHarEvidence()publishArticle()enqueueSeedJob()discoverUrlsFromSource()validateDatasetIntegrity()규칙:
- 이름이 길어질수록 재사용 가능성 증가
- 행동 중심 명명
- 파일 이름 = 함수 이름과 일치
4. 디렉토리 = 조직도
섹션 제목: “4. 디렉토리 = 조직도”// ❌ 금지/utils/helpers/common
// ✅ 권장/domain/research # Research 조직/domain/seed # Seed 조직/infra/cloudflare/d1 # D1 인프라 조직규칙:
- 디렉토리 = 조직
- 파일 = 직원
- One folder = One responsibility
5. Entry Point 얇게 만들기
섹션 제목: “5. Entry Point 얇게 만들기”// ✅ 올바른 패턴// apps/api/index.ts (120 lines max)import { handleHttpRequest } from "./http-handler";
export default { async fetch(req: Request, env: Bindings, ctx: ExecutionContext): Promise<Response> { return handleHttpRequest(req, env, ctx); },
async scheduled(event: ScheduledEvent, env: Bindings, ctx: ExecutionContext): Promise<void> { return handleScheduledEvent(event, env, ctx); },
async queue(batch: MessageBatch, env: Bindings, ctx: ExecutionContext): Promise<void> { return handleQueueBatch(batch, env, ctx); },};
// ❌ 잘못된 패턴export default { async fetch(req, env, ctx) { // 100줄의 로직... }};6. Business Logic은 Edge를 몰라야 함
섹션 제목: “6. Business Logic은 Edge를 몰라야 함”// ✅ 올바른 패턴export function discoverUrlsFromSource( input: DiscoverUrlsInput // 순수 데이터): DiscoverUrlsOutput { // Cloudflare API 없음 // Request 없음 // env 없음}
// ❌ 잘못된 패턴export function discoverUrls(req: Request, env: Bindings) { // Edge를 알고 있음}규칙:
- Domain → Infra → Edge 순서
- Domain은 순수 함수만
- 테스트 가능해야 함
7. Cloudflare 코드 격리
섹션 제목: “7. Cloudflare 코드 격리”// ✅ 올바른 패턴export async function saveDatasetMetadataToD1( db: D1Database, metadata: DatasetMetadata): Promise<void> { // D1 전용 코드}
// domain/metadata/saveDatasetMetadata.tsexport function saveDatasetMetadata( metadata: DatasetMetadata): SaveMetadataCommand { // Cloudflare 모름 return { type: "save", payload: metadata };}규칙:
/infra/cloudflare에만 Cloudflare API- Domain은 인프라를 모름
- Adapter 패턴 사용
8. Queue 메시지는 API 계약
섹션 제목: “8. Queue 메시지는 API 계약”// ✅ 올바른 패턴export const ResearchJobSchema = z.object({ jobId: z.string().uuid(), source: z.string().url(), country: z.enum(["SG", "GB", "US"]), requestedAt: z.string().datetime(),});
export type ResearchJob = z.infer<typeof ResearchJobSchema>;
// Producer와 Consumer가 같은 스키마 사용import { ResearchJobSchema } from "../../schema/queue/researchJob";
// ❌ 잘못된 패턴await queue.send({ type: "research", data: unknownData });규칙:
- Queue = Microservice boundary
- Zod 스키마로 계약 정의
- Producer/Consumer가 같은 스키마 공유
9. Import 방향 규칙
섹션 제목: “9. Import 방향 규칙”Allowed:domain → infraapps → domainapps → infra
Forbidden:domain → appsdomain → queue (직접)infra → domain규칙:
- Domain은 최상위 레벨
- Apps는 Domain과 Infra를 사용
- Infra는 Domain을 모름
10. 테스트 가능성 규칙
섹션 제목: “10. 테스트 가능성 규칙”// ✅ 테스트 가능export function discoverUrls(input: DiscoverUrlsInput): DiscoverUrlsOutput { // new Request() 없음 // env.KV 없음 // ctx.waitUntil 없음}
// ❌ 테스트 불가능export async function discoverUrls(req: Request, env: Bindings) { await env.KV.get("key"); ctx.waitUntil(...);}규칙:
- 모든 함수는 순수 함수 또는 의존성 주입
- Cloudflare API 직접 사용 금지
- Domain 함수는 단위 테스트 가능해야 함
11. 재사용 가능성 체크리스트
섹션 제목: “11. 재사용 가능성 체크리스트”새 파일 생성 전 질문:
| 질문 | Yes/No |
|---|---|
| Queue Consumer에서 쓸 수 있는가? | |
| Cron Job에서 쓸 수 있는가? | |
| API Handler에서 쓸 수 있는가? | |
| 다른 Worker에서 쓸 수 있는가? |
3개 이상 Yes여야 생성 가능
12. Logpush 통합
섹션 제목: “12. Logpush 통합”// ✅ 올바른 패턴export function logDeployment( version: string, commit: string, environment: string): void { console.log(JSON.stringify({ type: "deployment", version, commit, environment, timestamp: new Date().toISOString(), }));}
// 모든 Worker entry point에서 호출logDeployment(BUILD_VERSION, GIT_COMMIT, CF_ENV);규칙:
- 모든 Worker에서 배포 정보 로깅
- 구조화된 JSON 로그
- Logpush → R2 → 법적 증거
🔄 마이그레이션 전략
섹션 제목: “🔄 마이그레이션 전략”Phase 1: 구조 재구성 (점진적)
섹션 제목: “Phase 1: 구조 재구성 (점진적)”-
새 디렉토리 생성
src/├── apps/ # 신규├── domain/ # 신규├── infra/ # 신규└── schema/ # 기존 schemas/ 이동 -
기존 코드 점진적 이동
lib/domain.ts→domain/research/normalizeDomain.tslib/d1.ts→infra/cloudflare/d1/lib/r2.ts→infra/cloudflare/r2/lib/queue.ts→infra/cloudflare/queue/
-
Entry Point 얇게 만들기
src/index.ts→apps/api/index.ts- 로직을 별도 파일로 분리
Phase 2: 파일 분해
섹션 제목: “Phase 2: 파일 분해”-
큰 파일 분해
- 200줄 이상 파일 식별
- 책임별로 분해
- 함수 크기 50줄 이하로 제한
-
이름 개선
- 일반적인 이름 → 행동 중심 이름
- 파일 이름 = 주요 함수 이름
Phase 3: 의존성 정리
섹션 제목: “Phase 3: 의존성 정리”-
Import 방향 수정
- Domain → Infra 의존성 제거
- Apps → Domain/Infra 의존성만 허용
-
테스트 가능성 개선
- Cloudflare API 직접 사용 제거
- 의존성 주입 패턴 적용
📊 예상 효과
섹션 제목: “📊 예상 효과”재사용성
섹션 제목: “재사용성”- ✅ Queue Consumer 재사용 가능
- ✅ Cron Job 재사용 가능
- ✅ 다른 Worker에서 재사용 가능
유지보수성
섹션 제목: “유지보수성”- ✅ 10년 후에도 리팩터링 가능
- ✅ Cloudflare 교체 가능
- ✅ 마이크로서비스화 가능
테스트 가능성
섹션 제목: “테스트 가능성”- ✅ 단위 테스트 쉬움
- ✅ 통합 테스트 쉬움
- ✅ Mock 불필요
확장성
섹션 제목: “확장성”- ✅ Fork-News, ShotCert, OCL 등 다른 사업에 재사용
- ✅ 하나의 엔진으로 10개의 사업 가능
⚠️ 주의사항
섹션 제목: “⚠️ 주의사항”점진적 마이그레이션
섹션 제목: “점진적 마이그레이션”- 한 번에 모든 것을 바꾸지 말 것
- 기존 코드와 새 코드 공존 허용
- 단계적으로 마이그레이션
하위 호환성
섹션 제목: “하위 호환성”- 기존 API 엔드포인트 유지
- 기존 Queue 메시지 형식 유지
- 점진적 개선
문서화
섹션 제목: “문서화”- 새로운 구조 문서화
- 마이그레이션 가이드 제공
- 팀 교육
📝 .cursorrules 업데이트 항목
섹션 제목: “📝 .cursorrules 업데이트 항목”추가할 섹션
섹션 제목: “추가할 섹션”- 파일 크기 규칙 (신규)
- 함수 크기 규칙 (신규)
- 디렉토리 구조 표준 (대폭 수정)
- 이름 규칙 강화 (수정)
- Entry Point 규칙 (신규)
- Business Logic 격리 규칙 (신규)
- Cloudflare 코드 격리 규칙 (신규)
- Queue 메시지 계약 규칙 (신규)
- Import 방향 규칙 (신규)
- 테스트 가능성 규칙 (신규)
- 재사용 가능성 체크리스트 (신규)
- Logpush 통합 규칙 (신규)
수정할 섹션
섹션 제목: “수정할 섹션”- Directory Structure - 완전히 재작성
- Coding Conventions - 파일/함수 크기 규칙 추가
- Architecture Layers - Domain/Infra 분리 명시
- Common Mistakes - 새로운 규칙 위반 사례 추가
삭제할 섹션
섹션 제목: “삭제할 섹션”- 없음 (기존 내용은 유지하되 확장)
🎯 최종 목표
섹션 제목: “🎯 최종 목표”“Cloudflare + Queue + Logpush는 서버가 아니라 디지털 증거 공장”
이 규율을 따르면:
- ✅ 10년 후에도 유지 가능
- ✅ 여러 사업에 재사용 가능
- ✅ 법적 증거 확보 가능
- ✅ 마이크로서비스화 가능