mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 22:21:10 +02:00
Groundwork for server-side Space extensions that must NOT live in Dexie:
- spaces.credentials — per-space OAuth tokens, API keys, SMTP
configs. Access tokens are stored
encrypted at rest with the service KEK.
- spaces.module_permissions — role × module read/write/admin overrides
on top of the SPACE_MODULE_ALLOWLIST
defaults.
Both tables FK to auth.organizations with ON DELETE CASCADE so deleting
a space drops its credentials and permission overrides automatically.
RLS is intentionally deferred — enabling it now would lock out services
that don't yet pass space context. A follow-up migration turns it on
after mana-api speaks the Spaces protocol end-to-end.
To apply locally: bun run db:push in services/mana-auth, or psql -f
sql/004_spaces.sql against the mana_platform DB.
No runtime code reads these tables yet — they're the scaffolding that
Task-8 (mana-sync) and the eventual social-relay/clubs modules will
consume.
Plan: docs/plans/spaces-foundation.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
70 lines
3.6 KiB
SQL
70 lines
3.6 KiB
SQL
-- Migration 004: Spaces schema
|
||
--
|
||
-- Adds the `spaces` schema with two server-side tables that extend Better
|
||
-- Auth organizations for our multi-tenancy model. See
|
||
-- docs/plans/spaces-foundation.md for the full RFC, and the Drizzle
|
||
-- definitions at src/db/schema/spaces.ts.
|
||
--
|
||
-- Why a separate schema:
|
||
-- - Keeps auth tables focused on identity, not domain extensions
|
||
-- - Lets us grant narrower RLS policies per schema
|
||
-- - Mirrors the pgSchema-per-concern pattern used across mana_platform
|
||
--
|
||
-- Idempotent: re-running on a partially-migrated DB is safe.
|
||
|
||
-- ─── Schema ──────────────────────────────────────────────────────
|
||
CREATE SCHEMA IF NOT EXISTS spaces;
|
||
|
||
-- ─── credentials ────────────────────────────────────────────────
|
||
-- Per-space external credentials: OAuth tokens, API keys, SMTP configs.
|
||
-- NEVER stored client-side — these are server-held secrets, wrapped with
|
||
-- the service-wide KEK (same mechanism as auth.encryption_vaults).
|
||
CREATE TABLE IF NOT EXISTS spaces.credentials (
|
||
space_id TEXT NOT NULL,
|
||
provider TEXT NOT NULL,
|
||
access_token_encrypted TEXT NOT NULL,
|
||
refresh_token_encrypted TEXT,
|
||
expires_at TIMESTAMPTZ,
|
||
scopes TEXT[],
|
||
provider_account_id TEXT,
|
||
metadata_json TEXT,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
PRIMARY KEY (space_id, provider),
|
||
CONSTRAINT space_credentials_space_fk
|
||
FOREIGN KEY (space_id) REFERENCES auth.organizations (id) ON DELETE CASCADE
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS space_credentials_space_idx
|
||
ON spaces.credentials (space_id);
|
||
|
||
-- ─── module_permissions ─────────────────────────────────────────
|
||
-- Role × module permission matrix. If no row exists for a given
|
||
-- (space, role, module) tuple, the default is derived from SPACE_MODULE_ALLOWLIST
|
||
-- plus role-tier fallback (owner > admin > member). Rows here are
|
||
-- explicit overrides — typically written when a space owner customises
|
||
-- the default permissions for a custom role.
|
||
CREATE TABLE IF NOT EXISTS spaces.module_permissions (
|
||
space_id TEXT NOT NULL,
|
||
role TEXT NOT NULL,
|
||
module_id TEXT NOT NULL,
|
||
can_read BOOLEAN NOT NULL DEFAULT TRUE,
|
||
can_write BOOLEAN NOT NULL DEFAULT FALSE,
|
||
can_admin BOOLEAN NOT NULL DEFAULT FALSE,
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
PRIMARY KEY (space_id, role, module_id),
|
||
CONSTRAINT space_module_permissions_space_fk
|
||
FOREIGN KEY (space_id) REFERENCES auth.organizations (id) ON DELETE CASCADE
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS space_module_permissions_space_module_idx
|
||
ON spaces.module_permissions (space_id, module_id);
|
||
|
||
-- ─── RLS ─────────────────────────────────────────────────────────
|
||
-- Defer enabling RLS until the rest of the app is scope-aware. Turning
|
||
-- it on now would lock out services that don't yet pass the space
|
||
-- context. Re-enable in a follow-up migration once mana-api speaks the
|
||
-- Spaces protocol end-to-end.
|
||
--
|
||
-- ALTER TABLE spaces.credentials ENABLE ROW LEVEL SECURITY;
|
||
-- ALTER TABLE spaces.module_permissions ENABLE ROW LEVEL SECURITY;
|