Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions .claude/rules/patchlogr-core.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
paths:
- "packages/patchlogr-core/**"
---

# @patchlogr/core

API 스펙 파티셔닝, 변경 감지, 버전 범프 계산 등 핵심 비즈니스 로직 패키지.

## Exported Functions

### Partition (해시 기반 트리 생성)

```typescript
// 태그별로 operation 그룹화
function partitionByTag(spec: CanonicalSpec): PartitionedSpec<string>;

// HTTP 메서드별로 그룹화
function partitionByMethod(spec: CanonicalSpec): PartitionedSpec<string>;

// 노드 생성 유틸리티
function createNode<K, V>(key: K, hash: string, children: HashNode<K, V>[]): HashNode<K, V>;
function createLeafNode<K, V>(key: K, hash: string, value: V): HashNode<K, V>;
function createHashedLeaf<K, V>(key: K, value: V): HashNode<K, V>; // 자동 해시 생성
function createHashedNode<K, V>(key: K, children: HashNode<K, V>[]): HashNode<K, V>; // 자동 해시 생성
```

### Diff (변경 감지) - 현재 내부 모듈, 향후 export 예정

```typescript
// 두 PartitionedSpec 비교
function diffSpec<K>(base: PartitionedSpec<K>, head: PartitionedSpec<K>): SpecChangeSet<K>;

// 버전 범프 권장
function detectVersionBump<K>(changeSet: SpecChangeSet<K>): VersionBumpResult;
```

## Exported Types

### Partition Types

```typescript
type Hash = string;

type HashNode<K = string, V = unknown> = {
type: "node" | "leaf";
key: K;
hash: Hash;
children?: HashNode<K, V>[]; // type: "node"일 때
value?: V; // type: "leaf"일 때
};

type PartitionedSpec<K = string, V = unknown> = {
root: HashNode<K, V>;
metadata: Record<string, unknown>;
hashObjects: HashObject<V>[];
};
```

### Diff Types (내부 모듈)

```typescript
type ChangeType = "added" | "removed" | "modified" | "type_changed";

type SpecChange<K = string> = {
type: ChangeType;
path: K[];
key: K;
baseHash?: string;
headHash?: string;
baseNodeType?: "node" | "leaf";
headNodeType?: "node" | "leaf";
};

type SpecChangeSet<K = string> = {
baseHash: string;
headHash: string;
changes: SpecChange<K>[];
};

type VersionBump = "major" | "minor" | "patch" | "none";

type VersionBumpResult = {
recommendedBump: VersionBump;
isBreaking: boolean;
reasons: string[];
};
```

## 버전 범프 분류 기준

- **major** (Breaking): `removed`, `type_changed`
- **minor** (New feature): `added`
- **patch** (Bug fix): `modified` (현재는 minor로 처리)

## 의존성

- `@patchlogr/types`: CanonicalSpec 등 타입
- `@patchlogr/oas`: 전처리된 스펙 사용
- `fast-json-stable-stringify`: 결정적 해시 생성
46 changes: 46 additions & 0 deletions .claude/rules/patchlogr-inspector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
paths:
- "packages/patchlogr-inspector/**"
---

# @patchlogr/inspector

## Overview

API 변경사항을 시각적으로 리뷰할 수 있는 웹 UI 도구. Storybook처럼 로컬에서 띄워서 사용.

## 핵심 기능

- **Diff 시각화**: `@patchlogr/core`의 diff 결과를 side-by-side 뷰로 표시
- **Breaking Change 강조**: Breaking change를 명확하게 표시
- **Operation별 상세 뷰**: Parameters, Request Body, Responses 탭으로 구분
- **변경 타입 표시**: Added (초록), Removed (빨강), Modified (파랑) 구분

## 패키지 구조

```
packages/patchlogr-inspector/
client/ # React 기반 웹 UI
server/ # diff 결과를 서빙하는 dev server
```

## 의존성

- `@patchlogr/core`: `SpecChangeSet`, `VersionBumpResult` 타입 소비
- `@patchlogr/types`: `CanonicalSpec`, `CanonicalOperation` 등 타입 참조

## 아키텍처 결정

### 모노레포 유지 (별도 레포 분리 X)

**이유**:
1. **타이트한 타입 의존성**: core의 diff 결과 타입에 직접 의존
2. **버전 동기화 필요**: core 변경 시 inspector도 함께 수정 필요
3. **개발 편의성**: core 수정 후 바로 inspector에서 확인 가능
4. **Storybook 패턴**: 메인 프로젝트와 같은 레포에서 관리하는 것이 일반적

## 개발 가이드

- client는 React + Vite 사용 예정
- server는 Express 또는 Fastify 기반 dev server
- TypeScript strict mode 유지
65 changes: 65 additions & 0 deletions .claude/rules/patchlogr-oas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
paths:
- "packages/patchlogr-oas/**"
---

# @patchlogr/oas

OpenAPI 문서를 표준화된 `CanonicalSpec` 형태로 변환하는 파이프라인 패키지.

## 핵심 역할

- OpenAPI v2/v3 문서를 입력받아 `@patchlogr/types`에 정의된 표준화된 형태로 변환
- `allOf`, `anyOf`, `oneOf` 같은 composition을 펼쳐서 flat한 구조로 만듦
- `$ref` 참조를 모두 역참조(dereference)하여 self-contained 문서 생성
- v2/v3 차이를 추상화하여 일관된 데이터 구조 제공

## Exported Functions

### preprocessOASDocument

```typescript
function preprocessOASDocument(
doc: OpenAPI.Document,
options?: OASStageOptions,
): Promise<OASStageContext>;
```

**파이프라인 단계**:

1. `OASBundleStage` - 외부 참조($ref) 번들링
2. `OASValidationStage` - OpenAPI 스펙 유효성 검증
3. `OASDereferenceStage` - $ref 참조를 실제 객체로 역참조
4. `OASCanonicalizeStage` - allOf/anyOf/oneOf 펼치고 `CanonicalSpec`으로 변환

**사용 예시**:

```typescript
import { preprocessOASDocument } from "@patchlogr/oas";

const result = await preprocessOASDocument(oasDoc, { skipValidation: false });
const canonicalSpec = result.canonicalSpec;
```

## Exported Types

```typescript
type OASStageOptions = {
skipValidation?: boolean;
};
```

## 내부 구조

```
src/
pipeline/ # 파이프라인 인프라
canonicalize/
v2/ # OpenAPI v2 → CanonicalSpec 변환
v3/ # OpenAPI v3 → CanonicalSpec 변환
```

## 의존성

- `@patchlogr/types`: CanonicalSpec 등 타입
- `@apidevtools/swagger-parser`: OAS 파싱/검증/역참조
117 changes: 117 additions & 0 deletions .claude/rules/patchlogr-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
---
paths:
- "packages/patchlogr-types/**"
---

# @patchlogr/types

OpenAPI 스펙을 표준화(Canonicalization)한 타입 정의 패키지.

## 설계 목적

OpenAPI v2/v3의 `allOf`, `anyOf`, `oneOf` 같은 composition을 모두 펼쳐서(flatten) diff 비교가 용이한 flat한 구조로 정의. 실제 변환은 `@patchlogr/oas`에서 수행.

## Exported Types

### Utility Types

```typescript
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD" | "TRACE";
type OperationKey = `${HTTPMethod} ${string}`; // e.g. "GET /users/{id}"
```

### Schema Types (allOf/anyOf/oneOf 펼친 형태)

```typescript
type CanonicalSchema = {
type?: string | string[];
format?: string;
properties?: Record<string, CanonicalSchemaProperty>;
items?: CanonicalSchema | CanonicalSchema[];
enum?: unknown[];
default?: unknown;
description?: string;
[key: string]: unknown; // minimum, maximum, pattern 등
};

type CanonicalSchemaProperty = CanonicalSchema & {
required?: boolean; // required 배열에서 추출하여 필드에 직접 표시
};
```

### Request/Response Types

```typescript
type CanonicalParam = {
name: string;
in: "path" | "query" | "header" | "cookie";
required: boolean;
schema?: CanonicalSchema;
deprecated?: boolean;
description?: string;
};

type CanonicalBody = {
required: boolean;
content: Record<string, { schema?: CanonicalSchema }>;
};

type CanonicalMessage = {
params: CanonicalParam[];
body?: CanonicalBody;
};

type CanonicalHeader = {
required?: boolean;
schema?: CanonicalSchema;
deprecated?: boolean;
description?: string;
};

type CanonicalResponse = {
description?: string;
headers?: Record<string, CanonicalHeader>;
content?: CanonicalBody["content"];
};
```

### Operation Types

```typescript
type CanonicalSecurityRequirement = Record<string, string[]>;

type CanonicalOperationContract = {
key: OperationKey;
method: HTTPMethod;
path: string;
deprecated?: boolean;
security?: CanonicalSecurityRequirement[];
request: CanonicalMessage;
responses: Record<string, CanonicalResponse>;
};

type CanonicalOperationDoc = {
operationId?: string;
tags?: string[];
summary?: string;
description?: string;
};

type CanonicalOperation = CanonicalOperationContract & {
doc?: CanonicalOperationDoc;
};
```

### Spec Type

```typescript
type CanonicalSpec = {
info?: { title?: string; version?: string; description?: string };
security?: CanonicalSecurityRequirement[];
operations: Record<OperationKey, CanonicalOperation>;
};
```

## 의존성

- 없음 (기반 타입 레이어)
39 changes: 18 additions & 21 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
{
"hooks": {
"pre-commit": "yarn lint && yarn typecheck && yarn test"
},
"permissions": {
"allowedCommands": [
"yarn build",
"yarn test",
"yarn test:coverage",
"yarn lint",
"yarn lint:fix",
"yarn typecheck",
"yarn clean",
"git status",
"git diff",
"git log",
"git branch",
"ls",
"cat",
"pwd"
]
}
"permissions": {
"allowedCommands": [
"yarn build",
"yarn test",
"yarn test:coverage",
"yarn lint",
"yarn lint:fix",
"yarn typecheck",
"yarn clean",
"git status",
"git diff",
"git log",
"git branch",
"ls",
"cat",
"pwd"
]
}
}
Loading
Loading