From 444fa444444ff376e2491ae9912ba35d1098e511 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 13 Sep 2026 06:25:43 +0200 Subject: [PATCH] docs: sign-in is SSO-only, speech is a roster, the app is PedsHub Scribe Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU --- README.md | 2 +- docs/api-reference.md | 2 +- docs/authentication.md | 13 +++++++++++++ docs/configuration.md | 3 +-- docs/features-explained.md | 21 +++++++++++++++++++-- docs/speech.md | 16 ++++++++++++---- 6 files changed, 47 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index abdb4a7f..1e473021 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ Primary references: - `docs/configuration.md` — environment variables and live `app_settings`. - `docs/database.md` — every table, its columns, and what is encrypted. - `docs/migrations.md` — how schema changes are made and applied. -- `docs/authentication.md` — auth, OIDC, sign-in codes, invites, rate limits. +- `docs/authentication.md` — SSO-only sign-in, OIDC, sessions, rate limits. - `docs/ai-providers.md` — provider selection, prompts, injection hardening. - `docs/clinical-assistant.md` — MCP-backed assistant behavior and safety rules. - `docs/retrieval-tuning.md` — how much corpus each feature retrieves, and what it costs. diff --git a/docs/api-reference.md b/docs/api-reference.md index 35fc939e..92215722 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -1,6 +1,6 @@ # API Reference -Working endpoint reference for the main PedAI flows. It covers the clinical, auth, user data, and admin surfaces most commonly used by the frontend, but the source of truth is still `server.js` plus `src/routes/*.js`. Unless noted otherwise, authenticated endpoints require a valid web cookie or `Authorization: Bearer ` header. +Working endpoint reference for the main PedsHub Scribe flows. It covers the clinical, auth, user data, and admin surfaces most commonly used by the frontend, but the source of truth is still `server.js` plus `src/routes/*.js`. Unless noted otherwise, authenticated endpoints require a valid web cookie or `Authorization: Bearer ` header. --- diff --git a/docs/authentication.md b/docs/authentication.md index 363d64e9..615e437b 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -1,5 +1,18 @@ # Authentication & security +## Sign-in is SSO-only + +The front door is `sso.pedshub.com` (Authentik, `/home/danvics/docker/authentik-pedshub`). +`oidc.enabled` and `oidc.disable_local_auth` are both `true`, so `/api/auth/login`, +`/register`, `/forgot-password`, `/reset-password`, `/change-password` and the 2FA +routes answer 403 (`requireLocalAuth`). The OIDC client is `src/routes/oidc.js`: +signed state cookie, PKCE, nonce, `email_verified` required before an existing +local account is linked, `sub` mismatch refused, session row written before the +cookie is set. New accounts are created at the SSO from an invitation link +(`invite.py` there); an SSO account whose email matches a local one signs into +that account. The sections below describe the local machinery that remains +behind the switch. + ## Password hashing - Primary: **argon2id**, memory cost 19 MiB, time cost 2, parallelism 1 diff --git a/docs/configuration.md b/docs/configuration.md index 9426473e..91c682c6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -55,7 +55,7 @@ keys): | Variable | Purpose | |---|---| | `LITELLM_TTS_MODEL`, `LITELLM_TTS_VOICE` | LiteLLM-routed TTS model and default voice. | -| `LITELLM_TTS_VOICES` | Comma-separated LiteLLM-compatible voices exposed in voice search and user preferences. | +| `LITELLM_TTS_VOICES` | The voices of `LITELLM_TTS_MODEL` only; other models use the built-in table in `src/utils/ttsProvider.js`. The roster itself is `tts.roster` in `app_settings`. | ### Embeddings @@ -80,7 +80,6 @@ keys): | `METRICS_TOKEN` | Lets `/metrics` be scraped from off-host with `Authorization: Bearer `. Without it, any request carrying `X-Forwarded-For` gets a 404, so only same-host scrapes succeed. | | `API_RATE_LIMIT_MAX` | General request ceiling per IP per minute (default 200). | | `LOGIN_RATE_LIMIT_MAX` | Sign-in attempts per IP per 15 min (default 10). Raised in the e2e stack so multi-worker Playwright runs do not trip it. | -| `LOGIN_CODE_RATE_LIMIT_MAX` | Emailed sign-in codes per IP per hour (default 5). Lower than the sign-in limit because each request sends mail to somebody else's address. See `docs/authentication.md`. | ### Integrations diff --git a/docs/features-explained.md b/docs/features-explained.md index a9dde22b..c91a2d9d 100644 --- a/docs/features-explained.md +++ b/docs/features-explained.md @@ -22,9 +22,26 @@ Browser-native Web Speech is only an explicit opt-in preview path. It is not the Browser Whisper and browser-local model workers are removed. Do not expect a pre-download model button, public Whisper worker, or bundled Xenova model path. +## Signing in + +Sign-in is **SSO-only**: the sign-in screen has one button, "Sign in with +PedsHub", which goes to `sso.pedshub.com` (Authentik). There a person types +their email and the code that is sent to it — no password. New people are +invited with a sign-up link (`authentik-pedshub/invite.py` on the host mints +one); they enter a name and email, confirm with a code, and land in the +`pedshub-members` group, which is what both PedsHub apps admit. The same +account signs into the quiz app at `pedshub.com`. Local password sign-in, +registration, reset and the app's own emailed codes are switched off +(`oidc.disable_local_auth`); a local account with the same email is the same +account. + ## Text To Speech -The voice preview button calls LiteLLM TTS and plays the returned audio in the browser. If preview is silent, check that a LiteLLM voice is selected, the gateway is configured, the user is authenticated, and browser autoplay has not blocked playback. +Read Aloud uses a **roster** of speech models (Admin → Models → Speech): each +model brings the voices it accepts, and the default is a model-and-voice pair. +Users choose any voice of any roster model under Settings and preview it. If a +preview is silent, check that a default pair is set, the gateway is configured, +and browser autoplay has not blocked playback. ## Nextcloud WebDAV @@ -100,7 +117,7 @@ Admins can manage users, roles, registration, security settings, model defaults, | Clinical Assistant | Active | Grounded answers over MCP retrieval, with citations and source cards. | | My Resources | Active | Personal teaching decks and documents, rendered by python-pptx / python-docx. | | Deck vision review | Optional | Off by default; one pass, admin-configurable model. | -| Passwordless sign-in codes | Active | Emailed 6-digit code; password sign-in always stays available. | +| Sign-in | SSO-only | `sso.pedshub.com`: email → code. Invitation links create accounts. | | Personal notes | Active | Including dictation, with trash and restore. | ## Troubleshooting diff --git a/docs/speech.md b/docs/speech.md index 12a94f8d..9e1ec043 100644 --- a/docs/speech.md +++ b/docs/speech.md @@ -59,11 +59,19 @@ Browser-native Web Speech can show interim text when the user explicitly enables `POST /api/text-to-speech` returns audio from LiteLLM `/audio/speech`. The `X-TTS-Provider` response header identifies the LiteLLM model used. Requests are limited to 5000 characters. -| Provider | Notes | -|---|---| -| LiteLLM | Uses `LITELLM_TTS_MODEL` and `LITELLM_TTS_VOICE`. | +Speech models sit on a roster (`tts.roster`, Admin → Models → Speech), and the +default is a pair — `tts.model` and `tts.voice`, set together through +`PUT /api/admin/config/tts/default`, which refuses a voice the model does not +accept. `LITELLM_TTS_MODEL` / `LITELLM_TTS_VOICE` are the fallback when no +default has been chosen. -The admin/user voice pickers read available LiteLLM-compatible voices from `LITELLM_TTS_VOICES`. +Which voices a model accepts is a property of the model, not the gateway +(`/model/info` carries no voice field), so the table lives in +`src/utils/ttsProvider.js` (`MODEL_VOICES`, keyed by family: Kokoro, Orpheus +English/Arabic, Fish). `LITELLM_TTS_VOICES` names the voices of +`LITELLM_TTS_MODEL` only. A user's choice is stored as `model|voice`, so Read +Aloud sends each voice to the model that accepts it; `chooseTTS` is the one +place that decision is made. ## Recording