Repository navigation
chore(compose)!: share one pgvector PostgreSQL instance between OpenAEV and XTM One (#51) - #52
Conversation
…EV and XTM One (#51) OpenAEV and XTM One now use a single pgsql service on pgvector/pgvector:pg17, with one database each. The xtm-one-db-init one-shot service creates the XTM One role (no longer a superuser), its xtm_one database and the vector extension on every start. max_connections is raised to 200 so both connection pools fit, and the healthcheck goes over TCP so it no longer passes while a new volume is being initialised. The README diagram shows PostgreSQL in the shared infrastructure, and a new section explains how to upgrade an existing deployment. BREAKING CHANGE: the shared instance starts on a new pgsqlshareddata volume. Existing deployments dump the openaev and xtm_one databases before upgrading and restore them afterwards (README, "Upgrade from separate PostgreSQL instances").
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Matching database usernames can overwrite shared administrator credentials and leave XTM One running as a superuser.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Consolidates OpenAEV and XTM One onto one PostgreSQL + pgvector instance with separate databases.
Changes:
- Adds XTM One database initialization and shared connection settings.
- Uses a new shared volume and documents migration.
- Clarifies PostgreSQL role credentials.
| File | Description |
|---|---|
| README.md | Updates architecture and adds upgrade instructions. |
| docker-compose.yml | Shares PostgreSQL and adds database initialization. |
| .env.sample | Clarifies role credentials in comments. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
#51) xtm-one-db-init now exits before psql when XTM_ONE_POSTGRES_USER equals POSTGRES_USER. With separate instances the two names could match; on the shared instance the init would have reset the superuser's password, breaking OpenAEV and the next init, or left XTM One running as a superuser. The README recovery note now warns that the shared volume holds what the platforms wrote since they started, and says to dump it before removing it.
…CRQ (#49) Brings chore/shared-postgres-51 (#52) in, so OpenCRQ is built on the single pgvector pgsql instance OpenAEV and XTM One share. Conflicts resolved by keeping both sides: the pgsql block keeps the pgvector image, max_connections and TCP healthcheck of #52 and the shm_size of #49, and the README keeps PostgreSQL in the shared infrastructure with OpenCRQ pointing at it.
…#49) opencrq-db-init now uses pgvector/pgvector:pg17, the image pgsql runs, so the stack pulls one PostgreSQL image instead of two. Like xtm-one-db-init in #52, it refuses a role name equal to POSTGRES_USER, and also to XTM_ONE_POSTGRES_USER: the shared instance holds both roles, and the init would otherwise reset the superuser's or XTM One's password. The pgsql comments and the README count OpenCRQ among the platforms sharing the instance.
|
Live validation of the upgrade with the real
Not from this PR, but found on the way: with the current OpenAEV image, |


Proposed changes
pgsqlservice onpgvector/pgvector:pg17, with one database each (openaev,xtm_one). Thepgsql-xtm-oneservice and its volume are gone.xtm-one-db-initservice, same pattern asopencrq-db-initin feat(compose): add OpenCRQ to the XTM stack (#49) #50. On every start it:XTM_ONE_POSTGRES_USERequal toPOSTGRES_USERbeforepsqlruns: the init would otherwise reset the superuser's password, or leave XTM One running as a superuser;XTM_ONE_POSTGRES_USERrole, which is no longer a superuser, and keeps its password in sync with.env;xtm_onedatabase, owned by that role;vectorextension in it. pgvector is not a trusted extension, so only a superuser can create it, and XTM One's ownCREATE EXTENSION IF NOT EXISTS vectorthen finds it already there.xtm-onewaits for it (service_completed_successfully).pgsqlchanges:max_connections=200, the value XTM One's own compose file uses. OpenAEV (Hikari, 20) and XTM One (up to 35 per process with its tracing pool, over 2 web workers and the worker) go past the default of 100.pg_isready -h localhost). On a new volume, the temporary server that initialises it listens on the Unix socket only, so the socket check could report healthy before any TCP client can connect.pgsqlshareddatavolume (see Further comments)..env.sample: comments forPOSTGRES_USERandXTM_ONE_POSTGRES_USER. No variable is added, renamed or removed.Related issues
pgsql)How to test this PR
docker compose -f docker-compose.yml --env-file .env.sample config -qpasses, andconfig --serviceslists 29 services, as onmain(one removed, one added).docker compose up -d.xtm-one-db-initexits 0,xtm-oneturns healthy, and OpenAEV starts on theopenaevdatabase.docker compose up -dagain:xtm-one-db-initreplays without error.main, follow the README section, then check that OpenAEV and XTM One show their data.Already checked locally (Docker 29.8.2, Compose 5.5.1), under throwaway project names, all removed afterwards:
xtm-one-db-initexits 0 on the first run and on a re-run.xtmonecan log in but is not a superuser, and ownsxtm_one.vector0.8.6 exists inxtm_oneonly, andmax_connectionsreads 200.xtmonecan create and query avector(3)table, but getspermission denied for schema publicinopenaev.XTM_ONE_POSTGRES_USERequal toPOSTGRES_USER,xtm-one-db-initexits 1 with its message, the superuser still logs in with its own password, and noxtm_onedatabase is created.xtmone/platform:lateston the shared instance, with Redis and Silo:xtmone. No error-level log line, and no permission error.main'spgsqlandpgsql-xtm-onewith sample data: 500 rows behind unique text indexes inopenaev, 200 rows behind an HNSW index plusalembic_versioninxtm_one.down, switched to this branch, ranxtm-one-db-init, then restored. Bothpg_restoreruns exit 0 with no errors.openaev,xtmone) are preserved, a nearest-neighbour query returns the expected row, andxtmonecan insert.docker volume rmremoves them.Checklist
type(scope?): description (#issue)Further comments
pgsqldata. That volume was initialised by the Alpine image, which uses musl, while the pgvector image is Debian, which uses glibc. With theen_US.utf8collation the two sort text differently, so text indexes built under musl would be silently wrong under glibc. PostgreSQL records no collation version for musl, so nothing would warn. A dump and restore rebuilds every index. A fresh volume also means that skipping the procedure leaves the old data intact instead of half-migrated. This is why the title carries!.chore/shared-postgres-51, so its diff holds only OpenCRQ.opencrq-db-initruns on the same pgvector image, and refuses a role name equal toPOSTGRES_USERorXTM_ONE_POSTGRES_USER.mainwhen this branch is deleted, and mergingmaininto feat(compose): add OpenCRQ to the XTM stack (#49) #50 then leaves its diff to OpenCRQ alone.postgres18) no longer applies to this file once this merges, sincepostgres:17-alpineis gone.