-- Phase 2.8: Authentication and Multi-Tenant Schema -- -- Adds: -- 1. memory_projects table (source of truth for project ownership) -- 2. contributed_by columns (attribution tracking) -- 3. Indexes for fast lookups -- -- Note: RBAC itself lives in auth provider (Authentik, custom service, etc). -- This schema only tracks project ownership and user attribution. -- ───────────────────────────────────────────────────────────────────────────── -- 1. Projects table (source of truth for ownership) -- ───────────────────────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS memory_projects ( id VARCHAR(255) PRIMARY KEY, -- Ownership owner_id VARCHAR(255) NOT NULL, -- JWT "sub" of creator visibility VARCHAR(20) NOT NULL, -- "private" | "team" | "public" -- Metadata name VARCHAR(255), -- Display name description TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Soft delete deleted_at TIMESTAMPTZ ); CREATE INDEX IF NOT EXISTS idx_memory_projects_owner_id ON memory_projects(owner_id) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_memory_projects_visibility ON memory_projects(visibility) WHERE deleted_at IS NULL; -- ───────────────────────────────────────────────────────────────────────────── -- 2. Add attribution columns to entities -- ───────────────────────────────────────────────────────────────────────────── ALTER TABLE memory_entity ADD COLUMN IF NOT EXISTS ( contributed_by VARCHAR(255), -- JWT "sub" who added this contribution_type VARCHAR(50), -- "extracted" | "manual" | "inferred" contribution_date TIMESTAMPTZ ); -- Populate contributed_by with defaults (assume "system" if not present) UPDATE memory_entity SET contributed_by = 'system' WHERE contributed_by IS NULL; ALTER TABLE memory_entity ALTER COLUMN contributed_by SET NOT NULL; CREATE INDEX IF NOT EXISTS idx_memory_entity_contributed_by ON memory_entity(contributed_by); CREATE INDEX IF NOT EXISTS idx_memory_entity_contribution_date ON memory_entity(contribution_date) WHERE contribution_date IS NOT NULL; -- ───────────────────────────────────────────────────────────────────────────── -- 3. Add attribution columns to edges -- ───────────────────────────────────────────────────────────────────────────── ALTER TABLE memory_edge ADD COLUMN IF NOT EXISTS ( contributed_by VARCHAR(255), -- JWT "sub" who added this contribution_type VARCHAR(50) -- "extracted" | "inferred" ); -- Populate contributed_by with defaults UPDATE memory_edge SET contributed_by = 'system' WHERE contributed_by IS NULL; ALTER TABLE memory_edge ALTER COLUMN contributed_by SET NOT NULL; CREATE INDEX IF NOT EXISTS idx_memory_edge_contributed_by ON memory_edge(contributed_by); -- ───────────────────────────────────────────────────────────────────────────── -- 4. Add project_id to entities and edges (optional, for faster filtering) -- ───────────────────────────────────────────────────────────────────────────── -- ALTER TABLE memory_entity ADD COLUMN IF NOT EXISTS project_id VARCHAR(255); -- ALTER TABLE memory_edge ADD COLUMN IF NOT EXISTS project_id VARCHAR(255); -- -- Note: Deferred. Can use project info from path/source instead. -- ───────────────────────────────────────────────────────────────────────────── -- 5. Views for common queries -- ───────────────────────────────────────────────────────────────────────────── -- Entities contributed by a user in a time range CREATE OR REPLACE VIEW v_user_contributions AS SELECT contributed_by, COUNT(*) as entity_count, MAX(contribution_date) as last_contribution, ARRAY_AGG(DISTINCT contribution_type) as contribution_types FROM memory_entity WHERE contribution_date IS NOT NULL GROUP BY contributed_by; -- Recent contributions (last 7 days) CREATE OR REPLACE VIEW v_recent_contributions AS SELECT contributed_by, COUNT(*) as count, MAX(contribution_date) as latest FROM memory_entity WHERE contribution_date > CURRENT_TIMESTAMP - INTERVAL '7 days' GROUP BY contributed_by; -- ───────────────────────────────────────────────────────────────────────────── -- 6. Rollback support -- ───────────────────────────────────────────────────────────────────────────── -- To rollback this migration: -- -- DROP VIEW IF EXISTS v_recent_contributions; -- DROP VIEW IF EXISTS v_user_contributions; -- -- DROP INDEX IF EXISTS idx_memory_projects_owner_id; -- DROP INDEX IF EXISTS idx_memory_projects_visibility; -- DROP TABLE IF EXISTS memory_projects; -- -- DROP INDEX IF EXISTS idx_memory_entity_contributed_by; -- DROP INDEX IF EXISTS idx_memory_entity_contribution_date; -- ALTER TABLE memory_entity DROP COLUMN IF EXISTS contributed_by; -- ALTER TABLE memory_entity DROP COLUMN IF EXISTS contribution_type; -- ALTER TABLE memory_entity DROP COLUMN IF EXISTS contribution_date; -- -- DROP INDEX IF EXISTS idx_memory_edge_contributed_by; -- ALTER TABLE memory_edge DROP COLUMN IF EXISTS contributed_by; -- ALTER TABLE memory_edge DROP COLUMN IF EXISTS contribution_type;