# Xiteng Site component labels `xiteng.site` does not contain a hardcoded service list. A Docker container opts one or more components into the public catalog with labels under this namespace: ```yaml labels: - "xiteng.site.component.example.enabled=true" - "xiteng.site.component.example.name=Example" - "xiteng.site.component.example.description=What this component does." - "xiteng.site.component.example.section=services" - "xiteng.site.component.example.category=开发与协作" - "xiteng.site.component.example.url=https://example.xiteng.site" - "xiteng.site.component.example.endpoint=example.xiteng.site:443" - "xiteng.site.component.example.access=sso" - "xiteng.site.component.example.access-label=需要 Authentik" - "xiteng.site.component.example.icon=EX" - "xiteng.site.component.example.icon-url=https://example.xiteng.site/favicon.svg" - "xiteng.site.component.example.accent=blue" - "xiteng.site.component.example.order=100" - "xiteng.site.component.example.navigation=new-tab" - "xiteng.site.component.example.portal-link=native" - "xiteng.site.component.example.monitor.enabled=true" - "xiteng.site.component.example.monitor.url=http://example:8080/healthz" ``` ## Schema | Field | Required | Values / behavior | |---|---:|---| | `enabled` | yes | Only the exact value `true` publishes the component. | | `name` | yes | Public display name. | | `description` | recommended | Public description; never put secrets here. | | `section` | yes | `services` or `infrastructure`. | | `category` | recommended | Dynamic group heading. | | `url` | no | Only HTTP(S) URLs are accepted. No URL renders a non-clickable card. | | `endpoint` | no | Public protocol endpoint or connection hint. | | `access` | yes | Machine-readable mode such as `public`, `sso`, `mixed`, `access-key`, `ssh-key`, `local`, or `internal`. | | `access-label` | recommended | Human-readable access boundary shown on the card. | | `icon` | no | Final fallback text or emoji, limited to eight characters. | | `icon-url` | no | Preferred HTTP(S) icon URL. Without it, the UI tries `/favicon.svg`, `/favicon.ico`, then `/favicon.png` on the component origin before showing `icon`. | | `accent` | no | `red`, `green`, `yellow`, `blue`, or `ink`. | | `order` | no | Numeric order inside a section; defaults to `999`. | | `navigation` | no | `new-tab` (default for URLs), `same-tab`, or `endpoint` (default without a URL). | | `portal-link` | no | `embedded`, `native`, or `none`; documents how the service returns to the Portal. | | `monitor.enabled` | no | `true` enables the built-in HTTP GET probe. | | `monitor.url` | when enabled | Internal HTTP(S) target. It is never returned by the public API. | | `monitor.interval` | no | Check interval in seconds, default `60`. | | `monitor.failures` | no | Consecutive failures before `down`, default `3`. | | `monitor.timeout` | no | Request timeout in seconds, default `10`. | | `monitor.accept` | no | Accepted HTTP codes, default `200-299`; comma-separated values and ranges are supported. | The component id (`example` above) must be globally stable. One container may publish multiple components by using multiple ids, which is useful for services such as SeaweedFS Web and its S3 API. The registry reads container state and image names from Docker. It returns only the public fields above plus Compose project/service names, runtime status, sanitized monitor state, response time, last check time, and 24-hour availability. Internal monitor URLs, errors, environment variables, mounts, raw labels, Docker configuration, and secret values are never returned to the public site container. ## Navigation contract Components with a public HTTP(S) URL open in a new tab by default with `noopener noreferrer`, leaving the Portal available in the original tab. Owned or officially customizable applications link back to `https://xiteng.site/?focus=#services`; the Portal clears incompatible filters, scrolls to the component card, briefly highlights it, and then removes the `focus` query parameter. Protocol endpoints and internal-only components remain non-clickable. Do not inject navigation into third-party HTML at the proxy. ## Monitoring and lifecycle The Registry is the only discovery and lifecycle control plane. It uses the stable component id as the database primary key, so a component can never create multiple monitors. It performs bounded-concurrency HTTP GET probes and stores state in `site/data/registry.db`: ```text active → missing → archived → purged ``` - `active`: the component Label is currently present on a Docker container; - `missing`: the container or Label disappeared, but catalog and monitor history remain for 30 days; - `archived`: monitoring is paused and the component is hidden from the default public catalog; - `purged`: an administrator explicitly removes the component and all of its monitoring data. A component that returns with the same id before purge reuses its existing history. Raw checks are retained for 30 days; hourly and daily aggregates are retained for 365 days. Response bodies are never stored. `https://xiteng.site/admin` and `/api/admin/*` are protected by Authentik ForwardAuth and additionally require the exact username `liooil`; this check is repeated in the site backend and Key Vault. All other users use `/account` and `/api/account/*`. The account page is the canonical self-service surface for profile name/email, avatar resolution, password recovery, TOTP, Passkeys, Authentik sessions, and Provider configuration constrained by the session's `(issuer, sub)` pair. Provider definition, model list, and an optional credential are saved from one form. Backend credentials are encrypted by Key Vault; Frontend credentials remain in the current browser's IndexedDB. Either mode can be saved and connectivity-tested in the same action. The public homepage remains unauthenticated. The admin page is the canonical control plane for human users, ordinary groups, password setup/recovery, session revocation, authenticator status/reset, and a group-only application access matrix. The native Authentik admin UI is hidden. TOTP and Passkey enrollment launches dedicated Authentik setup flows and returns to `/account`; list, rename, delete, reset, and ownership checks remain in the Portal API. The account page hashes the normalized email with SHA-256 in the browser, then loads Gravatar and Libravatar directly with no referrer; a deterministic initials image remains visible while loading and on failure. Avatar bytes never pass through the Portal backend. The Portal accesses Authentik with a server-only API token and records every identity mutation in a local JSONL audit; password values are never logged. `liuhome` is protected and currently contains `liooil` and `ziyue`; all managed non-public applications are restricted to that group. The default Authentik identification stage enables WebAuthn conditional UI. A discoverable Passkey can authenticate directly on `auth.xiteng.site`; Authentik's default flow policies then skip both password and the later MFA stage. Username/password plus TOTP remains available as a fallback, and new Passkeys are enrolled with the default `resident_key_requirement=preferred` setup stage. ## Host metrics The internal `metrics` service publishes the sanitized `/api/metrics` payload used by the device status cards. It reads host CPU and memory counters from a read-only `/proc` mount, root filesystem capacity through a read-only bind on the same filesystem, and NVIDIA GPU telemetry through the `utility` driver capability. The public payload is limited to: - CPU usage, model, logical core count, and load averages; - memory and root filesystem used/available/total values; - GPU model, utilization, VRAM, temperature, and power; - hostname and collection timestamp. The metrics container has no Docker socket and no public router. The site server proxies its fixed internal endpoint as `/api/metrics`; arbitrary host files and commands are not exposed. ## PWA and icons `favicon.svg` is the source artwork for browser and install icons. The PNG and ICO derivatives live in `icons/` and at `favicon.ico`. `manifest.webmanifest` enables standalone installation and shortcuts to the service and infrastructure catalogs. `sw.js` caches only the public page shell and static artwork. Runtime component/metrics APIs, Authentik paths, and all administration requests always use the network and are never written to the PWA cache. Setting `enabled=false`, removing the labels, or removing the container moves the component to `missing` without changing `index.html` or `app.js`. The old `homepage.*` and `kuma.*` namespaces are no longer read; new and existing components use only the `xiteng.site.component.*` schema. Static edge caching is a separate, security-sensitive declaration and is intentionally not part of the public component schema. A service can opt public, user-independent asset directories into the shared cache with `xiteng.site.cache..*` labels. See `edge-cache/README.md` for the schema; never apply it to API, admin, callback, tokenized download, HTML, or user-content paths.