Skip to content

feat(web-app-jitsi-conference): jitsi-admin video call launcher + Space/file recipient calling - #551

Draft
dj4oC wants to merge 7 commits into
mainfrom
claude/ocis-jitsi-admin-archaeology-wdnm5b
Draft

feat(web-app-jitsi-conference): jitsi-admin video call launcher + Space/file recipient calling#551
dj4oC wants to merge 7 commits into
mainfrom
claude/ocis-jitsi-admin-archaeology-wdnm5b

Conversation

@dj4oC

@dj4oC dj4oC commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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's web-app-draw-io / web-app-external-sites precedents.
  • 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-admin Server.apiKey service credential.

Key design decisions (see DECISIONS.md)

  • D1 (framing): jitsi-admin embeds Jitsi Meet/LiveKit itself, so wrapping it in our own iframe would nest the live call two layers deep. Resolved by construction: open jitsi-admin top-level (web-app-external-sites' target: external convention), never in an iframe.
  • D2 (identity): relies entirely on jitsi-admin's own OIDC login against the same Keycloak instance as oCIS.
  • D3 (sidecar boundary): jitsi-admin's /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.
  • D4 (data sovereignty): manifest.json ships with no default url.

Phase 2 — "Call all Space members"

  • Verified (not assumed) that the Spaces overview's context menu isn't third-party extensible at all; global.files.sidebar is the one extensible point that reaches a Space, so this ships as a sidebarPanel, not an action.
  • Members resolved from SpaceResource.members (already present, no extra Graph call); only individual user grants are invited — group grants are skipped.
  • jitsi-admin sends the invitation emails itself (confirmed in Phase 0 archaeology) — no oCIS notification API is touched at all.

Phase 3 — "Call all recipients of a file/folder"

  • Reuses the same global.files.sidebar extension point and the same sidecar — no new API surface, just a second panel gated by !isSpaceResource instead of isProjectSpaceResource.
  • Recipients resolved via 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.
  • Shared room-provisioning logic extracted into useJitsiCall, with useSpaceCall/useFileCall as thin wrappers; useSpaceCall's existing tests were re-run unchanged to confirm the extraction stayed behavior-preserving.

Known limitations (stated plainly, not papered over)

  • jitsi-admin's exact /api/v1/room//api/v1/user request/response field names are a best-effort reconstruction from source-reading — not exercised against a live instance (none was available in this environment).
  • No Playwright e2e tests yet for either new package; neither is in the CI test matrix yet since that job runs test:e2e unconditionally.

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 lint and pnpm check:types (repo-wide, no new errors)
  • Playwright e2e — intentionally deferred, per the brief

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>
@kw-security

kw-security commented Aug 15, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 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>
@dj4oC dj4oC changed the title docs: jitsi-admin extension — Phase 0 archaeology and decisions feat(web-app-jitsi-conference): jitsi-admin video call launcher Aug 16, 2026
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>
@dj4oC dj4oC changed the title feat(web-app-jitsi-conference): jitsi-admin video call launcher feat(web-app-jitsi-conference): jitsi-admin video call + call all Space members Aug 16, 2026
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>

dj4oC commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

test (web-app-progress-bars) failed on a webkit e2e test (progressBar.spec.ts:16 › select NyanCat progressBarOption on the account page) — this PR doesn't touch that package. The most recent main run (2026-08-14, run 31777392728) has that same job passing, so this looks like an unrelated flake rather than something introduced here. Attempted to re-run just the failed job, but the workflow run was still in progress as a whole at the time; will re-run once it completes if it's still red.


Generated by Claude Code

@dj4oC

dj4oC commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

@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>
@dj4oC dj4oC changed the title feat(web-app-jitsi-conference): jitsi-admin video call + call all Space members feat(web-app-jitsi-conference): jitsi-admin video call launcher + Space/file recipient calling Aug 16, 2026
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>
@dj4oC

dj4oC commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

Added a complete, self-contained deployment example: packages/web-app-jitsi-conference/full-stack-example/.

It's a standalone Docker Compose stack (oCIS + Keycloak + jitsi-admin + LiveKit + LiveKit Meet + Mailpit), separate from the repo root docker-compose.yml since that file's oCIS service uses basic auth on a single host with path-prefix routing, and jitsi-admin needs its own vhost + Keycloak/OIDC — those don't fit the shared dev compose without changing it for every other package and CI.

All secrets in .env.example are blank placeholders with generation commands - nothing real is committed. The README documents five non-obvious deployment bugs found while getting this running end to end for the first time (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).

Verified against a live stack: Keycloak realm import (both oCIS and jitsiadmin), oCIS login, jitsi-admin OAuth login, the extension's manifest/config resolution via apps.yaml, and jitsi-admin-proxy's routing/auth gating. Not yet verified: the actual room-provisioning flow through jitsi-admin's /api/v1/room API, since that needs a jitsi-admin Server registered by hand (documented as a manual step in the README - can't be automated from a compose file).

🤖 Generated with Claude Code

@dj4oC

dj4oC commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

How to use it:

  1. create a space
  2. invite members to a space
  3. open the space - ensure that the right side bar opens, if not, click on the top right symbol next to the user name initials
  4. click on "video call"
  5. click on "call all members"
Screenshot 2026-08-16 at 22 12 02 Screenshot 2026-08-16 at 22 12 14

@dj4oC
dj4oC requested a review from LukasHirt August 17, 2026 04:19
…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>
@LukasHirt

Copy link
Copy Markdown
Collaborator

Needs to be rebased to resolve lockfile conflict.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants