Files
landing-builder/MAIN_PLAN.md
T
2025-11-14 20:29:54 +09:00

16 KiB

메인플랜: 랜딩 페이지 빌더

목표

  • 비개발자도 사용 가능한 단일 페이지 랜딩 페이지 빌더.
  • 결과물: 정적 ZIP(HTML/CSS/JS) 다운로드. 이미지: 외부 URL 또는 로컬 업로드(서버 저장 없음, ZIP에 패키징). 폰트는 외부 CDN 허용.
  • 폼: 다양한 필드 타입(파일 업로드 제외), 커스텀 name, action URL 설정. action 미지정 시 Google Sheets 저장.
  • 다국어 지원(i18n), 접근성 준수, SEO/OG 메타, 분석 스니펫 삽입.

확정 요구사항

  • 단일 페이지 기준.
  • 이미지: 외부 URL 또는 로컬 업로드 허용(서버 저장 없음, ZIP 패키징). CDN 허용(예: Google Fonts 등).
  • 폼 필드 타입: 텍스트/이메일/전화/셀렉트/라디오/체크박스/텍스트에어리어/날짜 등(파일 업로드는 추후).
  • 검증 규칙 필요. 스팸 방지: 기본(honeypot, 제출지연 타임스탬프).
  • 제출 경로: 1) 사용자가 action URL 지정 → 2) 미지정 시 Google Sheets.
    • 기본: Google Apps Script 웹앱 템플릿 가이드 제공(사용자 배포 URL 사용)。
    • 대안: 서비스계정 + Google Sheets API(선택).
  • 다국어 지원 필요. 접근성 준수. SEO/OG 포함. 분석 스니펫 삽입 기능 필요.
  • 스택: React 기반. Next.js(App Router) + TS + Tailwind + shadcn/ui 권장.

아키텍처 개요

  • 빌더 앱: Next.js(App Router, TS), Tailwind, shadcn/ui, dnd-kit, Zustand.
  • 도메인 스키마: Page → Section[] → Block[] → Form(fields, validation, actionUrl) → Theme.
  • 에셋 매니저: 사용자가 업로드한 이미지를 메모리/브라우저에서 관리, 파일명 해싱 후 assets/ 경로로 참조 재작성.
  • HTML Exporter: JSON 스키마 → 정적 HTML/CSS/JS 생성. 로컬 업로드 이미지는 assets/로 참조, 외부 URL은 그대로 유지.
  • 제출 경로: action 사용 또는 Google Sheets(기본 Apps Script 템플릿 제공).
  • i18n: next-intl. a11y: Testing Library + axe-core 스모크. SEO/OG 메타 생성.
  • 내보내기: ZIP(브라우저 JSZip 우선). 필요 시 서버(API Route) 대안 제공. 로컬 업로드 이미지는 ZIP 내 assets/ 폴더에 파일로 포함.

UI/UX 리디자인 계획(합의안)

  • 정보 구조(3패널)
    • 좌: 컴포넌트 패널(Hero/FAQ/CTA + Form 프리셋)
    • 중: 캔버스(dnd-kit, 섹션/필드 배치·정렬·삭제)
    • 우: 인스펙터(선택 요소 속성/검증/스타일 편집)
  • 상단 툴바: 언어, 테마, 프리셋, Export ZIP
  • 프리뷰: 실시간 렌더, 반응형 뷰포트 토글
  • 계약 고정: 스키마(섹션/폼/검증), 상태 인터페이스, Exporter 입·출력

단계별 TDD 진행

  1. 레이아웃 스캐폴딩(shadcn/ui) + 접근성 라벨링 테스트
  2. dnd 캔버스 1차: 섹션 드래그 정렬/삭제 테스트 → 최소 구현
  3. 인스펙터 1차: 선택 섹션/필드 기본 속성 편집 테스트 → 연동
  4. 컴포넌트 패널: 카드 추가(섹션/필드 프리셋) 테스트 → 드래그 추가
  5. 프리뷰 강화: 실시간 반영/뷰포트 토글 스모크 테스트

현재 상태(MVP)

  • 섹션 추가/삭제, 폼 필드 구성(옵션/필수/패턴/최대길이), i18n, ZIP Export, 로컬 에셋 포함 동작 확인
  • Next.js 16: middlewareproxy 마이그레이션 완료
  • dnd 상호작용 테스트 및 구현 안정화(정렬/삭제 버튼 폴백 포함)
  • 섹션 프리셋 확장: Features/Testimonials 카드 추가 및 프리뷰/Exporter 스텁 반영 완료
  • SEO/Analytics/OG 인스펙터 추가 및 프리뷰 반영
  • Exporter: og:image 메타 태그 반영 및 테스트 추가
  • a11y: jest-axe 스모크 테스트 통과(FormBuilderPanel), dnd-kit 라이브 리전/안내 존재 검증
  • 라벨-id 매핑 강화(중앙 입력/인스펙터/FAQ/CTA/Features/Testimonials)
  • 프리뷰 뷰포트 토글(Desktop/Mobile) + localStorage 영속화
  • Features/Testimonials 인스펙터 편집 UI(리스트 추가/삭제/편집) + 테스트
  • Exporter 타입 보강(any 제거) 및 CSS 보강(Features/Testimonials)
  • E2E(Playwright):
    • 기본 플로우(섹션 추가→편집→프리뷰→Export 클릭)
    • dnd 키보드 폴백(Up/Down) 재정렬
    • SEO/Analytics/OG 프리뷰 반영 검증
    • Export ZIP 메타(SEO/OG/Analytics) 검증(테스트 훅 사용)
    • 프리뷰 뷰포트 토글(aria-pressed/키보드 접근) 검증

a11y/반응형 정책(Exporter)

  • 문서 내비게이션: skip link, <main id="main" role="main"> 적용
  • 섹션 식별: 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 구조 스냅샷 강화: <main> 내부 섹션/폼 포함 검증
  • 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-<name><label for> 연결
    • help가 있을 경우 id=field-<name>-help 요소 생성 및 컨트롤에 aria-describedby 부여
    • 라디오 그룹은 fieldsetaria-describedby 적용, 옵션별 id/htmlFor 연결
  • next-intl 기본 timeZone 설정: Asia/Seoul로 ENVIRONMENT_FALLBACK 경고 제거
  • a11y 색/폰트 최소 기준 스모크(본문 컬러/폰트 패밀리/모바일 h1 폰트 크기) 추가
  • CTA 섹션에 aria-labelledby + <h2 id="cta-heading"> 추가(헤딩 레벨 일관성)
  • 전체 테스트 그린(유닛/컴포넌트/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) 도입 및 템플릿 테스트 추가
  • 신규 섹션 추가: Benefits
  • 스키마 확장(benefits): props.items:string[]
  • Exporter 렌더 추가: <section class="benefits" aria-labelledby>, <h2 id="benefits-heading">, 리스트 렌더
  • 테스트: 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 커버리지 체크리스트

  • Hero: Hero Heading 입력 aria-describedbyins-hero-heading-help
  • CTA: CTA Text/CTA Href 입력 aria-describedbyins-cta-text-help/ins-cta-href-help
  • FAQ: FAQ Q n/FAQ A n 입력 aria-describedbyins-faq-help
  • Features: Feature n 입력 aria-describedbyins-features-help
  • Testimonials: Author n/Quote n 입력 aria-describedbyins-testimonials-help
  • 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: #2
  • 러너: self-hosted, labels: [macos, host]
  • 테스트: Unit/Component + E2E 총 7/7 green
  • 수정 요약(E2E 포커스):
    • 초기 포커스 선점 방지: body 클릭으로 포커스 부여
    • 스킵링크 등 선행 포커서블 회피: Desktop 버튼에 명시적 focus()
    • 키보드 시나리오: Tab → Mobile 포커스 확인 → Space로 토글 → Shift+Tab → Enter

머지 상태

  • 머지 방식: 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-... 부여, <label for>로 연결
  • 헬프텍스트 연결: 헬프 요소 id=...-help 생성, 입력에 aria-describedby로 연결
  • 라디오 그룹: 개별 <input> 대신 <fieldset>aria-describedby 적용, 옵션은 id/htmlFor로 연결
  • 버튼 네이밍: 보이는 텍스트 또는 aria-label로 안정적 접근 가능한 이름 제공
  • 키보드 활성화: Enter/Space 활성(onClick와 동일 동작), focus-visible 스타일 유지
  • 스킵링크: <a class="skip-link"> 제공, 포커스 시 화면 내 표시
  • 헤딩 레벨: hero=h1, 1뎁스 섹션=h2, FAQ 항목=h3 일관성 유지
  • 미리보기 토글: 토글 버튼에 aria-pressed, aria-controls, aria-describedby 연결
  • i18n 키: 중첩 객체 구조, 신규 키 추가 시 en/ko 동시 보강
  • 테스트 원칙: TDD로 유닛/컴포넌트/E2E 및 스냅샷 추가. 포커스/ARIA/토큰 스모크 포함

적용 가이드(신규 섹션 추가 시)

  • 1) 섹션 구현: <section class="<name>" aria-labelledby="<name>-heading"><h2 id="<name>-heading"> 구성
  • 2) 인스펙터 입력: id=ins-..., <label for>, 헬프텍스트 ...-help + aria-describedby 연결
  • 3) Exporter 반영: 섹션 렌더 함수에 위 구조/속성 부여
  • 4) 테스트 추가:
    • 공통 템플릿 사용: lib/exporter/testUtils/sectionA11y.tsassertSectionA11y(html)
    • 샘플: lib/exporter/sectionA11y.template.test.ts 참고하여 새 섹션 추가해 검증
    • 필요 시 개별 스냅샷/스모크: 헤딩/ARIA/키보드/토큰 추가 검증

다음 단계(E2E 초안)

  • 시나리오: 섹션 추가(Hero/FAQ/Features/Testimonials/CTA) → 인스펙터 편집 → Export ZIP 생성 → HTML 메타/섹션/폼 렌더 확인
  • 환경: Playwright
  • 체크리스트:
    • 섹션 추가/정렬/삭제 동작
    • 인스펙터 편집 반영(미리보기/Export HTML)
    • i18n 라벨 안정성(data-testid 사용)
    • a11y 스모크 무결성 유지

TDD 전략

  • 각 기능 단위로: 실패 테스트 작성 → 최소 구현 → 리팩터 → 커버리지 확인.
  • 단위: Vitest + Testing Library + jsdom. E2E: Playwright.
  • 접근성: axe-core 스모크 테스트.

작업 보드(요약)

  • 스키마/도메인(Zod)
  • HTML Exporter
  • 에셋 매니저
  • 폼 엔진
  • Sheets 연동
  • 빌더 UI
  • 내보내기 ZIP
  • i18n
  • a11y/SEO/OG/Analytics

오류/버그 기록

  • [2025-11-13 22:55] BuilderClientPage 렌더 중 ref 접근 경고 / useRef.current를 렌더 중 참조하여 ESLint 경고 발생 / FormBuilderPanel 통합 시 useRef(createFormStore()) 사용 / useMemo(() => createFormStore(), [])로 스토어 인스턴스 고정하고 useSyncExternalStore에 직접 주입하여 해결 / 렌더 중 ref 접근 금지 원칙 재확인
  • [2025-11-14 09:35] Vitest 로그에서 i18n 누락 메시지 경고 확인(en: builder.action.addSelect/addRadio, builder.form.actionUrl/honeypot/minSeconds) → messages/en.json에 키 존재 여부 점검 및 누락 보완 후 재실행, 모든 테스트 그린 유지
  • [2025-11-14 09:45] 프리뷰 텍스트 매칭 불안정으로 테스트 실패 → data-testid 기반 안정화(preview-seo-title 등) 및 텍스트 매칭 지점 Title:Locale:로 조정, 전면 그린

의사결정 기록(ADR)

  • [YYYY-MM-DD] Next.js(App Router) 채택: 생태계/배포/서버리스/SEO 편의성.
  • [YYYY-MM-DD] Sheets 기본 방안: Apps Script 웹앱 템플릿(사용자 편의/트래픽 분산).
  • [YYYY-MM-DD] 로컬 이미지 업로드 허용: 서버 저장 없이 ZIP에 assets/로 패키징(브라우저 JSZip 우선).