The app connected as 'postgres' — the bootstrap SUPERUSER — which
bypasses row-level security unconditionally (FORCE RLS does not apply
to superusers), making any future policy a silent no-op. This is the
prerequisite commit for the RLS visibility work (plan
~/.opencode/plan/server-rls-library-visibility.md REV 2, §4.0).
What changed:
- database/schema/z_rls_role.sh: creates the bookhoard_srv role
(LOGIN, non-superuser, non-bypassrls) and transfers ownership of
every public table/sequence/function + schema + database to it.
Ownership (not mere grants) because executeSchema re-runs the whole
schema.sql on EVERY boot and needs owner DDL. Idempotent, catalog-
only — no user data is read or written.
- docker-compose.yml app service + docker-compose.dev.yml tests
service: DATABASE_USER postgres -> bookhoard_srv, DATABASE_PASSWORD
DBPASS -> DBSRVPASS (new .env key, generated locally).
- POSTGRES_USER: postgres stays as the container bootstrap account;
on FRESH volumes z_rls_role.sh runs automatically via
docker-entrypoint-initdb.d AFTER schema.sql (alphabetical: z > s).
Verified on the dev stack: role has rolsuper=f, rolbypassrls=f, owns
all 40 tables and every public function; single boot as bookhoard_srv
executed schema.sql cleanly (CREATE EXTENSION IF NOT EXISTS pg_trgm
skips fine as non-superuser when the extension exists); health +
authenticated smoke pass. Behavior otherwise unchanged — no policies
yet.