Picked up the four 'Still Open' standardization items from the audit doc
as Option B work. Audited each before starting implementation:
DC-013 (config schema migration) — src/config/migrations.js exists with
a versioned migration system (CURRENT_VERSION=2, v1 dns normalization,
v2 dns.provider field), loadAndMigrate() writes back to disk only when
version changes, called from src/config/site.js on every startup.
Guarded by 21 tests in __tests__/config-migrations.test.js.
DC-014 (monitoring endpoint opt-in) — MONITORING_PUBLIC env var +
config.monitoring.public both work via an IIFE in
src/utilities/middleware.js line 297. Routes are conditionally public
based on the flag. Default is 'true' for back-compat with existing
dashboards that pre-load widget data. Flipping the default to 'false'
is a fresh change with a real UX cost.
DC-015 (CSRF token path duplication) — grep confirms only
/api/v1/csrf-token exists. /api/v1/auth/csrf-token was never
implemented or was already cleaned up.
DC-016 (per-call fetchT timeouts) — src/utils/http.js defines
fetchT(url, opts, timeoutMs) with AbortSignal.timeout() in the
native branch and explicit timeout handlers in the http/https
raw-request branches. 5s default covers most calls; 8 of 77 sites
pass explicit overrides. 5min global request timeout is the backstop.
All four tasks reassigned from krystie → hermes because the work shifted
from 'implement' to 'verify and document'. No code changes in this commit
— only BACKLOG.md and CHANGELOG.md updated to reflect actual state.
This commit is the meta-example for Pitfall 20 (just added to the
standardization pitfalls reference): audit docs decay as fast as fixes
land. Always audit before implementing.
Fresh users copy-pasting healthcheck blocks from k8s/Docker docs need
the standard short aliases. Without /healthz and /readyz they get
connection refused. This commit:
1. Adds /healthz + /readyz as root-level aliases for /health/live +
/health/ready in src/app.js. Handler bodies DRYed into named
functions (livenessHandler, readinessHandler) so a probe semantics
change updates all five paths at once.
2. Removes the dead /api/v1/health*, /api/v1/health/live, /api/v1/health/ready
registrations from PUBLIC_ROUTES and CSRF exclusion list — those
routes were never actually mounted on the apiRouter (only root
paths existed). Anyone probing /api/v1/health now gets a clean 404
instead of being routed through to a duplicate root handler.
3. Adds bypass for the 5 probe paths in three places where it matters:
- PUBLIC_ROUTES (no auth)
- csrf-protection.js excludedPaths (no CSRF check)
- middleware.js request-logging exclusion (k8s polling every 10s
doesn't flood the audit log)
- middleware.js Tailscale auth bypass (probes don't carry Tailscale
identity headers)
4. Adds __tests__/health-probe-aliases.test.js (19 tests):
- Alias equivalence (/healthz == /health/live, /readyz == /health/ready)
- Back-compat (/health == /health/live)
- Path consolidation (all 3 /api/v1/health* return 404)
- Source-of-truth PUBLIC_ROUTES allowlist sync check
- Source-of-truth src/app.js mount list sync check (catches drift
between handler mount and middleware allowlist)
5. Documents probes in README (copy-paste docker-compose.yml +
Kubernetes blocks) and user-guide (Health Probes section + System
API table updated).
Post-fix: 941/941 tests pass (+19 new). Zero new ESLint warnings
introduced. The pre-existing warnings/errors in src/app.js line 906
('os' is not defined) and the empty blocks in logging.test.js are
not regressions from this commit.
The DC-005 src/ refactor left depth-2 route files (routes/auth/*,
routes/recipes/*, routes/apps/*, routes/arr/*, routes/config/*) with
broken require() paths. A filesystem-resolving scanner found 67 broken
requires across 21 files — three distinct bug classes:
A) '../../../src/...' (3 levels up, above package root) — Bug 7, ~49 occurrences
B) '../src/utils/...' (1 level up, resolves to nonexistent routes/src/) — ~15 occurrences
C) routes/apps/restore.js:5 used utilities/responses (wrong dir) — should be utils/responses
All fixed to '../../src/...' (or '../../src/utils/responses' for class C).
routes/auth/totp.js was already fixed in the DC-006 commit.
Post-fix: 922/922 tests pass, zero new ESLint warnings. No logic changes —
purely mechanical require() path corrections.
DC-006 marked done with 25-test result summary + 904/904 test note.
DC-005 annotated with two critical notes:
- Latent require-path bug in depth-2 routes (mechanical 3->2 fix needed in ~22 files)
- Branch state vs origin/main divergence (need coordinated merge, not silent FF)
Inserts a comprehensive Linux (DNS2 / Contabo VPS) section between the existing Windows docs and the Project Info footer. The new section documents:
- Production paths (/opt/dashcaddy/, /var/www/dashcaddy-status/, /etc/dashcaddy/)
- Container mount points with the /app/data/ auto-resolve fallback
- The three-filesystem frontend trap (source vs live vs build-context)
- Common admin commands (Caddyfile reload, logs, rebuild, services.json)
- Windows-vs-Linux differences table
- Four Linux-specific gotchas (Caddy network_mode host, credentials.json perms, CORS_ORIGINS, TS_AUTHKEY)
Also corrects the stale 'Version: 1.0' field to current 1.13.4 and adds the Linux-side default TLD (.home). All existing Windows content preserved verbatim per the LITERAL COPY RULE.
comprehensive-test.js and test-security-fixes.js are 875 lines of
ad-hoc security test scripts (not Jest tests). They have zero references
in code or docs. Moved to scripts/legacy/ to declutter repo root
without losing the content. All 759 Jest tests still pass.
- Updated root VERSION file from 1.13.0 → 1.13.4 to match package.json.
- scripts/release.sh now writes both files on every release bump, and
stages VERSION alongside package.json in the release commit.
- This prevents the drift that caused the stale VERSION in the first place.