Web

Packages: proxyd/, webd/. Web chat channel and auth perimeter.

proxyd โ€” auth perimeter

proxyd is the single public-facing HTTP server. It handles all auth and routes internally:

Path prefixAuthDestination
/pub/*NoneServed directly; web apps must live here to be public
/healthNoneHealth check
/auth/*NoneJWT login, OAuth, refresh, logout โ€” served by proxyd
/slink/*TokenResolves slink token โ†’ folder; proxied to webd or Vite; 10 req/min per IP
/dash/*JWTProxied to dashd
/dav/*JWTProxied to sigoden/dufs WebDAV container; requires DAV_ADDR
all otherJWTAuth-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.

JWT plane

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.

Cookie fallback

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.

Slink plane

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 โ€” web chat adapter

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.

Message flow (inbound)

Browser โ†’ POST /chat/<folder>/send
  โ†’ webd โ†’ POST /v1/messages (router)
  โ†’ gateway picks up web:<folder> JID on next poll

Message flow (outbound)

gateway โ†’ HTTPChannel.Send โ†’ POST /send (webd)
  โ†’ webd pushes to SSE stream for <folder>
  โ†’ browser receives event, appends to chat UI

Topics

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.

webd.requireFolder middleware

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.

WebDAV

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.

JID routing

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.