154 lines
6.4 KiB
PL/PgSQL
154 lines
6.4 KiB
PL/PgSQL
BEGIN;
|
|
|
|
-- DMLP phase 2: introduce the tenant, installation and license source of truth.
|
|
-- The fixed legacy tenant is a migration bridge for the identity data copied by
|
|
-- 001_identity_login_schema.sql. Replace its migration license through the
|
|
-- administration workflow before commercial enforcement is enabled.
|
|
|
|
CREATE TABLE IF NOT EXISTS identity.client_account (
|
|
tenant_id uuid PRIMARY KEY,
|
|
client_slug character varying(80) NOT NULL,
|
|
client_name character varying(200) NOT NULL,
|
|
status character varying(20) NOT NULL,
|
|
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
updated_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
CONSTRAINT uq_identity_client_account_slug UNIQUE (client_slug),
|
|
CONSTRAINT ck_identity_client_account_slug
|
|
CHECK (client_slug ~ '^[a-z0-9]+(?:-[a-z0-9]+)*$'),
|
|
CONSTRAINT ck_identity_client_account_status
|
|
CHECK (status IN ('ACTIVE', 'SUSPENDED', 'CANCELLED'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS identity.client_installation (
|
|
installation_id uuid PRIMARY KEY,
|
|
tenant_id uuid NOT NULL,
|
|
client_id character varying(80) NOT NULL,
|
|
installation_code character varying(100) NOT NULL,
|
|
assertion_public_key text NOT NULL,
|
|
allowed_scopes text[] NOT NULL DEFAULT ARRAY[]::text[],
|
|
enabled boolean NOT NULL DEFAULT true,
|
|
security_version integer NOT NULL DEFAULT 1,
|
|
last_authenticated_at timestamp with time zone,
|
|
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
updated_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
CONSTRAINT fk_identity_installation_tenant
|
|
FOREIGN KEY (tenant_id)
|
|
REFERENCES identity.client_account (tenant_id),
|
|
CONSTRAINT uq_identity_installation_client_code
|
|
UNIQUE (client_id, installation_code),
|
|
CONSTRAINT ck_identity_installation_client_id
|
|
CHECK (client_id ~ '^[A-Za-z0-9][A-Za-z0-9_-]*$'),
|
|
CONSTRAINT ck_identity_installation_code
|
|
CHECK (installation_code ~ '^[A-Za-z0-9][A-Za-z0-9_-]*$'),
|
|
CONSTRAINT ck_identity_installation_security_version
|
|
CHECK (security_version > 0)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS identity.client_license (
|
|
license_id uuid PRIMARY KEY,
|
|
tenant_id uuid NOT NULL,
|
|
license_type character varying(30) NOT NULL,
|
|
package_code character varying(50) NOT NULL,
|
|
valid_from timestamp with time zone NOT NULL,
|
|
valid_until timestamp with time zone NOT NULL,
|
|
status character varying(20) NOT NULL,
|
|
max_users integer,
|
|
max_installations integer,
|
|
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
updated_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
CONSTRAINT fk_identity_license_tenant
|
|
FOREIGN KEY (tenant_id)
|
|
REFERENCES identity.client_account (tenant_id),
|
|
CONSTRAINT ck_identity_license_period
|
|
CHECK (valid_until > valid_from),
|
|
CONSTRAINT ck_identity_license_status
|
|
CHECK (status IN ('ACTIVE', 'SUSPENDED', 'EXPIRED', 'CANCELLED')),
|
|
CONSTRAINT ck_identity_license_limits
|
|
CHECK ((max_users IS NULL OR max_users > 0)
|
|
AND (max_installations IS NULL OR max_installations > 0))
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS ix_identity_installation_tenant_enabled
|
|
ON identity.client_installation (tenant_id, enabled);
|
|
CREATE INDEX IF NOT EXISTS ix_identity_installation_lookup
|
|
ON identity.client_installation (client_id, installation_code, enabled);
|
|
CREATE INDEX IF NOT EXISTS ix_identity_license_tenant_period
|
|
ON identity.client_license (tenant_id, status, valid_from, valid_until);
|
|
|
|
-- Add tenant ownership without changing any legacy primary-key values.
|
|
ALTER TABLE identity.company
|
|
ADD COLUMN IF NOT EXISTS tenant_id uuid;
|
|
ALTER TABLE identity.company_branch
|
|
ADD COLUMN IF NOT EXISTS tenant_id uuid;
|
|
ALTER TABLE identity.user_group
|
|
ADD COLUMN IF NOT EXISTS tenant_id uuid;
|
|
ALTER TABLE identity.app_user
|
|
ADD COLUMN IF NOT EXISTS tenant_id uuid;
|
|
ALTER TABLE identity.permission
|
|
ADD COLUMN IF NOT EXISTS tenant_id uuid;
|
|
ALTER TABLE identity.denied_pages
|
|
ADD COLUMN IF NOT EXISTS tenant_id uuid;
|
|
ALTER TABLE identity.user_loginhistory
|
|
ADD COLUMN IF NOT EXISTS tenant_id uuid;
|
|
|
|
-- Seed a stable bridge tenant for all identity data that already exists.
|
|
INSERT INTO identity.client_account
|
|
(tenant_id, client_slug, client_name, status)
|
|
VALUES ('00000000-0000-4000-8000-000000000001', 'matrix', 'Matrix', 'ACTIVE')
|
|
ON CONFLICT (tenant_id) DO UPDATE SET
|
|
client_slug = EXCLUDED.client_slug,
|
|
client_name = EXCLUDED.client_name,
|
|
updated_at = now();
|
|
|
|
-- A non-expiring migration bridge keeps current users operational. It must be
|
|
-- replaced by a commercial license before license administration goes live.
|
|
INSERT INTO identity.client_license
|
|
(license_id, tenant_id, license_type, package_code,
|
|
valid_from, valid_until, status)
|
|
VALUES ('00000000-0000-4000-8000-000000000002',
|
|
'00000000-0000-4000-8000-000000000001',
|
|
'MIGRATION', 'LEGACY_FULL',
|
|
'2020-01-01 00:00:00+00', '2099-12-31 23:59:59+00', 'ACTIVE')
|
|
ON CONFLICT (license_id) DO NOTHING;
|
|
|
|
UPDATE identity.company
|
|
SET tenant_id = '00000000-0000-4000-8000-000000000001'
|
|
WHERE tenant_id IS NULL;
|
|
UPDATE identity.company_branch
|
|
SET tenant_id = '00000000-0000-4000-8000-000000000001'
|
|
WHERE tenant_id IS NULL;
|
|
UPDATE identity.user_group
|
|
SET tenant_id = '00000000-0000-4000-8000-000000000001'
|
|
WHERE tenant_id IS NULL;
|
|
UPDATE identity.app_user
|
|
SET tenant_id = '00000000-0000-4000-8000-000000000001'
|
|
WHERE tenant_id IS NULL;
|
|
UPDATE identity.permission
|
|
SET tenant_id = '00000000-0000-4000-8000-000000000001'
|
|
WHERE tenant_id IS NULL;
|
|
UPDATE identity.denied_pages
|
|
SET tenant_id = '00000000-0000-4000-8000-000000000001'
|
|
WHERE tenant_id IS NULL;
|
|
UPDATE identity.user_loginhistory
|
|
SET tenant_id = '00000000-0000-4000-8000-000000000001'
|
|
WHERE tenant_id IS NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS ix_identity_company_tenant
|
|
ON identity.company (tenant_id, company_id);
|
|
CREATE INDEX IF NOT EXISTS ix_identity_branch_tenant
|
|
ON identity.company_branch (tenant_id, company_id, branch_id);
|
|
CREATE INDEX IF NOT EXISTS ix_identity_group_tenant
|
|
ON identity.user_group (tenant_id, group_id);
|
|
CREATE INDEX IF NOT EXISTS ix_identity_user_tenant_login
|
|
ON identity.app_user (tenant_id, upper(loginid));
|
|
CREATE INDEX IF NOT EXISTS ix_identity_permission_tenant_group_page
|
|
ON identity.permission (tenant_id, group_id, page_id)
|
|
WHERE permission <> '000';
|
|
CREATE INDEX IF NOT EXISTS ix_identity_denied_tenant_user_page
|
|
ON identity.denied_pages (tenant_id, user_id, page_id)
|
|
WHERE isdenied = 1;
|
|
CREATE INDEX IF NOT EXISTS ix_identity_login_history_tenant_user_time
|
|
ON identity.user_loginhistory (tenant_id, user_id, logintime DESC);
|
|
|
|
COMMIT;
|