Release 2026.08.02-1
SQLite replaces Postgres, and two fixes from using the thing. - The database is a file under ./storage instead of a second container. Ten members never needed a database server, and the driver is pure Go, so the build stays CGO_ENABLED=0 and the dependency count is unchanged. One bind mount is now the whole backup: no pgdata, no healthcheck-gated depends_on, no startup retry loop. Timestamps are UTC text, idle_ttl is seconds, the divisive/unified boards carry their own stddev, and foreign keys are on by pragma. Tests get a database file each and run without any setup - Invites are copied, not clicked. An invite is something to send, and the anchor opened the join form in the admin's own browser - Feedback asks for more than faults: the footer reads "Ongelmia? Ideoita? Palautetta?" and the page behind it invites ideas rather than only bugs - Kuuntele YouTubessa opens in a new tab, so a half-typed review survives it
This commit is contained in:
@@ -209,3 +209,30 @@ says so.
|
||||
|
||||
The coverage assumption that shaped the earlier sketch was wrong and is corrected in `later.md`:
|
||||
LRCLIB has synced lyrics for a good share of Finnish rock, not almost none.
|
||||
46. **SQLite instead of Postgres — this reverses entries 1 and 3** (2026-08-02). 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 does not change: `pgx` out, `sqlite` in. What it buys: one container, one
|
||||
bind mount that is the entire backup, no `pgdata`, no healthcheck-gated `depends_on`, no startup
|
||||
retry loop, and tests that run anywhere instead of skipping without `TEST_DATABASE_URL`.
|
||||
|
||||
The port was smaller than expected, 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` → `timestamp` holding UTC `YYYY-MM-DD HH:MM:SS`.** The declared type is what
|
||||
makes the driver return `time.Time`; the fixed-width UTC string is what makes `order by
|
||||
created_at` and `expires_at > datetime('now')` mean what they say. `_time_format=datetime` and
|
||||
`_timezone=UTC` on the DSN make Go write exactly the shape `datetime('now')` produces, so the
|
||||
two sources of a timestamp are comparable.
|
||||
- **`interval` has no equivalent.** `sessions.idle_ttl` is seconds as an integer, and the review
|
||||
edit window travels as a SQLite date modifier string (`-1800 seconds`).
|
||||
- **No `stddev_pop`.** The divisive and unified boards use the population formula written out,
|
||||
guarded with `max(0.0, …)` because floating-point cancellation returns a tiny negative when
|
||||
every score is identical, and `sqrt` of that is null.
|
||||
- **`foreign_keys` is off by default in SQLite**, so every `on delete cascade` in the schema is
|
||||
decoration without the pragma. It is set on the DSN alongside WAL, `busy_timeout` and
|
||||
`_txlock=immediate`.
|
||||
|
||||
Taken while there was still no data: the tables were recreated rather than converted, same as
|
||||
entry 45. What would reverse this: enough concurrent writers that one writer is a real limit, or
|
||||
wanting the database on a different box from the audio files.
|
||||
|
||||
Reference in New Issue
Block a user