RINDA E2E · CI/CD 워크플로우 분석

Playwright E2E 스위트 전수 분석 + GitHub Actions 자동 실행 기준

📅 2026-06-18 🎯 alpha.rinda.ai 🧪 Playwright 1.61 📊 ReportPortal 연동

00 한눈에 (개발자 · 비개발자 공통)

전문 용어 없이, 이게 무엇이고 왜 하는지부터.

E2E 테스트가 뭔가요? — 로봇이 사람 대신 우리 서비스를 직접 클릭해보는 자동 점검입니다. "로그인 → 캠페인 만들기 → 발송 → 수신함 확인" 같은 실제 사용자 동선을 코드 배포가 일어날 때마다 자동으로 따라 해보고, 화면이 깨지거나 버튼이 안 눌리면 즉시 알려줍니다.
왜 해야 하나요? — 기능 하나를 고치면 엉뚱한 다른 화면이 조용히 깨지는 사고가 반복됩니다. 매번 사람이 13개 화면을 일일이 눌러 확인할 수 없으니 로봇이 대신합니다. 배포 직후 잡으면 몇 분이면 고치지만, 고객이 먼저 발견하면 장애 + 신뢰 손상으로 수십 배 비싼 문제가 됩니다.

30초 요약

질문
무엇을?실제 사용자 흐름을 자동으로 재현·검증 (현재 75개 시나리오 파일 · 183개 점검 케이스)
언제 실행?배포될 때마다 자동(빠른 점검) + 매일 새벽·저녁 전체 점검 + 필요 시 수동
결과는 어디서?ReportPortal 대시보드 + Slack 알림 (어느 코드에서 깨졌는지 추적)
개발자가 할 일?새 기능 만들면 테스트도 같이 추가, 기능 고치면 테스트도 같이 수정
비개발자가 볼 곳?ReportPortal에서 초록(통과)/빨강(실패) 현황 — 빨강이면 방금 배포가 뭔가 깨뜨린 것

01 개요

헥사고날(Ports & Adapters) + 도메인 분리 + 2026 web-first 패턴. e2e/ 는 독립 npm workspace.

75
spec 파일
183
test() 케이스
16
도메인/영역
9
GitHub 워크플로우
3-tier
E2E 실행 티어

디렉토리 구조

경로역할
tests/auth.setup.tsuiLogin → storageState 저장. 30분 TTL + JWT exp 캐시. 기본 WS "린다세일즈" 고정 + 신원 바인딩
tests/features/<도메인>/도메인별 스펙 (auth·leads·sequences·email-replies·settings·platform·dashboard·ai·billing·content·admin·lead-discovery·onboarding)
tests/db/drizzle 직접 접근, FK 무결성 검증
tests/dynamic/변경 기반(worktree-pr 브랜치명) 동적 회귀 가드
tests/exploratory/axe 접근성 상세 스캔
tests/ui/ports.ts + adapters/playwright.ts헥사고날 인터페이스 + Playwright 구현 = 셀렉터 SSOT
tests/fixtures/page-fixtures.tsapp 드라이버 + listeners 자동연결 + csrfRequest(CSRF 자동주입)
scripts/bootstrap·sync·dev-up·port-alloc(slot 격리)·run-e2e(EC2 docker)·rp-*
specs/Planner 에이전트 산출 Markdown 테스트 계획

02 playwright.config.ts

로컬/원격 자동 감지, 4개 project 분리, ReportPortal 조건부 연동.

항목
baseURLE2E_BASE_URL ?? https://alpha.rinda.ai
MODElocal(localhost) / alpha(원격) 자동감지, E2E_MODE override
workerslocal=20, alpha=4
retrieslocal=1, alpha=0
timeouttest 90s · expect 20s · nav 20s · action 10s
reporterslist + html + json + ReportPortal(alpha 또는 E2E_FORCE_RP + RP_API_KEY 시)
trace/video/screenshotfailure-only, E2E_DEBUG_ARTIFACTS=1 시 전량
viewport1440×900, headless, ignoreHTTPSErrors

4개 project

project대상storageState
setupauth.setup.ts (로그인)생성
chromiumnoauth/db 제외 전체로그인 상태 (setup 의존)
chromium-noauth*.noauth.spec.ts빈 상태
dbtests/db/**빈 상태 (setup 비의존)
storageState 경로 SSOT = scripts/storage-path.ts — writer/reader 공유. 과거 ENOENT 근본원인을 차단.

03 CI 자동 실행 기준 — 액션 → 워크플로우 매핑

9개 워크플로우. workflow_run 체인 2개(CI→리뷰, CD Alpha→E2E) 외 모두 독립 트리거.

액션 (이벤트)트리거되는 워크플로우
push → alphaCI · CD Alpha · Release
push → betaCI · CD Beta (app.rinda.ai 프로덕션)
push → main/masterCI
PR open/syncCI
CI 완료 (PR + success)Claude Code Review
CD Alpha 완료 (success)E2E on Alpha (smoke)
cron 05:00 · 21:00 KSTE2E on Alpha (full)
이슈 openauto-assign · (본문 @claude 시) Claude Code
PR merge (close)auto-close-issues
코멘트/리뷰에 @claudeClaude Code
수동 dispatchCD Alpha · CD Beta · E2E on Alpha

워크플로우 상세

e2e-on-alpha.yml — E2E on Alpha (Post-Deploy) ★ 핵심

3-tier 트리거:

  • Tier 1 (smoke): workflow_run ← "CD Pipeline (Alpha)" completed. 배포 완료 시점 트리거(구버전 회피). @smoke만 ~2-3분
  • Tier 2 (full): schedule cron 0 20 * * *(05:00 KST) · 0 12 * * *(21:00 KST). 전수 실행
  • Tier 3 (선택): workflow_dispatch input mode=full/smoke. 릴리스·beta 동기화 게이트 온디맨드

3 job 체인: guard(배포 success 확인) → detect(git diff로 변경 분석·모드 결정·docs만 변경 시 skip) → dispatch(SSH+Infisical→EC2 전송→nohup run-e2e.sh 백그라운드)

GHA는 경량(~40s): detect + 시크릿 export + SSH 트리거만. 실제 실행은 EC2 docker가 비동기로. 결과는 RP + Slack 통지.

ci.yml — CI 게이트
  • 트리거: push → [main, master, alpha, beta], PR → 동일 브랜치 대상
  • 동시성: PR은 cancel-in-progress, push는 SHA별 그룹(취소 안 함)
  • 비용 게이트: 봇/내부 6명 login은 CI skip
  • job: detect-changes(paths-filter) → admin(yarn ci:check + bundle) / server(bun ci:check: lint·type·check:routes 권한게이트·check:migrations·unit + bundle)
  • 완료 시 Claude Code Review 트리거
ci-cd-alpha.yml — CD Pipeline (Alpha)
  • 트리거: push → alpha, workflow_dispatch. 동시성 queue: max(FIFO)
  • SSH + Infisical 시크릿 export(.env.rp 포함 + Copilot flag) → 변경 컴포넌트 감지 → rsync → DB 백업+S3 → zero-downtime-deploy → health 240s(실패 시 롤백) → Cloudflare purge → Slack
  • 완료 시 E2E on Alpha 트리거
ci-cd-beta.yml — CD Pipeline (Beta · 프로덕션)
  • 트리거: push → beta, workflow_dispatch
  • alpha와 구조 동일. 차이: beta 시크릿 · app.rinda.ai · ReportPortal export 없음 · Copilot flag 주입 없음
  • E2E 미연결(E2E는 alpha 전용)
claude-code-review.yml · claude.yml — Claude 자동화
  • code-review: CI 완료 + PR + success 시 /code-review 자동 실행
  • claude: 코멘트/리뷰/이슈에 @claude 멘션 시 지시대로 실행
release.yml · auto-assign.yml · auto-close-issues.yml — 기타
  • release: alpha push 시 package.json 버전으로 GitHub Release + OpenAPI 첨부(동일 태그 있으면 skip)
  • auto-assign: 새 이슈/카드를 기본담당(classygoody)+생성자에 assign
  • auto-close: PR merge 시 본문 closes #N 파싱→이슈 close

04 배포 → E2E 자동 체인

두 개의 workflow_run 체인이 자동화의 핵심.

┌─ push → alpha ──────────────────────────────────────┐ │ │ ▼ ▼ ▼ [ CI ] [ CD Alpha ] [ Release ] │ success(PR) │ success │ ▼ ▼ ▼ [Claude Code Review] [E2E on Alpha · smoke] [GH Release + OpenAPI] ▲ │ cron 05:00 / 21:00 KST [E2E on Alpha · full] ▲ │ workflow_dispatch [E2E on Alpha · 선택]
배포 완료(success) 시점에만 E2E가 트리거되어 구버전 테스트를 회피. docs(.md/.txt)만 변경된 푸시는 detect 단계에서 자동 skip.

05 테스트 케이스 전수 목록

도메인별 집계 (실측 · 정적 test() 기준)

도메인 / 영역spectest() 케이스비고
sequences (캠페인)2154최대 도메인 · 회귀 가드 8
auth (인증)629전부 noauth
email-replies (수신함)517
settings (설정)716ws 전환·IAM
leads (바이어)614
admin (관리자)411
dashboard38
platform58+ 데이터기반 12(i18n)·6·6 런타임 확장
lead-discovery36
content44전부 진입 smoke
ai23
billing23
onboarding23
dynamic (변경 기반)23worktree-pr 회귀 가드
db (무결성)12로컬 PG 미접근 시 skip
exploratory (a11y)11axe 상세 스캔
합계75183
수치는 정적 test() 호출 기준 실측. public-pages.noauth(LANGS×PAGES=12), sidebar/main-menu(각 6) 등 데이터기반 파라미터화 테스트는 런타임에 더 많은 케이스로 확장되어 실제 실행 케이스는 이보다 큼.

도메인별 spec 상세. 태그 범례: @smoke @critical a11y tree flow noauth

auth — 인증/로그인 6 spec · 29 case
  • signin-tree.noauth — signin 화면 트리: heading·email/password·"Rinda AI" 타이틀·Google/Login/Sign up/Forgot 버튼·약관/개인정보 링크·빈폼 validation·잘못된 자격증명 차단 (12 case)
  • signin-flow.noauth — 입력 반영·잘못된 형식 제출 시 signin 유지·"Forgot password" 클릭→재설정 입력 노출 (3)
  • login.noauth — 존재X 이메일 4xx·필드누락·이메일형식 거부·/signin 렌더·Google OAuth URL 발급 (5)
  • signup-otp.noauth — 가입 완주: Sign up→이메일→Redis OTP→이름·비번·약관→완료
  • signup-tree.noauth/signup은 not-found(공개가입 미제공)·pageerror 0 (4)
  • routes-guard-tree.noauth — 전 라우트 비로그인 접근 가드
sequences — 캠페인 (최대 도메인) 21 spec · 54 case
  • list-tree/sequences·"Campaign Management"·All/In Progress/Completed 탭·New Campaign·검색 (8)
  • list-quality — 콘솔/5xx/pageerror 0·i18n 미번역 0·카드 발송진행률 \d+/\d+ 발송 카운터·mobile 360 a11y (6)
  • list-smoke — 진입 안정(body·pageerror·5xx 0)
  • create-tree / create-flow / create-a11y-tree/sequences/create 트리·그룹 선택→step2·키보드/터치타겟
  • campaign-create-entry — 목록→새 캠페인→모드 선택 모달
  • proposal-tree / proposal-smoke — AI 제안서: 바이어선택·그룹선택지·계정선택·"Get AI draft"·history endpoint (5)
  • personalized-preview — 바이어별 이메일 셀 프리뷰 클램프 + Enter/클릭→상세 전문
  • reply-automation-tree — 답장 자동처리 Step3: 3개 토글 기본 ON·동작·매트릭스 비노출
  • sendable-gate-flow — 발송가능 0명이면 다음단계 차단 (2)
  • step-editor-a11y — Step2 터치타겟·SaveStatusIndicator·콘솔/pageerror/5xx 0·탭 키보드 (6)
  • 회귀 가드 8 spec @critical — campaign-account-ux / batch1~4(#8747~8766) / create-parity(#42809) / multiaccount / remain(#8755·8760). 진입 깨짐·pageerror·5xx 0 가드
settings — 설정 7 spec · 16 case
  • save-roundtrip — 이름 변경→저장→reload 유지→원복
  • rinda-mail-connect — Rinda Mail 연동: prefix→Connect→성공
  • email-integration-tree — 내 이메일 탭·연동 시작→provider 다이얼로그
  • workspace-switch-race — ws 전환 직후 옛 ws E403이 새 선택 wipe 안 함·admin/non-admin 분기 (4)
  • workspace-switcher-tree — 현재 ws 이름·목록·선택 시 사이드바·localStorage 동기화 (3)
  • page-smoke / iam-pages-smoke — 설정 진입 0 error / IAM 3페이지 렌더
email-replies — 메일 수신함 5 spec · 17 case
  • bucket-actions — Follow-up 클릭→view+URL 동기화·Sent↔Inbox 왕복 (2)
  • email-tree/replied-emails·MAILBOX·Inbox·Follow-up·Compose·EmptyState (7)
  • inbox-buckets-tree — 버킷 카운트(Inbox·Follow-up·Positive·Negative·Today) (5)
  • inbox-a11y-tree — 버킷 네비 role/키보드·MAILBOX 랜드마크·Compose Escape 취소 (2)
  • page-smoke — URL 유지·main 렌더·pageerror 0
leads — 바이어 관리 6 spec · 14 case
  • leads-tree/leads·Buyer Groups·Lead Pipeline·검색·Create New Group·빈 WS 크래시없음 (8)
  • group-crud — 그룹 생성→상세→설정에서 삭제
  • group-validation-tree — Escape 취소·다이얼로그 a11y (2)
  • bulk-copy-combobox-layout — 긴 그룹명 truncate(다이얼로그 넘침 없음)
  • confirm-modal-standard — 삭제 확인모달 표준구조(취소+파괴)
  • list-smoke — URL유지·main·pageerror0·5xx0
platform — 플랫폼/공통 5 spec · 8 case
  • cors-origin — preflight wildcard ACAO/origin 반사 금지·정상 origin 통과 (2)
  • public-pages.noauth — LANGS(ko/en/id/ja) × PUBLIC_PAGES(signin·terms·privacy) = 12 case, 미번역 0
  • sidebar-nav-tree — MENUS 6개 클릭→이동+active
  • main-menu — PAGES 6개 기본 렌더·인증리다이렉트X·pageerror0
  • auto-publicroutes.json(114개)에서 public/root path param 없는 라우트 자동 smoke
admin — 관리자 4 spec · 11 case
  • sales-autopilot-journey — 해외영업 자율주행: 셋업→영업정보→계획수립→가동→허브→Done
  • sales-autopilot-access — flag ON 진입 렌더 / OFF /dashboard 리다이렉트 (2)
  • recordings-audio-progress — play 시 progress·range 변경으로 currentTime 이동
  • console-page/admin body·pageerror0·5xx0
dashboard · lead-discovery · content · onboarding · ai · billing 16 spec · 23 case
  • dashboard (3) — tree(WS 버튼·타이틀·Admin Menu·약관동의 후 인증유지) · a11y-tree(키보드·≥24px·새로고침 인증잔존) · page-smoke
  • lead-discovery (3) — buyer-search-tree(질문 heading·AI 기회카드·Recent) · workspace-isolation(타 ws jobId 200 절대X) · page-smoke
  • content (4) — campaign-calendar(#6045 5xx) · help-changelog(#6042 CSP/iframe) · knowledge-base · linkedin-sdr smoke
  • onboarding (2) — tree(인증 컨텍스트 해소·약관동의) · page-smoke(셸 flash 회귀 #6121)
  • ai (2) — copilot-sidebar(FAB·⌘J 토글·step2 자동숨김) · employee-smoke(AI Sales Team)
  • billing (2) — checkout-smoke(invalid purchaseId graceful) · plans-render(구독·플랜 카드)
dynamic · db · exploratory — 특수 4 spec · 6 case
  • dynamic/fix-workspace-fallback-gate — stale 캐시 있어도 비멤버 ws active 선택·발사 차단
  • dynamic/fix-workspace-identity-binding — 타 계정 stale ws 미발사·false-positive wipe 없음 (2)
  • db/fk-integrity — 모든 단순 FK 고아 row 0 (로컬 PG 미접근 시 skip)
  • exploratory/a11y-detail — 6개 페이지 axe 상세 스캔, serious/critical을 JSON 산출(단언 없음)

06 실행 인프라 — EC2 오프로드

GHA는 트리거만, 무거운 실행은 EC2 docker로 오프로드(GHA 과금·다운로드 제거).

로컬 — bootstrap.sh 파이프라인

단계내용
① sync-codegit pull + deps (자체 skip 판정으로 웜런 수초)
② sync-db / db-per-slotmigrate + alpha 데이터. slot 0~9 격리: PG rinda_wt<slot>
③ dev-upFE(5173+slot) + BE(3001+slot) health, atomic lockfile lease
④ E2Emode=smoke/regression/record/dynamic/none

원격 — run-e2e.sh (EC2)

ReportPortal은 매 실행 OAuth 재발급으로 api-key 우회. RP_MODE·RP_HEAD_SHA·GITHUB_PR_NUMBER를 env로 전달해 PR과 결과 연결.

07 2026 레퍼런스 · 베스트프랙티스

최신 Playwright 권장 패턴과 우리 스위트의 정합성. (출처: playwright.dev 공식 문서 · 2026 best-practices 가이드)

왜 "최신 패턴"이 중요한가 (비개발자용)

테스트도 잘못 짜면 멀쩡한데 자꾸 실패(거짓 경보)하거나 깨졌는데 통과(놓침)합니다. 2026 권장 방식은 "사람이 화면을 알아보는 방식 그대로" 로봇이 요소를 찾게 해서, 디자인을 바꿔도 테스트가 덜 깨지고 더 믿을 수 있게 만듭니다. 우리 스위트는 이 방식을 이미 채택하고 있습니다.

핵심 권장 패턴 (개발자용)

2026 권장내용우리 적용
역할 우선 셀렉터getByRole 최우선 → getByLabel/getByPlaceholdergetByTextgetByTestId → CSS/XPath 최후. role로 못 찾으면 접근성 결함이기도 함(동시 검증)tests/ui/ ports/adapters에 role 우선 셀렉터 SSOT
web-first assertionsexpect(locator).toBeVisible() 등이 조건 충족까지 자동 대기·재시도. 고정 waitForTimeout 금지(flaky 원인)✓ 전 spec web-first, 하드 wait 없음
POM 대신 fixture소~중 규모는 Page Object Model 대신 조합형 fixture가 더 가볍고 격리 우수fixtures/page-fixtures.ts(app·listeners·csrfRequest)
ARIA 스냅샷v1.60+ expect(page).toMatchAriaSnapshot()(Page 지원)·pathTemplate·codegen aria 픽커. 접근성 트리 기반 구조 회귀 검증◐ tree 패턴 사용 중, 표준 toMatchAriaSnapshot() 전환은 진행 노드(TEST-DESIGN-PLAN N1.3)
per-assertion 타임아웃전역 타임아웃 0 대신 단언별 명시 타임아웃 → 간헐 실패를 재현 가능한 실패로 전환✓ expect 20s·action 10s 명시
접근성 내장role 기반 로케이터가 곧 a11y 검증. 추가로 axe 스캔 병행✓ a11y 헬퍼(axe wcag2a/2aa) + exploratory/ 상세 스캔

참고 링크

정합성 결론: 우리 스위트는 2026 핵심 권장(role 우선·web-first·fixture·a11y 내장)을 이미 충족. 남은 현대화는 ① tree 패턴 → 표준 toMatchAriaSnapshot() 통일 ② MCP Playwright Agents 재연결로 self-healing 자동화 두 가지.

08 도입 프로세스 · 성과 · 커뮤니티 (2026)

대기업·유망 스타트업은 누가·어떻게 E2E를 운영하고 어떤 성과를 냈는가. (출처: State of Testing 2026 · State of JS 2025 · World Quality Report 2025-26 · 각 사 엔지니어링 블로그)

누가 / 어떻게 운영하나 — 2026 권장 "하이브리드 오너십"

모델내용평가
하이브리드 (권장)플랫폼팀이 실행 백본·공유 라이브러리·표준 소유, 제품 스쿼드 내 embedded QA/개발자가 자기 기능 영역을 책임주인의식 + 일관성 양립
중앙 QA 단독한 QA팀이 전부 소유병목 · 제품팀 주인의식 부재 (가장 역기능적)
개발자 100%개발자가 E2E도 전담품질 하락 · 커버리지 공백 (전담 지원 없으면)
공통 운영 패턴:Shift-left — 테스트를 배포 후가 아니라 개발 단계에서 작성(QA 역할이 "사후검증"→"조기 enabling") ② CI 품질 게이트 — 통과율·커버리지·보안 임계 미달 시 배포 차단 ③ preview/배포 환경에서 실행 — localhost가 못 잡는 통합 버그 포착
우리 위치: 플랫폼(e2e/ 인프라 + ui/ 셀렉터 SSOT) + 개발자(기능별 spec) = 하이브리드에 근접. EC2 오프로드 = "배포 환경 실행" 패턴의 self-hosted 버전. 다만 CI 품질 게이트(테스트 누락 차단)는 아직 없음 → 보강 필요.

실제 도입 사례 (대기업 · 스타트업)

조직어떻게
MicrosoftPlaywright 자체 개발사. VS Code 등 자사 제품 E2E에 사용. Codegen·UI Mode·Trace Viewer·MCP 에이전트로 작성→실행→수리 전 과정 도구화
Zalando (유럽 최대 패션 커머스)엔지니어링 블로그: Playwright "test probes"로 프로덕션 합성 모니터링(E2E를 배포 검증 + 상시 헬스체크로 확장)
Mission Lane (핀테크)Percy + Playwright + Figma 조합으로 전 페이지 모바일/데스크톱 비주얼 스냅샷 자동 생성
Fortune 500 프로덕션Amazon · Apple · NVIDIA · Walmart 등 — 12,000+ 기업이 프로덕션에서 Playwright 운영
스타트업 표준 패턴Vercel/Netlify preview 배포 + GitHub Actions에서 Playwright 자동 실행 → PR에 결과 코멘트 (우리 EC2 오프로드와 동형)

성과 / 정량 지표

41%
팀 primary E2E = Playwright
(State of Testing 2026, n=4,821)
91%
개발자 만족도
(State of JS 2025, vs Cypress 72%)
94%
retention (재사용률)
E2E 도구 중 최고
33M
주간 npm 다운로드
(Cypress의 5배)
3-6개월
자동화 투자 ROI 회수
(잦은 릴리스·회귀 환경)
75%
회귀 테스트 시간 감소
(95% 결함탐지·42% 빠른 실행)
커뮤니티 동향: Playwright는 5년간 ~70배 성장(npm 사상 최고 채택 속도)으로 Selenium(22%)·Cypress(34%)를 추월. 2026 최대 변화는 AI 테스트 생성의 표준화 — World Quality Report 2025-26 기준 89% 조직이 GenAI QE를 파일럿/배포(37% 프로덕션). 우리의 Playwright Agents(planner/generator/healer)가 이 흐름에 정확히 부합.

09 Playwright Agents (self-healing 루프)

.mcp.json playwright-test MCP 서버 기반 3개 에이전트(sonnet). 1 cycle ≈ $0.3–0.6.

에이전트역할
planner라이브 앱 탐색 → specs/*.md 생성 (happy/edge/error 시나리오)
generatorplan 단계를 MCP로 실시간 실행 → tests/<domain>/*.spec.ts 생성 (1파일 1테스트)
healer실패 진단·셀렉터/타이밍 수정·재시도, 끝까지 안 되면 test.fixme()
현재 세션 MCP 미연결 — 사용 시 재연결 필요. healer는 스케줄 실행 권장.