9148c358d0
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 폴더 제거.
5.6 KiB
5.6 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-단일-진실-공급원-single-source-of-truth | 단일 진실 공급원(Single Source of Truth) | 10_Wiki/Topics | verified | self |
|
none | A | 0.9 | applied |
|
2026-05-10 | pending |
|
단일 진실 공급원(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.
매 응용
- TanStack Query — server SSOT mirror.
- RSC (React Server Components) — server 의 SSOT 그대로 stream.
- URL-driven state (nuqs, TanStack Router) — 매 shareable SSOT.
- CRDT (Yjs, Automerge) — 매 distributed SSOT.
💻 패턴
Server SSOT via TanStack Query
// ❌ 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)
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)
// ❌ 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
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
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)
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 |