Replace Postgres with SQLite

Ten members and a handful of songs a week never needed a database server,
and the server was the last thing making this a two-container deployment.
modernc.org/sqlite is pure Go, so CGO_ENABLED=0 survives and the dependency
count is unchanged: pgx out, sqlite in.

The port stayed small because the driver matches $1-style placeholders
against argument ordinals exactly as pgx does, so no query needed rewriting
for parameters. What did change:

- timestamptz becomes timestamp holding UTC 'YYYY-MM-DD HH:MM:SS'. The
  declared type is what makes the driver return time.Time, and the
  fixed-width UTC string is what makes ordering and comparison against
  datetime('now') mean what they say.
- interval has no equivalent: sessions.idle_ttl is seconds, and the review
  edit window travels as a SQLite date modifier string.
- No stddev_pop, so the divisive and unified boards spell the population
  formula out, guarded with max(0.0, ...) because cancellation returns a
  tiny negative when every score is identical.
- foreign_keys is off by default, so the cascades only exist because the
  pragma is set on every connection.

Drops the postgres service, its healthcheck, the depends_on gate, the
startup retry loop and POSTGRES_PASSWORD. ./storage is now the whole
backup. Tests get a fresh database file per test and run everywhere
instead of skipping without TEST_DATABASE_URL.
This commit is contained in:
Esa Kataja
2026-08-02 20:47:41 +03:00
parent a9776c6dde
commit 1fe5211ae6
28 changed files with 440 additions and 389 deletions
+1 -21
View File
@@ -1,28 +1,10 @@
services:
postgres:
image: postgres:18-alpine
environment:
POSTGRES_USER: levyraati
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
POSTGRES_DB: levyraati
volumes:
# Postgres 18 keeps its data in /var/lib/postgresql/<version>/docker, so the mount is the
# parent directory, not the old /var/lib/postgresql/data.
- ./pgdata:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U levyraati"]
interval: 5s
timeout: 3s
retries: 10
restart: unless-stopped
app:
build:
context: .
args:
VERSION: ${VERSION:-dev}
environment:
DATABASE_URL: postgres://levyraati:${POSTGRES_PASSWORD}@postgres:5432/levyraati
ADMIN_USER: ${ADMIN_USER:-admin}
ADMIN_PASSWORD: ${ADMIN_PASSWORD:?set ADMIN_PASSWORD in .env}
ADDR: ":8080"
@@ -31,12 +13,10 @@ services:
ADMIN_ADDR: ":8081"
SECURE_COOKIES: ${SECURE_COOKIES:-true}
PUBLIC_URL: ${PUBLIC_URL:-}
# The SQLite file sits in here beside the audio, so this one mount is the whole backup.
volumes:
- ./storage:/storage
ports:
- "8080:8080"
- "8081:8081"
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped