Introduce server-migrations.ts with a named-migration runner that tracks
applied migrations in a _migrations table. runMigrations(db) is called at
startup before routes, so additive schema changes (ALTER TABLE, new settings)
are applied once and skipped on subsequent restarts.
Update ARCHITECTURE.md: five inline edits + new §4.4 documenting the convention.
- Rename caddy.redirect_path to caddy.redirect across schema, server, frontend and docs
- Remove obsolete ALTER TABLE migration (fresh-install model has no migrations)
- Move uid() from server.ts to server-db.ts for shared use
- Add addLog() general helper (prepared statement, shared timestamp support) and
replace ~24 inline INSERT INTO logs calls throughout server.ts
- Caddy CRUD now takes CaddyRouteInput object instead of positional arguments;
add/update reuse getCaddyRouteById() to avoid duplicate SELECT
Add a redirect_path column to the caddy table and an optional 'root redirect'
field in the route form. When set, buildCaddyfile emits 'redir / <path>' so the
bare host (e.g. checkmk.domain.local/) redirects to a sub-path (e.g.
/monitoring/check_mk/) while every other path still passes through to the
backend — the safe pattern for apps like CheckMK that bake their site path into
absolute URLs. Defensive ALTER TABLE keeps existing databases working.
One Caddy serves the whole container and POST /load replaces the entire
config, so two instances pushing would clobber each other. Now only the
instance with CADDY_MANAGER=true (production) pushes, seeds routes from the
Caddyfile, and accepts route mutations (others get 403). /api/auth/config
exposes caddyManaged so the non-owner Settings UI shows the Caddy section
read-only. The installer sets the flag on the production .env only.
Every generated reverse_proxy block now emits header_up for
X-Forwarded-Proto, X-Real-IP and Host. Caddy already sets the X-Forwarded-*
family and Host by default; this makes them explicit and adds X-Real-IP
(nginx convention) for backends that expect it. The https:// transport block
is preserved alongside the headers.
- index.css: add :root.light overrides for the sky-* accent used only by the
Caddy settings card (buttons, badges, hovers) + the missing red-950/30 hover
- favicon: add public/favicon.svg (GhostGrid logo) and link it in index.html
- ARCHITECTURE.md: GET /caddy/routes returns a plain array, document the Caddy
startup import, https:// upstream, favicon/public dir, and the SPA-catch-all-last
+ Cache-Control: no-store invariant
When a route's upstream starts with https://, buildCaddyfile emits a
transport http { tls_insecure_skip_verify } block so Caddy connects over TLS
and accepts the self-signed certificate typical of backends like Semaphore.
Added a UI hint explaining the https:// prefix.
When Caddy is enabled for the first time (caddy routes table empty),
importCaddyfileRoutes() reads /etc/caddy/Caddyfile and seeds all
hostname/upstream blocks as custom routes — no manual entry needed after deploy.
On first startup with an empty users table, a default admin user is created
(admin@ghostgrid.local / admin) so the system is immediately usable.
caddy_prod_domain and caddy_dev_domain are already handled by the Proxmox deploy
process. The Caddy integration is a generic TLS proxy for additional services
(Semaphore, Netbox, etc.) — the custom routes list is the sole mechanism.