299 lines
26 KiB
Markdown
299 lines
26 KiB
Markdown
# Vignette Handoff
|
|
|
|
> Updated: 2026-06-27 18:26 KST. 새 세션은 이 문서와 `docs/DESIGN_CONCEPT.md`를 먼저 읽고 이어가면 된다.
|
|
|
|
## 현재 상태
|
|
|
|
- Workspace: `D:\workspace\vignette`
|
|
- 로컬 웹 기본 포트: `http://localhost:5173`
|
|
- 로컬 API 기본 포트: `http://127.0.0.1:8000`
|
|
- 로컬 engine gateway 기본 포트: `http://127.0.0.1:9099`
|
|
- 공개 웹: `https://vignette.chanpaca.net`
|
|
- 공개 API: `https://api-vignette.chanpaca.net`
|
|
- 최신 앱 배포 소스 commit: `0ec266a` (`동의 게이트와 런타임 안정화`)
|
|
- 최신 Cloudflare Pages production deploy: `12da49f3`, source `0ec266a`, branch `main`.
|
|
- Google OAuth 허용 이메일 도메인: `hs.ac.kr`, `twentyoz.kr`
|
|
- 최신 백엔드 회귀: `python -m pytest app/ -q` → `130 passed`
|
|
- X1 재귀학습 export 1차: `scripts/export-recursive-dataset.py` 기본 read-only dry-run, `--write-dataset` 명시 시에만 `ds.*` write, approved export는 steward/legal/IAA gate 없으면 거부.
|
|
- C1 사례개념화 워크시트 1차: `SessionReviewResponse.caseWorksheet`와 리뷰 화면 read-only 카드가 축어록 근거 기반 초안을 제공한다. 편집·DB 저장, 임상 루브릭, AI 추출/채점은 후속.
|
|
- C3 이론모드 1차: `theory_mode`가 세션·평가·생성 프롬프트까지 흐르고, `build_turn_messages`는 인간중심/CBT/통합 프레이밍을 엔진 메시지에 넣는다. CBT 체인·이론부합 루브릭·명시적 선택 UI는 후속.
|
|
- H2 평가 정규화: 턴 평가의 대안발화도 `app.alternative_utterance`에 적재하고 리뷰 hydrate 시 `alternative_utterances`로 복원한다.
|
|
- X2 예산 경고/저비용 평가 라우팅: `ADMIN_USAGE_BUDGET_USD`가 0보다 크면 `/admin/usage`가 budget 상태(ok/warn/exceeded)를 반환하고 `/admin`이 예산 배너를 표시한다. `EVALUATOR_FAST_MODEL`/`EVALUATOR_DEEP_MODEL`을 설정하면 fast/deep 평가 호출만 해당 모델 override로 gateway에 전달한다. 비우면 기존 gateway default 라우팅을 유지한다.
|
|
- H4 LLM call audit + 동의 게이트: 상담 생성(generate/stream)과 fast/deep 평가의 외부 LLM 호출 직후 `audit.llm_call_log`에 provider/model/token/cost/inference_geo/latency metadata만 적재한다. prompt/completion 본문은 저장하지 않는다. 로컬 dev-login 실제 `/turn` smoke에서 `audit.llm_call_log`가 8→11로 3행 증가했다. 이번 패스에서 `app_user.consent_at` 기반 learner 동의 수락/철회 API와 세션 시작/voice dev persona 시작 하드게이트를 추가했다. 한국어 이름/기관 NER와 guardian/legal 서명 evidence는 후속.
|
|
- RAG warm 동시성: E2E가 여러 세션을 빠르게 만들 때 BGE-M3 embedder가 동시에 지연 로드되어 `tqdm` lock 예외와 API health/dev-login timeout이 반복됐다. `rag.py` embedder load/encode를 process-wide `RLock`으로 직렬화하고, `sessions.py` warm task를 semaphore 1개로 제한했다. 최신 검증: `layout-visual-gate + session-layout` 11 passed.
|
|
- 계약 SSOT 3차: `apps/web/src/lib/api.ts`의 수기 DTO 중 auth, persona, admin/user/engine, review leaf, teacher safety/growth leaf, learner sessions, session review/worksheet aggregate, teacher dashboard aggregate 타입을 `apps/web/src/lib/api.gen.ts`의 `ApiSchema` alias로 전환했다. generated optional/default 차이는 화면 form state, notification default helper, 배열 렌더링 fallback으로 흡수한다. CI 연결과 SessionDetail/SessionStart 계열 stage enum 정리는 후속. 검증: `npm run check:api-types`, `npm run typecheck`, `npm run build`, learner/session-review/teacher/layout focused E2E 32 passed.
|
|
- 턴 런타임 리팩터 2차: `turn_runtime.finalize_completed_turn`으로 REST submit/stream/voice WS의 `record_completed_turn` + `record_safety_event` 호출쌍을 공통화했다. gateway `/v1/stream` route 레벨에서 `token/done/error` SSE 프레임 contract tests를 추가했다. 검증: focused backend 40 passed.
|
|
- Phase3 artifact checker 강화: `scripts/check-phase3-artifacts.py`가 CSV enum, KPI report 필수 field, approved export의 PII pass·κ/ICC·withdrawn exclusion·consent scope·file sha256을 검증한다. `app/test_phase3_artifact_checker.py` 5 tests 추가. 실제 파일럿 evidence와 steward/legal/IAA gate는 그대로 외부 의존이다.
|
|
- 세션 종료 UX/dark theme SSOT 정리: 드래그형 `SlideToEnd`를 명시 확인 다이얼로그로 교체하고, Topbar/Settings theme 토글을 `lib/theme.ts` 단일 경로로 통합했다. 저장값이 없으면 dark를 기본으로 두고 앱 부팅 시 theme를 먼저 적용해 초기 flash를 줄인다. API 기본 preference `system`은 Settings에서 light로 오해하지 않고 현재 초기 테마를 따른다. 회기 리뷰·설정 포함 주요 페이지의 흰 섹션 잔재도 dark 작업면으로 맞췄다. 검증: `npm run typecheck`, `npm run build`, `npx playwright test e2e/layout-visual-gate.spec.ts e2e/settings.spec.ts e2e/session-review.spec.ts --project=chromium-desktop --project=chromium-mobile --project=chromium-single-run --workers=1` 22 passed.
|
|
- M3 인증 claim 1차: Google/SAML/dev-login이 설정 기반 cohort map과 SAML cohort claim을 `cohort_ids`로 넘기고, 관리 사용자 `external_id`는 provider subject 기반(`google:`/`saml:`/`dev:`)으로 저장한다. 운영 SAML 서명검증·기관 claim schema·deprovisioning audit은 후속.
|
|
- Google OAuth 진단 1차: provider callback error는 `access_denied`/`provider_error`로 분리하고, 로그인 화면은 실패 reason code를 함께 표시한다. 실제 Google 계정 완료 proof는 아직 owner 로그인/storageState가 필요하다.
|
|
- `frontenddesign` 스킬은 현재 세션의 사용 가능 스킬 목록에 없었다. 대신 `docs/DESIGN_CONCEPT.md`를 SSOT로 사용했다.
|
|
- 공개 API 터널은 현재 `C:\Users\encep\.cloudflared\vignette-config.yml`에서 `http://127.0.0.1:8001`을 본다.
|
|
- 공개용 API 프로세스는 `127.0.0.1:8001`에서 `ENVIRONMENT=prod`로 떠 있다. 로컬 개발 API `127.0.0.1:8000`과 Tailnet 개발 API `127.0.0.1:8010`도 `ENVIRONMENT=dev`로 떠 있다.
|
|
- 2026-06-27 05:34:32 UTC 모바일 502는 cloudflared 로그상 `127.0.0.1:8001` origin connection refused와 일치한다. 현재 public API는 복구됐고, watchdog 기본 검사에서 아직 DNS가 없는 `api-vnet.18ka.net`을 제외해 향후 설치 시 불필요한 restart loop를 막았다. 2026-06-27 18:25 KST 재확인: `https://vignette.chanpaca.net/login` 200, `https://api-vignette.chanpaca.net/health` prod/db/engine true, public Google start 302 to `accounts.google.com` + HttpOnly state cookie, provider callback error → `/login?oauth=access_denied`.
|
|
- `GET /personas`는 이제 인증 필요다. 검증 당시 로컬 `http://127.0.0.1:8000/personas`와 현재 공개 `https://api-vignette.chanpaca.net/personas` 모두 비로그인 401 확인 완료.
|
|
- 로컬 웹이 `http://127.0.0.1:5175`처럼 다른 Vite 포트로 떠도 로그인은 `로컬 테스트 계정으로 계속` 버튼을 사용한다. Google OAuth 버튼은 로컬에서는 disabled로 둔다. 현재 OAuth callback이 공개 API로 돌아가기 때문에 로컬 Google OAuth는 로컬 세션에 붙을 수 없다.
|
|
- 현재 확인용 프로세스는 `127.0.0.1:9099` engine gateway, `127.0.0.1:8001` prod public API, `127.0.0.1:8000` dev API, `127.0.0.1:8010` Tailnet dev API, `127.0.0.1:5173` Vite web, `cloudflared` tunnel 1개다. Tailnet URL은 `https://alpaca-home.taile93291.ts.net/login`이다. stale Vite allowedHosts로 403이 났던 상태는 `scripts/start-tailscale-runtime.ps1` 재기동 후 `login` 200, `/api/health` dev/db/engine true, `/api/auth/config` 200으로 재검증됐다.
|
|
- `scripts/dev-up.ps1 -NoGateway -NoWeb`는 이제 gateway/web stale 정리를 건너뛰고 지정 `-ApiPort`의 API만 재기동한다. 검증 당시 8000 API-only 재기동 후 8001/8010/5173/9099/20241 listener가 보존됐다.
|
|
- Docker `vignette-dev-db`는 실행 중이고 DB는 accepting connections다. 단, 기존 컨테이너라 healthcheck가 없고 `POSTGRES_USER=vignette` 기반이다. `vignette_app` role은 NOBYPASSRLS로 존재하지만 현재 API startup DDL이 owner 권한을 요구하므로 런타임 app-role 전환은 마이그레이션 owner/런타임 role 분리 후 진행한다.
|
|
- 공개 런타임 재기동 스크립트:
|
|
- start: `powershell -NoProfile -ExecutionPolicy Bypass -File scripts\start-public-runtime.ps1`
|
|
- stop: `powershell -NoProfile -ExecutionPolicy Bypass -File scripts\stop-public-runtime.ps1`
|
|
|
|
## 이번 세션 완료
|
|
|
|
- 남아 있던 E2E seed persona 결합을 제거했다.
|
|
- `session-persistence`, `teacher`, `voice` 스펙은 `/api/personas`에서 실제 DB persona를 가져와 사용한다.
|
|
- `voice-success`만 DB-offline fixture라 `ALLOW_SEED_PERSONA_FALLBACK=true`와 `P1`을 의도적으로 유지하고 주석을 남겼다.
|
|
- 운영 설정 fail-closed를 강화했다.
|
|
- `ENVIRONMENT != dev`에서 dev login, seed fallback, 기본 session secret, OAuth 누락, localhost frontend/CORS를 설정 검증에서 거부한다.
|
|
- API lifespan은 DB 초기화 실패 시 dev에서만 degraded fallback을 허용하고, staging/prod에서는 시작 실패로 둔다.
|
|
- `SettingsConfigDict(populate_by_name=True)`를 추가해 테스트/코드에서 field name 기반 설정 생성이 가능하게 했다.
|
|
- `infra/docker-compose.yml`을 깨끗한 ASCII compose로 재작성했다.
|
|
- `ENVIRONMENT`, Google OAuth client id/secret, `OAUTH_REDIRECT_URI`, `CORS_ORIGINS`, `OPENAI_BASE_URL`을 API 컨테이너에 명시 주입한다.
|
|
- 기존 손상된 줄 때문에 `OPENAI_API_KEY`가 주석/중복으로 처리되던 문제를 제거했다.
|
|
- 기본 `FRONTEND_BASE_URL`은 `https://vignette.chanpaca.net`로 수정했다.
|
|
- `infra/.env.example`에 운영 필수 값을 보강했다.
|
|
- `ENVIRONMENT=prod`, `OAUTH_GOOGLE_CLIENT_ID`, `OAUTH_GOOGLE_CLIENT_SECRET`
|
|
- 기본 CORS에서 localhost 제거. 로컬 개발은 주석대로 `ENVIRONMENT=dev`와 localhost CORS를 별도 추가.
|
|
- admin UI 안정화.
|
|
- health card의 긴 engine readiness JSON이 모바일 폭을 밀어내지 않도록 줄바꿈 처리.
|
|
- backend admin health는 동적인 raw JSON detail 대신 안정적인 `Engine readiness failed` 문구를 내려준다.
|
|
- 전역 engine config를 바꾸는 `db-persistence` E2E는 `@single-run`으로 분리했다.
|
|
- 사용자 생성 후 UI가 서버 목록 reload를 끝내기 전에 카드를 찾던 E2E 타이밍을 안정화했다. 생성한 이메일로 검색한 뒤 실제 서버 응답 카드만 검증한다.
|
|
- 사용자 관리 UI는 DB 사용자 저장소가 durable하지 않으면 생성/수정/비활성화를 막는다.
|
|
- AI 운영 라벨은 `Claude CLI 게이트웨이`, `Anthropic API`, `OpenAI 호환`, `Solar`처럼 실제 어댑터명으로 표시한다.
|
|
- 설정의 AI 운영 패널은 `/admin/health` 기반 응답 생성 상태를 함께 보여주되, health 지연이 설정 폼 로딩을 막지 않도록 분리했다.
|
|
- 비개발 환경에서 `admin_engine_config` singleton row가 없으면 runtime default로 내려가지 않고 fail-closed 한다.
|
|
- 비개발 DB 장애 상태는 `임시 기록`이 아니라 저장소 중단으로 표시한다.
|
|
- public Google OAuth smoke 문서를 보강했다.
|
|
- `E2E_PUBLIC_AUTH=1`에서는 로컬 Vite 서버를 띄우지 않고 공개 웹을 대상으로 한다.
|
|
- storageState는 인증 쿠키를 포함하므로 `node_modules/.tmp` 아래 민감 파일로 취급한다.
|
|
- API session TTL은 현재 8시간이다.
|
|
- 공개 API prod 전환을 완료했다.
|
|
- `cloudflared` ingress를 `127.0.0.1:8000`에서 `127.0.0.1:8001`로 변경했다.
|
|
- `https://api-vignette.chanpaca.net/health`가 `environment:"prod"`, `db:true`, `engine:true`를 반환한다.
|
|
- public production-safe Playwright 게이트가 통과한다.
|
|
- 공개 런타임 start/stop 스크립트를 추가했다.
|
|
- `scripts/start-public-runtime.ps1`는 prod-safe env override로 API 8001을 띄우고 health를 검증한다.
|
|
- 기본 실행 시 `cloudflared`도 vignette config 기준으로 재시작한다.
|
|
- `scripts/stop-public-runtime.ps1`는 8001 API를 정리한다. `-StopCloudflared`를 붙이면 터널도 같이 정리한다.
|
|
- 공개 API 보안 경계를 보강했다.
|
|
- `apps/api/app/routes/personas.py`에 `CurrentPrincipal`을 붙여 persona catalog를 authenticated-only로 전환했다.
|
|
- 로컬 E2E `auth.spec.ts`에 비로그인 `/api/personas => 401` 회귀를 추가했다.
|
|
- public readiness gate는 빈 API request context로 비로그인 `/personas => 401`을 확인한다. storageState가 붙은 request fixture를 쓰지 않도록 처리했다.
|
|
- 공개 웹 API base fallback을 보강했다.
|
|
- `apps/web/src/lib/api.ts`는 `VITE_API_BASE`가 없고 host가 `vignette.chanpaca.net` 또는 `*.pages.dev`이면 `https://api-vignette.chanpaca.net`을 기본 API origin으로 사용한다.
|
|
- 이 변경으로 public web의 `/api/auth/config`가 SPA HTML로 떨어져 Google 버튼이 disabled 되는 문제를 피한다.
|
|
- 로컬 로그인 UX를 보강했다.
|
|
- `apps/web/src/pages/Login.tsx`는 로컬 origin에서 OAuth redirect URI가 공개 API이면 Google 버튼을 disabled 처리하고 `로컬 테스트 계정으로 로그인` 안내를 보여준다.
|
|
- `auth.spec.ts`에 로컬 테스트 계정 로그인 후 `/learn` redirect 회귀를 추가했다.
|
|
- 학습자 홈 기록 UX를 보강했다.
|
|
- `apps/web/src/pages/LearnerHome.tsx`는 세션이 0개인 사용자에게도 실제 서버 세션 0개를 기반으로 `기존 회기` 빈 상태와 0 카운트를 보여준다.
|
|
- 기록이 있을 때만 `has-session-records` 압축 레이아웃을 쓰도록 분리했다. 0회 사용자 모바일에서도 선택 내담자 정보, 새 회기 CTA, 기록 빈 상태가 문서 스크롤 없이 보인다.
|
|
- `apps/web/e2e/readiness.spec.ts`는 fake 12회/최근 8회 부재뿐 아니라 서버 기반 0회 빈 상태를 기대하도록 갱신했다.
|
|
- history의 반복 CTA는 `다시 시도` 대신 `다시 연습`으로 바꿔 기록 회고와 새 회기 시작 의미를 분리했다.
|
|
- 직접 세션 URL의 persona 우회 경로를 막았다.
|
|
- `LearnerHome`에서만 막던 `degraded` 또는 non-DB persona 차단을 `Session` 직접 진입 경로에도 적용했다.
|
|
- `/learn/session/:personaCode`로 직접 들어와도 DB 원본 persona가 아니면 `회기 시작` 버튼이 비활성화된다.
|
|
- desktop/mobile E2E에 degraded `seed_fallback` persona route mock 회귀를 추가했다.
|
|
- active session dense viewport를 보정했다.
|
|
- `apps/web/src/pages/session/session.css`에서 380px 이하/낮은 화면의 stage padding과 avatar 크기를 줄여 stage 내부 clipping을 없앴다.
|
|
- `session-layout.spec.ts` dense viewport desktop/mobile 회귀와 전체 Playwright에서 확인했다.
|
|
- active session 텍스트 턴 저장/표시 흐름을 실제 SSE 계약에 맞췄다.
|
|
- 프론트 `sessionApi.stream`은 실제 백엔드 계약인 `POST /sessions/{id}/stream`을 fetch stream으로 소비한다.
|
|
- `/stream` 요청이 거절되거나 SSE가 열린 뒤 error 이벤트로 끝나면 학습자 발화와 부분 내담자 응답을 transcript에 남기지 않고 입력값을 복원한다.
|
|
- 내담자 자막은 로컬 typewriter가 아니라 서버 token 이벤트로만 쌓는다.
|
|
- 백엔드 `/turn`과 `/stream`은 엔진 성공 전 learner turn/state를 append하지 않도록 순서를 바꿨고, `app.test_session_turn_persistence` 회귀로 검증했다.
|
|
- 음성 회기 실패 턴 저장/표시도 같은 기준으로 맞췄다.
|
|
- voice route는 엔진 응답 생성 성공 후에만 learner/client turn을 저장한다.
|
|
- 프론트는 음성 transcript를 pending으로 표시하고, 엔진 실패 시 pending transcript를 제거한다.
|
|
- 음성 degraded reason의 내부 `seed_fallback`/runtime store 표현은 사용자용 한국어 상태 문구로 바꿨다.
|
|
- admin health의 dev DB fallback 문구를 `임시 기록`이 아니라 `비영구 런타임 기록`으로 정리했다.
|
|
- Live2D demo fallback과 샘플 자산을 제거했다.
|
|
- Mao/Haru 샘플 모델과 Pixi/Cubism 런타임은 공개 배포물에서 제거했다.
|
|
- 세션 화면은 SVG persona avatar만 렌더링한다.
|
|
- Cloudflare edge에 남은 기존 `/live2d/*` 캐시를 막기 위해 Pages Function `apps/web/functions/live2d/[[path]].js`가 404를 반환한다.
|
|
|
|
## 검증 결과
|
|
|
|
- Web typecheck:
|
|
- `cd apps/web; fnm env --use-on-cd | Out-String | Invoke-Expression; fnm use 22.22.3; npm run typecheck`
|
|
- Passed
|
|
- Backend unit/compile:
|
|
- `cd apps/api; C:\Users\encep\AppData\Local\Programs\Python\Python311\python.exe -m unittest app.test_runtime_policy app.test_session_turn_persistence engine_gateway.test_gateway_model`
|
|
- `20 tests OK`
|
|
- `python -m compileall app engine_gateway`
|
|
- Passed
|
|
- Web production build:
|
|
- `cd apps/web; fnm use 22.22.3; npm run build`
|
|
- Passed
|
|
- Docker compose config:
|
|
- With dummy required env vars, `docker compose -f infra\docker-compose.yml --env-file infra\.env.example config --quiet`
|
|
- Passed
|
|
- Focused Playwright after fixes:
|
|
- `npx playwright test e2e/admin.spec.ts e2e/db-persistence.spec.ts e2e/voice-success.spec.ts --project=chromium-desktop --project=chromium-mobile --project=chromium-single-run`
|
|
- `10 passed`
|
|
- Admin manage-users focused rerun:
|
|
- `PLAYWRIGHT_BASE_URL=http://127.0.0.1:5175 PLAYWRIGHT_SKIP_WEB_SERVER=1 npx playwright test e2e/admin.spec.ts --project=chromium-desktop --project=chromium-mobile --grep "manage real server-known users"`
|
|
- `2 passed`
|
|
- Full Playwright:
|
|
- `cd apps/web; PLAYWRIGHT_HOST=127.0.0.1 npx playwright test`
|
|
- `72 passed` after public API/cloudflared was restored
|
|
- 참고: tunnel을 내린 직후 첫 전체 실행은 public login gate 2개만 `Cloudflare 1033`으로 실패하고 나머지 `70 passed`였다. `scripts\start-public-runtime.ps1`로 prod public API와 cloudflared를 복구한 뒤 전체 재실행에서 `72 passed`.
|
|
- Public auth project discovery:
|
|
- `E2E_PUBLIC_AUTH=1 npx playwright test --list --project=chromium-public-auth`
|
|
- `2 tests`: public production-safe config + real OAuth `/turn`
|
|
- Public production-safe gate:
|
|
- `E2E_PUBLIC_AUTH=1 npx playwright test e2e/public-auth-turn.spec.ts --project=chromium-public-auth --grep "production-safe"`
|
|
- `1 passed` on rerun
|
|
- Admin/settings focused E2E:
|
|
- `npx playwright test e2e/admin.spec.ts e2e/settings.spec.ts --project=chromium-desktop --project=chromium-mobile --project=chromium-single-run`
|
|
- Latest focused reruns: `admin.spec.ts` `8 passed`, `settings.spec.ts` `9 passed`
|
|
- Auth/readiness focused E2E:
|
|
- `npx playwright test e2e/auth.spec.ts e2e/readiness.spec.ts --project=chromium-desktop --project=chromium-mobile`
|
|
- `14 passed`
|
|
- Persona auth boundary:
|
|
- local unauth `http://127.0.0.1:8000/personas` -> 401
|
|
- public unauth `https://api-vignette.chanpaca.net/personas` -> 401
|
|
- Public runtime script:
|
|
- `powershell -NoProfile -ExecutionPolicy Bypass -File scripts\start-public-runtime.ps1`
|
|
- API 8001 health and public `https://api-vignette.chanpaca.net/health` both returned `environment:"prod"`, `db:true`, `engine:true`
|
|
- Public web deployment:
|
|
- `wrangler pages deploy dist --project-name vignette --branch main --commit-dirty=true`
|
|
- Production deployment `12da49f3`
|
|
- `https://vignette.chanpaca.net/` serves `assets/index-DEgzFAUm.js` and `assets/index-BGRtWhu_.css`
|
|
- `https://vignette.chanpaca.net/live2d/mao/Mao.model3.json`, Haru model, and Cubism core routes return 404
|
|
- Public login screen:
|
|
- `npx playwright test e2e/auth.spec.ts --project=chromium-desktop --grep "public login"`
|
|
- `1 passed`
|
|
- OAuth state is now HMAC-signed and bound to a HttpOnly state cookie; fake callback with state cookie now reaches `oauth=token_exchange_failed` instead of `oauth=invalid_state`, provider callback error redirects to `oauth=access_denied`, and callback failures log non-secret reason/status details in `api.public.err.log`.
|
|
- Login UI maps known OAuth/SAML failure reasons and displays `오류 코드: ...`; auth focused E2E is now 7 passed.
|
|
- Public runtime watchdog:
|
|
- `powershell -NoProfile -ExecutionPolicy Bypass -File scripts\watch-public-runtime.ps1 -CheckOnly`
|
|
- healthy: `engine, api, web-preview, cloudflared, public-api`
|
|
- `api-vnet.18ka.net` is not part of the default watchdog checks while DNS is not live; add it later with `-AdditionalPublicHealthUrls`.
|
|
- Local login on `127.0.0.1:5175`:
|
|
- `PLAYWRIGHT_BASE_URL=http://127.0.0.1:5175 PLAYWRIGHT_SKIP_WEB_SERVER=1 npx playwright test e2e/auth.spec.ts --project=chromium-desktop`
|
|
- `6 passed`
|
|
- `PLAYWRIGHT_BASE_URL=http://127.0.0.1:5175 PLAYWRIGHT_SKIP_WEB_SERVER=1 npx playwright test e2e/auth.spec.ts --project=chromium-mobile`
|
|
- `6 passed`
|
|
- focused local dev-login redirect: `1 passed`
|
|
- Learner home/history focused verification:
|
|
- `cd apps/web; npm run typecheck`
|
|
- Passed
|
|
- `PLAYWRIGHT_BASE_URL=http://127.0.0.1:5175 PLAYWRIGHT_SKIP_WEB_SERVER=1 npx playwright test e2e/learner.spec.ts e2e/readiness.spec.ts --project=chromium-desktop --project=chromium-mobile`
|
|
- `14 passed`
|
|
- Visual audit screenshots: `apps/web/node_modules/.tmp/ui-audit/learn-empty-desktop.png`, `apps/web/node_modules/.tmp/ui-audit/learn-empty-mobile-compact.png`
|
|
- Screenshot metrics confirmed desktop/mobile document overflow `x:0, y:0`, empty history visible, and real stats area present.
|
|
- Session dense viewport verification:
|
|
- `PLAYWRIGHT_BASE_URL=http://127.0.0.1:5175 PLAYWRIGHT_SKIP_WEB_SERVER=1 npx playwright test e2e/session-layout.spec.ts --project=chromium-desktop --project=chromium-mobile`
|
|
- `8 passed`
|
|
- Latest voice/session focused E2E:
|
|
- `PLAYWRIGHT_BASE_URL=http://127.0.0.1:5175 PLAYWRIGHT_SKIP_WEB_SERVER=1 npx playwright test e2e/voice.spec.ts e2e/voice-success.spec.ts e2e/session-layout.spec.ts --project=chromium-desktop --project=chromium-mobile --project=chromium-single-run`
|
|
- `15 passed`
|
|
- Latest learner/session/settings/admin focused E2E:
|
|
- `PLAYWRIGHT_BASE_URL=http://127.0.0.1:5175 PLAYWRIGHT_SKIP_WEB_SERVER=1 npx playwright test e2e/learner.spec.ts e2e/session-layout.spec.ts e2e/settings.spec.ts e2e/admin.spec.ts --project=chromium-desktop --project=chromium-mobile --project=chromium-single-run`
|
|
- `37 passed`
|
|
|
|
## 아직 못 끝낸 것
|
|
|
|
- 공개 Google OAuth 실제 `/turn` proof는 아직 없다.
|
|
- 이유: `E2E_PUBLIC_STORAGE_STATE=apps/web/node_modules/.tmp/public-auth.json`가 아직 확보되지 않았다.
|
|
- 사용자가 Playwright codegen 브라우저에서 Google 로그인 후 storageState를 저장해야 한다.
|
|
- 2026-06-26 15:18 KST 기준 `apps/web/node_modules/.tmp/public-auth.json`은 없다. codegen 창/프로세스가 남아 있으면 로그인 완료 후 창을 닫아 저장을 완료하면 된다.
|
|
- 공개 API `environment:"dev"` 문제는 이번 세션에서 해결했다. cloudflared가 prod API인 `127.0.0.1:8001`을 보도록 변경했고 public gate로 확인했다.
|
|
- Google Console 설정은 브라우저 로그인 세션이 필요하다. 막히면 사용자가 로그인해 주기로 했다.
|
|
- 현재 worktree는 문서 상태 업데이트만 남아 있다. 관련 없는 사용자 변경을 되돌리지 말 것.
|
|
|
|
## 다음 세션 우선순위
|
|
|
|
1. Google OAuth Console을 확인한다.
|
|
- Authorized redirect URI: `https://api-vignette.chanpaca.net/auth/callback`
|
|
- Authorized JavaScript origin: `https://vignette.chanpaca.net`
|
|
- 앱/도메인 설정은 `hs.ac.kr`, `twentyoz.kr` 계정만 서버 claim 검증으로 허용한다. Google Console의 authorized domains와 이메일 도메인 제한은 다른 개념이다.
|
|
2. storageState를 캡처하고 public `/turn` 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`
|
|
3. UI/UX는 계속 `docs/DESIGN_CONCEPT.md`를 따른다.
|
|
- learner home은 빈 사용자에게 fake 통계/기록을 보여주지 않는다. 0회 상태는 실제 서버 기록 0개로 `기존 회기` 빈 상태를 보여주는 현재 구현을 유지한다.
|
|
- active learning session은 전체 화면, 문서 스크롤 없음이 원칙이다.
|
|
- 실제 session history는 `기존 회기`, `이어하기`, `기록/리뷰`, `다시 연습`, `새 회기 시작` 흐름으로 유지한다.
|
|
4. 다음 배포 전 `admin/engine-config`를 다시 확인한다.
|
|
- 의도된 현재값이 `claude_cli / http://127.0.0.1:9099 / gateway-default`인지 확인.
|
|
- E2E가 engine config를 건드리므로 배포 전 실제 운영값을 반드시 재확인한다.
|
|
|
|
## 로컬 실행 명령
|
|
|
|
Engine gateway:
|
|
|
|
```powershell
|
|
cd D:\workspace\vignette\apps\api
|
|
C:\Users\encep\AppData\Local\Programs\Python\Python311\python.exe -m uvicorn engine_gateway.gateway:app --host 127.0.0.1 --port 9099
|
|
```
|
|
|
|
API:
|
|
|
|
```powershell
|
|
cd D:\workspace\vignette\apps\api
|
|
$env:ENGINE_URL="http://127.0.0.1:9099"
|
|
$env:ENGINE_MODE="claude_cli"
|
|
$env:ENVIRONMENT="dev"
|
|
$env:AUTH_DEV_LOGIN_ENABLED="true"
|
|
C:\Users\encep\AppData\Local\Programs\Python\Python311\python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8000
|
|
```
|
|
|
|
Public API process:
|
|
|
|
```powershell
|
|
cd D:\workspace\vignette
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\start-public-runtime.ps1
|
|
```
|
|
|
|
Web:
|
|
|
|
```powershell
|
|
cd D:\workspace\vignette\apps\web
|
|
fnm env --use-on-cd | Out-String | Invoke-Expression
|
|
fnm use 22.22.3
|
|
npm run dev -- --host localhost --port 5173
|
|
```
|
|
|
|
## 최근 주요 변경 파일
|
|
|
|
- `apps/web/e2e/support.ts`
|
|
- `apps/web/e2e/auth.spec.ts`
|
|
- `apps/web/e2e/learner.spec.ts`
|
|
- `apps/web/e2e/session-layout.spec.ts`
|
|
- `apps/web/e2e/session-review.spec.ts`
|
|
- `apps/web/e2e/session-persistence.spec.ts`
|
|
- `apps/web/e2e/teacher.spec.ts`
|
|
- `apps/web/e2e/voice.spec.ts`
|
|
- `apps/web/e2e/voice-success.spec.ts`
|
|
- `apps/web/e2e/public-auth-turn.spec.ts`
|
|
- `apps/web/e2e/db-persistence.spec.ts`
|
|
- `apps/web/e2e/README.md`
|
|
- `apps/web/playwright.config.ts`
|
|
- `apps/web/src/pages/Admin.tsx`
|
|
- `apps/web/src/pages/Login.tsx`
|
|
- `apps/web/src/pages/Session.tsx`
|
|
- `apps/web/src/pages/Settings.tsx`
|
|
- `apps/web/src/pages/session/session.css`
|
|
- `apps/web/src/components/avatar/ClientAvatar.tsx`
|
|
- `apps/web/src/components/avatar/persona.ts`
|
|
- `apps/api/app/config.py`
|
|
- `apps/api/app/main.py`
|
|
- `apps/api/app/routes/admin.py`
|
|
- `apps/api/app/routes/personas.py`
|
|
- `apps/api/app/routes/users.py`
|
|
- `apps/api/app/routes/voice.py`
|
|
- `apps/api/app/test_session_turn_persistence.py`
|
|
- `apps/api/app/test_runtime_policy.py`
|
|
- `infra/docker-compose.yml`
|
|
- `infra/.env.example`
|
|
- `docs/HANDOFF.md`
|
|
- `docs/dev_dashboard.html`
|
|
- `apps/web/src/lib/api.ts`
|