46 lines
2.2 KiB
JavaScript
46 lines
2.2 KiB
JavaScript
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
|
|
const root = process.cwd()
|
|
const errors = []
|
|
const manifest = JSON.parse(fs.readFileSync(path.join(root, 'generated/screen-manifest.json'), 'utf8'))
|
|
for (const required of ['COMMON-OPS-001', 'COMMON-REC-001']) {
|
|
if (!manifest.some(x => x.id === required)) errors.push(`missing required operations screen ${required}`)
|
|
}
|
|
|
|
const migration = fs.readFileSync(path.join(root, 'backend/Database/Migrations/20260808_005_kbx_operations_reconcile.sql'), 'utf8')
|
|
for (const token of ['kbx.work_items', 'kbx.work_item_audit', 'kbx.reconcile_items', 'identity_key', 'reference_no', 'source_screen_id', 'source_version']) {
|
|
if (!migration.includes(token)) errors.push(`operations migration missing ${token}`)
|
|
}
|
|
|
|
function walk(dir) {
|
|
if (!fs.existsSync(dir)) return []
|
|
return fs.readdirSync(dir, { withFileTypes: true }).flatMap(entry => {
|
|
const full = path.join(dir, entry.name)
|
|
return entry.isDirectory() ? walk(full) : [full]
|
|
})
|
|
}
|
|
|
|
const operationalBackend = [
|
|
...walk(path.join(root, 'backend/Modules/Common/Operations')),
|
|
...walk(path.join(root, 'backend/Modules/Common/Reconcile')),
|
|
].filter(x => x.endsWith('.cs'))
|
|
|
|
const forbiddenDomainWrite = /\b(?:update|insert\s+into|delete\s+from)\s+(?:oms_|wms_|erp_)/i
|
|
for (const file of operationalBackend) {
|
|
const text = fs.readFileSync(file, 'utf8')
|
|
if (forbiddenDomainWrite.test(text)) errors.push(`${path.relative(root, file)} writes a source-module table directly`)
|
|
}
|
|
|
|
const projection = fs.readFileSync(path.join(root, 'backend/Shared/Operations/OperationsProjectionWriter.cs'), 'utf8')
|
|
if (!projection.includes('source_version')) errors.push('work-item projection lacks source_version out-of-order protection')
|
|
const reconcile = fs.readFileSync(path.join(root, 'backend/Shared/Operations/ReconcileProjectionWriter.cs'), 'utf8')
|
|
if (!reconcile.includes('excluded.occurred_at >= kbx.reconcile_items.occurred_at')) errors.push('reconcile projection lacks stale-observation protection')
|
|
|
|
if (errors.length) {
|
|
console.error('KBX operations validation failed:')
|
|
for (const error of errors) console.error(`- ${error}`)
|
|
process.exit(1)
|
|
}
|
|
console.log(`KBX operations validation passed (${operationalBackend.length} operational backend files).`)
|