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:
Antigravity Agent
2026-07-11 11:05:56 +09:00
parent 6549ead309
commit c24165b8bc
6193 changed files with 1717 additions and 31 deletions
@@ -0,0 +1,123 @@
---
id: db-migration-safety
title: DB Migration Safety — Zero-downtime 전환 패턴
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [database, migration, zero-downtime, postgres, vibe-coding]
tech_stack: { language: "SQL / Postgres / MySQL", applicable_to: ["Backend"] }
applied_in: []
aliases: [expand-contract, blue-green schema, online migration, lock-free]
---
# DB Migration Safety
> **Expand → Migrate → Contract** 3단계가 정답. 한 번에 schema + 코드 둘 다 못 바꾼다 — 둘이 동시에 deploy 안 되니까. NOT NULL 추가 / column rename / type change 가 가장 위험.
## 📖 핵심 개념
- **Expand**: 새 schema 추가. 옛 코드는 옛 schema 만 사용. 양립 가능.
- **Migrate**: 코드를 새 schema 로 이전. dual-write 또는 backfill.
- **Contract**: 옛 schema 제거.
- 각 단계는 별도 deploy. 사이에 모니터링 시간.
## 💻 코드 패턴
### Column rename `old_name → new_name`
#### Expand
```sql
ALTER TABLE users ADD COLUMN new_name TEXT;
-- Trigger: old_name 변경 시 new_name 동기화
CREATE OR REPLACE FUNCTION sync_name() RETURNS trigger AS $$
BEGIN NEW.new_name := COALESCE(NEW.new_name, NEW.old_name); RETURN NEW; END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_sync_name BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE sync_name();
-- Backfill (낮 시간대 batch)
UPDATE users SET new_name = old_name WHERE new_name IS NULL;
```
#### Migrate (코드 deploy)
- 코드: 읽기는 `COALESCE(new_name, old_name)`, 쓰기는 둘 다.
#### Contract
```sql
DROP TRIGGER trg_sync_name ON users;
DROP FUNCTION sync_name();
ALTER TABLE users DROP COLUMN old_name;
```
### NOT NULL 추가 — 큰 테이블
```sql
-- ❌ 직접 NOT NULL — 대형 테이블 long lock
ALTER TABLE orders ALTER COLUMN status SET NOT NULL;
-- ✅ 단계별
-- 1) DEFAULT + NOT VALID CHECK
ALTER TABLE orders ADD CONSTRAINT orders_status_chk CHECK (status IS NOT NULL) NOT VALID;
-- 2) 기존 행 backfill
UPDATE orders SET status = 'pending' WHERE status IS NULL;
-- 3) constraint validate (read lock 만)
ALTER TABLE orders VALIDATE CONSTRAINT orders_status_chk;
-- 4) 진짜 NOT NULL (Postgres 12+ — fast path)
ALTER TABLE orders ALTER COLUMN status SET NOT NULL;
ALTER TABLE orders DROP CONSTRAINT orders_status_chk;
```
### Index 추가 — CONCURRENTLY (Postgres)
```sql
CREATE INDEX CONCURRENTLY idx_users_email ON users(email);
-- write block 안 함. 단 transaction 안에서는 못 씀.
```
### 큰 테이블 backfill — batch
```sql
-- 한 번에 1000행씩
DO $$
DECLARE batch INT := 1000;
BEGIN
LOOP
WITH ids AS (
SELECT id FROM orders WHERE new_field IS NULL LIMIT batch FOR UPDATE SKIP LOCKED
)
UPDATE orders SET new_field = compute(id) WHERE id IN (SELECT id FROM ids);
EXIT WHEN NOT FOUND;
PERFORM pg_sleep(0.1);
END LOOP;
END$$;
```
## 🤔 의사결정 기준
| 변경 | 안전 |
|---|---|
| Column 추가 (nullable) | ✅ 즉시 |
| Column 추가 + DEFAULT (Postgres 11+) | ✅ — fast path |
| NOT NULL 추가 | expand-contract |
| Column rename | expand-contract |
| Type change (varchar → text) | 보통 안전 — but 큰 테이블이면 점검 |
| Type change (int → bigint) | expand-contract |
| Drop column | expand-contract — 코드 먼저 안 쓰게 |
| Index 추가 | CONCURRENTLY |
| FK 추가 | NOT VALID + VALIDATE |
## ❌ 안티패턴
- **schema 변경과 코드 변경 한 deploy**: 둘이 정확히 동시 시작 못 함. 한 쪽만 적용된 짧은 시간 = 사고.
- **online migration 없는 큰 테이블 ALTER**: 수십 분 lock → 다운타임.
- **rollback 계획 없음**: 새 코드 + 새 schema deploy 후 문제 → 옛 코드 + 새 schema 인스턴스 발생 → 사고. expand-contract 면 자연 롤백.
- **production 에 직접 SQL**: history / review 없음. migration tool (Flyway / Prisma migrate / golang-migrate / dbmate) 사용.
- **migration 안에 비즈니스 로직**: 한 트랜잭션에 무거운 변환. 별도 backfill batch.
- **trigger 가 영구 남음**: contract 단계에서 trigger 제거 잊음.
- **dev 에서만 테스트**: 데이터 양이 다름. staging with prod-size dataset 검증.
## 🤖 LLM 활용 힌트
- "schema 변경 = expand-migrate-contract 3 deploy" 강제.
- 큰 테이블 ALTER 는 항상 단계별 + CONCURRENTLY 권장.
## 🔗 관련 문서
- [[DB_Connection_Pool]]
- [[Optimistic_Concurrency_Control]]