GuidePortal 확장 아키텍처
결정 요약
GuidePortal은 공개 HTML 콘텐츠를 제공하고 편집·번역·버전관리를 담당하는 독립 포털로 유지한다. DirectoryService는 사용자·조직·포털 등록·공통 UI 릴리스의 중앙 원장으로 사용하되, GuidePortal의 콘텐츠 저장소와 배포 수명주기를 소유하지 않는다. portal-foundation은 각 포털이 검증한 특정 버전을 채택하는 공통 UI 패키지로 사용하며, DirectoryService가 승인한 테마 토큰만 런타임에 동기화한다.
| 영역 | 소유 서비스 | GuidePortal 구현 원칙 |
|---|---|---|
| 공개 콘텐츠 | GuidePortal | HTML을 기본 콘텐츠 형식으로 저장하고, 공개 페이지는 비로그인으로 열람한다. |
| 사용자·조직 | DirectoryService | 현재 DirectoryService 인증을 기본 제공자로 유지하되, 포털 내부 코드는 제공자 독립 인터페이스만 사용한다. |
| 인증 세션 | GuidePortal | 외부 제공자의 토큰과 포털 브라우저 세션을 분리하고, 포털 전용 세션 키·발급자·대상을 사용한다. |
| 공통 UI | portal-foundation + DirectoryService | 컴포넌트·토큰은 버전 의존성으로 수용하고, 테마 Push는 별도 서비스 토큰으로 검증한다. |
| 자동번역 | GuidePortal | 서버 전용 LLM 호출로 번역 초안을 생성하고, 용어집·HTML 보존·검토 상태를 강제한다. |
| 외부 퍼블리싱 | GuidePortal | MCP 등 외부 발행자는 포털 API 키로 인증하고, 표준 발행 패키지를 통해 콘텐츠·자산·원본 버전을 전달한다. |
인증 경계
현재 구현은 DirectoryService 토큰 검증, 브라우저 쿠키, 공통 UI Push 검증이 하나의 모듈과 공유 비밀에 결합되어 있다. 이를 다음 네 가지 역할로 분리한다.
| 구성요소 | 책임 | 초기 구현 | 향후 확장 |
|---|---|---|---|
AuthProvider | 외부 로그인 시작·콜백 교환·외부 사용자 정규화 | DirectoryAuthProvider | OIDC, SAML 브로커, 사내 IdP, 패스키 제공자 |
SessionService | 포털 브라우저 세션 발급·검증·삭제 | 포털 전용 서명 JWT 쿠키 | Redis/DB 세션 저장소, 강제 로그아웃, 세션 회전 |
RequestAuthenticator | 요청에서 사용자 주체를 해석 | 세션 쿠키 또는 포털 전용 Bearer 세션 | 서비스 간 사용자 위임 토큰 |
ServiceTokenVerifier | DirectoryService Push 및 발행자 API 인증 | 공통 UI Push audience와 scope 별도 검증 | 키 회전·JWKS·mTLS |
브라우저 로그인 경로는 제공자 이름에 의존하지 않는 /auth/login과 /auth/callback/:provider를 기본으로 한다. 기존 /auth/directory/* 경로는 호환용 별칭으로 유지한다. 공개 조회 API는 사용자 주체가 없어도 동작하며, 관리자 편집·번역 검토·버전 복원만 역할 검사를 수행한다.
콘텐츠·언어·버전 모델
콘텐츠의 정체성은 manual_pages가 보유하고, 각 언어의 제목·요약·HTML은 언어별 번역 레코드가 보유한다. 초기 활성 언어는 ko, en으로 시드하되, 언어 코드와 표시명은 portal_locales에 데이터로 보관한다. UI 문구도 코드에 고정하지 않고 locale 메시지 카탈로그로 제공하여 이후 언어를 추가할 때 테이블이나 화면 구조를 바꾸지 않는다.
| 객체 | 목적 | 불변성 |
|---|---|---|
manual_pages | 콘텐츠의 시스템·노드·공개 상태·현재 기준 버전 | 현재 상태만 변경 |
manual_page_translations | 언어별 현재 HTML·제목·요약과 기준 원본 버전 | 현재 상태만 변경 |
manual_page_versions | 원문 콘텐츠의 발행 이력 스냅샷 | 추가 전용 |
manual_translation_versions | 언어별 번역·검토·발행 이력 스냅샷 | 추가 전용 |
translation_jobs | 원문 버전에서 대상 언어로 생성된 번역 요청 | 상태 전이만 허용 |
translation_memory | 모델 번역 초안과 검토 결과 | 원문 해시로 재사용 |
저장·외부 발행·복원은 모두 새 버전 스냅샷을 남긴다. 복원은 과거 데이터를 덮어쓰는 작업이 아니라, 선택한 스냅샷을 새 현재 버전으로 채택한 새로운 복원 버전을 생성한다. 원문이 바뀌면 대상 언어 번역은 STALE 상태가 되어 재번역 또는 수동 검토 대상이 된다.
자동번역 흐름
관리자가 원문을 저장하거나 외부 발행자가 새 원본 버전을 수신하면, 활성화된 대상 언어마다 번역 작업을 만든다. 이미 동일한 원문 해시와 대상 언어의 번역 메모리가 있으면 재사용하고, 그렇지 않으면 서버 전용 LLM을 호출한다. 모델은 기본적으로 gpt-5-mini를 사용하며 추론 모드는 비활성화한다. 응답은 엄격한 JSON 스키마로 받고, HTML 구조·URL·코드·플레이스홀더·수치가 유지되는지 프로그램적으로 검사한다. 통과한 결과도 기본값은 REVIEW_REQUIRED이며, 운영자가 게시할 때에만 공개 번역으로 승격한다.
외부 LLM 자격 증명과 모델 호출은 서버에서만 수행한다. 브라우저에는 모델 키, 원문 전체, 내부 용어집을 직접 노출하지 않는다.
공통 UI 적용
@hohyun94/portal-foundation은 포털의 화면 프레임·브랜드·인증 카드·상태 배지·테마 제공자를 담당한다. GuidePortal은 포털 고유의 콘텐츠 탐색·HTML 읽기·편집기를 유지한다. DirectoryService의 THEME_SYNC는 허용된 CSS 토큰만 적용하고, PACKAGE_PUSH는 실제 소스 변경이 아닌 검증 가능한 패키지 버전의 재배포 대기 상태로만 기록한다.
외부 퍼블리싱 계약
MCP 또는 외부 시스템은 POST /api/manuals/publish-package 계열 계약을 통해 sourceSystem, sourcePageId, sourceVersion, 원본 locale, HTML, 자산 매니페스트를 전달한다. API 키 인증은 브라우저 사용자 인증과 분리하며, 입력은 HTML 정화·자산 검증·콘텐츠 해시 계산·불변 버전 스냅샷·번역 작업 생성 순으로 처리한다. 이 계약은 MCP 구현체를 바꾸더라도 포털 내부 콘텐츠 서비스가 변하지 않도록 어댑터 형태로 유지한다.
구현 순서
- 인증을 제공자·세션·서비스 토큰 경계로 분리하고 기존 DirectoryService 흐름을 호환 모드로 이전한다.
- 공개 열람 기본 정책, 콘텐츠 저장 시 원문·번역 버전 스냅샷, 언어별 최신성 상태를 구현한다.
- 서버 전용 LLM 번역 제공자와 작업 실행·검토·게시 흐름을 연결한다.
- 공통 UI 패키지와 런타임 테마 수신 계약을 통합하고 포털 화면의 인증·언어 UI를 일반화한다.
- 외부 발행 API를 새 콘텐츠 서비스로 수렴시키고 회귀 테스트로 계약을 고정한다.
기본 선택은 DirectoryService 인증 + 한국어·영어 + 공개 HTML 열람 + 관리자 검토 후 번역 게시이다. 추가 인증 제공자·언어·MCP 발행자는 새 어댑터나 데이터 행을 더하는 방식으로 확장한다.
운영 환경 변수
| 변수 | 용도 |
|---|---|
AUTH_PROVIDERS | 활성 인증 제공자 목록. 기본값은 directory이다. |
DEFAULT_AUTH_PROVIDER | 일반 로그인 경로가 선택할 제공자. 기본값은 directory이다. |
GUIDE_SESSION_SECRET | GuidePortal 브라우저 세션 서명 키. DirectoryService JWT 키와 분리한다. |
GUIDE_SESSION_ISSUER / GUIDE_SESSION_AUDIENCE | 포털 세션 검증 범위. |
DIRECTORY_SERVICE_JWT_SECRET | DirectoryService가 발급한 서비스 토큰 검증 키. 기존 PORTAL_JWT_SECRET은 호환용으로 읽는다. |
DIRECTORY_COMMON_UI_AUDIENCE | 공통 UI Push 전용 audience. 기존 운영값과의 호환을 위해 기본값은 현재 audience를 사용한다. |
TRANSLATION_MODEL | 서버 자동번역에 사용할 모델. 기본값은 gpt-5-mini이다. |
NPM_TOKEN | GitHub Packages의 공통 UI 패키지 설치용 토큰. 저장소에 기록하지 않는다. |
검증 기준
- 로그인, 로그아웃, DirectoryService 콜백, 기존
/auth/directory/*호환 경로가 모두 동작한다. - 공통 UI Push 토큰은 사용자 세션과 별도 검증 경로를 사용하며 scope·대상 포털·audience가 일치할 때만 수락한다.
- 인증 없이 PUBLIC 콘텐츠와 해당 자산을 열람할 수 있고, 초안·제한 콘텐츠와 관리자 API는 거부된다.
- 원문·각 번역 저장 및 복원마다 버전 이력이 증가하며, 복원은 새 이력을 생성한다.
ko와en이 초기 활성 언어로 보이고, 새 locale을 데이터로 추가할 수 있다.- 자동번역 결과는 HTML 보존 검증을 통과한 뒤 검토 대기로 저장되며, 실패 시 원문이나 게시 번역을 변경하지 않는다.
- 공통 UI 패키지와 테마 Push의 적용·재배포 대기 상태가 분리되어 기록된다.