import fs from 'node:fs' import path from 'node:path' const root = process.cwd() const errors = [] 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 moduleFiles = walk(path.join(root, 'apps/web/src/modules')).filter(f => /\.(ts|vue)$/.test(f)) for (const file of moduleFiles) { const text = fs.readFileSync(file, 'utf8') if (/from\s+['\"]primevue\//.test(text) || /from\s+['\"]ag-grid-(vue3|community)/.test(text)) { errors.push(`${path.relative(root,file)}: business module imports PrimeVue/AG Grid directly`) } } const manifestFile = path.join(root, 'generated/screen-manifest.json') if (!fs.existsSync(manifestFile)) errors.push('generated/screen-manifest.json is missing') else { const manifest = JSON.parse(fs.readFileSync(manifestFile, 'utf8')) const ids = new Map() for (const screen of manifest) { if (ids.has(screen.id)) errors.push(`duplicate screen id ${screen.id}: ${ids.get(screen.id)} / ${screen.source}`) ids.set(screen.id, screen.source) if (!/^((OMS|ERP|WMS|COMMON)-[A-Z0-9-]+)$/.test(screen.id)) errors.push(`invalid screen id: ${screen.id}`) if (screen.version === 'unknown' || screen.type === 'unknown') errors.push(`incomplete screen definition: ${screen.id}`) } } const migrations = walk(path.join(root, 'backend/Database/Migrations')).filter(f => f.endsWith('.sql')).map(f => path.basename(f)) const sorted = [...migrations].sort() if (migrations.join('|') !== sorted.join('|')) errors.push('migration files are not lexicographically ordered') if (errors.length) { console.error('KBX architecture validation failed:') for (const error of errors) console.error(`- ${error}`) process.exit(1) } console.log(`KBX architecture validation passed (${moduleFiles.length} module source files, ${migrations.length} migrations).`)