fix(handlers): add handlers

This commit is contained in:
2026-01-30 16:31:53 +08:00
parent bb82c75834
commit ce12b997f4
38 changed files with 3746 additions and 317 deletions

11
sql/drop_iam_schema.sql Normal file
View File

@@ -0,0 +1,11 @@
BEGIN;
DROP TABLE IF EXISTS role_permissions;
DROP TABLE IF EXISTS user_roles;
DROP TABLE IF EXISTS refresh_tokens;
DROP TABLE IF EXISTS audit_logs;
DROP TABLE IF EXISTS roles;
DROP TABLE IF EXISTS permissions;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS tenants;
COMMIT;

106
sql/schema_post_init.sql Normal file
View File

@@ -0,0 +1,106 @@
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE tenants (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR(255) NOT NULL,
status VARCHAR(50) DEFAULT 'active',
config JSONB DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
email VARCHAR(255) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(100),
phone_number VARCHAR(20),
is_active BOOLEAN DEFAULT TRUE,
is_verified BOOLEAN DEFAULT FALSE,
mfa_enabled BOOLEAN DEFAULT FALSE,
mfa_secret VARCHAR(255),
last_login_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE UNIQUE INDEX idx_users_tenant_email ON users(tenant_id, email);
CREATE TABLE roles (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
tenant_id UUID NOT NULL REFERENCES tenants(id),
name VARCHAR(50) NOT NULL,
description TEXT,
is_system BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(tenant_id, name)
);
CREATE TABLE permissions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
code VARCHAR(100) NOT NULL UNIQUE,
description TEXT,
resource VARCHAR(50),
action VARCHAR(50),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE TABLE role_permissions (
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
permission_id UUID NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (role_id, permission_id)
);
CREATE TABLE user_roles (
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
PRIMARY KEY (user_id, role_id)
);
CREATE TABLE refresh_tokens (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token_hash VARCHAR(255) NOT NULL,
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
is_revoked BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
replaced_by_token_hash VARCHAR(255)
);
CREATE INDEX idx_refresh_tokens_user_id ON refresh_tokens(user_id);
CREATE INDEX idx_refresh_tokens_token_hash ON refresh_tokens(token_hash);
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
tenant_id UUID REFERENCES tenants(id),
user_id UUID,
action VARCHAR(100) NOT NULL,
resource VARCHAR(100),
ip_address VARCHAR(45),
user_agent TEXT,
status VARCHAR(20) NOT NULL,
details JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
INSERT INTO tenants (id, name) VALUES ('11111111-1111-1111-1111-111111111111', 'Default Corp');
INSERT INTO permissions (code, description, resource, action) VALUES
('user:read', 'View users', 'user', 'read'),
('user:write', 'Create/Update/Delete users', 'user', 'write'),
('role:read', 'View roles', 'role', 'read'),
('role:write', 'Manage roles', 'role', 'write'),
('tenant:read', 'View tenant info', 'tenant', 'read'),
('tenant:write', 'Manage tenant settings and status', 'tenant', 'write');
INSERT INTO roles (tenant_id, name, description, is_system) VALUES
('11111111-1111-1111-1111-111111111111', 'Admin', 'Administrator with full access', TRUE);
INSERT INTO role_permissions (role_id, permission_id)
SELECT r.id, p.id FROM roles r, permissions p
WHERE r.name = 'Admin' AND r.tenant_id = '11111111-1111-1111-1111-111111111111';

74
sql/verify_iam_schema.sql Normal file
View File

@@ -0,0 +1,74 @@
DO $$
BEGIN
IF to_regclass('public.tenants') IS NULL THEN
RAISE EXCEPTION 'missing table: tenants';
END IF;
IF to_regclass('public.users') IS NULL THEN
RAISE EXCEPTION 'missing table: users';
END IF;
IF to_regclass('public.roles') IS NULL THEN
RAISE EXCEPTION 'missing table: roles';
END IF;
IF to_regclass('public.permissions') IS NULL THEN
RAISE EXCEPTION 'missing table: permissions';
END IF;
IF to_regclass('public.user_roles') IS NULL THEN
RAISE EXCEPTION 'missing table: user_roles';
END IF;
IF to_regclass('public.role_permissions') IS NULL THEN
RAISE EXCEPTION 'missing table: role_permissions';
END IF;
IF to_regclass('public.refresh_tokens') IS NULL THEN
RAISE EXCEPTION 'missing table: refresh_tokens';
END IF;
IF to_regclass('public.audit_logs') IS NULL THEN
RAISE EXCEPTION 'missing table: audit_logs';
END IF;
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'tenants' AND column_name = 'status'
) THEN
RAISE EXCEPTION 'tenants.status missing';
END IF;
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'tenants' AND column_name = 'config'
) THEN
RAISE EXCEPTION 'tenants.config missing';
END IF;
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'users' AND column_name = 'mfa_enabled'
) THEN
RAISE EXCEPTION 'users.mfa_enabled missing';
END IF;
IF NOT EXISTS (
SELECT 1
FROM pg_indexes
WHERE schemaname = 'public' AND tablename = 'users' AND indexname = 'idx_users_tenant_email'
) THEN
RAISE EXCEPTION 'missing index: idx_users_tenant_email';
END IF;
IF NOT EXISTS (
SELECT 1
FROM pg_constraint c
JOIN pg_class t ON t.oid = c.conrelid
WHERE t.relname = 'users' AND c.contype = 'f' AND pg_get_constraintdef(c.oid) LIKE 'FOREIGN KEY (tenant_id)%'
) THEN
RAISE EXCEPTION 'missing foreign key users.tenant_id -> tenants.id';
END IF;
IF NOT EXISTS (
SELECT 1 FROM tenants WHERE id = '11111111-1111-1111-1111-111111111111'
) THEN
RAISE EXCEPTION 'missing seed tenant Default Corp';
END IF;
IF NOT EXISTS (SELECT 1 FROM permissions WHERE code = 'user:read') THEN
RAISE EXCEPTION 'missing seed permission user:read';
END IF;
END $$;