refactor(topics): 멀티 에이전트용 지식 재편 — _Common(공통 기본기) + Domain_* 구조
에이전트 8종(대화형/프로그래머 C·S/디자이너/설계자/기획자/QA/PD/PM)에게 [공통 기본 능력 + 롤별 Specialty] 2층으로 지식을 주입하기 위한 재분류. 문서 내용·포맷은 무수정, 폴더 이동만 (6,372개 문서 수 보존 확인). - Topic_Programming → Domain_Programming (내부 구조 보존) - Topic_Graphic → Domain_Design - Topic_Business → Domain_Product - Topic_General → Domain_General - _Common 신설: Math(구 Topic_Math_Specialty), Reasoning(구 General/From_Thinking & Reasoning), Reasoning_Creativity(구 General/From_창의성), Communication(Poetic_Blog_Writing + From_writing) - 타 도메인의 From_* 폴더는 유지 (출처 표기일 뿐, 이미 도메인에 맞게 분류된 문서) - 빈 폴더 정리 (memory/procedures) - 에이전트→폴더 매핑은 workspace의 .astra/agent-knowledge-map.json (9개 에이전트) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
---
|
||||
id: api-openapi-spec
|
||||
title: OpenAPI / Swagger — Schema-first vs Code-first
|
||||
category: Coding
|
||||
status: draft
|
||||
source_trust_level: B
|
||||
verification_status: conceptual
|
||||
created_at: 2026-05-09
|
||||
updated_at: 2026-05-09
|
||||
tags: [api, openapi, swagger, vibe-coding]
|
||||
tech_stack: { language: "TS / OpenAPI", applicable_to: ["Backend"] }
|
||||
applied_in: []
|
||||
aliases: [OpenAPI, Swagger, schema-first, code-first, Hono RPC, oRPC, ts-rest]
|
||||
---
|
||||
|
||||
# OpenAPI
|
||||
|
||||
> API contract 표준. **Schema → Type generation, mock server, client SDK, docs**. Schema-first 또는 Code-first. **Hono / ts-rest / oRPC** 가 modern code-first.
|
||||
|
||||
## 📖 핵심 개념
|
||||
- OpenAPI 3.1: 표준 spec.
|
||||
- Schema-first: yaml/json 먼저 → 코드 생성.
|
||||
- Code-first: 코드의 type → spec 자동.
|
||||
- Server / client SDK 자동.
|
||||
|
||||
## 💻 코드 패턴
|
||||
|
||||
### Schema-first (yaml)
|
||||
```yaml
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: Acme API
|
||||
version: 1.0.0
|
||||
|
||||
paths:
|
||||
/orders:
|
||||
get:
|
||||
summary: List orders
|
||||
parameters:
|
||||
- { name: limit, in: query, schema: { type: integer, default: 20 } }
|
||||
- { name: cursor, in: query, schema: { type: string } }
|
||||
responses:
|
||||
'200':
|
||||
description: ok
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/OrderList'
|
||||
post:
|
||||
summary: Create order
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CreateOrder' }
|
||||
responses:
|
||||
'201':
|
||||
description: created
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Order' }
|
||||
'400':
|
||||
description: validation error
|
||||
content:
|
||||
application/problem+json:
|
||||
schema: { $ref: '#/components/schemas/Problem' }
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Order:
|
||||
type: object
|
||||
required: [id, items, total]
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
items:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/OrderItem' }
|
||||
total: { type: string }
|
||||
status: { type: string, enum: [open, paid, shipped] }
|
||||
|
||||
Problem:
|
||||
type: object
|
||||
required: [type, title, status]
|
||||
properties:
|
||||
type: { type: string, format: uri }
|
||||
title: { type: string }
|
||||
status: { type: integer }
|
||||
detail: { type: string }
|
||||
```
|
||||
|
||||
### 코드 생성
|
||||
```bash
|
||||
# Server stub
|
||||
openapi-generator-cli generate -i api.yaml -g typescript-node-server -o server/
|
||||
|
||||
# Client SDK
|
||||
openapi-generator-cli generate -i api.yaml -g typescript-axios -o client/
|
||||
|
||||
# 또는 modern: openapi-typescript
|
||||
npx openapi-typescript api.yaml -o api-types.ts
|
||||
```
|
||||
|
||||
```ts
|
||||
import type { paths } from './api-types';
|
||||
type CreateOrderRequest = paths['/orders']['post']['requestBody']['content']['application/json'];
|
||||
type OrderResponse = paths['/orders']['post']['responses']['201']['content']['application/json'];
|
||||
```
|
||||
|
||||
### Code-first — Hono + zod-openapi
|
||||
```ts
|
||||
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi';
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
const route = createRoute({
|
||||
method: 'post',
|
||||
path: '/orders',
|
||||
request: {
|
||||
body: {
|
||||
content: { 'application/json': { schema: CreateOrderSchema } },
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
201: {
|
||||
content: { 'application/json': { schema: OrderSchema } },
|
||||
description: 'Created',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
app.openapi(route, async (c) => {
|
||||
const data = c.req.valid('json'); // typed
|
||||
const order = await createOrder(data);
|
||||
return c.json(order, 201);
|
||||
});
|
||||
|
||||
// Spec 노출
|
||||
app.doc('/openapi.json', { openapi: '3.1.0', info: { title: 'API', version: '1.0' } });
|
||||
```
|
||||
|
||||
### Code-first — ts-rest
|
||||
```ts
|
||||
import { initContract } from '@ts-rest/core';
|
||||
const c = initContract();
|
||||
|
||||
export const contract = c.router({
|
||||
createOrder: {
|
||||
method: 'POST',
|
||||
path: '/orders',
|
||||
body: CreateOrderSchema,
|
||||
responses: { 201: OrderSchema, 400: ProblemSchema },
|
||||
},
|
||||
});
|
||||
|
||||
// Server (Express / Fastify / Hono)
|
||||
import { initServer } from '@ts-rest/express';
|
||||
const router = initServer().router(contract, {
|
||||
createOrder: async ({ body }) => ({ status: 201, body: await create(body) }),
|
||||
});
|
||||
|
||||
// Client (auto-typed)
|
||||
import { initClient } from '@ts-rest/core';
|
||||
const api = initClient(contract, { baseUrl: '...' });
|
||||
const r = await api.createOrder({ body: { items: [...] } });
|
||||
```
|
||||
|
||||
→ Frontend / backend 가 type 공유.
|
||||
|
||||
### Mock server (fast prototyping)
|
||||
```bash
|
||||
# Prism — OpenAPI mock
|
||||
prism mock api.yaml --port 4010
|
||||
```
|
||||
|
||||
→ Backend 만들기 전에 frontend 시작.
|
||||
|
||||
### Docs UI
|
||||
```ts
|
||||
// Swagger UI
|
||||
import swaggerUi from 'swagger-ui-express';
|
||||
app.use('/docs', swaggerUi.serve, swaggerUi.setup(spec));
|
||||
|
||||
// Scalar (modern, beautiful)
|
||||
import { apiReference } from '@scalar/express-api-reference';
|
||||
app.use('/docs', apiReference({ spec: { url: '/openapi.json' } }));
|
||||
|
||||
// Stoplight Elements
|
||||
```
|
||||
|
||||
### Validation (Hono / Express middleware)
|
||||
```ts
|
||||
// Express
|
||||
import OpenApiValidator from 'express-openapi-validator';
|
||||
app.use(OpenApiValidator.middleware({ apiSpec: 'api.yaml' }));
|
||||
// 자동 validate body / query / response
|
||||
```
|
||||
|
||||
### Lint (Spectral)
|
||||
```bash
|
||||
npx spectral lint api.yaml
|
||||
# 표준 / 일관성 검사
|
||||
```
|
||||
|
||||
```yaml
|
||||
# .spectral.yml
|
||||
rules:
|
||||
operation-tag-defined: warn
|
||||
operation-success-response: error
|
||||
no-unresolved-refs: error
|
||||
```
|
||||
|
||||
### Diff (breaking change)
|
||||
```bash
|
||||
npx oasdiff diff old.yaml new.yaml --breaking-only
|
||||
# CI 에서 PR 마다
|
||||
```
|
||||
|
||||
### Code-first vs Schema-first
|
||||
```
|
||||
Schema-first:
|
||||
+ Single source of truth
|
||||
+ Multi-language (server / client)
|
||||
- Sync 어려움 (yaml 과 코드)
|
||||
|
||||
Code-first:
|
||||
+ TS type 가 진실
|
||||
+ Hot reload
|
||||
- 다른 언어 client = generate 필요
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준
|
||||
| 상황 | 추천 |
|
||||
|---|---|
|
||||
| TS only fullstack | ts-rest / oRPC / Hono RPC / tRPC |
|
||||
| 다양한 client 언어 | Schema-first OpenAPI |
|
||||
| Public API | OpenAPI + Scalar docs |
|
||||
| Mock first | Schema-first + Prism |
|
||||
| Strong type 일급 | Code-first |
|
||||
| 빠른 prototype | Code-first |
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Spec 과 코드 drift**: schema-first 의 위험. CI 에서 검증.
|
||||
- **모든 endpoint 200 만 명시**: 4xx / 5xx 같이.
|
||||
- **Schema 안 example**: 사용자 모름.
|
||||
- **Auth 누락 (security scheme)**: 명시.
|
||||
- **Generated client 직접 변경**: 다음 generate 시 잃음.
|
||||
- **OpenAPI 안 서버 검증**: client 만 — server bypass 가능.
|
||||
- **Versioning 없는 spec 변경**: breaking.
|
||||
|
||||
## 🤖 LLM 활용 힌트
|
||||
- TS = ts-rest / Hono RPC.
|
||||
- 다중 언어 = OpenAPI yaml + generators.
|
||||
- Spectral lint + oasdiff CI.
|
||||
|
||||
## 🔗 관련 문서
|
||||
- [[API_REST_Best_Practices]]
|
||||
- [[API_Versioning_Strategies]]
|
||||
- [[TS_Schema_Validation_Comparison]]
|
||||
Reference in New Issue
Block a user