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,306 @@
---
id: frontend-progressive-enhancement
title: Progressive Enhancement — Server-first / 점진 JS
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [frontend, progressive-enhancement, html, vibe-coding]
tech_stack: { language: "HTML / TS", applicable_to: ["Frontend"] }
applied_in: []
aliases: [progressive enhancement, server-first, no-JS fallback, HTMX, web standards, MPA]
---
# Progressive Enhancement
> Server-rendered HTML 부터 → JS 로 향상. **JS 없어도 작동, 있으면 더 좋음**. Remix / Next App Router / HTMX / web standards. SPA 의 reaction.
## 📖 핵심 개념
- HTML 가 baseline.
- Form / link 가 native (JS 없어도).
- JS = enhancement.
- 학교 wifi / slow 3G / 옛 browser 도 작동.
## 💻 코드 패턴
### 기본 — Form 가 native
```html
<form method="post" action="/api/login">
<input name="email" type="email" required>
<input name="password" type="password" required minlength="8" required>
<button>Sign in</button>
</form>
```
→ JS 없이 작동. 검증도 native.
### Next.js Server Action (PE)
```tsx
// app/login/page.tsx
async function login(formData: FormData) {
'use server';
const email = formData.get('email') as string;
const password = formData.get('password') as string;
// ... auth
redirect('/dashboard');
}
export default function LoginPage() {
return (
<form action={login}>
<input name="email" type="email" required />
<input name="password" type="password" required />
<button>Sign in</button>
</form>
);
}
```
→ JS 없어도 form submit. JS 가 활성화되면 SPA-like UX.
### useFormStatus (loading state)
```tsx
'use client';
import { useFormStatus } from 'react-dom';
function SubmitButton() {
const { pending } = useFormStatus();
return <button disabled={pending}>{pending ? 'Signing in…' : 'Sign in'}</button>;
}
```
→ JS 활성 시 loading 표시. JS 없으면 기본 button.
### Remix loader / action
```tsx
// app/routes/login.tsx
export async function action({ request }: ActionArgs) {
const formData = await request.formData();
const email = formData.get('email');
// ...
return redirect('/dashboard');
}
export default function Login() {
return (
<Form method="post">
<input name="email" type="email" />
<input name="password" type="password" />
<button>Sign in</button>
</Form>
);
}
```
→ Remix `<Form>` = JS 없어도 native form, JS 있으면 SPA submit.
### HTMX (server-rendered + AJAX)
```html
<button hx-post="/api/like" hx-target="#likes">
Like
</button>
<span id="likes">42</span>
```
→ Server 가 새 HTML fragment 반환. JS 없으면 일반 button (또는 fallback).
```html
<!-- Fallback -->
<form action="/like" method="post">
<button hx-post="/api/like" hx-target="#likes" hx-swap="innerHTML">
Like
</button>
</form>
<span id="likes">42</span>
```
### Native dialog (JS 안)
```html
<dialog id="modal">
<form method="dialog">
<p>Are you sure?</p>
<button value="confirm">Yes</button>
<button value="cancel">No</button>
</form>
</dialog>
<button onclick="document.getElementById('modal').showModal()">Open</button>
```
→ JS 안 쓰고도 modal. (showModal 만 JS — fallback 가능).
### View Transitions (declarative animation)
```html
<a href="/about">About</a>
<!-- 새 page navigation 자동 transition (Chrome) -->
```
```css
@view-transition { navigation: auto; }
```
### Anchor link / form / radio = SPA-like 가능
```html
<!-- Tabs = radio + label -->
<input type="radio" id="tab1" name="tabs" checked>
<label for="tab1">Tab 1</label>
<input type="radio" id="tab2" name="tabs">
<label for="tab2">Tab 2</label>
<div class="content">
<section data-tab="tab1">Tab 1 content</section>
<section data-tab="tab2">Tab 2 content</section>
</div>
<style>
section[data-tab] { display: none; }
#tab1:checked ~ .content [data-tab="tab1"] { display: block; }
#tab2:checked ~ .content [data-tab="tab2"] { display: block; }
</style>
```
→ JS 0 — 작동.
### Search — native form + URL
```tsx
<form method="get" action="/search">
<input name="q" type="search" placeholder="Search…">
<button>Search</button>
</form>
```
→ JS 가 query param + result render. 없어도 server 가 SSR.
### Optimistic UI + rollback
```tsx
'use client';
import { useOptimistic } from 'react';
const [optimistic, addOptimistic] = useOptimistic(items);
async function add(item) {
addOptimistic([...items, item]); // 즉시 UI
await fetch('/api/add', { method: 'POST', body: JSON.stringify(item) });
}
```
→ JS 활성 시 즉시 반응. 없으면 server 의 form submit.
### loading="lazy", decoding="async"
```html
<img src="..." loading="lazy" decoding="async" alt="...">
<iframe src="..." loading="lazy"></iframe>
```
### Tailwind + native HTML
```html
<details class="border rounded p-4">
<summary class="cursor-pointer font-bold">FAQ</summary>
<p class="mt-2">Answer</p>
</details>
```
→ JS 없는 accordion.
### Form validation (browser native)
```html
<input type="email" required>
<input type="number" min="0" max="100" step="0.1">
<input pattern="[A-Z]{3}-\d{4}" title="ABC-1234">
<input type="text" required minlength="3" maxlength="20">
```
```css
input:invalid { border-color: red; }
input:invalid:not(:placeholder-shown) { ... }
```
### Web standards 활용
```html
<input type="date"> <!-- date picker native -->
<input type="color"> <!-- color picker -->
<input type="range"> <!-- slider -->
<input type="search"> <!-- clear button native -->
<input type="file" accept="image/*" multiple>
```
→ JS 라이브러리 없이.
### Fetch with form + JSON 전환
```tsx
async function handleSubmit(e: FormEvent) {
e.preventDefault();
const data = Object.fromEntries(new FormData(e.target as HTMLFormElement));
await fetch('/api/...', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(data),
});
}
<form onSubmit={handleSubmit} action="/api/..." method="post">
...
</form>
```
→ JS 활성 = JSON. 없으면 form encode + server 가 처리.
### MPA vs SPA vs PE
```
MPA (Multi-Page App): 서버 매번 HTML 보냄. 옛.
SPA: JS 가 모든 거. PE 무시 자주.
Progressive Enhanced: 둘 다 — MPA 처럼 baseline, SPA 처럼 향상.
→ Next App Router / Remix / Phoenix LiveView / Rails Hotwire.
```
### a11y 자연
```html
<button>Click</button> <!-- focus, role 자동 -->
<a href="...">Link</a> <!-- 키보드 navigation 자동 -->
<form> <!-- enter submit, label association -->
```
→ Custom div 보다 우월.
### React Server Components (RSC)
```tsx
// 서버 컴포넌트 — JS 0 client
async function Page() {
const data = await db.query(...);
return <ul>{data.map(d => <li>{d}</li>)}</ul>;
}
```
→ HTML 만 보냄. 작은 page = JS 0.
## 🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| Public site (SEO, accessibility) | PE strict |
| 내부 dashboard (관리자만) | SPA OK |
| Form-heavy | Server actions / Remix |
| 인터랙션 없는 콘텐츠 | RSC + 0 client JS |
| 복잡 인터랙션 | SPA + PE 가능 한도 |
| 옛 browser / slow 3G | PE 강 |
## ❌ 안티패턴
- **모든 거 client-side JS**: SEO / a11y / slow.
- **`<div onClick>` button**: 키보드 안 됨.
- **Form 가 fetch + JSON 만 — server action 없음**: JS X = 작동 X.
- **Required JS — fallback X**: 옛 browser fail.
- **Client-only routing — server URL 안 됨**: refresh = 404.
- **Loading skeleton 만 + 데이터 없음**: PE 무시.
## 🤖 LLM 활용 힌트
- Form action + method = baseline.
- Native HTML 우선 (button, dialog, details).
- JS 는 향상 — 없어도 작동.
- Next App Router / Remix 가 PE 친화.
## 🔗 관련 문서
- [[React_RSC_Server_Actions_Deep]]
- [[Frontend_A11y_Testing]]
- [[Web_Performance_Core_Vitals]]