diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx index ac3e6a9888..1a868046bf 100644 --- a/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx +++ b/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx @@ -1,7 +1,7 @@ import { createFileRoute, Link } from "@tanstack/react-router"; import { DocsPage } from "@/components/site/docs-page"; -import { CodeBlock, FeatureRow } from "@/components/site/primitives"; +import { Callout, CodeBlock, FeatureRow } from "@/components/site/primitives"; export const Route = createFileRoute("/docs/self-hosting-operations")({ head: () => ({ @@ -10,13 +10,13 @@ export const Route = createFileRoute("/docs/self-hosting-operations")({ { name: "description", content: - "Operate the self-hosted Gittensory review service: readiness, metrics, logs, dashboards, jobs, queues, and routine checks.", + "Operate the self-hosted Gittensory review service: readiness, metrics, logs, dashboards, jobs, queues, routine checks, and safe updates/rollback.", }, { property: "og:title", content: "Self-host operations — Gittensory docs" }, { property: "og:description", content: - "Operate the self-hosted Gittensory review service: readiness, metrics, logs, dashboards, jobs, queues, and routine checks.", + "Operate the self-hosted Gittensory review service: readiness, metrics, logs, dashboards, jobs, queues, routine checks, and safe updates/rollback.", }, { property: "og:url", content: "/docs/self-hosting-operations" }, ], @@ -275,6 +275,131 @@ volumes:
+ Both update paths below only ever restart the gittensory app service (
+ --no-deps) — they never touch other compose-profile services or their state
+ (Postgres, Redis, Qdrant, and Grafana's own grafana-data volume), and they
+ never touch .env keys other than the one they persist for next time. That means{" "}
+ .env, the gittensory-config/ mount, every data volume — including
+ the app's own /data volume where Codex/Claude Code auth material lives —
+ and any docker-compose.override.yml are preserved automatically across an
+ update. You don't need to back those up or re-supply them just to run either script,
+ and you only need to recreate a profile service yourself if you're deliberately
+ upgrading that service (its own image tag in docker-compose.yml, or a
+ Postgres/Redis/Qdrant major-version bump) rather than the app.
+
+ scripts/deploy-selfhost-image.sh pulls a tag or digest, restarts only the{" "}
+ gittensory service, waits for it to report healthy via{" "}
+ docker inspect's health status (configurable timeout, default 180s), and
+ then persists the resolved image reference back to GITTENSORY_IMAGE in{" "}
+ .env so the next plain invocation reuses it.
+
+ The pull always runs with --policy always, so re-running the script against an
+ unchanged tag is safe: if the registry has nothing new, it just restarts the same image and
+ the health-check wait passes immediately.
+
+ scripts/deploy-selfhost-prebuilt.sh is for a source-based deploy (this is how{" "}
+ GITTENSORY_VERSION ends up as a short git SHA instead of an image tag). It
+ builds the bundle inside a Dockerized Node container — the host itself never needs Node or
+ npm installed — then restarts only the gittensory service the same way as the
+ image path.
+
+ SENTRY_RELEASE defaults to{" "}
+ gittensory-selfhost@<short git SHA of the current HEAD> unless you
+ override it, so each deploy from a new commit gets a distinct release id automatically. When{" "}
+ SENTRY_AUTH_TOKEN, SENTRY_ORG, and SENTRY_PROJECT are
+ all configured, the script also injects and uploads Sentry source maps for that release
+ before restarting the service (set SELFHOST_SKIP_SENTRY_UPLOAD=1 to skip this
+ even when those three are present).
+
+ There is no rollback script. Rolling back means re-running one of the two
+ scripts above pointed at an older target:
+
deploy-selfhost-image.sh with the prior tag or digest (
+ docker inspect on the running container, or your own deploy log, has the
+ digest you were on before the update).
+ git checkout the prior commit, then re-run{" "}
+ deploy-selfhost-prebuilt.sh.
+ scripts/check-migrations.mjs only
+ enforces a contiguous, non-colliding numbering, not a reverse path. If a migration has
+ already run forward against the live database, rolling back the app code is{" "}
+ not safe in general: older code can break against a newer schema (a
+ dropped/renamed column, a NOT NULL column it never writes, a changed constraint), even
+ though the migration itself succeeded. Before rolling back across a migration boundary,
+ check whether everything the newer migration(s) did is purely additive (new nullable column,
+ new table, new index) and, specifically, whether the code you're rolling back to actually
+ still runs against that schema — additive is usually fine; anything the old code can't
+ tolerate is not. Take a fresh backup first regardless — see{" "}
+ Backup and scaling — and if in doubt,
+ restore that backup to a scratch database and boot the older code against it before doing
+ the same on the live instance.
+ Before updating:
+git status is clean (no uncommitted local changes the
+ build would silently pick up or drop).
+
+ After updating, work through the same checks as any other health pass — see{" "}
+ Health endpoints and Useful commands above: confirm{" "}
+ /ready returns 200, docker compose ps shows the service{" "}
+ healthy, and tail recent logs for startup errors or an unexpected absence of{" "}
+ selfhost_listening / selfhost_migrations_applied.
+
+ Neither /health nor /ready reports a version, so confirm the
+ deployed release directly — GITTENSORY_IMAGE or SENTRY_RELEASE in{" "}
+ .env records what the deploy script just resolved, and{" "}
+ docker inspect confirms what the running container actually has:
+
If an operating check fails, go to{" "} Self-host troubleshooting.