From 3eeb05445269f2b9acfebe837194645e4d96751e Mon Sep 17 00:00:00 2001 From: ZhenYi <434836402@qq.com> Date: Mon, 20 Apr 2026 19:32:38 +0800 Subject: [PATCH] feat(admin): auto-migrate admin DB tables on health check (audit_log, user, role, permission) --- admin/src/app/api/health/route.ts | 135 +++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 2 deletions(-) diff --git a/admin/src/app/api/health/route.ts b/admin/src/app/api/health/route.ts index 7b3a304..5d3bba9 100644 --- a/admin/src/app/api/health/route.ts +++ b/admin/src/app/api/health/route.ts @@ -1,7 +1,138 @@ import { NextResponse } from "next/server"; +import { query } from "@/lib/db"; export const runtime = "nodejs"; -export async function GET() { - return NextResponse.json({ status: "ok" }, { status: 200 }); +let migrationDone = false; + +async function ensureTables() { + if (migrationDone) return; + migrationDone = true; + + console.log("[Health] Checking database tables..."); + + // 1. admin_audit_log + await query(` + CREATE TABLE IF NOT EXISTS admin_audit_log ( + id BIGSERIAL PRIMARY KEY, + user_id INTEGER NOT NULL, + username VARCHAR(255) NOT NULL, + action VARCHAR(50) NOT NULL, + resource VARCHAR(255) NOT NULL, + resource_id VARCHAR(255), + request_params JSONB, + ip_address VARCHAR(255), + user_agent TEXT, + result VARCHAR(20) NOT NULL DEFAULT 'success', + error_message TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ) + `); + + // 2. admin_user + await query(` + CREATE TABLE IF NOT EXISTS admin_user ( + id SERIAL PRIMARY KEY, + username VARCHAR(255) UNIQUE NOT NULL, + password_hash VARCHAR(255) NOT NULL, + is_active BOOLEAN NOT NULL DEFAULT true, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ) + `); + + // 3. admin_role + await query(` + CREATE TABLE IF NOT EXISTS admin_role ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) UNIQUE NOT NULL, + description TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ) + `); + + // 4. admin_permission + await query(` + CREATE TABLE IF NOT EXISTS admin_permission ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + code VARCHAR(255) UNIQUE NOT NULL, + description TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ) + `); + + // 5. admin_user_role + await query(` + CREATE TABLE IF NOT EXISTS admin_user_role ( + user_id INTEGER NOT NULL REFERENCES admin_user(id) ON DELETE CASCADE, + role_id INTEGER NOT NULL REFERENCES admin_role(id) ON DELETE CASCADE, + PRIMARY KEY (user_id, role_id) + ) + `); + + // 6. admin_role_permission + await query(` + CREATE TABLE IF NOT EXISTS admin_role_permission ( + role_id INTEGER NOT NULL REFERENCES admin_role(id) ON DELETE CASCADE, + permission_id INTEGER NOT NULL REFERENCES admin_permission(id) ON DELETE CASCADE, + PRIMARY KEY (role_id, permission_id) + ) + `); + + // 索引 + await query(`CREATE INDEX IF NOT EXISTS idx_admin_user_username ON admin_user(username)`); + await query(`CREATE INDEX IF NOT EXISTS idx_admin_audit_log_user_id ON admin_audit_log(user_id)`); + await query(`CREATE INDEX IF NOT EXISTS idx_admin_audit_log_created_at ON admin_audit_log(created_at DESC)`); + await query(`CREATE INDEX IF NOT EXISTS idx_admin_audit_log_action ON admin_audit_log(action)`); + await query(`CREATE INDEX IF NOT EXISTS idx_admin_audit_log_resource ON admin_audit_log(resource)`); + + // Seed data + await query(` + INSERT INTO admin_permission (name, code, description) VALUES + ('用户管理', 'user:read', '查看用户列表'), + ('用户创建', 'user:create', '创建管理员用户'), + ('用户更新', 'user:update', '更新管理员用户'), + ('用户删除', 'user:delete', '删除管理员用户'), + ('角色管理', 'role:read', '查看角色'), + ('角色创建', 'role:create', '创建角色'), + ('角色更新', 'role:update', '更新角色'), + ('角色删除', 'role:delete', '删除角色'), + ('权限管理', 'permission:read', '查看权限'), + ('权限创建', 'permission:create', '创建权限'), + ('权限更新', 'permission:update', '更新权限'), + ('权限删除', 'permission:delete', '删除权限'), + ('日志查看', 'log:read', '查看审计日志'), + ('会话管理', 'session:manage', '管理在线用户会话'), + ('平台数据', 'platform:read', '查看平台数据'), + ('平台管理', 'platform:manage', '管理平台数据') + ON CONFLICT (code) DO NOTHING + `); + + await query(` + INSERT INTO admin_role (name, description) VALUES + ('超级管理员', '拥有所有权限') + ON CONFLICT (name) DO NOTHING + `); + + await query(` + INSERT INTO admin_role_permission (role_id, permission_id) + SELECT r.id, p.id + FROM admin_role r + CROSS JOIN admin_permission p + WHERE r.name = '超级管理员' + ON CONFLICT DO NOTHING + `); + + console.log("[Health] Database tables ready"); +} + +export async function GET() { + try { + await ensureTables(); + return NextResponse.json({ status: "ok" }, { status: 200 }); + } catch (e) { + console.error("[Health] DB check failed:", e); + return NextResponse.json({ status: "error", reason: String(e) }, { status: 503 }); + } }