124 lines
4.4 KiB
PL/PgSQL
124 lines
4.4 KiB
PL/PgSQL
BEGIN;
|
|
|
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
|
|
CREATE OR REPLACE FUNCTION set_updated_at()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = NOW();
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE TABLE tenants (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_code TEXT NOT NULL UNIQUE,
|
|
name TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('draft', 'active', 'disabled', 'archived')),
|
|
theme_jsonb JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
settings_jsonb JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TRIGGER tenants_set_updated_at
|
|
BEFORE UPDATE ON tenants
|
|
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
|
|
|
CREATE TABLE entry_channels (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
|
|
channel_code TEXT NOT NULL,
|
|
channel_type TEXT NOT NULL CHECK (channel_type IN ('app', 'wechat_mini', 'wechat_oa', 'h5', 'qr')),
|
|
platform_app_id TEXT,
|
|
display_name TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('draft', 'active', 'disabled', 'archived')),
|
|
is_default BOOLEAN NOT NULL DEFAULT FALSE,
|
|
config_jsonb JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
UNIQUE (tenant_id, channel_code)
|
|
);
|
|
|
|
CREATE INDEX entry_channels_tenant_id_idx ON entry_channels(tenant_id);
|
|
CREATE INDEX entry_channels_platform_app_id_idx ON entry_channels(platform_app_id);
|
|
|
|
CREATE TRIGGER entry_channels_set_updated_at
|
|
BEFORE UPDATE ON entry_channels
|
|
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
|
|
|
CREATE TABLE users (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_public_id TEXT NOT NULL UNIQUE,
|
|
default_tenant_id UUID REFERENCES tenants(id) ON DELETE SET NULL,
|
|
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled', 'deleted')),
|
|
nickname TEXT,
|
|
avatar_url TEXT,
|
|
last_login_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX users_default_tenant_id_idx ON users(default_tenant_id);
|
|
|
|
CREATE TRIGGER users_set_updated_at
|
|
BEFORE UPDATE ON users
|
|
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
|
|
|
CREATE TABLE login_identities (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
identity_type TEXT NOT NULL CHECK (identity_type IN ('mobile', 'wechat_mini_openid', 'wechat_oa_openid', 'wechat_unionid')),
|
|
provider TEXT NOT NULL,
|
|
provider_subject TEXT NOT NULL,
|
|
country_code TEXT,
|
|
mobile TEXT,
|
|
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'disabled', 'deleted')),
|
|
profile_jsonb JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
UNIQUE (provider, provider_subject)
|
|
);
|
|
|
|
CREATE INDEX login_identities_user_id_idx ON login_identities(user_id);
|
|
CREATE INDEX login_identities_mobile_idx ON login_identities(country_code, mobile);
|
|
|
|
CREATE TRIGGER login_identities_set_updated_at
|
|
BEFORE UPDATE ON login_identities
|
|
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
|
|
|
CREATE TABLE auth_sms_codes (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
scene TEXT NOT NULL,
|
|
country_code TEXT NOT NULL,
|
|
mobile TEXT NOT NULL,
|
|
client_type TEXT NOT NULL CHECK (client_type IN ('app', 'wechat')),
|
|
device_key TEXT NOT NULL,
|
|
code_hash TEXT NOT NULL,
|
|
provider_payload_jsonb JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
cooldown_until TIMESTAMPTZ NOT NULL,
|
|
consumed_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX auth_sms_codes_lookup_idx
|
|
ON auth_sms_codes(country_code, mobile, client_type, scene, created_at DESC);
|
|
|
|
CREATE TABLE auth_refresh_tokens (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
client_type TEXT NOT NULL CHECK (client_type IN ('app', 'wechat')),
|
|
device_key TEXT,
|
|
token_hash TEXT NOT NULL UNIQUE,
|
|
issued_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
revoked_at TIMESTAMPTZ,
|
|
replaced_by_token_id UUID REFERENCES auth_refresh_tokens(id) ON DELETE SET NULL
|
|
);
|
|
|
|
CREATE INDEX auth_refresh_tokens_user_id_idx ON auth_refresh_tokens(user_id);
|
|
CREATE INDEX auth_refresh_tokens_expires_at_idx ON auth_refresh_tokens(expires_at);
|
|
|
|
COMMIT;
|