696 lines
136 KiB
Markdown
696 lines
136 KiB
Markdown
# E2E 전수 순회 체크리스트 — 2026-07-27
|
||
|
||
> **목적**: IA·버튼 단위로 온보딩→가입→학습자→교수자→관리자→설정 전 페이지의 모든 기능을 순회하며
|
||
> (1) 의도와 다른 동작, (2) 오류, (3) 나쁜 UI/UX를 잡아낸다.
|
||
> **방식**: RED → GREEN. 각 항목은 검증 수단(기존 spec / 신규 spec / 탐색 순회)을 명시하고,
|
||
> 실제 실행해 GREEN이 된 것만 `- [x]`로 바꾼다. 가짜 DONE 금지(실행 명령+관측 결과 필수).
|
||
> **SSOT**: 상태 결론은 `docs/dev_dashboard.html`에 동기화한다.
|
||
>
|
||
> 실행 스택: dev-up.ps1 (DB 55432 + API 8000 + web 5173 + engine 9099, `db:true engine:true` 확인됨).
|
||
|
||
## 전체 항목 수 요약
|
||
|
||
11개 에이전트가 수합한 기능 인벤토리 기준. 총 **412개 feature**, 그중 **139건**이 의심 결함(risk)으로 보고됐다.
|
||
|
||
| # | 영역 | 라우트 | 항목 수 | 의심 결함 |
|
||
|---|---|---|---|---|
|
||
| 1 | 인증·온보딩 (auth) | `/login`, `/onboarding`, `/pending` | 34 | 13 |
|
||
| 2 | 학습자 홈 (learner-home) | `/learn`, `/learn/practice`, `/learn/history` | 37 | 12 |
|
||
| 3 | 상담 세션 (session) | `/learn/session/:sessionId` | 53 | 11 |
|
||
| 4 | 회기 리뷰 (session-review) | `/learn/session/:id/review`, `/teach/session/:id/review` | 37 | 18 |
|
||
| 5 | 교수자 콘솔 (professor) | `/teach`, `/teach/analysis` | 36 | 12 |
|
||
| 6 | 페르소나 스튜디오 (persona-studio) | `/teach/personas` | 71 | 21 |
|
||
| 7 | 관리자 콘솔 (admin) | `/admin`, `/admin/users`, `/admin/access`, `/admin/tickets` | 57 | 15 |
|
||
| 8 | 관리자 AI 설정 (admin-ai) | `/admin/ai` | 27 | 9 |
|
||
| 9 | 설정 (settings) | `/settings` | 35 | 18 |
|
||
| 10 | 공통 셸·GNB·라우팅 가드 (shell) | 전역 GNB, `/`, `*`, dev 라우트 | 25 | 10 |
|
||
| | **합계** | | **412** | **139** |
|
||
|
||
검증 수단 표기 규칙:
|
||
|
||
- `기존 e2e/{파일}` — 해당 spec 시나리오가 그 기능을 명확히 검증함. 베이스라인 실행으로 GREEN 확인.
|
||
- `기존(부분) e2e/{파일} + 탐색 순회` — spec이 일부(레이아웃·인접 흐름)만 덮음. 나머지는 브라우저 순회로 확인.
|
||
- `신규 spec 필요` — 이 기능을 검증하는 spec이 없음. RED 스펙부터 작성.
|
||
- `탐색 순회` — 자동화 가치가 낮은 순수 표시·이동 항목. 브라우저 순회로만 확인.
|
||
|
||
## 0. 베이스라인 — 기존 E2E 215개 전체 실행
|
||
|
||
- [x] `npm run e2e` parallel 단계 (166 tests) 전체 GREEN — 2026-07-27 실행, **166 passed (2.6m)**
|
||
- [x] `npm run e2e` single-run 단계 (49 tests) 전체 GREEN — 2026-07-27 실행, **49 passed (15.1m)**
|
||
- [x] 실패 항목 → 아래 해당 영역에 RED로 등재 후 수정 — 베이스라인 실패 0건(등재할 항목 없음)
|
||
|
||
> 베이스라인 근거: dev-up 스택(`db:true engine:true`)에서 `npm run e2e` 1회 완주, 215/215 passed.
|
||
> 아래 각 영역에서 `검증: 기존 e2e/...`(부분 아님) 항목은 이 실행을 GREEN 증거로 삼아 체크한다.
|
||
>
|
||
> **최종 게이트(2026-07-27, 결함 수정 반영 후)**: 신규 `full-sweep-*.spec.ts` 10파일 포함
|
||
> `npm run e2e` 재완주 — 병렬 단계 424 수집(fixme 4·모바일 의도 숨김 스킵 2 제외 전 GREEN),
|
||
> 직렬 단계 **49/49 passed (14.4m)**, exit 0. 부가 게이트: 백엔드 pytest **412/412**, gateway 29/29,
|
||
> typecheck·build·check:api-types·design-ssot·dead-code·duplication(0.03%) 통과,
|
||
> layout-visual-gate **15/15**, session-layout **8/8**.
|
||
>
|
||
> **소유자 결정 구현 후 재완주(2026-07-27, 대시보드 144차)**: 아바타 변경·동의 철회/재동의·기초 우선
|
||
> 추천·분석 테이블 가상화·저작 레일 정리·감정 밸런스 차트 반영 후 `npm run e2e` 3차 완주 —
|
||
> 병렬 **432 수집**(구 fixme 2건은 실 계약 테스트로 전환 GREEN, 모바일 의도 숨김 스킵 2 제외 전 GREEN),
|
||
> 직렬 **49/49 passed (15.9m)**, exit 0. 백엔드 pytest **421/421**(`test_review_valence.py` 9 신규),
|
||
> 감정 차트는 실DB 공감 5턴 세션에서 baseline·client 각 5포인트/축 4라벨 라이브 실측.
|
||
|
||
## 1. 인증·온보딩 (auth)
|
||
|
||
- [x] `auth-login-config-load` 로그인 설정 조회 (OAuth 구성/허용 도메인) — `GET /auth/config`로 OAuth 구성·dev 로그인 가능 여부·허용 도메인을 받아 버튼 활성/라벨/배지를 결정한다 · 검증: 기존(부분) e2e/auth.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `auth-login-school-google-button` 학교 Google 계정으로 계속 버튼 (primary) — 클릭 시 `/auth/login?provider=google&next=`로 이동해 Google OAuth를 시작하고 oauthReady가 아니면 비활성화된다 · 검증: 기존(부분) e2e/auth.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `auth-login-generic-google-button` Google 계정으로 계속 버튼 (secondary) — primary와 동일한 startOAuth를 호출하며 서브라벨에 두 번째 허용 도메인을 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `auth-login-oauth-status-notice` OAuth 비활성 사유 status 안내 — oauthReady가 아닐 때 role=status로 설정 확인 중/미연결/로컬 테스트 계정 사유를 아이콘과 함께 표시한다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-login-oauth-error-notice` OAuth 콜백 오류 메시지 (?oauth= 쿼리) — 쿼리 사유별(not_configured·domain_not_allowed·access_denied 등) 한국어 안내문과 원본 코드를 표시한다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-login-dev-role-radiogroup` 로컬 테스트 역할 선택 라디오그룹 (학습자/교수자/관리자) — DEV이고 dev_login_enabled일 때만 노출되며 세 역할 버튼으로 dev 로그인 역할을 고른다 · 검증: 기존(부분) e2e/auth.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `auth-login-dev-enter-button` 로컬 테스트 계정으로 계속 버튼 — 선택 역할의 고정 dev 계정으로 `POST /auth/dev-login` 후 initialPathForUser 규칙대로 이동한다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-login-brand-domain-badges` 브랜드 패널 허용 도메인 배지 — allowed_email_domains를 배지로 나열하고 조회 중/미설정 상태를 구분 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `auth-login-dev-oauth-unavailable-detection` 로컬 개발에서 OAuth 차단 감지 — redirect_uri가 localhost가 아니면 OAuth 버튼을 비활성화하고 테스트 계정 안내로 대체한다 · 검증: 기존(부분) e2e/auth.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `auth-onboarding-initial-load` 온보딩 초기 데이터 로드 (프로필+약관) — `/users/me`와 `/users/legal-docs`를 병렬 호출해 폼을 프리필하고 약관 본문을 채운다 · 검증: 기존(부분) e2e/auth.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `auth-onboarding-avatar-upload` 상징 아바타 이미지 업로드 — 파일 선택 즉시 multipart로 업로드해 avatar_url을 폼에 반영하고 실패 시 3MB 안내를 띄운다 · 검증: 신규 spec 필요
|
||
- [x] `auth-onboarding-avatar-preview` 아바타 미리보기 (이미지/이니셜 폴백) — avatar_url이 있으면 이미지를, 없으면 닉네임 첫 글자를 원 안에 표시한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `auth-onboarding-nickname-input` 닉네임 입력 — 필수 닉네임 텍스트 입력으로 폼 상태를 갱신한다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-onboarding-self-introduction-textarea` 자기소개 textarea (600자 제한) — maxLength 600의 필수 textarea로 상담 훈련 관련 자기소개를 받는다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-onboarding-legal-name-input` 이름(법정 이름) 입력 — 필수 입력이며 프로필의 legal_name 또는 display_name으로 프리필된다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-onboarding-affiliation-input` 소속 입력 (기본값 한신대학교) — 소속 필수 입력으로 프로필 값이 없으면 기본값이 채워진다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-onboarding-department-input` 학과/부서 입력 — department 필수 텍스트 입력으로 폼 상태를 갱신한다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-onboarding-grade-level-input` 학년/직위 입력 — grade_level 필수 텍스트 입력으로 폼 상태를 갱신한다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-onboarding-phone-input` 연락처 입력 — autoComplete=tel 필수 입력으로 연락처를 받는다 · 검증: 기존(부분) e2e/auth.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `auth-onboarding-contact-address-input` 주소/수령지 입력 — autoComplete=street-address 필수 입력으로 주소를 받는다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-onboarding-terms-checkbox` 서비스 이용약관 동의 체크박스 — terms_accepted를 토글하며 미체크 시 제출이 비활성화된다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-onboarding-privacy-checkbox` 개인정보 수집·이용 동의 체크박스 — privacy_accepted를 토글하며 미체크 시 제출이 막힌다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-onboarding-legal-doc-details` 약관/개인정보 문서 펼침 (details/summary) — 두 문서를 details로 펼쳐 제목·버전·본문을 확인하고 미로드 시 폴백을 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `auth-onboarding-submit` 가입 설정 완료 제출 버튼 (form submit) — 필수 필드와 두 동의가 모두 충족될 때만 활성화되어 온보딩을 저장하고 역할 홈으로 이동한다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-onboarding-error-notice` 온보딩 로드/저장 오류 알림 — 로드·저장 실패 시 role=alert 문단을 폼 하단에 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `auth-pending-status-panel` 승인 대기/접속 보류 상태 표시 — suspended면 '접속 보류', 아니면 '승인 대기' 키커와 이메일·안내를 role=status로 보여준다 · 검증: 신규 spec 필요
|
||
- [x] `auth-pending-refresh-button` 승인 상태 새로고침 버튼 — `GET /auth/me`로 세션을 재조회해 승인되면 온보딩 또는 역할 홈으로 이동시킨다 · 검증: 신규 spec 필요
|
||
- [x] `auth-pending-signout-button` 다른 계정으로 로그인 버튼 (로그아웃) — 세션을 종료하고 /login으로 이동해 다른 계정 로그인을 허용한다 · 검증: 신규 spec 필요
|
||
- [x] `auth-provider-bootstrap` AuthProvider 세션 부트스트랩 — 앱 시작 시 `/auth/me`로 쿠키 세션을 복원하고 auth-expired 이벤트 수신 시 user를 비운다 · 검증: 기존(부분) e2e/learner.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `auth-guard-require-auth` RequireAuth 라우트 가드 — 미인증이면 state.from을 담아 /login으로, 역할 불일치면 자기 역할 홈으로 리다이렉트한다 · 검증: 기존 e2e/learner.spec.ts
|
||
- [x] `auth-guard-onboarding-gate` OnboardingGate 리다이렉트 — 온보딩 미완료자를 /onboarding으로 강제 이동시키고 완료자가 /login·/onboarding에 오면 되돌린다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `auth-guard-pending-approval-gate` PendingApprovalGate 리다이렉트 — 미승인 로그인 사용자를 어느 경로에서든 /pending으로 회수한다 · 검증: 신규 spec 필요
|
||
- [x] `auth-root-redirect` 루트(/) 및 미정의 경로 리다이렉트 — / 진입 시 승인·온보딩 상태에 따라 분기하고 미정의 경로(*)는 /로 회수한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `auth-boot-screen` 인증 부트스트랩 로딩 화면 (BootScreen) — 인증 확인·lazy 라우트 로딩 동안 중앙 정렬 '불러오는 중…' 중립 화면을 띄운다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
|
||
**의심 결함(에이전트 리포트)**:
|
||
|
||
- `auth-login-config-load`: config 로드 실패 시 별도 오류 배너 없이 버튼이 영구 비활성 상태로만 남고, statusMessage는 '연결되지 않았습니다' 문구라서 네트워크 오류와 미설정을 구분해 주지 않는다.
|
||
- `auth-login-school-google-button`: '학교 Google 계정' 버튼과 일반 'Google 계정' 버튼이 완전히 동일한 provider=google 흐름을 호출한다(학교 SSO/SAML 별도 흐름 없음). 또한 startOAuth 내부의 !oauthReady 오류 세팅 분기는 버튼이 이미 disabled라 실제로 도달 불가한 사문(死文) 코드다.
|
||
- `auth-login-generic-google-button`: 두 버튼이 기능적으로 중복이라 사용자가 다른 인증 경로로 오해할 수 있다.
|
||
- `auth-login-oauth-error-notice`: 오류 문단에 role=alert/aria-live가 없어 스크린리더에 즉시 공지되지 않는다.
|
||
- `auth-login-dev-role-radiogroup`: role=radio 버튼 그룹이지만 방향키 이동 등 라디오그룹 키보드 시맨틱은 구현되어 있지 않다(Tab으로만 이동).
|
||
- `auth-login-dev-enter-button`: 실패 시 err.message를 그대로 노출하는데 ApiError 메시지가 'API 500: ...' 같은 원문이라 사용자 친화적이지 않을 수 있다.
|
||
- `auth-onboarding-initial-load`: 로드 실패 시 재시도 버튼이 없어 새로고침 외 복구 수단이 없고, 약관 로드 실패여도 동의 체크는 가능해 문서 미확인 동의가 성립한다.
|
||
- `auth-onboarding-avatar-upload`: 클라이언트 측 파일 크기/타입 사전 검증이 없어 3MB 제한을 서버 거절 후에야 알게 되고, 서버 오류 상세는 콘솔에만 남는다.
|
||
- `auth-onboarding-phone-input`: type=text 자유 입력이라 전화번호 형식 검증이 전혀 없다.
|
||
- `auth-onboarding-terms-checkbox`: 약관 본문을 펼쳐 보지 않아도 체크 가능해 열람 강제가 없다.
|
||
- `auth-onboarding-submit`: 실패 시 '온보딩 저장에 실패했습니다' 일반 문구만 표시하고 서버의 필드별 검증 상세(ApiError.detail)는 콘솔에만 버려진다. 또한 성공 후 initialPathForUser가 아닌 roleHomePath로 이동해 admin_access만 있는 비-admin 역할 사용자의 도착지가 로그인 직후 규칙(/admin)과 어긋난다.
|
||
- `auth-pending-refresh-button`: refresh가 네트워크 오류로 실패하면 AuthProvider가 user를 null로 만들어 RequireAuth가 아무 안내 없이 /login으로 튕긴다(여전히 pending인 경우에도 '아직 승인 전'이라는 피드백이 전혀 없음). 버튼 아이콘도 refresh가 아닌 'settings'라 의미가 어긋난다.
|
||
- `auth-guard-pending-approval-gate`: pending 사용자는 /login에도 접근할 수 없어(항상 /pending으로 회수) 계정 전환 경로가 PendingApproval의 로그아웃 버튼 하나뿐이다.
|
||
|
||
## 2. 학습자 홈 (learner-home)
|
||
|
||
- [x] `learner-home-guard-require-auth` RequireAuth(roles=[learner]) 라우트 가드 — 미인증은 /login, learner 권한 없는 역할은 자기 역할 홈으로 보낸다(admin·superAdmin은 통과) · 검증: 기존 e2e/learner.spec.ts
|
||
- [x] `learner-home-guard-pending-approval` PendingApprovalGate 리다이렉트 — 미승인 사용자가 /learn 계열에 오면 state.from을 담아 /pending으로 보낸다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-guard-onboarding` OnboardingGate 리다이렉트 — onboardingCompletedAt이 null이면 /onboarding으로 보낸다 · 검증: 기존 e2e/auth.spec.ts
|
||
- [x] `learner-home-nav-sidebar` 좌측 사이드바 학습자 내비게이션 — 대시보드·학습·기록·설정 NavLink를 제공하고 활성 항목을 알약으로 표시한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `learner-home-initial-load` 마운트 시 페르소나·회기·대시보드 병렬 로드 — allSettled로 3개 API를 병렬 요청하고 각 섹션이 독립된 로딩/오류 상태를 유지한다 · 검증: 기존 e2e/learner.spec.ts + e2e/readiness.spec.ts
|
||
- [x] `learner-home-head-status-live` 헤더 상태 배지(aria-live) — 사용 가능 페르소나 수와 기록 상태를 aria-live=polite로 헤더 우측에 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-dash-metric-cards` 학습 현황 지표 카드 4개 — 진행 회기·리뷰 대기·최근 평가·라포 흐름 카드를 버튼으로 렌더하고 각각 기록/연습 화면으로 이동시킨다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-dash-midwidth-tabs` 중간 폭(≤1180px) 대시보드 가로 탭 3개 — 오늘의 회기·기록 리뷰·성장 지표 탭으로 그리드를 전환하고 데스크톱에서는 2컬럼을 유지한다 · 검증: 기존(부분) e2e/layout-visual-gate.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `learner-home-dash-new-session-shortcut` 오늘의 회기 작업 헤더 '새 회기 선택' 버튼 — 클릭 시 /learn/practice로 이동해 연습 대상 선택 화면을 연다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `learner-home-dash-recap-card` 스포트라이트 회기 리캡 카드 — 우선순위로 고른 회기의 상세를 불러와 아바타·단계·진행률·마지막 발화를 보여준다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-dash-coach-cta` AI 코치 카드와 기본 행동 CTA 버튼 — 규칙 기반 코치 문구와 힌트 칩을 만들고 CTA로 세션·리뷰·연습 중 적절한 곳으로 보낸다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-dash-recommend-card` 다음 연습 추천 카드 버튼 — 리뷰 대기 유무와 최근 평균 턴 수에 따라 문구를 바꿔 기록 또는 연습 화면으로 이동시킨다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-dash-recent-feedback` 최근 피드백 패널(최신 1건 리뷰 이동) — 대시보드 recent_feedback 첫 항목을 버튼으로 보여주고 해당 회기 리뷰로 이동시킨다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-dash-recent-records` 최근 기록 패널(최근 4건 + 전체 보기) — 최근 회기 4건을 컴팩트 행으로 보여주고 상태에 따라 세션 또는 리뷰로 이동시킨다 · 검증: 기존(부분) e2e/learner.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `learner-home-dash-review-queue` 리뷰 대기 패널(review_ready 상위 3건) — review_ready 상위 3건에서 'AI 피드백' 버튼으로 리뷰 화면에 진입시킨다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-dash-weakness-insights` 보완할 부분 패널(파생 인사이트 최대 3건) — growth 데이터에서 하락 추세·낮은 라포 등을 결정론적으로 도출해 버튼으로 제시한다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-dash-rapport-progress` 내담자와 쌓은 라포 누적 바(상위 3명) — 회기가 있는 페르소나 상위 3명의 rapport_percent를 progressbar로 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-dash-milestones` 연습 이정표 배지(achievements) — achievements를 상태별 배지로 나열하고 상세는 title 툴팁으로만 제공한다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-dash-recap-fetch-states` 리캡 상세 로딩·오류 상태 — 스포트라이트 회기가 바뀔 때마다 상세를 다시 불러오고 stale 응답은 session_id 비교로 무시한다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-practice-persona-listbox` 연습 페르소나 선택 리스트(role=listbox/option) — 페르소나별 옵션 버튼으로 선택 상태를 바꾸고 degraded·비DB 항목은 비활성 처리한다 · 검증: 기존 e2e/learner.spec.ts
|
||
- [x] `learner-home-practice-persona-skeleton` 페르소나 목록 스켈레톤·오류 상태 — 로딩 중 스켈레톤 3개를, 실패 시 role=alert 안내를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-practice-preview-pane` 선택 페르소나 프리뷰 — 선택 페르소나의 인적사항·주호소·난도/접근/음성을 보여주고 사용 가능 항목이 없으면 카탈로그 안내로 전환한다 · 검증: 기존(부분) e2e/learner.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `learner-home-practice-start-session` '새 회기 시작' 버튼과 회기 시작 흐름 — 사용 가능 여부를 재검증한 뒤 세션 프리스타트로 이동시킨다 · 검증: 기존 e2e/learner.spec.ts
|
||
- [x] `learner-home-practice-activity-stats` 연습 기록 통계 3칸 — 진행 중·리뷰 가능·누적 회기 수를 표시하고 로딩·오류 시 대시로 대체한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `learner-home-practice-existing-sessions` 선택 페르소나의 기존 회기 목록(최근 5건) — 같은 페르소나의 최근 5건을 상태·단계·턴·진행률과 함께 카드로 나열한다 · 검증: 기존(부분) e2e/learner.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `learner-home-session-card-continue` 회기 카드 '이어하기' 버튼(진행 중 회기) — active 회기에서 세션 화면으로 이동해 대화를 재개한다 · 검증: 기존 e2e/learner.spec.ts
|
||
- [x] `learner-home-session-card-review` 회기 카드 '리뷰'/'기록' 버튼(종료 회기) — review_ready·보관 여부에 따라 라벨을 바꿔 리뷰 화면으로 이동한다 · 검증: 기존 e2e/learner.spec.ts
|
||
- [x] `learner-home-session-card-repeat` 회기 카드 '다시 연습' 버튼 — 같은 페르소나 코드로 새 회기 준비 화면을 연다 · 검증: 기존(부분) e2e/learner.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `learner-home-session-card-archive-toggle` 회기 카드 '보관'/'복원' 토글 버튼 — 종료 회기에서만 보관/복원을 호출하고 성공 시 회기·대시보드를 재조회한다 · 검증: 기존 e2e/learner.spec.ts
|
||
- [x] `learner-home-history-overview-cards` 기록 상태 요약 필터 카드 4개 — 전체·진행 중·리뷰 필요·보관됨 버킷 카드(aria-pressed)로 historyFilter를 전환한다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-history-search` 기록 검색 입력 — 코드·이름·단계·상태·날짜 라벨을 이어붙인 문자열에 부분 일치로 즉시 필터링한다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-history-filter-chips` 기록 상태 필터 칩(도구 행) — 요약 카드와 상태를 공유하는 칩 버튼으로 동일 필터를 전환한다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-history-list` 필터·검색 적용된 회기 카드 목록 — 정렬된 회기를 필터·검색으로 걸러 액션 버튼·진행률 바와 함께 카드로 나열한다 · 검증: 기존(부분) e2e/learner.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `learner-home-history-archive-notice` 보관/복원 결과 안내 배너(role=status) — 보관·복원 성공/실패 문구를 목록 위에 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-history-archive-guide` 아카이브 기준 안내 패널(읽기 전용) — 진행 중·리뷰 필요·보관됨 각각의 의미를 정적 텍스트로 안내한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `learner-home-history-persona-progress` 페르소나별 진행 행 버튼 — 페르소나별 회기·진행·리뷰·평균 턴 요약을 행 버튼으로 보여주고 클릭 시 해당 페르소나로 연습 화면에 진입한다 · 검증: 신규 spec 필요
|
||
- [x] `learner-home-session-list-states` 회기 목록 공용 로딩·오류·빈 상태 — 로딩 문구·인라인 경고·컨텍스트별 빈 메시지를 구분 표시한다 · 검증: 신규 spec 필요
|
||
|
||
**의심 결함(에이전트 리포트)**:
|
||
|
||
- `learner-home-initial-load`: 실패 시 재시도 버튼이 어디에도 없어 사용자는 새로고침 외에 복구 수단이 없음
|
||
- `learner-home-head-status-live`: loadState가 error일 때도 삼항 조건이 '확인 중'을 영구 표시해 페르소나 로드 실패가 헤더에서는 드러나지 않음
|
||
- `learner-home-dash-midwidth-tabs`: role=tab인데 화살표 키 이동·aria-controls/tabpanel 연결이 없어 WAI-ARIA 탭 패턴 미준수
|
||
- `learner-home-dash-recap-card`: 아바타 rapport 값이 실제 데이터가 아닌 하드코딩(정리 단계 0.72, 그 외 0.38)이고, 상세 로드 실패(error)와 발화 없음(empty)이 같은 문구로 표시되어 구분 불가
|
||
- `learner-home-dash-coach-cta`: sessionLoadState=error일 때 CTA 라벨이 '기록 다시 확인'이지만 실제 동작은 재요청이 아니라 /learn/practice 이동이라 라벨과 동작이 불일치
|
||
- `learner-home-dash-recent-feedback`: 배지에는 recentFeedback.length건으로 표시하면서 목록에는 1건만 노출해 나머지 피드백에 접근할 UI가 없음
|
||
- `learner-home-dash-milestones`: 상세 설명이 title 툴팁뿐이라 터치 기기·스크린리더에서 접근 불가
|
||
- `learner-home-practice-persona-listbox`: role=listbox/option 구조인데 화살표 키 탐색·aria-activedescendant가 없어 커스텀 리스트박스 키보드 패턴 미구현(버튼 Tab 이동만 가능)
|
||
- `learner-home-practice-persona-skeleton`: '다시 시도해 주세요' 안내만 있고 실제 재시도 버튼은 제공하지 않음
|
||
- `learner-home-session-card-repeat`: 해당 페르소나가 현재 사용 불가(degraded/비DB)로 바뀐 경우에도 비활성화 없이 이동을 허용해 Session 페이지에서야 실패를 만나게 됨
|
||
- `learner-home-session-card-archive-toggle`: archiveNotice 표시 블록이 history 뷰에만 렌더링되어, practice 뷰의 기존 회기 목록에서 보관/복원(특히 실패)을 눌러도 결과 안내가 화면에 전혀 나타나지 않음
|
||
- `learner-home-history-archive-notice`: 자동 해제 타이머가 없어 다음 토글 전까지 이전 안내가 계속 남고, 실패 원인(HTTP 상태 등)은 console.warn으로만 남아 사용자에게 전달되지 않음
|
||
|
||
## 3. 상담 세션 (session)
|
||
|
||
- [x] `session-guard-require-auth` RequireAuth(learner) 라우트 가드 — 미인증은 /login(state.from 보존), learner 권한 없으면 자기 역할 홈으로 보낸다 · 검증: 기존 e2e/learner.spec.ts
|
||
- [x] `session-guard-pending-approval` PendingApprovalGate 가드 — 미승인 계정은 /pending으로 리다이렉트한다 · 검증: 신규 spec 필요
|
||
- [x] `session-guard-onboarding` OnboardingGate 가드 — 온보딩 미완료 사용자는 /onboarding으로 리다이렉트한다 · 검증: 기존(부분) e2e/auth.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-route-empty-param-redirect` 빈 라우트 파라미터 리다이렉트 — 파라미터가 비면 /learn으로 replace 이동하고, 페르소나 코드면 세션 상태를 초기화한다 · 검증: 신규 spec 필요
|
||
- [x] `session-persona-load` 페르소나 정보 로드(로딩/누락/오류 상태) — 코드를 대조해 아바타·컨텍스트를 구성하고 상태별 안내를 프리스타트에 표시한다 · 검증: 기존 e2e/learner.spec.ts
|
||
- [x] `session-resume-load` 기존 회기 재개(resume) 로드 — 세션 ID면 서버 스냅샷으로 턴·단계·경과·진행률을 복원하고 방금 시작한 회기는 재로딩을 건너뛴다 · 검증: 기존 e2e/session-layout.spec.ts
|
||
- [x] `session-theory-mode-select` 이론모드 세그먼트 선택(인간중심/CBT/통합) — 시작 전 이론모드를 고르며 페르소나 theory_target 첫 항목이 기본 선택된다 · 검증: 기존 e2e/session-persistence.spec.ts
|
||
- [x] `session-goal-toggle` 이번 회기 목표 단계 토글(라포/탐색/개입/정리) — 목표 단계를 1~4개 토글하며 0개면 시작 버튼이 비활성화된다 · 검증: 기존(부분) e2e/session-mvp.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-consent-checkbox` 연습 기록 처리 동의 체크박스 — 동의 이력이 없는 learner에게만 노출되며 체크해야 저장 버튼이 활성화된다 · 검증: 신규 spec 필요
|
||
- [x] `session-consent-save` 동의 저장 버튼 — 동의를 서버에 기록하고 성공 시 pos 신호, 실패 시 오류 문구를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `session-start-button` 회기 시작 버튼 — 준비·동의·목표 조건이 충족될 때만 활성화되어 세션을 생성하고 URL을 실제 세션 ID로 교체한 뒤 음성 가용성을 사전 확인한다 · 검증: 기존 e2e/session-persistence.spec.ts
|
||
- [x] `session-prestart-status-messages` 프리스타트 상태/오류 문구 표시 — 페르소나 로딩·없음·실패·사용 불가와 시작 오류를 구분된 문구로 표시한다 · 검증: 기존(부분) e2e/learner.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-nav-back-history` 세션바 '기록으로' 버튼 — 회기 시작 후 상단 세션바에서 /learn/history로 이동한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-nav-learn-home` 세션바 '학습 홈' 버튼 — /learn 학습자 홈으로 이동한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-nav-review-sessionbar` 세션바 리뷰 이동 버튼 — 종료 후에만 노출되어 리뷰로 이동하며 reviewReady에 따라 라벨이 바뀐다 · 검증: 기존(부분) e2e/session-mvp.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-time-alarms` 시간 알람(10분 전 경고·시간 만료) — 경고 구간 진입 시 warn 신호를 1회 띄우고 만료 시 timeUp으로 전환해 종료 다이얼로그를 자동으로 연다 · 검증: 신규 spec 필요
|
||
- [x] `session-timebar-end-button` 시간 만료 바 '종료하고 리뷰 보기' 버튼 — role=alert 시간 바에서 만료 시 노출되어 종료 확인 다이얼로그를 연다 · 검증: 신규 spec 필요
|
||
- [x] `session-phase-tracker` 회기 단계 트래커(헤더 가로 + 좌측 세로) — 4단계의 완료·진행·예정 상태와 목표 배지, 서버 progress 기반 누적 게이지를 표시한다 · 검증: 기존(부분) e2e/session-layout.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `session-ctx-collapse` 내담자 컨텍스트 패널 접기/펼치기 — aria-expanded 토글로 내담자 이름·메타·호소/대상/난도 행을 접고 펼친다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-progress-panel` 세션 진행 패널(경과/남은 시간/발화 수) — 경과·남은 시간·저장 발화 수를 표시하고 목표 달성 시 축하 문구를 띄운다 · 검증: 기존(부분) e2e/session-layout.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `session-avatar-display` 내담자 아바타 + 음성 오브 표시 — 상태·개방도·단계에서 파생한 표정을 렌더하고 TTS 재생 중 Analyser로 입모양을 구동한다 · 검증: 기존 e2e/avatar-expression.spec.ts
|
||
- [x] `session-transcript-autoscroll` 자막 자동 스크롤 + '최신으로' 점프 버튼 — 새 발화 시 하단으로 따라가되 위로 스크롤하면 해제하고 복귀 버튼을 띄운다 · 검증: 신규 spec 필요
|
||
- [x] `session-transcript-utterances` 발화 목록(부분 스트리밍/저장 실패/응답 대기 표시) — 화자·타임코드와 함께 스트리밍 캐럿·저장 실패 노트·응답 대기 인디케이터를 표시한다 · 검증: 기존 e2e/session-mvp.spec.ts · 베이스라인 215/215 GREEN
|
||
- [x] `session-transcript-empty-state` 자막 빈 상태 안내 — 발화가 없으면 종료 여부에 따라 첫 질문 대기 또는 종료 기록 문구를 보여준다 · 검증: 신규 spec 필요
|
||
- [x] `session-transcript-coach-mark` 학습자 발화의 코칭 마크(C) 버튼 — 코칭 이력이 있는 턴에 C 배지를 붙이고 클릭 시 해당 턴 필터로 이력 모달을 연다 · 검증: 기존 e2e/session-mvp.spec.ts
|
||
- [x] `session-compose-input` 학습자 발화 텍스트 입력(Enter 전송) — Enter 전송·Shift+Enter 줄바꿈이며 종료·일시정지·전송 중에는 비활성화된다 · 검증: 기존 e2e/session-mvp.spec.ts
|
||
- [x] `session-send-button` '보내기' 버튼(텍스트 턴 SSE 스트림) — 낙관적 발화 추가 후 SSE로 응답 토큰을 흘리고 done에서 단계·개방도·진행률을 반영한다 · 검증: 기존 e2e/session-persistence.spec.ts
|
||
- [x] `session-stream-error-handling` 스트림 오류 처리(롤백·문구 매핑) — 실패 시 낙관적 발화를 제거하고 입력을 복원하며 오류 코드를 사용자 문구로 매핑한다 · 검증: 기존 e2e/session-layout.spec.ts
|
||
- [x] `session-turn-error-display` 턴 오류 알림 섹션 — turnError를 role=alert 섹션에 '엔진 연결/회기 종료' 제목과 함께 표시한다 · 검증: 기존(부분) e2e/session-layout.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-crisis-gate` 위기 안전게이트 — 위기 신호 수신 시 회기를 일시정지하고 마이크를 끄며 109 등 위기 자원과 안전 패널을 강제로 연다 · 검증: 기존 e2e/session-mvp.spec.ts + e2e/session-persistence.spec.ts
|
||
- [x] `session-crisis-tel-link` 위기 자원 전화 링크 — 위기 자원 번호를 tel: 링크로 제공해 즉시 전화를 걸 수 있게 한다 · 검증: 신규 spec 필요
|
||
- [x] `session-safety-panel-collapse` 안전 점검 패널 접기/펼치기 — 토글로 접되 위기 신호가 있으면 접힘을 무시하고 항상 펼친다 · 검증: 기존(부분) e2e/session-mvp.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-live-signal` 라이브 신호(앰비언트 도트 + 최근 흐름) — 이벤트마다 도트를 6초 페이드로 띄우고 최근 5개 시퀀스를 누적하며 모드별로 노출을 달리한다 · 검증: 신규 spec 필요
|
||
- [x] `session-feedback-mode-segmented` 화면 모드 세그먼트(몰입/상태 신호/코칭) — 피드백 강도 3모드를 전환하고 코칭 버튼에 남은 기회 배지를 붙인다 · 검증: 기존(부분) e2e/session-mvp.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `session-coach-auto-request` 턴 완료 후 라이브 코칭 자동 요청 — 코칭 모드에서 남은 기회를 확인해 코칭을 요청하고 409면 소진 문구를, 비코칭 모드면 넛지로 보관한다 · 검증: 기존 e2e/session-mvp.spec.ts + e2e/session-persistence.spec.ts
|
||
- [x] `session-coach-card` AI 코치 카드(기회 도트·크레딧 펄스·degraded) — 남은 기회 도트와 크레딧 펄스, 제안 문구, degraded·runtime 경고를 표시한다 · 검증: 기존 e2e/session-mvp.spec.ts
|
||
- [x] `session-coach-nudge` 코칭 넛지 버튼 — 코칭 화면이 닫힌 채 기회가 대기 중이면 넛지를 띄우고 클릭 시 코칭 모드로 전환해 즉시 요청한다 · 검증: 신규 spec 필요
|
||
- [x] `session-coach-evidence-modal` 코칭 근거 모달('근거 보기') — 판단·다음 문장·RAG 근거 자료를 다이얼로그로 보여주고 Escape·오버레이·닫기로 닫는다 · 검증: 기존 e2e/session-mvp.spec.ts
|
||
- [x] `session-coach-history-modal` 코칭 이력 모달('이력 보기'/턴 마크) — 턴별 코칭 이벤트를 시간순으로 보여주고 로딩/오류/빈 상태와 runtime 경고를 구분한다 · 검증: 기존 e2e/session-mvp.spec.ts
|
||
- [x] `session-meters-collapse` 관찰 신호 패널 접기 + 게이지 3종 — 방어·유효 개방도·라포 게이지를 서버 progress 또는 휴리스틱으로 표시하고 접으면 라포 %를 요약한다 · 검증: 신규 spec 필요
|
||
- [x] `session-mic-toggle` 마이크 버튼(음성 녹음 시작/발화 전송) — 권한 요청 후 음성 WS를 열어 PCM 청크를 보내고 다시 누르면 audio_end로 발화를 확정한다 · 검증: 기존 e2e/voice-success.spec.ts
|
||
- [x] `session-voice-ws-events` 음성 WebSocket 이벤트 처리 — ready/state/transcript/reply/tts_end/degraded/error 이벤트를 상태·자막·신호에 반영하고 바이너리는 TTS 버퍼로 쌓는다 · 검증: 기존 e2e/voice-success.spec.ts
|
||
- [x] `session-voice-error-recovery` 음성 오류/연결 종료 시 발화 실패 처리 — reply 확정 전 WS가 끊기면 대기 발화를 '저장 실패'로 표시하고 마이크를 안전 상태로 되돌린다 · 검증: 기존 e2e/session-mvp.spec.ts
|
||
- [x] `session-tts-playback` 내담자 TTS 재생(WebAudio+Analyser, Audio 폴백) — 합성 mp3를 WebAudio로 재생하며 입모양을 구동하고 실패 시 Audio 폴백·degraded 안내로 넘어간다 · 검증: 기존 e2e/voice-success.spec.ts
|
||
- [x] `session-voice-skip` 음성 '건너뛰기' 버튼 — TTS 재생 중에만 노출되어 재생·버퍼를 끊고 소켓을 닫은 뒤 idle로 복귀한다 · 검증: 신규 spec 필요
|
||
- [x] `session-pause-toggle` 일시정지/이어가기 버튼 — 일시정지 시 타이머·음성 캡처·재생을 모두 멈추고 이어가기 시 listening으로 복귀한다 · 검증: 신규 spec 필요
|
||
- [x] `session-end-open` '회기 종료' 버튼 — 종료 확인 다이얼로그를 열며 종료 처리 중에는 비활성화된다 · 검증: 기존 e2e/session-mvp.spec.ts
|
||
- [x] `session-end-dialog` 회기 종료 확인 다이얼로그 — 취소/종료 버튼 사이 Tab 포커스 트랩과 Escape·오버레이 닫기, 포커스 복원을 제공한다 · 검증: 기존(부분) e2e/session-mvp.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `session-end-confirm` '종료하고 리뷰 보기' 확정 버튼 — 종료 API 성공 시 리뷰로 replace 이동하고 실패 시 리뷰로 넘어가지 않고 오류를 표시한다 · 검증: 기존 e2e/session-mvp.spec.ts
|
||
- [x] `session-review-button-controlbar` 컨트롤바 리뷰 이동 버튼(종료 후) — 종료 후 일시정지·종료 자리를 대체해 리뷰로 이동하며 준비 상태에 따라 라벨이 바뀐다 · 검증: 기존(부분) e2e/session-mvp.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-keyboard-shortcuts` 키보드 단축키(Space=마이크, P=일시정지) — 입력창 포커스가 아닐 때 Space로 마이크를, P로 일시정지를 토글한다 · 검증: 신규 spec 필요
|
||
- [x] `session-elapsed-live-region` 경과 시간 스크린리더 라이브 리전 — sr-only aria-live 요소로 경과 시간을 보조기기에 알린다 · 검증: 신규 spec 필요
|
||
- [x] `session-mobile-context-strip` 모바일 컨텍스트 요약 스트립 — 모바일 폭에서 회기 상태·내담자·마이크·단계·안전 상태를 한 줄로 요약한다 · 검증: 기존(부분) e2e/session-layout.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
|
||
**의심 결함(에이전트 리포트)**:
|
||
|
||
- `session-start-button`: consent_required 외 모든 시작 실패가 단일 일반 문구로 뭉개져 원인(권한/404 등) 구분이 안 됨
|
||
- `session-nav-back-history`: 진행 중 회기에서 확인 없이 즉시 이탈 가능(회기는 서버에 남지만 이탈 경고 없음)
|
||
- `session-nav-learn-home`: 진행 중 회기 이탈 확인 다이얼로그 없음
|
||
- `session-timebar-end-button`: timeUp 이후에도 텍스트 입력이 클라이언트에서 막히지 않고 서버 session_time_over 오류에 의존함(의도된 정리 유예일 수 있으나 안내 부족)
|
||
- `session-stream-error-handling`: 오류 롤백 시 서버에 이미 저장됐을 수 있는 턴과 클라이언트 상태가 어긋나 재전송하면 중복 턴 가능
|
||
- `session-feedback-mode-segmented`: 세그먼트 3개 버튼에 type="button" 누락, 선택 상태가 aria-pressed 없이 클래스로만 표현됨
|
||
- `session-coach-evidence-modal`: 초기 포커스와 Escape만 있고 Tab 포커스 트랩이 없어 모달 밖으로 포커스 이탈 가능(종료 다이얼로그는 트랩 있음)
|
||
- `session-coach-history-modal`: 근거 모달과 동일하게 Tab 포커스 트랩 없음
|
||
- `session-mic-toggle`: WS onmessage가 소켓 생성 시점의 elapsed를 클로저로 고정해 음성 발화 타임코드가 마이크 연결 시각으로 표시됨
|
||
- `session-keyboard-shortcuts`: 한글 IME 등 contentEditable은 typing 예외에서 빠져 있고, P 단축키는 다이얼로그가 열린 상태에서도 동작해 모달 뒤 상태를 바꿀 수 있음
|
||
- `session-elapsed-live-region`: 매초 갱신되는 aria-live=polite라 스크린리더가 1초마다 경과 시간을 읽어 소음이 될 수 있음
|
||
|
||
## 4. 회기 리뷰 (session-review)
|
||
|
||
- [x] `session-review-guard-require-auth` RequireAuth 라우트 가드 — 미인증은 /login, 역할 불일치(학습자/교수자 경로)면 자기 역할 홈으로 replace 리다이렉트한다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-guard-pending-onboarding` PendingApprovalGate·OnboardingGate 전역 가드 — 미승인은 /pending, 온보딩 미완료는 /onboarding으로 보내고 로딩 중 BootScreen을 띄운다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-initial-load` 리뷰 데이터 초기 로드와 로딩 상태 — 축어록·평가·워크시트·교수자 검토를 한 번에 불러오고 로딩 중 빈 카드를 표시한다 · 검증: 기존 e2e/session-review.spec.ts
|
||
- [x] `session-review-error-state` 리뷰 로드 오류 상태 — sessionId 누락·로드 실패 시 '리뷰를 표시할 수 없습니다' 카드에 오류 메시지를 보여준다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-teacher-auto-redirect` 교수자 자동 리다이렉트 — 학습자 경로에서 teacher 권한자가 teacherReview 응답이나 403을 만나면 교수자 리뷰 경로로 옮긴다 · 검증: 기존 e2e/session-review.spec.ts
|
||
- [x] `session-review-ready-polling` 평가 준비 상태 폴링 — 평가 대기 조건이면 1.5초 간격 최대 60회까지 리뷰를 재조회한다 · 검증: 기존 e2e/session-review.spec.ts
|
||
- [x] `session-review-tabs` 리뷰 영역 가로 탭(축어록/피드백/워크시트) — role=tablist 탭 3개로 영역을 전환하며 aria-selected로 활성 탭을 표시한다 · 검증: 기존(부분) e2e/session-review.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `session-review-btn-teach-console` 교수 콘솔로 이동 버튼 — 교수자 화면에서만 노출되며 클릭 시 /teach로 이동한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-review-btn-retry-evaluation` AI 평가 재시도 버튼 — 평가 실패 상태의 종료 회기에서만 노출되어 session_end 범위 재평가를 요청하고 리뷰를 다시 로드한다 · 검증: 기존 e2e/session-review.spec.ts + e2e/session-persistence.spec.ts
|
||
- [x] `session-review-btn-audio` 오디오 다시 듣기 버튼 — audioUrl이 있을 때만 활성화되어 새 탭으로 오디오 URL을 연다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-btn-pdf` PDF 내보내기 버튼 — pdfExportUrl이 있을 때만 활성화되어 새 탭으로 내보내기 URL을 연다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-btn-share` 공유 URL 생성·복사 버튼 — 종료된 회기의 학습자 화면에서 공유 링크를 만들어 클립보드에 복사하고 라벨을 바꾼다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-share-note` 공유 URL·오류 노트 표시 — 생성된 URL 또는 실패 메시지를 요약 카드 하단 노트로 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-transcript-filter` 축어록 전체/내 발화만 필터 토글 — aria-pressed 칩 2개로 전체·학습자 발화 보기를 전환하며 발화가 없으면 비활성화된다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-turn-jump` 코멘트 타임스탬프로 발화 점프 — jumpTo 버튼으로 해당 발화를 강조·중앙 정렬하고 필요하면 필터를 자동 해제한다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-transcript-display` 축어록 타임라인 표시(칩·PII 마스킹·빈 상태) — 타임스탬프·기법/비언어 칩·콜아웃을 표시하고 PII 플레이스홀더를 한국어 라벨로 치환한다 · 검증: 기존 e2e/session-review.spec.ts
|
||
- [x] `session-review-summary-band` 리뷰 요약 밴드와 준비 상태 표시 — 강조 태그 포함 요약과 근거 발화 수·평가 상태·도달 단계를 보여주고 엔진 오류 흔적은 대체 문구로 마스킹한다 · 검증: 기존(부분) e2e/session-review.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `session-review-valence-chart` 감정 밸런스 타임라인 차트 — 내담자 정서가와 상담자 기준선을 스무딩 SVG로 그리고 데이터가 없으면 빈 상태를 보여준다 · 검증: 기존(부분) e2e/session-review.spec.ts + 탐색 순회 · 빈 상태 GREEN — 차트 데이터 경로는 서버 미구현(결함 로그 #21, 로드맵)
|
||
- [x] `session-review-phase-flow` 회기 흐름 단계 바 — 단계별 weight 비율 가로 바를 그리고 구간마다 단계명·비율 툴팁을 붙인다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-rubric-display` 기법 사용 분포 카드 — 기법별 사용 빈도 바와 적절/살펴보기 품질 배지를 표시하고 평가가 없으면 대기 상태를 보여준다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-good-growth-points` 좋았던 순간·다음 회기 개선점 카드 — 근거 있는 강점과 개선점(최대 3개)을 점프 버튼과 함께 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-client-feedback` 마지막 내담자 반응 표시 — AI 내담자가 생성한 마지막 피드백 인용문을 보여주고 없으면 빈 문구를 표시한다 · 검증: 기존(부분) e2e/session-mvp.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-review-worksheet-edit` 사례개념화 워크시트 항목 편집 — 학습자 화면에서 섹션별 textarea 수정 시 confidence를 자동 조정하고 dirty 상태로 전환한다(교수자는 읽기 전용) · 검증: 기존 e2e/session-persistence.spec.ts
|
||
- [x] `session-review-worksheet-save` 워크시트 저장 버튼 — 변경이 있을 때만 활성화되어 초안과 limitations를 PUT 저장하고 라벨을 저장→저장됨으로 바꾼다 · 검증: 기존 e2e/session-persistence.spec.ts
|
||
- [x] `session-review-worksheet-evidence-jump` 워크시트 근거 발화 이동 버튼 — 워크시트 항목의 첫 근거 인용 버튼으로 해당 발화에 점프한다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-prepost-load` 사전/사후 점수 원장 로드 — 마운트 시 phase3-pilot-draft 파일럿 측정값을 불러와 초안·기준선과 완료쌍 배지를 채운다 · 검증: 기존 e2e/session-persistence.spec.ts
|
||
- [x] `session-review-prepost-input` 사전/사후 점수 입력(3척도×2시점) — 자기효능감·기술숙련도·수련만족도 사전/사후 값을 1~5로 편집하고 범위 밖 입력은 오류로 막는다 · 검증: 기존 e2e/session-review.spec.ts
|
||
- [x] `session-review-prepost-save` 사전/사후 점수 저장 버튼 — 유효 변경만 있을 때 활성화되어 키별 순차 PUT 후 원장을 재조회한다 · 검증: 기존 e2e/session-persistence.spec.ts
|
||
- [x] `session-review-teacher-note-input` 교수자 검토 메모 입력 — 교수자 전용 textarea(2000자)에 다음 지도 메모를 작성한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `session-review-teacher-save-viewed` 메모 저장(검토 중) 버튼 — 검토 상태를 viewed로 두고 메모·워크시트 메모를 PUT 저장한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `session-review-teacher-close` 검토 완료 버튼 — 종료·평가 준비된 회기에서만 활성화되어 검토 상태를 closed로 저장하고 완료 시각을 표시한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `session-review-teacher-worksheet-note` 워크시트 검수 메모 입력 — 수정요청·반려 사유를 적는 textarea로 검수 결정·메모 저장 시 함께 PUT된다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-teacher-worksheet-approve` 워크시트 승인 버튼 — 학습자 저장본이 있는 종료 회기에서 worksheet_status=approved를 저장한다 · 검증: 기존(부분) e2e/session-persistence.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `session-review-teacher-worksheet-request-changes` 워크시트 수정요청 버튼 — 같은 조건에서 worksheet_status=changes_requested를 저장하고 검수 배지를 갱신한다 · 검증: 기존 e2e/session-persistence.spec.ts
|
||
- [x] `session-review-teacher-worksheet-reject` 워크시트 반려 버튼 — 같은 조건에서 worksheet_status=rejected를 저장하며 저장 중에는 세 결정 버튼이 모두 비활성화된다 · 검증: 신규 spec 필요
|
||
- [x] `session-review-eval-scope-notice` AI 평가 범위 안내 박스 — fast-loop/deep-loop 구현 범위와 임상팀 확정 필요 항목을 정적으로 안내한다 · 검증: 기존 e2e/session-review.spec.ts
|
||
- [x] `session-review-head-meta` 회기 헤더·상태 스탯 표시 — 내담자·날짜·소요시간·페르소나와 화면 배지, SESSION/SUPERVISOR 상태와 세션 ID를 표시한다 · 검증: 기존(부분) e2e/session-review.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
|
||
**의심 결함(에이전트 리포트)**:
|
||
|
||
- `session-review-error-state`: 오류 화면에 재시도/뒤로가기 액션이 없어 새로고침 외 복구 수단이 없다.
|
||
- `session-review-teacher-auto-redirect`: 403 detail 문자열('session does not belong to user') 완전 일치에 의존해 백엔드 문구가 바뀌면 리다이렉트가 조용히 깨진다.
|
||
- `session-review-ready-polling`: 60회 한도 도달 시 아무 안내 없이 폴링이 멈춰 사용자는 '대기' 표시가 영구 상태인지 알 수 없다. 또한 폴링마다 setData로 워크시트 초안 상태가 리셋되어 입력 중이던 학습자 텍스트가 날아갈 수 있다.
|
||
- `session-review-tabs`: role=tab을 쓰지만 화살표 키 이동·aria-controls·tabpanel 연결이 없어 ARIA 탭 패턴 접근성이 불완전하다.
|
||
- `session-review-btn-retry-evaluation`: displayEvaluationRetryError가 실제 오류 detail을 버리고 항상 동일한 일반 문구만 보여줘 실패 원인 파악이 불가능하다. 노출 조건이 '평가 실패'·'종료됨' 같은 한국어 표시 문자열 일치에 결합돼 있어 깨지기 쉽다.
|
||
- `session-review-btn-share`: clipboard.writeText 실패 시에도 catch에서 'copied' 상태로 표시해 실제 복사 실패를 숨긴다. api에 있는 공유 해지(DELETE /share)는 UI에 노출되지 않아 만든 링크를 화면에서 되돌릴 수 없다. 활성 조건이 표시 문자열 '종료됨' 일치에 의존한다.
|
||
- `session-review-share-note`: 공유 URL이 일반 텍스트로만 표시되고 앵커 링크나 재복사 버튼이 없다.
|
||
- `session-review-turn-jump`: 필터 해제 직후 requestAnimationFrame 1회로 scrollIntoView를 호출해 React 리렌더 전이면 대상 ref가 아직 없어 스크롤이 무시될 수 있는 경합이 있다.
|
||
- `session-review-transcript-display`: 비언어 칩의 상세 내용이 title 속성 툴팁에 의존해 키보드·터치 사용자에게 전달되지 않는다.
|
||
- `session-review-worksheet-edit`: worksheet prop이 바뀔 때마다 초안·dirty가 무조건 리셋되므로 백그라운드 폴링/재로딩과 겹치면 저장 전 입력이 소실된다. 이탈 시 미저장 경고(beforeunload/라우트 블록)도 없다.
|
||
- `session-review-worksheet-save`: 저장 실패 시 '워크시트를 저장하지 못했습니다' 고정 문구만 표시하고 서버 오류 상세를 버린다.
|
||
- `session-review-worksheet-evidence-jump`: evidence 배열의 첫 항목만 노출되어 두 번째 이후 근거는 접근 불가다.
|
||
- `session-review-prepost-input`: 저장된 값을 비우는 것은 영구히 불가능하며(빈칸이 invalid 처리), invalid 칸이 하나라도 있으면 다른 유효한 변경까지 통째로 저장이 막힌다.
|
||
- `session-review-prepost-save`: 키별 순차 PUT 중 하나가 실패하면 일부만 저장된 채 일반 오류 문구만 표시되고 어떤 항목이 저장됐는지 재동기화되지 않는다.
|
||
- `session-review-teacher-save-viewed`: 이미 closed인 검토에 메모 저장을 누르면 status가 viewed로 덮여 검토 완료 상태가 되돌려질 수 있다(닫힘 여부를 보존하지 않음).
|
||
- `session-review-teacher-close`: 한 번 closed로 저장하면 화면에서 다시 여는(viewed로 되돌리는) 명시적 수단이 없다(메모 저장 부작용으로만 가능).
|
||
- `session-review-teacher-worksheet-note`: 이 textarea만 name·autoComplete 속성이 없어 다른 입력과 마크업 일관성이 없다.
|
||
- `session-review-teacher-worksheet-reject`: 승인/수정요청/반려에 확인 다이얼로그가 없어 오클릭 한 번으로 결정이 즉시 저장된다.
|
||
|
||
## 5. 교수자 콘솔 (professor)
|
||
|
||
- [x] `professor-guard-require-auth-teacher` RequireAuth(teacher) 라우트 가드 — 미인증은 /login, teacher 권한이 없으면 자기 역할 홈으로 리다이렉트한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `professor-guard-pending-approval` PendingApprovalGate 리다이렉트 — 미승인 계정이 /teach 계열에 오면 /pending으로 보내고 승인 계정이 /pending에 오면 되돌린다 · 검증: 신규 spec 필요
|
||
- [x] `professor-guard-onboarding` OnboardingGate 리다이렉트 — 온보딩 미완료 사용자가 /teach 계열에 오면 /onboarding으로 보낸다 · 검증: 신규 spec 필요
|
||
- [x] `professor-dashboard-initial-load` 교수자 대시보드 초기 로드 — 검토 대기·최근 세션·안전 알림·학습자 성장 데이터를 불러와 로딩/오류/갱신 시각을 관리한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `professor-dashboard-error-banner` 대시보드 오류 배너 — 로드 실패 시 role=alert 배너에 오류 메시지를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `professor-persona-review-initial-load` 페르소나 검수 큐 초기 로드 — 검수 대기 페르소나를 불러오며 404는 빈 큐로, 5xx만 오류 카드로 처리한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `professor-header-refresh` 새로고침 버튼 — 대시보드와 뷰별 데이터(검수 큐 또는 학습자 분석)를 함께 재조회하고 진행 중에는 비활성화된다 · 검증: 신규 spec 필요
|
||
- [x] `professor-open-first-pending-review` 첫 검토 열기 버튼 — 검토 대기가 있을 때만 헤더에 노출되어 첫 번째 회기의 교수자 리뷰로 이동한다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `professor-nav-to-analysis` 학생 분석 이동 버튼 — 콘솔 헤더에서 /teach/analysis로 이동한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `professor-nav-to-console` 콘솔로 이동 버튼 — 분석 뷰 헤더에서 /teach 콘솔로 되돌아간다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `professor-triage-status-strip` 검토 큐 상태 스트립 — 코호트 라벨·마지막 갱신 시각·리뷰 대기/누적 회기 수를 role=status로 표시한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `professor-kpi-cards` KPI 카드 6종 — 검토 대기·위기 알림·페르소나 검수·최근 세션·전체 학생·활성 세션 수를 표시 전용 카드로 요약한다 · 검증: 신규 spec 필요
|
||
- [x] `professor-pending-review-list` 검토 대기 회기 목록 — 종료됐지만 닫지 않은 회기를 행 버튼으로 나열하고 클릭 시 교수자 리뷰로 이동한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `professor-safety-alert-list` 위기 알림(109) 목록 — safety_alerts를 학습자·페르소나·위험도·발생시각·안내 자원과 함께 나열한다 · 검증: 기존 e2e/session-persistence.spec.ts
|
||
- [x] `professor-persona-review-approve` 페르소나 검수 승인 버튼 — review 상태 페르소나에만 노출되어 approve 결정을 저장하고 결과에 따라 행 갱신 또는 큐 제거를 한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `professor-persona-review-open-studio` 스튜디오에서 검수 버튼 — `/teach/personas?draft={id}`로 이동해 스튜디오에서 상세 검수를 잇는다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `professor-persona-review-error-retry` 검수 큐 오류 카드 + 다시 시도 — 로드·결정 실패 시 role=alert 카드와 재조회 버튼을 제공한다 · 검증: 신규 spec 필요
|
||
- [x] `professor-persona-review-empty-loading` 검수 큐 로딩/빈 상태 — 로딩 중 '검수 큐 확인 중', 비면 '검수 대기 페르소나 없음'을 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `professor-open-persona-studio` 페르소나 스튜디오 열기 버튼 — 콘텐츠 저작실 카드에서 초안 건수 메타와 함께 /teach/personas로 이동한다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `professor-recent-session-table` 최근 회기 기록 테이블 — 최근 세션을 행 버튼으로 나열하고 종료 여부에 따라 상세 리뷰/진행 기록 라벨로 리뷰 화면에 진입시킨다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `professor-analysis-learner-search` 학습자 검색 입력 — 학습자 라벨·ID·추이·기법 태그를 합친 문자열에 부분 일치로 실시간 필터링한다 · 검증: 기존 e2e/teacher.spec.ts · 베이스라인 215/215 GREEN
|
||
- [x] `professor-analysis-sort-segment` 학습자 정렬 세그먼트 (최근순/회기순/점수순/변화순) — 네 기준 중 하나로 학습자 목록을 재정렬한다 · 검증: 신규 spec 필요
|
||
- [x] `professor-analysis-table-states` 학습자 테이블 로딩/빈/검색결과없음 상태 — 데이터 없음·로딩·검색 결과 없음을 각각 다른 문구로 구분한다 · 검증: 신규 spec 필요
|
||
- [x] `professor-analysis-row-expand` 학습자 행 펼침 토글 — aria-expanded 버튼으로 회기별 스파크바·점수 변화·기법 태그 요약을 한 행씩 펼친다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `professor-analysis-open-learner-detail` 학습자 상세 진입 (이름 버튼 · 상세 보기 버튼) — `?learner={id}` 쿼리를 설정해 드릴다운 화면으로 전환한다(URL 공유·뒤로가기 가능) · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `professor-analysis-detail-load` 학습자 상세 분석 로드 — learner 파라미터 변경마다 상세를 조회하고 로딩·오류·미선택 상태를 구분하며 낡은 응답을 무시한다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `professor-analysis-back-to-list` 전체 목록 복귀 버튼 — learner 쿼리를 지워 검색 테이블로 돌아간다 · 검증: 신규 spec 필요
|
||
- [x] `professor-analysis-invalid-learner-redirect` 존재하지 않는 학습자 파라미터 자동 복귀 — learner_growth에 없는 ID면 쿼리를 지워 전체 목록으로 되돌린다 · 검증: 신규 spec 필요
|
||
- [x] `professor-analysis-depth-strip` 분석 깊이 표시 스트립 — 현재 드릴다운 깊이(1 목록 → 2 상세 → 3 리뷰)를 표시 전용으로 안내한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `professor-analysis-summary-metrics` 학습자 상세 요약 메트릭 — 전체 회기·완료/진행·검토 대기·최근 적절성·변화·평균 라포 6개 지표를 상단에 요약한다 · 검증: 기존(부분) e2e/layout-visual-gate.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `professor-analysis-tabs` 상세 분석 탭 (페르소나별 회기/추이/전체 회기/단계 분석) — 4개 탭으로 콘텐츠를 전환하고 각 탭에 건수 배지를 표시한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `professor-analysis-persona-group-drill` 페르소나별 회기 그룹 아코디언 — 페르소나 요약 그룹 버튼을 눌러 그룹 내 회기 목록을 한 번에 하나씩 펼친다 · 검증: 기존 e2e/layout-visual-gate.spec.ts
|
||
- [x] `professor-analysis-session-row-open` 회기 행 열기 (페르소나 탭·전체 회기 탭 공용) — 회기 요약 행 버튼 클릭 시 교수자 리뷰 화면으로 이동한다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `professor-analysis-trend-chart` 추이 탭 회기별 막대 차트 — 회기별 점수를 막대로 그리고 title 툴팁에 페르소나·회기·점수를 담는다 · 검증: 신규 spec 필요
|
||
- [x] `professor-analysis-stage-breakdown` 단계 분석 탭 — 상담 단계별 회기 수와 턴 수를 카드 목록으로 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `professor-analysis-list-reuses-dashboard` 학습자 목록 데이터 소스 — 분석 뷰 검색 테이블이 별도 API 없이 teacher/dashboard의 learner_growth를 재사용한다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
|
||
**의심 결함(에이전트 리포트)**:
|
||
|
||
- `professor-dashboard-error-banner`: 배너 자체에 재시도 버튼이 없음 — 헤더의 새로고침 버튼까지 시선 이동 필요. 오류 상태에서도 아래 큐 섹션들이 빈 상태 문구로 그대로 렌더되어 '데이터 없음'과 '로드 실패'가 혼동될 수 있음.
|
||
- `professor-kpi-cards`: KPI 카드가 해당 섹션으로 스크롤/이동하는 링크가 아니어서 숫자만 보이는 죽은 UI — 특히 '위기 알림' 같은 긴급 지표도 클릭 동작이 없음.
|
||
- `professor-safety-alert-list`: 표시 전용이라 알림 확인(acknowledge)·해결 처리 액션이 전혀 없고, session_id를 보여주면서도 해당 회기 리뷰로 이동하는 링크가 없어 위기 대응 동선이 끊김.
|
||
- `professor-persona-review-approve`: 승인 실패 시 setPersonaReviewError로 패널 전체가 에러 카드로 대체되어 검수 목록이 통째로 사라짐(단건 실패가 전역 오류로 승격). 또한 busy 비교가 정확히 '해당 persona:action'만이라 다른 행의 승인 버튼은 여전히 눌러져 동시 다발 요청 가능. 확인(confirm) 단계 없이 즉시 승인됨.
|
||
- `professor-recent-session-table`: 테이블이 div+button 구조이고 헤더 행이 aria-hidden이라 스크린리더는 열 제목 없이 셀 텍스트만 듣게 됨 (data-label 속성은 시각용). 진짜 table/grid 시맨틱 부재.
|
||
- `professor-analysis-sort-segment`: 활성 표시가 CSS 클래스(is-active)뿐이고 aria-pressed/aria-current가 없어 보조기기에서 현재 정렬 기준을 알 수 없음.
|
||
- `professor-analysis-detail-load`: 상세 로드 오류 카드에 재시도 버튼이 없음 — 헤더 새로고침으로만 복구 가능.
|
||
- `professor-analysis-invalid-learner-redirect`: learner_growth가 아직 로드되지 않은 짧은 순간에는 판정을 보류하지만, 대시보드 로드가 실패하면 learnerGrowth가 빈 배열로 남아 유효한 딥링크도 상세 제목이 '학습자 이력' 폴백으로 표시됨.
|
||
- `professor-analysis-depth-strip`: nav 요소지만 각 단계가 클릭 불가한 span이라 브레드크럼처럼 보이면서 동작하지 않음 — 1단계 클릭으로 목록 복귀를 기대하는 사용자에게 혼란.
|
||
- `professor-analysis-tabs`: role=tab/aria-selected는 있으나 tabpanel 연결(aria-controls/id)과 화살표 키 로빙 탭인덱스가 없어 WAI-ARIA 탭 패턴 미완성.
|
||
- `professor-analysis-trend-chart`: 차트 정보가 title 속성 툴팁에만 있어 키보드/터치/스크린리더로는 개별 막대 값을 알 수 없음.
|
||
- `professor-analysis-stage-breakdown`: 다른 탭과 달리 stage_breakdown이 빈 배열일 때 EmptyState가 없어 제목만 있고 내용이 없는 화면이 됨.
|
||
|
||
## 6. 페르소나 스튜디오 (persona-studio)
|
||
|
||
- [x] `persona-studio-guard-require-auth` RequireAuth 라우트 가드 (teacher/admin) — 미인증은 /login, teacher/admin이 아니면 자기 역할 홈으로 보낸다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-guard-pending-approval` PendingApprovalGate 가드 — 미승인 사용자는 /pending으로 리다이렉트한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-guard-onboarding` OnboardingGate 가드 — 온보딩 미완료 사용자는 /onboarding으로 리다이렉트한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-initial-load` 초기 데이터 로드 (카탈로그·검수 큐·교수 대시보드) — 3개 API를 병렬 호출하며 카탈로그 실패만 전체 오류, 검수 큐 404는 빈 목록, 대시보드 실패는 경고로 처리한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-load-error-banner` 로드 오류 배너 — 카탈로그 로드 실패 시 role=alert 섹션에 오류 메시지를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-dashboard-degraded-note` 학습 지표 실패 시 부분 동작 안내 — 대시보드 호출 실패 시 경고 노트만 띄우고 카탈로그·저작 기능은 계속 쓰게 한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-status-message-line` 폼 오류/성공 메시지 라인 — formError가 있으면 role=alert 오류를, 없으면 성공/안내 문장을 헤더 아래에 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-refresh-button` 새로고침 버튼 — 카탈로그·검수 큐·대시보드를 다시 호출하며 로딩·busy 중에는 비활성화된다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-workspace-tabs` 워크스페이스 탭 (대시보드/카탈로그/페르소나) — view 쿼리 기반으로 탭을 전환하며 나머지 쿼리 파라미터를 모두 제거한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-create-open` 새로운 페르소나 만들기 버튼 — 초안 상태를 초기화하고 localStorage 임시본이 있으면 복원 메시지와 함께 되살린 뒤 작성 단계로 이동한다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-dash-review-more` 검수 현황 더보기 버튼 — `view=personas&queue=review`로 이동해 검수 대기 목록을 연다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-dash-usage-row` 페르소나별 학습 현황 행 클릭 — 공개 페르소나 상위 8개 행을 클릭하면 승인본 상세로 이동한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-dash-usage-empty` 공개 페르소나 없음 빈 상태 — 카탈로그가 비면 '공개 페르소나 없음' 빈 상태를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-catalog-view-all` 전체 페르소나 보기 버튼 — 카탈로그 화면에서 `view=personas` 목록으로 이동한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-catalog-row` 공개본 상태 목록 행 클릭 — 공개 페르소나 행을 클릭하면 승인본 상세로 이동한다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `persona-studio-catalog-empty-distribution` 이론 분포 빈 상태 — 공개 페르소나가 없으면 이론 분포 대신 '분포 자료 없음'을 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-list-subtabs` 목록 서브탭 (전체 페르소나/검수 현황) — queue 파라미터를 all/review로 바꾸고 열린 상세를 닫으며 건수를 표시한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-list-search` 페르소나 검색 입력 — 코드·이름·이론·상태 라벨 문자열에 ko-KR 소문자 부분일치로 필터링한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-list-origin-filter` 구분 필터 셀렉트 (전체/시스템/새로 만든) — P1~P11·seed 출처는 시스템, 나머지는 커스텀으로 분류해 필터링한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-list-row-open-detail` 목록 행 식별자/상세 버튼 — 행의 코드·이름 또는 상세 버튼으로 `persona={key}` 상세 화면을 연다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-list-approved-revise` 공개본 수정 버튼 (새 버전 초안 생성) — 승인본에서 revision 초안을 만들어 편집기로 불러오고 승인 전까지 공개본을 유지한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-list-approved-archive` 공개본 삭제(보관) 버튼 — confirm 후 DELETE로 보관 처리하고 같은 대상 편집 중이면 상태를 초기화한 뒤 목록을 새로고침한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-list-draft-edit` 초안 행 수정 버튼 — `mode=edit&draft={id}`로 이동해 초안 상세를 편집 폼에 자동 로드한다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-list-empty` 목록 필터 결과 빈 상태 — 검색·필터 결과가 없으면 '조건에 맞는 페르소나 없음'을 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-review-card-detail` 검수 카드 상세 버튼 — `persona=draft:{id}`로 이동해 해당 초안 상세를 연다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-review-card-edit` 검수 카드 수정 버튼 — 해당 초안을 mode=edit 편집기로 연다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-review-card-approve` 검수 카드 승인 버튼 — approve 결정으로 공개본으로 승격하고 편집 상태를 초기화한 뒤 목록을 새로고침한다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-review-card-reject` 검수 카드 반려 버튼 — reject 결정을 저장하며 status가 review가 아니거나 busy면 비활성화된다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-review-empty` 검수 대기 없음 빈 상태 — review/draft 항목이 없으면 '검수 대기 없음'을 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-detail-back` 상세 → 목록으로 버튼 — persona·detailTab 쿼리를 제거해 목록으로 돌아간다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-detail-tabs` 상세 서브탭 (소개·정보/학습 현황/설정 내용) — detailTab 쿼리로 상세 화면 3개 탭을 전환한다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-detail-draft-fetch` 초안 상세 자동 조회 — persona 키가 draft:면 초안 상세를 조회해 주호소·핵심 신념·민감 영역·출처를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-detail-revise-button` 상세 헤더 수정 버튼 — 승인본이면 revision 초안을 만들어, 초안이면 바로 편집기로 이동한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-detail-learning-empty` 학습 기록 없음 빈 상태 — 평가된 회기 궤적이 없으면 빈 상태를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-detail-notfound` 상세 대상 미존재 빈 상태 — persona 키가 목록에 없으면 '페르소나를 찾지 못했습니다'를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-author-stepper` 저작 4단계 스테퍼 (자료/초안/설정/검토) — step 쿼리로 단계를 이동하며 검토 단계 진입 시 프롬프트 미리보기로 자동 전환한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-author-back-to-list` 저작 화면 목록으로 버튼 — `view=personas`로 돌아가 저작 모드를 종료하며 busy 중에는 비활성화된다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-author-rail-draft-load` 좌측 레일 초안 목록 클릭 로드 — 검수 큐 초안을 클릭하면 상세를 불러와 현재 편집 폼을 교체한다 · 검증: 신규 spec 필요 · 현행 설계 특성화 GREEN(저작 모드 레일 숨김 — 결함 로그 #14 소유자 확인)
|
||
- [x] `persona-studio-author-rail-approved-actions` 좌측 레일 공개본 수정/삭제 버튼 — 공개본별로 revision 초안 생성 또는 confirm 후 보관 처리를 수행한다 · 검증: 신규 spec 필요 · 현행 설계 특성화 GREEN(저작 모드 레일 숨김 — 결함 로그 #14 소유자 확인)
|
||
- [x] `persona-studio-author-empty-states` 저작 레일/인스펙터 빈 상태 — 초안·공개본·결정 대상이 없을 때 각각의 빈 문구를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-source-dropzone` 자료 파일 드래그&드롭 업로드 — 드롭된 첫 파일만 처리해 엑셀은 서버 변환, 텍스트는 브라우저에서 읽어 본문에 채운다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-source-file-picker` 파일 선택 버튼 + 숨김 file input — 엑셀은 multipart 업로드로 표→텍스트 변환·KB 등록하고 그 외는 본문에 읽어 넣는다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-source-kind-select` 자료 종류 셀렉트 — client_record/textbook_guide/mixed_notes 중 근거 자료 종류를 선택해 요청에 함께 보낸다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-source-name-input` 파일/자료명 입력 — 등록될 근거 문서의 파일명·제목으로 쓰이며 비우면 기본값이 적용된다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-generation-goal-input` 생성 목표 입력 — 초안 생성 요청의 generation_goal과 근거 문서 source_note로 전달된다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-source-text-area` 자료 본문 붙여넣기 textarea — 내담자 기록·교재 기준을 붙여넣으면 생성 시 KB 근거 문서로 먼저 등록된다(20자 이상) · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-generate-draft` KB 등록 후 생성 버튼 — 붙여넣은 텍스트를 근거 문서로 등록한 뒤 RAG 초안 생성을 호출하고 결과·마스킹·근거 청크를 인스펙터에 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-studio-tabs` 저작 섹션 탭 7종 (개요/임상/저항/회기/말투/안전/프롬프트) — role=tablist로 편집 섹션을 전환하며 섹션별 작성 가이드를 함께 보여준다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-field-code` 코드 입력 (자동 제안·중복 검사) — 대문자로 정규화하고 비면 다음 P{n}을 제안하며 카탈로그·검수 큐와 중복이면 검증 오류를 낸다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-field-display-name` 표시 이름 입력 — 표시 이름을 입력하며 비면 저장·검수 요청 모두 검증 오류가 된다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-field-difficulty` 난이도 셀렉트 (easy/moderate/hard) — 페르소나 난이도를 선택한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-field-synthetic` 합성 여부 셀렉트 (synthetic/clinical source) — 합성 초안인지 실제 임상 근거 기반인지 is_synthetic 플래그를 설정한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-theory-toggle` 대상 이론 토글 (humanistic/cbt/integrative) — 세그먼트 버튼으로 이론을 다중 선택·해제하며 마지막 하나를 해제하면 humanistic으로 되돌린다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-fields-demographics` 인구통계 입력 4종 (연령대/성별·젠더/역할·학년/맥락) — demographics 객체의 네 키를 자유 텍스트로 편집한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-fields-presenting` 주호소·첫 회기 입장 발화 textarea — presenting.complaint와 first_session_opening을 편집하며 주호소는 검수 요청 시 필수다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-field-provenance` 출처(source_provenance) 입력 — 작성 근거·출처를 기록하며 비면 경고로 표시된다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-fields-clinical` 임상 탭 입력 (가족/학교·직장/관계/촉발 사건/강점 + CCD 5종 + 증상 메모) — history 5개와 CCD·dsm5 메모를 편집하며 핵심신념은 검수 요청 시 필수다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-fields-resistance-numbers` 저항 탭 숫자 입력 16종 (저항 5·Big5 5·정서 기저선 5·자살사고 단계) — 0~1 파라미터와 자살사고 단계를 number 입력으로 편집한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-fields-scenario` 회기 탭 입력 (회기별 시나리오 리스트/표면화 조건/추가 프롬프트 계약) — session_scenarios 리스트와 surface·prompt_contract 장문을 편집한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-fields-speech` 말투 탭 입력 (어조/문장 길이/존댓말/군말·말버릇·비언어 단서) — speech_style의 셀렉트와 세 리스트를 편집한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-fields-safety` 안전 탭 입력 (역린 민감 영역/상담자 금기/역린 반응/내담자 금기어) — triggers의 리스트와 reaction 장문을 편집하며 sore_spots는 검수 요청 시 필수다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-listfield-add-remove` 리스트 필드 공통 항목 추가/삭제 — 모든 ListField에서 빈 행 추가와 X 버튼 삭제를 제공하고 저장 시 빈 항목을 거른다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-prompt-preview` 프롬프트 미리보기 패널 (읽기 전용) — 구조화 데이터를 8개 섹션 런타임 계약으로 렌더하고 빈 섹션은 '작성된 항목 없음'으로 표시한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-author-prev-next` 이전/다음 단계 버튼 — step 쿼리를 앞뒤로 옮기며 마지막 단계에서는 검수 요청 버튼으로 대체된다 · 검증: 기존(부분) e2e/teacher.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `persona-studio-save-progress` 중간 저장 버튼 — 작성 내용을 localStorage에 항상 저장하고 최소 검증을 통과하면 서버 초안으로도 생성·갱신한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-submit-review` 검수 요청 버튼 — 전체 검증 통과 시 submit_for_review로 저장해 상태를 review로 올리고 localStorage 임시본을 삭제한다 · 검증: 기존 e2e/teacher.spec.ts
|
||
- [x] `persona-studio-inspector-validation` 인스펙터 검증 체크리스트 — 필수 오류·경고를 실시간으로 나열하고 모두 통과하면 완료 배지를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-inspector-evidence` 인스펙터 생성 근거 패널 — 생성 요약·PII 마스킹·경고·등록 근거 문서·상위 3개 근거 청크를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-inspector-review-actions` 인스펙터 검수 큐 편집/반려/승인 버튼 — 저작 화면 우측에서 초안을 편집기로 로드하거나 즉시 승인·반려 결정을 보낸다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-draft-autoload-param` `?draft=` 파라미터 초안 자동 로드 — draft 파라미터로 진입하면 로드 완료 후 해당 초안을 한 번 자동으로 편집 폼에 채운다 · 검증: 신규 spec 필요
|
||
- [x] `persona-studio-loading-busy-states` busy 상태별 버튼 라벨/비활성화 — load/save/submit/decide/generate/archive 작업 중 관련 버튼을 진행 라벨로 바꾸고 비활성화한다 · 검증: 신규 spec 필요
|
||
|
||
**의심 결함(에이전트 리포트)**:
|
||
|
||
- `persona-studio-load-error-banner`: 오류 배너에 재시도 버튼이 없어 헤더의 새로고침 버튼을 찾아야 재시도 가능
|
||
- `persona-studio-status-message-line`: formError가 message를 항상 가리므로 직전 성공 안내가 오류 발생 시 소실됨
|
||
- `persona-studio-workspace-tabs`: 저작(mode=create/edit) 중 탭 클릭 시 확인 없이 편집 화면을 이탈해 미저장 서버 반영분이 사라질 수 있음(localStorage 임시본만 남음)
|
||
- `persona-studio-create-open`: 복원된 임시본은 검수 요청 성공 때만 삭제되므로 오래된 초안이 새 작성 세션에 계속 되살아날 수 있음
|
||
- `persona-studio-dash-usage-row`: role=table/row 구조인데 행 전체가 button이고 cell 역할이 없어 스크린리더 표 탐색이 어긋남
|
||
- `persona-studio-list-origin-filter`: 검색어·필터가 쿼리스트링에 저장되지 않아 상세 진입 후 돌아오면 초기화됨
|
||
- `persona-studio-list-approved-revise`: persona_id가 없는 시드 공개본은 버튼이 disabled이나 이유 툴팁이 없어 사용자가 원인을 알 수 없음
|
||
- `persona-studio-list-approved-archive`: 네이티브 window.confirm 사용으로 앱 디자인·접근성과 불일치하고 E2E에서 다이얼로그 처리가 필요
|
||
- `persona-studio-detail-draft-fetch`: 조회 실패를 catch에서 조용히 무시(null 처리)해 사용자는 작성 정보 섹션이 왜 안 보이는지 알 수 없음
|
||
- `persona-studio-detail-notfound`: 빈 상태에 목록으로 돌아가는 버튼이 없어 사용자가 직접 URL/탭을 조작해야 함
|
||
- `persona-studio-author-stepper`: 단계 이동에 완료 조건 검증이 없어 자료 없이도 검토 단계로 건너뛸 수 있음(의도된 자유 이동일 수 있음)
|
||
- `persona-studio-author-back-to-list`: 미저장 변경이 있어도 확인 없이 이탈함(localStorage 임시본은 중간 저장을 눌렀을 때만 존재)
|
||
- `persona-studio-author-rail-draft-load`: 현재 작성 중이던 내용을 확인 없이 덮어씀
|
||
- `persona-studio-source-dropzone`: 여러 파일을 드롭해도 첫 파일만 조용히 처리되고 나머지는 무시됨
|
||
- `persona-studio-source-file-picker`: accept에 .xls가 빠져 있는데 코드 분기는 .xls도 처리함(파일 선택 대화상자에서 .xls가 걸러짐); 텍스트 분기는 확장자 검증 없이 아무 파일이나 text()로 읽음
|
||
- `persona-studio-theory-toggle`: 마지막 항목 해제 시 조용히 humanistic으로 바뀌어 사용자가 의도치 않은 값을 가질 수 있음(안내 없음)
|
||
- `persona-studio-fields-resistance-numbers`: min/max가 HTML 속성뿐이라 직접 타이핑하면 범위 밖 값(예: 7, -3)이 상태에 그대로 저장되고 JS 클램핑·검증이 없음
|
||
- `persona-studio-generate-draft`: 재클릭 시 같은 붙여넣기 텍스트가 매번 새 근거 문서로 중복 등록됨; 생성 성공 시 기존 편집 내용을 확인 없이 덮어씀
|
||
- `persona-studio-save-progress`: localStorage에는 sourceText 등 원문 자료가 평문 저장됨(내담자 실제 기록일 경우 브라우저에 PII 잔존)
|
||
- `persona-studio-inspector-review-actions`: 검수 보드와 달리 status!=='review'(작성 중 draft)여도 승인/반려 버튼이 활성화되어 UI 가드가 불일치함(서버 거부에 의존)
|
||
- `persona-studio-draft-autoload-param`: Professor 페이지는 mode 없이 `?draft=`만 붙여 이동하는데 자동 로드는 isAuthoring(mode=create/edit)일 때만 동작해 해당 진입 경로에서 초안이 로드되지 않음
|
||
|
||
## 7. 관리자 콘솔 (admin)
|
||
|
||
- [x] `admin-guard-require-auth` RequireAuth admin 가드 — 미인증은 /login, admin·superAdmin·adminAccess가 없으면 자기 역할 홈으로 리다이렉트한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-guard-pending-approval` PendingApprovalGate 승인 대기 가드 — 미승인 사용자가 /admin 계열에 오면 /pending으로 보내고 승인 사용자가 /pending에 있으면 되돌린다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-guard-onboarding-bypass` OnboardingGate admin 우회 — 온보딩 미완료여도 admin 접근 권한이 있으면 /admin 경로는 그대로 통과시킨다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-error-boundary` AdminErrorBoundary 렌더 예외 진단 — 렌더 예외 시 빈 화면 대신 section·path·error·componentStack 진단 패널을 띄우고 섹션 변경 시 리셋한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-blank-content-probe` 빈 본문 감지 프로브 — 마운트 800ms 후 본문 텍스트·높이·가시 노드를 검사해 비어 있으면 진단 패널을 표시한다 · 검증: 기존 e2e/public-admin-visual.spec.ts
|
||
- [x] `admin-data-diagnostics-panel` 관리자 데이터 계약 진단 패널 — users/tickets 응답 정규화 중 생긴 경고를 최대 8건까지 나열하고 초과분은 개수로 요약한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-unknown-section-panel` 알 수 없는 섹션 폴백 패널 — 정의되지 않은 섹션이 전달되면 섹션·경로·asset 진단 패널을 표시한다 · 검증: 신규 spec 필요 · 도달 불가 방어 코드(라우터가 섹션을 하드코딩, 미정의 경로는 루트 회수) — E2E 불가, 코드 확인으로 종결
|
||
- [x] `admin-overview-refresh-button` 운영 홈 새로고침 버튼 — 헬스·사용자·사용량·업타임·티켓 5개 API를 병렬 재조회하고 로딩 중 비활성화한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-overview-status-banner` 서비스 상태 배너 — health 상태에 따라 색상·문구를 바꾸고 환경·엔진 모드·갱신 시각을 role=status로 표시한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-overview-kpi-cards` 운영 요약 KPI 4종 — 활성 회기·최근 15분 온라인 사용자·등록 사용자 수·헬스 ok/total을 카드로 표시한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-overview-flow-panel` 실시간 교육 흐름 패널 — 학습자 회기 수·온라인 교수자/관리자 수·최근 7일 AI 계량 턴 수를 표시한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-overview-availability-panel` 가용성 패널 — 현재 헬스, 24시간 샘플 정상률(샘플 없음/미연결 구분), 최근 중단 시각을 표시한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-overview-cost-panel` AI 비용 패널 — 7일 비용·예산 상태·사용률 바·평가 캐시 hit-rate·일별 비용 추이를 표시한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-overview-ticket-mini-panel` 운영 티켓 미니 패널 — 미해결·높은 우선순위·24시간 정체 요약과 상위 활성 티켓 2건을 표시한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-overview-services-list` 서비스 리소스 목록 — health.services를 상태 Dot·Badge·detail·load 바로 렌더하고 로딩 스켈레톤과 빈 문구를 갖는다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-overview-health-error` 헬스 조회 실패 InlineError — health 호출 실패 시 오류 메시지를 role=alert 섹션으로 표시한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-users-tabs` 사용자 관리 탭바(승인/목록/등록/활동) — 대기 건수를 표시한 4개 탭을 role=tablist + aria-selected로 전환한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-users-approval-queue` 가입 승인 대기 큐 — pending 사용자를 접수일 내림차순으로 나열하고 집계 배지·스켈레톤·빈 상태를 제공한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-users-approve-button` 가입 승인 버튼 — 대기 사용자의 account_status를 approved로 PATCH하고 목록·드래프트를 갱신한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-users-suspend-button` 가입 보류 버튼 — 대기 사용자의 account_status를 suspended로 PATCH해 보류 처리한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-users-readonly-guard` DB 미연결 읽기 전용 경고 — durable이 false면 경고를 띄우고 승인·등록·편집·저장·비활성화 등 쓰기 UI를 모두 비활성화한다 · 검증: 기존(부분) e2e/readiness.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-users-search-input` 사용자 검색 입력 — 이메일·이름·역할·권한·상태·소속·코호트 문자열에 부분 일치로 필터링하고 카운트를 표시한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-users-table-sort` 사용자 표 컬럼 정렬 — TanStack Table로 8개 헤더를 클릭 정렬(기본 last_seen_at 내림차순)하고 aria-sort를 갱신한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-users-table-scroll-region` 사용자 표 가로 스크롤 영역 — 작은 화면에서 표를 tabIndex=0, role=region 가로 스크롤 컨테이너로 감싼다 · 검증: 기존 e2e/layout-visual-gate.spec.ts + e2e/admin.spec.ts
|
||
- [x] `admin-users-row-cap` 표 40행 렌더 제한 안내 — 상위 40행만 렌더하고 초과분은 검색으로 좁히라는 안내문을 표시한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-users-edit-name-input` 행 내 표시 이름 편집 — 각 행의 표시 이름을 드래프트로 수정하며 DB 미연결·저장 중에는 비활성화한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-users-edit-role-select` 행 내 역할 셀렉트 — 역할을 드래프트로 변경하되 관리자 옵션은 superAdmin만 선택 가능하다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-users-admin-access-toggle` 관리자 페이지 권한 체크박스 — admin_access를 토글하며 superAdmin이 아니거나 대상이 super_admin이면 비활성화한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-users-status-select` 행 내 승인 상태 셀렉트 — 승인 대기/승인됨/보류를 드래프트로 바꾸고 현재 서버 값은 옆 배지로 구분한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-users-affiliation-input` 행 내 소속 편집 — 소속 문자열을 드래프트로 수정한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-users-cohort-input` 행 내 코호트 편집 — 콤마 구분 문자열을 trim·빈값 제거해 cohort_ids 배열로 반영한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-users-save-button` 행 저장 버튼 — 드래프트가 서버 값과 다를 때만 활성화되어 PATCH하고 응답으로 로컬 상태를 교체한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-users-deactivate-button` 사용자 비활성화 버튼 — DELETE 후 목록·드래프트에서 즉시 제거하며 처리 중 라벨로 중복 클릭을 막는다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-users-register-form` 새 사용자 등록 폼 — 이메일·이름·역할·권한·상태·코호트·소속을 POST하고 성공 시 폼 초기화 후 목록 탭으로 이동한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-users-activity-tab` 활동 요약 탭 — 역할 분포를 ProgressBar로, last_seen 상위 8명의 최근 활동을 표로 표시한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-users-states` 사용자 로딩/빈/오류 상태 — 스켈레톤, InlineError와 재시도 안내, 검색 0건·등록 0건 문구를 구분해 표시한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-access-tabs` 접근 권한 탭바(역할/그룹/매트릭스) — 3개 탭을 role=tablist로 전환한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `admin-access-roles-cards` 역할 정책 카드 — 관리자/교수자/학습자 3개 역할의 범위·권한 칩·위험 문구를 하드코딩 상수로 표시한다 · 검증: 기존(부분) e2e/public-admin-visual.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `admin-access-groups-cards` 그룹 정책 카드 — 운영자/학과 관리자/슈퍼바이저 그룹의 범위와 접근 칩을 '정책 초안' 배지와 함께 표시한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-access-matrix-table` 권한 매트릭스 표 — 리소스별 역할 접근 수준을 정적 5행 표로 표시한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-tickets-refresh-button` 티켓 새로고침 버튼 — 현재 필터 조합으로 티켓 목록을 재조회하고 로딩 중 비활성화한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-tickets-search-input` 티켓 검색 입력 — 제목·본문·신고자·경로를 서버 search 파라미터로 필터링하며 값 변경 시 자동 재조회한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-tickets-status-filter` 상태 필터 셀렉트 — 전체/미해결/분류됨/처리 중/해결/종결을 status 파라미터로 서버 필터링한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-tickets-category-filter` 카테고리 필터 셀렉트 — 계정·세션·음성·콘텐츠·안전·기타를 category 파라미터로 서버 필터링한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-tickets-priority-filter` 우선순위 필터 셀렉트 — 긴급/높음/보통/낮음을 priority 파라미터로 서버 필터링한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-tickets-assigned-group-input` 담당 그룹 필터 입력 — assigned_group 파라미터로 담당 그룹을 서버 필터링한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-tickets-stale-toggle` 정체만 체크박스 — stale_only=true로 24시간 이상 미변경 티켓만 조회한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-tickets-clear-filters-button` 필터 초기화 버튼 — 모든 필터를 기본값으로 되돌리며 필터가 없으면 비활성화된다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-tickets-category-queue-chips` 카테고리 큐 칩 버튼 — 건수가 있는 카테고리를 칩으로 나열하고 클릭 시 해당 필터를 적용하며 활성 칩을 강조한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-tickets-kpi-cards` 티켓 요약 KPI 4종 — 전체 접수·미해결·높은 우선순위·정체 건수를 summary 기반 카드로 표시한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-tickets-active-list` 미해결 티켓 큐 목록 — 활성 티켓 최대 24건을 카테고리·신고자·중복 관계·처리 이력·배지와 함께 렌더한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-ticket-inprogress-button` 티켓 '처리 중' 버튼 — 상태를 in_progress로 PATCH하고 pendingRef로 중복 클릭을 즉시 차단한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-ticket-resolve-button` 티켓 '해결' 버튼 — 상태를 resolved로 PATCH하고 성공 시 큐에서 이력으로 내린다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-ticket-link-duplicate-button` 중복 후보 '연결' 버튼 — 중복 후보가 있을 때만 노출되어 parent_ticket_id를 후보로 PATCH해 연결한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-ticket-unlink-duplicate-button` 중복 연결 '해제' 버튼 — parent_ticket_id를 빈 값으로 PATCH해 중복 연결을 해제한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
- [x] `admin-tickets-resolved-history` 최근 해결 이력 섹션 — 해결·종결 티켓 최대 6건을 읽기 전용 '이력' 카드로 표시한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-tickets-states` 티켓 로딩/빈/오류 상태 — 최초 로딩·활성 0건 빈 상태·실패 InlineError를 구분해 표시한다 · 검증: 신규 spec 필요 · 신규 spec GREEN(full-sweep-admin)
|
||
|
||
**의심 결함(에이전트 리포트)**:
|
||
|
||
- `admin-data-diagnostics-panel`: users는 필드 단위 정규화가 있지만 tickets 배열은 as AdminSupportTicket[] 캐스트만 함 — reporter 등 누락 시 ticket.reporter.email 접근에서 렌더 크래시(에러 바운더리로만 방어)
|
||
- `admin-overview-refresh-button`: disabled 조건이 loading||usersLoading||usageLoading뿐이라 uptime·tickets 로딩 중에는 중복 클릭 가능
|
||
- `admin-users-tabs`: role=tab이지만 화살표 키 내비게이션·aria-controls·tabpanel 연결이 없어 ARIA 탭 패턴 미완성
|
||
- `admin-users-row-cap`: 페이지네이션이 없어 41번째 이후 사용자는 검색 없이는 도달 불가
|
||
- `admin-users-status-select`: super_admin 계정의 승인 상태도 일반 관리자가 보류로 바꿀 수 있게 UI가 열려 있음(서버 검증 의존)
|
||
- `admin-users-deactivate-button`: 확인 대화상자 없이 한 번의 클릭으로 계정이 비활성화됨(파괴적 작업 컨펌 누락)
|
||
- `admin-users-register-form`: 이메일 형식 검증 없이 비어 있지만 않으면 제출됨; 오류는 상단 usersError 배너로만 표시되어 폼 필드와 연결 안 됨
|
||
- `admin-users-states`: '새로고침을 눌러 다시 시도하세요' 문구가 있지만 users 탭 화면에는 재시도 버튼이 없음(새로고침 버튼은 overview에만 존재)
|
||
- `admin-access-tabs`: users 탭바와 동일하게 키보드 화살표 내비게이션 미구현
|
||
- `admin-access-roles-cards`: 화면 스스로 '역할·그룹 저장 API는 아직 분리되지 않았다'고 명시한 정적 화면 — 조작 요소가 전혀 없어 실데이터와 어긋날 수 있음
|
||
- `admin-tickets-search-input`: 디바운스가 없어 키 입력마다 GET /admin/tickets가 발사됨(담당 그룹 입력도 동일)
|
||
- `admin-tickets-assigned-group-input`: 키 입력마다 즉시 재조회(디바운스 없음)
|
||
- `admin-tickets-category-queue-chips`: 활성 칩을 다시 클릭해도 해제(전체로 복귀)되지 않음 — 해제하려면 셀렉트나 초기화 버튼을 써야 함
|
||
- `admin-ticket-resolve-button`: 성공 시 로컬 상태 교체와 loadTickets 재조회를 둘 다 수행해 요청이 중복됨(경미)
|
||
- `admin-tickets-states`: loadTickets가 시작·성공 시 ticketsError를 초기화하지 않아 한 번 실패하면 이후 조회가 성공해도 오류 배너가 계속 남음(티켓 상태 변경 성공 시에만 지워짐)
|
||
|
||
## 8. 관리자 AI 설정 (admin-ai)
|
||
|
||
- [x] `admin-ai-guard-require-auth` RequireAuth(admin) 라우트 가드 — 미인증은 /login, admin 권한이 없으면 자기 역할 홈으로 리다이렉트한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-ai-guard-pending-approval` PendingApprovalGate 리다이렉트 — 미승인 사용자가 /admin/ai에 오면 /pending으로 리다이렉트한다 · 검증: 신규 spec 필요
|
||
- [x] `admin-ai-guard-onboarding-bypass` OnboardingGate 관리자 경로 우회 — 온보딩 미완료여도 admin 권한 보유 시 /admin/* 경로를 통과시킨다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-ai-shell-sidebar-nav` AppShell 관리자 사이드바 내비게이션 — navRole=admin 셸로 관리자 메뉴 링크를 제공하고 현재 페이지를 활성 표시한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-ai-initial-load` 초기 데이터 병렬 로드 — usage·health·engine-config·engine-capabilities를 allSettled로 호출해 성공분만 반영하고 실패 메시지는 중복 제거해 배너에 잇는다 · 검증: e2e/admin.spec.ts + e2e/full-sweep-admin-ai.spec.ts
|
||
- [x] `admin-ai-refresh-button` 새로고침 버튼 — 사용량·헬스·설정·provider capability를 모두 다시 불러오며 로딩 중 비활성화된다 · 검증: e2e/full-sweep-admin-ai.spec.ts
|
||
- [x] `admin-ai-error-alert` 오류 배너(role=alert) — 로드·저장 실패 시 오류 메시지를 role=alert 배너로 띄우고 다음 요청 시작 시 초기화한다 · 검증: 신규 spec 필요
|
||
- [x] `admin-ai-aria-busy` 로딩 중 aria-busy 표시 — 페이지 컨테이너에 로딩 동안 aria-busy=true를 설정한다 · 검증: 신규 spec 필요
|
||
- [x] `admin-ai-window-toggle` 계량 기간 토글(7/30/90일) — 기간을 바꾸면 usage만 재조회하고 늦게 도착한 응답은 active 플래그로 무시한다 · 검증: 신규 spec 필요
|
||
- [x] `admin-ai-source-indicator` 계량 데이터 원천 표시 — durable+database면 '운영 DB 원장'을, 아니면 런타임 임시 집계와 소실 경고를 표시한다 · 검증: 기존 e2e/readiness.spec.ts
|
||
- [x] `admin-ai-ledger-cards` 핵심 지표 카드 5종 — 누적 비용·계량 호출·입출력 토큰·호출당 비용을 usage에서 계산해 표시한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `admin-ai-budget-panel` 예산 상태·사용률 트랙 — budget.status를 배지로, used_ratio를 100% 캡 진행 바로 표시하고 disabled면 설정 안내를 보여준다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `admin-ai-coverage-track` DB 계량 커버리지 트랙 — metered_turns/total_turns 비율을 진행 바로 표시하고 미계량 턴 수를 안내한다 · 검증: 신규 spec 필요
|
||
- [x] `admin-ai-daily-chart` 일별 비용 막대 차트 — daily_cost를 상대 높이 막대로 렌더하고 날짜·비용 툴팁과 role=img aria-label을 제공한다 · 검증: 신규 spec 필요
|
||
- [x] `admin-ai-daily-chart-empty` 일별 차트 빈 상태 — 선택 기간에 계량된 호출이 없으면 안내 문구를 보여준다 · 검증: 신규 spec 필요
|
||
- [x] `admin-ai-provider-table` Provider·모델별 사용 원장 테이블 — by_provider 행을 비용 내림차순으로 정렬해 호출·토큰·비용·비중을 표로 보여준다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `admin-ai-provider-table-empty` 모델 원장 빈 상태 — 계량 행이 없으면 '모델별 계량 행이 아직 없습니다.'를 보여준다 · 검증: 신규 spec 필요
|
||
- [x] `admin-ai-engine-status-pill` 엔진 런타임 상태 배지 — health.services의 engine 서비스를 정상/중단/제한 운영으로 표시하고 미확인 시 '확인 불가'를 보여준다 · 검증: 기존(부분) e2e/settings.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `admin-ai-engine-provider-select` AI provider 드롭다운(6종) — Claude CLI·Anthropic API·Codex CLI·Agy CLI·OpenAI·Solar를 select로 제공하고, 설치·인증되어 모델을 조회할 수 있는 provider만 저장 가능하다 · 검증: e2e/admin.spec.ts + e2e/full-sweep-admin-ai.spec.ts
|
||
- [x] `admin-ai-engine-url-input` 연결 주소 입력 — engine_url을 편집하면 이전 주소의 model catalog를 즉시 무효화하고, 새 주소를 query로 전달한 목록 새로고침이 끝나기 전에는 저장할 수 없다 · 검증: e2e/admin.spec.ts desktop/mobile
|
||
- [x] `admin-ai-engine-model-select` 기본 모델 드롭다운 — 선택 provider의 live capability 목록만 표시하고 Codex는 Terra, Agy는 Gemini 3.6 Flash High를 기본 선택한다 · 검증: e2e/admin.spec.ts + e2e/full-sweep-admin-ai.spec.ts
|
||
- [x] `admin-ai-engine-effort-select` 추론 강도 드롭다운 — 선택 모델이 실제 지원하는 강도만 표시하고 Codex Terra는 Medium, Agy Flash는 High를 기본 선택한다 · 검증: e2e/admin.spec.ts
|
||
- [x] `admin-ai-engine-config-meta` 엔진 설정 메타 정보 — 저장 원천(DB 영구/런타임)·현재 소스·최근 변경 시각·변경자를 dl로 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `admin-ai-engine-save-button` 운영 설정 저장 버튼 — provider·URL·모델·추론 강도를 PATCH 저장한다. 서버는 제안된 게이트웨이 capability를 다시 검증하고 성공 후 health를 재조회하며 2.4초간 '저장됨' 배지를 띄운다 · 검증: e2e/admin.spec.ts + e2e/db-persistence.spec.ts
|
||
- [x] `admin-ai-engine-loading-empty` 엔진 설정 로딩/실패 빈 상태 — engine-config가 없으면 '불러오는 중입니다' 문구를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `admin-ai-cache-panel` 평가 캐시 효율 패널 — enabled 배지·hit-rate·요청/적중/미스/저장/엔트리/축출 카운트와 원문 미저장 안내를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `admin-ai-integrity-panel` DB 계량 상태(무결성) 패널 — 계량 원천·durable 여부·미계량 턴 수와 '감사 필요/누락 없음' 판정을 표시한다 · 검증: 기존(부분) e2e/readiness.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `admin-ai-note-no-source-pack-kb` [조사 노트] source pack sync·KB 관리 부재 — 이 페이지에는 source pack sync·KB 관리 UI가 없고 관련 코드는 PersonaStudio·Session에만 존재한다 · 검증: 기존 e2e/kb-source-packs.spec.ts
|
||
|
||
**의심 결함(에이전트 리포트)**:
|
||
|
||
- `admin-ai-initial-load`: 부분 실패 시 성공 데이터와 오류 배너가 공존해 어떤 패널이 실패했는지 구분하기 어렵다. engine-config 실패 시 엔진 패널은 '불러오는 중' 문구가 영구히 남는다(재시도 UI 없음).
|
||
- `admin-ai-refresh-button`: 엔진 설정 폼을 수정하고 저장하기 전에 새로고침을 누르면 편집 중이던 engine_url·model·mode가 서버 값으로 조용히 덮어써진다(변경사항 유실 경고 없음).
|
||
- `admin-ai-aria-busy`: aria-busy 외에 시각적 로딩 스피너/스켈레톤이 없어 데이터 미도착 시 지표가 '—'로만 보인다.
|
||
- `admin-ai-window-toggle`: 기간 변경 실패 시 이전 기간의 usage 데이터가 화면에 그대로 남은 채 오류 배너만 떠서 기간 라벨(예: '90일 DB 집계')과 실제 표시 데이터가 불일치할 수 있다.
|
||
- `admin-ai-daily-chart`: 막대별 상세가 title 속성에만 있어 키보드·스크린리더로는 개별 일자 값에 접근할 수 없다(전체 aria-label만 존재).
|
||
- `admin-ai-engine-provider-select`: **해결(2026-07-30)** — 옛 4종 라디오와 `messages_api` 별칭을 없애고 6종 provider select와 capability 상태를 단일 계약으로 연결했다.
|
||
- `admin-ai-engine-url-input`: **해결(2026-07-30)** — 서버가 제안된 URL의 capability를 조회한 뒤 연결 실패·모델/강도 불일치를 422로 거부하므로 잘못된 주소가 durable 설정을 덮지 않는다.
|
||
- `admin-ai-engine-save-button`: 저장 성공 후 health 재조회 실패는 catch(() => health)로 조용히 무시되며 이때 스테일 클로저의 이전 health를 쓴다. window.setTimeout(2400ms)을 언마운트 시 정리하지 않아 페이지 이탈 후 setState가 호출될 수 있다. 저장 확인(confirm) 없이 즉시 운영 엔진이 교체된다.
|
||
- `admin-ai-engine-loading-empty`: GET 실패 시에도 같은 '불러오는 중' 문구가 영구 표시되어 실패 상태를 로딩으로 오인하게 한다(패널 내 재시도 수단 없음).
|
||
|
||
## 9. 설정 (settings)
|
||
|
||
- [x] `settings-guard-require-auth` RequireAuth 가드 (미인증 → /login) — 로딩 중 BootScreen을 띄우고 미인증이면 state.from을 담아 /login으로 보낸다(역할 제한 없음) · 검증: 신규 spec 필요
|
||
- [x] `settings-guard-pending-approval` PendingApprovalGate (미승인 → /pending) — 미승인 사용자가 /settings에 접근하면 /pending으로 리다이렉트한다 · 검증: 신규 spec 필요
|
||
- [x] `settings-guard-onboarding` OnboardingGate (온보딩 미완료 → /onboarding) — onboardingCompletedAt이 null이면 /onboarding으로 보낸다(/settings는 관리자 예외 경로가 아님) · 검증: 신규 spec 필요
|
||
- [x] `settings-initial-load` 설정 데이터 일괄 로드 — 프로필·환경설정·지원 티켓·음성 프리셋을 병렬 조회하고 관리자면 엔진 설정·헬스·provider capability도 추가 조회한다 · 검증: e2e/settings.spec.ts
|
||
- [x] `settings-load-error-callout` 로드 실패 경고 콜아웃 — 로드 실패 시 화면 상단에 role=alert 경고 콜아웃으로 오류 메시지를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `settings-section-skeletons` 섹션별 로딩 스켈레톤 — 데이터 도착 전 role=status 스켈레톤을 띄우고 스크린리더용 텍스트를 숨김 제공한다 · 검증: 기존 e2e/settings.spec.ts
|
||
- [x] `settings-rail-nav-buttons` 좌측 레일 섹션 내비게이션 버튼 — 계정·지원·(관리자 AI 운영)·테마·알림·음성 버튼으로 해당 섹션에 스크롤하고 aria-current를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `settings-rail-nav-scrollspy` 스크롤 스파이 (IntersectionObserver) — 화면에 가장 많이 보이는 섹션을 감지해 레일 활성 항목을 자동 동기화한다 · 검증: 신규 spec 필요
|
||
- [x] `settings-rail-account-summary` 레일 계정 요약 카드·역할 pill — 이니셜 아바타·표시 이름·이메일·역할·소속 배지를 요약하고 관리자에게는 AI 헬스 pill을 더한다 · 검증: 기존(부분) e2e/settings.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `settings-account-display-name-input` 표시 이름 입력 — 입력 시 dirty ref를 켜서 이후 도착하는 서버 로드값이 입력을 덮어쓰지 않게 한다 · 검증: 기존 e2e/settings.spec.ts
|
||
- [x] `settings-account-email-readonly` 이메일 (읽기 전용) — 로그인으로 확인된 이메일을 disabled 입력으로 표시만 한다 · 검증: 기존(부분) e2e/settings.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `settings-account-affiliation-input` 소속 입력 — 강의·연구 운영에서 표시할 소속 문자열을 입력받는다 · 검증: 기존(부분) e2e/settings.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `settings-account-save-button` 계정 저장 버튼 — 표시 이름·소속을 PATCH 저장하고 응답으로 폼을 동기화한 뒤 '저장됨'을 2.4초 띄운다 · 검증: 기존 e2e/settings.spec.ts + e2e/db-persistence.spec.ts
|
||
- [x] `settings-support-ticket-list` 내 지원 요청 티켓 목록 — 내가 접수한 티켓을 상태·카테고리·우선순위 배지, 담당 그룹, 해결 메모와 함께 나열한다 · 검증: 기존 e2e/settings.spec.ts
|
||
- [x] `settings-support-error-state` 지원 요청 로드 실패 상태 — 티켓 조회만 실패하면 페이지를 깨뜨리지 않고 섹션 안에 role=alert 경고를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `settings-support-empty-state` 지원 요청 빈 상태 — 0건이면 '접수한 지원 요청이 없습니다', null이면 '저장소에 표시할 항목이 없습니다'를 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `settings-engine-provider-select` AI provider 드롭다운 (관리자) — 6가지 provider 중 하나를 고르고 설치·인증·모델 조회 상태를 함께 표시한다 · 검증: e2e/settings.spec.ts
|
||
- [x] `settings-engine-url-input` AI 연결 주소 입력 (관리자) — URL을 로컬 상태에 반영하면서 이전 주소의 catalog를 무효화하고 새 주소 모델 조회 전 저장을 막는다 · 검증: e2e/settings.spec.ts + admin.spec.ts의 동일 계약
|
||
- [x] `settings-engine-model-select` 기본 모델 드롭다운 (관리자) — provider capability에 있는 모델만 선택하고 최근 변경자·저장 상태 메타를 함께 표시한다 · 검증: e2e/settings.spec.ts
|
||
- [x] `settings-engine-effort-select` 추론 강도 드롭다운 (관리자) — 선택 모델이 지원하는 강도만 고를 수 있다 · 검증: e2e/settings.spec.ts
|
||
- [x] `settings-engine-save-button` 운영 설정 저장 버튼 (관리자) — provider·주소·모델·추론 강도를 PATCH 저장한 뒤 헬스를 재조회해 상태 칩을 갱신한다 · 검증: e2e/settings.spec.ts + e2e/db-persistence.spec.ts
|
||
- [x] `settings-engine-health-chip` 응답 생성 헬스 상태 칩 (관리자) — engine 서비스 상태를 정상/제한 운영/중단/확인 중 텍스트와 detail·metric으로 표시한다 · 검증: 기존(부분) e2e/settings.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `settings-theme-dark-toggle` 다크 모드 토글 — role=switch 토글로 즉시 data-theme을 바꾸고 localStorage에 저장해 전역 구독자와 동기화한다 · 검증: 신규 spec 필요
|
||
- [x] `settings-theme-save-button` 테마 저장 버튼 — 현재 다크 여부를 theme으로 서버 환경설정에 PATCH 저장하고 '저장됨'을 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `settings-voice-preset-radiogroup` 음성 프리셋 선택 라디오 카드 — 서버 프리셋 목록을 role=radio 카드로 나열하고 클릭 시 voice_preset_id를 로컬 상태에 반영한다 · 검증: 기존 e2e/voice.spec.ts
|
||
- [x] `settings-voice-rate-slider` 말하기 속도 슬라이더 — 0.8x~1.2x range 입력으로 voice_rate를 조절하고 현재값을 실시간 표시한다 · 검증: 기존(부분) e2e/settings.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `settings-voice-save-button` 음성 저장 버튼 — 프리셋 ID와 말하기 속도를 서버 환경설정에 PATCH 저장하고 '저장됨'을 표시한다 · 검증: 기존 e2e/settings.spec.ts
|
||
- [x] `settings-voice-empty-state` 음성 프리셋 빈 상태 — 등록 프리셋이 없으면 안내를 표시하고 슬라이더·저장 버튼을 숨긴다 · 검증: 신규 spec 필요
|
||
- [x] `settings-notify-toggles` 알림 항목 토글 (역할 필터) — 공통 3종에 더해 담당 학습자 진행은 teacher/admin, 가입 승인은 admin에게만 role=switch로 표시한다 · 검증: 기존 e2e/settings.spec.ts
|
||
- [x] `settings-notify-save-button` 알림 저장 버튼 — 토글 상태를 theme·voice 값과 함께 환경설정에 PATCH 저장하고 '저장됨'을 표시한다 · 검증: 기존 e2e/settings.spec.ts + e2e/db-persistence.spec.ts
|
||
- [x] `settings-saved-flash-indicator` '저장됨' 플래시 피드백 — 각 섹션 저장 성공 시 체크 아이콘과 문구를 2.4초 표시했다 자동으로 지운다 · 검증: 신규 spec 필요
|
||
- [x] `settings-topbar-theme-toggle` 톱바 테마 전환 버튼 (공용 셸) — 상단 Topbar의 해/달 버튼이 설정 섹션의 다크 모드 토글과 같은 전역 스토어를 전환한다 · 검증: 신규 spec 필요
|
||
- [x] `settings-topbar-logout` 로그아웃 버튼 (공용 Topbar) — 설정 화면의 로그아웃은 공용 Topbar 아이콘에 있으며 서버 로그아웃 후 /login으로 이동한다 · 검증: 신규 spec 필요
|
||
- [x] `settings-topbar-role-switch` 역할 공간 전환 링크 (공용 Topbar) — 복수 역할 권한자에게 학습자/교수자/관리자 홈 이동 링크를 표시한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실브라우저 순회)
|
||
- [x] `settings-avatar-upload-missing` 아바타 업로드 UI (부재) — 브리핑상 설정에 있어야 할 아바타 업로드가 없고 업로드 API는 온보딩에서만 쓰인다 · 검증: 신규 spec 필요 · **구현 완료(2026-07-27 소유자 결정: 설정에 추가)** — 신규 spec GREEN(full-sweep-settings 4/4 desktop+mobile)
|
||
- [x] `settings-consent-management-missing` 동의 관리·철회 UI (부재) — 브리핑상 설정에 있어야 할 동의 관리·철회가 없고 withdrawConsent는 어떤 UI에서도 호출되지 않는다 · 검증: 신규 spec 필요 · **구현 완료(2026-07-27 소유자 결정: 전체 흐름)** — 철회·재동의 실 API round-trip GREEN(full-sweep-settings 44/44 무회귀)
|
||
|
||
**의심 결함(에이전트 리포트)**:
|
||
|
||
- `settings-initial-load`: supportTickets만 개별 catch되고 나머지는 하나라도 실패하면 페이지 전체 오류로 전환됨(부분 성공 데이터 폐기). 서버 theme 값이 로드 시 setDark를 호출해 사용자가 Topbar에서 방금 바꾼 로컬 테마를 되돌릴 수 있음.
|
||
- `settings-load-error-callout`: 재시도 버튼이 없어 사용자는 새로고침 외 복구 수단이 없음.
|
||
- `settings-rail-account-summary`: 서버 profile의 avatar_url을 무시하고 항상 이니셜만 렌더 — Topbar는 업로드된 아바타 이미지를 보여줘 화면 간 불일치.
|
||
- `settings-account-save-button`: saveProfile에 try/catch가 없어 실패 시 unhandled rejection — 사용자에게 오류 표시가 전혀 없고 저장 실패를 알 수 없음. 저장 중 busy 상태도 없어 연타 가능.
|
||
- `settings-support-ticket-list`: 읽기 전용 목록만 있고 이 화면에서 새 지원 요청을 접수하는 UI가 없음.
|
||
- `settings-support-empty-state`: 빈 상태가 로딩용 SettingsLoadingState(점멸 dot, role=status) 컴포넌트를 재사용해 영구 로딩 중처럼 오인될 수 있음. 두 빈 상태가 같은 testId(settings-support-empty)를 공유.
|
||
- `settings-engine-provider-select`: **해결(2026-07-30)** — 옛 DOM 조회 라디오를 제어 select 상태로 교체하고 6종 provider capability와 연결했다.
|
||
- `settings-engine-url-input`: **해결(2026-07-30)** — 저장 전 서버 capability 검증으로 잘못된 URL을 durable 설정에 반영하지 않는다.
|
||
- `settings-engine-save-button`: **해결(2026-07-30)** — React 상태에서 provider·모델·강도를 직접 전송하고 저장 실패를 화면 오류로 표면화한다.
|
||
- `settings-engine-health-chip`: 헬스 조회 실패를 조용히 삼키고 null 처리 — 실패해도 '확인 중'으로만 남아 장애와 로딩을 구분할 수 없음. 기본 status fallback이 'degraded'라 로딩 중에도 경고색 칩으로 렌더됨.
|
||
- `settings-theme-save-button`: savePreferences에 try/catch 없음(실패 무통보). 저장 안 하면 서버 theme이 남아 다음 /settings 방문 로드 시 로컬 토글값을 되돌림 — 토글 즉시 반영과 서버 저장이 이중 상태.
|
||
- `settings-voice-preset-radiogroup`: 카드 우측 SpeakerIcon(재생 삼각형)이 role=presentation·aria-hidden 장식일 뿐 미리듣기 기능이 없음 — 재생 버튼처럼 보이는 죽은 어포던스. 화살표 키 라디오 이동도 없음.
|
||
- `settings-voice-save-button`: try/catch 없음(실패 무통보). savePreferences가 theme·notifications까지 통째로 전송해 다른 섹션의 미저장 변경도 함께 확정됨.
|
||
- `settings-notify-save-button`: try/catch 없음(실패 무통보). 알림 알림 자체는 저장만 되고 실제 알림 전달 채널이 이 화면에서 확인 불가.
|
||
- `settings-saved-flash-indicator`: role=status/aria-live가 없어 스크린리더는 저장 완료를 인지하지 못함.
|
||
- `settings-topbar-logout`: auth.tsx의 logout이 API 실패를 무시하고 로컬 세션만 지우는 구조인지 확인 필요 — Settings 본문에는 로그아웃·계정 삭제 등 세션 관리 UI가 전무.
|
||
- `settings-avatar-upload-missing`: 온보딩 이후 아바타를 바꿀 UI가 앱 어디에도 없음.
|
||
- `settings-consent-management-missing`: 동의 철회 경로가 UI에 전혀 노출되지 않아 규정(동의 철회권) 관점에서 공백 — dead code 상태의 withdrawConsent.
|
||
|
||
## 10. 공통 셸·GNB·라우팅 가드 (shell)
|
||
|
||
- [x] `shell-topbar-brand-link` 톱바 브랜드 로고 링크 — 워드마크 클릭 시 로그인 상태면 루트로, 미로그인이면 /login으로 이동한다 · 검증: 신규 spec 필요
|
||
- [x] `shell-topbar-role-context-label` 역할 컨텍스트 라벨 — 톱바에 현재 역할 라벨 또는 페이지가 넘긴 contextLabel을 표시한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `shell-topbar-space-switcher` 공간 전환 링크 그룹 — 권한에 따라 학습자/교수자/관리자 공간 링크를 노출하고 현재 경로 접두 일치 시 활성 표시한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `shell-topbar-theme-toggle` 다크/라이트 테마 토글 — 아이콘 버튼으로 data-theme을 전환하고 localStorage에 저장하며 Settings와 같은 스토어를 공유한다 · 검증: 기존(부분) e2e/auth-visual.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `shell-topbar-user-chip` 사용자 아바타·이름 표시 — avatarUrl 이미지(없으면 이니셜)와 이름을 톱바 우측에 표시한다(클릭 동작 없음) · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `shell-topbar-logout` 로그아웃 버튼 — 로그아웃 API 호출 후(실패해도) 로컬 사용자 상태를 비우고 /login으로 replace 이동한다 · 검증: 신규 spec 필요
|
||
- [x] `shell-sidebar-learner-nav` 학습자 사이드바 메뉴 — 대시보드·학습·기록·설정 4개 NavLink를 표시하고 활성 항목을 알약으로 강조한다 · 검증: 기존(부분) e2e/layout-visual-gate.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `shell-sidebar-teacher-nav` 교수자 사이드바 메뉴 — 콘솔·학생 분석·페르소나·설정 4개 NavLink를 표시한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `shell-sidebar-admin-nav` 관리자 사이드바 메뉴 — 관리자 5 + 교수자 3 + 학습자 3 + 설정 1, 총 12개 NavLink를 한 목록으로 표시한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `shell-sidebar-ethics-footnote` 사이드바 윤리 고지 — 교육용 시뮬레이션이며 실제 치료·진단을 대체하지 않는다는 고지를 항상 표시한다 · 검증: 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `shell-appshell-focus-modes` 셸 레이아웃 변형(hideNav/hideTopbar/bleed/wide) — 페이지 props로 사이드바 숨김·전체화면·풀블리드·넓은 작업폭을 제공하고 미인증 시 사이드바를 자동 숨긴다 · 검증: 기존 e2e/session-layout.spec.ts
|
||
- [x] `shell-appshell-role-theming` body[data-role] 역할 테마 적용 — navRole에 따라 body에 data-role을 설정해 역할별 팔레트를 적용하고 언마운트 시 복원한다 · 검증: 신규 spec 필요
|
||
- [x] `shell-auth-bootstrap-loading` 인증 부트스트랩 로딩 화면 — 앱 시작 시 세션을 복원하고 완료 전까지 모든 가드가 중립 BootScreen을 표시한다 · 검증: 신규 spec 필요
|
||
- [x] `shell-suspense-fallback` lazy 라우트 청크 로딩 fallback — 모든 페이지가 lazy import이므로 청크 로딩 동안 Suspense fallback으로 BootScreen을 표시한다. 배포 후 stale 청크 실패는 문서 재로드 1회로 최신 배포를 받고 연속 실패 시 ErrorBoundary로 넘긴다 · 검증: `e2e/full-sweep-shell.spec.ts` + `e2e/chunk-recovery-preview.spec.ts`, 공개 강제 실패 포함 GREEN(2026-07-28)
|
||
- [x] `shell-guard-require-auth` RequireAuth 미인증 리다이렉트 — 보호 라우트에서 미인증이면 원래 경로를 state.from에 담아 /login으로 replace 리다이렉트한다 · 검증: 기존 e2e/learner.spec.ts
|
||
- [x] `shell-guard-role-restriction` RequireAuth 역할 제한 리다이렉트 — 역할 불일치 시 빈 화면 대신 자기 역할 홈으로 보내며 admin·adminAccess 예외를 적용한다 · 검증: 기존 e2e/admin.spec.ts + e2e/teacher.spec.ts
|
||
- [x] `shell-guard-pending-approval` PendingApprovalGate 승인 대기 리다이렉트 — 미승인 사용자는 어떤 경로든 /pending으로 보내고 승인 사용자가 /pending에 오면 초기 경로로 되돌린다 · 검증: 신규 spec 필요
|
||
- [x] `shell-guard-onboarding` OnboardingGate 온보딩 리다이렉트 — 온보딩 미완료자는 /onboarding으로(admin의 /admin*만 예외), 완료자가 /login·/onboarding에 오면 initialPathForUser로 되돌린다 · 검증: 기존(부분) e2e/auth.spec.ts + 탐색 순회 · 탐색 GREEN(2026-07-27 실순회)
|
||
- [x] `shell-root-redirect` 루트 경로 역할별 분기 — / 접근 시 미승인은 /pending, 인증 사용자는 initialPathForUser, 미인증은 /login으로 replace 이동한다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `shell-unknown-route-redirect` 미정의 경로 리다이렉트 — 정의되지 않은 모든 경로는 404 화면 없이 /로 replace되어 역할 홈으로 재분기된다 · 검증: 신규 spec 필요
|
||
- [x] `shell-route-error-boundary` 라우트 렌더 오류 fallback — 렌더 예외 시 role=alert 진단 화면을 띄우고 경로가 바뀌면 오류 상태를 자동 리셋한다. 최신 버전 재로드·홈 이동 복구 액션을 제공한다 · 검증: 기존(부분) e2e/admin.spec.ts + 탐색 순회 + chunk recovery focused GREEN(2026-07-28)
|
||
- [x] `shell-scroll-reset-on-navigate` 경로 변경 시 스크롤 최상단 리셋 — scrollRestoration을 manual로 두고 경로 변경·bfcache 복원 시 스크롤을 최상단으로 되돌린다 · 검증: 기존 e2e/admin.spec.ts
|
||
- [x] `shell-auth-expired-listener` 세션 만료 이벤트 자동 로그아웃 — API 계층이 401에서 발행하는 auth-expired 이벤트를 받아 사용자 상태를 비워 /login으로 유도한다 · 검증: 기존 e2e/learner.spec.ts
|
||
- [x] `shell-avatar-expression-board` Live2D 페르소나 표정 보드 — P4~P7 모델별 공유 표정 라이브러리 전체를 모델 경로·모션·페이드 메타와 함께 정적 렌더하는 QA 보드다 · 검증: 기존 e2e/avatar-expression-lab.spec.ts
|
||
- [x] `shell-avatar-preview-dev-page` 서연 SVG 아바타 dev 미리보기 — 인증 없이 접근 가능한 dev 페이지로 4개 상태 애니메이션과 대표 표정 12종 그리드를 표시한다 · 검증: 신규 spec 필요
|
||
|
||
**의심 결함(에이전트 리포트)**:
|
||
|
||
- `shell-topbar-space-switcher`: 일반 학습자·교수자에게는 아예 미노출(의도). 컨테이너가 nav가 아닌 div에 aria-label만 부여됐고, accessibleRolesFor 결과를 canAccessRole로 재필터링하는 중복 로직이 있음.
|
||
- `shell-sidebar-admin-nav`: 12개 항목이 역할 그룹 구분(구분선·소제목) 없이 한 열에 나열되고 review 아이콘이 5개 항목에 중복 사용되어 스캔성이 낮음.
|
||
- `shell-auth-bootstrap-loading`: me 호출 실패 사유(네트워크 오류 vs 미인증)를 구분하지 않고 catch에서 조용히 user=null 처리해 오프라인 시 로그인 화면으로 떨어짐.
|
||
- `shell-suspense-fallback`: ~~청크 로드 실패(배포 후 stale 해시)는 Suspense가 아닌 ErrorBoundary로 전파되는데 별도 새로고침 유도 UI 없이 진단 표만 노출됨.~~ **FIXED(2026-07-28)** — `vite:preloadError`에서 경로별 자동 새로고침을 1회만 수행하고 정상 라우트 렌더 뒤 잠금을 해제한다. 개발/production preview/공개 도메인 강제 청크 실패 E2E GREEN.
|
||
- `shell-guard-onboarding`: 온보딩 미완료 admin은 /admin*만 예외라 /settings·/teach 접근 시 /onboarding으로 튕김. 미인증 방문자의 /dev/avatar-preview는 통과되지만 로그인된 미승인·미온보딩 사용자는 이 dev 페이지도 게이트에 걸려 접근 불가.
|
||
- `shell-root-redirect`: onboardingCompletedAt==null 분기와 최종 분기가 동일하게 initialPathForUser를 호출해 사실상 죽은 중복 분기.
|
||
- `shell-unknown-route-redirect`: 전용 404 페이지가 없어 오타 URL이 조용히 홈으로 이동, 사용자가 링크 오류를 인지하지 못함.
|
||
- `shell-route-error-boundary`: 진단의 componentStack은 운영 식별 증거로 유지한다. ~~재시도/홈 버튼이 없어 URL을 직접 바꿔야 함.~~ **FIXED(2026-07-28)** — `최신 버전 다시 불러오기`와 `홈으로 이동` 액션을 추가했다.
|
||
- `shell-avatar-expression-board`: 학습자 사이드바 등 어떤 GNB에도 링크가 없어 URL 직접 입력으로만 접근 가능한 숨은 라우트. 콘텐츠가 QA용인데 learner 라우트(/learn/*)에 위치.
|
||
- `shell-avatar-preview-dev-page`: 인증 가드 없는 dev 라우트가 프로덕션 라우터에 그대로 포함되어 누구나 페르소나 리그를 열람 가능(코드 주석상 의도지만 배포 노출 여부 재검토 필요).
|
||
|
||
## 발견 결함 로그 (RED → GREEN 추적)
|
||
|
||
| # | 영역 | 증상 | 재현 spec | 상태 |
|
||
|---|---|---|---|---|
|
||
| 1 | auth | 온보딩 연락처에 임의 텍스트("전화번호아님텍스트") 입력 시 클라이언트·서버 모두 통과되어 DB에 저장됨 | 서버: `test_user_onboarding_validation.py`(#13) · 클라: `Onboarding.tsx` `isValidPhone` + 구체 오류 문구 | **FIXED** (typecheck GREEN, e2e 재검증은 최종 게이트에서) |
|
||
| 2 | learner-home | 신규 학습자 첫 추천이 고난도 P1인데 AI 코치 문구는 "낮은 난도부터"를 권함 — 상호 모순 | 소유자 결정(기초 우선) → `starterPersona()` 난도 오름차순 기본 선택, RED→GREEN(full-sweep-learner-home 신규 2건) | **FIXED** (42/42 무회귀) |
|
||
| 3 | learner-home | 대시보드 탭 전환 후에도 패널 aria-label이 "최근 기록 패널"로 고정 | `LearnerHome.tsx` — dashTab에 따라 "성장 지표 패널"로 전환 | **FIXED** (typecheck GREEN) |
|
||
| 4 | professor | 학생 분석 테이블이 347명 전행 렌더(페이지네이션·가상화 없음) — 규모 성능·탐색성 우려 | 소유자 결정(지금 가상화) → @tanstack/react-virtual 세로 가상화(동적 행 높이·펼침 재측정), RED(300행 전량 렌더 관측)→GREEN | **FIXED** (40/40 무회귀 + professor 게이트 4/4) |
|
||
| 5 | admin-ai | `/admin/ai` 정상 렌더에도 부트 watchdog 진단 오버레이 표시(`asset=module-not-discovered` 오탐) | `admin.spec.ts` "keeps the boot diagnostic overlay off a rendered AI operations page" — RED 재현 후 `index.html` 셀렉터에 `.aic` 추가 | **FIXED** (1 passed 12.2s) |
|
||
| 6 | auth/admin | 관리자가 보류(pending) 처리한 사용자가 dev-login 재로그인 시 자동 재승인됨 — dev 한정 | 소유자 결정: **현행 유지**(dev/E2E 편의 의도 확정, 프로덕션은 dev-login 자체 폐쇄) | **CLOSED** (의도 확정, 코드 변경 없음) |
|
||
| 7 | auth | /pending "승인 상태 새로고침"이 여전히 미승인일 때 아무 피드백 없음(확인 수행 여부 불명) | `PendingApproval.tsx` — 미승인/실패 시각 포함 안내 문구 + refresh 아이콘 신설 | **FIXED** (typecheck GREEN) |
|
||
| 8 | 백엔드 마스킹 | 평가/코칭 문장의 일반 단어(유의점은·방치되는·마무리했을·연결감과·표현함을·어지러움은)가 `[NAME]`으로 오탐 치환되어 문장 훼손 | `test_orchestrator_masking.py::test_mask_pii_does_not_mask_evaluator_abstract_words_as_names` — RED 재현 후 `guardrail.py` 꼬리 글자 가드 추가 | **FIXED** (마스킹 18/18, 의존 스위트 69/69, 백엔드 전체 401/401) |
|
||
| 9 | settings | 온보딩 입력 항목 및 동의 철회를 설정 화면에서 수정할 수단 없음 | 소유자 결정 → 아바타 변경(#15)·동의 철회/재동의(#16) 구현 완료. 닉네임·자기소개·연락처·주소 편집은 후속 확장 후보로 남김 | **부분 FIXED** (#15·#16 해결) |
|
||
| 10 | session | 회기 종료 확인 다이얼로그만 반말 문체("종료할까?", "이동한다") — 앱 전반 존댓말과 불일치 | `Session.tsx` — "종료할까요?"/"이동합니다."로 통일 | **FIXED** (typecheck GREEN) |
|
||
| 11 | 백엔드 리드모델 | 리뷰 요약 "하늘**와**의 회기는" — 받침 있는 이름 뒤 조사 오류 | `test_review_summary_josa.py` — RED 재현 후 `_josa_wa_gwa` 헬퍼 추가 | **FIXED** (3/3, 백엔드 409/409) |
|
||
| 12 | 백엔드 리드모델 | 리뷰 헤더 난도가 "P4 · easy" 원문 노출(타 화면은 "기초") | `test_review_summary_josa.py::ReviewPersonaLabelTest` — `_persona_label` 한글 매핑 추가 | **FIXED** (백엔드 410/410) |
|
||
| 13 | auth | 온보딩 서버 검증 부재(#1의 서버측) — `OnboardingRequest`/`UserProfilePatch` phone 자유 문자열 허용 | `test_user_onboarding_validation.py` — RED 3건 재현 후 `_validate_phone_format` 추가 | **FIXED** (5/5, 백엔드 406/406 당시) · 클라이언트 측 안내는 #1에서 계속 |
|
||
| 14 | persona-studio | 저작 모드 좌측 레일(.ps-rail)이 무조건 `display:none` — 숨겨진 인터랙티브 마크업 DOM 잔존 | 소유자 결정(정리) → 레일 JSX·전용 CSS 삭제, 특성화 테스트 toHaveCount(0) RED→GREEN | **FIXED** (20/20 무회귀 + persona 게이트 2/2 + dead-code 통과) |
|
||
| 15 | settings | 설정에 아바타 변경 UI 부재(업로드 API는 온보딩 전용) — #9 세분화 | 소유자 결정(설정에 추가) → 계정 섹션 업로드 컨트롤+미리보기+PATCH avatar_url, fixme 해제 RED→GREEN | **FIXED** (4/4 desktop+mobile, 44/44 무회귀) |
|
||
| 16 | settings/auth | 동의 철회 UI 부재 + `withdrawConsent` dead code — #9 세분화 | 소유자 결정(전체 흐름) → 설정 동의 섹션(상태·버전 표시+철회 2단계 확인+재동의), 세션 프리스타트 기존 재동의 게이트와 연결, fixme 해제 RED→GREEN | **FIXED** (철회·재동의 실 API round-trip GREEN) |
|
||
| 17 | settings | 스크롤 스파이가 마지막 섹션(음성)을 활성화하지 못함 — 0 임계값 부재 + 비율 우세 휴리스틱이 scroll-margin 정렬 지점과 충돌(모바일에서 두드러짐) | `full-sweep-settings.spec.ts` 모바일 2건 RED 재현 → `Settings.tsx` 밴드 최하단 섹션 규칙 + 스무스 스크롤 억제 + 바닥 폴백 | **FIXED** (settings desktop+mobile 26/26) |
|
||
| 18 | session | 모바일 겹침 2건: (a) 절대배치 코치 넛지가 음성 건너뛰기 클릭 가로챔, (b) 타임바 등장 시 3행 그리드 템플릿 밀림으로 컨텍스트 패널이 타임바 종료 버튼을 덮음 | `full-sweep-session.spec.ts` 모바일 RED 재현 → `session.css` `:has(> .sx-timebar)` 4행 템플릿 + 모바일 넛지 플로우 배치 | **FIXED** (session desktop+mobile 28/28, session-layout 8/8, layout-visual-gate 15/15) |
|
||
| 19 | admin | **관리자 콘솔 무한 렌더 루프 프리즈** — users API 실패(usersData=null) 상태 탭 클릭·실DB 스케일 티켓 검색 입력 시 TanStack `_autoResetPageIndex`↔setState 동기 루프로 영구 프리즈 | 에이전트 CDP 채증 + 결정적 재현 스펙 2건 → `Admin.tsx` users/services 메모화 + `autoResetPageIndex:false` | **FIXED** (재현 2건 GREEN 포함 admin 19/19) |
|
||
| 20 | admin/백엔드 | **복수 코호트 조용한 유실** — POST/PATCH `/admin/users`가 cohort_ids 첫 항목만 저장(`_cohort_value`가 첫 값만 취함) | 의도적 RED e2e + `test_admin_ops.py::CohortSerializationTest` → 콤마 직렬화 + `notifications.py` 배열 겹침 비교 | **FIXED** (백엔드 412/412, e2e 재실행 GREEN) |
|
||
| 21 | session-review/백엔드 | 감정 밸런스 타임라인 데이터 소스가 항상 빈 배열 — 사문 렌더 경로 | 소유자 결정(지금 구현) → 혼합 접근: deep 스키마 `turn_valence` 신설(LLM 산출)+저장 데이터 결정론 파생 폴백(counselorBaseline=rapport_signal 누적 평균), `test_review_valence.py` RED 8건→GREEN 9/9 | **FIXED** (백엔드 421/421, e2e 차트 렌더 검증 포함 14/14) |
|
||
| 22 | persona-studio/백엔드 | **공개 페르소나 보관 전면 불능** — DELETE `/personas/{id}`가 실DB에서 항상 503. `archive_persona_family`의 UPDATE…FROM RETURNING에서 무한정 `code`가 target.code와 모호(AmbiguousColumnError) | 실API RED 재현(QAX1 초안 생성→DELETE 503) → RETURNING 컬럼 card. 한정 → 재시작 후 같은 호출 200/archived | **FIXED** (백엔드 412/412 + 실API GREEN) |
|
||
| 23 | 스모크 스크립트 | `smoke-resistance-openness-db.py`의 advice_jump 단언(turn_client_state ≥5)이 엔진 변동성에 민감 — 조언점프 5턴 중 2턴에서 evaluator가 client_state 라벨을 비워 3행만 저장(2026-07-27 실행, 코드 회귀 아님 — 당일 diff는 deep-loop 한정) | 스모크 실행 로그 | OPEN·스모크 단언 완화 검토(예: ≥3 또는 재시도) |
|