Packages: proxyd/, webd/. Web chat channel and auth perimeter.
proxyd is the single public-facing HTTP server. It handles all auth and routes internally:
| Path prefix | Auth | Destination |
|---|---|---|
/pub/* | None | Served directly; web apps must live here to be public |
/health | None | Health check |
/auth/* | None | JWT login, OAuth, refresh, logout โ served by proxyd |
/slink/* | Token | Resolves slink token โ folder; proxied to webd or Vite; 10 req/min per IP |
/dash/* | JWT | Proxied to dashd |
/dav/* | JWT | Proxied to sigoden/dufs WebDAV container; requires DAV_ADDR |
| all other | JWT | Auth-gated; proxied to Vite dev server or served from web/dist/ |
proxyd receives DATA_DIR to locate web/vhosts.json, which maps virtual hostnames to web apps. The file is reloaded every 5 seconds without restart.
User logs in via /auth/. proxyd validates the JWT and injects X-User-Sub and optionally X-User-Groups (JSON array of folder names). groups: null in the JWT = operator (unrestricted). groups: [] = no group access. Raw AUTH_SECRET value accepted as a bypass token for operator tooling.
When no Bearer header is present, proxyd checks the refresh_token cookie. This allows browser navigation without a JS Bearer header. Looks up the session by auth.HashToken(cookie) and injects X-User-Sub and X-User-Name. Unauthenticated requests redirect to /auth/login.
A slink token is a short token stored in registered_groups.slink_token. proxyd resolves it against the database and injects X-Folder, X-Group-Name, and X-Slink-Token. Rate-limited at 10 req/min per IP. Slink tokens give direct group access without a user account โ for embedding a chat widget in an external site.
webd registers with gated as a channel adapter using the standard channel protocol. It uses the JID prefix web:.
It serves the chat UI under /chat/ and exposes an SSE stream for live message delivery.
Browser โ POST /chat/<folder>/send
โ webd โ POST /v1/messages (router)
โ gateway picks up web:<folder> JID on next poll
gateway โ HTTPChannel.Send โ POST /send (webd)
โ webd pushes to SSE stream for <folder>
โ browser receives event, appends to chat UI
Each web message carries a topic field. The gateway's processWebTopics splits messages by topic and runs one agent per topic. Topics allow a single group to maintain multiple parallel conversations in the web UI.
Checks X-User-Groups on folder-specific endpoints. If the header is absent, the request is treated as operator (no restriction). If present and the folder is not in the list, the request is rejected with 403.
When WEBDAV_ENABLED=true, proxyd exposes /dav/ as an auth-gated reverse proxy to a davd container (sigoden/dufs:latest) that mounts groups/ read-only. The /dav path prefix is stripped before forwarding. Requires JWT authentication.
groupForJid in the gateway resolves web:<folder> JIDs by stripping the prefix and looking up the group by folder path. The same fallback is used for slink:<token> JIDs โ the token is resolved to a folder via registered_groups.slink_token.