Skip to content

Cursor Rules Missing Content

This content is not available in your language yet.

  1. GitHub Actions & CI/CD 섹션 존재
  2. Shell First 전략 언급
  3. wrangler 기본 사용법 (deploy 명령)
  4. Testing Guidelines 섹션 존재
  • ACTIONS_STEP_DEBUG 설정 방법
  • ACTIONS_RUNNER_DEBUG 설정 방법
  • ❌ tmate SSH 세션 사용법
  • ❌ 로그 그룹핑 방법
  • ❌ 환경 변수 출력 방법
  • ❌ 파일 구조 출력 방법
  • ❌ 로컬에서 CI 스크립트 실행 방법
  • ❌ CI와 동일한 환경 재현 방법
  • ❌ 로컬에서 CI 스크립트 테스트 방법
  • ❌ 환경 변수 설정 방법
  • wrangler dev 사용법
  • wrangler dev --local vs --remote
  • wrangler deploy --dry-run 상세 사용법
  • wrangler d1 execute 사용법
  • wrangler d1 migrations apply 사용법
  • wrangler kv namespace 관리
  • wrangler queues 관리
  • wrangler r2 관리
  • ❌ Vitest 설정 방법
  • ❌ Cloudflare Workers 테스트 (vitest-pool-workers)
  • ❌ Domain 함수 단위 테스트
  • ❌ Infra 어댑터 통합 테스트
  • ❌ Mock 사용법

1. GitHub Actions 디버깅 환경 (신규 섹션)

섹션 제목: “1. GitHub Actions 디버깅 환경 (신규 섹션)”
## GitHub Actions 디버깅 환경
### 1. 디버그 모드 활성화
```yaml
# ✅ 올바른 패턴: 디버그 모드 활성화
jobs:
deploy:
env:
ACTIONS_STEP_DEBUG: true
ACTIONS_RUNNER_DEBUG: true
steps:
- name: Setup tmate session (on failure)
if: failure()
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-this-repository: true
timeout-minutes: 30
.github/scripts/lib/logging.sh
log_group_start "Environment Variables"
env | sort
log_group_end
log_group_start "File Structure"
find . -type f | head -20
log_group_end

실패 시 tmate 세션으로 VM에 SSH 접속 가능

### 2. 로컬 CI 환경 테스트 (신규 섹션)
```markdown
## 로컬 CI 환경 테스트
### 1. CI 스크립트 로컬 실행
```bash
# ✅ 올바른 패턴: 로컬에서 CI와 동일하게 실행
./.github/scripts/ci.sh
# 특정 단계만 실행
CI_MODE=deploy DEPLOY_ENV=staging ./.github/scripts/ci.sh
# 환경 변수 설정
export GITHUB_SHA=$(git rev-parse HEAD)
export BUILD_VERSION=$(date -u +%Y-%m-%dT%H%M%SZ)
./.github/scripts/ci.sh
Terminal window
# CI와 동일한 환경 변수 설정
export ACTIONS_STEP_DEBUG=true
export GITHUB_SHA=$(git rev-parse HEAD)
export GITHUB_REPOSITORY="owner/repo"
export CLOUDFLARE_API_TOKEN="your-token"
export CLOUDFLARE_ACCOUNT_ID="your-account-id"
# CI 스크립트 실행
./.github/scripts/ci.sh
### 3. Wrangler 상세 사용법 (확장 필요)
```markdown
## Wrangler 사용법
### 1. 개발 환경
```bash
# ✅ 로컬 개발 (로컬 D1/KV 사용)
wrangler dev --local
# ✅ 원격 개발 (Cloudflare 리소스 사용)
wrangler dev --remote
# ✅ 특정 환경
wrangler dev --env staging
Terminal window
# ✅ Dry-run 검증
wrangler deploy --dry-run --env staging
# ✅ Bundle 정보 확인
wrangler deploy --dry-run --env staging > bundle-info.txt
Terminal window
# ✅ 마이그레이션 실행
wrangler d1 migrations apply METADATA_DB --env staging
# ✅ SQL 직접 실행
wrangler d1 execute METADATA_DB --env staging --file=./migrations/001_init.sql
# ✅ 쿼리 실행
wrangler d1 execute METADATA_DB --env staging --command="SELECT * FROM dataset_metadata LIMIT 10"
Terminal window
# ✅ Namespace 생성
wrangler kv namespace create DOMAIN_KV --env staging
# ✅ 키-값 설정
wrangler kv key put "domain:example.com" '{"data": "value"}' --namespace-id=xxx --env staging
# ✅ 키-값 조회
wrangler kv key get "domain:example.com" --namespace-id=xxx --env staging
Terminal window
# ✅ Queue 생성
wrangler queues create newsfork-research-staging --env staging
# ✅ Queue 목록
wrangler queues list
### 4. Vitest 테스트 (신규 섹션)
```markdown
## Vitest 테스트
### 1. Vitest 설정
```typescript
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
pool: "@cloudflare/vitest-pool-workers",
poolOptions: {
workers: {
wrangler: { configPath: "./wrangler.jsonc" },
},
},
},
});
domain/research/discoverUrlsFromSource.test.ts
// ✅ Domain 함수 테스트 (Mock 불필요)
import { describe, it, expect } from "vitest";
import { discoverUrlsFromSource } from "./discoverUrlsFromSource";
describe("discoverUrlsFromSource", () => {
it("should discover URLs from source", () => {
const input = { source: "https://example.com" };
const result = discoverUrlsFromSource(input);
expect(result.urls).toHaveLength(10);
});
});
infra/cloudflare/d1/saveDatasetMetadataToD1.test.ts
// ✅ Infra 어댑터 테스트 (Mock 사용)
import { describe, it, expect, vi } from "vitest";
import { saveDatasetMetadataToD1 } from "./saveDatasetMetadataToD1";
describe("saveDatasetMetadataToD1", () => {
it("should save metadata to D1", async () => {
const mockD1 = {
prepare: vi.fn().mockReturnValue({
bind: vi.fn().mockReturnValue({
run: vi.fn().mockResolvedValue({ success: true }),
}),
}),
} as unknown as D1Database;
await saveDatasetMetadataToD1(mockD1, metadata);
expect(mockD1.prepare).toHaveBeenCalled();
});
});
apps/api/index.test.ts
// ✅ Workers 통합 테스트
import { describe, it, expect } from "vitest";
import { env, createExecutionContext } from "cloudflare:test";
import app from "./index";
describe("API", () => {
it("should handle HTTP request", async () => {
const request = new Request("https://example.com/api/v1/research/SG/news/2026-01-27");
const ctx = createExecutionContext();
const response = await app.fetch(request, env, ctx);
expect(response.status).toBe(200);
});
});
Terminal window
# ✅ 로컬 테스트
pnpm test
# ✅ Cloudflare Workers 환경 테스트
pnpm test:local
# ✅ 특정 파일만 테스트
pnpm test domain/research/discoverUrlsFromSource.test.ts