Appearance
Overview
HVC Web (repo hippo-portal at hippo2/Frontend/hvcweb) is the clinician web portal for the HVC platform. It is a modern Svelte 5 (runes) + SvelteKit 2 single-page app that runs on the same backend as the mobile and headset clients: GraphQL (hvc-api /graphql), Keycloak SSO, the SignalR /hubs/mobile hub, and Pexip conferencing.
Technology Stack
Core
- Framework: Svelte 5 (runes) + SvelteKit 2 (adapter-static SPA)
- Build tool: Vite 7
- GraphQL: Houdini (codegen; feature-scoped
*.gqldocs, generated$houdinistores) - Styling: Tailwind CSS 4 (
@tailwindcss/vite) - TypeScript: 5.9
- Auth: Keycloak + OIDC via the shared
@rkosafo/cai.componentspackage - Realtime:
@microsoft/signalr(/hubs/mobile) + per-call WebSocket - Video: Pexip WebRTC (
pexrtc.jsloaded fromstatic/)
Key libraries
- UI kit:
@rkosafo/cai.components— shared components (Modal, Drawer, Alert/AlertDialog, Dropdown, Buttons, Datatable, Forms suite, Toaster, KeycloakService) - Calendar:
@event-calendar/*(core, day-grid, time-grid, list, interaction) - Date/time:
dayjs - Uploads:
filepond+svelte-filepond(Bearer-authenticated) - Emoji:
@joeattardi/emoji-button - Sanitization:
dompurify,sanitize-html - Misc:
nanoid,lodash,svelte-pincode,graphql-ws(subscriptions)
Project Structure
text
src/
├── routes/ # SvelteKit routes (SPA)
│ ├── +layout.svelte # bootstrap: Keycloak init, token refresh, tenant config
│ ├── +page.svelte # splash → redirect to home page
│ ├── private/ # legacy /private → /secure redirect (catch-all)
│ ├── rc/ # Rapid Connect alias routes
│ ├── rapidConnect/ # anonymous Rapid Connect pages
│ ├── secure/ # authenticated area (dashboard, contacts, calendar, events,
│ │ # ledger, settings, terms, admin)
│ └── unknown/ # invalid-tenant fallback
├── features/ # one folder per feature: index.svelte + partials/ + svc/
│ ├── admin/ auth/ calendar/ chat/ contacts/ dashboard/
│ ├── events/ ledger/ notification/ rapidConnect/ settings/ terms/
├── components/ # shared app chrome
│ └── UI/ # Topbar, TopbarQrCode, NotificationBanner, ContactAvatar, ...
├── data/ # appStore.svelte.ts, permissions.svelte.ts, shared.ts (URLs)
├── lib/ # graphql wrappers, server.ts (REST), subscriptions.ts,
│ ├── realtime/ # mobileHub.svelte.ts (SignalR)
│ └── paraglide/ # i18n scaffold (unused)
├── client.ts # Houdini client (Bearer + graphql-ws subscriptions)
├── app.html # shell (loads pexrtc etc.)
└── app.d.tsThere is also a checked-in schema.graphql next to the source (the client GraphQL schema snapshot used by Houdini) and .houdini/ (generated).
Key Concepts
- Multi-tenancy — the tenant realm is resolved from the subdomain via GraphQL
tenantInfo; Keycloak realm =hvc--+ tenant. - Auth — Keycloak login via
@rkosafo/cai.components; token refresh every 30 s; permissions resolved frommeintouserSession(src/data/permissions.svelte.ts). - Realtime — SignalR
/hubs/mobile(calls, chat, presence, devices) piped through a local pub/sub bus (src/lib/subscriptions.ts); per-call WebSocket for the roster. - Rapid Connect — anonymous device sign-in (no Keycloak) using a minted token.
Environments
The app runs against .env.* modes (dev, devlocal, myhippoio, rw):
text
npm run dev # mode=test
npm run dev:local # local backend
npm run dev:myhippo.io
npm run build # static SPA build (adapter-static, fallback index.html)Related
- Api — the backend this app talks to.
- Getting Started — running the portal locally.
- Shared Components — the
@rkosafo/cai.componentskit.