docs: take the Learning Hub out of the docs
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:
parent
8ae47feeff
commit
ceccd18387
15 changed files with 34 additions and 548 deletions
|
|
@ -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.
|
- 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.
|
- 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.
|
- 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.
|
- Audit, API, access, and client-error logs with redaction hardening.
|
||||||
- OpenBao secret loading support at container startup.
|
- OpenBao secret loading support at container startup.
|
||||||
- S3-compatible document storage support.
|
- S3-compatible document storage support.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# API Reference
|
# 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)
|
- [User Preferences](#user-preferences)
|
||||||
- [Phone Extensions And Pagers](#phone-extensions-and-pagers)
|
- [Phone Extensions And Pagers](#phone-extensions-and-pagers)
|
||||||
- [Nextcloud Integration](#nextcloud-integration)
|
- [Nextcloud Integration](#nextcloud-integration)
|
||||||
- [Learning Hub (Public)](#learning-hub-public)
|
|
||||||
- [Learning Hub CMS (Moderator+)](#learning-hub-cms-moderator)
|
|
||||||
- [Admin - Users](#admin---users)
|
- [Admin - Users](#admin---users)
|
||||||
- [Admin - Configuration](#admin---configuration)
|
- [Admin - Configuration](#admin---configuration)
|
||||||
- [Logs](#logs)
|
- [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
|
## Phone Extensions And Pagers
|
||||||
|
|
||||||
Base path: `/api/extensions`. All endpoints require authentication and operate on the current user's personal directory.
|
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
|
## Admin - Users
|
||||||
|
|
||||||
Requires admin role.
|
Requires admin role.
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ Ped-AI is a self-hosted Express application with a browser frontend, PostgreSQL
|
||||||
|
|
||||||
| Area | Owner | Notes |
|
| 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 |
|
| 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 |
|
| Operational cache | Redis | Prompt suggestions, lightweight state, queue groundwork; not clinical answer caching |
|
||||||
| Model gateway | LiteLLM | Text, speech and image model discovery and routing |
|
| Model gateway | LiteLLM | Text, speech and image model discovery and routing |
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ Helmet defaults plus:
|
||||||
| Role | Access |
|
| Role | Access |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `admin` | Everything. First registered user auto-promoted. |
|
| `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. |
|
| `user` | Clinical features, no admin routes. |
|
||||||
|
|
||||||
## Audit logging
|
## Audit logging
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,6 @@ OpenAI-compatible gateway — LiteLLM, Bifrost, or other proxies.
|
||||||
|
|
||||||
## Retrieval sizing
|
## 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:
|
Resources each receive, and the reranker cap that overrides all three:
|
||||||
[retrieval-tuning.md](retrieval-tuning.md).
|
[retrieval-tuning.md](retrieval-tuning.md).
|
||||||
|
|
|
||||||
|
|
@ -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:`). |
|
| 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 |
|
| reset_token, reset_expires | TEXT, BIGINT | Password reset |
|
||||||
| stt_model, tts_voice | TEXT | Per-user STT/TTS override |
|
| 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() | |
|
| created_at, updated_at | TIMESTAMPTZ DEFAULT NOW() | |
|
||||||
|
|
||||||
### `user_sessions`
|
### `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 |
|
| context_included, context_total | INTEGER | How much context the prompt could carry |
|
||||||
| created_at, updated_at | TIMESTAMPTZ NOT NULL | |
|
| 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`
|
### `mermaid_diagrams`
|
||||||
|
|
||||||
Saved diagrams: the Mermaid source plus the user's own notes.
|
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)`
|
- `user_memories(user_id, category)`
|
||||||
- `audio_backups(user_id)`, `audio_backups(expires_at)`
|
- `audio_backups(user_id)`, `audio_backups(expires_at)`
|
||||||
- `user_documents(user_id)`
|
- `user_documents(user_id)`
|
||||||
- `learning_content(category_id)`
|
|
||||||
- `learning_progress(user_id, content_id)`
|
|
||||||
- `developmental_milestones(age_group, domain)`
|
- `developmental_milestones(age_group, domain)`
|
||||||
|
|
||||||
The `COLLATE "C"` indexes are immune to ICU library version changes between
|
The `COLLATE "C"` indexes are immune to ICU library version changes between
|
||||||
|
|
|
||||||
|
|
@ -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 |
|
| `admin.js` | `/api/admin` | Admin | User management |
|
||||||
| `adminConfig.js` | `/api/admin` | Admin | Settings, prompts, models, SMTP, OIDC |
|
| `adminConfig.js` | `/api/admin` | Admin | Settings, prompts, models, SMTP, OIDC |
|
||||||
| `adminMilestones.js` | `/api/admin` | Admin | Milestone data management |
|
| `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 |
|
| `clinicalAssistant.js` | `/api` | Auth | Grounded clinical answers over MCP retrieval |
|
||||||
| `myResources.js` | `/api` | Auth | Personal teaching material: generate, refine, export |
|
| `myResources.js` | `/api` | Auth | Personal teaching material: generate, refine, export |
|
||||||
| `notes.js` | `/api` | Auth | Personal notes |
|
| `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 |
|
| `patientEducation.js` | `/api` | Auth | Patient education handouts |
|
||||||
| `peGuide.js` | `/api` | Auth | Physical exam guide |
|
| `peGuide.js` | `/api` | Auth | Physical exam guide |
|
||||||
| `diagrams.js` | `/api` | Auth | Diagram rendering |
|
| `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 |
|
| `extensions.js` | `/api` | Auth | Browser-extension integration |
|
||||||
| `adminDocs.js` | `/api/admin/docs` | Admin | In-app rendering of this `docs/` tree |
|
| `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 |
|
| `nextcloud.js` | Connect / export |
|
||||||
| `documents.js` | S3 upload / download |
|
| `documents.js` | S3 upload / download |
|
||||||
| `calculators.js` | Pediatric calculators (BP, BMI, growth, bilirubin, vitals, etc.) |
|
| `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 |
|
| `accountBoundary.js` | One verified account owner per JS realm; guards cross-account leakage |
|
||||||
| `ed-encounters.js` | ED encounter workflow: staged notes, consolidate, MDM finalize |
|
| `ed-encounters.js` | ED encounter workflow: staged notes, consolidate, MDM finalize |
|
||||||
| `voiceDictation.js` | Dictation capture and voice-mode call UI |
|
| `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) |
|
| `admin.js` | Admin panel (users, settings, prompts, models) |
|
||||||
|
|
||||||
Larger features live in their own directory rather than a single file:
|
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/`.
|
and `wellVisit/`.
|
||||||
|
|
||||||
## Common tasks
|
## Common tasks
|
||||||
|
|
|
||||||
|
|
@ -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.
|
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.
|
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
|
### 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.
|
**Further improvement:** Add handout templates, saved handout history, institution-approved language libraries, and printable/PDF export.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,10 @@ For someone brand new to the codebase:
|
||||||
routing, TTS, and the AudioRecorder. Voice/STT plumbing is high-risk — the
|
routing, TTS, and the AudioRecorder. Voice/STT plumbing is high-risk — the
|
||||||
doc describes it without proposing changes.
|
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
|
(local + OIDC SSO + 2FA), session management, OpenBao secret loading
|
||||||
at container start, the Admin panel (model allowlist, prompt
|
at container start, and the Admin panel (model allowlist, prompt
|
||||||
overrides, milestone editor), and the Learning Hub (AI-authored
|
overrides, milestone editor).
|
||||||
quizzes / outlines / Marp presentations).
|
|
||||||
|
|
||||||
## What's NOT here
|
## What's NOT here
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ mobile support.
|
||||||
1. Load environment and core middleware.
|
1. Load environment and core middleware.
|
||||||
2. Apply Helmet/CSP, CORS, cookie parsing, metrics, JSON limits, rate limiters,
|
2. Apply Helmet/CSP, CORS, cookie parsing, metrics, JSON limits, rate limiters,
|
||||||
static file serving, and logging.
|
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.
|
metrics, and utility routers.
|
||||||
4. Serve the SPA fallback for non-API paths.
|
4. Serve the SPA fallback for non-API paths.
|
||||||
5. Drain audit queues and close Postgres on shutdown.
|
5. Drain audit queues and close Postgres on shutdown.
|
||||||
|
|
|
||||||
|
|
@ -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
|
source of truth is `server.js`, `src/routes/*.js`, and the focused top-level
|
||||||
docs.
|
docs.
|
||||||
|
|
||||||
|
|
@ -31,20 +31,13 @@ login screen). Admin responsibilities include:
|
||||||
- milestone management
|
- milestone management
|
||||||
- admin docs browser
|
- 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
|
## Security Rules
|
||||||
|
|
||||||
- Never expose raw secrets in admin health/config responses.
|
- Never expose raw secrets in admin health/config responses.
|
||||||
- Keep OIDC issuer validation and SSRF protections intact.
|
- Keep OIDC issuer validation and SSRF protections intact.
|
||||||
- Keep login, password reset, 2FA, and session endpoints rate-limited.
|
- Keep login, password reset, 2FA, and session endpoints rate-limited.
|
||||||
- Treat Learning Hub uploads as untrusted input and keep file-type checks.
|
- Treat uploaded files as untrusted input and keep the file-type checks.
|
||||||
- Sanitize rendered Learning Hub content.
|
- Sanitize any rendered user content.
|
||||||
|
|
||||||
## Change Checklist
|
## Change Checklist
|
||||||
|
|
||||||
|
|
@ -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
|
tomorrow's session, a handout, a summary — kept privately and exported as
|
||||||
PowerPoint, Word or PDF.
|
PowerPoint, Word or PDF.
|
||||||
|
|
||||||
Deliberately separate from the Learning Hub. That is moderator-owned content
|
Deliberately personal: everything here belongs to whoever made it. It needs no
|
||||||
published into categories for everyone; this needs no role beyond being signed
|
role beyond being signed in, and nothing is shared. Every statement filters on
|
||||||
in, and nothing here is shared. Every statement filters on `user_id`, and there
|
`user_id`, and there is no route that returns another person's work. Sharing,
|
||||||
is no route that returns another person's work. Sharing, if it is ever wanted,
|
if it is ever wanted, should be a deliberate feature rather than something that
|
||||||
should be a deliberate feature rather than something that leaks out of a
|
leaks out of a forgotten `WHERE` clause.
|
||||||
forgotten `WHERE` clause.
|
|
||||||
|
|
||||||
## What a resource is
|
## 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
|
`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
|
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
|
twelve-slide deck, and the clinical assistant depends on that rule. Same queue, same storage, same `my_resources` workflow, same asset
|
||||||
rule. Same queue, same storage, same `my_resources` workflow, same asset
|
|
||||||
endpoint; only the number differs, bounded at `MAX_IMAGES` because each figure
|
endpoint; only the number differs, bounded at `MAX_IMAGES` because each figure
|
||||||
is a paid request.
|
is a paid request.
|
||||||
|
|
||||||
|
|
@ -275,9 +273,8 @@ colour on the resource, passed to the renderer — not a wider slide vocabulary.
|
||||||
|
|
||||||
## The image library
|
## The image library
|
||||||
|
|
||||||
Library → **Images** is every picture the account has generated, across all
|
Library → **Images** is every picture the account has generated — from My
|
||||||
three features — My Resources, the Clinical Assistant and the Learning Hub —
|
Resources and from the Clinical Assistant — newest first. A figure outlives the deck it was drawn for: the deck gets
|
||||||
newest first. A figure outlives the deck it was drawn for: the deck gets
|
|
||||||
replaced, the diagram is still good.
|
replaced, the diagram is still good.
|
||||||
|
|
||||||
`GET /api/generated-images` returns only finished jobs, scoped by `owner_id` in
|
`GET /api/generated-images` returns only finished jobs, scoped by `owner_id` in
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ coded.
|
||||||
A clinical documentation assistant. Two halves:
|
A clinical documentation assistant. Two halves:
|
||||||
|
|
||||||
- **Workspace** — encounter notes, dictation, SOAP, well and sick visits, ED,
|
- **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.
|
through the LiteLLM gateway.
|
||||||
- **Clinical Assistant** — a chat that answers only from an indexed medical
|
- **Clinical Assistant** — a chat that answers only from an indexed medical
|
||||||
library, with numbered citations back to the source documents.
|
library, with numbered citations back to the source documents.
|
||||||
|
|
@ -61,8 +61,7 @@ bootstrap that provisions the roles.
|
||||||
|
|
||||||
| Data | Where |
|
| Data | Where |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Accounts, notes, encounters, Learning Hub content and quizzes | Postgres (`pedscribe`) |
|
| Accounts, notes, encounters, saved resources | Postgres (`pedscribe`) |
|
||||||
| Learning Hub semantic search | `learning_content.embedding`, pgvector |
|
|
||||||
| Generated images | MinIO bucket `generated-images` |
|
| Generated images | MinIO bucket `generated-images` |
|
||||||
| Voice recordings, kept 24 hours | MinIO bucket `audio-backups` |
|
| Voice recordings, kept 24 hours | MinIO bucket `audio-backups` |
|
||||||
| Medical library chunks | Clinical Milvus |
|
| Medical library chunks | Clinical Milvus |
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,12 @@ clamped on read so a bad value cannot break a search.
|
||||||
| Feature | Keys | Default | Clamp |
|
| Feature | Keys | Default | Clamp |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| Clinical Assistant | `clinical_assistant.search_limit`, `clinical_assistant.context_chars` | 8, 1400 | 3–20, 300–4000 |
|
| Clinical Assistant | `clinical_assistant.search_limit`, `clinical_assistant.context_chars` | 8, 1400 | 3–20, 300–4000 |
|
||||||
| Learning Hub | `learning.search_limit`, `learning.context_chars` | 30, 2500 | 3–60, 300–8000 |
|
| My Resources | `learning.search_limit`, `learning.context_chars` | 30, 2500 | 3–60, 300–8000 |
|
||||||
| My Resources | *the same `learning.*` keys* | 30, 2500 | 3–60, 300–8000 |
|
|
||||||
|
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
|
`search_limit` is how many excerpts to request; `context_chars` is how much text
|
||||||
to pull around each one.
|
to pull around each one.
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ Consider moving these to a queue when latency or concurrency becomes a problem:
|
||||||
|
|
||||||
- long transcription jobs,
|
- long transcription jobs,
|
||||||
- file import/export,
|
- file import/export,
|
||||||
- Learning Hub AI generation from large files,
|
- My Resources generation from large files,
|
||||||
- image generation,
|
- image generation,
|
||||||
- bulk document operations,
|
- bulk document operations,
|
||||||
- provider metadata refresh,
|
- provider metadata refresh,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue