vnet.18ka.net 공개 배포에서 vite preview 서버가 Host 검증으로 공개 도메인 요청을 "Blocked request. This host is not allowed." 403으로 막아 SPA 전체가 블랭크로 뜨던 문제를 수정. server.allowedHosts와 같은 목록을 preview에도 적용하고 기본 허용 호스트에 vnet.18ka.net/api-vnet.18ka.net/vignette.chanpaca.net 추가. 검증: curl -H "Host: vnet.18ka.net" 127.0.0.1:5174 가 수정 전 Blocked → 수정 후 200+정상 index, 로컬 dev·preview 일반/슈퍼관리자 전 페이지 정상 렌더, npm run typecheck. 대시보드 104차 기록. |
||
|---|---|---|
| .. | ||
| e2e | ||
| functions/live2d | ||
| public | ||
| scripts | ||
| src | ||
| .dockerignore | ||
| .gitignore | ||
| Dockerfile | ||
| index.html | ||
| nginx.conf | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.ts | ||
| README.md | ||
| tsconfig.app.json | ||
| tsconfig.json | ||
| tsconfig.node.json | ||
| vite.config.ts | ||
apps/web — Vignette 프론트엔드
React 19 + Vite + TypeScript + react-router v6. 상태는 Context(AuthContext) 중심.
3역할(학습자/교수자/관리자) 공통 앱 셸 + 상담 세션 UI + 가상 내담자 아바타.
디자인 단일진실원본: docs/DESIGN_CONCEPT.md + docs/dev_dashboard.html(토큰).
실행
cd apps/web
npm install
npm run dev # http://localhost:5173 (개발 서버, /api → :8000 프록시)
기타 스크립트:
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/타입이 안정 계약이다. ClientAvatarprops(persona/state/affect/analyser)는 확정 인터페이스. avatar 에이전트는 이 파일 내부 SVG/모션만 고도화하고 시그니처는 유지.- 세션 데이터는
lib/api.ts의sessionApi(start/turn/end/stream) 사용. SSE 토큰 수신은openSessionStream(sessionId, { onToken, onDone, ... }). - 페이지는
default export.AppShell로 감싸면 톱바/네비/역할 accent가 자동 적용.