books/backend/Books.Api/Database/Migrations/005_UserCompanyAccess.sql

34 lines
1.6 KiB
MySQL
Raw Normal View History

-- 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;