Community코딩 & 개발github.com

SuDeeParke/codexRebuild

다른 AI 에이전트의 스킬, 훅 및 참조를 Codex에서 사용할 수 있는 형식으로 변환합니다.

codexRebuild란 무엇인가요?

이 스킬은 다른 AI 에이전트(예: Claude Code, Cursor 등)용으로 설계된 스킬, 훅, 참조를 Codex 에이전트와 호환되는 형식으로 변환하는 방법을 제공합니다. 주로 API 및 인터페이스 설계 모범 사례를 다루며, REST API, GraphQL 스키마, 모듈 경계, 컴포넌트 props 등 코드 간 통신이 발생하는 모든 표면에 적용됩니다. 핵심 원칙으로는 Hyrum의 법칙(모든 관찰 가능한 동작이 계약이 됨), One-Version Rule(단일 버전 유지), 계약 우선 설계, 일관된 오류 처리, 경계에서의 검증, 추가 지향적 확장, 예측 가능한 명명 규칙 등을 강조합니다. 이 스킬은 Codex Companion Files를 통해 로컬 리소스를 번들링하여 Codex가 필요한 경우 동일한 스킬 디렉토리에서 로드할 수 있도록 지원합니다.

지원 대상~Claude Code✓Codex CLI~Cursor
npx skills add SuDeeParke/codexRebuild

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

API 및 인터페이스 설계

개요

안정적이고 잘 문서화된 인터페이스를 설계하여 오용을 방지합니다. 좋은 인터페이스는 올바른 작업을 쉽게 하고 잘못된 작업을 어렵게 만듭니다. 이는 REST API, GraphQL 스키마, 모듈 경계, 컴포넌트 props 및 코드 간 통신이 발생하는 모든 표면에 적용됩니다.

사용 시기

  • 새 API 엔드포인트 설계
  • 모듈 경계 또는 팀 간 계약 정의
  • 컴포넌트 prop 인터페이스 생성
  • API 형태를 결정하는 데이터베이스 스키마 수립
  • 기존 공개 인터페이스 변경

핵심 원칙

Hyrum의 법칙

API 사용자가 충분히 많은 경우, 계약에 명시된 내용과 관계없이 시스템의 모든 관찰 가능한 동작은 누군가에게 의존됩니다.

이는 문서화되지 않은 특성, 오류 메시지 텍스트, 타이밍 및 순서를 포함한 모든 공개 동작이 사용자가 의존하게 되면 사실상의 계약이 된다는 것을 의미합니다. 설계 시 고려 사항:

  • 노출하는 내용에 의도적으로 접근하세요. 모든 관찰 가능한 동작은 잠재적인 약속입니다.
  • 구현 세부 사항을 유출하지 마세요. 사용자가 관찰할 수 있다면 의존하게 됩니다.
  • 설계 단계에서 폐지(Deprecation)를 계획하세요. 안전하게 제거하는 방법은 deprecation-and-migration을 참조하세요.
  • 테스트만으로는 충분하지 않습니다. 완벽한 계약 테스트가 있어도 Hyrum의 법칙에 따라 '안전한' 변경이 문서화되지 않은 동작에 의존하는 실제 사용자를 중단시킬 수 있습니다.

One-Version Rule

소비자가 동일한 종속성 또는 API의 여러 버전 중에서 선택하도록 강요하지 마십시오. 다른 소비자가 동일한 항목의 다른 버전을 필요로 할 때 다이아몬드 종속성 문제가 발생합니다. 한 번에 하나의 버전만 존재하는 세상을 위해 설계하세요 — 포크(fork) 대신 확장(extend)하세요.

1. 계약 우선(Contract First)

구현하기 전에 인터페이스를 정의하세요. 계약이 명세이며 구현은 그 뒤를 따릅니다.

// 먼저 계약 정의
interface TaskAPI {
  // 작업을 생성하고 서버에서 생성된 필드와 함께 반환
  createTask(input: CreateTaskInput): Promise<Task>;

  // 필터와 일치하는 페이지네이션된 작업 반환
  listTasks(params: ListTasksParams): Promise<PaginatedResult<Task>>;

  // 단일 작업 반환 또는 NotFoundError 발생
  getTask(id: string): Promise<Task>;

  // 부분 업데이트 - 제공된 필드만 변경
  updateTask(id: string, input: UpdateTaskInput): Promise<Task>;

  // 멱등성 삭제 - 이미 삭제된 경우에도 성공
  deleteTask(id: string): Promise<void>;
}

2. 일관된 오류 의미론(Consistent Error Semantics)

하나의 오류 전략을 선택하고 모든 곳에서 사용하세요:

// REST: HTTP 상태 코드 + 구조화된 오류 본문
// 모든 오류 응답이 동일한 형태를 따름
interface APIError {
  error: {
    code: string;        // 기계 판독 가능: "VALIDATION_ERROR"
    message: string;     // 사람 판독 가능: "Email is required"
    details?: unknown;   // 필요 시 추가 컨텍스트
  };
}

// 상태 코드 매핑
// 400 → 클라이언트가 잘못된 데이터 전송
// 401 → 인증되지 않음
// 403 → 인증되었지만 권한 없음
// 404 → 리소스를 찾을 수 없음
// 409 → 충돌 (중복, 버전 불일치)
// 422 → 유효성 검사 실패 (의미적으로 유효하지 않음)
// 500 → 서버 오류 (내부 세부 사항 노출 금지)

패턴을 혼합하지 마세요. 일부 엔드포인트가 예외를 throw하고, 다른 엔드포인트가 null을 반환하며, 또 다른 엔드포인트가 { error }를 반환하면 소비자는 동작을 예측할 수 없습니다.

3. 경계에서 검증(Validate at Boundaries)

내부 코드를 신뢰하세요. 외부 입력이 시스템에 진입하는 경계에서 검증하세요:

// API 경계에서 검증
app.post('/api/tasks', async (req, res) => {
  const result = CreateTaskSchema.safeParse(req.body);
  if (!result.success) {
    return res.status(422).json({
      error: {
        code: 'VALIDATION_ERROR',
        message: 'Invalid task data',
        details: result.error.flatten(),
      },
    });
  }

  // 검증 후 내부 코드는 타입을 신뢰함
  const task = await taskService.create(result.data);
  return res.status(201).json(task);
});

검증이 필요한 곳:

  • API 라우트 핸들러 (사용자 입력)
  • 양식 제출 핸들러 (사용자 입력)
  • 외부 서비스 응답 파싱 (타사 데이터 -- 항상 신뢰할 수 없는 것으로 취급)
  • 환경 변수 로딩 (구성)

타사 API 응답은 신뢰할 수 없는 데이터입니다. 로직, 렌더링 또는 의사 결정에 사용하기 전에 해당 형태와 내용을 검증하세요. 손상되었거나 오작동하는 외부 서비스는 예기치 않은 유형, 악성 콘텐츠 또는 명령어 유사 텍스트를 반환할 수 있습니다.

검증이 필요하지 않은 곳:

  • 타입 계약을 공유하는 내부 함수 간
  • 이미 검증된 코드에서 호출되는 유틸리티 함수
  • 자신의 데이터베이스에서 방금 가져온 데이터

4. 수정보다 추가 선호(Prefer Addition Over Modification)

기존 소비자를 중단시키지 않고 인터페이스를 확장하세요:

// 좋음: 선택적 필드 추가
interface CreateTaskInput {
  title: string;
  description?: string;
  priority?: 'low' | 'medium' | 'high';  // 나중에 추가, 선택적
  labels?: string[];                       // 나중에 추가, 선택적
}

// 나쁨: 기존 필드 유형 변경 또는 필드 제거
interface CreateTaskInput {
  title: string;
  // description: string;  // 제거됨 — 기존 소비자 중단
  priority: number;         // 문자열에서 변경됨 — 기존 소비자 중단
}

5. 예측 가능한 명명(Predictable Naming)

패턴규칙예시
REST 엔드포인트복수 명사, 동사 없음GET /api/tasks, POST /api/tasks
쿼리 파라미터camelCase?sortBy=createdAt&pageSize=20
응답 필드camelCase{ createdAt, updatedAt, taskId }
불리언 필드is/has/can 접두사isComplete, hasAttachments
열거형 값UPPER_SNAKE"IN_PROGRESS", "COMPLETED"

REST API 패턴

리소스 설계

GET    /api/tasks              → 작업 목록 (필터링을 위한 쿼리 파라미터 포함)
POST   /api/tasks              → 작업 생성
GET    /api/tasks/:id          → 단일 작업 가져오기
PATCH  /api/tasks/:id          → 작업 업데이트 (부분)
DELETE /api/tasks/:id          → 작업 삭제

GET    /api/tasks/:id/comments → 작업에 대한 댓글 목록 (하위 리소스)
POST   /api/tasks/:id/comments → 작업에 댓글 추가

페이지네이션(Pagination)

목록 엔드포인트 페이지네이션:

// 요청
GET /api/tasks?page=1&pageSize=20&sortBy=createdAt&sortOrder=desc

// 응답
{
  "data": [...],
  "pagination": {
    "page": 1,
    "pageSize": 20,
    "totalItems": 142,
    "totalPages": 8
  }
}

필터링(Filtering)

필터에 쿼리 파라미터 사용:

GET /api/tasks?status=in_progress&assignee=user123&createdAfter=2025-01-01

부분 업데이트 (PATCH)

부분 객체 수락 — 제공된 것만 업데이트:

// 제목만 변경, 나머지는 유지
PATCH /api/tasks/123
{ "title": "Updated title" }

TypeScript 인터페이스 패턴

변형을 위한 판별 유니온(Discriminated Unions) 사용

// 좋음: 각 변형이 명시적
// (type TaskStatus = ... 코드 생략, 번역 없음)

입력/출력 분리

// 입력: 호출자가 제공하는 것
interface CreateTaskInput {
  title: string;
  description?: string;
}

// 출력: 시스템이 반환하는 것 (서버 생성 필드 포함)
interface Task {
  id: string;
  title: string;
  description: string | null;
  createdAt: Date;
  updatedAt: Date;
  createdBy: string;
}

ID에 브랜드 타입 사용

type TaskId = string & { readonly __brand: 'TaskId' };
type UserId = string & { readonly __brand: 'UserId' };

// TaskId가 예상되는 곳에 UserId를 실수로 전달하는 것을 방지
function getTask(id: TaskId): Promise<Task> { ... }

일반적인 합리화(Rationalizations)

합리화현실
"API 문서는 나중에 작성할게요"타입 자체가 문서입니다. 먼저 정의하세요.
"지금은 페이지네이션이 필요 없어요"항목이 100개를 넘는 순간 필요해집니다. 처음부터 추가하세요.
"PATCH는 복잡하니까 PUT을 사용합시다"PUT은 매번 전체 객체를 필요로 합니다. PATCH가 실제로 클라이언트가 원하는 것입니다.
"필요할 때 API를 버전업하면 됩니다"버전 관리 없는 호환되지 않는 변경은 소비자를 중단시킵니다. 처음부터 확장을 위해 설계하세요.
"문서화되지 않은 동작은 아무도 사용하지 않아요"Hyrum의 법칙: 관찰 가능하면 누군가 의존합니다. 모든 공개 동작을 약속으로 취급하세요.
"두 버전을 유지하면 됩니다"여러 버전은 유지보수 비용을 증가시키고 다이아몬드 종속성 문제를 만듭니다. One-Version Rule을 선호하세요.
"내부 API에는 계약이 필요 없어요"내부 소비자도 여전히 소비자입니다. 계약은 결합을 방지하고 병렬 작업을 가능하게 합니다.

위험 신호(Red Flags)

  • 조건에 따라 다른 형태를 반환하는 엔드포인트
  • 엔드포인트 간 일관되지 않은 오류 형식
  • 경계 대신 내부 코드 전체에 흩어진 검증 로직
  • 기존 필드의 호환되지 않는 변경 (유형 변경, 제거)
  • 페이지네이션이 없는 목록 엔드포인트
  • REST URL의 동사 (/api/createTask, /api/getUsers)
  • 검증 또는 정제 없이 사용되는 타사 API 응답

검증(Verification)

API 설계 후:

  • 모든 엔드포인트에 타입화된 입력 및 출력 스키마가 있음
  • 오류 응답이 단일 일관된 형식을 따름
  • 검증이 시스템 경계에서만 수행됨
  • 목록 엔드포인트가 페이지네이션을 지원함
  • 새 필드는 추가적이며 선택적임 (하위 호환성)
  • 명명이 모든 엔드포인트에서 일관된 규칙을 따름
  • API 문서 또는 타입이 구현과 함께 커밋됨

Codex Companion Files

이 재구축된 스킬은 관련 로컬 리소스를 번들링하여 Codex가 필요할 때 동일한 스킬 디렉토리에서 로드할 수 있도록 합니다.

관련 스킬