Skip to content

test(db-postgres): run on a schema of its own; document database isolation - #206

Merged
maritonx merged 1 commit into
mainfrom
test/postgres-schema-isolation
Oct 24, 2026
Merged

maritonx merged 1 commit into
mainfrom
test/postgres-schema-isolation

Conversation

@maritonx

Copy link
Copy Markdown
Owner

Closes #156 (M5, ADR-0055 L1 step 1).

CI

  • The pgbouncer job now connects as role cms, whose search_path is its own schema easy_cms. The role is set up with the same three statements the docs show, and it has no rights on public.
  • The postgres job stays on public.
  • New postgres-schema.test.ts checks that every table lands in easy_cms and none in public, both from push and from migration files (createMigration → migrate → verify). It runs only when POSTGRES_SCHEMA is set.
  • Test cleanup now drops tables in current_schema() instead of public.

Docs

New page Database isolation (EN/TH), linked from Databases and the sidebar. It covers:

  • L0–L3 and when to pick each
  • a separate pool isolates only connections, not CPU, IO or locks
  • the L1 setup
  • what happens when you forget the role: on Postgres 15+ the first start fails with "permission denied for schema public"
  • GRANTs so the app can read CMS tables
  • moving an existing install from L0 to L1
  • L2/L3 need only their own url

The schema option (#172) and the DML-only role (#173) are mentioned in one line as planned.

No changeset: no package changes. The website shows these docs from the next release, or earlier via docs-ref.txt.

Verified locally (Docker, Postgres 17 + PgBouncer 1.26)

  • Postgres suites as cms through PgBouncer: 351 passed. Afterwards no Easy CMS table is in public.
  • A role without search_path: gets "permission denied for schema public", as the docs say.
  • Moving an install from L0 to L1 with the documented SQL: the old data stays and new ids continue from the old ones. verify passes, nothing is re-applied, and all 9 tables are in easy_cms.
  • Other checks:
    • pnpm turbo run test --continue 53/53
    • docs tests 85/85
    • vitepress build passes, with matching EN/TH anchors
    • biome ci passes (the 7 warnings were already there)

🤖 Generated with Claude Code

…ation

The pgbouncer CI job now connects as a role whose search_path is its own
schema (database isolation L1), set up with the SQL the docs show. A new
test checks that tables, from push and from migration files, land in that
schema and none in public. Test cleanup drops tables in current_schema().

New "Database isolation" page (EN/TH): levels L0-L3 and when to pick
each, why a separate pool does not isolate CPU or IO, the L1 setup, read
grants for the app, and moving an existing install to L1 (tested against
Postgres 17: data, ids and migrations carry over).

Closes #156

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@maritonx
maritonx merged commit 2f423ed into main Oct 24, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Document database isolation levels and test a separate schema

1 participant