217 lines
8.3 KiB
Go
217 lines
8.3 KiB
Go
package meta
|
||
|
||
import (
|
||
"context"
|
||
"database/sql"
|
||
"fmt"
|
||
)
|
||
|
||
const metaSchemaSQL = `
|
||
CREATE SCHEMA IF NOT EXISTS platform_meta;
|
||
|
||
CREATE TABLE IF NOT EXISTS platform_meta.tenants (
|
||
tenant_id BIGSERIAL PRIMARY KEY,
|
||
name VARCHAR(128) NOT NULL,
|
||
slug VARCHAR(64) NOT NULL DEFAULT '',
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS platform_meta.users (
|
||
user_id BIGSERIAL PRIMARY KEY,
|
||
tenant_id BIGINT REFERENCES platform_meta.tenants(tenant_id),
|
||
username VARCHAR(64) NOT NULL,
|
||
password_hash TEXT NOT NULL,
|
||
display_name VARCHAR(128) NOT NULL DEFAULT '',
|
||
role VARCHAR(32) NOT NULL DEFAULT 'pending',
|
||
status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
CONSTRAINT uq_users_username UNIQUE (username)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_users_tenant ON platform_meta.users (tenant_id);
|
||
|
||
-- 兼容旧库:允许无租户(pending)
|
||
ALTER TABLE platform_meta.users ALTER COLUMN tenant_id DROP NOT NULL;
|
||
ALTER TABLE platform_meta.users ADD COLUMN IF NOT EXISTS status VARCHAR(32) NOT NULL DEFAULT 'active';
|
||
|
||
CREATE TABLE IF NOT EXISTS platform_meta.tenant_apps (
|
||
app_id UUID PRIMARY KEY,
|
||
tenant_id BIGINT NOT NULL,
|
||
slug VARCHAR(64) NOT NULL,
|
||
name VARCHAR(128) NOT NULL,
|
||
schema_name VARCHAR(64) NOT NULL,
|
||
engine VARCHAR(32) NOT NULL,
|
||
status VARCHAR(32) NOT NULL,
|
||
blueprint_json JSONB NOT NULL,
|
||
ddl_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||
endpoints_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||
error_msg TEXT NOT NULL DEFAULT '',
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
CONSTRAINT uq_tenant_apps_tenant_slug UNIQUE (tenant_id, slug)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_tenant_apps_tenant_status
|
||
ON platform_meta.tenant_apps (tenant_id, status);
|
||
|
||
ALTER TABLE platform_meta.tenant_apps
|
||
ADD COLUMN IF NOT EXISTS database_name VARCHAR(64) NOT NULL DEFAULT '';
|
||
|
||
CREATE TABLE IF NOT EXISTS platform_meta.audit_logs (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
tenant_id BIGINT NOT NULL,
|
||
user_id BIGINT NOT NULL,
|
||
action VARCHAR(64) NOT NULL,
|
||
detail TEXT NOT NULL DEFAULT '',
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
|
||
-- 智能体服务账号(机器身份,供宿主自动登录)
|
||
CREATE TABLE IF NOT EXISTS platform_meta.agent_accounts (
|
||
agent_id BIGSERIAL PRIMARY KEY,
|
||
tenant_id BIGINT NOT NULL REFERENCES platform_meta.tenants(tenant_id),
|
||
name VARCHAR(128) NOT NULL,
|
||
client_id VARCHAR(64) NOT NULL,
|
||
client_secret_hash TEXT NOT NULL,
|
||
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
||
created_by BIGINT NOT NULL DEFAULT 0,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
last_token_at TIMESTAMPTZ,
|
||
CONSTRAINT uq_agent_client_id UNIQUE (client_id)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_agent_accounts_tenant
|
||
ON platform_meta.agent_accounts (tenant_id);
|
||
|
||
ALTER TABLE platform_meta.agent_accounts
|
||
ADD COLUMN IF NOT EXISTS host_key VARCHAR(128) NOT NULL DEFAULT '';
|
||
|
||
CREATE UNIQUE INDEX IF NOT EXISTS uq_agent_tenant_host_key
|
||
ON platform_meta.agent_accounts (tenant_id, host_key)
|
||
WHERE host_key <> '';
|
||
|
||
CREATE TABLE IF NOT EXISTS platform_meta.agent_permissions (
|
||
agent_id BIGINT NOT NULL REFERENCES platform_meta.agent_accounts(agent_id) ON DELETE CASCADE,
|
||
perm VARCHAR(64) NOT NULL,
|
||
PRIMARY KEY (agent_id, perm)
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS platform_meta.agent_app_grants (
|
||
agent_id BIGINT NOT NULL REFERENCES platform_meta.agent_accounts(agent_id) ON DELETE CASCADE,
|
||
slug VARCHAR(64) NOT NULL,
|
||
PRIMARY KEY (agent_id, slug)
|
||
);
|
||
|
||
-- 可编辑角色(租户级)
|
||
CREATE TABLE IF NOT EXISTS platform_meta.roles (
|
||
role_id BIGSERIAL PRIMARY KEY,
|
||
tenant_id BIGINT NOT NULL REFERENCES platform_meta.tenants(tenant_id),
|
||
code VARCHAR(64) NOT NULL,
|
||
name VARCHAR(128) NOT NULL,
|
||
description TEXT NOT NULL DEFAULT '',
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
CONSTRAINT uq_roles_tenant_code UNIQUE (tenant_id, code)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_roles_tenant ON platform_meta.roles (tenant_id);
|
||
|
||
CREATE TABLE IF NOT EXISTS platform_meta.role_permissions (
|
||
role_id BIGINT NOT NULL REFERENCES platform_meta.roles(role_id) ON DELETE CASCADE,
|
||
perm VARCHAR(64) NOT NULL,
|
||
PRIMARY KEY (role_id, perm)
|
||
);
|
||
|
||
ALTER TABLE platform_meta.agent_accounts
|
||
ADD COLUMN IF NOT EXISTS role_id BIGINT;
|
||
|
||
-- 租户邀请码:pending 用户凭码加入已有公司
|
||
CREATE TABLE IF NOT EXISTS platform_meta.tenant_invites (
|
||
invite_id BIGSERIAL PRIMARY KEY,
|
||
tenant_id BIGINT NOT NULL REFERENCES platform_meta.tenants(tenant_id) ON DELETE CASCADE,
|
||
code VARCHAR(64) NOT NULL,
|
||
role VARCHAR(32) NOT NULL DEFAULT 'editor',
|
||
created_by BIGINT NOT NULL DEFAULT 0,
|
||
max_uses INT NOT NULL DEFAULT 1,
|
||
used_count INT NOT NULL DEFAULT 0,
|
||
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
||
expires_at TIMESTAMPTZ,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
CONSTRAINT uq_tenant_invites_code UNIQUE (code)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_tenant_invites_tenant
|
||
ON platform_meta.tenant_invites (tenant_id);
|
||
|
||
-- 租户内多级组织(默认最多 5 级)
|
||
CREATE TABLE IF NOT EXISTS platform_meta.org_units (
|
||
org_unit_id BIGSERIAL PRIMARY KEY,
|
||
tenant_id BIGINT NOT NULL REFERENCES platform_meta.tenants(tenant_id) ON DELETE CASCADE,
|
||
parent_id BIGINT REFERENCES platform_meta.org_units(org_unit_id) ON DELETE CASCADE,
|
||
name VARCHAR(128) NOT NULL,
|
||
code VARCHAR(64) NOT NULL DEFAULT '',
|
||
depth INT NOT NULL DEFAULT 1,
|
||
path VARCHAR(512) NOT NULL DEFAULT '',
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_org_units_tenant_parent
|
||
ON platform_meta.org_units (tenant_id, parent_id);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_org_units_tenant_path
|
||
ON platform_meta.org_units (tenant_id, path);
|
||
|
||
CREATE UNIQUE INDEX IF NOT EXISTS uq_org_units_tenant_code
|
||
ON platform_meta.org_units (tenant_id, code)
|
||
WHERE code <> '';
|
||
|
||
ALTER TABLE platform_meta.users
|
||
ADD COLUMN IF NOT EXISTS org_unit_id BIGINT;
|
||
|
||
ALTER TABLE platform_meta.tenant_invites
|
||
ADD COLUMN IF NOT EXISTS org_unit_id BIGINT NOT NULL DEFAULT 0;
|
||
|
||
ALTER TABLE platform_meta.users
|
||
ALTER COLUMN role TYPE VARCHAR(64);
|
||
|
||
CREATE TABLE IF NOT EXISTS platform_meta.tenant_permissions (
|
||
tenant_id BIGINT NOT NULL REFERENCES platform_meta.tenants(tenant_id) ON DELETE CASCADE,
|
||
perm VARCHAR(64) NOT NULL,
|
||
PRIMARY KEY (tenant_id, perm)
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS platform_meta.tenant_entitlement_state (
|
||
tenant_id BIGINT PRIMARY KEY REFERENCES platform_meta.tenants(tenant_id) ON DELETE CASCADE,
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
|
||
-- 公司路径 slug(www.example.com/{slug}/);旧库补列
|
||
ALTER TABLE platform_meta.tenants ADD COLUMN IF NOT EXISTS slug VARCHAR(64) NOT NULL DEFAULT '';
|
||
CREATE UNIQUE INDEX IF NOT EXISTS uq_tenants_slug ON platform_meta.tenants (slug) WHERE slug <> '';
|
||
|
||
-- 手机号(可绑定;非空时全局唯一,可用于登录)
|
||
ALTER TABLE platform_meta.users ADD COLUMN IF NOT EXISTS phone VARCHAR(20) NOT NULL DEFAULT '';
|
||
CREATE UNIQUE INDEX IF NOT EXISTS uq_users_phone ON platform_meta.users (phone) WHERE phone <> '';
|
||
|
||
-- 已绑手机时可禁用用户名登录(仅手机号+密码/短信)
|
||
ALTER TABLE platform_meta.users ADD COLUMN IF NOT EXISTS username_login_disabled BOOLEAN NOT NULL DEFAULT false;
|
||
|
||
-- 授权租约已消费 id(删 leases 目录后仍能拦截旧延期包)
|
||
CREATE TABLE IF NOT EXISTS platform_meta.license_consumed (
|
||
lease_id VARCHAR(64) PRIMARY KEY,
|
||
active BOOLEAN NOT NULL DEFAULT false,
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_license_consumed_active ON platform_meta.license_consumed (active) WHERE active;
|
||
`
|
||
|
||
// EnsureSchema 创建平台元数据表(幂等)。
|
||
func EnsureSchema(ctx context.Context, db *sql.DB) error {
|
||
if db == nil {
|
||
return fmt.Errorf("db is nil")
|
||
}
|
||
if _, err := db.ExecContext(ctx, metaSchemaSQL); err != nil {
|
||
return fmt.Errorf("meta migrate: %w", err)
|
||
}
|
||
return nil
|
||
}
|