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,169 @@
|
||||
---
|
||||
id: wiki-2026-0508-단일-진실-공급원-single-source-of-truth
|
||||
title: 단일 진실 공급원(Single Source of Truth)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [SSOT, Single Source of Truth, 진실의 단일 공급원]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, state-management, ssot, frontend]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: typescript
|
||||
framework: react-19
|
||||
---
|
||||
|
||||
# 단일 진실 공급원(Single Source of Truth)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 모든 derived state 의 single canonical origin"**. 매 1970s database normalization 에서 시작 — 매 modern frontend (Redux, TanStack Query, RSC) 의 핵심 원리. 매 duplication 의 elimination → 매 inconsistency bug 의 소멸.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 정의
|
||||
- 매 한 데이터 의 **하나의** authoritative location.
|
||||
- 매 다른 모든 view/component 의 derive (read-only projection).
|
||||
- 매 update 의 single entry point — 매 race / drift 의 prevention.
|
||||
|
||||
### 매 frontend 적용 layer
|
||||
- **Server state SSOT**: 매 backend DB — 매 client 의 cache (TanStack Query, SWR).
|
||||
- **URL state SSOT**: 매 query params / path — 매 shareable, refreshable.
|
||||
- **Form state SSOT**: 매 RHF / Formik 의 form object — 매 controlled input 의 derive.
|
||||
- **Global UI state SSOT**: 매 Zustand / Jotai store — 매 cross-component shared.
|
||||
|
||||
### 매 응용
|
||||
1. TanStack Query — server SSOT mirror.
|
||||
2. RSC (React Server Components) — server 의 SSOT 그대로 stream.
|
||||
3. URL-driven state (nuqs, TanStack Router) — 매 shareable SSOT.
|
||||
4. CRDT (Yjs, Automerge) — 매 distributed SSOT.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Server SSOT via TanStack Query
|
||||
```typescript
|
||||
// ❌ duplication — local state mirrors server
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
useEffect(() => { fetchUser().then(setUser); }, []);
|
||||
|
||||
// ✅ SSOT — server is truth, query is cached projection
|
||||
const { data: user } = useQuery({
|
||||
queryKey: ['user', userId],
|
||||
queryFn: () => fetchUser(userId),
|
||||
});
|
||||
```
|
||||
|
||||
### URL as SSOT (nuqs)
|
||||
```typescript
|
||||
import { useQueryState, parseAsInteger } from 'nuqs';
|
||||
|
||||
function ProductList() {
|
||||
const [page, setPage] = useQueryState('page', parseAsInteger.withDefault(1));
|
||||
const [sort, setSort] = useQueryState('sort');
|
||||
// URL ?page=2&sort=price is the truth — refresh-safe, shareable
|
||||
return <List page={page} sort={sort} />;
|
||||
}
|
||||
```
|
||||
|
||||
### Derived state (no duplicate store)
|
||||
```typescript
|
||||
// ❌ duplicating filtered list in state
|
||||
const [items, setItems] = useState(allItems);
|
||||
const [filter, setFilter] = useState('');
|
||||
useEffect(() => { setItems(allItems.filter(i => i.name.includes(filter))); }, [filter]);
|
||||
|
||||
// ✅ derive on render — items isn't state
|
||||
const [filter, setFilter] = useState('');
|
||||
const visible = useMemo(() => allItems.filter(i => i.name.includes(filter)), [filter]);
|
||||
```
|
||||
|
||||
### Form SSOT via RHF
|
||||
```typescript
|
||||
const { register, watch, handleSubmit } = useForm<FormData>({
|
||||
defaultValues: { email: '', plan: 'free' },
|
||||
});
|
||||
const plan = watch('plan'); // derived from form SSOT
|
||||
return (
|
||||
<form onSubmit={handleSubmit(submit)}>
|
||||
<input {...register('email')} />
|
||||
{plan === 'pro' && <input {...register('teamSize')} />}
|
||||
</form>
|
||||
);
|
||||
```
|
||||
|
||||
### Zustand store SSOT
|
||||
```typescript
|
||||
import { create } from 'zustand';
|
||||
|
||||
type CartStore = {
|
||||
items: CartItem[];
|
||||
add: (item: CartItem) => void;
|
||||
remove: (id: string) => void;
|
||||
};
|
||||
|
||||
export const useCart = create<CartStore>((set) => ({
|
||||
items: [],
|
||||
add: (item) => set((s) => ({ items: [...s.items, item] })),
|
||||
remove: (id) => set((s) => ({ items: s.items.filter((i) => i.id !== id) })),
|
||||
}));
|
||||
|
||||
// Total derived — not stored
|
||||
const useCartTotal = () => useCart((s) => s.items.reduce((a, i) => a + i.price, 0));
|
||||
```
|
||||
|
||||
### CRDT SSOT (collaborative)
|
||||
```typescript
|
||||
import * as Y from 'yjs';
|
||||
import { WebrtcProvider } from 'y-webrtc';
|
||||
|
||||
const ydoc = new Y.Doc();
|
||||
new WebrtcProvider('room-id', ydoc);
|
||||
const ytext = ydoc.getText('content');
|
||||
|
||||
ytext.observe(() => {
|
||||
// single source — all peers converge
|
||||
render(ytext.toString());
|
||||
});
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 데이터 종류 | SSOT location |
|
||||
|---|---|
|
||||
| 영속 entity (user, order) | Backend DB → TanStack Query cache |
|
||||
| Shareable view state | URL params (nuqs) |
|
||||
| Form draft | RHF / Formik form object |
|
||||
| Cross-component UI | Zustand / Jotai |
|
||||
| Component-local | useState (그 component 자체 가 SSOT) |
|
||||
| Collaborative | CRDT (Yjs) |
|
||||
|
||||
**기본값**: 매 server 의 SSOT, 매 client 의 cache projection.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[State Management]]
|
||||
- 변형: [[Event Sourcing]] · [[CQRS]]
|
||||
- 응용: [[React Server Components — 경계 의식]] · [[CRDT]]
|
||||
- Adjacent: [[단일 진실 공급원(Single Source of Truth) 구축]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 state architecture design / data flow audit / bug-prone "two stores out of sync" 발견 시.
|
||||
**언제 X**: 매 truly independent UI ephemeral state (hover, focus) — 매 local 이 자체 SSOT.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Mirror state**: 매 server 의 data 를 useState 로 복제. → 매 stale + 두 source 의 drift.
|
||||
- **Multiple stores 의 same field**: Redux + Context + URL 모두 `selectedId` 보유. 매 update 의 race.
|
||||
- **Premature derivation cache**: 매 derived value 를 별도 state 로 저장. 매 useMemo 충분.
|
||||
- **localStorage 의 silent SSOT**: 매 sync 없는 cross-tab — 매 BroadcastChannel 또는 storage event 필요.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Redux docs — "Three Principles", Dan Abramov; Martin Fowler — SSOT).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — SSOT FULL writeup |
|
||||
Reference in New Issue
Block a user