feat: production-harden app and finalize merge-ready UX/theme baseline

- complete tokenized theme preset system and admin style guide visibility
- refine dashboard layout/scroll behavior and shared async/request UI states
- add user nav-visibility settings across API, migration, and frontend stores
- harden security headers/CSP handling and related test coverage
- enforce CI repository hygiene + frontend contract/theme/build quality gates
- update docs/env references and make migration smoke test head-aware
This commit is contained in:
Justin Visser 2026-02-19 15:43:20 +01:00
parent ab1d29b203
commit ae2ca8f149
66 changed files with 5655 additions and 853 deletions

View file

@ -0,0 +1,84 @@
import fs from "node:fs";
import path from "node:path";
const projectRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..");
const sourceRoot = path.join(projectRoot, "src");
const allowedExtensions = new Set([".vue", ".css"]);
const checks = [
{
name: "non-token palette utility",
regex: /\b(?:bg|text|border|ring|from|to|via)-(?:zinc|gray|slate|neutral|stone|white|black)(?:[-/][A-Za-z0-9_\-[\]./%]+)?\b/g,
},
{
name: "dark mode utility variant",
regex: /\bdark:[^\s"'`<>}]*/g,
},
{
name: "inline hex color",
regex: /#[0-9a-fA-F]{3,8}\b/g,
},
];
function listFilesRecursively(dirPath) {
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const nextPath = path.join(dirPath, entry.name);
if (entry.isDirectory()) {
files.push(...listFilesRecursively(nextPath));
continue;
}
if (allowedExtensions.has(path.extname(nextPath))) {
files.push(nextPath);
}
}
return files;
}
function relativePath(filePath) {
return path.relative(projectRoot, filePath).replaceAll(path.sep, "/");
}
function run() {
const violations = [];
const files = listFilesRecursively(sourceRoot);
for (const filePath of files) {
const content = fs.readFileSync(filePath, "utf8");
const lines = content.split(/\r?\n/);
for (let index = 0; index < lines.length; index += 1) {
const line = lines[index];
for (const check of checks) {
check.regex.lastIndex = 0;
let match = check.regex.exec(line);
while (match) {
violations.push({
filePath: relativePath(filePath),
line: index + 1,
check: check.name,
value: match[0],
});
match = check.regex.exec(line);
}
}
}
}
if (violations.length > 0) {
console.error("Theme token policy violations found:\n");
for (const violation of violations) {
console.error(`${violation.filePath}:${violation.line} [${violation.check}] ${violation.value}`);
}
process.exit(1);
}
console.log(`Theme token policy passed for ${files.length} files.`);
}
run();