Commit graph

7 commits

Author SHA1 Message Date
3670f02ccd Document authenticated deployment 2026-09-28 22:42:11 +02:00
0a17da2b8e Align runtime and editor documentation with current implementation 2026-09-26 21:02:48 +02:00
2e3e85a8e5 Harden the container runtime and shut down cleanly
Running the stack on built output stopped the idle CPU load, but the
remaining findings from the deployment report were still open.

The Dockerfile is now multi-stage. The prod target runs on node:24-slim as
the "node" user instead of root and carries only its runtime dependencies;
"npm prune --omit=dev" drops tsx, drizzle-kit and typescript. The migration
scripts need drizzle-orm and better-sqlite3, both regular dependencies, so
they keep working. The dev target keeps devDependencies for compose.dev.yaml.

Both compose files get a mem_limit. The server stack also sets memswap_limit
to the same value, so a leak lets the OOM killer replace the container
instead of pushing the host into swap. The Express API is no longer
published on the host: it has no authentication and is reached through the
Next.js rewrite. Development ports are bound to the loopback interface.
Services drop all capabilities and run with no-new-privileges.

SIGTERM and SIGINT now close the HTTP server and the SQLite handle and exit,
instead of only logging the signal and waiting for the container's SIGKILL
ten seconds later. server.closeIdleConnections() releases the keep-alive
sockets the Next.js server holds, which would otherwise keep server.close()
pending for the whole grace period. The compose start commands exec into
node, because otherwise sh stays the foreground process and the signal never
reaches it.

Delete scripts/docker-start.sh rather than fixing its unsupervised
background API: both compose stacks set their own command, so the
single-container entrypoint has no caller left. Also remove drizzle.config.js
(a stray tsc artifact drizzle-kit never reads) and the pre-Next index.html
and styles.css.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 11:04:34 +02:00
906aa751c7 Run the Docker stack on built output instead of dev servers
compose.yaml overrode the image's own entrypoint to start "tsx watch" and
"next dev" with CHOKIDAR_USEPOLLING and WATCHPACK_POLLING enabled. The
built dist/ and .next from the image were never used, and the polling
watchers kept both containers busy around the clock whether or not
anyone used the application.

Split the two use cases: compose.yaml now runs node dist/server/index.js
and next start with no source mounts and no watchers, and the watching
setup moves to compose.dev.yaml.

next build writes the rewrite destinations from next.config.mjs into
.next/routes-manifest.json, so next start cannot pick up API_INTERNAL_URL
at runtime the way next dev does. Pass it as a build argument.

Give the web container its own probe. The healthcheck hit "/", which
redirects to "/projects", and fetch follows redirects, so every probe
rendered two pages every five seconds. "/health" could not serve as the
probe because next.config.mjs rewrites it to the API. Add "/web-health"
as a route handler, exclude it from the proxy matcher, and relax both
intervals to 30s.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 18:25:06 +02:00
fa96be2d42 Fix crash handling and log noise in logging feature
Review of the logging work from the previous commit turned up a real
correctness issue: the uncaughtException/unhandledRejection handlers
logged the error but let the process keep running, which silently
disabled Node's default crash-on-fatal-error behavior and could leave
a zombie process serving broken requests instead of restarting. Both
processes now log and then exit(1); restart: unless-stopped is added
to both services so Docker actually brings them back up.

Also: harden the logger against JSON.stringify throwing on
non-serializable meta, log aborted (closed-before-finished) requests
in the API access log, and stop the Next.js proxy from logging the
Docker healthcheck's request to "/" every few seconds so real
navigation events aren't drowned out.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 19:58:31 +02:00
ea3c02cd6b Add configurable structured logging
Adds a leveled JSON logger (error/warn/info/verbose/debug, controlled via
LOG_LEVEL) wired into the Express API (access log, error middleware,
crash handlers, memory heartbeat) and the Next.js server (page-request
proxy, instrumentation crash handlers, heartbeat). LOG_LEVEL is exposed
through compose.yaml, and both services now rotate their Docker logs
(json-file, 20m x 10 files) instead of growing unbounded. Intended to
capture long-running diagnostic data for the intermittent 502s seen on
the Docker host.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 19:45:39 +02:00
6b6d2c2a42 Rewrite project documentation 2026-07-23 21:05:43 +02:00