Skip to content

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 *.gql docs, generated $houdini stores)
  • Styling: Tailwind CSS 4 (@tailwindcss/vite)
  • TypeScript: 5.9
  • Auth: Keycloak + OIDC via the shared @rkosafo/cai.components package
  • Realtime: @microsoft/signalr (/hubs/mobile) + per-call WebSocket
  • Video: Pexip WebRTC (pexrtc.js loaded from static/)

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.ts

There 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 from me into userSession (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)

Released under the MIT License.