vignette/apps/web/README.md
Yun Chan 613bcb603e
Some checks failed
API contract / OpenAPI type drift (push) Has been cancelled
아바타 v3 세션 연결 — P1 서연 리노컷 아바타와 음성 립싱크
- ClientAvatar가 리그 레지스트리(v3/rigs)로 P1을 판정해 그림 영역을 ClientAvatarV3로 그린다(로드 중·실패 시 기존 SVG, VITE_AVATAR_V3=0이면 끔)
- 발화 구동 공용 모듈 speechDriver: Lab과 세션이 함께 쓰고, TTS AudioBuffer를 오디오 시계로 표본해 립싱크·발화 동반층·지문 cue를 돌린다
- Session: TTS 재생 시작 시 발화(원문·버퍼·시작 시각) 전달, 음성 실패 시 텍스트 타이밍 발화, 정지 경로에서 해제, 개방도·겉표정 강도 전달
- 정지 화면(시작 전·썸네일)도 한 프레임을 그리고, 박스 실측 폭으로 상반신/얼굴 크롭을 고른다
- 세션 발화 E2E(오디오·실패 경로), P1 레이아웃 게이트, P1 표정 시험을 v3 기대로 갱신
2026-10-01 16:12:24 +09:00

104 lines
5.4 KiB
Markdown

# apps/web — Vignette 프론트엔드
React 19 + Vite + TypeScript + react-router v6. 상태는 Context(AuthContext) 중심.
3역할(학습자/교수자/관리자) 공통 앱 셸 + 상담 세션 UI + 가상 내담자 아바타.
디자인 단일진실원본: `docs/DESIGN_CONCEPT.md` + `docs/dev_dashboard.html`(토큰).
## 실행
```bash
cd apps/web
npm install
npm run dev # http://localhost:5173 (개발 서버, /api → :8000 프록시)
```
기타 스크립트:
```bash
npm run build # tsc -b + vite build → dist/
npm run generate:api-types # FastAPI OpenAPI → src/lib/api.gen.ts
npm run check:api-types # 생성 타입 stale 체크
npm run generate:live2d-assets
npm run preview # 빌드 결과 미리보기
npm run typecheck # tsc --noEmit (타입 체크만)
```
백엔드(FastAPI)는 `apps/api`에서 `uvicorn app.main:app --port 8000`으로 띄운다.
프론트는 실제 API 세션과 DB 기반 데이터를 사용한다. 로컬 개발 로그인은
`AUTH_DEV_LOGIN_ENABLED=true`인 개발 API에서만 제공되며, 공개 환경은 Google OAuth만 사용한다.
### 환경변수
| 변수 | 기본값 | 설명 |
|---|---|---|
| `VITE_API_BASE` | `/api` | API 베이스. 개발은 vite proxy, 프로덕션은 nginx가 백엔드로 라우팅 |
세션 아바타는 first-party SVG Live2D parameter rig를 사용한다. P4~P7 모델은
`components/avatar/live2dModel.ts`의 모델 계약으로 관리하며, 각 모델은 28개 표정 모션을
갖는다. `npm run generate:live2d-assets`는 이 계약에서
`public/live2d/personas/{p4..p7}`의 `model3.json`/`exp3.json` 산출물을 재생성한다.
Mao/Haru 같은 샘플 Live2D 자산과 Pixi/Cubism 런타임은 공개 배포물에서 제거했다.
## 라우트
| 경로 | 페이지 | 역할 | 비고 |
|---|---|---|---|
| `/login` | Login | — | 실제 Google OAuth + 개발 API 한정 로컬 로그인 |
| `/learn` | LearnerHome | learner | 실제 persona catalog와 서버 세션 기록 |
| `/learn/session/:sessionId` | Session | learner | 실제 세션 시작/이어하기 + 서버 SSE 응답 |
| `/learn/session/:sessionId/review` | SessionReview | learner | 저장된 세션 기반 리뷰/기록 |
| `/teach` | Professor | teacher | 실제 담당 학습자/회기 요약 |
| `/admin` | Admin | admin | 실제 사용자 관리, health, AI 운영 설정 |
| `/settings` | Settings | 전체 | 실제 계정/환경설정, 관리자 AI 운영 설정 |
| `/` | → 역할 홈 | — | 미인증이면 `/login` |
보호 라우트는 `AuthContext` 기반 `RequireAuth` 가드(미인증 → `/login`,
역할 불일치 → 자신의 역할 홈). 과설계 없음.
## 구조
```
src/
main.tsx 엔트리. 스타일 import 1회.
App.tsx 라우터 + 역할 가드.
vite-env.d.ts import.meta.env 타입.
styles/
tokens.css ★ 디자인 토큰 (라이트/다크/역할 accent). dev_dashboard 계승.
global.css reset + body + 스크롤바 + 유틸.
lib/
api.ts fetch wrapper(credentials:include) + SSE 헬퍼 + 세션 API.
api.gen.ts FastAPI OpenAPI에서 생성한 백엔드 DTO 타입.
auth.tsx AuthContext(user/role/login/logout). body[data-role] 반영.
format.ts 시간/타이머/숫자 포맷(tabular).
components/
ui/ 프리미티브: Button Card Panel Kicker Badge StatLine
ProgressBar Field/Input Dot Icon(inline svg) SectionHead.
배럴: index.ts → import { Button, ... } from "../components/ui"
shell/ AppShell Sidebar Topbar (§6.3 공통 셸).
avatar/ClientAvatar.tsx 가상 내담자 SVG Live2D parameter rig.
avatar/live2dModel.ts P4~P7 모델/표정 모션 계약.
public/live2d/personas/ 생성된 first-party Live2D-compatible model3/exp3 자산.
pages/ Login + learner/teacher/admin/settings/session 화면.
```
## 디자인 철칙 (위반 시 재작업)
- border-left 강조선·좌측 사이드바 강조줄 금지
- 이모지 금지 — 아이콘은 전부 inline SVG(`components/ui/Icon.tsx`, stroke=currentColor)
- 카드 격자 덤프 금지 (한 화면 한 메시지, 위계는 weight+여백)
- 순흑(#000)/순백(#fff) 금지 — `--paper`/`--ink` 토큰만
- 모서리 절제: 카드/버튼 8px, 입력 6px. 원형은 dot/아바타/음성오브만
- 강조 = weight(400→600) + accent 텍스트 + accent-tint 배경 + 상단 kicker(+dot)
- 빨강(`--crit-*`)은 진짜 위급/리스크에만
## Features 단계 인계 노트
- UI 프리미티브는 `components/ui` 배럴에서 가져온다. props/타입이 안정 계약이다.
- `ClientAvatar` props(`persona`/`state`/`affect`/`analyser`)는 확정 인터페이스.
avatar 에이전트는 이 파일 내부 SVG/모션만 고도화하고 시그니처는 유지.
리노컷 리그가 있는 페르소나(`components/avatar/v3/rigs`, 지금은 P1)는 내부에서 v3로 그리며,
선택 prop `openness`·`surfaceIntensity`·`speech`(TTS 발화 구동)를 더 받는다(결정문
`docs/decisions/avatar-expression-engine-v3.md` §8.5). 빌드 플래그 `VITE_AVATAR_V3=0`이면 모두 기존 SVG.
- 세션 데이터는 `lib/api.ts`의 `sessionApi`(start/turn/end/stream) 사용.
SSE 토큰 수신은 `openSessionStream(sessionId, { onToken, onDone, ... })`.
- 페이지는 `default export`. `AppShell`로 감싸면 톱바/네비/역할 accent가 자동 적용.