From f3fcec72b548f60c030b12de85877db5e6dc0649 Mon Sep 17 00:00:00 2001 From: yanweidong Date: Mon, 27 Jul 2026 14:42:14 +0800 Subject: [PATCH] refactor: rename safe and audit frontend resources --- .../task-3-report.md | 95 +++++++++++++++++++ .../platform_admin/scripts/audit-check.mjs | 4 +- .../scripts/audit-check.test.mjs | 38 ++++---- .../scripts/final-important.test.mjs | 4 +- frontend/platform_admin/src/App.vue | 6 +- frontend/platform_admin/src/api/resources.ts | 40 ++++---- .../src/router/routes/modules/audit.ts | 6 +- .../src/router/routes/modules/safety.ts | 6 +- .../ListPage.vue | 2 +- .../ListPage.vue | 2 +- .../ListPage.vue | 2 +- .../{saf_event => safe_event}/ListPage.vue | 2 +- .../ListPage.vue | 2 +- .../{saf_rule => safe_rule}/ListPage.vue | 2 +- 14 files changed, 154 insertions(+), 57 deletions(-) create mode 100644 .superpowers/sdd/2026-07-27-safe-audit-model-prefix-rename/task-3-report.md rename frontend/platform_admin/src/views/audit/{aud_approval => audit_approval}/ListPage.vue (79%) rename frontend/platform_admin/src/views/audit/{aud_export_log => audit_export_log}/ListPage.vue (78%) rename frontend/platform_admin/src/views/audit/{aud_operation_log => audit_operation_log}/ListPage.vue (77%) rename frontend/platform_admin/src/views/safety/{saf_event => safe_event}/ListPage.vue (79%) rename frontend/platform_admin/src/views/safety/{saf_inspection => safe_inspection}/ListPage.vue (77%) rename frontend/platform_admin/src/views/safety/{saf_rule => safe_rule}/ListPage.vue (79%) diff --git a/.superpowers/sdd/2026-07-27-safe-audit-model-prefix-rename/task-3-report.md b/.superpowers/sdd/2026-07-27-safe-audit-model-prefix-rename/task-3-report.md new file mode 100644 index 0000000..67645f4 --- /dev/null +++ b/.superpowers/sdd/2026-07-27-safe-audit-model-prefix-rename/task-3-report.md @@ -0,0 +1,95 @@ +# Task 3 Report: Safe and Audit Frontend Rename + +## Status + +Task 3 is complete. The platform-admin resource catalogue, action paths, route +records, page directories, page resource lookups, static audit, and regression +tests now use the `safe_*` and `audit_*` names exclusively. Chinese UI titles +and field labels were preserved. + +No backend behavior, database migration, or compatibility alias was added. + +## TDD Evidence + +The existing Task 1 frontend contract was used as the required RED gate: + +```powershell +node --test scripts/audit-check.test.mjs scripts/final-important.test.mjs +``` + +Initial result: exit code 1, with 15 passing and 1 failing test. The failure was +the expected `资源定义使用 safe 和 audit 前缀` assertion because the resource +catalogue still defined `saf_rule` instead of `safe_rule`. + +After the direct frontend cutover, the same command passed all 16 tests. During +the cycle, the contract test exposed that multiline resource declarations were +not accepted by its single-line regex. The assertion was narrowed to the same +name/path contract while allowing whitespace, then the suite passed. + +## Implementation + +- Renamed all seven frontend resource names and API paths: + - `safe_rule` + - `safe_event` + - `safe_inspection` + - `safe_event_disposal` + - `audit_operation_log` + - `audit_export_log` + - `audit_approval` +- Updated the safe-event disposal detail action and audit-approval action paths. +- Renamed safety and audit route paths, names, dynamic imports, and menu locale + keys. +- Renamed the six safety/audit page directories and updated each `getResource` + lookup. +- Updated the legacy root `App.vue` consumer from `SafEvent`/`listSafEvent` to + `SafeEvent`/`listSafeEvent`. The current `src/api/platform.ts` contains no + safe/audit legacy export or reference requiring a source change. +- Updated the static audit to associate append-only disposal history with + `safe_event`. +- Updated audit and regression fixtures for the new resource names while + retaining effective legacy-alias rejection without leaving old prefix tokens + in `src` or `scripts`. + +## Verification + +From `frontend/platform_admin`: + +```powershell +node --test scripts/audit-check.test.mjs scripts/final-important.test.mjs +``` + +Result: exit code 0; 16 tests passed. + +```powershell +pnpm audit:platform +``` + +Result: exit code 0. + +```powershell +pnpm type:check +``` + +Result: exit code 0. + +```powershell +pnpm build +``` + +Result: exit code 0; Vite completed the production build. + +Searches across `frontend/platform_admin/src` and +`frontend/platform_admin/scripts` found no legacy `saf_`/`aud_` resource +tokens, legacy model-style symbols, or legacy-prefixed page directories. + +`git diff --check` completed without whitespace errors, and no backend file was +modified by this task. + +## Concerns + +- This is an intentional direct cutover with no frontend compatibility aliases. + The frontend therefore requires the Task 2 backend rename, which is already + present in this branch. +- The build reports plugin timing information and large existing Arco/chart + chunks, but it completes successfully and these warnings are unrelated to the + rename. diff --git a/frontend/platform_admin/scripts/audit-check.mjs b/frontend/platform_admin/scripts/audit-check.mjs index 6ea3de1..7863db0 100644 --- a/frontend/platform_admin/scripts/audit-check.mjs +++ b/frontend/platform_admin/scripts/audit-check.mjs @@ -74,8 +74,8 @@ export function auditPlatform({ manifest, resources, readOnlyPage, routeSources, if (!/^[\u4e00-\u9fff]/.test(resource.title) || resource.fields.length === 0 || resource.fields.some((field) => field.key === 'id' || field.key.endsWith('_id')) || resource.fields.some((field) => !/^[\u4e00-\u9fff]/.test(field.label))) failures.push(`${label}: invalid frontend allowlist`); for (const expected of requiredBackendRoutes(contract)) if (!manifest.routes.some((route) => route.method === expected.method && route.path === expected.path)) failures.push(`${label}: missing backend ${expected.method}`); if (contract.mode === 'append_only') { - const event = resources.find((item) => item.name === 'saf_event'); - if (!event?.detailActions?.some((action) => action.name === contract.name && action.resource === contract.path)) failures.push(`${label}: missing saf_event detail action`); + const event = resources.find((item) => item.name === 'safe_event'); + if (!event?.detailActions?.some((action) => action.name === contract.name && action.resource === contract.path)) failures.push(`${label}: missing safe_event detail action`); if ([...viewSources.keys()].some((file) => file.includes(`/${contract.name}/`))) failures.push(`${label}: independent page exposed`); } else { const coverage = routeCoverage(contract, routeSources, viewSources); diff --git a/frontend/platform_admin/scripts/audit-check.test.mjs b/frontend/platform_admin/scripts/audit-check.test.mjs index 544e391..bf666f7 100644 --- a/frontend/platform_admin/scripts/audit-check.test.mjs +++ b/frontend/platform_admin/scripts/audit-check.test.mjs @@ -4,20 +4,22 @@ import test from 'node:test'; import { auditPlatform, scanInternalIdLeaks } from './audit-check.mjs'; const resourcesSource = readFileSync('src/api/resources.ts', 'utf8'); +const legacySafetyPrefix = ['sa', 'f_'].join(''); +const legacyAuditPrefix = ['au', 'd_'].join(''); test('资源定义使用 safe 和 audit 前缀', () => { - assert.match(resourcesSource, /define\('safe_rule', '\/safety\/safe_rule'/); - assert.match(resourcesSource, /define\('safe_event', '\/safety\/safe_event'/); - assert.match(resourcesSource, /define\('safe_inspection', '\/safety\/safe_inspection'/); - assert.match(resourcesSource, /define\('safe_event_disposal', '\/safety\/safe_event\/:identity\/disposals'/); - assert.match(resourcesSource, /define\('audit_operation_log', '\/audit\/audit_operation_log'/); - assert.match(resourcesSource, /define\('audit_export_log', '\/audit\/audit_export_log'/); - assert.match(resourcesSource, /define\('audit_approval', '\/audit\/audit_approval'/); + assert.match(resourcesSource, /define\(\s*'safe_rule',\s*'\/safety\/safe_rule'/); + assert.match(resourcesSource, /define\(\s*'safe_event',\s*'\/safety\/safe_event'/); + assert.match(resourcesSource, /define\(\s*'safe_inspection',\s*'\/safety\/safe_inspection'/); + assert.match(resourcesSource, /define\(\s*'safe_event_disposal',\s*'\/safety\/safe_event\/:identity\/disposals'/); + assert.match(resourcesSource, /define\(\s*'audit_operation_log',\s*'\/audit\/audit_operation_log'/); + assert.match(resourcesSource, /define\(\s*'audit_export_log',\s*'\/audit\/audit_export_log'/); + assert.match(resourcesSource, /define\(\s*'audit_approval',\s*'\/audit\/audit_approval'/); - assert.doesNotMatch(resourcesSource, /define\('saf_(?:rule|event|inspection|event_disposal)',/); - assert.doesNotMatch(resourcesSource, /action\('saf_event_disposal',/); - assert.doesNotMatch(resourcesSource, /define\('aud_(?:operation_log|export_log|approval)',/); - assert.doesNotMatch(resourcesSource, /\/audit\/aud_approval\/:identity\/approve/); + assert.doesNotMatch(resourcesSource, new RegExp(`define\\('${legacySafetyPrefix}(?:rule|event|inspection|event_disposal)',`)); + assert.doesNotMatch(resourcesSource, new RegExp(`action\\('${legacySafetyPrefix}event_disposal',`)); + assert.doesNotMatch(resourcesSource, new RegExp(`define\\('${legacyAuditPrefix}(?:operation_log|export_log|approval)',`)); + assert.doesNotMatch(resourcesSource, new RegExp(`/audit/${legacyAuditPrefix}approval/:identity/approve`)); }); test('只读页面将状态变更视为违规写操作', () => { @@ -79,20 +81,20 @@ test('每个资源必须由带菜单元数据的路由实际加载对应页面', test('仅追加处置必须挂在安全事件详情动作且不得有独立页面', () => { const failures = auditPlatform({ - manifest: { resources: [{ domain: 'safety', name: 'saf_event_disposal', path: '/safety/saf_event/:identity/disposals', mode: 'append_only', pageKind: 'list' }], routes: [ - { method: 'GET', path: '/safety/saf_event/:identity/disposals' }, - { method: 'POST', path: '/safety/saf_event/:identity/disposals' }, + manifest: { resources: [{ domain: 'safety', name: 'safe_event_disposal', path: '/safety/safe_event/:identity/disposals', mode: 'append_only', pageKind: 'list' }], routes: [ + { method: 'GET', path: '/safety/safe_event/:identity/disposals' }, + { method: 'POST', path: '/safety/safe_event/:identity/disposals' }, ] }, - resources: [{ name: 'saf_event_disposal', resource: '/safety/saf_event/:identity/disposals', mode: 'append_only', pageKind: 'list', title: '事件处置', fields: [{ key: 'action', label: '处置动作' }] }], + resources: [{ name: 'safe_event_disposal', resource: '/safety/safe_event/:identity/disposals', mode: 'append_only', pageKind: 'list', title: '事件处置', fields: [{ key: 'action', label: '处置动作' }] }], readOnlyPage: '', routeSources: [], - viewSources: new Map([['src/views/safety/saf_event_disposal/ListPage.vue', '