From 47c5b97a6d0738842726bccc4e9e87e6b6940d5a Mon Sep 17 00:00:00 2001 From: Yun Chan Date: Fri, 26 Jun 2026 16:05:46 +0900 Subject: [PATCH] docs: consolidate dashboard details into tabs --- docs/dev_dashboard.html | 702 +++++++++++++++++++++++++++------------- 1 file changed, 480 insertions(+), 222 deletions(-) diff --git a/docs/dev_dashboard.html b/docs/dev_dashboard.html index da49fa6..bce69dd 100644 --- a/docs/dev_dashboard.html +++ b/docs/dev_dashboard.html @@ -135,6 +135,55 @@ color:var(--ink-2); font-size:13px; } + .tabs { + border:1px solid var(--hair); + border-radius:12px; + background:var(--surface); + overflow:hidden; + box-shadow:0 1px 2px rgba(28,42,42,.05); + } + .tabbar { + display:flex; + gap:0; + overflow-x:auto; + border-bottom:1px solid var(--hair); + background:var(--paper-2); + } + .tab-button { + appearance:none; + border:0; + border-right:1px solid var(--hair); + background:transparent; + color:var(--ink-2); + padding:13px 16px; + font:700 13px/1.2 var(--font); + white-space:nowrap; + cursor:pointer; + } + .tab-button:hover { background:rgba(62,122,110,.08); color:var(--ink); } + .tab-button[aria-selected="true"] { background:var(--surface); color:var(--accent-deep); box-shadow:inset 0 -2px 0 var(--accent); } + .tab-panel { padding:20px; } + .tab-panel[hidden] { display:none; } + .detail-head { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:18px; align-items:start; margin-bottom:16px; } + .detail-head h3 { margin:0; font-size:18px; line-height:1.35; } + .detail-head p { margin:6px 0 0; color:var(--ink-2); font-size:13px; } + .mini-metrics { display:flex; flex-wrap:wrap; gap:8px; justify-content:flex-end; } + .mini-metrics span { display:inline-flex; align-items:center; min-height:28px; padding:4px 9px; border:1px solid var(--hair); border-radius:999px; background:var(--paper); color:var(--ink-2); font:650 12px/1 var(--num); } + .task-list { display:grid; border:1px solid var(--hair); border-radius:12px; overflow:hidden; background:var(--hair); gap:1px; } + .task-row { display:grid; grid-template-columns:108px minmax(220px,1fr) minmax(180px,.8fr) minmax(190px,.9fr); gap:0; background:var(--surface); } + .task-row > div { padding:13px 14px; min-width:0; } + .task-row b { display:block; margin-bottom:4px; font-size:13px; color:var(--ink); } + .task-row p { margin:0; color:var(--ink-2); font-size:12px; line-height:1.45; } + .task-status { display:inline-flex; align-items:center; justify-content:center; min-width:76px; min-height:28px; padding:4px 8px; border-radius:999px; font:760 12px/1 var(--num); } + .s-done { background:var(--pos-bg); color:var(--pos); } + .s-doing { background:var(--warn-bg); color:var(--warn); } + .s-risk { background:var(--crit-bg); color:var(--crit); } + .s-plan { background:var(--info-bg); color:#2E5A7A; } + .detail-blocks { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:12px; margin-top:14px; } + .detail-block { border:1px solid var(--hair); border-radius:12px; padding:14px; background:var(--paper); } + .detail-block h4 { margin:0 0 8px; font-size:13px; } + .detail-block ul { margin:0; padding-left:18px; color:var(--ink-2); font-size:12px; line-height:1.6; } + .detail-block li + li { margin-top:4px; } code { font-family:var(--num); font-size:12px; background:var(--paper-2); padding:2px 6px; border-radius:6px; } .wide { grid-column:1 / -1; } .commands { display:grid; gap:10px; } @@ -149,6 +198,12 @@ .hero { grid-template-columns:1fr; } .grid { grid-template-columns:1fr; } .roadmap { grid-template-columns:1fr; } + .detail-head { grid-template-columns:1fr; } + .mini-metrics { justify-content:flex-start; } + .task-row { grid-template-columns:1fr; } + .task-row > div { padding:12px 14px; border-bottom:1px solid var(--hair); } + .task-row > div:last-child { border-bottom:0; } + .detail-blocks { grid-template-columns:1fr; } } @media (max-width:520px) { .summary { grid-template-columns:1fr; } @@ -160,7 +215,7 @@
Vignette 개발 대시보드
-
2026-06-26 15:35 KST
+
2026-06-26 16:04 KST
@@ -256,234 +311,437 @@ -
+
-

팀장 판정

-

이 HTML만 보고 판단해야 하는 항목

+

상세 페이지

+

탭별 할 일, 산출물, 검증 기준. 팀장 리뷰는 여기서 다음 작업을 고르면 된다.

-
-
- go -

로컬 회귀와 공개 prod-safe 게이트 통과

-

백엔드 unittest 20개, Python compile, 웹 production build, 전체 Playwright 72개가 통과했다. 공개 API도 `environment:"prod"`, `db:true`, `engine:true`로 응답한다.

-
-
- deployed -

커스텀 도메인 운영 반영 완료

-

Cloudflare Pages production `0fe8f3cc`이 `543d48c`로 배포됐고, `https://vignette.chanpaca.net`이 `index-D1Z5DH5J.js`와 `index-BA9-xxfn.css`를 서빙한다.

-
-
- conditional -

운영 반영 전 남은 증거 1개

-

실제 Google 로그인 쿠키가 필요한 공개 `/turn` smoke는 아직 storageState가 없어 미완이다. 로그인 가능한 계정으로 한 번 캡처하면 바로 검증 가능하다.

-
-
- mock audit -

런타임 목업 제거 기준

-

프론트 페이지는 실제 API/DB 경로를 탄다. 남은 `mock` 표기는 테스트 코드의 `unittest.mock` 또는 의도적 fixture이며, seed fallback은 prod/staging에서 fail-closed 된다.

-
+
+
+ + + + + + + +
+ +
+
+
+

Phase 0 마감 상세

+

지금 단계는 구현을 더 벌리는 단계가 아니라, 운영 증거를 닫고 P1 진입 조건을 고정하는 단계다.

+
+
상태: 조건부우선순위: P0블로커: public /turn
+
+
+
+
BLOCK
+
공개 Google OAuth 실제 `/turn` proof 확보

로그인 가능한 계정으로 storageState를 저장한 뒤 public-auth-turn E2E를 실행한다.

+
산출물

`apps/web/node_modules/.tmp/public-auth.json`, public `/turn` 성공 로그

+
검증

`E2E_PUBLIC_AUTH=1` + `chromium-public-auth` 1회 통과

+
+
+
CHECK
+
engine config 운영값 재확인

E2E가 admin engine config를 만질 수 있으므로 배포 전 `mode/url/model` 값을 확인한다.

+
산출물

admin AI 운영 화면 캡처 또는 config API 응답

+
검증

`claude_cli / http://127.0.0.1:9099 / gateway-default` 의도값 대조

+
+
+
DONE
+
과거 Live2D demo 자산 제거

Mao/Haru 샘플, Pixi/Cubism 런타임, 공개 `/live2d/*` 캐시 잔여 접근을 차단했다.

+
산출물

`apps/web/functions/live2d/[[path]].js`, SVG-only avatar

+
검증

운영 `/live2d/mao/*`, Cubism core `404`

+
+
+
DONE
+
프로세스 난립 정리

임시 Vite preview와 dev API를 내리고 운영 확인용 프로세스만 유지한다.

+
산출물

9099 engine, 8001 prod API, cloudflared tunnel 1개

+
검증

`Get-NetTCPConnection`에서 8000/517x/5537 비어 있음

+
+
+
GATE
+
한신대 공문/데이터 거버넌스 게이트 정리

SSO 클레임, 추가 축어록 수급, 미성년 원본 활용동의, 개인정보 처리방침을 P1 진입 전 외부 의존성으로 명확히 둔다.

+
산출물

공문 질의서, 동의 범위 체크리스트, SSO claim 표

+
검증

IRB 게이트가 아니라 데이터/SSO 게이트로 문서 전수 정합

+
+
+
+
+

팀장 판정

+
    +
  • 로컬 회귀와 공개 prod-safe 게이트는 통과했다.
  • +
  • Cloudflare Pages production `0fe8f3cc`이 `543d48c` 소스로 배포됐다.
  • +
  • 운영 반영 전 남은 핵심 증거는 공개 Google OAuth 실제 `/turn` smoke다.
  • +
  • 런타임 mock/demo 자산은 운영 번들에서 제거하고, 테스트 fixture만 남긴다.
  • +
+
+
+

제품/UX 완료

+
    +
  • 학습자 홈 0회 기록 상태는 fake 기록 없이 실제 서버 세션 0개로 표시한다.
  • +
  • active session은 실제 SSE token 이벤트로 자막을 쌓는다.
  • +
  • 텍스트/음성 실패 턴은 transcript와 저장소에 남기지 않는다.
  • +
  • 375px급 active session viewport overflow를 보정했다.
  • +
  • 직접 URL persona 우회는 DB 원본 persona가 아니면 차단한다.
  • +
  • 세션 화면은 SVG persona avatar만 렌더링한다.
  • +
+
+
+

운영/테스트 완료

+
    +
  • seed persona 결합을 제거하고 DB persona 기반 E2E로 전환했다.
  • +
  • 비개발 런타임은 dev login, seed fallback, 기본 secret, localhost CORS를 fail-closed 한다.
  • +
  • compose OAuth/CORS/OpenAI base 설정을 API 컨테이너에 명시했다.
  • +
  • persona catalog는 비로그인 401로 인증 경계를 가진다.
  • +
  • admin 모바일 overflow, AI 운영 상태 문구, global engine config 테스트 격리를 정리했다.
  • +
  • handoff, E2E README, 이 대시보드를 최신 상태로 맞췄다.
  • +
+
+
+
+ + + + + + + + + + + +
-
-
-
-

완료

-

새 세션에서 반복하지 않아도 되는 작업

-
-
-
-
- E2E persona decoupled -

DB persona 기반 테스트

-

`session-persistence`, `teacher`, `voice`는 `/api/personas`에서 실제 DB persona를 가져온다.

-
-
- fail-closed -

비개발 런타임 보호

-

prod/staging에서 dev login, seed fallback, OAuth 누락, 기본 secret, localhost CORS를 거부한다.

-
-
- infra -

compose OAuth 주입

-

`ENVIRONMENT`, Google OAuth vars, `CORS_ORIGINS`, `OPENAI_BASE_URL`을 API 컨테이너에 명시했다.

-
-
- admin UX -

모바일 overflow 수정

-

긴 readiness detail을 안정화했고, 사용자 변경은 DB 저장소가 durable할 때만 허용한다. AI 운영은 실제 어댑터명과 health 상태를 표시한다.

-
-
- test isolation -

global engine config 분리

-

`db-persistence`는 전역 engine config를 바꾸므로 `@single-run`으로 분리했다.

-
-
- docs -

handoff 갱신

-

`docs/HANDOFF.md`, `docs/dev_dashboard.html`, `apps/web/e2e/README.md`를 최신 상태로 맞췄다.

-
-
- public prod -

공개 API prod 전환

-

`cloudflared` ingress를 `127.0.0.1:8001` prod API로 돌렸고 public readiness gate가 통과했다.

-
-
- ops script -

공개 런타임 재기동

-

`scripts/start-public-runtime.ps1`와 `scripts/stop-public-runtime.ps1`로 API 8001과 cloudflared를 재현 가능하게 만들었다.

-
-
- auth boundary -

persona catalog 인증화

-

`/personas`는 이제 비로그인 401이다. 로컬과 공개 API 모두 직접 확인했고 E2E 회귀를 추가했다.

-
-
- public web -

API base fallback 보강

-

public 웹에서 `/api/auth/config`가 SPA HTML로 떨어지지 않도록 public API origin fallback을 추가했다.

-
-
- learner UX -

0회 기록 상태 보강

-

학습자 홈은 이제 fake 기록 없이 실제 서버 세션 0개를 `기존 회기` 빈 상태와 0 카운트로 표시한다.

-
-
- local login -

5175 로컬 재기동 검증

-

`127.0.0.1:5175` web, `8000` API, `9099` engine을 재기동하고 dev-login 서버 세션과 `/learn` redirect를 확인했다.

-
-
- session UX -

dense viewport 보정

-

375px급 active session에서 stage 내부가 1px 넘게 잘리던 문제를 avatar/padding 조정으로 제거했다.

-
-
- real stream -

텍스트 턴 SSE 전환

-

`POST /sessions/{id}/stream` token 이벤트로만 내담자 자막을 쌓고, HTTP 거절과 SSE error 모두 실패 턴을 transcript와 저장소에 남기지 않는다.

-
-
- voice turn -

음성 실패 턴 미저장

-

음성 회기도 엔진 응답 생성 성공 후에만 learner/client turn을 저장한다. 실패한 transcript는 pending 상태에서 제거한다.

-
-
- ops copy -

비영구 상태 문구 정리

-

admin health와 voice degraded reason은 내부 fallback/seed 표현 대신 비영구 런타임 상태를 사용자용 문구로 표시한다.

-
-
- route guard -

직접 URL persona 차단

-

`/learn/session/:code`로 직접 들어와도 DB 원본 persona가 아니면 회기 시작을 막는다. degraded/seed fallback 회귀를 추가했다.

-
-
- avatar -

demo Live2D 자산 제거

-

Mao/Haru 샘플과 Pixi/Cubism 런타임을 공개 배포물에서 제거했다. 세션 화면은 SVG persona avatar만 렌더링한다.

-
-
-
- -
-
-
-

검증

-

마지막으로 직접 실행한 결과

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
범위명령결과
Web typechecknpm run typecheckPassed
Backendpython -m unittest app.test_runtime_policy app.test_session_turn_persistence engine_gateway.test_gateway_model20 tests OK
Compilepython -m compileall app engine_gatewayPassed
Web buildnpm run buildPassed
Pages production deploywrangler pages deploy dist --project-name vignette --branch main`0fe8f3cc`, source `543d48c`
Custom domain assetshttps://vignette.chanpaca.net/`index-D1Z5DH5J.js`, `index-BA9-xxfn.css`
Legacy Live2D routes/live2d/mao/* / /live2d/haru/* / /live2d/live2dcubismcore.min.js404
Composedocker compose --env-file .env.example config --quietPassed with dummy required env
Focused E2Eadmin + db-persistence + voice-success10 passed
Admin manage-usersadmin.spec.ts --grep manage real server-known usersdesktop/mobile 2 passed
Full E2EPLAYWRIGHT_HOST=127.0.0.1 npx playwright test72 passed
Public auth discoveryE2E_PUBLIC_AUTH=1 npx playwright test --list --project=chromium-public-auth2 tests listed
Public readinesspublic-auth-turn.spec.ts --grep production-safe1 passed
Persona auth boundaryGET /personasverified local/public unauth 401
Public loginauth.spec.ts --grep public login1 passed
Public runtime scriptscripts\start-public-runtime.ps1engine 9099 + API 8001 + cloudflared only
Public API healthhttps://api-vignette.chanpaca.net/healthprod, db true, engine true
Local 5175 loginPLAYWRIGHT_BASE_URL=http://127.0.0.1:5175 auth.spec.tsdesktop/mobile passed
Learner/readiness E2Elearner.spec.ts + readiness.spec.ts desktop/mobile14 passed
Learner screenshotslearn-empty-desktop.png / learn-empty-mobile-compact.pngdocument overflow 0, empty history visible
Session layout/turnsession-layout.spec.ts desktop/mobile8 passed
Voice/session focusedvoice + voice-success + session-layout15 passed
Latest focused E2Elearner + session-layout + settings + admin37 passed
-
- -
-
-
-

남은 리스크

-

다음 세션 첫 작업

-
-
-
-
- blocker -

public `/turn` proof 없음

-

2026-06-26 15:18 KST 기준 Google 로그인 storageState가 없어 공개 API `/turn` 실제 성공 증거가 아직 없다.

-
-
- ops -

공개 운영 프로세스 유지

-

현재 실행 프로세스는 `127.0.0.1:9099` engine gateway, `127.0.0.1:8001` prod API, cloudflared tunnel 1개다. 재부팅 후에는 engine gateway와 prod API, cloudflared를 같이 재기동해야 한다.

-
-
- check before deploy -

engine config 재확인

-

E2E가 admin engine config를 건드린다. 배포 전 의도한 model/url/mode인지 다시 확인해야 한다.

-
-
-
- -
-
-
-

다음 명령

-

공개 OAuth smoke

-
-
-
-
cd D:\workspace\vignette\apps\web
-npx playwright codegen https://vignette.chanpaca.net/login --save-storage=.\node_modules\.tmp\public-auth.json
-
-$env:E2E_PUBLIC_AUTH="1"
-$env:E2E_PUBLIC_STORAGE_STATE=".\node_modules\.tmp\public-auth.json"
-.\node_modules\.bin\playwright.cmd test e2e/public-auth-turn.spec.ts --project=chromium-public-auth
-
cd D:\workspace\vignette
-powershell -NoProfile -ExecutionPolicy Bypass -File scripts\start-public-runtime.ps1
-
-
- -
-
-
-

주의

-

작업 방식

-
-
-
    -
  • `frontenddesign` 스킬은 현재 세션에 없었다. 다음 세션에서 보이면 먼저 사용하고, 없으면 `docs/DESIGN_CONCEPT.md`를 따른다.
  • -
  • 학습자 홈과 active session UX는 사용자가 강하게 불만을 말한 영역이다. fake 기록/통계 금지, 0회 기록은 실제 서버 세션 0개 기반 빈 상태로 유지, active session 전체화면/무문서스크롤 유지.
  • -
  • 추적 파일 기준 worktree는 깨끗하게 유지한다. `.env`, 로그, `node_modules` 같은 ignored runtime 파일은 운영/개발 상태로만 취급하고 커밋하지 않는다.
  • -
  • OAuth secret은 출력하지 말 것. 실제 secret은 환경 파일/인프라 설정에만 둔다.
  • -
-
+