docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거

Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
This commit is contained in:
Antigravity Agent
2026-07-05 00:33:48 +09:00
parent 1cfd3bbb56
commit 9148c358d0
6455 changed files with 1 additions and 86875 deletions
@@ -0,0 +1,334 @@
---
id: testing-pact-contract-deep
title: Pact Contract Testing — consumer-driven contracts
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [testing, contract, vibe-coding]
tech_stack: { language: "TS / Java", applicable_to: ["Backend", "Testing"] }
applied_in: []
aliases: [Pact, contract testing, consumer driven, schema test, OpenAPI test, broker]
---
# Pact Contract Testing
> Microservice / API consumer-provider 의 schema mismatch = production 발견. **Pact: consumer 가 contract 정의 → broker → provider verify**. E2E 보다 빠름 + 안정.
## 📖 핵심 개념
- Consumer 가 expected interaction 정의.
- Provider 가 verify (모든 expectation 처리).
- Broker = central registry (Pactflow / OSS).
- Bi-directional (OpenAPI 비교 도).
## 💻 코드 패턴
### Consumer test (TS)
```ts
import { PactV3, MatchersV3 } from '@pact-foundation/pact';
const { like, integer } = MatchersV3;
const provider = new PactV3({
consumer: 'web-app',
provider: 'user-api',
});
provider
.given('user 1 exists')
.uponReceiving('a request for user 1')
.withRequest({ method: 'GET', path: '/users/1' })
.willRespondWith({
status: 200,
body: like({ id: integer(1), name: 'Alice' }),
});
await provider.executeTest(async (mock) => {
const r = await fetch(`${mock.url}/users/1`);
expect(r.status).toBe(200);
});
// → pact JSON 생성
```
### Pact JSON
```json
{
"consumer": { "name": "web-app" },
"provider": { "name": "user-api" },
"interactions": [{
"providerStates": [{ "name": "user 1 exists" }],
"request": { "method": "GET", "path": "/users/1" },
"response": { "status": 200, "body": { "id": 1, "name": "Alice" } }
}]
}
```
→ Broker 에 publish.
### Provider verify
```ts
import { Verifier } from '@pact-foundation/pact';
await new Verifier({
providerBaseUrl: 'http://localhost:3000',
pactBrokerUrl: 'https://broker.example.com',
provider: 'user-api',
publishVerificationResult: true,
providerVersion: '1.2.3',
stateHandlers: {
'user 1 exists': async () => {
await db.users.insert({ id: 1, name: 'Alice' });
},
},
}).verifyProvider();
```
→ 매 interaction = stateHandler setup → 호출 → 응답 검증.
### Broker
```bash
docker run -p 9292:9292 pactfoundation/pact-broker
# Publish
pact-broker publish ./pacts \
--consumer-app-version 1.0.0 \
--broker-base-url https://broker
# Can-i-deploy
pact-broker can-i-deploy \
--pacticipant web-app --version 1.0.0 \
--to production
```
→ Broker 가 매 version compatibility check.
### Matchers
```ts
import { MatchersV3 } from '@pact-foundation/pact';
const { like, term, eachLike, integer, decimal, datetime, uuid } = MatchersV3;
body: {
id: integer(1), // any int
email: term({ generate: 'a@x.com', matcher: '\\S+@\\S+' }), // regex
age: like(25), // type
items: eachLike({ name: 'book' }, { min: 1 }), // array of like
created: datetime("yyyy-MM-dd'T'HH:mm:ss"),
uuid: uuid(),
}
```
→ Schema 매칭. Concrete value X.
### Pact vs OpenAPI
```
Pact:
- Consumer-driven (실제 사용).
- Interaction 별 (state + request + response).
- Provider 가 verify (running app).
OpenAPI:
- Provider-published (모든 가능 endpoint).
- Schema 만.
- Static check.
→ OpenAPI = "이거 가 가능". Pact = "이거 가 사용".
```
→ 둘 다 가능. Bi-directional pact (OpenAPI ↔ Pact).
### Bi-directional contract
```
Provider publishes OpenAPI spec.
Consumer publishes Pact.
Broker compares.
→ Provider 가 actual run 안 — schema 만 검증.
```
### Async / Kafka
```ts
// Producer (의 message)
.uponReceiving('an order created event')
.withContent({
orderId: integer(123),
userId: integer(1),
total: decimal(99.99),
});
// Consumer 가 verify (read message → assert)
```
### Versioning
```
Consumer publishes pact-v1, pact-v2.
Provider verifies 둘 다.
→ 옛 client 도 작동 가 검증.
```
### CI integration
```yaml
# Consumer
- run: yarn test:pact
- run: pact-broker publish pacts --consumer-app-version $GIT_SHA
# Provider (PR + merge)
- run: yarn test:provider-verify
- run: pact-broker can-i-deploy --pacticipant user-api --version $GIT_SHA --to production
```
→ 매 PR 가 broker check.
### `can-i-deploy`
```bash
pact-broker can-i-deploy \
--pacticipant web-app --version 2.0.0 \
--to production
# Computer says no
# - web-app 2.0.0 의 pact 가 user-api 1.5.0 에서 verified X
```
→ Deploy 막음 — schema mismatch 가 prod 안 감.
### Webhook
```bash
# Consumer 가 새 pact publish → broker 가 provider CI trigger.
pact-broker create-webhook \
--consumer web-app --provider user-api \
--request POST --url https://ci.example.com/build \
--description "trigger provider verify"
```
### State handler
```ts
stateHandlers: {
'user exists': async (params) => {
await db.users.insert({ id: params.id, name: params.name });
return { id: params.id };
},
'user does not exist': async () => {
await db.users.deleteAll();
},
}
```
→ Provider state setup. Test isolation.
### Polyglot (다른 언어)
```
Pact = 다 언어 (Java, Ruby, Go, Python, JS, C#).
JSON spec 표준.
→ Consumer JS, Provider Java OK.
```
### When NOT contract test?
```
- Monolith (1 deploy)
- 1 client + 1 server (직접 test)
- API 가 매우 stable
- 변경 자주 (overhead)
→ Microservice (여러 client, 여러 provider, 자주 deploy) 가 sweet spot.
```
### Cost / overhead
```
- Pact infrastructure (broker, CI)
- Test 작성 cost
- 매 변경 = consumer + provider 협조
→ 5+ service team 가 가치.
```
### Storybook + MSW + Pact
```ts
// Storybook story 가 MSW handler 사용
// MSW handler 가 Pact 와 align
// → UI test 가 contract align
```
→ Frontend 도 contract.
### SchemaThesis (alternative)
```bash
# OpenAPI 기반 fuzz test
schemathesis run https://api.example.com/openapi.json
```
→ OpenAPI 의 모든 endpoint 가 fuzz.
### Function vs API
```
Pact: HTTP API.
TypeScript: type-level (compile-time check).
gRPC: proto buf.
→ Pact 가 HTTP / queue 친화.
```
### 함정
```
- 모든 interaction pact: 큰 file, 느린 verify.
- Specific value (가짜 ID 1): brittle. matchers.
- State 쟁이 함: setup 어려움.
- Pact 가 functional / business test 됨: scope creep.
- Provider 가 pact 무시: silent break.
- can-i-deploy 사용 X: pact 의 가치 ↓.
```
### Best practices
```
1. Consumer 가 minimum interaction (실제 필요한 것만).
2. Matchers > 정확 value.
3. State handler 가 idempotent.
4. CI 가 매 PR 검증.
5. can-i-deploy 가 prod gate.
6. Broker 의 tag (env, branch).
```
### Example workflow
```
1. Consumer dev: write code → test (pact).
2. Pact publish to broker.
3. Webhook trigger provider CI.
4. Provider verify pact.
5. Result publish to broker.
6. Consumer can deploy if all green.
7. Provider can deploy if all consumer pact green.
```
→ Bi-directional gate.
## 🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| 5+ microservice | Pact |
| API 자주 변경 | Pact |
| OpenAPI 만 | Bi-directional |
| Async / Kafka | Pact message |
| 작은 system | OpenAPI + integration test |
| Monolith | E2E 만 |
| API 가 stable | Schema test 만 |
## ❌ 안티패턴
- **모든 interaction**: pact 폭발.
- **State handler 가 unhealthy**: test 불안정.
- **Provider 가 verify 안 함**: silent break.
- **can-i-deploy 무시**: pact 의 가치 ↓.
- **정확 value (no matchers)**: brittle.
- **Pact 가 business test**: scope creep.
- **Broker 백업 X**: history 잃음.
## 🤖 LLM 활용 힌트
- Consumer-driven > provider-defined.
- Matchers (like, term) 가 핵심.
- can-i-deploy 가 prod gate.
- Pactflow (managed) 가 작은 팀 친화.
## 🔗 관련 문서
- [[Testing_Contract_Testing]]
- [[API_OpenAPI_Spec]]
- [[Backend_GraphQL_Server_Patterns]]