- Create chat_service.spec.ts with tests for suggestion parsing (comma/newline
separated, bullet points, numbered lists, quote stripping), model selection
(largest model), error handling for all DB-dependent methods, generateTitle
fallback logic, and message role validation
- Fix TypeScript narrowing error in docker_service.spec.ts container command
splitting test (null type cast)
- Add .env.test with required environment variables for test suite bootstrap
https://claude.ai/code/session_01JFvpTYgm8GiE4vJ4cJKsFx
- Test GPU detection logic with mocked exec calls
- Test service installation guard and race condition prevention
- Test container command splitting with quoted arguments
- Test sanitizeFilename utility function
- Test file type validation and error handling
https://claude.ai/code/session_01JFvpTYgm8GiE4vJ4cJKsFx
- Create api_response.ts helper for consistent { success, error/data } format
- Add radix parameter (10) to all parseInt calls across controllers and services
- Fix race condition in DockerService by making in-memory guard atomic
- Fix container command splitting to handle quoted arguments properly
- Stop leaking internal error.message to API responses; log details server-side
https://claude.ai/code/session_01JFvpTYgm8GiE4vJ4cJKsFx
- Add set -euo pipefail to install and update scripts for fail-fast behavior
- Escape sed replacement strings to prevent injection via special characters
- Add || true guards for commands expected to fail (tr pipe, read prompts)
- Validate target_tag in update-watcher to prevent unsafe characters in sed
- Properly quote variable assignments to satisfy strict mode
https://claude.ai/code/session_01JFvpTYgm8GiE4vJ4cJKsFx
- system.ts: Add maxLength(100) and alphanumeric/hyphen/underscore regex to service_name fields
- system.ts: Add maxLength(50) and semver/Docker tag regex to target_version field
- rag.ts: Add maxLength(500) to filePath field
- rag_controller.ts: Add 50MB file upload size limit and validation error handling
- settings_controller.ts: Validate getSetting() key parameter against KV_STORE_SCHEMA at runtime
https://claude.ai/code/session_01JFvpTYgm8GiE4vJ4cJKsFx
Add an in-memory sliding window rate limiter as AdonisJS named
middleware. Applied to expensive endpoints to prevent abuse:
- POST /api/system/services/install: 5 req/min
- POST /api/benchmark/run{,/system,/ai}: 3 req/min
- POST /api/rag/upload: 10 req/min
- POST /api/ollama/models (pull): 5 req/min
Returns 429 with Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining
headers. Expired entries are cleaned up periodically.
https://claude.ai/code/session_01JFvpTYgm8GiE4vJ4cJKsFx
Extract common logic from runSystem() and runAI() into a private
_runBenchmark() helper that handles checking for running benchmarks,
dispatching the job, and returning the response.
https://claude.ai/code/session_01JFvpTYgm8GiE4vJ4cJKsFx
Add indexes on chat_messages.session_id (primary query path for loading
messages by session) and installed_resources.resource_type to improve
query performance on foreign key lookups.
https://claude.ai/code/session_01JFvpTYgm8GiE4vJ4cJKsFx
- Enable CSRF protection with XSRF cookie for Inertia.js/React SPA
- Enable HSTS with 180-day max-age and includeSubDomains
- Enable CSP with nonce-based script policy, unsafe-inline for Tailwind
styles, and restrictive defaults for frames/objects
- Allow map tile sources in img-src for offline map support
https://claude.ai/code/session_01JFvpTYgm8GiE4vJ4cJKsFx
The 2024-01 all_maxi ZIM was removed from Kiwix mirrors, causing
silent 404 failures for users selecting "Complete Wikipedia (Full)".
Updated to 2026-02 release (115 GB).
Closes#216
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GPU detection results were only applied at container creation time and
never persisted. If live detection failed transiently (Docker daemon
hiccup, runtime temporarily unavailable), Ollama would silently fall
back to CPU-only mode with no way to recover short of force-reinstall.
Now _detectGPUType() persists successful detections to the KV store
(gpu.type = 'nvidia' | 'amd') and uses the saved value as a fallback
when live detection returns nothing. This ensures GPU config survives
across container recreations regardless of transient detection failures.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Failed download jobs persist in BullMQ forever with no way to clear
them, leaving stale error notifications in Content Explorer and Easy
Setup. Adds a dismiss button (X) on failed download cards that removes
the job from the queue via a new DELETE endpoint.
- Backend: DELETE /api/downloads/jobs/:jobId endpoint
- Frontend: X button on failed download cards with immediate refresh
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The security audit report was an internal pre-launch document that
shouldn't be exposed in the user-facing documentation sidebar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The KV store returns ui.hasVisitedEasySetup as boolean true, but the
comparison checked against string 'true'. Since true !== 'true', the
badge was always shown even after completing Easy Setup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After an update completes, the page reloads but the KV store still has
updateAvailable=true from the pre-update check. This causes the banner
to show "Current 1.30.0-rc.1 → New 1.30.0-rc.1" until the user
manually clicks Check Again.
Now triggers a version re-check before the post-update reload so the
KV store is updated and the banner reflects the correct state.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three bugs caused downloads to hang, disappear, or leave stuck spinners:
1. Wikipedia downloads that failed never updated the DB status from 'downloading',
leaving the spinner stuck forever. Now the worker's failed handler marks them as failed.
2. No stall detection on streaming downloads - if data stopped flowing mid-download,
the job hung indefinitely. Added a 5-minute stall timer that triggers retry.
3. Failed jobs were invisible to users since only waiting/active/delayed states were
queried. Now failed jobs appear with error indicators in the download list.
Closes#364, closes#216
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The East North Central region had a single "indianamichigan" entry pointing
to a pmtiles file that doesn't exist. Indiana and Michigan are separate
files in the maps repo.
Closes#350
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Kiwix skipped the January 2026 build of devdocs_en_react — the
2026-01 URL returns 404. Updated to 2026-02 which exists.
Closes#269
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The disk-collector could produce an empty fsSize array when
/host/proc/1/mounts is unreadable, causing the admin UI to fall back
to systeminformation's fsSize which includes tmpfs mounts. This led to
the storage display showing ~1.5 GB (tmpfs /run) instead of the actual
storage capacity.
Two changes:
- disk-collector: fall back to df on /storage when host mount table
yields no real filesystems, since /storage is always bind-mounted
from the host and reflects the actual backing device.
- easy-setup UI: when falling back to systeminformation fsSize, filter
for /dev/ block devices and prefer the largest one instead of blindly
taking the first entry.
Fixes#373
When Ollama isn't installed, every ZIM download dispatches embedding jobs
that fail and retry 30x with 60s backoff. With many ZIM files downloading
in parallel, this exhausts Redis connections with EPIPE/ECONNRESET errors.
Two changes:
1. Don't dispatch embedding jobs when Ollama isn't installed (belt)
2. Use BullMQ UnrecoverableError for "not installed" so jobs fail
immediately without retrying (suspenders)
Closes#351
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>