파사드

wippy/facade 모듈은 CDN에서 Wippy 프런트엔드를 로드하고 구성하는 이식 가능한 facade를 제공합니다. Web Host JS 모듈 엔트리(기본 compat 셸의 경우 module.js, managed 모드의 경우 managed-layout.js)를 로드하는 얇은 HTML 페이지를 서빙하고, 인증을 처리하며, 백엔드와 프런트엔드 사이의 구성을 중계합니다. 로드된 모듈은 페이지 전체와 브라우저 히스토리를 인계받습니다.

iframe 기반 전달 방식(iframe.html + SetConfig PostMessage 핸드셰이크)은 격리나 페이지 일부 임베딩을 위해 호스트를 직접 임베드하는 수동·facade 없는 임베딩용으로 여전히 제공되지만, facade 자체는 더 이상 이를 사용하지 않습니다.

분리되거나 부분적인 페이지 통합에서는 iframe.html과 SetConfig postMessage handshake를 통해 host를 직접 embed할 수 있습니다. facade 자체는 이 전달 모드를 사용하지 않습니다.

프로젝트에 모듈을 추가합니다:

wippy add wippy/facade
wippy install

의존성을 선언합니다:

version: "1.0"
namespace: app

entries:
  - name: gateway
    kind: http.service
    addr: :8090
    lifecycle:
      auto_start: true

  - name: api
    kind: http.router
    meta:
      server: app:gateway
    prefix: /api/public

  - name: dep.facade
    kind: ns.dependency
    component: wippy/facade
    version: "*"
    parameters:
      - name: server
        value: app:gateway
      - name: router
        value: app:api

구성 파라미터

Parameter 필수 Default 설명
server yes — 정적 파일 및 페이지 서빙용 HTTP 서버
router yes — config 엔드포인트용 공개 API 라우터
fe_facade_url no https://web-host.wippy.ai/<release-tag> 프런트엔드 번들의 기본 CDN URL
fe_entry_path no /iframe.html 번들의 iframe 엔트리 경로로, iframe 임베딩 모드에서 사용됩니다. 현재 facade 페이지는 대신 JS 모듈 엔트리(module.js/managed-layout.js)를 로드하며, 이 iframe 경로는 수동·facade 없는 iframe 임베딩용으로 남아 있습니다.
fe_mode no compat facade 페이지가 로드할 셸: compat은 module.js(기본 채팅 셸), managed는 managed-layout.js(선택적 선언형 멀티 패널 레이아웃)를 로드합니다. /facade/config에 mode/module_file로 노출됩니다.
host_config_layout no {} hostConfig.layout으로 방출되는 JSON 레이아웃 구성이며, managed 셸에서만 사용됩니다.
render_engine no iframe 페이지 렌더 엔진으로, hostConfig.renderEngine으로 방출됩니다. 렌더 엔진을 참조하세요.
login_path no /login.html 인증되지 않은 사용자를 리다이렉트할 페이지 오리진 내 경로이며, login_redirect_param과 함께 동작합니다.
login_redirect_param no "" (off) login_path로 리다이렉트할 때 로그인 후 복귀 URL을 덧붙일 쿼리 파라미터 이름입니다. 비어 있으면 복귀 URL을 덧붙이지 않습니다.
extra_scripts no [] facade 페이지가 로드할 추가 스크립트 URL의 JSON 배열이며, /facade/config에 extraScripts로 방출됩니다.

렌더 엔진

render_engine은 배포 전체의 페이지 렌더 엔진을 선택합니다. hostConfig.renderEngine으로 방출되며 Web Host가 단일 페이지 렌더 분기 지점에서 읽습니다.

Value 효과
iframe (기본값) 페이지가 srcdoc iframe으로 렌더링됩니다 — 주 엔진(기본값)입니다.
fragment 페이지가 Web Fragment로 렌더링됩니다(shadow root에 반영되는 reframed realm).

정확히 fragment 문자열만 활성화합니다. 다른 값은 — fragmnet 같은 오타를 포함해 — iframe으로 고정됩니다(안전 측 동작이지만 경고는 없습니다). fragment 엔진을 켜려면 /@fragment 게이트웨이도 필요하며, 이는 wippy/views(≥ 0.5.9)가 자체 제공하므로 소비자 측 배선이 필요 없습니다. 페이지는 wippy.renderEngine으로 배포 기본값을 페이지 단위로 재정의할 수 있습니다.

앱 아이덴티티

Parameter Default 설명
app_title Wippy 사이드바에 표시되는 제목
app_name Wippy AI 전체 애플리케이션 이름
app_icon wippy:logo Iconify 아이콘 참조

기능 플래그

Parameter Default 설명
hide_nav_bar false 왼쪽 내비게이션 사이드바 숨김
disable_right_panel false 오른쪽 사이드바 패널 비활성화
start_nav_open false 내비게이션 드로어를 기본으로 열어둠
show_admin true 관리자 패널 토글 표시
allow_select_model false 사용자가 LLM 모델을 선택하도록 허용
session_type non-persistent 인증 토큰 저장 방식: non-persistent(인메모리) 또는 cookie. Web Host는 cookie 이외의 값을 모두 non-persistent로 취급합니다.
history_mode hash 브라우저 히스토리 모드: hash 또는 browser. Web Host는 browser 이외의 값을 모두 hash로 취급합니다.
hide_session_selector false 세션 선택 UI 숨김

테마

세 가지 범위가 적용됩니다: global(모든 곳), host(Web Host chrome — 사이드바, 채팅, 페이지 영역), children(자식 view.page iframe 및 view.component 웹 컴포넌트 양쪽). 각 설정이 어떤 서피스에 도달하는지는 CSS 전달 매트릭스를 참조하세요.

Parameter 범위 Default 설명
custom_css global Google Fonts import 전역 CSS — 호스트 chrome, view.page iframe, view.component shadow root에 도달합니다(1.0.43+).
css_variables global {} 임의의 CSS 커스텀 프로퍼티의 JSON 맵. Auto 모드와 강제 모드용으로 컴파일되며 컴포넌트 shadow root로 브릿지됩니다.
icon_sets global [] Iconify 아이콘 세트 URL(인라인 JSON 전용 — fs:// 불가)
host_custom_css host "" 호스트 chrome 전용 CSS — 자식에는 적용되지 않습니다. 클래스 기반 규칙은 .wippy-host-app으로 범위를 지정하세요.
host_css_variables host {} 호스트 chrome 전용 CSS 커스텀 프로퍼티
host_icon_sets host [] 호스트 전용 아이콘 세트(인라인 JSON 전용)
children_custom_css children "" 자식 전용 CSS — view.page iframe과 view.component shadow root에 주입되며(1.0.43+), 호스트 chrome에는 적용되지 않습니다
children_css_variables children {} 자식 전용 CSS 커스텀 프로퍼티

기본 지침: 공통·브랜드 스타일링은 custom_css와 css_variables(global)에 두세요 — 테마의 약 95%가 여기에 속하며 모든 서피스에 도달합니다. host_custom_css / host_css_variables는 호스트 전용 chrome(사이드바, 채팅 패널, 스플리터)에만 사용하세요. view.component는 customCss: false로 shadow root의 *_custom_css 적용을 해제할 수 있습니다.

테마 모드와 지속성

Parameter Default 설명
theme_mode auto 호스트 + 자식에 강제되는 테마: auto(OS 설정 따름), light, dark. /facade/config에 themeMode로 방출됩니다.
theme_persist none 사용자가 선택한 테마를 새로고침 후에도 유지: none, cookie, localStorage. cookie 모드에서는 Jet로 렌더링된 셸이 서버 측에서 쿠키를 읽어 첫 페인트 전에 w-theme-* 클래스를 적용합니다(깜빡임 없음). themePersist로 방출됩니다.
theme_storage_key @wippy-theme-mode 모드가 저장되는 쿠키 / localStorage 키입니다. themeStorageKey로 방출되며 생성된 /facade/theme-persist.js에 내장됩니다.

테마 지속성은 옵트인입니다. theme_persist의 기본값은 none이므로, 배포에서 cookie 또는 localStorage로 설정하기 전까지는 아무것도 저장되지 않습니다. 활성화하면 facade가 키와 모드가 내장된 스크립트를 **GET /facade/theme-persist.js**로 제공합니다. 테마를 공유해야 하는 모든 페이지에 포함하세요. 전체 모델, themeChanged 호스트 이벤트, Wippy 외부 페이지 통합은 테마 지속성을 참조하세요.

Web Host 외부 페이지에서 facade 테마 재사용

Web Host 밖에서 서빙되는 페이지 — login.html, 오류 페이지, 이메일 확인 페이지 — 도 테마를 중복 정의하는 대신 동일한 facade 브랜드 테마를 재사용할 수 있으므로, 토큰과 커스텀 규칙이 한곳에 모입니다.

먼저 custom_css와 css_variables를 인라인이 아니라 별도 파일로 유지하고, fs://와 content_fs 파일 시스템으로 파라미터가 해당 파일을 가리키게 합니다:

custom_css:    fs://custom-css.facade.css
css_variables: fs://css-variables.facade.json
content_fs:    app:app_fs

file://가 아니라 fs://를 사용하세요(런타임에 content_fs가 해석). file://은 로드 시점에 wippy 로더가 YAML 기준으로 인라인 처리합니다. 파일은 login_path 페이지가 서빙되는 정적 폴더와 같은 위치에 두세요(app에서는 /app으로 서빙되는 static/).

fs:// 해석은 정확히 여섯 개의 테마 파라미터 — custom_css, css_variables, host_custom_css, host_css_variables, children_custom_css, children_css_variables — 에만 적용됩니다(CSS 문자열은 그대로 읽고, JSON *_css_variables 파일은 변수 맵으로 파싱됩니다). icon_sets / host_icon_sets와 그 밖의 모든 JSON 파라미터(api_routes, chat, tanstack, …)는 인라인 전용이며, 거기서는 fs://가 해석되지 않습니다.

독립 페이지는 다음 두 가지를 링크합니다:

  • custom_css — 이미 .css 파일이므로 서빙되는 위치에서 바로 링크합니다.
  • css_variables — JSON이므로 그대로는 링크할 수 없습니다. facade가 이를 **GET /facade/variables.css**에서 기본값과 유효 Auto-light, Auto-dark, 강제 Light, 강제 Dark 블록으로 렌더링합니다. 최상위 값은 모든 곳에 적용되며 @light / @dark가 선택된 이름을 대체합니다. 이 스타일시트는 1시간 캐시되고 /facade/config와 같은 공개 라우터에 등록되므로 라우터 prefix가 붙습니다.
<!-- Web Host 외부에서 서빙되는 login.html 안에서 -->
<link rel="stylesheet" href="/api/public/facade/variables.css">  <!-- css_variables, 생성된 CSS -->
<link rel="stylesheet" href="/app/custom-css.facade.css">        <!-- custom_css 파일 -->

테마 모드까지 공유하려면(login.html이 호스트와 동일한 라이트/다크 선택을 따르고 유지하도록), 생성된 theme-persist 스크립트를 추가하고 스위처에서 그 write()를 호출하세요:

<script src="/api/public/facade/theme-persist.js"></script>
<!-- 저장된 테마를 조기에 적용하고 window.wippyThemePersist를 노출합니다 -->

완전한 스위처 예제는 테마 지속성 → Wippy 외부 호스팅 페이지를 참조하세요.

선택적 JSON 파라미터

다음 파라미터는 각각 JSON으로 인코딩된 문자열이며 기본값은 비어 있습니다({} 또는 []).

아래 네 가지는 hostConfig 아래에 그대로 프런트엔드로 노출됩니다:

Parameter Default 설명
additional_nav_items [] 추가 사이드바 항목
state_cache {} 프런트엔드 상태 캐시 구성
allow_additional_tags {} HTML 새니타이저 태그 화이트리스트(Record<string, string[]>, 태그 → 허용 속성)
chat {} 채팅 UI 오버라이드

아래 세 가지는 hostConfig 아래가 아니라 최상위 AppConfig 필드(hostConfig의 형제)로 방출됩니다:

Parameter 방출 이름 Default 설명
api_routes apiRoutes {} 프런트엔드 라우트 오버라이드
axios_defaults axiosDefaults {} 프런트엔드 axios HTTP 클라이언트 기본값
tanstack tanstack {} TanStack Query 기본값: { default?, content?, lists? }. default는 모든 쿼리에, content는 단일 리소스 렌더링에, lists는 내비게이션/인덱스 쿼리에 적용됩니다. 호스트 기본값은 refetchOnWindowFocus:false입니다

아래 세 개는 hostConfig 아래가 아니라 최상위 AppConfig 필드로 방출됩니다.

facade는 구성된 라우터에 GET /facade/config를 등록합니다. 이 경로는 공개 라우터 위에 등록되므로 페이지가 실제로 가져오는 URL에는 라우터의 prefix가 포함됩니다. 예시 prefix /api/public(Setup 참조)에서는 /api/public/facade/config가 되며, 이는 배포된 facade 페이지가 가져오는 경로와 정확히 같습니다. (facade는 같은 라우터에 라우트를 하나 더 등록합니다 — GET /facade/variables.css로, css_variables를 Web Host 외부 페이지를 위한 text/css 스타일시트로 렌더링합니다. Web Host 외부 페이지에서 facade 테마 재사용을 참조하세요.) 프런트엔드는 로드 시 이 구성을 가져옵니다:

{
    "facade_url": "https://web-host.wippy.ai/<release-tag>",
    "iframe_origin": "https://web-host.wippy.ai",
    "iframe_url": "https://web-host.wippy.ai/<release-tag>/iframe.html?waitForCustomConfig",
    "login_path": "/login.html",
    "login_redirect_param": null,
    "mode": "compat",
    "module_file": "/module.js",
    "extraScripts": null,
    "env": {
        "APP_API_URL": "https://api.example.com",
        "APP_AUTH_API_URL": "https://api.example.com",
        "APP_WEBSOCKET_URL": "wss://api.example.com"
    },
    "routePrefix": "https://api.example.com",
    "apiRoutes":     { "...": "..." },
    "axiosDefaults": { "...": "..." },
    "tanstack":      { "lists": { "refetchOnWindowFocus": true } },
    "theming": {
        "global":  { "customCSS": "...", "cssVariables": {}, "iconSets": {} },
        "host":    { "customCSS": "...", "cssVariables": {}, "iconSets": {}, "i18n": { "app": { "title": "Wippy", "icon": "wippy:logo", "appName": "Wippy AI" } } },
        "children": { "customCSS": "...", "cssVariables": {} }
    },
    "hostConfig": {
        "session": { "type": "non-persistent" },
        "history": "hash",
        "renderEngine": "iframe",
        "showAdmin": true,
        "allowSelectModel": false,
        "startNavOpen": false,
        "hideNavBar": false,
        "disableRightPanel": false,
        "hideSessionSelector": false,
        "additionalNavItems": [],
        "stateCache":        { "...": "..." },
        "allowAdditionalTags": { "w-chart": ["data", "type"] },
        "chat":              { "...": "..." }
    }
}

API URL은 PUBLIC_API_URL 환경 변수에서 읽어옵니다. APP_WEBSOCKET_URL은 http://를 ws://로 또는 https://를 wss://로 대체하여 파생됩니다. 테마는 세 가지 범위(global, host, children)를 가지며 — host.i18n은 앱 브랜딩을 담습니다. hostConfig 키는 camelCase이며 facade 파라미터에서 조립됩니다: session_type, history_mode, render_engine, show_admin, allow_select_model, start_nav_open, hide_nav_bar, disable_right_panel, hide_session_selector, 그리고 선택적 additional_nav_items, state_cache, allow_additional_tags, chat. render_engine은 renderEngine이 됩니다(렌더 엔진 참조). api_routes, axios_defaults, tanstack 파라미터는 hostConfig 내부가 아니라 그 형제인 최상위 AppConfig 필드(apiRoutes, axiosDefaults, tanstack)로 방출됩니다.

facade_url, iframe_origin, iframe_url, login_path, mode, module_file 필드는 임베딩 페이지가 스스로를 구성하는 데 사용하는 셸 수준 필드로, 호스트가 초기화에 사용하는 자식 AppConfig의 일부가 아닙니다. iframe_origin/iframe_url 필드는 수동·facade 없는 iframe 임베딩에서만 사용됩니다(Facade 진입점 참조). mode 필드는 정규화된 fe_mode(compat 또는 managed)이며, module_file은 facade 페이지가 로드하는 JS 모듈 엔트리로 compat에서는 /module.js, managed에서는 /managed-layout.js입니다.

facade_url, iframe_origin, iframe_url, login_path, mode, module_file은 embedding 페이지가 자체 구성을 위해 사용하는 shell 수준 필드이며 host가 초기화하는 자식 AppConfig의 일부가 아닙니다. iframe_origin/iframe_url은 facade 없는 수동 iframe embedding에서만 사용됩니다(Facade Entry Point 참고). mode는 정규화된 fe_mode(compat 또는 managed)이고, module_file은 facade 페이지가 로드하는 JS module entry로 compat에서는 /module.js, managed에서는 /managed-layout.js입니다.

wippy/views로 등록된 페이지는 메타데이터에 따라 사이드바에 자동으로 표시됩니다:

entries:
  - name: dashboard
    kind: registry.entry
    meta:
      type: view.page
      name: dashboard
      title: Dashboard
      icon: tabler:chart-bar
      group: Analytics
      group_icon: tabler:chart-dots
      group_order: 10
      order: 1
      announced: true
      secure: true
      url: https://cdn.example.com/dashboard/

사이드바 그룹

group 값이 같은 페이지는 접을 수 있는 섹션으로 묶입니다. 그룹은 group_order(작을수록 먼저), 그룹 내 페이지는 order로 정렬됩니다.

Field 설명
group 사이드바에 표시되는 카테고리 이름
group_icon 카테고리 헤더 아이콘
group_order 그룹 정렬 위치(작을수록 위)
group_placement "sidebar"(사이드바에 표시) 또는 "default"(본문 영역에만)

group이 없는 페이지는 최상위 항목으로 표시됩니다.

표시 여부 제어

Field 효과
announced: true 페이지가 사이드바 내비게이션에 표시됩니다
announced: false 내비게이션에서는 숨기지만 URL로는 접근할 수 있습니다
inline: true 내부 페이지로, 모든 UI 목록에서 숨겨집니다
hide_nav_bar: true facade 파라미터 — 왼쪽 사이드바 전체를 숨깁니다

임베드된 에셋과 함께 게시하기

정적 파일(예: facade의 public/ 디렉터리)을 포함하는 컴포넌트를 게시할 때는 --embed를 사용해 패키지에 fs.directory 엔트리를 포함시킵니다:

wippy publish --embed facade:public_files

--embed 없이는 fs.directory 엔트리가 게시 패키지에서 제외됩니다. --embed 플래그는 fs.directory 엔트리와 일치하는 엔트리 ID 또는 이름을 받습니다.

참고

  • Views - 페이지 및 컴포넌트 시스템
  • HTTP Server - HTTP 서비스 구성
  • Framework Overview - 프레임워크 모듈 사용법
  • Facade 진입점 - facade가 Web Host를 부트스트랩하는 방식(FE 관점)
  • CSS 주입 - facade 테마가 자식 iframe으로 흐르는 방식
  • 렌더 엔진 - iframe 대 Web Fragment 페이지 렌더링(render_engine 스위치)