` 적용 - 섹션 식별: `aria-labelledby` + 섹션 헤딩 id(features/testimonials/faq) - 이미지 대체텍스트: hero img `alt` = heading 파생 - 포커스 표시: 포커스 가능한 요소 outline 표시 - 반응형: 모바일 컨테이너 패딩 축소, grid 자동 칼럼, `prefers-reduced-motion` 준수 ### 최근 보강 내역(접근성/테스트) - 인스펙터 입력에 `aria-describedby` 연결(SEO/Analytics/OG/Hero/CTA) - SEO/Analytics/OG/Hero/CTA/FAQ 헬프텍스트 추가 - Exporter 구조 스냅샷 강화: `
` 내부 섹션/폼 포함 검증 - Exporter CSS 토큰 스냅샷: skip-link/focus outline/반응형/모션 감소 토큰 존재 검증 - Features/Testimonials `aria-labelledby`/헤딩 id 일치 검증 추가 - Exporter 헤딩 레벨 일관성 전수 테스트(hero=h1, others=h2, FAQ=h3) 추가 - Exporter 색상/타이포그래피 토큰 스모크 테스트 추가 - Exporter(Form): helptext ↔ aria-describedby 연결 TDD 완료 - 각 필드 `id=field-`와 `

` 추가(헤딩 레벨 일관성) - 전체 테스트 그린(유닛/컴포넌트/E2E) - Inspector a11y 스모크: SEO/Analytics/OG 입력과 헬프텍스트의 `aria-describedby` 연결 검증 - Exporter CSS 스모크: 본문 텍스트 컬러/포커스 outline/모바일 h1 폰트 크기/MQ 토큰 존재 검증 - FAQ 인스펙터 Q/A 입력 `aria-describedby`(ins-faq-help) 연결 보강 - Inspector 키보드 UX 스모크: Features/Testimonials 항목 추가( Space/Enter ) 검증 추가 - Inspector 키보드 UX 스모크: Features/Testimonials 항목 삭제(Remove) Enter/Space 검증 추가 - 인스펙터 Remove 버튼 키보드 처리(onKeyDown/onKeyUp) 반영 - Exporter 회귀 스냅샷: heading/ARIA/반응형 토큰 통합 검증 추가 - Preview 토글 ARIA 회귀 스냅샷(Desktop/Mobile: aria-pressed/controls/describedby) - Exporter CSS 토큰 회귀 확대(:root --primary, body font, skip-link base/focus, focus outline, reduced-motion) - 컴포넌트 i18n 회귀 스냅샷(en/ko 주요 라벨/버튼 키 존재) - 섹션 a11y 자동 검증 템플릿(testUtils/sectionA11y) 도입 및 템플릿 테스트 추가 - 이미지 최적화 옵션 1차(TDD): hero 이미지에 `fetchpriority`/`srcset`/`sizes` 조건부 렌더링 - 테스트: `lib/exporter/image.responsive.options.test.ts` (속성 존재 검증) - 구현: `lib/exporter/html.ts`(`ExportOptions`에 옵션 추가 및 `` 렌더 반영) - 브랜치: `feat/image-optimization` (로컬 커밋, 푸쉬 보류) - 이미지 최적화 옵션 2차(TDD): `srcset`만 제공 시 기본 `sizes` 자동 적용(`imageAutoSizes`) - 기본값: `(max-width: 640px) 100vw, 600px` - 테스트: `image.responsive.options.test.ts` (auto on/off 케이스) - 구현: `ExportOptions.imageAutoSizes` 추가 및 `renderHero` 적용 - 신규 섹션 추가: Benefits - 스키마 확장(`benefits`): props.items:string[] - Exporter 렌더 추가: `
`, `

`, 리스트 렌더 - 테스트: sections.benefits.test.ts (h2/aria-labelledby/리스트 아이템 검증) - 섹션 회귀 스냅샷(benefits 포함) 보강: sections.regression.benefits.test.ts 추가(ARIA/헤딩/리스트 구조 전수 검증) - 섹션 회귀 스냅샷(CTA/Testimonials): sections.regression.cta-testimonials.test.ts 추가(figure/blockquote/figcaption, CTA 링크 클래스/URL 검증) - 섹션 회귀 스냅샷(Features/FAQ): sections.regression.features-faq.test.ts 추가(리스트/클래스/아이템 수 검증) - Exporter 이스케이프 회귀: sections.escape.regression.test.ts 추가(특수문자 <, >, &, ") 안전 이스케이프 검증) - 인스펙터 a11y 자동 체크 헬퍼 도입: components/testUtils/inspectorA11y.ts + 템플릿 테스트 2종(InspectorA11y.template/sections) - i18n 회귀 확장: Sidebar Add 버튼군(en/ko) 라벨 스모크(i18n.sidebar.actions.test.tsx) - E2E 스모크: 프리뷰/Export 마커(heading/ARIA/반응형 CSS) 존재 검증 추가 - SEO description 기본값 설정으로 Export 스키마 안정화 - 프리뷰 토글 버튼에 `aria-controls="preview-container"` 추가로 제어 영역 명시 - 프리뷰 토글에 sr-only 설명 추가 및 두 토글 버튼 `aria-describedby` 연결 - SectionCanvas 제어 버튼 `aria-label` 스모크(Select/Up/Down/Remove) 추가 - CSS focus-visible 토큰 스모크(3px solid + HEX 컬러) 추가 - 인스펙터 Add 버튼 title 보조 힌트 추가(Features/Testimonials/FAQ) 및 일관성 테스트 - SectionCanvas 버튼 title/aria-label 일관성 스모크 - 전역 버튼 네이밍 일관성 보강: Inspector Add/Remove 및 SectionCanvas Select/Up/Down/Remove의 title/aria-label 일치 확인 및 스모크 완료 - a11y 커버리지 최종 점검: 전 섹션 인스펙터 입력 aria-describedby 연결 확인(체크리스트 충족) ### 다음 작업(계획) - Exporter 헤딩 레벨 일관성 테스트: hero는 h1, 나머지 섹션은 h2, FAQ 항목은 h3 검증 - a11y 색/폰트 최소 기준 스모크: 대비/폰트크기 관련 CSS 토큰/규칙 존재 여부 스냅샷 ### Inspector a11y 커버리지 체크리스트 - [x] Hero: `Hero Heading` 입력 `aria-describedby` → `ins-hero-heading-help` - [x] CTA: `CTA Text`/`CTA Href` 입력 `aria-describedby` → `ins-cta-text-help`/`ins-cta-href-help` - [x] FAQ: `FAQ Q n`/`FAQ A n` 입력 `aria-describedby` → `ins-faq-help` - [x] Features: `Feature n` 입력 `aria-describedby` → `ins-features-help` - [x] Testimonials: `Author n`/`Quote n` 입력 `aria-describedby` → `ins-testimonials-help` - [x] Preview 토글: sr-only 설명(`preview-toggle-help`)과 버튼 `aria-describedby` 연결, `aria-controls="preview-container"` ### CI/테스트 실행 - 유닛/컴포넌트: `npm test` (Vitest) - E2E: `npm run test:e2e` (Playwright) - 로컬 개발 서버는 Playwright 설정에서 자동 기동(webServer: `npm run dev`) - GitHub Actions 워크플로: `.github/workflows/ci.yml` - Node 20 + `npm ci` - Vitest 실행 → Playwright 브라우저 설치(`npx playwright install --with-deps`) → E2E 실행 ### CI 최종 점검 - main/master 브랜치 푸시/PR 시 워크플로 자동 실행 확인 - 새로 추가된 테스트(헤딩 레벨 전수, 색/폰트 스모크) CI 통합 확인 - 작업 브랜치 푸시 완료: `chore/ci-verify-a11y-headings` (원격: origin) - PR 생성 및 Actions 결과 기록 예정(base: main) - CI verification note: 러너 온라인 이후, 사소 변경으로 CI 트리거 검증 예정 - CI rerun: 워크플로 재실행용 ping 커밋 ### PR/CI 결과(2025-11-14) - PR: feat/ci-verify-run → main 머지 완료 - CI: Vitest + Playwright 전부 그린 - E2E 추가: Exported page skip-link focus 표시 회귀 테스트 포함 - 워크플로: self-hosted runner [macos, host], Playwright 보고서 업로드 아티팩트 활성화 - 제안: 다음 릴리스 태그(v0.2.0)로 회귀 커버리지/Benefits 섹션 추가 반영 #### 결과: CI 통과 (self-hosted Gitea Actions) - PR: https://gitea.jaybe.dev/jaybe/landing-builder/pulls/2 - 러너: self-hosted, labels: [macos, host] - 테스트: Unit/Component + E2E 총 7/7 green - 수정 요약(E2E 포커스): - 초기 포커스 선점 방지: `body` 클릭으로 포커스 부여 - 스킵링크 등 선행 포커서블 회피: Desktop 버튼에 명시적 `focus()` - 키보드 시나리오: Tab → Mobile 포커스 확인 → Space로 토글 → Shift+Tab → Enter ##### 추가 CI 결과(2025-11-14) - E2E a11y 스모크 추가: 포커스 아웃라인(3px solid, 브랜드 컬러), 스킵링크 탭 순서(main 포커스 이동) - Exporter JS에 스킵링크 클릭 시 `#main`에 `tabindex="-1"` 부여 후 `focus()` 처리 → CI 그린 통과 #### 머지 상태 - 머지 방식: Squash and merge - 브랜치 정리: `feat/ci-verify-run` 삭제 완료 ### 다음 스프린트 후보 과제 - Exporter 회귀 스냅샷 보강(폼 토큰/검증 토큰 범위 확대) - 인스펙터 신규 섹션 추가 시 a11y 베이스라인 재사용 가이드 마련 - 버튼 네이밍 일관성 전수 스캔 스모크 범위 확대 - node 20 + npm ci - Vitest 실행 → Playwright 브라우저 설치 → E2E 실행 ## 마일스톤 1. 스캐폴딩 및 테스트 환경 구성 2. 스키마 정의(Zod) 및 HTML Exporter TDD 3. 컴포넌트/상태관리(Zustand) 및 인스펙터 기본 기능 4. 접근성/키보드 네비게이션 강화 및 테스트 안정화 5. CI/CD(Self-hosted Gitea) 연동 및 그린 검증 ## 릴리스 ### v0.1.0 - CI 검증 완료(Self-hosted Gitea runner, labels: [macos, host]) - E2E 안정화: 초기 포커스 이슈 제거(Desktop 명시 focus), 스킵링크 고려 - Exporter(Form) a11y: helptext ↔ aria-describedby, id/htmlFor 연결, 라디오 fieldset 설명 연결 - i18n: en/ko 중첩 구조, 누락 키 보강(builder.action.*, builder.form.*) - next-intl: 기본 timeZone=Asia/Seoul 설정으로 ENVIRONMENT_FALLBACK 경고 제거 - 태그: v0.1.0 ## 접근성 베이스라인 가이드(신규 섹션/인스펙터 적용 규칙) - **레이블 연결**: 모든 입력은 `id=ins-...` 또는 `id=field-...` 부여, `
`에 `aria-describedby` 적용, 옵션은 `id/htmlFor`로 연결 - **버튼 네이밍**: 보이는 텍스트 또는 `aria-label`로 안정적 접근 가능한 이름 제공 - **키보드 활성화**: Enter/Space 활성(onClick와 동일 동작), `focus-visible` 스타일 유지 - **스킵링크**: `