-- User Company Access table for multi-tenant authorization -- Maps users to companies with specific roles CREATE TABLE IF NOT EXISTS user_company_access_read_models ( aggregate_id VARCHAR(255) PRIMARY KEY, create_time TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_time TIMESTAMPTZ NOT NULL DEFAULT NOW(), last_aggregate_sequence_number INT NOT NULL DEFAULT 1, user_id VARCHAR(255) NOT NULL, -- Keycloak user ID or email company_id VARCHAR(255) NOT NULL, -- Reference to company aggregate role VARCHAR(50) NOT NULL, -- owner, accountant, viewer granted_by VARCHAR(255) NOT NULL, -- Who granted this access granted_at TIMESTAMPTZ NOT NULL, is_active BOOLEAN NOT NULL DEFAULT TRUE, revoked_at TIMESTAMPTZ, revoked_by VARCHAR(255), -- Ensure unique user-company combination (only one active access per user per company) CONSTRAINT uq_user_company_active UNIQUE (user_id, company_id), -- Ensure valid role values CONSTRAINT chk_role CHECK (role IN ('owner', 'accountant', 'viewer')) ); -- Index for looking up all companies a user has access to CREATE INDEX IF NOT EXISTS idx_user_access_user ON user_company_access_read_models(user_id) WHERE is_active = true; -- Index for looking up all users with access to a company CREATE INDEX IF NOT EXISTS idx_user_access_company ON user_company_access_read_models(company_id) WHERE is_active = true; -- Composite index for efficient access checks CREATE INDEX IF NOT EXISTS idx_user_access_check ON user_company_access_read_models(user_id, company_id, role) WHERE is_active = true;