docs: take the Learning Hub out of the docs
Some checks failed
Forgejo Docker Build / Root app tests (push) Successful in 47s
Forgejo Docker Build / Build Docker image (push) Successful in 22s
Forgejo Docker Build / Deploy to the host (push) Failing after 1s

The feature was removed; the docs still described it as live. Worst of
it was api-reference.md, which documented nine /api/learning endpoints
and fourteen /api/admin/learning CMS endpoints — routes that answer 404
— plus POST /api/user/webdav-path, whose column was dropped by
migration. Anyone reading them was reading fiction.

Checked against the running system rather than assumed: no learning
table exists, users.webdav_learning_path is gone, generated_image_links
is gone, and no route mounts /api/learning or /api/admin/learning.

Two things that look like Learning Hub and are not, so they stay:

- learningRetrieval.js is live — My Resources uses it. Its settings keep
  the learning.* names because renaming them would orphan whatever an
  administrator has already set. retrieval-tuning.md now says so instead
  of listing the rows under two different feature names.
- the moderator role is still assignable. It gated the CMS and now
  grants nothing; authentication.md says that rather than implying
  powers it does not have. moderatorMiddleware has no callers left,
  which is worth removing on its own.

auth-admin-learning.md is now auth-admin.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
This commit is contained in:
Daniel 2026-09-12 22:24:29 +02:00
parent 8ae47feeff
commit ceccd18387
15 changed files with 34 additions and 548 deletions

View file

@ -44,7 +44,7 @@ The app runs as an authenticated Express/Postgres service with a browser fronten
- Sign in with a password or a six-digit code emailed to you — offered side by side, because a code depends on mail arriving and a password does not.
- Role-based access, TOTP 2FA, OIDC/SSO, email verification, and optional Turnstile. Passwords are argon2id, with bcrypt rows rehashed on their next sign-in.
- Registration can be open, closed, or invite-only with generated codes. A code can be revoked while live, and deleted only once it is spent.
- Admin panel for users, settings, prompts, models, logs, and Learning Hub content.
- Admin panel for users, settings, prompts, models, and logs.
- Audit, API, access, and client-error logs with redaction hardening.
- OpenBao secret loading support at container startup.
- S3-compatible document storage support.

View file

@ -1,6 +1,6 @@
# API Reference
Working endpoint reference for the main PedAI flows. It covers the clinical, auth, Learning Hub, 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 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.
---
@ -19,8 +19,6 @@ Working endpoint reference for the main PedAI flows. It covers the clinical, aut
- [User Preferences](#user-preferences)
- [Phone Extensions And Pagers](#phone-extensions-and-pagers)
- [Nextcloud Integration](#nextcloud-integration)
- [Learning Hub (Public)](#learning-hub-public)
- [Learning Hub CMS (Moderator+)](#learning-hub-cms-moderator)
- [Admin - Users](#admin---users)
- [Admin - Configuration](#admin---configuration)
- [Logs](#logs)
@ -1130,26 +1128,6 @@ List available STT models and TTS voices that the user can choose from.
---
### POST /api/user/webdav-path
Save the user's preferred WebDAV learning content path.
- **Auth required:** Yes
- **Request body:**
```json
{
"path": "string"
}
```
- **Response:**
```json
{
"success": true
}
```
---
## Phone Extensions And Pagers
Base path: `/api/extensions`. All endpoints require authentication and operate on the current user's personal directory.
@ -1451,480 +1429,6 @@ Disconnect the user's Nextcloud integration.
---
## Learning Hub (Public)
Public-facing learning content endpoints. Authentication is required to track progress and submit quizzes.
### GET /api/learning/categories
List all learning content categories.
- **Auth required:** Yes
- **Response:**
```json
[
{
"id": "number",
"name": "string",
"slug": "string",
"description": "string"
}
]
```
---
### GET /api/learning/feed
Get a paginated feed of learning content.
- **Auth required:** Yes
- **Query parameters:**
| Parameter | Type | Default | Description |
|-----------|--------|---------|-----------------------|
| `limit` | number | 20 | Items per page |
| `offset` | number | 0 | Pagination offset |
- **Response:**
```json
[
{
"id": "number",
"title": "string",
"slug": "string",
"summary": "string",
"category": "string",
"created_at": "string (ISO 8601)"
}
]
```
---
### GET /api/learning/category/:slug
Get all learning content within a specific category.
- **Auth required:** Yes
- **Path parameters:**
| Parameter | Type | Description |
|-----------|--------|----------------|
| `slug` | string | Category slug |
- **Response:** Array of content items in the category.
---
### GET /api/learning/content/:slug
Get a single piece of learning content, including quiz questions, answer options, and the user's progress.
- **Auth required:** Yes
- **Path parameters:**
| Parameter | Type | Description |
|-----------|--------|---------------|
| `slug` | string | Content slug |
- **Response:**
```json
{
"id": "number",
"title": "string",
"slug": "string",
"body": "string (markdown)",
"category": "object",
"questions": [
{
"id": "number",
"text": "string",
"options": [
{
"id": "number",
"text": "string"
}
]
}
],
"progress": {
"completed": "boolean",
"score": "number | null"
}
}
```
---
### GET /api/learning/content/:slug/slides
Render Marp-formatted markdown content as HTML presentation slides.
- **Auth required:** Yes
- **Path parameters:**
| Parameter | Type | Description |
|-----------|--------|---------------|
| `slug` | string | Content slug |
- **Response:** HTML presentation content.
---
### POST /api/learning/submit-quiz
Submit quiz answers for a piece of learning content.
- **Auth required:** Yes
- **Request body:**
```json
{
"contentId": "number",
"answers": [
{
"questionId": "number",
"optionIds": ["number"]
}
]
}
```
- **Response:**
```json
{
"success": true,
"score": "number",
"total": "number",
"results": [
{
"questionId": "number",
"correct": "boolean"
}
]
}
```
---
### GET /api/learning/search
Keyword-based search across learning content.
- **Auth required:** Yes
- **Query parameters:**
| Parameter | Type | Description |
|-----------|--------|-----------------|
| `q` | string | Search query |
- **Response:** Array of matching content items.
---
### GET /api/learning/search/semantic
Semantic (vector-based) search across learning content using embeddings.
- **Auth required:** Yes
- **Query parameters:**
| Parameter | Type | Description |
|-----------|--------|-----------------|
| `q` | string | Search query |
- **Response:** Array of matching content items ranked by semantic similarity.
---
### GET /api/learning/search/hybrid
Combined keyword and semantic search for best-of-both-worlds results.
- **Auth required:** Yes
- **Query parameters:**
| Parameter | Type | Description |
|-----------|--------|-----------------|
| `q` | string | Search query |
- **Response:** Array of matching content items with combined ranking.
---
## Learning Hub CMS (Moderator+)
Content management endpoints for learning content. Requires moderator or admin role.
### GET /api/admin/learning/categories
List all learning categories (admin view).
- **Auth required:** Yes (moderator+)
- **Response:** Array of category objects.
---
### POST /api/admin/learning/categories
Create a new learning category.
- **Auth required:** Yes (moderator+)
- **Request body:**
```json
{
"name": "string",
"slug": "string",
"description": "string"
}
```
- **Response:**
```json
{
"success": true,
"id": "number"
}
```
---
### PUT /api/admin/learning/categories/:id
Update a learning category.
- **Auth required:** Yes (moderator+)
- **Path parameters:**
| Parameter | Type | Description |
|-----------|--------|---------------|
| `id` | number | Category ID |
- **Request body:**
```json
{
"name": "string",
"slug": "string",
"description": "string"
}
```
- **Response:**
```json
{
"success": true
}
```
---
### DELETE /api/admin/learning/categories/:id
Delete a learning category.
- **Auth required:** Yes (moderator+)
- **Path parameters:**
| Parameter | Type | Description |
|-----------|--------|---------------|
| `id` | number | Category ID |
- **Response:**
```json
{
"success": true
}
```
---
### GET /api/admin/learning/content
List all learning content (admin view, includes unpublished).
- **Auth required:** Yes (moderator+)
- **Response:** Array of content objects.
---
### POST /api/admin/learning/content
Create new learning content.
- **Auth required:** Yes (moderator+)
- **Request body:**
```json
{
"title": "string",
"slug": "string",
"body": "string (markdown)",
"categoryId": "number",
"questions": "array (optional)"
}
```
- **Response:**
```json
{
"success": true,
"id": "number"
}
```
---
### GET /api/admin/learning/content/:id
Get a single content item for editing.
- **Auth required:** Yes (moderator+)
- **Path parameters:**
| Parameter | Type | Description |
|-----------|--------|--------------|
| `id` | number | Content ID |
- **Response:** Full content object with questions and metadata.
---
### PUT /api/admin/learning/content/:id
Update existing learning content.
- **Auth required:** Yes (moderator+)
- **Path parameters:**
| Parameter | Type | Description |
|-----------|--------|--------------|
| `id` | number | Content ID |
- **Request body:**
```json
{
"title": "string",
"slug": "string",
"body": "string (markdown)",
"categoryId": "number",
"questions": "array (optional)"
}
```
- **Response:**
```json
{
"success": true
}
```
---
### DELETE /api/admin/learning/content/:id
Delete learning content.
- **Auth required:** Yes (moderator+)
- **Path parameters:**
| Parameter | Type | Description |
|-----------|--------|--------------|
| `id` | number | Content ID |
- **Response:**
```json
{
"success": true
}
```
---
### POST /api/admin/learning/ai-generate
Generate learning content or presentations using AI. Accepts either multipart form data (with file uploads) or JSON.
- **Auth required:** Yes (moderator+)
- **Content-Type:** `multipart/form-data` or `application/json`
- **Request body (JSON):**
```json
{
"topic": "string",
"type": "article | presentation",
"model": "string"
}
```
- **Request body (multipart):** Same fields plus uploaded reference files.
- **Response:**
```json
{
"success": true,
"content": "string (markdown)"
}
```
---
### POST /api/admin/learning/ai-refine
Refine learning content body text using AI.
- **Auth required:** Yes (moderator+)
- **Request body:**
```json
{
"body": "string",
"instructions": "string",
"model": "string"
}
```
- **Response:**
```json
{
"success": true,
"content": "string"
}
```
---
### POST /api/admin/learning/preview-slides
Preview Marp-formatted markdown as rendered presentation slides.
- **Auth required:** Yes (moderator+)
- **Request body:**
```json
{
"markdown": "string"
}
```
- **Response:**
```json
{
"css": "string",
"slides": ["string (HTML)"]
}
```
---
### POST /api/admin/learning/generate-pptx
Generate a PowerPoint file from Marp markdown.
- **Auth required:** Yes (moderator+)
- **Request body:**
```json
{
"markdown": "string",
"title": "string"
}
```
- **Response:** Binary `.pptx` file download.
---
### GET /api/admin/learning/webdav-browse
Browse files on the connected WebDAV/Nextcloud server.
- **Auth required:** Yes (moderator+)
- **Query parameters:**
| Parameter | Type | Description |
|-----------|--------|------------------------------|
| `path` | string | Directory path to browse |
- **Response:** Array of file/directory entries.
---
### GET /api/admin/learning/stats
Get learning hub statistics (content counts, quiz completion rates, etc.).
- **Auth required:** Yes (moderator+)
- **Response:**
```json
{
"totalContent": "number",
"totalCategories": "number",
"totalQuizSubmissions": "number",
"averageScore": "number"
}
```
---
## Admin - Users
Requires admin role.

View file

@ -183,7 +183,7 @@ Ped-AI is a self-hosted Express application with a browser frontend, PostgreSQL
| Area | Owner | Notes |
|---|---|---|
| Web app | Ped-AI | Auth, UI, clinical workflows, admin settings, notes, Learning Hub, bedside tools |
| Web app | Ped-AI | Auth, UI, clinical workflows, admin settings, notes, My Resources, bedside tools |
| Database | PostgreSQL | Users, sessions, settings, saved app data, audit/API/access logs |
| Operational cache | Redis | Prompt suggestions, lightweight state, queue groundwork; not clinical answer caching |
| Model gateway | LiteLLM | Text, speech and image model discovery and routing |

View file

@ -269,7 +269,7 @@ Helmet defaults plus:
| Role | Access |
|---|---|
| `admin` | Everything. First registered user auto-promoted. |
| `moderator` | Learning Hub CMS + standard user features. |
| `moderator` | Standard user features. The role is still assignable but no longer grants anything of its own — it gated the Learning Hub CMS, which has been removed. |
| `user` | Clinical features, no admin routes. |
## Audit logging

View file

@ -213,6 +213,6 @@ OpenAI-compatible gateway — LiteLLM, Bifrost, or other proxies.
## Retrieval sizing
How many corpus excerpts the Clinical Assistant, the Learning Hub and My
How many corpus excerpts the Clinical Assistant and My
Resources each receive, and the reranker cap that overrides all three:
[retrieval-tuning.md](retrieval-tuning.md).

View file

@ -40,7 +40,6 @@ Core accounts. Local-auth + OIDC federation + per-user preferences.
| nextcloud_url, nextcloud_user, nextcloud_token, nextcloud_folder | TEXT | WebDAV credentials. `nextcloud_token` stored AES-256-GCM encrypted (prefix `enc1:`). |
| reset_token, reset_expires | TEXT, BIGINT | Password reset |
| stt_model, tts_voice | TEXT | Per-user STT/TTS override |
| webdav_learning_path | TEXT | Learning Hub file-browser root |
| created_at, updated_at | TIMESTAMPTZ DEFAULT NOW() | |
### `user_sessions`
@ -296,9 +295,6 @@ becomes claimable again instead of being stuck.
| context_included, context_total | INTEGER | How much context the prompt could carry |
| created_at, updated_at | TIMESTAMPTZ NOT NULL | |
`generated_image_links(asset_id, content_id)` ties an image to the Learning Hub
content that embeds it.
### `mermaid_diagrams`
Saved diagrams: the Mermaid source plus the user's own notes.
@ -394,8 +390,6 @@ Core btree indexes — see `database.js` for the full list.
- `user_memories(user_id, category)`
- `audio_backups(user_id)`, `audio_backups(expires_at)`
- `user_documents(user_id)`
- `learning_content(category_id)`
- `learning_progress(user_id, content_id)`
- `developmental_milestones(age_group, domain)`
The `COLLATE "C"` indexes are immune to ICU library version changes between

View file

@ -284,9 +284,6 @@ docker exec -w /app pediatric-ai-scribe npm run migrate:new -- add_my_table
| `admin.js` | `/api/admin` | Admin | User management |
| `adminConfig.js` | `/api/admin` | Admin | Settings, prompts, models, SMTP, OIDC |
| `adminMilestones.js` | `/api/admin` | Admin | Milestone data management |
| `learningHub.js` | `/api/learning` | Auth | Content delivery + quizzes |
| `learningAdmin.js` | `/api/admin/learning` | Moderator | CMS CRUD |
| `learningAI.js` | `/api/admin/learning` | Moderator | AI content gen, PPTX export |
| `clinicalAssistant.js` | `/api` | Auth | Grounded clinical answers over MCP retrieval |
| `myResources.js` | `/api` | Auth | Personal teaching material: generate, refine, export |
| `notes.js` | `/api` | Auth | Personal notes |
@ -295,7 +292,7 @@ docker exec -w /app pediatric-ai-scribe npm run migrate:new -- add_my_table
| `patientEducation.js` | `/api` | Auth | Patient education handouts |
| `peGuide.js` | `/api` | Auth | Physical exam guide |
| `diagrams.js` | `/api` | Auth | Diagram rendering |
| `generatedImages.js` | `/api`, `/api/admin/learning/image` | Auth | Image generation jobs and their stored output |
| `generatedImages.js` | `/api`, `/api/admin` | Auth | Image generation jobs and their stored output |
| `extensions.js` | `/api` | Auth | Browser-extension integration |
| `adminDocs.js` | `/api/admin/docs` | Admin | In-app rendering of this `docs/` tree |
@ -319,7 +316,6 @@ docker exec -w /app pediatric-ai-scribe npm run migrate:new -- add_my_table
| `nextcloud.js` | Connect / export |
| `documents.js` | S3 upload / download |
| `calculators.js` | Pediatric calculators (BP, BMI, growth, bilirubin, vitals, etc.) |
| `learningHub.js` | Content browser + CMS editor |
| `accountBoundary.js` | One verified account owner per JS realm; guards cross-account leakage |
| `ed-encounters.js` | ED encounter workflow: staged notes, consolidate, MDM finalize |
| `voiceDictation.js` | Dictation capture and voice-mode call UI |
@ -332,7 +328,7 @@ docker exec -w /app pediatric-ai-scribe npm run migrate:new -- add_my_table
| `admin.js` | Admin panel (users, settings, prompts, models) |
Larger features live in their own directory rather than a single file:
`admin/`, `assistant/`, `bedside/`, `calculators/`, `learningHub/`, `notes/`,
`admin/`, `assistant/`, `bedside/`, `calculators/`, `notes/`,
and `wellVisit/`.
## Common tasks

View file

@ -8,7 +8,7 @@ A non-technical overview of what the app does today and how it can be taken furt
Pediatric AI Scribe is a clinical documentation tool for pediatric physicians. It listens to doctor-patient encounters (or accepts typed/pasted notes) and uses AI to generate structured medical notes — HPIs, SOAP notes, hospital courses, chart reviews, well visit and sick visit documentation.
It also includes pediatric calculators (blood pressure percentiles, BMI, growth charts, bilirubin nomograms, vital signs reference), a Learning Hub for educational content and quizzes, and a full security layer (two-factor authentication, session management, audit logging, single sign-on).
It also includes pediatric calculators (blood pressure percentiles, BMI, growth charts, bilirubin nomograms, vital signs reference), and a full security layer (two-factor authentication, session management, audit logging, single sign-on).
The app runs as a self-hosted web application with a mobile-friendly PWA interface.
@ -93,7 +93,7 @@ This would help administrators optimize model selection and identify training op
### 9. Patient Education Materials
**Current state:** Patient education handouts are active as post-note helpers. Generated notes can open a Handout panel that creates a parent-facing plain-text draft from the clinician note, with optional diagnosis, medication, patient age, and preferred language context. The Learning Hub remains the physician-facing education/CMS area.
**Current state:** Patient education handouts are active as post-note helpers. Generated notes can open a Handout panel that creates a parent-facing plain-text draft from the clinician note, with optional diagnosis, medication, patient age, and preferred language context.
**Further improvement:** Add handout templates, saved handout history, institution-approved language libraries, and printable/PDF export.

View file

@ -44,11 +44,10 @@ For someone brand new to the codebase:
routing, TTS, and the AudioRecorder. Voice/STT plumbing is high-risk — the
doc describes it without proposing changes.
6. **[auth-admin-learning.md](auth-admin-learning.md)** — Authentication
6. **[auth-admin.md](auth-admin.md)** — Authentication
(local + OIDC SSO + 2FA), session management, OpenBao secret loading
at container start, the Admin panel (model allowlist, prompt
overrides, milestone editor), and the Learning Hub (AI-authored
quizzes / outlines / Marp presentations).
at container start, and the Admin panel (model allowlist, prompt
overrides, milestone editor).
## What's NOT here

View file

@ -32,7 +32,7 @@ mobile support.
1. Load environment and core middleware.
2. Apply Helmet/CSP, CORS, cookie parsing, metrics, JSON limits, rate limiters,
static file serving, and logging.
3. Mount auth, admin, Learning Hub, clinical workflow, storage, user data,
3. Mount auth, admin, clinical workflow, storage, user data,
metrics, and utility routers.
4. Serve the SPA fallback for non-API paths.
5. Drain audit queues and close Postgres on shutdown.

View file

@ -1,6 +1,6 @@
# Auth, Admin, And Learning Hub Logic
# Auth And Admin Logic
This doc summarizes the current auth/admin/Learning Hub responsibilities. The
This doc summarizes the current auth/admin responsibilities. The
source of truth is `server.js`, `src/routes/*.js`, and the focused top-level
docs.
@ -31,20 +31,13 @@ login screen). Admin responsibilities include:
- milestone management
- admin docs browser
## Learning Hub
Learning Hub has two surfaces:
- learner/user-facing routes under `/api/learning`
- moderator/admin CMS routes under `/api/admin/learning`
## Security Rules
- Never expose raw secrets in admin health/config responses.
- Keep OIDC issuer validation and SSRF protections intact.
- Keep login, password reset, 2FA, and session endpoints rate-limited.
- Treat Learning Hub uploads as untrusted input and keep file-type checks.
- Sanitize rendered Learning Hub content.
- Treat uploaded files as untrusted input and keep the file-type checks.
- Sanitize any rendered user content.
## Change Checklist

View file

@ -4,12 +4,11 @@ Teaching material a signed-in user generates for themselves — a deck for
tomorrow's session, a handout, a summary — kept privately and exported as
PowerPoint, Word or PDF.
Deliberately separate from the Learning Hub. That is moderator-owned content
published into categories for everyone; this needs no role beyond being signed
in, and nothing here is shared. Every statement filters on `user_id`, and there
is no route that returns another person's work. Sharing, if it is ever wanted,
should be a deliberate feature rather than something that leaks out of a
forgotten `WHERE` clause.
Deliberately personal: everything here belongs to whoever made it. It needs no
role beyond being signed in, and nothing is shared. Every statement filters on
`user_id`, and there is no route that returns another person's work. Sharing,
if it is ever wanted, should be a deliberate feature rather than something that
leaks out of a forgotten `WHERE` clause.
## What a resource is
@ -177,8 +176,7 @@ covering sentence is read rather than refused.
`resourceImages.js`, **not** the shared `imageTool.dispatch` — that one permits
exactly one image per request, which is right for a chat reply and wrong for a
twelve-slide deck, and the clinical assistant and Learning Hub depend on that
rule. Same queue, same storage, same `my_resources` workflow, same asset
twelve-slide deck, and the clinical assistant depends on that rule. Same queue, same storage, same `my_resources` workflow, same asset
endpoint; only the number differs, bounded at `MAX_IMAGES` because each figure
is a paid request.
@ -275,9 +273,8 @@ colour on the resource, passed to the renderer — not a wider slide vocabulary.
## The image library
Library → **Images** is every picture the account has generated, across all
three features — My Resources, the Clinical Assistant and the Learning Hub —
newest first. A figure outlives the deck it was drawn for: the deck gets
Library → **Images** is every picture the account has generated — from My
Resources and from the Clinical Assistant — newest first. A figure outlives the deck it was drawn for: the deck gets
replaced, the diagram is still good.
`GET /api/generated-images` returns only finished jobs, scoped by `owner_id` in

View file

@ -11,7 +11,7 @@ coded.
A clinical documentation assistant. Two halves:
- **Workspace** — encounter notes, dictation, SOAP, well and sick visits, ED,
hospital course, calculators, Learning Hub. Each generates text with an LLM
hospital course, calculators, My Resources. Each generates text with an LLM
through the LiteLLM gateway.
- **Clinical Assistant** — a chat that answers only from an indexed medical
library, with numbered citations back to the source documents.
@ -61,8 +61,7 @@ bootstrap that provisions the roles.
| Data | Where |
|---|---|
| Accounts, notes, encounters, Learning Hub content and quizzes | Postgres (`pedscribe`) |
| Learning Hub semantic search | `learning_content.embedding`, pgvector |
| Accounts, notes, encounters, saved resources | Postgres (`pedscribe`) |
| Generated images | MinIO bucket `generated-images` |
| Voice recordings, kept 24 hours | MinIO bucket `audio-backups` |
| Medical library chunks | Clinical Milvus |

View file

@ -54,8 +54,12 @@ clamped on read so a bad value cannot break a search.
| Feature | Keys | Default | Clamp |
|---|---|---|---|
| Clinical Assistant | `clinical_assistant.search_limit`, `clinical_assistant.context_chars` | 8, 1400 | 320, 3004000 |
| Learning Hub | `learning.search_limit`, `learning.context_chars` | 30, 2500 | 360, 3008000 |
| My Resources | *the same `learning.*` keys* | 30, 2500 | 360, 3008000 |
| My Resources | `learning.search_limit`, `learning.context_chars` | 30, 2500 | 360, 3008000 |
The `learning.*` names are historical: they were the Learning Hub's, and My
Resources inherited the retrieval code when that was removed. Renaming the keys
would orphan whatever an administrator has already set, so they keep the old
names.
`search_limit` is how many excerpts to request; `context_chars` is how much text
to pull around each one.

View file

@ -58,7 +58,7 @@ Consider moving these to a queue when latency or concurrency becomes a problem:
- long transcription jobs,
- file import/export,
- Learning Hub AI generation from large files,
- My Resources generation from large files,
- image generation,
- bulk document operations,
- provider metadata refresh,