swwa-mcp 0.1.0

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.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -0
  3. package/assets/alt-text-ko.json +7 -0
  4. package/assets/axe-rule-map.json +196 -0
  5. package/assets/certification.json +47 -0
  6. package/assets/kwcag22-checklist.md +123 -0
  7. package/assets/kwcag22.json +1688 -0
  8. package/assets/link-text-ko.json +8 -0
  9. package/assets/mobile-app-2.0.md +38 -0
  10. package/assets/sources.json +68 -0
  11. package/assets/wcag22.json +780 -0
  12. package/bin/swwa-mcp.mjs +15 -0
  13. package/dist/color/contrast.js +175 -0
  14. package/dist/color/contrast.js.map +1 -0
  15. package/dist/data/axe-map.js +32 -0
  16. package/dist/data/axe-map.js.map +1 -0
  17. package/dist/data/certification.js +54 -0
  18. package/dist/data/certification.js.map +1 -0
  19. package/dist/data/kwcag22.js +91 -0
  20. package/dist/data/kwcag22.js.map +1 -0
  21. package/dist/data/loader.js +18 -0
  22. package/dist/data/loader.js.map +1 -0
  23. package/dist/data/sources.js +44 -0
  24. package/dist/data/sources.js.map +1 -0
  25. package/dist/data/wcag22.js +44 -0
  26. package/dist/data/wcag22.js.map +1 -0
  27. package/dist/data/wordlists.js +40 -0
  28. package/dist/data/wordlists.js.map +1 -0
  29. package/dist/engine/browser-detect.js +44 -0
  30. package/dist/engine/browser-detect.js.map +1 -0
  31. package/dist/engine/browser.js +114 -0
  32. package/dist/engine/browser.js.map +1 -0
  33. package/dist/engine/static-worker.js +18 -0
  34. package/dist/engine/static-worker.js.map +1 -0
  35. package/dist/engine/static.js +139 -0
  36. package/dist/engine/static.js.map +1 -0
  37. package/dist/engine/url-guard.js +37 -0
  38. package/dist/engine/url-guard.js.map +1 -0
  39. package/dist/index.js +23 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/messages.js +176 -0
  42. package/dist/messages.js.map +1 -0
  43. package/dist/normalize/axe.js +72 -0
  44. package/dist/normalize/axe.js.map +1 -0
  45. package/dist/normalize/checkpoints.js +47 -0
  46. package/dist/normalize/checkpoints.js.map +1 -0
  47. package/dist/normalize/finding.js +24 -0
  48. package/dist/normalize/finding.js.map +1 -0
  49. package/dist/normalize/locale.js +20 -0
  50. package/dist/normalize/locale.js.map +1 -0
  51. package/dist/prompts/audit-report.js +45 -0
  52. package/dist/prompts/audit-report.js.map +1 -0
  53. package/dist/prompts/review-markup.js +35 -0
  54. package/dist/prompts/review-markup.js.map +1 -0
  55. package/dist/report/cert.js +72 -0
  56. package/dist/report/cert.js.map +1 -0
  57. package/dist/report/format.js +36 -0
  58. package/dist/report/format.js.map +1 -0
  59. package/dist/report/summarize.js +61 -0
  60. package/dist/report/summarize.js.map +1 -0
  61. package/dist/report/types.js +2 -0
  62. package/dist/report/types.js.map +1 -0
  63. package/dist/resources/index.js +69 -0
  64. package/dist/resources/index.js.map +1 -0
  65. package/dist/rules/b/b-focus-order.js +33 -0
  66. package/dist/rules/b/b-focus-order.js.map +1 -0
  67. package/dist/rules/b/b-focus-visible.js +71 -0
  68. package/dist/rules/b/b-focus-visible.js.map +1 -0
  69. package/dist/rules/b/b-keyboard-reachable.js +82 -0
  70. package/dist/rules/b/b-keyboard-reachable.js.map +1 -0
  71. package/dist/rules/b/b-motion-runtime.js +50 -0
  72. package/dist/rules/b/b-motion-runtime.js.map +1 -0
  73. package/dist/rules/b/b-skip-link-works.js +58 -0
  74. package/dist/rules/b/b-skip-link-works.js.map +1 -0
  75. package/dist/rules/b/b-target-size-6mm.js +54 -0
  76. package/dist/rules/b/b-target-size-6mm.js.map +1 -0
  77. package/dist/rules/b/index.js +7 -0
  78. package/dist/rules/b/index.js.map +1 -0
  79. package/dist/rules/k/index.js +33 -0
  80. package/dist/rules/k/index.js.map +1 -0
  81. package/dist/rules/k/k-accesskey.js +20 -0
  82. package/dist/rules/k/k-accesskey.js.map +1 -0
  83. package/dist/rules/k/k-alt-meaningless.js +35 -0
  84. package/dist/rules/k/k-alt-meaningless.js.map +1 -0
  85. package/dist/rules/k/k-autocomplete-missing.js +36 -0
  86. package/dist/rules/k/k-autocomplete-missing.js.map +1 -0
  87. package/dist/rules/k/k-autoplay-media.js +30 -0
  88. package/dist/rules/k/k-autoplay-media.js.map +1 -0
  89. package/dist/rules/k/k-captcha-detect.js +24 -0
  90. package/dist/rules/k/k-captcha-detect.js.map +1 -0
  91. package/dist/rules/k/k-carousel-no-pause.js +33 -0
  92. package/dist/rules/k/k-carousel-no-pause.js.map +1 -0
  93. package/dist/rules/k/k-device-motion.js +22 -0
  94. package/dist/rules/k/k-device-motion.js.map +1 -0
  95. package/dist/rules/k/k-down-event-action.js +19 -0
  96. package/dist/rules/k/k-down-event-action.js.map +1 -0
  97. package/dist/rules/k/k-error-association.js +31 -0
  98. package/dist/rules/k/k-error-association.js.map +1 -0
  99. package/dist/rules/k/k-flash-animation.js +57 -0
  100. package/dist/rules/k/k-flash-animation.js.map +1 -0
  101. package/dist/rules/k/k-gesture-listener.js +30 -0
  102. package/dist/rules/k/k-gesture-listener.js.map +1 -0
  103. package/dist/rules/k/k-iframe-title.js +23 -0
  104. package/dist/rules/k/k-iframe-title.js.map +1 -0
  105. package/dist/rules/k/k-lang-ko-expected.js +29 -0
  106. package/dist/rules/k/k-lang-ko-expected.js.map +1 -0
  107. package/dist/rules/k/k-link-same-text-diff-href.js +41 -0
  108. package/dist/rules/k/k-link-same-text-diff-href.js.map +1 -0
  109. package/dist/rules/k/k-link-text-generic.js +29 -0
  110. package/dist/rules/k/k-link-text-generic.js.map +1 -0
  111. package/dist/rules/k/k-media-track.js +22 -0
  112. package/dist/rules/k/k-media-track.js.map +1 -0
  113. package/dist/rules/k/k-mouse-only-handler.js +27 -0
  114. package/dist/rules/k/k-mouse-only-handler.js.map +1 -0
  115. package/dist/rules/k/k-new-window-notice.js +27 -0
  116. package/dist/rules/k/k-new-window-notice.js.map +1 -0
  117. package/dist/rules/k/k-onload-popup.js +30 -0
  118. package/dist/rules/k/k-onload-popup.js.map +1 -0
  119. package/dist/rules/k/k-outline-none.js +55 -0
  120. package/dist/rules/k/k-outline-none.js.map +1 -0
  121. package/dist/rules/k/k-parse-errors.js +38 -0
  122. package/dist/rules/k/k-parse-errors.js.map +1 -0
  123. package/dist/rules/k/k-placeholder-only-label.js +32 -0
  124. package/dist/rules/k/k-placeholder-only-label.js.map +1 -0
  125. package/dist/rules/k/k-select-onchange.js +19 -0
  126. package/dist/rules/k/k-select-onchange.js.map +1 -0
  127. package/dist/rules/k/k-sensory-instruction.js +32 -0
  128. package/dist/rules/k/k-sensory-instruction.js.map +1 -0
  129. package/dist/rules/k/k-session-timeout-hint.js +29 -0
  130. package/dist/rules/k/k-session-timeout-hint.js.map +1 -0
  131. package/dist/rules/k/k-skip-link-first.js +23 -0
  132. package/dist/rules/k/k-skip-link-first.js.map +1 -0
  133. package/dist/rules/k/k-skip-target-exists.js +28 -0
  134. package/dist/rules/k/k-skip-target-exists.js.map +1 -0
  135. package/dist/rules/k/k-tabindex-positive.js +23 -0
  136. package/dist/rules/k/k-tabindex-positive.js.map +1 -0
  137. package/dist/rules/k/k-table-caption.js +26 -0
  138. package/dist/rules/k/k-table-caption.js.map +1 -0
  139. package/dist/rules/k/k-table-th-missing.js +28 -0
  140. package/dist/rules/k/k-table-th-missing.js.map +1 -0
  141. package/dist/rules/k/k-title-generic.js +35 -0
  142. package/dist/rules/k/k-title-generic.js.map +1 -0
  143. package/dist/rules/registry.js +62 -0
  144. package/dist/rules/registry.js.map +1 -0
  145. package/dist/rules/types.js +2 -0
  146. package/dist/rules/types.js.map +1 -0
  147. package/dist/rules/util/browser-dom.js +50 -0
  148. package/dist/rules/util/browser-dom.js.map +1 -0
  149. package/dist/rules/util/focusable.js +29 -0
  150. package/dist/rules/util/focusable.js.map +1 -0
  151. package/dist/rules/util/selector.js +19 -0
  152. package/dist/rules/util/selector.js.map +1 -0
  153. package/dist/rules/util/text.js +13 -0
  154. package/dist/rules/util/text.js.map +1 -0
  155. package/dist/schema-dialect.js +41 -0
  156. package/dist/schema-dialect.js.map +1 -0
  157. package/dist/server.js +36 -0
  158. package/dist/server.js.map +1 -0
  159. package/dist/tools/audit-url.js +109 -0
  160. package/dist/tools/audit-url.js.map +1 -0
  161. package/dist/tools/browser-status.js +29 -0
  162. package/dist/tools/browser-status.js.map +1 -0
  163. package/dist/tools/cert-readiness.js +76 -0
  164. package/dist/tools/cert-readiness.js.map +1 -0
  165. package/dist/tools/check-contrast.js +58 -0
  166. package/dist/tools/check-contrast.js.map +1 -0
  167. package/dist/tools/check-html.js +88 -0
  168. package/dist/tools/check-html.js.map +1 -0
  169. package/dist/tools/checklist.js +94 -0
  170. package/dist/tools/checklist.js.map +1 -0
  171. package/dist/tools/lookup.js +70 -0
  172. package/dist/tools/lookup.js.map +1 -0
  173. package/dist/tools/report-schema.js +49 -0
  174. package/dist/tools/report-schema.js.map +1 -0
  175. package/package.json +76 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SWJoong and SWWA contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # SWWA — 웹 접근성(KWCAG 2.2) Skill + MCP
2
+
3
+ 국가표준 **KWCAG 2.2**(한국형 웹 콘텐츠 접근성 지침, 4원칙·14지침·33개 검사항목)와 **웹 접근성 품질인증** 기준으로 웹 콘텐츠의 접근성을 검사·리뷰·인증 준비하도록 돕는 Claude Code 플러그인(스킬 3종)과 MCP 서버(npm `swwa-mcp`)입니다.
4
+
5
+ > 판정·측정·지식은 서버(결정적·오프라인)가, 해석·수정안·보고서는 클라이언트 LLM이. 도구의 자동 판정은 전문가·사용자 심사를 대체하지 않습니다.
6
+
7
+ ## 설치
8
+
9
+ ```bash
10
+ # Claude Code 플러그인 (스킬 3종 포함, 권장)
11
+ /plugin marketplace add SWJoong/SWWA
12
+ /plugin install swwa@swwa
13
+
14
+ # 또는 MCP 서버만
15
+ claude mcp add swwa -- npx -y swwa-mcp # Claude Code
16
+ npx -y swwa-mcp # 다른 MCP 클라이언트
17
+ ```
18
+
19
+ 자세한 설치·첫 사용: [docs/install/](docs/install/) ([Claude Code](docs/install/claude-code.md) · [Claude Desktop](docs/install/claude-desktop.md) · [처음 사용해보기](docs/install/first-use.md)).
20
+
21
+ ## 구성
22
+
23
+ | 구성 | 내용 |
24
+ |---|---|
25
+ | 스킬 `kwcag-guide` | KWCAG 2.2 33개 검사항목·WCAG 2.2 매핑·품질인증 기준·모바일 앱 지침 2.0 요약 (도메인 지식) |
26
+ | 스킬 `a11y-review` | HTML·JSX·Vue·Svelte·CSS를 검사항목 ID 기준으로 리뷰하고 수정안 제시 |
27
+ | 스킬 `a11y-audit` | URL을 실제 브라우저로 감사해 33항목 판정표·보고서·인증 준비도 산출 |
28
+ | MCP 도구 7종 | `check_html` · `check_contrast` · `lookup_checkpoint` · `get_checklist` · `audit_url` · `browser_status` · `estimate_cert_readiness` |
29
+ | MCP 프롬프트·리소스 | `review-markup` · `audit-report` / `swwa://kwcag22` 등 6종 |
30
+
31
+ - 정적 검사(jsdom + axe-core 한국어 로케일 + 자체 `k-` 규칙 18종)는 브라우저 없이 동작합니다.
32
+ - 브라우저 감사(playwright-core + @axe-core/playwright + 자체 `b-` 규칙 6종)는 설치된 Chrome/Edge를 자동 사용하며, 없으면 `npx playwright install chromium`을 안내합니다.
33
+
34
+ ## 문서
35
+
36
+ - [CHANGELOG.md](CHANGELOG.md) — 버전별 변경
37
+ - [docs/plan/00-overview.md](docs/plan/00-overview.md) — 총괄·기술 스택·로드맵
38
+ - [docs/plan/02-architecture.md](docs/plan/02-architecture.md) — MCP 인터페이스 명세(계약)·Report 스키마·데이터 모델
39
+ - [skills/kwcag-guide/references/kwcag22-checklist.md](skills/kwcag-guide/references/kwcag22-checklist.md) — 검사항목 33개 단일 소스(규칙 카탈로그)
40
+ - [docs/plan/07-references.md](docs/plan/07-references.md) — 레퍼런스 조사 결과
41
+
42
+ ## 출처·저작권
43
+
44
+ KWCAG 2.2 원문 저작권은 국립전파연구원(방송통신표준)에 있으며, 이 프로젝트는 검사항목 명칭·요구 문장만 인용하고 설명은 자체 요약합니다. axe-core(MPL-2.0)를 검사 엔진으로 사용합니다. 자세한 출처는 `docs/plan/07-references.md`와 `assets/sources.json`을 참조하세요.
45
+
46
+ > 자동 판정 수치 중 품질인증 기준(전문가 95%·사용자 100%·평균 90)과 일부 법령 조항은 인증기관 공지로 재확인이 필요한 잠정치입니다.
47
+
48
+ ## 라이선스
49
+
50
+ MIT — [LICENSE](LICENSE)
@@ -0,0 +1,7 @@
1
+ {
2
+ "meaningless": [
3
+ "이미지", "사진", "그림", "아이콘", "썸네일", "배너",
4
+ "img", "image", "photo", "picture", "icon", "thumbnail", "banner"
5
+ ],
6
+ "filenamePattern": "\\.(png|jpe?g|gif|svg|webp)$"
7
+ }
@@ -0,0 +1,196 @@
1
+ {
2
+ "image-alt": {
3
+ "kwcag": "5.1.1"
4
+ },
5
+ "input-image-alt": {
6
+ "kwcag": "5.1.1"
7
+ },
8
+ "area-alt": {
9
+ "kwcag": "5.1.1"
10
+ },
11
+ "object-alt": {
12
+ "kwcag": "5.1.1"
13
+ },
14
+ "svg-img-alt": {
15
+ "kwcag": "5.1.1"
16
+ },
17
+ "role-img-alt": {
18
+ "kwcag": "5.1.1"
19
+ },
20
+ "video-caption": {
21
+ "kwcag": "5.2.1"
22
+ },
23
+ "td-headers-attr": {
24
+ "kwcag": "5.3.1"
25
+ },
26
+ "th-has-data-cells": {
27
+ "kwcag": "5.3.1"
28
+ },
29
+ "scope-attr-valid": {
30
+ "kwcag": "5.3.1"
31
+ },
32
+ "table-fake-caption": {
33
+ "kwcag": "5.3.1"
34
+ },
35
+ "table-duplicate-name": {
36
+ "kwcag": "5.3.1"
37
+ },
38
+ "heading-order": {
39
+ "kwcag": "5.3.2"
40
+ },
41
+ "link-in-text-block": {
42
+ "kwcag": "5.4.1",
43
+ "staticDisabled": true
44
+ },
45
+ "no-autoplay-audio": {
46
+ "kwcag": "5.4.2",
47
+ "staticDisabled": true
48
+ },
49
+ "color-contrast": {
50
+ "kwcag": "5.4.3",
51
+ "staticDisabled": true
52
+ },
53
+ "scrollable-region-focusable": {
54
+ "kwcag": "6.1.1",
55
+ "staticDisabled": true
56
+ },
57
+ "nested-interactive": {
58
+ "kwcag": "6.1.1"
59
+ },
60
+ "server-side-image-map": {
61
+ "kwcag": "6.1.1"
62
+ },
63
+ "target-size": {
64
+ "kwcag": "6.1.3",
65
+ "staticDisabled": true
66
+ },
67
+ "meta-refresh": {
68
+ "kwcag": "6.2.1"
69
+ },
70
+ "blink": {
71
+ "kwcag": "6.2.2"
72
+ },
73
+ "marquee": {
74
+ "kwcag": "6.2.2"
75
+ },
76
+ "bypass": {
77
+ "kwcag": "6.4.1"
78
+ },
79
+ "skip-link": {
80
+ "kwcag": "6.4.1"
81
+ },
82
+ "document-title": {
83
+ "kwcag": "6.4.2"
84
+ },
85
+ "frame-title": {
86
+ "kwcag": "6.4.2"
87
+ },
88
+ "frame-title-unique": {
89
+ "kwcag": "6.4.2"
90
+ },
91
+ "page-has-heading-one": {
92
+ "kwcag": "6.4.2"
93
+ },
94
+ "empty-heading": {
95
+ "kwcag": "6.4.2"
96
+ },
97
+ "link-name": {
98
+ "kwcag": "6.4.3"
99
+ },
100
+ "label-content-name-mismatch": {
101
+ "kwcag": "6.5.3"
102
+ },
103
+ "html-has-lang": {
104
+ "kwcag": "7.1.1"
105
+ },
106
+ "html-lang-valid": {
107
+ "kwcag": "7.1.1"
108
+ },
109
+ "html-xml-lang-mismatch": {
110
+ "kwcag": "7.1.1"
111
+ },
112
+ "valid-lang": {
113
+ "kwcag": "7.1.1"
114
+ },
115
+ "label": {
116
+ "kwcag": "7.3.2"
117
+ },
118
+ "label-title-only": {
119
+ "kwcag": "7.3.2"
120
+ },
121
+ "select-name": {
122
+ "kwcag": "7.3.2"
123
+ },
124
+ "form-field-multiple-labels": {
125
+ "kwcag": "7.3.2"
126
+ },
127
+ "autocomplete-valid": {
128
+ "kwcag": "7.3.4"
129
+ },
130
+ "duplicate-id-active": {
131
+ "kwcag": "8.1.1"
132
+ },
133
+ "duplicate-id-aria": {
134
+ "kwcag": "8.1.1"
135
+ },
136
+ "aria-allowed-attr": {
137
+ "kwcag": "8.2.1"
138
+ },
139
+ "aria-required-attr": {
140
+ "kwcag": "8.2.1"
141
+ },
142
+ "aria-roles": {
143
+ "kwcag": "8.2.1"
144
+ },
145
+ "aria-valid-attr": {
146
+ "kwcag": "8.2.1"
147
+ },
148
+ "aria-valid-attr-value": {
149
+ "kwcag": "8.2.1"
150
+ },
151
+ "aria-hidden-focus": {
152
+ "kwcag": "8.2.1"
153
+ },
154
+ "aria-hidden-body": {
155
+ "kwcag": "8.2.1"
156
+ },
157
+ "button-name": {
158
+ "kwcag": "8.2.1"
159
+ },
160
+ "aria-command-name": {
161
+ "kwcag": "8.2.1"
162
+ },
163
+ "aria-input-field-name": {
164
+ "kwcag": "8.2.1"
165
+ },
166
+ "aria-toggle-field-name": {
167
+ "kwcag": "8.2.1"
168
+ },
169
+ "aria-dialog-name": {
170
+ "kwcag": "8.2.1"
171
+ },
172
+ "aria-progressbar-name": {
173
+ "kwcag": "8.2.1"
174
+ },
175
+ "aria-tooltip-name": {
176
+ "kwcag": "8.2.1"
177
+ },
178
+ "aria-treeitem-name": {
179
+ "kwcag": "8.2.1"
180
+ },
181
+ "presentation-role-conflict": {
182
+ "kwcag": "8.2.1"
183
+ },
184
+ "color-contrast-enhanced": {
185
+ "kwcag": "5.4.3",
186
+ "staticDisabled": true
187
+ },
188
+ "frame-tested": {
189
+ "kwcag": null,
190
+ "staticDisabled": true
191
+ },
192
+ "css-orientation-lock": {
193
+ "kwcag": null,
194
+ "staticDisabled": true
195
+ }
196
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "legalBasis": [
3
+ {
4
+ "law": "디지털포용법",
5
+ "article": "제21조",
6
+ "note": "시행령 조 번호는 출처마다 상이하게 인용됨(17조/20조) — 시행령 원문 재확인 필요",
7
+ "needsVerification": true
8
+ }
9
+ ],
10
+ "standard": { "name": "KWCAG 2.2", "checkpoints": 33 },
11
+ "criteria": [
12
+ {
13
+ "kind": "expert",
14
+ "text": "검사항목 준수율 95% 이상",
15
+ "value": 0.95,
16
+ "needsVerification": true,
17
+ "verifiedOn": null,
18
+ "sourceUrl": null
19
+ },
20
+ {
21
+ "kind": "user",
22
+ "text": "장애유형별 과업 성공률 100%",
23
+ "value": 1.0,
24
+ "needsVerification": true,
25
+ "verifiedOn": null,
26
+ "sourceUrl": null
27
+ },
28
+ {
29
+ "kind": "overall",
30
+ "text": "두 심사 평균 90점 이상",
31
+ "value": 90,
32
+ "needsVerification": true,
33
+ "verifiedOn": null,
34
+ "sourceUrl": null
35
+ }
36
+ ],
37
+ "validity": {
38
+ "text": "1년(확인 필요)",
39
+ "needsVerification": true
40
+ },
41
+ "agencies": [
42
+ { "name": "한국디지털접근성진흥원", "url": "http://www.kwacc.or.kr" },
43
+ { "name": "웹와치", "url": "https://www.webwatch.or.kr" },
44
+ { "name": "한국시각장애인연합회 웹접근성평가센터", "url": null, "needsVerification": true }
45
+ ],
46
+ "procedure": ["신청", "전문가 심사", "사용자 심사", "결과 통보·보완", "인증 마크 부여", "사후 관리"]
47
+ }
@@ -0,0 +1,123 @@
1
+ # KWCAG 2.2 검사항목 체크리스트 — 단일 소스
2
+
3
+ > **이 파일이 검사항목·규칙 ID·자동화 등급의 단일 소스다**(ADR-04). `assets/kwcag22.json`·`src/rules`·`tests/`는 이 표를 따른다. 변경 절차: 이 파일(W) → `kwcag22.json`(U) → 데이터 테스트(W). 문서에서 검사항목을 인용할 때는 `6.4.1(2.4.1) 반복 영역 건너뛰기`처럼 **공식 번호(별칭)** 를 병기한다.
4
+ >
5
+ > 출처: 국립전파연구원 방송통신표준 「한국형 웹 콘텐츠 접근성 지침 2.2」(KS X OT0003, 2022-12 개정) — 비공식 HTML판 https://a11ykr.github.io/kwcag22/ , 웹소울랩 https://websoul.co.kr/accessibility/WA_guide22.asp (확인일 2026-09-04). 요구 문장만 한 줄 인용하고 설명은 자체 요약이다.
6
+
7
+ ## 1. 용어
8
+
9
+ | 용어 | 뜻 |
10
+ |---|---|
11
+ | 공식 번호 | 표준 본문 장 번호 기준 `5.1.1`~`8.2.1`(5=인식, 6=운용, 7=이해, 8=견고) |
12
+ | 별칭 | 업계·인증 실무에서 쓰는 `1.1.1`~`4.2.1` |
13
+ | 자동화 등급 | **자동**(auto): 도구가 fail을 확정 · **보조**(assist): 후보를 탐지하고 사람이 확정 · **수동**(manual): 체크리스트만 · **N/A**: 조건부(해당 콘텐츠가 있을 때만) |
14
+ | 규칙 ID | `k-*` 정적(jsdom) 규칙, `b-*` 브라우저(Playwright) 규칙, 그 외는 axe-core 규칙 ID |
15
+ | 티어 | T1 = M2 구현, T2 = M3(일부 백로그 허용), B = 브라우저(M3) |
16
+ | 상태 | Report의 검사항목 상태 `fail` / `incomplete` / `manual` / `pass` / `na` |
17
+
18
+ ## 2. 원칙·지침 (4원칙 · 14지침)
19
+
20
+ | 원칙 | 지침 |
21
+ |---|---|
22
+ | 5(1) 인식의 용이성 | 5.1(1.1) 대체 텍스트 · 5.2(1.2) 멀티미디어 대체수단 · 5.3(1.3) 적응성 · 5.4(1.4) 명료성 |
23
+ | 6(2) 운용의 용이성 | 6.1(2.1) 입력장치 접근성 · 6.2(2.2) 충분한 시간 제공 · 6.3(2.3) 광과민성 발작 예방 · 6.4(2.4) 쉬운 내비게이션 · 6.5(2.5) 입력 방식 |
24
+ | 7(3) 이해의 용이성 | 7.1(3.1) 가독성 · 7.2(3.2) 예측 가능성 · 7.3(3.3) 입력 도움 |
25
+ | 8(4) 견고성 | 8.1(4.1) 문법 준수 · 8.2(4.2) 웹 애플리케이션 접근성 |
26
+
27
+ ## 3. 검사항목 33개 — 요구 문장 (원문 한 줄 인용)
28
+
29
+ | ID(별칭) | 검사항목 | 요구 문장 | 2.2 신규 |
30
+ |---|---|---|---|
31
+ | 5.1.1 (1.1.1) | 적절한 대체 텍스트 제공 | 텍스트 아닌 콘텐츠는 그 의미나 용도를 이해할 수 있도록 대체 텍스트를 제공해야 한다. | |
32
+ | 5.2.1 (1.2.1) | 자막 제공 | 멀티미디어 콘텐츠에는 자막, 원고 또는 수어를 제공해야 한다. | |
33
+ | 5.3.1 (1.3.1) | 표의 구성 | 표는 이해하기 쉽게 구성해야 한다. | |
34
+ | 5.3.2 (1.3.2) | 콘텐츠의 선형구조 | 콘텐츠는 논리적인 순서로 제공해야 한다. | |
35
+ | 5.3.3 (1.3.3) | 명확한 지시사항 제공 | 지시사항은 모양, 크기, 위치, 방향, 색, 소리 등에 관계없이 인식될 수 있어야 한다. | |
36
+ | 5.4.1 (1.4.1) | 색에 무관한 콘텐츠 인식 | 콘텐츠는 색에 관계없이 인식될 수 있어야 한다. | |
37
+ | 5.4.2 (1.4.2) | 자동 재생 금지 | 자동으로 소리가 재생되지 않아야 한다. | |
38
+ | 5.4.3 (1.4.3) | 텍스트 콘텐츠의 명도 대비 | 텍스트 콘텐츠와 배경 간의 명도 대비는 4.5 대 1 이상이어야 한다. | |
39
+ | 5.4.4 (1.4.4) | 콘텐츠 간의 구분 | 이웃한 콘텐츠는 구별될 수 있어야 한다. | |
40
+ | 6.1.1 (2.1.1) | 키보드 사용 보장 | 모든 기능은 키보드만으로도 사용할 수 있어야 한다. | |
41
+ | 6.1.2 (2.1.2) | 초점 이동과 표시 | 키보드에 의한 초점은 논리적으로 이동해야 하며, 시각적으로 구별할 수 있어야 한다. | |
42
+ | 6.1.3 (2.1.3) | 조작 가능 | 사용자 입력 및 컨트롤은 조작 가능하도록 제공되어야 한다. | |
43
+ | 6.1.4 (2.1.4) | 문자 단축키 | 문자 단축키는 오동작으로 인한 오류를 방지하여야 한다. | ✅ |
44
+ | 6.2.1 (2.2.1) | 응답시간 조절 | 시간제한이 있는 콘텐츠는 응답시간을 조절할 수 있어야 한다. | |
45
+ | 6.2.2 (2.2.2) | 정지 기능 제공 | 자동으로 변경되는 콘텐츠는 움직임을 제어할 수 있어야 한다. | |
46
+ | 6.3.1 (2.3.1) | 깜빡임과 번쩍임 사용 제한 | 초당 3~50회 주기로 깜빡이거나 번쩍이는 콘텐츠를 제공하지 않아야 한다. | |
47
+ | 6.4.1 (2.4.1) | 반복 영역 건너뛰기 | 콘텐츠의 반복되는 영역은 건너뛸 수 있어야 한다. | |
48
+ | 6.4.2 (2.4.2) | 제목 제공 | 페이지, 프레임, 콘텐츠 블록에는 적절한 제목을 제공해야 한다. | |
49
+ | 6.4.3 (2.4.3) | 적절한 링크 텍스트 | 링크 텍스트는 용도나 목적을 이해할 수 있도록 제공해야 한다. | |
50
+ | 6.4.4 (2.4.4) | 고정된 참조 위치 정보 | 전자출판문서 형식의 웹 페이지는 각 페이지로 이동할 수 있는 기능이 있어야 하고, 서식이나 플랫폼에 상관없이 참조 위치 정보를 일관되게 제공·유지해야 한다. | ✅ |
51
+ | 6.5.1 (2.5.1) | 단일 포인터 입력 지원 | 다중 포인터 또는 경로기반 동작을 통한 입력은 단일 포인터 입력으로도 조작할 수 있어야 한다. | ✅ |
52
+ | 6.5.2 (2.5.2) | 포인터 입력 취소 | 단일 포인터 입력으로 실행되는 기능은 취소할 수 있어야 한다. | ✅ |
53
+ | 6.5.3 (2.5.3) | 레이블과 네임 | 텍스트 또는 텍스트 이미지가 포함된 레이블이 있는 사용자 인터페이스 구성요소는 네임에 시각적으로 표시되는 해당 텍스트를 포함해야 한다. | ✅ |
54
+ | 6.5.4 (2.5.4) | 동작기반 작동 | 동작기반으로 작동하는 기능은 사용자 인터페이스 구성요소로 조작할 수 있고, 동작기반 기능을 비활성화할 수 있어야 한다. | ✅ |
55
+ | 7.1.1 (3.1.1) | 기본 언어 표시 | 주로 사용하는 언어를 명시해야 한다. | |
56
+ | 7.2.1 (3.2.1) | 사용자 요구에 따른 실행 | 사용자가 의도하지 않은 기능(새 창, 초점에 의한 맥락 변화 등)은 실행되지 않아야 한다. | |
57
+ | 7.2.2 (3.2.2) | 찾기 쉬운 도움 정보 | 도움 정보가 제공되는 경우, 각 페이지에서 동일한 상대적인 순서로 접근할 수 있어야 한다. | ✅ |
58
+ | 7.3.1 (3.3.1) | 오류 정정 | 입력 오류를 정정할 수 있는 방법을 제공해야 한다. | |
59
+ | 7.3.2 (3.3.2) | 레이블 제공 | 사용자 입력에는 대응하는 레이블을 제공해야 한다. | |
60
+ | 7.3.3 (3.3.3) | 접근 가능한 인증 | 인증 과정은 인지 기능 테스트에만 의존해서는 안 된다. | ✅ |
61
+ | 7.3.4 (3.3.4) | 반복 입력 정보 | 반복되는 입력 정보는 자동 입력 또는 선택 입력할 수 있어야 한다. | ✅ |
62
+ | 8.1.1 (4.1.1) | 마크업 오류 방지 | 마크업 언어의 요소는 열고 닫음, 중첩 관계 및 속성 선언에 오류가 없어야 한다. | |
63
+ | 8.2.1 (4.2.1) | 웹 애플리케이션 접근성 준수 | 콘텐츠에 포함된 웹 애플리케이션은 접근성이 있어야 한다. | |
64
+
65
+ 신규 9항목(2.1 → 2.2): 6.1.4 · 6.4.4 · 6.5.1 · 6.5.2 · 6.5.3 · 6.5.4 · 7.2.2 · 7.3.3 · 7.3.4. (2.1의 24항목은 번호·명칭 일부가 재배치되었다 — `wcag-mapping.md` §2 대조표.)
66
+
67
+ ## 4. 검사항목 × 엔진 × 자동화 등급 (규칙 카탈로그)
68
+
69
+ WCAG 번호는 **WCAG 2.2 확정본(2023-10)** 기준이다. KWCAG 2.2 원문의 참조가 2.2 초안 번호일 수 있어 7.2.2→3.2.6, 7.3.3→3.3.8, 7.3.4→3.3.7로 매핑했다(검증 필요 — `wcag-mapping.md`).
70
+
71
+ | ID(별칭) | 검사항목 | WCAG 2.2 | axe 규칙 | 자체 규칙 (티어: 의도) | 등급 |
72
+ |---|---|---|---|---|---|
73
+ | 5.1.1 (1.1.1) | 적절한 대체 텍스트 제공 | 1.1.1 | image-alt, input-image-alt, area-alt, object-alt, svg-img-alt, role-img-alt | k-alt-meaningless (T1: 파일명·"이미지"·"사진"·공백 alt) | 보조 |
74
+ | 5.2.1 (1.2.1) | 자막 제공 | 1.2.1, 1.2.2, 1.2.3 | video-caption | k-media-track (T1: video/audio에 track[kind=captions] 없음) | 보조 |
75
+ | 5.3.1 (1.3.1) | 표의 구성 | 1.3.1 | td-headers-attr, th-has-data-cells, scope-attr-valid, table-fake-caption, table-duplicate-name | k-table-caption (T1: 데이터 표에 caption 없음), k-table-th-missing (T1: th 없는 데이터 표) | 보조 |
76
+ | 5.3.2 (1.3.2) | 콘텐츠의 선형구조 | 1.3.2 | heading-order(best-practice) | k-tabindex-positive (T1: tabindex > 0) | 보조 |
77
+ | 5.3.3 (1.3.3) | 명확한 지시사항 제공 | 1.3.3 | — | k-sensory-instruction (T2: "오른쪽의·빨간·둥근" 등 감각 지시어, confidence low) | 수동 |
78
+ | 5.4.1 (1.4.1) | 색에 무관한 콘텐츠 인식 | 1.4.1 | link-in-text-block(브라우저) | — | 수동 |
79
+ | 5.4.2 (1.4.2) | 자동 재생 금지 | 1.4.2 | no-autoplay-audio(브라우저) | k-autoplay-media (T1: audio/video[autoplay]:not([muted]), bgsound, embed·iframe autoplay 파라미터) | 자동 |
80
+ | 5.4.3 (1.4.3) | 텍스트 콘텐츠의 명도 대비 | 1.4.3 | color-contrast(브라우저) | `check_contrast` 도구(정적 색상 쌍) | 자동(브라우저) / 수동(정적) |
81
+ | 5.4.4 (1.4.4) | 콘텐츠 간의 구분 | (1.4.11 참고) | — | — | 수동 |
82
+ | 6.1.1 (2.1.1) | 키보드 사용 보장 | 2.1.1 | scrollable-region-focusable, nested-interactive, server-side-image-map | k-mouse-only-handler (T1: 비대화형 요소에 onclick/onmouseover만, tabindex·role 없음), b-keyboard-reachable (B: 대화형인데 Tab 순회에 없음) | 보조 |
83
+ | 6.1.2 (2.1.2) | 초점 이동과 표시 | 2.4.3, 2.4.7 | — | k-outline-none (T2: CSS `outline: 0/none` on :focus, 대안 스타일 없음), b-focus-visible (B: 초점 전후 계산 스타일 차이 없음), b-focus-order (B: DOM 순서 대비 역행) | 보조 |
84
+ | 6.1.3 (2.1.3) | 조작 가능 | (2.5.5, 2.5.8 참고) | target-size(브라우저) | b-target-size-6mm (B: 대각선 < 6mm ≈ 22.7px@96dpi, 인라인 텍스트 링크 예외) | 보조(브라우저) |
85
+ | 6.1.4 (2.1.4) | 문자 단축키 | 2.1.4 | — | k-accesskey (T2: accesskey 사용 → 검토) | 수동 |
86
+ | 6.2.1 (2.2.1) | 응답시간 조절 | 2.2.1 | meta-refresh | k-session-timeout-hint (T2: "자동 로그아웃·세션 만료" 문구 → 연장 수단 확인) | 보조 |
87
+ | 6.2.2 (2.2.2) | 정지 기능 제공 | 2.2.2 | blink, marquee | k-carousel-no-pause (T2: 슬라이더·롤링 컨테이너에 정지/일시정지 컨트롤 없음), b-motion-runtime (B: 5초 이상 자동 DOM 변경 + 정지 컨트롤 없음) | 보조 |
88
+ | 6.3.1 (2.3.1) | 깜빡임과 번쩍임 사용 제한 | 2.3.1 | — | k-flash-animation (T2: animation-duration < 0.33s & infinite) | 수동 |
89
+ | 6.4.1 (2.4.1) | 반복 영역 건너뛰기 | 2.4.1 | bypass, skip-link | k-skip-link-first (T1: 문서 첫 초점 요소가 문서 내 앵커 링크), k-skip-target-exists (T1: 링크 대상 존재), b-skip-link-works (B: Tab→Enter→초점 이동) | 자동 |
90
+ | 6.4.2 (2.4.2) | 제목 제공 | 2.4.2 (2.4.6 참고) | document-title, frame-title, frame-title-unique, page-has-heading-one, empty-heading | k-title-generic (T1: 빈/기본/사이트명만), k-iframe-title (T1: iframe title 없음·무의미) | 자동 |
91
+ | 6.4.3 (2.4.3) | 적절한 링크 텍스트 | 2.4.4 | link-name | k-link-text-generic (T1: `link-text-ko.json` 사전 일치), k-link-same-text-diff-href (T2: 같은 텍스트·다른 href) | 보조 |
92
+ | 6.4.4 (2.4.4) | 고정된 참조 위치 정보 | — (전자출판) | — | — | N/A |
93
+ | 6.5.1 (2.5.1) | 단일 포인터 입력 지원 | 2.5.1 | — | k-gesture-listener (T2: touchmove/pinch/swipe 핸들러 문자열) | 수동 |
94
+ | 6.5.2 (2.5.2) | 포인터 입력 취소 | 2.5.2 | — | k-down-event-action (T2: onmousedown/onpointerdown/ontouchstart 인라인 핸들러) | 보조 |
95
+ | 6.5.3 (2.5.3) | 레이블과 네임 | 2.5.3 | label-content-name-mismatch(experimental → 활성화) | — | 보조 |
96
+ | 6.5.4 (2.5.4) | 동작기반 작동 | 2.5.4 | — | k-device-motion (T2: devicemotion/deviceorientation 리스너) | 수동 |
97
+ | 7.1.1 (3.1.1) | 기본 언어 표시 | 3.1.1 | html-has-lang, html-lang-valid, html-xml-lang-mismatch, valid-lang | k-lang-ko-expected (T1: 본문 한글 비율 ≥ 30%인데 lang ≠ ko*) | 자동 |
98
+ | 7.2.1 (3.2.1) | 사용자 요구에 따른 실행 | 3.2.1, 3.2.2 | — | k-new-window-notice (T1: target=_blank인데 "새 창" 안내 없음), k-select-onchange (T1: select[onchange]로 이동·제출), k-onload-popup (T2: window.open on load) | 보조 |
99
+ | 7.2.2 (3.2.2) | 찾기 쉬운 도움 정보 | 3.2.6 | — | (`audit_site` 백로그: 도움 링크 상대 순서 비교) | 수동 |
100
+ | 7.3.1 (3.3.1) | 오류 정정 | 3.3.1, 3.3.3 | — | k-error-association (T2: aria-invalid 필드에 aria-describedby/오류 메시지 연결 없음) | 보조 |
101
+ | 7.3.2 (3.3.2) | 레이블 제공 | 3.3.2 (1.3.1, 4.1.2 참고) | label, label-title-only, select-name, form-field-multiple-labels | k-placeholder-only-label (T1: placeholder만 있고 label·aria-label 없음) | 자동 |
102
+ | 7.3.3 (3.3.3) | 접근 가능한 인증 | 3.3.8 | — | k-captcha-detect (T1: captcha/recaptcha/보안문자/자동입력 방지 탐지 → 대안 확인) | 보조 |
103
+ | 7.3.4 (3.3.4) | 반복 입력 정보 | 3.3.7 | autocomplete-valid | k-autocomplete-missing (T2: 이름·이메일·전화·주소 필드에 autocomplete 없음) | 보조 |
104
+ | 8.1.1 (4.1.1) | 마크업 오류 방지 | 4.1.1 | duplicate-id-active, duplicate-id-aria | k-parse-errors (T1: parse5 onParseError — 닫힘·중첩·중복 속성) | 자동 |
105
+ | 8.2.1 (4.2.1) | 웹 애플리케이션 접근성 준수 | 4.1.2 | aria-allowed-attr, aria-required-attr, aria-roles, aria-valid-attr, aria-valid-attr-value, aria-hidden-focus, aria-hidden-body, button-name, aria-command-name, aria-input-field-name, aria-toggle-field-name, aria-dialog-name, aria-progressbar-name, aria-tooltip-name, aria-treeitem-name, presentation-role-conflict | b-widget-keyboard (백로그: role 위젯 키보드 조작) | 보조 |
106
+
107
+ 등급 집계: 자동 7 · 보조 17 · 수동 8 · N/A 1 = 33.
108
+
109
+ ## 5. 규칙 ID 목록
110
+
111
+ - **T1 (18, M2)**: k-alt-meaningless · k-media-track · k-table-caption · k-table-th-missing · k-tabindex-positive · k-autoplay-media · k-mouse-only-handler · k-skip-link-first · k-skip-target-exists · k-title-generic · k-iframe-title · k-link-text-generic · k-lang-ko-expected · k-new-window-notice · k-select-onchange · k-placeholder-only-label · k-captcha-detect · k-parse-errors
112
+ - **T2 (13, M3·백로그 허용)**: k-sensory-instruction · k-outline-none · k-accesskey · k-session-timeout-hint · k-carousel-no-pause · k-flash-animation · k-link-same-text-diff-href · k-gesture-listener · k-down-event-action · k-device-motion · k-onload-popup · k-error-association · k-autocomplete-missing
113
+ - **B (6, M3)**: b-keyboard-reachable · b-focus-visible · b-focus-order · b-target-size-6mm · b-motion-runtime · b-skip-link-works · (백로그) b-widget-keyboard
114
+
115
+ ## 6. 검사항목 상태 판정 규칙 (Report `checkpoints[].status`)
116
+
117
+ 1. 귀속 규칙(axe·k·b) 중 `fail` 존재 → `fail`
118
+ 2. `incomplete`만 존재 → `incomplete`
119
+ 3. 자동/보조 규칙이 실행되어 모두 pass → `pass`
120
+ 4. 등급이 수동이거나, 정적 모드에서 귀속 규칙이 전부 비활성 → `manual`(notice "브라우저 감사 필요" 또는 "수동 확인")
121
+ 5. 6.4.4처럼 조건부 → `na`(전자출판 콘텐츠 징후가 있으면 `manual`로 승격)
122
+
123
+ 정적 모드 비활성 axe 규칙: color-contrast, color-contrast-enhanced, link-in-text-block, target-size, scrollable-region-focusable, no-autoplay-audio, frame-tested, css-orientation-lock.