외부 계정 수동 등록 허용
This commit is contained in:
parent
bd389a97cc
commit
8ed185ce6c
9 changed files with 3450 additions and 1484 deletions
|
|
@ -8,7 +8,7 @@ Vignette(AI 심리상담 시뮬레이션 훈련 플랫폼)를 로컬에서 띄
|
|||
- `apps/api` — FastAPI 백엔드 (Python)
|
||||
- `apps/api/engine_gateway` — AI 턴 생성용 엔진 게이트웨이(별도 프로세스, 포트 9099)
|
||||
- `apps/web` — React 19 + Vite 프런트엔드
|
||||
- `infra` — Docker Compose 스택(pgvector pg16 + api + web + rag + proxy)
|
||||
- `infra` — Docker Compose 스택(pgvector pg16 + api + web + proxy)
|
||||
- `scripts` — 운영/점검 스크립트
|
||||
|
||||
핵심 구성요소: 학습자(상담수련생)가 AI 내담자 페르소나와 회기를 진행하고, 종료 후 회기 리뷰 피드백을 받는다.
|
||||
|
|
@ -87,7 +87,7 @@ python -m pip install -r apps\api\requirements.txt
|
|||
```
|
||||
|
||||
`apps/api/requirements.txt`는 `fastapi`, `uvicorn[standard]`, `asyncpg`, `pydantic`,
|
||||
`pydantic-settings`, `python-multipart`, `httpx`, `sse-starlette`를 포함한다.
|
||||
`pydantic-settings`, `python-multipart`, `httpx`, `sse-starlette`를 exact version으로 고정한다.
|
||||
엔진 게이트웨이도 `fastapi`+`uvicorn`만 쓰므로 위 설치로 함께 충족된다.
|
||||
(Presidio PII 마스킹은 선택 의존성이라 기본 제외 — 없으면 정규식 폴백으로 자동 degrade.)
|
||||
|
||||
|
|
@ -117,7 +117,10 @@ npm install
|
|||
| `ENGINE_URL` | `http://127.0.0.1:9099` | 엔진 게이트웨이 베이스 URL |
|
||||
| `ENGINE_MODE` | `claude_cli` | 엔진 provider 라우팅 |
|
||||
| `AUTH_DEV_LOGIN_ENABLED` | `true` | dev-login 엔드포인트 활성화 |
|
||||
| `AUTH_ALLOWED_EMAIL_DOMAINS` | `["hs.ac.kr","twentyoz.kr"]` | 로그인 허용 이메일 도메인(dev-login 포함 검증) |
|
||||
| `AUTH_ALLOWED_EMAIL_DOMAINS` | `["hs.ac.kr","twentyoz.kr"]` | 기본 로그인 허용 이메일 도메인(dev-login 포함 검증). `/admin/users`에 미리 등록된 정확한 이메일은 도메인 밖이어도 예외로 로그인 가능 |
|
||||
| `AUTH_SUPER_ADMIN_EMAILS` | `["yunchan@twentyoz.kr","hoonjungkoo@hs.ac.kr"]` | 학습자·교수자·관리자 공간 접근과 승인 상태를 부여할 슈퍼 관리자 이메일 |
|
||||
| `AUTH_APPROVED_EMAILS` | `[]` | 신규 외부 로그인 시 pending 없이 바로 승인할 이메일 allowlist |
|
||||
| `AUTH_NEW_USER_DEFAULT_STATUS` | `pending` | Google/SAML 신규 사용자의 기본 승인 상태. `dev:` 로그인은 로컬/E2E 편의를 위해 자동 승인 |
|
||||
| `AUTH_EMAIL_COHORT_MAP` | `{}` | 특정 이메일을 cohort id로 매핑한다. 값은 comma-separated 문자열도 허용 |
|
||||
| `AUTH_DOMAIN_COHORT_MAP` | `{}` | 이메일/Google hosted domain을 cohort id로 매핑한다. Google/SAML/dev-login 세션 `cohort_ids`에 반영 |
|
||||
| `VIGNETTE_VOICE_POC_SAMPLE_TTS` | `false` | P1 무참조 샘플 음성을 `/voice/ws` TTS에 연결하는 개발 전용 플래그. 마이크/STT는 `OPENAI_API_KEY` 필요, 프로덕션 금지 |
|
||||
|
|
@ -136,7 +139,7 @@ python -m uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload
|
|||
|
||||
### 2.3 seed 페르소나로 띄우기 (선택)
|
||||
|
||||
기본값은 seed 미적재(`AUTO_SEED_PERSONAS=false`)다. 내장 페르소나(P1~P3)를 메모리/DB에 올려서
|
||||
기본값은 seed 미적재(`AUTO_SEED_PERSONAS=false`)다. 시스템 페르소나(P1~P3)와 저장소 페르소나(P4~P7)를 DB 카탈로그에 올려서
|
||||
바로 회기를 만들고 싶으면 실행 전에 두 플래그를 켠다.
|
||||
|
||||
```powershell
|
||||
|
|
@ -147,6 +150,7 @@ python -m uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload
|
|||
```
|
||||
|
||||
`main.py` lifespan은 `settings.auto_seed_personas`가 켜져 있을 때만 `materialize_seed_personas()`를 호출한다.
|
||||
이 호출은 `(code, version)` 누락분만 insert하며, 교수자가 수정한 DB 저작본이나 `archived` 보관본을 덮어쓰거나 재노출하지 않는다.
|
||||
(또는 `apps/api/.env`에 두 키를 `true`로 적어도 된다.)
|
||||
|
||||
### 2.4 DB 없이 degraded 기동 (정상 동작)
|
||||
|
|
@ -188,10 +192,19 @@ curl.exe http://127.0.0.1:8000/health
|
|||
- 본문: `{ "email": ..., "role": "learner|teacher|admin", "display_name": ... }`
|
||||
- `role` 기본값은 `learner`.
|
||||
- 성공 시 `__Host-vignette_sid` 쿠키(및 dev 전용 `vignette_sid` 쿠키)를 세팅한다.
|
||||
- dev-login 사용자는 로컬/E2E 흐름 유지를 위해 `account_status=approved`로 생성된다.
|
||||
- Google/SAML 신규 사용자는 기본적으로 `account_status=pending`이며, 승인 전에는 `/pending` 화면만 볼 수 있다.
|
||||
관리자 콘솔 `/admin/users`의 가입 승인 탭에서 `approved`로 바꾸면 역할 홈에 접근한다.
|
||||
- 신규 사용자 또는 온보딩 미완료 사용자는 로그인 직후 `/onboarding`에서 닉네임, 자기소개,
|
||||
선택 아바타 이미지, 이름, 소속, 학과, 학년/직위, 전화번호, 주소/수령지와 약관·개인정보
|
||||
동의를 저장해야 역할 홈으로 이동한다. 학습자 회기 시작은 온보딩 완료와 동의가 모두 있어야 한다.
|
||||
- 프로필 아바타 업로드는 API 작업 디렉터리 기준 `USER_UPLOAD_DIR`(기본 `uploads`) 아래
|
||||
`profile-avatars/`에 저장되고, `/uploads/profile-avatars/...` URL로 서빙된다.
|
||||
|
||||
> 주의(이메일 도메인): dev-login도 `validate_google_identity_domain`을 거치므로 **이메일 도메인이
|
||||
> `AUTH_ALLOWED_EMAIL_DOMAINS`에 있어야 한다**. 예: `learner@hs.ac.kr`. 다른 도메인이면
|
||||
> `403 email domain is not allowed`.
|
||||
> 주의(이메일 도메인): dev-login도 기본적으로 `validate_google_identity_domain`을 거치므로
|
||||
> 이메일 도메인이 `AUTH_ALLOWED_EMAIL_DOMAINS`에 있어야 한다. 예: `learner@hs.ac.kr`.
|
||||
> 단, 관리자가 `/admin/users`에 미리 등록한 정확한 이메일은 도메인 밖이어도 로그인할 수 있다.
|
||||
> 미등록 외부 도메인은 계속 `403 email domain is not allowed`.
|
||||
|
||||
### 3.1 PowerShell(권장) — Invoke-RestMethod + 세션 쿠키
|
||||
|
||||
|
|
@ -233,6 +246,33 @@ curl.exe http://127.0.0.1:8000/auth/me -b cookies.txt
|
|||
> 로컬/Tailnet 테스트는 dev-login을 사용한다. Google OAuth는 공개 도메인
|
||||
> `https://vignette.chanpaca.net`에서만 실제 계정 흐름으로 검증한다.
|
||||
|
||||
### 3.4 라이브 코칭 source pack RAG 색인
|
||||
|
||||
`data/kb/live_coaching_workbook_0615.json`와 `data/kb/live_coaching_sources/*.json`는 라이브 코칭의
|
||||
기본 근거 source pack이다. API가 DB와 연결된 상태라면 관리자 dev-login 쿠키로 같은 자료를 RAG KB에도
|
||||
증분 색인할 수 있다.
|
||||
|
||||
이 디렉터리는 Docker 이미지가 `COPY data ./data`로 포함하는 런타임 입력이다. 다른 머신에 심기 전에는
|
||||
source pack 파일이 워크트리에 존재하는지 반드시 확인한다. commit하지 않는 배포 방식이면 같은 경로로 별도
|
||||
provision해야 하며, 아래 preflight가 없으면 실패하게 둔다.
|
||||
|
||||
```powershell
|
||||
python scripts\check-deploy-preflight.py --skip-db --env-file infra\.env.example --allow-placeholder-secrets
|
||||
```
|
||||
|
||||
```powershell
|
||||
$body = '{"email":"admin@hs.ac.kr","role":"admin","display_name":"로컬 관리자"}'
|
||||
Invoke-RestMethod -Method Post -Uri http://127.0.0.1:8000/auth/dev-login `
|
||||
-ContentType 'application/json' -Body $body -SessionVariable adminSession
|
||||
|
||||
Invoke-RestMethod -Method Post `
|
||||
-Uri http://127.0.0.1:8000/kb/live-coach/source-packs/sync `
|
||||
-WebSession $adminSession
|
||||
```
|
||||
|
||||
응답의 `skipped_unchanged`가 0보다 크면 content_hash가 동일해 재색인을 건너뛴 source pack이 있다는 뜻이다.
|
||||
임베딩 모델이 없으면 `degraded=true`로 BM25-only 색인이 되지만, 라이브 코칭 기본 로컬 근거는 계속 동작한다.
|
||||
|
||||
---
|
||||
|
||||
## 4. 웹(프런트엔드) 실행
|
||||
|
|
@ -311,7 +351,7 @@ python scripts\probe-engine-gateway.py --json # 기계 판독용
|
|||
|
||||
## 6. (선택) Docker Compose 전체 스택
|
||||
|
||||
DB까지 포함한 통합 실행은 `infra/docker-compose.yml`(db pgvector pg16 + api + web + rag + proxy)을 쓴다.
|
||||
DB까지 포함한 통합 실행은 `infra/docker-compose.yml`(db pgvector pg16 + api + web + proxy)을 쓴다.
|
||||
Docker Desktop이 필요하고, `infra/.env`(템플릿: `infra/.env.example`)에 `POSTGRES_PASSWORD`,
|
||||
`APP_DB_PASSWORD`, `SESSION_SECRET`, OAuth/OpenAI 키 등을 채워야 한다.
|
||||
|
||||
|
|
@ -321,8 +361,18 @@ docker compose up -d db # DB만
|
|||
docker compose up -d # 전체
|
||||
```
|
||||
|
||||
배포지에 심기 전에는 저장소 루트에서 preflight를 먼저 실행한다. DB 검증을 붙일 때는 owner 계정이 아니라
|
||||
API가 쓸 app-role `DATABASE_URL`을 넘긴다. 실패하면 owner-run init/migration을 먼저 처리하고 API를 띄운다.
|
||||
|
||||
```powershell
|
||||
python scripts\check-deploy-preflight.py --env-file infra\.env
|
||||
python scripts\check-deploy-preflight.py --env-file infra\.env --database-url $env:DATABASE_URL --require-app-role
|
||||
```
|
||||
|
||||
엔진 게이트웨이(9099)는 컴포즈 밖 호스트에서 돌리고, api 컨테이너는
|
||||
`ENGINE_URL=http://host.docker.internal:9099`로 호출한다(compose 기본값).
|
||||
RAG 임베딩/리랭커 의존성은 기본 이미지에 설치하지 않는다. 모델까지 포함한 API 이미지를 만들 때만
|
||||
`infra/.env`에 `INSTALL_RAG=true`를 설정한다.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -331,8 +381,8 @@ docker compose up -d # 전체
|
|||
```powershell
|
||||
# 백엔드 (apps/api)
|
||||
cd apps\api
|
||||
python -m pytest app\ -q # 현재 113 pass
|
||||
python -m pytest engine_gateway\ -q # 7 pass
|
||||
python -m pytest app/ -q # 현재 145 pass
|
||||
python -m pytest engine_gateway\ -q # 현재 9 pass
|
||||
|
||||
# 웹 (apps/web)
|
||||
cd apps\web
|
||||
|
|
@ -363,7 +413,8 @@ npm run e2e # Playwright — web+api+DB 스택 필요
|
|||
요청이 로컬 Origin/Host인지 확인. `apps/api`에서 uvicorn을 실행해 `.env`가 로드됐는지도 확인.
|
||||
|
||||
- **dev-login이 403 (`email domain is not allowed`)**: 이메일 도메인이
|
||||
`AUTH_ALLOWED_EMAIL_DOMAINS`에 없음. `learner@hs.ac.kr` 같은 허용 도메인을 쓴다.
|
||||
`AUTH_ALLOWED_EMAIL_DOMAINS`에 없고, `/admin/users`에 정확히 등록된 관리 사용자도 아니다.
|
||||
`learner@hs.ac.kr` 같은 허용 도메인을 쓰거나 관리자가 해당 이메일을 먼저 등록한다.
|
||||
|
||||
- **`/auth/me`가 401**: 쿠키가 전달되지 않음. curl은 `-c`/`-b`로 쿠키를 저장·재사용하고,
|
||||
PowerShell은 `-SessionVariable`/`-WebSession`을 쓴다. 브라우저는 프록시(5173) 경유로 호출해야
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue