vignette/docs/ops/evidence/nas-prod-deploy-2026-09-01.json

93 lines
5.6 KiB
JSON

{
"title": "NAS vignette-prod 정식 배포 (A 경로)",
"date": "2026-09-01",
"source": {
"forgejo_master": "dce85620",
"deploy_commits": [
"72353ecd 회기 연속성과 멀티 케이스 계약을 영속화",
"f1b80676 케이스 이어하기 UI와 공통 탭·이미지 복구를 반영",
"d6d9dc5f NAS 정식 스택과 배포 파이프라인 도구를 고정",
"ed3252ed 상태판·가이드와 검증 증거를 동기화",
"8931e64b NAS compose를 운영 실물 정의로 동기화",
"5a74302e 마이그레이션 22의 name 배열 비교 캐스트를 교정",
"dce85620 게이트웨이 openai provider 경로를 정식 소스로 복원"
],
"build_host": "yunchan-nas (Forgejo http clone, git container)",
"clone_verification": "HEAD dce85620 == Forgejo master"
},
"pre_deploy_backup": {
"db_dump": "/volume1/docker/vignette-prod/backups/pre-deploy-8931e64b-20260901-114915.dump",
"dump_bytes": 11036928,
"dump_sha256": "cab6826b6f4b09d7dc87c68103310daa38d367db4e05791fd925d79c0c1e53e2",
"dump_toc_entries": 1783,
"env_backup": "private/env.nas.before-deploy-8931e64b-20260901",
"rollback_images": {
"api": "vignette-nas-api:goal-nas-ssot-20260830 (sha256:7d39d211...)",
"web": "vignette-nas-web:goal-nas-ssot-20260830 (sha256:3998d90b...)"
}
},
"db_migrations": {
"duplicate_active_cleanup": {
"closed_rows": 30,
"policy": "learner-persona 쌍마다 최신 활성 회기만 유지, 이전 활성은 ended_at=now()로 종료 (데이터 삭제 없음)",
"receipt": "/volume1/docker/vignette-prod/receipts/stale-active-cleanup-20260901.csv",
"remaining_duplicate_pairs": 0
},
"applied": ["20_public_bootstrap_ticket_events.sql", "21_single_active_session.sql", "22_case_profile_multi_case.sql"],
"mig21_index_valid": true,
"mig22_fix": "attname name[] vs text[] 비교 캐스트 결함을 발견·교정 (5a74302e)"
},
"deployed_runtime": {
"api_engine_image": "vignette-nas-api:dce85620 (sha256:b0ea1ce8a047d36b63b45b1bca795d1f5687e7c9fc0deafea0827684d1de6ffc)",
"web_image": "vignette-nas-web:8931e64b (sha256:8040a6541285a95e180d81c9f06c5b22711849fa02029e824104ac7fac057f5c)",
"db_container": "미교체 (Up 45h 연속, pgdata 외부 볼륨 보존)",
"gateway_regression_found": "master에 openai provider 구현이 없어 첫 컷오버가 degraded — 구 운영 이미지에서 코드 이식·테스트 71 passed 후 재배포로 해소"
},
"post_deploy_readiness": {
"public_health": "status=ok, db=true, engine=true, engine_mode=openai, provider OK",
"openapi": 200,
"auth_me_unauthenticated": 401,
"dev_login": 404,
"internal_loopback_18080": 200,
"containers": "api/engine/db healthy, web/proxy up"
},
"data_preservation": {
"before": {"app_user": 1380, "sessions": 618, "turns": 1743, "case_profile": 565, "active_sessions": 437},
"after": {"app_user": 1380, "sessions": 618, "turns": 1743, "case_profile": 565},
"note": "active_sessions는 중복 정리 30행 종료로 437→407 (행 삭제 0)"
},
"public_web_pages": {
"deployment": "9224a64b.vignette-b1q.pages.dev (production, branch main)",
"new_entry": "index-BFKGXJQi.js / index-DT8YbZqu.css (200, application/javascript)",
"previous_entry_preserved": "index-Bm30Ozeb.js = 200",
"preserved_prior_assets": 175
},
"browser_e2e_readonly": {
"login_screen": "렌더 정상 (단일 Google CTA)",
"console_errors": "비로그인 /auth/me 401 1건뿐 (예상 동작)",
"oauth_redirect": "accounts.google.com, redirect_uri=https://api-vignette.chanpaca.net/auth/callback, PKCE S256, scope openid email profile"
},
"oauth_secret_fix": {
"symptom": "google_oauth_callback_failed token_exchange_failed 401 invalid_client",
"cause": "NAS env.nas의 OAUTH_GOOGLE_CLIENT_SECRET이 잘못된 값(secret sha16 ef2cc311c2f2ce39)",
"fix": "동작 실적 있는 PC 런타임 env의 secret(sha16 77becad9b95f2131)으로 교체 후 api 재생성 — 로그인 성공",
"backup": "private/env.nas.before-oauth-secret-fix-20260901"
},
"headful_closed_loop": {
"login": "소유자 실제 Google 계정 로그인 (자격증명은 소유자 직접 입력) → auth_session 1건 생성, 관리자 권한 유지",
"data_visibility": "기존 회기 20건 목록 표시 (7/13~8/31, 34턴·40턴 회기 포함) — 이전 데이터 보존 확인",
"guards": "활성 회기 존재 시 새 사례 시작 차단 문구, 시간 만료 회기 유예 후 서버 발화 거부 (fail-closed)",
"fresh_case": "P1 새 사례 시작 → session 9fb604a1-cb41-4138-bfee-b52b8475913e 생성 (migration 22 운영 실증)",
"pre_pulse": "목표/과업/유대 3관점 잠금 후 첫 발화 준비",
"turn": "학습자 발화 1건 → AI 내담자(P1 서연, openai 엔진) 응답 1건 SSE 수신·저장",
"end_review": "회기 종료 → 리뷰 페이지 실제 축어록 2개 기반 생성, 탭 UI(축어록/피드백/워크시트) 정상",
"db_delta": "sessions 618→619, turns 1743→1745, case_profile 565→566, 새 회기 ended_at 기록",
"admin_console": "현재 서비스 상태·리소스 5/5 렌더, 페이지 오류 0",
"screenshot": "prod-e2e-review-2026-09-01.png"
},
"backup_automation": {
"service": "db-backup 사이드카 (postgres 이미지, 일일 pg_dump -Fc → pg_restore -l 검증 → 원자 mv, 보존 14일)",
"first_dump": "vignette-20260901-033517.dump 11,202,927 bytes OK",
"owner_password_alignment": "볼륨 실비번과 env.nas POSTGRES_PASSWORD 불일치를 ALTER ROLE로 일치화 (socket 경유)"
}
}