@wooojin/forgen 0.4.8 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/assets/dev-guide/be/README.md +226 -0
- package/assets/dev-guide/be/adapters/build-agents-md.sh +63 -0
- package/assets/dev-guide/be/principles/common.md +433 -0
- package/assets/dev-guide/be/principles/go.md +469 -0
- package/assets/dev-guide/be/principles/node.md +388 -0
- package/assets/dev-guide/be/skills/go/be-build/SKILL.md +262 -0
- package/assets/dev-guide/be/skills/go/be-perf/SKILL.md +308 -0
- package/assets/dev-guide/be/skills/go/be-review/SKILL.md +119 -0
- package/assets/dev-guide/be/skills/go/be-security/SKILL.md +362 -0
- package/assets/dev-guide/be/skills/node/be-build/SKILL.md +239 -0
- package/assets/dev-guide/be/skills/node/be-perf/SKILL.md +272 -0
- package/assets/dev-guide/be/skills/node/be-review/SKILL.md +118 -0
- package/assets/dev-guide/be/skills/node/be-security/SKILL.md +355 -0
- package/assets/dev-guide/be/sources/12factor/INDEX.md +53 -0
- package/assets/dev-guide/be/sources/api-design/INDEX.md +56 -0
- package/assets/dev-guide/be/sources/ddia/INDEX.md +55 -0
- package/assets/dev-guide/be/sources/go-runtime/INDEX.md +62 -0
- package/assets/dev-guide/be/sources/node-runtime/INDEX.md +60 -0
- package/assets/dev-guide/be/sources/otel/INDEX.md +53 -0
- package/assets/dev-guide/be/sources/owasp-api/INDEX.md +52 -0
- package/assets/dev-guide/be/sources/postgres/INDEX.md +55 -0
- package/assets/dev-guide/be/sources/sre-book/INDEX.md +48 -0
- package/assets/dev-guide/fe/README.md +197 -0
- package/assets/dev-guide/fe/adapters/build-agents-md.sh +63 -0
- package/assets/dev-guide/fe/adapters/refresh.sh +68 -0
- package/assets/dev-guide/fe/principles/common.md +160 -0
- package/assets/dev-guide/fe/principles/react.md +183 -0
- package/assets/dev-guide/fe/principles/vue.md +196 -0
- package/assets/dev-guide/fe/skills/react/fe-build/SKILL.md +139 -0
- package/assets/dev-guide/fe/skills/react/fe-perf/SKILL.md +179 -0
- package/assets/dev-guide/fe/skills/react/fe-review/SKILL.md +141 -0
- package/assets/dev-guide/fe/skills/vue/fe-build/SKILL.md +148 -0
- package/assets/dev-guide/fe/skills/vue/fe-perf/SKILL.md +163 -0
- package/assets/dev-guide/fe/skills/vue/fe-review/SKILL.md +136 -0
- package/assets/dev-guide/fe/sources/a11y-dx/INDEX.md +41 -0
- package/assets/dev-guide/fe/sources/a11y-dx/chrome-devtools-memory.md +150 -0
- package/assets/dev-guide/fe/sources/a11y-dx/chrome-devtools-performance.md +99 -0
- package/assets/dev-guide/fe/sources/a11y-dx/lighthouse-audits.md +146 -0
- package/assets/dev-guide/fe/sources/a11y-dx/react-devtools-profiler.md +128 -0
- package/assets/dev-guide/fe/sources/a11y-dx/wcag22-new-criteria.md +174 -0
- package/assets/dev-guide/fe/sources/perf/01-core-web-vitals.md +58 -0
- package/assets/dev-guide/fe/sources/perf/02-inp.md +83 -0
- package/assets/dev-guide/fe/sources/perf/03-lcp-cls.md +130 -0
- package/assets/dev-guide/fe/sources/perf/04-speculation-rules.md +148 -0
- package/assets/dev-guide/fe/sources/perf/05-view-transitions.md +153 -0
- package/assets/dev-guide/fe/sources/perf/06-nextjs-caching.md +188 -0
- package/assets/dev-guide/fe/sources/perf/07-server-components.md +181 -0
- package/assets/dev-guide/fe/sources/perf/08-ppr.md +133 -0
- package/assets/dev-guide/fe/sources/perf/09-nextjs-image.md +200 -0
- package/assets/dev-guide/fe/sources/perf/10-optimize-lcp.md +201 -0
- package/assets/dev-guide/fe/sources/perf/INDEX.md +88 -0
- package/assets/dev-guide/fe/sources/react/INDEX.md +41 -0
- package/assets/dev-guide/fe/sources/react/keeping-components-pure.md +135 -0
- package/assets/dev-guide/fe/sources/react/no-effect-patterns.md +183 -0
- package/assets/dev-guide/fe/sources/react/react-compiler.md +182 -0
- package/assets/dev-guide/fe/sources/react/server-components.md +194 -0
- package/assets/dev-guide/fe/sources/react/server-functions.md +192 -0
- package/assets/dev-guide/fe/sources/react/suspense.md +218 -0
- package/assets/dev-guide/fe/sources/react/use-action-state.md +123 -0
- package/assets/dev-guide/fe/sources/react/use-form-status.md +158 -0
- package/assets/dev-guide/fe/sources/react/use-hook.md +153 -0
- package/assets/dev-guide/fe/sources/react/use-optimistic.md +194 -0
- package/assets/dev-guide/fe/sources/toss-ff/INDEX.md +58 -0
- package/assets/dev-guide/fe/sources/toss-ff/cohesion-code-directory.md +79 -0
- package/assets/dev-guide/fe/sources/toss-ff/cohesion-form-fields.md +110 -0
- package/assets/dev-guide/fe/sources/toss-ff/cohesion-magic-number.md +47 -0
- package/assets/dev-guide/fe/sources/toss-ff/coupling-item-edit-modal.md +124 -0
- package/assets/dev-guide/fe/sources/toss-ff/coupling-use-bottom-sheet.md +57 -0
- package/assets/dev-guide/fe/sources/toss-ff/coupling-use-page-state.md +71 -0
- package/assets/dev-guide/fe/sources/toss-ff/overview-4-principles.md +77 -0
- package/assets/dev-guide/fe/sources/toss-ff/predictability-hidden-logic.md +59 -0
- package/assets/dev-guide/fe/sources/toss-ff/predictability-http.md +77 -0
- package/assets/dev-guide/fe/sources/toss-ff/predictability-use-user.md +110 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-comparison-order.md +52 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-condition-name.md +64 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-login-start-page.md +183 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-magic-number.md +53 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-submit-button.md +73 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-ternary-operator.md +38 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-use-page-state.md +77 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-user-policy.md +98 -0
- package/assets/dev-guide/fe/sources/vue/INDEX.md +17 -0
- package/assets/dev-guide/fe/sources/vue/composition-api.md +251 -0
- package/assets/dev-guide/fe/sources/vue/nuxt-data-fetching.md +232 -0
- package/assets/dev-guide/fe/sources/vue/pinia-state-management.md +134 -0
- package/assets/dev-guide/fe/sources/vue/reactivity-pitfalls.md +261 -0
- package/assets/dev-guide/fe/sources/vue/style-guide-priority-a.md +117 -0
- package/assets/dev-guide/fe/sources/vue/style-guide-priority-b.md +231 -0
- package/assets/dev-guide/fe/sources/vue/style-guide-priority-c.md +86 -0
- package/assets/dev-guide/fe/sources/vue/style-guide-priority-d.md +72 -0
- package/dist/cli.js +42 -0
- package/dist/core/dashboard-cli.d.ts +12 -0
- package/dist/core/dashboard-cli.js +226 -0
- package/dist/core/dev-guide-injector.d.ts +26 -0
- package/dist/core/dev-guide-injector.js +137 -0
- package/dist/core/init.js +53 -0
- package/dist/core/lifecycle-classifier.d.ts +23 -0
- package/dist/core/lifecycle-classifier.js +104 -0
- package/dist/core/observability-backfill.d.ts +31 -0
- package/dist/core/observability-backfill.js +178 -0
- package/dist/core/observability-store.d.ts +58 -0
- package/dist/core/observability-store.js +195 -0
- package/dist/core/session-store.js +4 -0
- package/dist/core/spawn.d.ts +17 -0
- package/dist/core/spawn.js +179 -2
- package/dist/core/statusline-cli.js +34 -1
- package/dist/engine/compound-extractor.js +39 -0
- package/dist/engine/compound-loop.js +6 -0
- package/dist/engine/compound-retire.d.ts +20 -0
- package/dist/engine/compound-retire.js +85 -0
- package/dist/hooks/context-guard.js +25 -1
- package/dist/hooks/post-tool-use.js +48 -0
- package/dist/hooks/solution-injector.js +93 -0
- package/dist/host/install-claude.d.ts +6 -2
- package/dist/host/install-claude.js +74 -2
- package/dist/host/install-codex.d.ts +4 -0
- package/dist/host/install-codex.js +71 -0
- package/dist/host/install-orchestrator.js +1 -0
- package/package.json +6 -6
- package/plugin.json +1 -1
- package/scripts/postinstall.js +134 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Chrome DevTools 메모리 패널 진단 가이드
|
|
3
|
+
source: https://developer.chrome.com/docs/devtools/memory-problems
|
|
4
|
+
fetched: 2026-05-18
|
|
5
|
+
category: devtools-memory
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Chrome DevTools Memory Panel
|
|
9
|
+
|
|
10
|
+
## 언제 쓰는가
|
|
11
|
+
|
|
12
|
+
- 페이지를 오래 쓸수록 느려지거나 탭이 크래시될 때
|
|
13
|
+
- Task Manager에서 메모리가 지속 상승할 때
|
|
14
|
+
- SPA에서 라우트 이동 후에도 메모리가 반환되지 않을 때
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1단계: Task Manager로 메모리 누수 확인
|
|
19
|
+
|
|
20
|
+
1. `Shift+Esc` → Chrome Task Manager 열기
|
|
21
|
+
2. 오른쪽 클릭 → **JavaScript Memory** 컬럼 활성화
|
|
22
|
+
3. 문제 탭의 **JavaScript Memory** 값이 계속 증가하면 누수 의심
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 세 가지 진단 도구
|
|
27
|
+
|
|
28
|
+
### A. Heap Snapshot (정적 스냅샷)
|
|
29
|
+
|
|
30
|
+
**용도:** 특정 시점에 메모리에 무엇이 있는지 파악, Detached DOM 찾기
|
|
31
|
+
|
|
32
|
+
**절차:**
|
|
33
|
+
1. Memory 패널 → **Heap snapshot** 선택 → **Take snapshot**
|
|
34
|
+
2. 의심 동작 수행 (라우트 이동, 모달 열고 닫기 등)
|
|
35
|
+
3. 두 번째 스냅샷 → **Comparison** 뷰 선택
|
|
36
|
+
4. `# Delta` 양수인 항목이 증가한 객체
|
|
37
|
+
5. 검색창에 `Detached` 입력 → Detached DOM 트리 찾기
|
|
38
|
+
6. **Objects pane**에서 어떤 변수가 참조 중인지 확인
|
|
39
|
+
|
|
40
|
+
### B. Allocation Timeline (동적 추적)
|
|
41
|
+
|
|
42
|
+
**용도:** 어느 시점에 메모리가 급증하는지 타임라인으로 파악
|
|
43
|
+
|
|
44
|
+
**절차:**
|
|
45
|
+
1. Memory 패널 → **Allocations on timeline** 선택 → **Start**
|
|
46
|
+
2. 문제 동작 반복 → **Stop**
|
|
47
|
+
3. 파란 막대 = 새 할당. 막대를 클릭하면 해당 시점 할당 객체 목록
|
|
48
|
+
4. 사라지지 않는 파란 막대(회색으로 변하지 않는 것)가 누수 후보
|
|
49
|
+
|
|
50
|
+
### C. Allocation Sampling (함수별 분석)
|
|
51
|
+
|
|
52
|
+
**용도:** 어떤 함수가 메모리를 가장 많이 할당하는지 성능 부담 없이 분석
|
|
53
|
+
|
|
54
|
+
**절차:**
|
|
55
|
+
1. Memory 패널 → **Allocation sampling** → **Start**
|
|
56
|
+
2. 동작 수행 → **Stop**
|
|
57
|
+
3. **Heavy (Bottom Up)** 뷰에서 메모리 소비 함수 Top N 확인
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 흔한 메모리 누수 패턴
|
|
62
|
+
|
|
63
|
+
### 1. Detached DOM
|
|
64
|
+
```js
|
|
65
|
+
// Bad: DOM 제거 후에도 JS에서 참조 유지
|
|
66
|
+
let cachedNode;
|
|
67
|
+
function init() {
|
|
68
|
+
cachedNode = document.getElementById('temp');
|
|
69
|
+
}
|
|
70
|
+
function remove() {
|
|
71
|
+
document.body.removeChild(cachedNode);
|
|
72
|
+
// cachedNode 변수가 여전히 노드를 참조 → GC 불가
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Fix: 참조 해제
|
|
76
|
+
function remove() {
|
|
77
|
+
document.body.removeChild(cachedNode);
|
|
78
|
+
cachedNode = null; // 참조 해제
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. 이벤트 리스너 미제거
|
|
83
|
+
```js
|
|
84
|
+
// Bad: 컴포넌트 unmount 시 리스너 제거 안 함
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
window.addEventListener('resize', handleResize);
|
|
87
|
+
// cleanup 없음
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
// Fix
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
window.addEventListener('resize', handleResize);
|
|
93
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
94
|
+
}, []);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 3. 타이머 미정리
|
|
98
|
+
```js
|
|
99
|
+
// Bad
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
const id = setInterval(poll, 1000);
|
|
102
|
+
// clearInterval 없음
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
// Fix
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
const id = setInterval(poll, 1000);
|
|
108
|
+
return () => clearInterval(id);
|
|
109
|
+
}, []);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 4. 클로저에 의한 의도치 않은 참조 유지
|
|
113
|
+
```js
|
|
114
|
+
// Bad: 큰 배열이 클로저에 캡처됨
|
|
115
|
+
function setup() {
|
|
116
|
+
const bigData = new Array(1000000).fill(0);
|
|
117
|
+
return function handler() {
|
|
118
|
+
// bigData를 실제로 쓰지 않아도 클로저가 유지
|
|
119
|
+
console.log('clicked');
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Fix: 필요한 값만 클로저 내부에 두기
|
|
124
|
+
function setup() {
|
|
125
|
+
const bigData = new Array(1000000).fill(0);
|
|
126
|
+
const needed = bigData[0]; // 필요한 값만 추출
|
|
127
|
+
return function handler() {
|
|
128
|
+
console.log(needed);
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 진단 워크플로우 요약
|
|
136
|
+
|
|
137
|
+
1. Task Manager로 누수 확인 (JavaScript Memory 열 모니터링)
|
|
138
|
+
2. Performance 패널 + Memory 체크박스로 힙 추이 녹화
|
|
139
|
+
3. Heap Snapshot 2개 → Comparison으로 증가 객체 특정
|
|
140
|
+
4. `Detached` 검색으로 떠도는 DOM 확인
|
|
141
|
+
5. Allocation Timeline으로 누수 발생 시점 핀포인트
|
|
142
|
+
6. 코드에서 참조 해제 / cleanup 추가 → 재검증
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## React SPA 특유 주의사항
|
|
147
|
+
|
|
148
|
+
- **useEffect cleanup** 누락이 가장 흔한 원인
|
|
149
|
+
- React 18 StrictMode는 개발 환경에서 useEffect를 2번 실행 → cleanup 누락 즉시 발견 가능
|
|
150
|
+
- 라우트 이동 후 Heap Snapshot 비교: 이전 페이지 컴포넌트 인스턴스가 남아있으면 누수
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Chrome DevTools 성능 패널 진단 가이드
|
|
3
|
+
source: https://developer.chrome.com/docs/devtools/performance
|
|
4
|
+
fetched: 2026-05-18
|
|
5
|
+
category: devtools-perf
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Chrome DevTools Performance Panel
|
|
9
|
+
|
|
10
|
+
## 언제 쓰는가
|
|
11
|
+
|
|
12
|
+
- 페이지가 느리게 느껴질 때 (스크롤 jank, 애니메이션 끊김, 클릭 반응 지연)
|
|
13
|
+
- LCP/TBT/CLS 점수를 개선하기 전 병목 위치 특정
|
|
14
|
+
- "어떤 JS 함수가 메인 스레드를 막는가" 파악
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 기본 녹화 절차
|
|
19
|
+
|
|
20
|
+
1. DevTools 열기 (Mac: `Cmd+Option+I` / Win: `Ctrl+Shift+I`)
|
|
21
|
+
2. **Performance** 탭 선택
|
|
22
|
+
3. **Screenshots** 체크박스 활성화
|
|
23
|
+
4. CPU 스로틀링 설정: 일반 사용자 환경 시뮬레이션 → **4x slowdown** 권장
|
|
24
|
+
5. **Record** 버튼 클릭 → 문제 동작 재현 → **Stop**
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 핵심 지표
|
|
29
|
+
|
|
30
|
+
| 지표 | 설명 | 목표 |
|
|
31
|
+
|------|------|------|
|
|
32
|
+
| **FPS** | 초당 프레임 수. 빨간 바 = jank | 60fps 유지 |
|
|
33
|
+
| **FCP** | First Contentful Paint | ≤ 1.8s |
|
|
34
|
+
| **LCP** | Largest Contentful Paint | ≤ 2.5s |
|
|
35
|
+
| **TBT** | Total Blocking Time (메인 스레드 블로킹 합계) | ≤ 200ms |
|
|
36
|
+
| **CLS** | Cumulative Layout Shift | ≤ 0.1 |
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Flame Chart 읽는 법
|
|
41
|
+
|
|
42
|
+
- **X축**: 시간 경과
|
|
43
|
+
- **Y축**: 콜스택 (위 = 부모, 아래 = 자식)
|
|
44
|
+
- **바 너비**: 실행 시간 (넓을수록 오래 걸림)
|
|
45
|
+
- **빨간 삼각형**: 잠재적 문제 (Long Task, Forced Layout 등)
|
|
46
|
+
- **노란색 바**: JS 실행
|
|
47
|
+
- **보라색 바**: Rendering (Style/Layout)
|
|
48
|
+
- **초록색 바**: Painting
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Long Task 식별
|
|
53
|
+
|
|
54
|
+
- 50ms 이상 메인 스레드를 점유하는 작업 = Long Task
|
|
55
|
+
- Flame chart에서 빨간 삼각형 → 클릭하면 소스 위치로 이동
|
|
56
|
+
- **Summary 탭**에서 시간 분포 확인 (Scripting / Rendering / Painting 비율)
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Forced Layout (Layout Thrashing) 진단
|
|
61
|
+
|
|
62
|
+
**원인:** JS에서 레이아웃 속성(offsetTop, clientWidth 등)을 읽고 쓰기를 반복하면 브라우저가 강제로 layout을 재계산
|
|
63
|
+
|
|
64
|
+
**증상:** Flame chart에서 Layout 블록이 JS 실행 사이사이에 자주 등장
|
|
65
|
+
|
|
66
|
+
**해결:**
|
|
67
|
+
```js
|
|
68
|
+
// Bad: 읽기/쓰기 혼재
|
|
69
|
+
elements.forEach(el => {
|
|
70
|
+
const h = el.offsetHeight; // 읽기 → layout 강제
|
|
71
|
+
el.style.height = h + 10 + 'px'; // 쓰기
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Good: 읽기 먼저, 쓰기 나중에
|
|
75
|
+
const heights = elements.map(el => el.offsetHeight);
|
|
76
|
+
elements.forEach((el, i) => {
|
|
77
|
+
el.style.height = heights[i] + 10 + 'px';
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 진단 워크플로우
|
|
84
|
+
|
|
85
|
+
1. 증상 재현 → Performance 녹화
|
|
86
|
+
2. FPS 차트에서 빨간 구간(drop) 찾기
|
|
87
|
+
3. 해당 구간 Flame chart 줌인
|
|
88
|
+
4. 가장 넓은 바(오래 걸리는 함수) 클릭 → Source 확인
|
|
89
|
+
5. Summary 탭에서 Scripting/Rendering 비율 확인
|
|
90
|
+
6. Long Task 원인: 무거운 JS 계산이면 코드 분할·Web Worker 검토
|
|
91
|
+
7. Rendering 비율 높으면 CSS 속성 변경 최소화, `will-change`, `transform` 활용
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 성능 비교 (Before/After)
|
|
96
|
+
|
|
97
|
+
- 최적화 전 녹화 저장 → 최적화 후 재녹화
|
|
98
|
+
- **CPU throttling 동일하게 맞추기** (결과 재현성)
|
|
99
|
+
- 3회 이상 녹화하여 평균값으로 비교 (노이즈 제거)
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Lighthouse 접근성·성능·Best Practices 항목 레퍼런스
|
|
3
|
+
source: https://developer.chrome.com/docs/lighthouse/accessibility/ https://developer.chrome.com/docs/lighthouse/performance/
|
|
4
|
+
fetched: 2026-05-18
|
|
5
|
+
category: lighthouse
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Lighthouse 감사 항목
|
|
9
|
+
|
|
10
|
+
## 점수 체계
|
|
11
|
+
|
|
12
|
+
- **90–100**: 초록 (Good)
|
|
13
|
+
- **50–89**: 주황 (Needs Improvement)
|
|
14
|
+
- **0–49**: 빨강 (Poor)
|
|
15
|
+
- 접근성 점수: 각 감사 항목의 가중 평균 (axe 영향도 기준), **이진 평가** (부분 통과 없음)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 성능(Performance) 핵심 지표
|
|
20
|
+
|
|
21
|
+
| 지표 | 가중치 | 설명 | 목표 |
|
|
22
|
+
|------|--------|------|------|
|
|
23
|
+
| **LCP** (Largest Contentful Paint) | 25% | 가장 큰 콘텐츠 표시 시점 | ≤ 2.5s |
|
|
24
|
+
| **TBT** (Total Blocking Time) | 30% | 메인 스레드 블로킹 합계 | ≤ 200ms |
|
|
25
|
+
| **CLS** (Cumulative Layout Shift) | 25% | 예기치 않은 레이아웃 이동 | ≤ 0.1 |
|
|
26
|
+
| **FCP** (First Contentful Paint) | 10% | 초기 콘텐츠 표시 시점 | ≤ 1.8s |
|
|
27
|
+
| **Speed Index** | 10% | 시각적 완성 속도 | ≤ 3.4s |
|
|
28
|
+
|
|
29
|
+
**주의:** 점수 변동 요인 — A/B 테스트, 네트워크 라우팅, 브라우저 확장, 안티바이러스. 3회 이상 측정 평균값 사용 권장.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 접근성(Accessibility) 감사 항목
|
|
34
|
+
|
|
35
|
+
### ARIA 관련
|
|
36
|
+
|
|
37
|
+
| 항목 | 가중치 | 핵심 |
|
|
38
|
+
|------|--------|------|
|
|
39
|
+
| `[aria-*]` 속성이 역할과 일치 | 10 | 잘못된 aria 조합 방지 |
|
|
40
|
+
| `[aria-*]` 값이 유효 | 10 | 오타·잘못된 값 방지 |
|
|
41
|
+
| `[role]` 값이 유효 | 10 | 표준 role만 사용 |
|
|
42
|
+
| role에 필요한 `[aria-*]` 모두 제공 | 10 | 불완전한 ARIA 패턴 방지 |
|
|
43
|
+
| 자식 role 요건 충족 | 10 | `listbox > option` 등 구조 준수 |
|
|
44
|
+
| 부모 role 요건 충족 | 10 | `li` → `ul/ol` 내부 등 |
|
|
45
|
+
|
|
46
|
+
### 이름(Accessible Name) 관련
|
|
47
|
+
|
|
48
|
+
| 항목 | 가중치 | 핵심 |
|
|
49
|
+
|------|--------|------|
|
|
50
|
+
| 버튼에 접근 가능한 이름 | 10 | `aria-label` or 텍스트 콘텐츠 필수 |
|
|
51
|
+
| 링크에 식별 가능한 이름 | 7 | "여기 클릭" 같은 모호한 링크 금지 |
|
|
52
|
+
| 폼 요소에 레이블 연결 | 10 | `<label for>` or `aria-label` |
|
|
53
|
+
| 이미지에 `alt` 속성 | 10 | 장식 이미지는 `alt=""` |
|
|
54
|
+
| `<video>`에 자막 트랙 | 10 | `<track kind="captions">` |
|
|
55
|
+
| 다이얼로그에 접근 가능한 이름 | 7 | `aria-labelledby` or `aria-label` |
|
|
56
|
+
|
|
57
|
+
### 포커스·내비게이션
|
|
58
|
+
|
|
59
|
+
| 항목 | 가중치 | 핵심 |
|
|
60
|
+
|------|--------|------|
|
|
61
|
+
| `tabindex` > 0 없음 | 7 | 자연스러운 탭 순서 방해 금지 |
|
|
62
|
+
| 스킵 링크가 포커스 가능 | 3 | `<a href="#main">` 등 |
|
|
63
|
+
| 페이지에 제목/랜드마크/스킵링크 존재 | 7 | 스크린리더 내비게이션 진입점 |
|
|
64
|
+
|
|
65
|
+
### 구조·시맨틱
|
|
66
|
+
|
|
67
|
+
| 항목 | 가중치 | 핵심 |
|
|
68
|
+
|------|--------|------|
|
|
69
|
+
| `<html lang>` 유효한 언어 코드 | 7 | `lang="ko"` |
|
|
70
|
+
| `<title>` 요소 존재 | 7 | 탭/스크린리더 페이지 식별 |
|
|
71
|
+
| 제목 계층 순차적 (h1→h2→h3) | 3 | 건너뛰기 금지 |
|
|
72
|
+
| 리스트 구조 올바름 | 7 | `<ul>` > `<li>` only |
|
|
73
|
+
|
|
74
|
+
### 시각·색상
|
|
75
|
+
|
|
76
|
+
| 항목 | 가중치 | 핵심 |
|
|
77
|
+
|------|--------|------|
|
|
78
|
+
| 배경/전경 색상 대비 충분 | 7 | 일반 텍스트 4.5:1, 큰 텍스트 3:1 |
|
|
79
|
+
| 링크가 색상 외 수단으로 구별 | 7 | 밑줄, 아이콘 등 |
|
|
80
|
+
| 사용자 확대 허용 (`user-scalable`) | 10 | `maximum-scale` ≥ 5 |
|
|
81
|
+
|
|
82
|
+
### 숨김·포커스 관리
|
|
83
|
+
|
|
84
|
+
| 항목 | 가중치 | 핵심 |
|
|
85
|
+
|------|--------|------|
|
|
86
|
+
| `aria-hidden="true"` 요소에 포커스 가능 자식 없음 | 7 | 숨겨진 요소에 탭 진입 방지 |
|
|
87
|
+
| `<body>`에 `aria-hidden="true"` 없음 | 10 | 전체 페이지 숨김 금지 |
|
|
88
|
+
|
|
89
|
+
### 고유 식별자
|
|
90
|
+
|
|
91
|
+
| 항목 | 가중치 | 핵심 |
|
|
92
|
+
|------|--------|------|
|
|
93
|
+
| ARIA ID 중복 없음 | 10 | `aria-labelledby` 오작동 방지 |
|
|
94
|
+
| 포커스 가능 요소의 `id` 중복 없음 | 7 | |
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 자주 실패하는 항목 & 빠른 수정
|
|
99
|
+
|
|
100
|
+
```html
|
|
101
|
+
<!-- 1. 버튼 이름 없음 (가중치 10) -->
|
|
102
|
+
<!-- Bad -->
|
|
103
|
+
<button><img src="close.svg"></button>
|
|
104
|
+
<!-- Fix -->
|
|
105
|
+
<button aria-label="닫기"><img src="close.svg" alt=""></button>
|
|
106
|
+
|
|
107
|
+
<!-- 2. 입력 필드 레이블 없음 (가중치 10) -->
|
|
108
|
+
<!-- Bad -->
|
|
109
|
+
<input type="text" placeholder="이름">
|
|
110
|
+
<!-- Fix -->
|
|
111
|
+
<label for="name">이름</label>
|
|
112
|
+
<input id="name" type="text">
|
|
113
|
+
|
|
114
|
+
<!-- 3. 이미지 alt 없음 (가중치 10) -->
|
|
115
|
+
<!-- Bad -->
|
|
116
|
+
<img src="hero.jpg">
|
|
117
|
+
<!-- Fix -->
|
|
118
|
+
<img src="hero.jpg" alt="서비스 히어로 이미지">
|
|
119
|
+
|
|
120
|
+
<!-- 4. 사용자 확대 차단 (가중치 10) -->
|
|
121
|
+
<!-- Bad -->
|
|
122
|
+
<meta name="viewport" content="width=device-width, user-scalable=no">
|
|
123
|
+
<!-- Fix -->
|
|
124
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
125
|
+
|
|
126
|
+
<!-- 5. 색상 대비 부족 (가중치 7) -->
|
|
127
|
+
<!-- Bad: #999 on white = 2.85:1 -->
|
|
128
|
+
<p style="color: #999;">안내 텍스트</p>
|
|
129
|
+
<!-- Fix: #767676 on white = 4.54:1 -->
|
|
130
|
+
<p style="color: #767676;">안내 텍스트</p>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Lighthouse 실행 방법
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# CLI
|
|
139
|
+
npm install -g lighthouse
|
|
140
|
+
lighthouse https://example.com --output html --output-path report.html
|
|
141
|
+
|
|
142
|
+
# 특정 카테고리만
|
|
143
|
+
lighthouse https://example.com --only-categories=accessibility,performance
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
DevTools → Lighthouse 탭 → 카테고리 선택 → Analyze page load
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: React DevTools Profiler 렌더 진단 가이드
|
|
3
|
+
source: https://react.dev/learn/react-developer-tools
|
|
4
|
+
fetched: 2026-05-18
|
|
5
|
+
category: react-profiler
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# React DevTools Profiler
|
|
9
|
+
|
|
10
|
+
## 설치
|
|
11
|
+
|
|
12
|
+
### 브라우저 확장 (권장)
|
|
13
|
+
- Chrome: [Chrome Web Store](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi)
|
|
14
|
+
- Firefox: [Mozilla Add-ons](https://addons.mozilla.org/en-US/firefox/addon/react-devtools/)
|
|
15
|
+
- Edge: [Edge Add-ons](https://microsoftedge.microsoft.com/addons/detail/react-developer-tools/gpphkfbcpidddadnkolkpfckpihlkkil)
|
|
16
|
+
|
|
17
|
+
### Safari / 기타
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g react-devtools
|
|
20
|
+
react-devtools
|
|
21
|
+
```
|
|
22
|
+
`<head>`에 추가:
|
|
23
|
+
```html
|
|
24
|
+
<script src="http://localhost:8097"></script>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
DevTools 열면 **Components** 탭과 **Profiler** 탭이 생긴다.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Profiler 탭 기본 사용
|
|
32
|
+
|
|
33
|
+
### 녹화
|
|
34
|
+
1. Profiler 탭 → **Record** 버튼(원형) 클릭
|
|
35
|
+
2. 문제 동작 수행 (버튼 클릭, 입력, 페이지 이동 등)
|
|
36
|
+
3. **Stop** 클릭
|
|
37
|
+
|
|
38
|
+
### React의 두 단계 이해
|
|
39
|
+
- **Render phase**: `render()` 호출, 이전 결과와 diff 계산
|
|
40
|
+
- **Commit phase**: 실제 DOM에 변경 반영, lifecycle 호출
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Flame Chart 읽는 법
|
|
45
|
+
|
|
46
|
+
- **가로 길이**: 렌더에 걸린 시간 (길수록 느림)
|
|
47
|
+
- **색상**
|
|
48
|
+
- 노란색(황색): 상대적으로 느린 렌더
|
|
49
|
+
- 파란색: 상대적으로 빠른 렌더
|
|
50
|
+
- 회색: 이 commit에서 렌더되지 않음 (재사용됨)
|
|
51
|
+
- 컴포넌트 클릭 → 우측 패널에서 해당 commit의 props/state 확인
|
|
52
|
+
- **commit bar** (상단 막대): 각 commit의 상대적 소요 시간. 높을수록 느린 commit
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Ranked Chart
|
|
57
|
+
|
|
58
|
+
- 단일 commit에서 렌더 시간 기준으로 컴포넌트를 내림차순 정렬
|
|
59
|
+
- 맨 위 = 가장 느린 컴포넌트 (자식 포함 합산)
|
|
60
|
+
- 병목 컴포넌트를 빠르게 특정할 때 유용
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## "Why did this render?" 기능
|
|
65
|
+
|
|
66
|
+
Profiler 설정(⚙️) → **"Record why each component rendered while profiling"** 활성화
|
|
67
|
+
|
|
68
|
+
녹화 후 컴포넌트 클릭 → **"Why did this render?"** 섹션에 원인 표시:
|
|
69
|
+
- `Props changed` + 변경된 prop 이름
|
|
70
|
+
- `State changed` + 변경된 state 이름
|
|
71
|
+
- `Context changed`
|
|
72
|
+
- `Hooks changed`
|
|
73
|
+
- `Parent component rendered`
|
|
74
|
+
|
|
75
|
+
**흔한 불필요 렌더 원인:**
|
|
76
|
+
```js
|
|
77
|
+
// Bad: 매 렌더마다 새 객체 생성
|
|
78
|
+
<MyComp style={{ color: 'red' }} />
|
|
79
|
+
|
|
80
|
+
// Fix: 객체를 외부로 분리 or useMemo
|
|
81
|
+
const style = { color: 'red' };
|
|
82
|
+
<MyComp style={style} />
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Highlight Updates 기능
|
|
88
|
+
|
|
89
|
+
Components 탭 → 설정(⚙️) → **"Highlight updates when components render"** 활성화
|
|
90
|
+
|
|
91
|
+
페이지 위에서 컴포넌트가 렌더될 때 파란→노란→빨간 테두리로 강조:
|
|
92
|
+
- 파란색: 렌더 횟수 적음
|
|
93
|
+
- 빨간색: 렌더 횟수 많음 (최적화 필요)
|
|
94
|
+
|
|
95
|
+
스크롤하거나 마우스를 움직이기만 해도 렌더되는 컴포넌트를 시각적으로 파악 가능
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 불필요 렌더 최적화 체크리스트
|
|
100
|
+
|
|
101
|
+
| 원인 | 해결 |
|
|
102
|
+
|------|------|
|
|
103
|
+
| 부모 렌더 시 자식 전체 재렌더 | `React.memo()` 로 자식 메모이제이션 |
|
|
104
|
+
| 매 렌더마다 새 함수/객체 props | `useCallback`, `useMemo` 사용 |
|
|
105
|
+
| Context 값 변경 시 모든 소비자 재렌더 | Context 분리 또는 `useMemo`로 값 안정화 |
|
|
106
|
+
| State 위치가 너무 높음 | State를 사용하는 컴포넌트 가까이 내리기 |
|
|
107
|
+
| List에 key 없거나 index 사용 | 고유 ID를 key로 사용 |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 프로덕션 환경 프로파일링
|
|
112
|
+
|
|
113
|
+
기본적으로 프로파일러는 개발 빌드에서만 동작.
|
|
114
|
+
프로덕션에서 사용하려면:
|
|
115
|
+
```bash
|
|
116
|
+
# webpack alias 설정
|
|
117
|
+
react-dom/profiling 대신 react-dom 사용 (package.json alias)
|
|
118
|
+
```
|
|
119
|
+
또는 번들러에서 `react-dom/profiling`으로 alias 처리.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Component 탭 활용 팁
|
|
124
|
+
|
|
125
|
+
- 컴포넌트 선택 → props/state 실시간 편집 (빠른 검증)
|
|
126
|
+
- `$r` : 선택된 컴포넌트 인스턴스를 콘솔에서 참조 가능
|
|
127
|
+
- 검색창에서 컴포넌트 이름으로 필터링
|
|
128
|
+
- Suspense boundary 시각적으로 확인 가능
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: WCAG 2.2 신규 성공 기준 9개
|
|
3
|
+
source: https://www.w3.org/WAI/WCAG22/quickref/
|
|
4
|
+
fetched: 2026-05-18
|
|
5
|
+
category: wcag22
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# WCAG 2.2 신규 성공 기준 (2023년 10월 W3C 권고)
|
|
9
|
+
|
|
10
|
+
WCAG 2.2는 WCAG 2.1에 9개의 신규 Success Criteria(SC)를 추가했다. 아래는 각 SC의 레벨, 핵심 요건, 영향받는 컴포넌트 패턴을 정리한다.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 2.4.11 Focus Not Obscured (Minimum)
|
|
15
|
+
**레벨: AA**
|
|
16
|
+
|
|
17
|
+
**요약:** 키보드 포커스를 받은 컴포넌트가 다른 콘텐츠에 완전히 가려지면 안 된다.
|
|
18
|
+
|
|
19
|
+
**영향받는 패턴:**
|
|
20
|
+
- Sticky header / sticky footer 내부에 포함된 인터랙티브 요소
|
|
21
|
+
- Fixed position modal backdrop 뒤로 숨겨지는 요소
|
|
22
|
+
- z-index 문제로 포커스 링이 가려지는 custom dropdown, tooltip
|
|
23
|
+
|
|
24
|
+
**실전 체크:**
|
|
25
|
+
- `position: sticky` 헤더 높이만큼 `scroll-margin-top` 설정
|
|
26
|
+
- 모달 열릴 때 focus trap 적용하여 모달 외부 요소가 포커스 안 받도록 처리
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 2.4.12 Focus Not Obscured (Enhanced)
|
|
31
|
+
**레벨: AAA**
|
|
32
|
+
|
|
33
|
+
**요약:** 포커스 인디케이터가 최소한의 겹침도 없이 완전히 보여야 한다. (2.4.11의 강화 버전)
|
|
34
|
+
|
|
35
|
+
**영향받는 패턴:**
|
|
36
|
+
- 2.4.11과 동일하나 더 엄격: 부분적 가려짐도 불허
|
|
37
|
+
- 팝오버, 드롭다운, 툴팁이 포커스 요소 위를 부분적으로라도 덮는 경우
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2.4.13 Focus Appearance
|
|
42
|
+
**레벨: AA**
|
|
43
|
+
|
|
44
|
+
**요약:** 포커스 인디케이터는 최소 크기, 색상 대비, 시각적 구분 기준을 만족해야 한다.
|
|
45
|
+
|
|
46
|
+
**요건:**
|
|
47
|
+
- 포커스 인디케이터 둘레: 컴포넌트 경계의 최소 CSS 둘레 길이만큼의 영역
|
|
48
|
+
- 색상 대비: 포커스 전후 색상 차이 3:1 이상
|
|
49
|
+
|
|
50
|
+
**영향받는 패턴:**
|
|
51
|
+
- `outline: none` 으로 포커스 링 제거한 모든 컴포넌트
|
|
52
|
+
- 커스텀 버튼, 링크, 입력 필드의 `:focus-visible` 스타일
|
|
53
|
+
- 브라우저 기본 outline을 덮어쓰는 컴포넌트 라이브러리
|
|
54
|
+
|
|
55
|
+
**실전 체크:**
|
|
56
|
+
```css
|
|
57
|
+
/* 최소 요건 충족 예시 */
|
|
58
|
+
:focus-visible {
|
|
59
|
+
outline: 2px solid #005FCC;
|
|
60
|
+
outline-offset: 2px;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 2.5.7 Dragging Movements
|
|
67
|
+
**레벨: AA**
|
|
68
|
+
|
|
69
|
+
**요약:** 드래그 제스처가 필요한 모든 기능은 단일 포인터(클릭/탭)로 대체 가능해야 한다.
|
|
70
|
+
|
|
71
|
+
**영향받는 패턴:**
|
|
72
|
+
- Drag-and-drop 파일 업로드 → 클릭으로 파일 선택 버튼 필요
|
|
73
|
+
- 정렬 가능한 리스트(sortable list) → 키보드/버튼 기반 순서 변경 제공
|
|
74
|
+
- 슬라이더(range input) → 키보드 방향키로 값 조정 가능해야 함
|
|
75
|
+
- Carousel / 이미지 스와이프 → 이전/다음 버튼 필수
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 2.5.8 Target Size (Minimum)
|
|
80
|
+
**레벨: AA**
|
|
81
|
+
|
|
82
|
+
**요약:** 포인터 입력 대상(터치/클릭 영역)은 최소 24×24 CSS px 이상이어야 한다.
|
|
83
|
+
|
|
84
|
+
**예외:** 대상 간격이 24px 이상이거나, 인라인 텍스트 링크, 브라우저 기본 컨트롤은 예외
|
|
85
|
+
|
|
86
|
+
**영향받는 패턴:**
|
|
87
|
+
- 아이콘 버튼 (닫기, 좋아요, 공유) — padding으로 터치 영역 확보 필요
|
|
88
|
+
- 체크박스, 라디오 버튼의 실제 클릭 영역
|
|
89
|
+
- 테이블 내 액션 버튼, 태그 삭제 버튼
|
|
90
|
+
|
|
91
|
+
**실전 체크:**
|
|
92
|
+
```css
|
|
93
|
+
/* 아이콘 버튼 터치 영역 확보 */
|
|
94
|
+
.icon-btn {
|
|
95
|
+
min-width: 24px;
|
|
96
|
+
min-height: 24px;
|
|
97
|
+
padding: 8px; /* 시각적 크기와 터치 영역 분리 */
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 3.2.6 Consistent Help
|
|
104
|
+
**레벨: A**
|
|
105
|
+
|
|
106
|
+
**요약:** 도움말 메커니즘(고객센터 링크, 챗봇, FAQ 등)은 같은 유형의 페이지 내에서 일관된 위치에 제공해야 한다.
|
|
107
|
+
|
|
108
|
+
**영향받는 패턴:**
|
|
109
|
+
- 글로벌 네비게이션 내 고객센터/도움말 링크
|
|
110
|
+
- 페이지마다 위치가 달라지는 채팅 위젯
|
|
111
|
+
- 온보딩 툴팁 버튼의 비일관적 배치
|
|
112
|
+
|
|
113
|
+
**실전 체크:** 도움말 관련 UI 요소의 위치를 공통 레이아웃 컴포넌트로 고정
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 3.3.7 Redundant Entry
|
|
118
|
+
**레벨: A**
|
|
119
|
+
|
|
120
|
+
**요약:** 같은 세션 내 이전에 입력한 정보를 다시 입력하도록 요구하면 안 된다.
|
|
121
|
+
|
|
122
|
+
**영향받는 패턴:**
|
|
123
|
+
- 멀티 스텝 폼 (배송지 → 청구지 주소 동일 여부)
|
|
124
|
+
- 회원가입 후 바로 로그인 정보 재입력 요구
|
|
125
|
+
- 이메일 확인을 위한 이메일 재입력 필드
|
|
126
|
+
|
|
127
|
+
**실전 체크:**
|
|
128
|
+
- 이전 단계 값 자동 채우기 or "이전과 동일" 체크박스 제공
|
|
129
|
+
- 확인용 재입력이 꼭 필요하면 허용되나 최소화
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 3.3.8 Accessible Authentication (Minimum)
|
|
134
|
+
**레벨: AA**
|
|
135
|
+
|
|
136
|
+
**요약:** 인증 과정에서 인지 기능 테스트(퍼즐, 기억, 계산)에만 의존하면 안 된다.
|
|
137
|
+
|
|
138
|
+
**허용 예외:** 사용자 제공 오브젝트 인식, 비비음문자(non-text) CAPTCHA에 대체 수단 제공
|
|
139
|
+
|
|
140
|
+
**영향받는 패턴:**
|
|
141
|
+
- 텍스트 기반 CAPTCHA → 오디오 CAPTCHA 또는 이미지 CAPTCHA 대안 필요
|
|
142
|
+
- 복잡한 보안 질문만으로 구성된 로그인
|
|
143
|
+
- OTP/매직링크 대안 없이 복잡한 패스워드 규칙만 강제
|
|
144
|
+
|
|
145
|
+
**실전 체크:**
|
|
146
|
+
- 패스워드 매니저 지원 (`autocomplete` 속성 적절히 설정)
|
|
147
|
+
- 생체인증, 매직링크, 소셜 로그인 등 대안 제공
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 3.3.9 Accessible Authentication (Enhanced)
|
|
152
|
+
**레벨: AAA**
|
|
153
|
+
|
|
154
|
+
**요약:** 3.3.8보다 강화된 요건 — 인지 기능 테스트를 완전히 배제해야 한다. 오브젝트 인식 예외도 불허.
|
|
155
|
+
|
|
156
|
+
**영향받는 패턴:**
|
|
157
|
+
- 3.3.8과 동일하나 이미지 선택 CAPTCHA도 불허
|
|
158
|
+
- 완전히 패스워드리스(passwordless) 인증 또는 완전 대체 수단 필요
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 체크리스트 요약
|
|
163
|
+
|
|
164
|
+
| SC | 레벨 | 핵심 포인트 |
|
|
165
|
+
|----|------|------------|
|
|
166
|
+
| 2.4.11 | AA | 포커스 완전 가려짐 금지 |
|
|
167
|
+
| 2.4.12 | AAA | 포커스 부분 가려짐도 금지 |
|
|
168
|
+
| 2.4.13 | AA | 포커스 인디케이터 크기·대비 기준 |
|
|
169
|
+
| 2.5.7 | AA | 드래그 → 단일 포인터 대안 필수 |
|
|
170
|
+
| 2.5.8 | AA | 터치 타겟 최소 24×24px |
|
|
171
|
+
| 3.2.6 | A | 도움말 위치 일관성 |
|
|
172
|
+
| 3.3.7 | A | 이전 입력 재입력 금지 |
|
|
173
|
+
| 3.3.8 | AA | 인증 인지 테스트 대안 필수 |
|
|
174
|
+
| 3.3.9 | AAA | 인증 인지 테스트 완전 배제 |
|