feat(ops): 每日数据库备份 + 资金异常巡检告警 + 后台操作审计
- 新增 system_alerts/admin_audit_logs 表与 (status,created_at) 索引;启动即巡检、每 5 分钟扫描提现卡单/支付与订单不一致/待接单超时 - 后台新增「系统告警与操作审计」页(告警处理 + 审计列表),并接入消息铃铛待办 - 余额调整/封禁/删除/大神审核/提现打款/告警处理等敏感操作写入审计日志(含 IP) - 新增 server/scripts/backup-db.sh 并已在生产配置每日 03:30 cron(校验+保留 14 天) - 清理空的 order_messages 表;115 套件/750 用例全绿;线上实测告警接口/审计落库/备份均通过
这个提交包含在:
@@ -0,0 +1,56 @@
|
||||
// 已读取AGENTS.md
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
/**
|
||||
* 第一百批:资金巡检告警 + 后台操作审计 + 每日备份。
|
||||
*/
|
||||
describe('第一百批系统告警与后台审计', () => {
|
||||
const root = path.resolve(__dirname, '../../');
|
||||
const read = (rel: string) => fs.readFileSync(path.join(root, rel), 'utf-8');
|
||||
|
||||
const mysql = read('server/src/db/mysql.ts');
|
||||
const repo = read('server/src/db/repository.ts');
|
||||
const indexCode = read('server/src/index.ts');
|
||||
const adminPage = read('admin/arco-design-pro-vite/src/views/safety/system-alerts/index.vue');
|
||||
const safetyRoute = read('admin/arco-design-pro-vite/src/router/routes/modules/safety.ts');
|
||||
const zhLocale = read('admin/arco-design-pro-vite/src/locale/zh-CN.ts');
|
||||
const backupScript = read('server/scripts/backup-db.sh');
|
||||
|
||||
it('告警与审计表必须落库,并补充巡检所需索引', () => {
|
||||
expect(mysql).toContain('CREATE TABLE IF NOT EXISTS system_alerts');
|
||||
expect(mysql).toContain('CREATE TABLE IF NOT EXISTS admin_audit_logs');
|
||||
expect(mysql).toContain("['withdrawals', 'idx_wd_status_created'");
|
||||
expect(mysql).toContain("['payment_intents', 'idx_pi_status_created'");
|
||||
});
|
||||
|
||||
it('巡检必须覆盖提现卡单、支付与订单不一致、待接单超时', () => {
|
||||
expect(indexCode).toContain('runSystemAlertScan');
|
||||
expect(indexCode).toContain('提现打款卡在「处理中」');
|
||||
expect(indexCode).toContain('支付已成功但订单仍为待付款');
|
||||
expect(indexCode).toContain('待接单订单超时未退款');
|
||||
expect(indexCode).toContain('startSystemAlertScheduler');
|
||||
});
|
||||
|
||||
it('敏感后台操作必须写审计日志', () => {
|
||||
expect(repo).toContain('async createAdminAuditLog');
|
||||
expect(indexCode).toContain('function logAdminAudit');
|
||||
const actions = ['余额充值', '封禁用户', '删除用户', '通过大神入驻', '提现打款'];
|
||||
for (const a of actions) expect(indexCode).toContain(a);
|
||||
});
|
||||
|
||||
it('后台必须提供告警/审计查询与处理入口', () => {
|
||||
expect(indexCode).toContain("app.get('/api/admin/system/alerts'");
|
||||
expect(indexCode).toContain("app.get('/api/admin/audit-logs'");
|
||||
expect(safetyRoute).toContain("path: 'system-alerts'");
|
||||
expect(zhLocale).toContain('menu.safety.systemAlerts');
|
||||
expect(adminPage).toContain('/api/admin/system/alerts');
|
||||
expect(adminPage).toContain('/api/admin/audit-logs');
|
||||
});
|
||||
|
||||
it('每日备份脚本必须校验压缩包并保留 14 天', () => {
|
||||
expect(backupScript).toContain('mysqldump --single-transaction --quick --no-tablespaces');
|
||||
expect(backupScript).toContain('gzip -t');
|
||||
expect(backupScript).toContain("-mtime +14 -delete");
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户