Mirrors the mbrian_admin pattern: the binary connects as a role bounded
to the projax schema, so even a compromised projax process cannot read
mai.workers, otto.*, vault.*, etc.
- 0001: switch grants block from postgres → projax_admin (conditional
on the role existing — bootstrap still works as superuser before the
role is created). Wrap `create schema` in a guard so the migration
is idempotent when re-run as a non-superuser app role that lacks
database-level CREATE.
- 0005_reown_to_projax_admin.sql: enumerate every projax-namespaced
object via pg_namespace + pg_class / pg_proc and ALTER OWNER to
projax_admin. Explicitly scoped — no global REASSIGN OWNED that
would yank ownership from other projects sharing the postgres role.
Strips residual postgres grants. No-ops with a NOTICE when the role
is missing.
- README: new "Manual prerequisite" deploy section. Documents the
CREATE ROLE statement, the cross-schema USAGE + SELECT grants, AND
the RLS policy `projax_read ON mai.projects` that's required because
mai.projects has row-level security with policies scoped to `mai`
and `anon` only. Without the policy, items_unified silently returns
zero mai-source rows.
- deploy/dokploy.yaml: DSN comment now reflects projax_admin and
points at the README prereq.
Verified locally against msupabase with a throwaway projax_admin role:
- 13/13 tests green
- mai.workers SELECT → permission denied
- mai.sessions SELECT → permission denied
- mai.projects SELECT → 59 rows (RLS policy in effect)
- projax.items_unified SELECT → 66 rows (7 projax + 59 mai)