docs: sign-in is SSO-only, speech is a roster, the app is PedsHub Scribe
Some checks failed
Forgejo Docker Build / Root app tests (push) Successful in 48s
Forgejo Docker Build / Build Docker image (push) Successful in 6s
Forgejo Docker Build / End-to-end (browser) (push) Failing after 7s

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
This commit is contained in:
Daniel 2026-09-13 06:25:43 +02:00
parent 8c6126b112
commit 444fa44444
6 changed files with 47 additions and 10 deletions

View file

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

View file

@ -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 <token>` 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 <token>` header.
---

View file

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

View file

@ -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 <token>`. 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

View file

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

View file

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