feat(web-app-jitsi-conference): jitsi-admin video call launcher + Space/file recipient calling - #551
feat(web-app-jitsi-conference): jitsi-admin video call launcher + Space/file recipient calling#551dj4oC wants to merge 7 commits into
Conversation
Research H2-invent/jitsi-admin's API surface, OIDC auth model, iframe embeddability, and self-hosting requirements, and cross-reference the web-app-draw-io / web-app-external-sites iframe patterns already in this repo. Records open questions (D1-D4) instead of silently resolving them, per the archaeology brief; recommends holding Phase 1 implementation on a D1 sign-off (nested-iframe framing and WebRTC permission propagation for the live call are not verifiable from source alone). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JWGj1sNpSCpr4P55UDUw44 Signed-off-by: Claude <noreply@anthropic.com>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
Add a "Start video call" app-menu entry that opens a self-hosted H2-invent/jitsi-admin instance in a new browser tab. Per DECISIONS.md (D1), the live call is deliberately never embedded in an oCIS iframe: jitsi-admin already wraps Jitsi Meet/LiveKit in its own internal iframe, so nesting it under ours would frame the call two layers deep, depending on frame-ancestors and WebRTC permission-policy propagation neither we nor jitsi-admin's own hosting guarantees. Opening it top-level, following the web-app-external-sites `target: external` convention, removes that risk by construction. Identity relies entirely on jitsi-admin's own OIDC login against the same Keycloak instance oCIS uses (D2) - no token forwarding, no service-account bridge. The manifest ships with no default url so the menu item stays hidden until an operator points it at their own instance (D4); nothing here defaults to a public jitsi-admin instance. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JWGj1sNpSCpr4P55UDUw44 Signed-off-by: Claude <noreply@anthropic.com>
Add a "Video call" sidebar panel for Spaces that creates a jitsi-admin room and invites the Space's individual members by email in one click. Research against owncloud/ocis's merged web/ frontend confirmed the Spaces list's own context menu (SpaceContextActions.vue) has no third-party extension point at all, so this lands on global.files.sidebar instead - the one point that does reach a SpaceResource, gated by isProjectSpaceResource - rather than the global.spaces.actions this was originally expected to use. Group-granted members are skipped (resolving a group to individual emails is out of scope); jitsi-admin sends the invite emails itself, so no oCIS notification API is needed at all. Add packages/jitsi-admin-proxy, a sidecar structured like ai-llm-proxy: mandatory Origin check against OCIS_URL, oCIS OIDC bearer validation, and the only place the jitsi-admin Server API key lives (browsers can't hold that key directly per DECISIONS.md D3). Its jitsi-admin request/response field names are a best-effort reconstruction from Phase 0's source-reading, not verified against a live instance - documented plainly in its README rather than overclaimed, with the calling code kept small and isolated so it's easy to correct once verified. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JWGj1sNpSCpr4P55UDUw44 Signed-off-by: Claude <noreply@anthropic.com>
The mock requests carried a hardcoded Origin header that only matched the empty ALLOWED_ORIGIN of an unconfigured local sandbox. CI sets a real OCIS_URL globally, so ALLOWED_ORIGIN is non-empty there and the origin check rejected every mocked request before it ever reached the auth/body-reading stages the tests meant to exercise - the 401 test got a 403 instead, and the rest hung waiting for a body-read listener that origin rejection never attaches, until they timed out. Match ai-llm-proxy's existing tests: don't set an Origin header at all on these mock requests, since isOriginAllowed only enforces a match when one is actually present. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JWGj1sNpSCpr4P55UDUw44 Signed-off-by: Claude <noreply@anthropic.com>
|
Generated by Claude Code |
|
@mscholz-h2-invent look at this little fellow |
Add a second "Video call" sidebar panel, reusing the same global.files.sidebar extension point Phase 2 already registered for Spaces, gated by !isSpaceResource instead of isProjectSpaceResource so the two panels are mutually exclusive. Recipients are resolved from the item's LibreGraph share list, scoped to direct same-instance individual-user shares only (ShareTypes.user) - group shares, public links, guest shares, and federated/OCM shares (ShareTypes.remote) are all skipped, per the brief's own guidance to flag OCM as a follow-up rather than attempt it silently. Extracted the room-provisioning core shared by both flows into useJitsiCall, with useSpaceCall and the new useFileCall as thin wrappers over it; useSpaceCall's existing tests were re-run unchanged to confirm the extraction stayed behavior-preserving. No sidecar changes needed - jitsi-admin-proxy already accepts an arbitrary roomName/participants payload. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JWGj1sNpSCpr4P55UDUw44 Signed-off-by: Claude <noreply@anthropic.com>
Complete, self-contained Docker Compose stack for exercising this PR end to end: oCIS + Keycloak (shared IdP for both, per DECISIONS.md D2) + jitsi-admin (MariaDB + websocket hub) + LiveKit (meeting backend) + LiveKit Meet (browser client) + Mailpit. Kept separate from the repo root docker-compose.yml, whose oCIS service uses basic auth on a single host with path-prefix routing - jitsi-admin needs its own vhost and Keycloak/OIDC, which don't fit that shared file without changing it for every other package + CI. All secrets in .env.example are blank placeholders with generation commands; none of this was exercised against a live jitsi-admin instance until now, so the README documents five real, non-obvious deployment bugs hit and fixed along the way (root-owned log file from CRON_USER_1, league/oauth2-client's verify-requires-proxy gate, cross-realm Keycloak credential ID collisions, apps.yaml's shallow config templating, and Docker Desktop's docker-proxy blowup on large UDP port ranges). 🤖 Generated with Claude Code Signed-off-by: dj4oC <david.walter@kiteworks.com>
|
Added a complete, self-contained deployment example: It's a standalone Docker Compose stack (oCIS + Keycloak + jitsi-admin + LiveKit + LiveKit Meet + Mailpit), separate from the repo root All secrets in Verified against a live stack: Keycloak realm import (both 🤖 Generated with Claude Code |
…ypoint printenv dumped every container env var - including JITSI_ADMIN_OIDC_CLIENT_SECRET, KC_DB_PASSWORD, and KC_BOOTSTRAP_ADMIN_PASSWORD - to stdout on every Keycloak start, landing in plaintext in whatever aggregates docker compose logs. Debug leftover, not needed for the entrypoint to work. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JWGj1sNpSCpr4P55UDUw44 Signed-off-by: Claude <noreply@anthropic.com>
|
Needs to be rebased to resolve lockfile conflict. |


Summary
Phase 0 archaeology + Phase 1–3 implementation of a jitsi-admin (H2-invent) video-conferencing launcher, per sign-off in this PR's discussion.
ARCHAEOLOGY.md/DECISIONS.md— cited research on jitsi-admin's REST API, OIDC/Keycloak auth model, iframe/framing behavior, and self-hosting requirements, plus this repo'sweb-app-draw-io/web-app-external-sitesprecedents.packages/web-app-jitsi-conference— a "Start video call" app-menu entry (opens jitsi-admin in a new tab), plus a "Video call" sidebar panel that appears on both Spaces and regular files/folders.packages/jitsi-admin-proxy— the sidecar that provisions rooms and invites participants, holding the jitsi-adminServer.apiKeyservice credential.Key design decisions (see
DECISIONS.md)web-app-external-sites'target: externalconvention), never in an iframe./api/v1/*room API needs a static per-server API key, not a forwarded user token — hence the sidecar, used by Phase 2/3, not Phase 1.manifest.jsonships with no defaulturl.Phase 2 — "Call all Space members"
global.files.sidebaris the one extensible point that reaches a Space, so this ships as asidebarPanel, not anaction.SpaceResource.members(already present, no extra Graph call); only individual user grants are invited — group grants are skipped.Phase 3 — "Call all recipients of a file/folder"
global.files.sidebarextension point and the same sidecar — no new API surface, just a second panel gated by!isSpaceResourceinstead ofisProjectSpaceResource.GraphPermissions.listPermissions, scoped to direct same-instance individual-user shares (ShareTypes.user) only — group shares, public links, guest shares, and federated/OCM shares (ShareTypes.remote) are all skipped, per the brief's own guidance to flag OCM as a follow-up.useJitsiCall, withuseSpaceCall/useFileCallas thin wrappers;useSpaceCall's existing tests were re-run unchanged to confirm the extraction stayed behavior-preserving.Known limitations (stated plainly, not papered over)
/api/v1/room//api/v1/userrequest/response field names are a best-effort reconstruction from source-reading — not exercised against a live instance (none was available in this environment).test:e2eunconditionally.Not in this PR
Phase 4 (Collabora-plus-call layout) remains out of scope, per the original brief.
Test plan
pnpm --filter jitsi-conference build / check:types / test:unit(18 tests)pnpm --filter jitsi-admin-proxy test:unit(16 tests)pnpm lintandpnpm check:types(repo-wide, no new errors)