Commit graph

67 commits

Author SHA1 Message Date
Daniel
a0d81789ff feat: My Resources — anyone can generate teaching material, privately
Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 49s
Forgejo Docker Build / Root app tests (push) Successful in 47s
Forgejo Android APK / Build signed APK (push) Successful in 2m2s
Forgejo Docker Build / Build Docker image (push) Successful in 9s
Forgejo Docker Build / Deploy to the host (push) Failing after 2s
Learning is moderator-owned: content published into categories that everyone
sees, behind router.use(moderatorMiddleware). That is right for institutional
material and wrong as the only way in — an ordinary user could not generate
anything at all.

So this is a separate pathway rather than a loosening of that one. Learning is
untouched; the moderator gate stays exactly where it was. A signed-in user can
generate a deck or an article for their own use, keep it, refine it and export
it, and nobody else ever sees it.

Private by construction. Every statement filters on the owner and there is no
route that returns another person's work, which a test asserts statement by
statement rather than trusting. The foreign key cascades, so deleting an account
takes its drafts with it. There is no category, no publish state and no sharing:
adding sharing later should be a deliberate feature, not something that leaks
out of a forgotten WHERE clause.

Markdown is the artifact. Every format is rendered from it on demand — pptx and
docx by pandoc, both carrying the house reference deck, and PDF by Gotenberg,
whose LibreOffice preserves a deck's layout in a way rendering from markdown
would not. That is what makes "add a slide on when to admit" a text edit rather
than a binary patch.

Gotenberg was published on the host but on a network of its own, so reaching it
from a container went out and back through the host gateway. It now joins
danvics_convert, owned by danvics-net like the others. PDF is the one export
allowed to fail: if that service is down, the deck and the document still
download and the error says which.

Verified end to end as a plain user: the moderator route still refuses with 403,
generation returned a deck grounded on 12 corpus excerpts, the library lists
only their own, pptx/docx/pdf all downloaded valid, "add a slide on when to
admit" put the slide in the right place and left References last, and an
unauthenticated request gets 401 while someone else's id gets 404.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-11 14:50:54 +02:00
Daniel
97454a8941 refactor: the clinical index volume is named for what it holds
Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 55s
Forgejo Docker Build / Root app tests (push) Successful in 47s
Forgejo Android APK / Build signed APK (push) Successful in 1m56s
Forgejo Docker Build / Build Docker image (push) Successful in 12s
Forgejo Docker Build / Deploy to the host (push) Failing after 0s
mcp-server_mcp-data carried the Compose project prefix, which tied its name to a
directory that has since been renamed to clinical-assist-deploy. It is now
clinical-assist-data, named explicitly in both stacks so it no longer depends on
a project name at all.

Migrated rather than renamed, because Docker cannot rename a volume: writers
stopped, 2.9GB copied, then verified before switching — 13265 files both sides,
3080478708 bytes of file content both sides, and an md5 over every file in
sorted order matching exactly. The old volume is kept, and is now referenced by
nothing, so it can be removed once this has run for a while.

Also removed mcp-server_qdrant-data: 1.7GB belonging to a Qdrant deployment that
no longer exists and which no container mounted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-11 04:26:04 +02:00
Daniel
85dbbc1a4a fix: the clinical MCP has a name that says what it is; gateway from the vault
Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 52s
Forgejo Docker Build / Root app tests (push) Successful in 47s
Forgejo Android APK / Build signed APK (push) Successful in 2m14s
Forgejo Docker Build / Build Docker image (push) Successful in 18s
Forgejo Docker Build / Deploy to the host (push) Failing after 0s
"mcp" said nothing — this host runs several MCP servers. The clinical corpus
query service now also answers to clinical-mcp, and ped-ai asks for it by that
name. The bare service name stays an alias automatically, so anything still
pointing at http://mcp:8000 keeps working. Hyphens rather than underscores:
underscores are legal in Docker's embedded DNS but not in hostnames generally.

LITELLM_API_BASE goes back to being unset here, so OpenBao's
https://llm.danvics.com applies. The public hostname is the deliberate choice for
consistency across the estate. It is not a speed question — the gateway hop is
~19ms on calls taking hundreds of milliseconds, and describing that as "4x" was
a misleading way to put it. The real cost is that AI calls now depend on Caddy,
public DNS and edge TLS; one line here pins it back to the container network.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-11 03:49:41 +02:00
Daniel
f735e2e910 fix: ped-ai leaves Open WebUI's network, and pins LiteLLM internally on purpose
Some checks failed
Forgejo Android APK / Build signed APK (push) Blocked by required conditions
Forgejo Docker Build / Build Docker image (push) Blocked by required conditions
Forgejo Docker Build / Deploy to the host (push) Blocked by required conditions
Forgejo Android APK / Root app tests (push) Successful in 48s
Forgejo Docker Build / Root app tests (push) Has been cancelled
ped-ai joined open-webui_openwebui-network to resolve exactly one hostname:
libretranslate. LibreTranslate is its own Compose project but had no network of
its own, so it borrowed Open WebUI's — which meant a clinical app's startup was
coupled to an unrelated stack's lifecycle for a translation call.

LibreTranslate now owns danvics_translate and ped-ai joins that instead. It also
keeps its Open WebUI attachment, because Open WebUI is configured to use it
(webui.db refers to it) and cutting that would have broken translation there
silently. Verified after the move that Open WebUI still reaches it.

LITELLM_API_BASE is pinned to the container network again, now deliberately and
with the reason recorded: clinical traffic should not leave the host or depend on
Caddy, public DNS and edge TLS. Speed is not the reason — it is ~19ms on calls
taking hundreds of ms, and quoting that as "4x" was misleading. OpenBao still
stores the public URL for this key and Compose wins, so the vault value is dead
until someone changes it by hand; the app's AppRole is read-only by design.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-11 02:39:57 +02:00
Daniel
20ef50e8e9 fix: the hidden attribute now hides, and the gateway URL comes from the vault
Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 46s
Forgejo Docker Build / Root app tests (push) Successful in 53s
Forgejo Android APK / Build signed APK (push) Successful in 1m57s
Forgejo Docker Build / Build Docker image (push) Successful in 10s
Forgejo Docker Build / Deploy to the host (push) Failing after 1s
"Retry loading settings" was permanently on screen even though the settings had
loaded fine. The browser's [hidden]{display:none} lives in the user agent
stylesheet, so any author rule setting display beats it — .btn-sm sets
display:inline-flex, so `<button hidden class="btn-sm btn-ghost">` never hid.
Earlier fixes bolted style="display:none" onto individual elements one at a
time; one [hidden]{display:none!important} covers all fourteen.

LITELLM_API_BASE is no longer pinned in Compose. Compose env wins over OpenBao,
so hardcoding http://litellm:4000 silently overrode the vault's
https://llm.danvics.com and the intended configuration had never taken effect.
The entrypoint now applies 28 secrets rather than 27, with 2 deliberate
overrides rather than 3. Transcription, text-to-speech and the signed-out
preview were all checked through the public gateway afterwards.

Worth recording since it was the reason for the change: this clears no network
dependency. ped-ai still needs danvics_mcp for mcp, the assets network for
MinIO, the openwebui network for LibreTranslate and danvics_monitoring for Loki;
none of those has a public route. It also adds about 20ms per call.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-11 02:29:55 +02:00
Daniel
ca0be0a98e fix: the sign-in line describes the app, and ped-ai drops a network it never used
Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 49s
Forgejo Docker Build / Root app tests (push) Successful in 49s
Forgejo Android APK / Build signed APK (push) Successful in 2m5s
Forgejo Docker Build / Build Docker image (push) Successful in 11s
Forgejo Docker Build / Deploy to the host (push) Failing after 0s
"AI-Powered Clinical Documentation" named about a third of what is here.
Documentation is one pillar; the assistant and the learning hub are the others,
and none of it said pediatric, which is both true and the differentiator.

danvics_speech is gone from ped-ai. Everything ped-ai dials was checked against
every network it joins: assets, libretranslate, litellm, mcp and monitoring-loki
are the only internal hosts, and litellm answers to that alias on danvics_mcp
already. supertonic/kokoro/sherpa appear here only as LiteLLM model ids and
voice names, never as hostnames — speech goes through the gateway, exactly as
intended. Joining danvics_speech therefore bought no reachability and cost a
cold-boot dependency on local-speech-gateway, which had to have been up once
before ped-ai could start at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-11 01:37:39 +02:00
Daniel
8d0dc968b3 feat: a deploy you can repeat, and prove afterwards
Reproducibility means two things here: the same commit builds the same image,
and the running container can be asked which commit it is.

  - Base images are pinned by digest, not by tag. A tag moves; two builds of one
    commit could otherwise differ. These are manifest-list digests, so buildx
    still picks the right architecture.

  - scripts/build-image.sh also writes ped-ai-local:<revision>, an immutable
    name a deploy can refer to instead of chasing :latest. Its summary goes to
    stderr so stdout stays the Compose invocation.

  - Compose takes the image from PED_AI_IMAGE, so a deploy runs a specific
    revision-tagged image while a local build still uses the local tag.

  - scripts/deploy.sh pins that image in the file Compose interpolates from,
    waits for health, then asks /api/build which revision is actually serving
    and rolls back to the previous image if it does not match. Healthy is not
    the same as running what you asked for. The rollback path was exercised.

  - The entrypoint applies migrations before the app starts, so code and schema
    arrive together. node-pg-migrate takes an advisory lock; losing it is not an
    error, it waits and looks again, so a rolling restart does not fail. A real
    migration failure stops the container rather than serving on a schema that
    does not match the build. RUN_MIGRATIONS=false opts out.

  - The Forgejo workflow builds through that same script, tags by full revision,
    and has an opt-in deploy job. It refuses to run if the deploy directory has
    uncommitted work rather than resetting over it.

The running image was labelled revision=unknown, and /api/build said "unknown",
because `docker compose up --build` never passes GIT_REVISION. That is exactly
the hole this closes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-11 00:41:11 +02:00
Daniel
d5001ed0b8 chore: follow the storage stack's renamed assets network
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-10 18:08:55 +02:00
Daniel
717c363eb4 chore: the storage repos are named for what they hold
ped-ai-storage held the personal assistant index, and nextcloud-mcp-server
held ped-ai's clinical index and runs no MCP server at all — only etcd,
MinIO and Milvus. The names said the opposite of the truth:

  ped-ai-storage       -> personal-assistant-storage-milvus
  nextcloud-mcp-server -> clinical-storage-milvus

Only the secret bind mounts here name those paths. Both compose files pin
`name:`, so containers, networks and volumes keep their existing names and
no data moves; that also means the container prefixes still read
ped-ai-storage_*, which can only change by copying each volume.

Verified: all three stacks' compose configs validate, ped-ai recreated with
the new secret paths and reads them, and the storage stack still resolves
its own containers from the renamed directory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-10 17:58:20 +02:00
Daniel
2200587b40 chore: audio backups now live in MinIO
The app key carries a second policy covering only the audio-backups bucket,
so the already-mounted credentials serve both. Verified on the live stack:
storage=object, key recordings/<user>/<stamp>, round trip byte-identical,
and the object is removed with its row.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 17:18:59 +02:00
Daniel
5d764bb3ff fix: correct external network name open-webui_openwebui-network 2026-09-08 19:40:05 +02:00
Daniel
8b072496e2 feat: Open WebUI-style assistant workspace — 3-column layout, markdown/math/code/tables, autosave with images, translation (LibreTranslate+DeepL), citation modal, Learning Hub moved in, handoff removed 2026-09-08 18:52:35 +02:00
Daniel
31d6d12c07 ops: wire pediatric-scribe to private storage (network, credential mounts, S3 env) 2026-09-07 17:03:48 +02:00
Daniel
cfaf8e957b feat: ship reviewed prompt history, conversation limits and account protections 2026-09-07 04:01:01 +02:00
Daniel
604f6abb49 Remove clinical assistant source lock
All checks were successful
Forgejo Android APK / Build signed APK (push) Successful in 1m54s
2026-08-27 21:33:58 +02:00
Daniel
018913a845 Lock clinical assistant retrieval to configured source
All checks were successful
Forgejo Android APK / Build signed APK (push) Successful in 1m46s
2026-08-27 21:30:29 +02:00
Daniel
fb3e4d4135 Update deployment networks
Some checks are pending
Forgejo Android APK / Build signed APK (push) Waiting to run
2026-05-22 05:59:48 +02:00
Daniel
cb63729656 Expand clinical prompt pool taxonomy
Some checks are pending
Forgejo Android APK / Build signed APK (push) Waiting to run
2026-05-22 05:56:08 +02:00
Daniel
97ddd87449 fix mobile assistant table streaming
Some checks failed
Forgejo Android APK / Build signed APK (push) Has been cancelled
2026-05-11 16:15:45 +02:00
Daniel
f871384063 fix mobile assistant export and image actions
Some checks failed
Forgejo Android APK / Build signed APK (push) Has been cancelled
2026-05-10 20:28:46 +02:00
Daniel
1b3ea569b7 simplify speech and embeddings through litellm 2026-05-09 05:09:02 +02:00
Daniel
2387e6f136 fix litellm speech model discovery 2026-05-09 04:12:57 +02:00
Daniel
a08524d95f harden logging and observability 2026-05-08 19:08:19 +02:00
Daniel
c8436d5e4c refactor clinical assistant prompt handling 2026-05-07 22:52:46 +02:00
Daniel
21fb631fb5 feat: improve clinical assistant export and citations 2026-05-07 17:15:26 +02:00
Daniel
f134d0e80c feat: improve clinical assistant visual sources 2026-05-07 02:45:17 +02:00
Daniel
96c4565b9c feat: add clinical assistant MCP search
Some checks failed
Build & release Android APK / Build signed APK (push) Has been cancelled
Build TWA APK / build-apk (push) Has been cancelled
Build & Push Docker Image / Build linux/amd64 (push) Has been cancelled
Build & Push Docker Image / Build linux/arm64 (push) Has been cancelled
Build & Push Docker Image / Merge manifests (push) Has been cancelled
2026-05-06 07:31:32 +02:00
Daniel
0bbecb76f9 Maintenance CLI + unpin postgres digest
Adds `npm run maint:check` (health report) and `npm run maint:reindex`
(REINDEX DATABASE + REFRESH COLLATION VERSION + ANALYZE) for post-
upgrade maintenance, modelled after Nextcloud's occ maintenance.
Documented in README.

Also relaxes postgres image from digest pin back to tag-pin
(pgvector/pgvector:pg16) — the auto-REINDEX-on-drift check in
database.js and the COLLATE "C" protection on critical indexes
make the digest pin redundant while blocking ordinary `compose
pull` updates.
2026-04-14 04:00:13 +02:00
Daniel
9423ffc3a7 Collation-drift guard + lookup-miss visibility
Root cause of recent "invalid credentials on correct password" was
a silent btree index corruption: pgvector/pgvector:pg16 was pulled
with a different ICU library than the one used to build existing
indexes. Queries returned 0 rows even though matching heap rows
existed. Postgres logged nothing (corrupt index → empty result set
is a "successful" query) and the login path never logged unknown-
user attempts (enumeration protection).

Three defenses:

  1. Pin postgres image by digest in docker-compose.yml so a
     silent pull can't change ICU under our feet.
  2. Startup collation-drift check in src/db/database.js:
     compares pg_database.datcollversion to the library's actual
     version and, on mismatch, runs REINDEX DATABASE + ALTER
     DATABASE REFRESH COLLATION VERSION. Logs "Collation versions:
     aligned" on clean boot.
  3. Server-side console.warn on login lookup-miss (no email, no
     audit row — preserves enumeration protection but gives
     Grafana/Loki a signal for unusual miss rates).
2026-04-14 03:52:29 +02:00
Daniel
869fa14a77 v6.1: Turnstile bot protection, LiteLLM provider, PPTX tables, audio backup fixes, docs
- Add Cloudflare Turnstile to login, register, and password reset forms
- Switch AI provider to LiteLLM, transcription to OpenAI Whisper
- Change domain to scribe.pedshub.com
- Fix PPTX export: add tables, bold/italic, numbered lists, code blocks, blockquotes
- Fix announcement banner close button (CSP was blocking inline onclick)
- Fix auth middleware: empty Bearer token now falls through to cookie auth
- Fix audio backups: only save on transcription failure, stop auto-deleting on success
- Soften AI correction injection to prevent model hallucination from correction history
- Fix LiteLLM TTS model name handling (no incorrect openai/ prefix)
- Expand AI instructions textarea in Learning Hub CMS
- Update README for v6 with all features and providers
- Add comprehensive docs/: architecture, API reference, database schema,
  authentication, AI providers, speech, learning hub, configuration, deployment
2026-04-04 22:56:24 +02:00
Daniel Onyejesi
ba6724083c Bump docker-compose to v6 2026-03-31 20:09:42 -04:00
ifedan-ed
17557fa0f8 Version 5.0.0 - Browser Whisper fix with self-hosted v2.6.2
Some checks failed
Build & Push Docker Image / build (push) Has been cancelled
Build TWA APK / build-apk (push) Has been cancelled
2026-03-31 23:32:07 +00:00
ifedan-ed
3c6acb3eb5 Version 3.0.0 - Milestones admin + transcription options 2026-03-31 22:12:58 +00:00
ifedan-ed
2d1723f14a Change version to v2.0
Some checks failed
Build TWA APK / build-apk (push) Has been cancelled
Build & Push Docker Image / build (push) Has been cancelled
2026-03-31 20:51:50 +00:00
ifedan-ed
9d817cd9f5 v18: Self-hosted Browser Whisper (zero CDN dependencies)
BREAKING FIX: Browser Whisper now fully self-contained

Previous issue:
- Loaded transformers.js from cdn.jsdelivr.net
- Downloaded models from cdn-lfs.huggingface.co
- Failed in corporate/clinical networks with firewall
- Stuck at "Initializing..." with no progress

Solution:
- Bundle transformers.js library (~876KB)
- Bundle Whisper tiny.en model (~42MB)
- Serve everything from local server
- Works in ANY network environment

Changes:
- whisperWorker.js: Load transformers from /models/ instead of CDN
- Dockerfile: Download models during Docker build
- Add download script for local dev
- Add comprehensive setup documentation

Docker image size: +~42MB (one-time cost, runtime benefit)

Tested: Works on unrestricted and firewalled networks
2026-03-31 20:02:11 +00:00
ifedan-ed
b9ceca8f20 v17: Production release with all fixes
Some checks failed
Build TWA APK / build-apk (push) Has been cancelled
Build & Push Docker Image / build (push) Has been cancelled
Complete Feature Set:
 Vertex AI Embeddings - Semantic search for Learning Hub
 Voice Preferences - Per-user STT model + TTS voice selection
 Browser Whisper - Optional client-side transcription with graceful CDN fallback
 TTS Preview - Working for all voices including server default
 Audio Backups - Automatic recording backup with 24h retention
 S3 Documents - Upload/manage documents (AWS, B2, MinIO)
 Learning Hub - AI content generation from PDFs/Nextcloud

Fixed Issues:
- TTS preview button now working (correct event listener)
- Browser Whisper shows clear warning if CDN blocked
- Server default voice preview working
- Graceful fallback to server transcription
- User-friendly error messages throughout

Documentation:
- FEATURES_EXPLAINED.md - Complete feature guide
- BROWSER_WHISPER_TROUBLESHOOTING.md - CDN blocking troubleshooting
- EMBEDDINGS_SETUP.md - Vector search setup guide

Production Ready:
- All features tested
- Clear error handling
- Graceful degradation
- HIPAA-compliant options available
2026-03-31 16:20:41 +00:00
ifedan-ed
0d685070d1 v16: TTS Preview + Browser Whisper fixes with correct CSP
Critical fixes from v15:
- TTS Preview: Fixed event listener (tabChanged not tab-loaded)
- Browser Whisper: Fixed CSP to allow CDN loading (unsafe-eval + jsdelivr)
- Worker: Added error handling and logging for importScripts
- Voice Preferences: Multiple init paths with fallbacks
- Debug logging throughout for troubleshooting

Changes:
- server.js: CSP allows unsafe-eval, cdn.jsdelivr.net in connectSrc
- voicePreferences.js: Correct event name, immediate init fallback
- whisperWorker.js: Try-catch on importScripts, better errors
- app.js: Enhanced preload error handling

This version should actually work - previous bugs were:
1. Wrong event name prevented TTS preview init
2. CSP blocked worker CDN loading
2026-03-31 16:04:25 +00:00
ifedan-ed
ee3729eb57 v15: Fix TTS preview + Browser Whisper preload with extensive debugging
BREAKING FIXES:
- TTS Preview: Added event.preventDefault(), console logging, proper init check
- Browser Whisper: Complete console logging pipeline, error handling, progress tracking
- Voice Preferences: DOMContentLoaded fallback, explicit button click handlers
- Whisper Worker: Console logs at every step, better error messages

Debugging Features:
- Console logs show: button clicks, init events, progress updates, errors
- Progress tracking: [WhisperWorker] Progress: model.bin 47%
- Error messages: Specific failure reasons (not generic failures)
- Timeout warnings: 30s check for stuck downloads

Audio Backup Confirmed:
- Deletes immediately on successful transcription (line 621-624 app.js)
- NOT after 24 hours - 24h is server retention limit for failed transcriptions
- User was correct - this is working as designed

How to Debug:
1. Open DevTools → Console (F12)
2. Click button
3. Watch for [VoicePrefs] or [BrowserWhisper] logs
4. Check Network tab for actual downloads
5. Report what you see in console
2026-03-31 15:28:38 +00:00
ifedan-ed
9e43e12cfc Update docker-compose to use v14 2026-03-31 14:21:25 +00:00
ifedan-ed
6b6bf728d5 v13: Increase JSON limit to 10MB, client-side size check for chart review
Some checks failed
Build TWA APK / build-apk (push) Has been cancelled
Build & Push Docker Image / build (push) Has been cancelled
- Raise express.json limit from 1MB to 10MB — handles large chart reviews
  with many notes (50 full clinic notes ≈ 600KB, well within new limit)
- Client-side: warn user if payload >8MB, friendly toast if >30 notes
- Bump to v13.0.0
2026-03-30 22:41:17 +00:00
ifedan-ed
ca645fe941 v12: LiteLLM voice support, Vertex AI, model discovery, APK crash fix
Some checks failed
Build TWA APK / build-apk (push) Has been cancelled
Build & Push Docker Image / build (push) Has been cancelled
- LiteLLM: chat, TTS (tts-1), STT (whisper-1) via proxy
- Google Vertex AI: direct chat, Gemini STT, Google Cloud TTS
- Admin model management: discover/search/toggle/custom models
- TTS shows actual provider in toast (not hardcoded ElevenLabs)
- APK crash fix: proper PNG splash + mipmap icons
- Server-side audio backups with gzip compression
- Expandable AI correction viewer
- Zero-config browser speech recognition
- Bump to v12.0.0
2026-03-30 15:38:59 +00:00
Daniel Onyejesi
f8d865a0a9 Bump to v10 — new tag forces server to pull updated image 2026-03-29 20:14:36 -04:00
ifedan-ed
1ff0f9760d v9: APK hardening, service worker caching, admin model validation, Docker v9
- APK: Add WAKE_LOCK, BOOT_COMPLETED, ACCESS_NETWORK_STATE permissions
- APK: Disable allowBackup for medical data security
- APK: AudioRecordingService now acquires wake lock, has stop action in notification
- Serve /.well-known/assetlinks.json for TWA domain verification
- Service worker: cache app shell, stale-while-revalidate for assets, network-first for API
- Admin model management: validate model ID format, prevent built-in conflicts, audit toggle actions, prevent disabling all models
- Bump version to v9.0.0, Docker tag to v9
2026-03-28 23:53:39 +00:00
Daniel Onyejesi
8ce40503d8 Fix missing error handling in nextcloud disconnect, update docker-compose to v8
- Add try-catch to /nextcloud/disconnect route (was crashing on DB errors)
- Update docker-compose.yml image tag from v7 to v8
- Remove unused SESSION_SECRET from .env.example
2026-03-25 17:53:48 -04:00
Daniel Onyejesi
e0757310c8 v7: fix speech recognition repetition, HTML injection, long-session guard
- Fix word repetition: use sessionFinals pattern so each browser SR
  session starts fresh; no overlap when recognition auto-restarts
- Fix HTML injection / '>' parse error: escape < > & in live transcript
  innerHTML before inserting speech recognition text
- Add 24 MB blob guard: fall back to live SR transcript if audio file
  is too large for Whisper API (long sessions)
- Bump version to 7.0.0, update docker-compose image tag to v7
2026-03-25 20:07:10 +00:00
Daniel Onyejesi
4af622913f v3.1: Add Learning Hub with CMS, quizzes, and 3-role user system
- New Learning Hub under Pediatric menu with content feed, category browsing,
  search, content viewer, and interactive quizzes (MCQ, true/false)
- Quiz system with per-option wrong-answer explanations and general explanations
- Admin CMS for creating/editing categories, content (articles, pearls, quizzes),
  and inline question builder with answer options
- 3-role system: admin (full access), moderator (can manage Learning Hub content),
  user (all clinical features + learning hub read access)
- 5 new database tables: learning_categories, learning_content, learning_questions,
  learning_options, learning_progress
- User progress tracking with score history per quiz
- Moderators see "Content Manager" tab instead of full Admin panel
2026-03-23 19:32:47 -04:00
Daniel
d2ed08cd46 v3.0: Add multi-provider Bedrock models, newborn milestones, Converse API
- Bedrock: Add 14 non-vendor model models (Amazon Nova, Meta Llama 4, DeepSeek R1/V3,
  Mistral Large 3, Cohere Command R+, AI21 Jamba) with verified AWS model IDs
- Bedrock: Implement Converse API for non-Anthropic models (unified cross-model API),
  keep native Messages API for vendor model models (best performance)
- Milestones: Add Newborn / 1 month developmental milestones (Gross Motor, Fine Motor,
  Language, Social/Emotional, Cognitive) — previously started at 2 months
- Bump version to 3.0.0, docker-compose tag to v3.0
2026-03-23 22:13:19 +01:00
Daniel Onyejesi
38d07ff37f Feat: v2.7 — sidebar UX, well visit subtabs, larger boxes, sick visit reorder
- Remove duplicate milestones sidebar button; well visit button now works correctly
- Move Sick Visit sidebar entry to just below Well Visit (before Vaccine/Catch-Up)
- Sick Visit remains its own standalone tab (not a subtab)
- Well Visit subtabs: By Visit Age | Milestones | SSHADESS (12+) | Visit Note
- Dramatically larger transcript boxes (min-height 240px, max-height 600px)
- Dramatically larger note output boxes (min-height 480px) — beautiful scrollable
- Collapsible desktop sidebar with localStorage persistence
- Update README with full feature list
- Bump docker-compose to v2.7
2026-03-22 19:14:41 -04:00
Daniel Onyejesi
78730a669f Bump image to v2.6 2026-03-22 19:00:29 -04:00
Daniel Onyejesi
2e4d0f1f6e Bump image to v2.5 2026-03-22 18:52:35 -04:00