refactor(stage8): 建表语句集中到 server/db/schema,并修复只读模式的漏写
问题
- 4 处运行时 DDL(scheduling / ele / feedback / mileage 日报)分散在路由与 store 里;
- 只读保护只按 HTTP 方法拦截,而建表由 GET 处理器触发,
于是 DB_READ_ONLY=1 的"只读预览"仍可能执行 CREATE TABLE / ALTER TABLE(已记录在案的漏洞)。
改动
- 新增 src/server/db/schema/{guard,scheduling,ele,feedback,mileage-report}.ts:
建表/改表的唯一位置;guard 提供 ddlAllowed(),DB_READ_ONLY=1 时每个 ensure* 直接跳过并打印一行日志。
- daily-report-store 的表名改为从 schema 模块导出,避免两处各写一份表名。
- 移除 feedback/index.ts 与 ele/migration.ts 中的内联 DDL。
验证
- 实测:DB_READ_ONLY=1 下依次调用 4 个 ensure*,全部跳过且未触碰数据库(无连接错误/挂起)。
- 架构测试新增 2 条:DDL 只允许出现在 server/db/schema;每个 schema 模块必须检查 ddlAllowed()。
lint / test(139) / build 全绿。
This commit is contained in:
@@ -4,7 +4,7 @@ import * as XLSX from 'xlsx';
|
||||
import pool from '../../db/mysql.js';
|
||||
import type { AuthUser } from '../../auth/types.js';
|
||||
import { canAccessEnergy } from '../../auth/types.js';
|
||||
import { ensureChargeRecordTable } from './migration.js';
|
||||
import { ensureChargeRecordTable } from '../../db/schema/ele.js';
|
||||
|
||||
const app = new Hono();
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import pool from '../../db/mysql.js';
|
||||
|
||||
const CREATE_TABLE_SQL = `
|
||||
CREATE TABLE IF NOT EXISTS bi_ele_charge_record (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
order_no VARCHAR(64) NOT NULL,
|
||||
station_no VARCHAR(64) NULL,
|
||||
station_name VARCHAR(128) NULL,
|
||||
terminal_name VARCHAR(64) NULL,
|
||||
region VARCHAR(64) NULL,
|
||||
city VARCHAR(64) NULL,
|
||||
district VARCHAR(64) NULL,
|
||||
operating_company VARCHAR(128) NULL,
|
||||
station_type VARCHAR(32) NULL,
|
||||
order_status VARCHAR(32) NULL,
|
||||
charge_form VARCHAR(32) NULL,
|
||||
start_time DATETIME NULL,
|
||||
end_time DATETIME NULL,
|
||||
duration_min INT NULL,
|
||||
kwh DECIMAL(10,3) NULL,
|
||||
e_fee DECIMAL(10,2) NULL,
|
||||
service_fee DECIMAL(10,2) NULL,
|
||||
fee DECIMAL(10,2) NULL,
|
||||
plate VARCHAR(32) NULL,
|
||||
judged_plate VARCHAR(32) NULL,
|
||||
vin VARCHAR(64) NULL,
|
||||
customer_name VARCHAR(128) NULL,
|
||||
customer_phone VARCHAR(32) NULL,
|
||||
enterprise_name VARCHAR(128) NULL,
|
||||
matched_truck_id VARCHAR(32) NULL,
|
||||
matched_plate VARCHAR(32) NULL,
|
||||
vehicle_kind ENUM('internal','external','unknown') NOT NULL DEFAULT 'unknown',
|
||||
raw_json JSON NULL,
|
||||
batch_id VARCHAR(64) NOT NULL,
|
||||
imported_at DATETIME NOT NULL,
|
||||
UNIQUE KEY uk_order_no (order_no),
|
||||
KEY idx_start_time (start_time),
|
||||
KEY idx_batch (batch_id),
|
||||
KEY idx_kind (vehicle_kind),
|
||||
KEY idx_plate (plate)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
`;
|
||||
|
||||
let ensured = false;
|
||||
export async function ensureChargeRecordTable(): Promise<void> {
|
||||
if (ensured) return;
|
||||
await pool.query(CREATE_TABLE_SQL);
|
||||
ensured = true;
|
||||
}
|
||||
Reference in New Issue
Block a user