feat: 운영 안정성과 세션 음성 경험 개선
This commit is contained in:
parent
facc4ad2d9
commit
c788343467
95 changed files with 8431 additions and 1785 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# Vignette Handoff
|
||||
|
||||
> Updated: 2026-07-15 KST. 새 세션은 이 문서와 `docs/DESIGN_CONCEPT.md`를 먼저 읽고 이어가면 된다.
|
||||
> Updated: 2026-07-30 KST. 새 세션은 이 문서와 `docs/DESIGN_CONCEPT.md`를 먼저 읽고 이어가면 된다.
|
||||
|
||||
## 현재 상태
|
||||
|
||||
|
|
@ -10,8 +10,9 @@
|
|||
- 로컬 engine gateway 기본 포트: `http://127.0.0.1:9099`
|
||||
- 공개 웹: `https://vignette.chanpaca.net`
|
||||
- 공개 API: `https://api-vignette.chanpaca.net`
|
||||
- 최신 앱 배포 소스: 2026-07-15 전 저장소 리팩터 거버넌스 P1~P8, 계약/런타임/디자인 SSOT와 대형 화면 구조 분리, 회기·관리자·설정 회귀 수정까지 포함한 `master` 커밋 `3dfddcac`.
|
||||
- 최신 Cloudflare Pages production deploy: 2026-07-15 manual deploy `https://9fa684e5.vignette-b1q.pages.dev`, branch `main`, custom domain assets `assets/index-FVj73yvV.js` + `assets/index-B3HPjbqc.css`. 커스텀 도메인과 preview가 같은 엔트리 번들을 서빙하고, 공개 API는 prod/db/engine 200, 비인증 `/personas` 401, Google OAuth 시작 302다.
|
||||
- 최신 앱 배포 소스: base commit `facc4ad2`의 현재 dirty worktree를 `--commit-dirty=true`로 표시해 빌드했다. AI provider capability 변경과 작업트리의 현재 웹 변경이 포함됐으며 별도 commit/push는 하지 않았다.
|
||||
- 최신 Cloudflare Pages production deploy: 2026-07-30 guarded manual deploy `https://2f52f8e3.vignette-b1q.pages.dev` (`2f52f8e3-f992-441f-ada4-f6396cbb1a2b`), branch `main`, custom domain assets `assets/index-B54GMBSf.js` + `assets/AdminAi-ClAJvCvx.js`. 현재와 이전 4세대 엔트리를 JavaScript 200으로 보존했고, 공개 API는 prod/db/engine 정상이다.
|
||||
- 관리자 AI 엔진 capability: 공급자 6종을 드롭다운으로 선택하고 설치·인증 상태에 따라 live 모델과 추론 강도만 선택한다. 공개 인증 E2E에서 Codex 7개 모델의 기본 `gpt-5.6-terra / medium`, Agy 11개 모델의 기본 `gemini-3.6-flash-high / high`를 확인했으며 설정은 저장하지 않았다. Anthropic API는 키가 없어 fail-closed unavailable이다.
|
||||
- Google OAuth 허용 이메일 도메인: `hs.ac.kr`, `twentyoz.kr`
|
||||
- 최신 백엔드 회귀: API `400 passed`, engine gateway `29 passed`; 프론트 전체 Playwright fixture `166/166` + DB/engine/provider 직렬 `49/49`로 합계 `215/215 passed`.
|
||||
- X1 재귀학습 export 1차: `scripts/export-recursive-dataset.py` 기본 read-only dry-run, `--write-dataset` 명시 시에만 `ds.*` write, approved export는 steward/legal/IAA gate 없으면 거부.
|
||||
|
|
@ -30,7 +31,10 @@
|
|||
- 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은 후속.
|
||||
- 페르소나 저작/P4~P7 적재 2차: `data/personas/P4.json`~`P7.json`을 저장소 관리 `PersonaCard`로 읽어 `materialize_seed_personas()`와 seed fallback catalog에 포함했다. 검증: `python -m pytest app/test_persona_review.py -q` 22 passed, 로컬 dev DB materialize 결과 `approved_codes=P1,P2,P3,P4,P5,P6,P7`, 인증된 로컬 `GET /personas`도 `P1..P7` 반환.
|
||||
- Google OAuth 진단 1차: provider callback error는 `access_denied`/`provider_error`로 분리하고, 로그인 화면은 실패 reason code를 함께 표시한다. 실제 Google 계정 완료 proof는 아직 owner 로그인/storageState가 필요하다.
|
||||
- 관리자 기본 진입 경로와 blank diagnostics: `initialPathForUser()`가 pending/onboarding/admin-entitled landing을 소유한다. 관리자 콘솔 접근권이 있는 계정은 primary role이 learner/teacher여도 `/` 또는 로그인 완료 뒤 `/admin`으로 들어간다. `App.tsx`는 pathname 변경마다 document scroll을 0으로 복원해 긴 관리자 화면에서 짧은 `/admin/access`로 이동해도 sticky shell만 보이는 빈 화면을 만들지 않는다. 관리자 화면은 `/admin/users`와 `/admin/tickets` payload 계약 위반을 안전하게 정규화하고 `관리자 데이터 진단`으로 깨진 필드/path/asset을 표시한다. 앱 route-level error boundary도 렌더 예외를 full white page 대신 진단 화면으로 대체하며, 0-height main도 진단 패널로 노출한다. `index.html`에는 React/module 실행 자체가 실패해도 3.5초 뒤 `Vignette 화면 진단`을 body에 직접 띄우는 boot watchdog이 있고, 같은 진단을 `/client-diagnostics`로 보내 API 로그에 남긴다. 검증: `npm run typecheck`, `npm run build`, `python -X utf8 -B -m pytest -p no:cacheprovider app/test_client_diagnostics.py -q`, `npx playwright test e2e/admin.spec.ts --project=chromium-desktop --workers=1 --grep "admin route guards"` 5 passed, dist file JS-missing watchdog smoke passed, custom domain 새 asset 확인.
|
||||
- 관리자 기본 진입 경로와 blank diagnostics: `initialPathForUser()`가 pending/onboarding/admin-entitled landing을 소유한다. 관리자 콘솔 접근권이 있는 계정은 primary role이 learner/teacher여도 `/` 또는 로그인 완료 뒤 `/admin`으로 들어간다. `App.tsx`는 pathname 변경마다 document scroll을 0으로 복원해 긴 관리자 화면에서 짧은 `/admin/access`로 이동해도 sticky shell만 보이는 빈 화면을 만들지 않는다. 최초 `/auth/me`는 요청별 5초 상한과 짧은 3회 재시도를 사용하며, 재부팅 중 연결 실패는 로그아웃/권한 상실로 오인하지 않고 `AuthRestoreGate`에서 같은 세션으로 다시 연결한다. 설정 기반 슈퍼 관리자/관리자 entitlement는 로그인과 세션 복원 시 `app.app_user.admin_access`에도 영속화해 재기동 뒤 설정 판정만 의존하지 않는다. OAuth upsert의 nullable 관리자 플래그는 PostgreSQL `boolean`으로 명시 캐스팅하며 non-dev 저장 실패는 원래 DB 예외를 로그에 남기고 503으로 닫는다. primary role 화면의 사이드바에도 `운영 콘솔` 진입점을 유지해 학습자/교수자 작업면으로 이동한 뒤 관리자 페이지가 사라지지 않는다. 관리자 화면은 `/admin/users`와 `/admin/tickets` payload 계약 위반을 안전하게 정규화하고 `관리자 데이터 진단`으로 깨진 필드/path/asset을 표시한다. 앱 route-level error boundary도 렌더 예외를 full white page 대신 진단 화면으로 대체하며, 0-height main도 진단 패널로 노출한다. `index.html`에는 React/module 실행 자체가 실패해도 3.5초 뒤 `Vignette 화면 진단`을 body에 직접 띄우는 boot watchdog이 있고, 같은 진단을 `/client-diagnostics`로 보내 API 로그에 남긴다. 2026-07-30 Cloudflare Pages production `1332ccbe`는 새 엔트리 `index-D4Twx0A1.js`와 직전 3세대 자산을 함께 게시했다. 실제 Google 슈퍼 관리자 사용자 행에 연결한 15분 임시 세션으로 관리자 5경로, primary learner 화면의 운영 콘솔 복귀, restored-tab 복원을 공개 사이트에서 4 passed로 확인했고 임시 세션은 즉시 삭제했다. 이어 관리자 권한 영속화 SQL의 타입 추론 회귀를 수정해 API PID `40992`로 재시작했고, 같은 실제 사용자 행으로 신규 세션 생성→공개 `/auth/me` 200(`admin_access=true`, `super_admin=true`, approved)까지 재검증한 뒤 세션을 폐기했다.
|
||||
- 2026-07-30 관리자 실제 빈 본문 후속: 실제 스크롤 소유자는 document가 아니라 `.vg-main`이므로 `AppShell`이 mount·pathname 변경·`pageshow`마다 내부 스크롤을 직접 0으로 복원한다. 이전 E2E는 `window.scrollY`만 조작해 잘못된 대상을 통과시켰고, 정확한 `.vg-main.scrollTop=900` 재현은 수정 전 2 failed·수정 후 desktop/mobile 8 passed였다. 진단 visible node도 `.vg-main` viewport 교차를 요구한다. Cloudflare Pages production `f323a41d`는 `index-Dun9umCY.js`와 현재 포함 직전 4세대 자산을 서빙한다. 실제 Google 슈퍼 관리자 사용자 행 기반 공개 5경로·learner→운영 콘솔·내부 scrollTop 복원 4 passed와 관리자 홈 픽셀 캡처를 직접 확인하고 임시 세션을 폐기했다. API PID는 `40992`, 공개 health는 prod·db=true·engine=true다.
|
||||
- 2026-07-30 관리자 광고 차단기 blank 근본 수정: 실제 사용자 캡처와 같은 셸-only 화면은 권한/API/스크롤이 아니라 공식 EasyList의 `.ad-root`·`.ad-section` cosmetic rule이 관리자 `ad-*` 클래스를 광고로 오인한 결과였다. 같은 `display:none!important` 규칙을 주입해 첨부 화면을 그대로 RED 재현한 뒤 관리자 DOM/CSS 487곳을 `vgops-*`로 교체했다. 루트/진단은 `data-vignette-admin-*` marker를 쓰고 HTML watchdog은 marker의 실제 computed visibility까지 검사한다. 로컬 EasyList 회귀 1/1, admin guards 12/12, admin full-sweep 20/20, admin layout 3/3, session-layout 8/8, typecheck가 통과했다. production `0a339b77` 배포 뒤 실제 Google 슈퍼 관리자 사용자 행의 임시 세션에서 같은 EasyList 규칙을 켠 채 운영 홈·AI 운영·사용자·권한·티켓 5경로가 모두 visible, legacy `ad-*` class 0, boot/admin diagnostic 0, 브라우저 오류 0임을 확인하고 세션을 즉시 폐기했다.
|
||||
- 같은 장애의 재유입 차단: `apps/web/scripts/check-cosmetic-filter-safety.mjs`가 프로덕션 소스 81개와 `index.html`을 검사하고 `ad-*`/`ads-*`/`advert*`/`sponsor*` UI namespace를 발견하면 `npm run build`와 `npm run lint`를 실패시킨다. 탐지기 자체의 RED/GREEN fixture도 매 실행에 포함된다. 로컬 EasyList E2E는 첫 watchdog 판정 뒤에도 실제 root/heading이 보이고 legacy class가 0인지 검사하며, 공개 E2E는 같은 필터 아래 관리자 5경로를 모두 검증하도록 승격했다. 이 gate를 통과한 격리 빌드를 production `1b3b6d5b`로 다시 게시했고 custom/preview entry 일치, Admin JS SHA-256 일치, `vgops-root` 존재, `ad-root` 부재를 공개 응답 바이트로 확인했다.
|
||||
- `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`로 떠 있다.
|
||||
|
|
@ -182,6 +186,8 @@
|
|||
- `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`.
|
||||
- 2026-07-30부터 엔진 readiness와 관리자·인증 제어면을 분리한다. 엔진 단독 장애는 API·웹·터널 재시작을 유발하지 않는다. 실운영에서 API PID `36824` 유지, 예약 작업 `LastTaskResult=0`, failcount `0`을 확인했다.
|
||||
- API 코드 배포는 `start-public-runtime.ps1 -ForceApiRestart -SkipEngineRestart -SkipWebRestart -SkipCloudflaredRestart`로 API만 교체한다. 2026-07-30 관리자 entitlement 수정 배포 뒤 public `/health`는 `prod/db/engine=true`다.
|
||||
- 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`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue