Skip to content

번역 팩(Translation Pack) — AI 번역이 쓰는 표준 용어 ​

AI 번역은 매번 같은 표기를 써야 한다. 그 보장을 위해 용어집(원장)이 승인한 표준 번역을 번역 팩으로 내보내고, 번역 파이프라인이 그 팩을 프롬프트에 그대로 넣는다. 번역 프롬프트 조립은 이미 GuideCenter translationService.ts 의 buildTranslationPrompt 가 갖고 있고, 이 계약은 그 입력(glossary)을 어디서 받는가를 정한다.

엔드포인트 ​

GET /api/directory/v1/glossary/pack?sourceLocale=ko&targetLocale=en[&scope=platform,process-center]
Authorization: Bearer <포털 API Key>   # 스코프: glossary:read
파라미터필수설명
sourceLocale✅원문 언어 코드(예: ko)
targetLocale✅번역 언어 코드(예: en)
scope—쉼표 목록. 생략하면 platform + 호출 포털 (포털이 자기 업무 용어와 플랫폼 표준 단어를 함께 받는다)

응답 ​

json
{
  "data": {
    "packVersion": "a3f1…(32hex)",
    "generatedAt": "2026-10-11T07:20:00.000Z",
    "sourceLocale": "ko",
    "targetLocale": "en",
    "terms": [
      { "sourceTerm": "결재", "preferredTranslation": "approval", "acronym": null,
        "description": "결재 정의", "aliases": ["승인"], "scope": "process-center" }
    ]
  },
  "meta": { "generatedAt": "…", "scopes": ["platform", "process-center"] }
}
  • ETag = "<packVersion>". If-None-Match 로 보내면 바뀌지 않았을 때 304 를 돌려준다(소비자 캐시용).
  • Cache-Control: private, max-age=0, must-revalidate.

규칙 (왜 이렇게 하는가) ​

규칙이유
승인(approved)·활성 용어만 담는다초안까지 넣으면 같은 본문이 번역할 때마다 달라진다 — 용어집을 쓰는 의미가 사라진다
개념 ID 가 없는 번역 전용 용어도 포함한다번역에는 개념이 필요 없다. 온톨로지 팩(/ontology/pack)과 다른 점
같은 표기가 여러 scope 에 있으면 먼저 온 행(포털 우선) 을 남긴다원장 정렬이 priority 높은 순이라, 포털이 자기 용어를 우선하고 없으면 플랫폼 표준 단어를 쓴다
packVersion 은 용어 집합의 지문소비자가 "언제 다시 받아야 하는지" 를 판단할 수 있다(용어 추가·수정·비활성 시 값이 바뀐다)
표준 번역이 빈 행은 버린다번역에 쓸 값이 없다

중앙 번역 서비스 (POST /api/directory/v1/translation) ​

포털마다 번역기를 따로 만들면 같은 용어를 다르게 옮기고 프롬프트 규칙도 갈라진다. 그래서 번역 실행도 콘솔이 제공한다 — 포털은 자기 콘텐츠를 넘기고, 콘솔이 용어 팩을 붙여 프롬프트를 만들고 ModelGateway 로 보낸다. 작업 큐·버전·발행·결과 저장은 포털 소관이다(중앙 서비스는 상태를 갖지 않는다).

POST /api/directory/v1/translation          # 스코프: translation:invoke
{
  "sourceLocale": "ko", "targetLocale": "en",
  "title": "제목", "summary": "요약", "htmlBody": "<p>본문</p>",
  "scope": ["platform", "guide-center"],    # 생략하면 platform + 호출 포털
  "model": "선택"
}
→ { "data": { "title": "Title", "summary": "Summary", "htmlBody": "<p>Body</p>",
              "packVersion": "…", "glossaryTermCount": 42, "model": "gpt-x",
              "usage": { "promptTokens": 1200, "completionTokens": 800 } },
    "meta": { "scopes": ["platform", "guide-center"], "sourceLocale": "ko", "targetLocale": "en" } }
  • 프롬프트 규칙은 GuideCenter 번역기와 같은 문장을 쓴다(HTML 구조·링크·코드·숫자·placeholder·제품명·ID 보존, 용어집 우선, JSON 응답). 포털이 바뀌어도 모델이 같은 지시를 받는다.
  • 모델 호출은 temperature: 0 · x-purpose: translation — 같은 입력에 같은 표기, 그리고 사용 귀속.
  • 필요한 환경변수(다른 포털과 동일): MODEL_GATEWAY_URL, MODEL_GATEWAY_SERVICE_TOKEN. 없으면 503 translation_unavailable 로 거절한다 — 조용히 빈 결과나 원문을 돌려주지 않는다.
  • 팩과 마찬가지로 원장 승인 용어만 쓰고, 용어를 추가하면 모든 포털의 다음 번역에 즉시 반영된다.

소비자 ​

소비자쓰는 법
GuideCenter 번역server/termLinkDirectory.ts fetchCentralTranslationPack() → server/translationGlossary.ts resolveTranslationGlossary() 가 원장 용어를 먼저, 로컬 용어를 보조로 병합해 TranslationRequest.glossary 에 넣는다. 원장이 없거나 닿지 않으면 로컬로 폴백한다(번역은 멈추지 않는다)
(예정) 중앙 번역 서비스포털이 늘어나면 번역 실행 자체를 콘솔로 올린다 — 팩 조회·프롬프트 조립·ModelGateway 호출을 한 곳에서. 공용 라이브러리(@hohyun94/portal-ai)의 번역 모듈 승격이 선행 조건이다(현재 vendored tarball 이라 소스 저장소가 필요)

배포 env — 어느 앱에 넣나 ​

번역은 콘솔이 실행하고 포털은 콘텐츠만 넘긴다. 그래서 필요한 값도 두 앱에 나뉜다.

앱env값
PortalConsole (원장·번역 서비스)MODEL_GATEWAY_URL + MODEL_GATEWAY_SERVICE_TOKEN게이트웨이 주소와 게이트웨이의 같은 이름 값(소비자 토큰). 관리 토큰(MODEL_GATEWAY_ADMIN_TOKEN)과 분리한다
PortalConsolePORTAL_API_KEYS_JSON포털 키 새 항목 — portalId(등록된 포털) + apiKey(48자 hex) + 스코프 glossary:read·glossary:write·translation:invoke
GuideCenter (번역 소비자)DIRECTORY_BASE_URL(또는 PORTAL_CONSOLE_ORIGIN) + DIRECTORY_PORTAL_API_KEY(또는 PORTAL_CONSOLE_API_KEY)위 키와 같은 값이어도 되고, 별도 키면 translation:invoke 스코프가 있어야 한다(없으면 403)
GuideCenterGUIDE_TRANSLATION_PROVIDER (선택)local 이면 중앙 대신 로컬 모델로 번역(폐쇄망·중앙 장애 시 우회)
ModelGateway—추가 없음. 이미 서비스 토큰을 갖고 있고, 콘솔이 보내는 값과 같아야 한다. 공급자·키는 기존 구성 그대로
FileStore·기타 포털—이 기능에는 불필요(원장/번역을 직접 부르지 않는다)
  • 시드 실행 위치: 배포 콘솔에 네트워크가 닿는 곳이면 어디서든 된다(스크립트는 HTTP 클라이언트다).
    bash
    PORTAL_CONSOLE_ORIGIN=https://<배포 콘솔> PORTAL_CONSOLE_PORTAL_API_KEY=<키> pnpm seed:glossary
  • 스코프를 바꾸는 정식 경로는 콘솔 관리자 화면이다 — 포털 설정 데스크의 API 키 섹션에서 대상 키의 scope 를 편집하면(settings.updatePortalApiKey) DB 에 즉시 반영되고 감사 로그(PORTAL_API_KEY_SCOPES_UPDATED)가 남는다. 새 키를 만들 필요가 없다.
  • ⚠️ 반대로 env(PORTAL_API_KEYS_JSON)에서 기존 키의 스코프를 고치면 반영되지 않는다 — 부팅 시 env→DB 반영이 keyId 만 갱신하기 때문이다(keyId 는 apiKey 해시에서 나오므로 같은 키는 같은 행). env 만으로 스코프를 바꾸려면 apiKey 가 새 값인 항목을 추가하고 그 키를 쓰는 포털 env 를 교체한다.

시드(팩이 비지 않게) ​

팩은 승인 용어만 담으므로 원장이 비어 있으면 번역이 용어를 못 받는다. 표준 표기를 파일로 두고 한 번에 넣는다.

bash
node scripts/seed-glossary-terms.mjs --dry-run          # 무엇을 넣을지/건너뛸지만 확인(네트워크 없음)
PORTAL_CONSOLE_ORIGIN=https://console.example.com \
PORTAL_CONSOLE_PORTAL_API_KEY=*** pnpm seed:glossary     # 실제 등록
  • 시드 파일: docs/glossary-seed-terms.json (플랫폼 표준 표기 ko↔en 38개). 다른 파일은 --file, 소속 강제는 --scope 로 지정한다.
  • 멱등: 먼저 같은 언어쌍의 기존 용어를 조회해 이미 있는 표기는 건너뛴다 — 원장에는 (언어쌍·표기) 유니크 제약이 없어 중복 행이 쌓이면 팩에서 서로 다른 번역으로 갈라진다.
  • 포털 API 키에 glossary:write 스코프가 필요하다. 등록은 각 포털이 자기 소속으로 자유롭게 하고, 승인(status)은 원장이 관리한다.
  • 업무 용어는 각 포털이 자기 scope(예: process-center)로 등록하고, 플랫폼 공통 UI 표기는 scope=platform 으로 둔다 — 팩의 기본 범위가 platform + 호출 포털이라 어느 쪽이든 번역에 들어온다.
  • FileStore 관리자 화면의 번역 규칙은 FileStore/docs/UI_TERMS.md 가 코드 쪽 기준이고, 표기의 정본은 이 원장이다.

관련 문서: UiPlatform/docs/ONTOLOGY_SCOPE.md(온톨로지 범위·소유·저장), GuideCenter/docs/translation-automation.md(번역 파이프라인).