전수 E2E 순회·소유자 결정 6건 구현·디자인 감사 반영
- 전수 순회: IA 전 라우트 412개 기능 인벤토리를 체크리스트 백로그로 관리 (docs/ops/e2e-full-sweep-2026-07-27.md), 신규 full-sweep 스펙 10파일 추가. RED→GREEN으로 결함 12건 수정: 관리자 무한 렌더 프리즈(TanStack autoReset 루프), 복수 코호트 저장 유실, 페르소나 보관 503(SQL 컬럼 모호성), PII 과잉 마스킹, /admin/ai watchdog 오탐 오버레이, 모바일 겹침 2건, 설정 스크롤 스파이, 온보딩 전화번호 무검증, 리뷰 조사·난도 라벨, pending 피드백 등. - 소유자 결정 구현: 설정 아바타 변경, 동의 철회·재동의 전체 흐름, 신규 학습자 기초 우선 추천, 학생 분석 테이블 가상화(@tanstack/react-virtual), 저작 모드 죽은 레일 정리, 감정 밸런스 타임라인 차트(deep turn_valence + 결정론 파생 폴백). - 디자인 감사(142차): 라이트 팔레트 AA 대비, 다크 토큰 별칭 통일, 미정의 CSS 변수 정리, 한글 keep-all 전역화, 탭 타깃 24px, LCP preconnect. - 검증: npm run e2e 병렬 432 수집 GREEN + 직렬 49/49 exit 0, 백엔드 pytest 421, gateway 29, typecheck/build/design-ssot/dead-code/중복 게이트 통과, layout-visual-gate 15/15, session-layout 8/8. 상세는 SSOT 대시보드 142~144차 노트.
This commit is contained in:
parent
0ae94499f2
commit
4511383cd9
55 changed files with 9333 additions and 573 deletions
|
|
@ -2595,120 +2595,6 @@ export default function PersonaStudio() {
|
|||
className="ps-layout ps-authoring-layout"
|
||||
data-authoring-step={authoringStep}
|
||||
>
|
||||
<aside className="ps-rail" aria-label="페르소나 목록">
|
||||
<div className={surfaceClassName("ps-rail__head")}>
|
||||
<div>
|
||||
<Kicker>카탈로그</Kicker>
|
||||
<b>{catalog.length + reviews.length}개</b>
|
||||
</div>
|
||||
<Badge tone={loadState === "ready" ? "accent" : "neutral"}>
|
||||
{loadState === "ready" ? suggestedCode : "..."}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={surfaceClassName("ps-workflow")}
|
||||
aria-label="저작 단계"
|
||||
>
|
||||
<Kicker>저작 흐름</Kicker>
|
||||
{AUTHORING_STEPS.map((step, index) => (
|
||||
<div
|
||||
className={`ps-workflow-step ${
|
||||
index < authoringStepIndex
|
||||
? "is-done"
|
||||
: index === authoringStepIndex
|
||||
? "is-current"
|
||||
: ""
|
||||
}`}
|
||||
key={step.label}
|
||||
>
|
||||
<span>{index + 1}</span>
|
||||
<div>
|
||||
<b>{step.label}</b>
|
||||
<small>{step.desc}</small>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="ps-list">
|
||||
{reviews.length > 0 ? (
|
||||
reviews.map((persona) => (
|
||||
<button
|
||||
type="button"
|
||||
className={surfaceClassName(
|
||||
`ps-list-row ${editingId === persona.persona_id ? "is-active" : ""}`,
|
||||
{ variant: "interactive", flat: true },
|
||||
)}
|
||||
key={`${persona.persona_id}:${persona.version}`}
|
||||
onClick={() => void loadDraft(persona.persona_id)}
|
||||
disabled={busy !== null}
|
||||
>
|
||||
<span className="ps-list-row__code">{persona.code}</span>
|
||||
<span className="ps-list-row__body">
|
||||
<b>{persona.display_name}</b>
|
||||
<small>
|
||||
v{persona.version} ·{" "}
|
||||
{personaReviewStatusLabel(persona.status)}
|
||||
</small>
|
||||
</span>
|
||||
</button>
|
||||
))
|
||||
) : (
|
||||
<EmptyState
|
||||
title="검수 큐 없음"
|
||||
desc="저장된 초안이 여기에 표시됩니다."
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={surfaceClassName("ps-approved")}>
|
||||
<Kicker>공개 페르소나</Kicker>
|
||||
{catalog.length > 0 ? (
|
||||
catalog.map((persona) => (
|
||||
<article
|
||||
className="ps-approved-row"
|
||||
key={`${persona.code}:${persona.version ?? "approved"}`}
|
||||
data-approved-persona-row="true"
|
||||
>
|
||||
<span className="ps-approved-row__code">
|
||||
{persona.code}
|
||||
</span>
|
||||
<div className="ps-approved-row__body">
|
||||
<b>{persona.display_name}</b>
|
||||
<small>
|
||||
v{persona.version ?? 1} ·{" "}
|
||||
{persona.source === "database"
|
||||
? "DB 공개본"
|
||||
: persona.source}
|
||||
</small>
|
||||
</div>
|
||||
<div className="ps-approved-row__actions">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
onClick={() => void reviseApprovedPersona(persona)}
|
||||
disabled={busy !== null || !persona.persona_id}
|
||||
>
|
||||
수정
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="danger"
|
||||
onClick={() => void archiveApprovedPersona(persona)}
|
||||
disabled={busy !== null || !persona.persona_id}
|
||||
>
|
||||
삭제
|
||||
</Button>
|
||||
</div>
|
||||
</article>
|
||||
))
|
||||
) : (
|
||||
<span className="ps-muted">공개 목록 없음</span>
|
||||
)}
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<section className="ps-editor">
|
||||
<div className={surfaceClassName("ps-editor__top")}>
|
||||
<div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue