135 Zeilen
4.1 KiB
JavaScript
135 Zeilen
4.1 KiB
JavaScript
// Seed controlled vocabulary (categories/subcategories) and skills
|
||
// from shared/skills.js (SKILL_HIERARCHY) into the local SQLite DB.
|
||
//
|
||
// Usage:
|
||
// cd backend
|
||
// node scripts/seed-skills-from-shared.js
|
||
//
|
||
// Optionally set DATABASE_PATH to seed a custom DB file.
|
||
|
||
const path = require('path')
|
||
const fs = require('fs')
|
||
const crypto = require('crypto')
|
||
const Database = require('better-sqlite3')
|
||
|
||
function getDbPath() {
|
||
if (process.env.DATABASE_PATH && process.env.DATABASE_PATH.length > 0) {
|
||
return process.env.DATABASE_PATH
|
||
}
|
||
// default dev DB in backend folder
|
||
return path.join(__dirname, '..', 'skillmate.dev.encrypted.db')
|
||
}
|
||
|
||
function ensureTables(db) {
|
||
// controlled_vocabulary (canonical definition from secureDatabase)
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS controlled_vocabulary (
|
||
id TEXT PRIMARY KEY,
|
||
category TEXT NOT NULL,
|
||
value TEXT NOT NULL,
|
||
description TEXT,
|
||
is_active INTEGER DEFAULT 1,
|
||
created_at TEXT NOT NULL,
|
||
UNIQUE(category, value)
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_vocab_category ON controlled_vocabulary(category);
|
||
CREATE INDEX IF NOT EXISTS idx_vocab_value ON controlled_vocabulary(value);
|
||
`)
|
||
|
||
// skills (canonical definition from secureDatabase)
|
||
db.exec(`
|
||
CREATE TABLE IF NOT EXISTS skills (
|
||
id TEXT PRIMARY KEY,
|
||
name TEXT NOT NULL,
|
||
category TEXT NOT NULL,
|
||
description TEXT,
|
||
requires_certification INTEGER DEFAULT 0,
|
||
expires_after INTEGER
|
||
)
|
||
`)
|
||
}
|
||
|
||
function loadHierarchy() {
|
||
// Load from shared/skills.js
|
||
const skillsPath = path.join(__dirname, '..', '..', 'shared', 'skills.js')
|
||
if (!fs.existsSync(skillsPath)) {
|
||
throw new Error('shared/skills.js not found')
|
||
}
|
||
const mod = require(skillsPath)
|
||
if (!mod || !Array.isArray(mod.SKILL_HIERARCHY)) {
|
||
throw new Error('SKILL_HIERARCHY missing or invalid in shared/skills.js')
|
||
}
|
||
return mod.SKILL_HIERARCHY
|
||
}
|
||
|
||
function seed(db, hierarchy) {
|
||
const now = new Date().toISOString()
|
||
|
||
const insertVocab = db.prepare(`
|
||
INSERT OR IGNORE INTO controlled_vocabulary (id, category, value, description, is_active, created_at)
|
||
VALUES (?, ?, ?, ?, ?, ?)
|
||
`)
|
||
|
||
const insertSkill = db.prepare(`
|
||
INSERT OR IGNORE INTO skills (id, name, category, description, requires_certification, expires_after)
|
||
VALUES (?, ?, ?, ?, ?, ?)
|
||
`)
|
||
|
||
let catCount = 0
|
||
let subCount = 0
|
||
let skillCount = 0
|
||
|
||
for (const cat of hierarchy) {
|
||
const catId = String(cat.id)
|
||
const catName = String(cat.name || cat.id)
|
||
|
||
// category
|
||
const catPk = crypto.randomUUID()
|
||
const catRes = insertVocab.run(catPk, 'skill_category', catId, catName, 1, now)
|
||
if (catRes.changes > 0) catCount++
|
||
|
||
for (const sub of (cat.subcategories || [])) {
|
||
const subId = String(sub.id)
|
||
const subName = String(sub.name || sub.id)
|
||
const key = `${catId}.${subId}`
|
||
|
||
// subcategory
|
||
const subPk = crypto.randomUUID()
|
||
const subRes = insertVocab.run(subPk, 'skill_subcategory', key, subName, 1, now)
|
||
if (subRes.changes > 0) subCount++
|
||
|
||
for (const sk of (sub.skills || [])) {
|
||
const sId = `${key}.${sk.id}`
|
||
const sName = String(sk.name || sk.id)
|
||
const requires = (catId === 'certifications' || subId === 'weapons') ? 1 : 0
|
||
const expires = (catId === 'certifications') ? 36 : null
|
||
const sRes = insertSkill.run(sId, sName, key, null, requires, expires)
|
||
if (sRes.changes > 0) skillCount++
|
||
}
|
||
}
|
||
}
|
||
|
||
return { catCount, subCount, skillCount }
|
||
}
|
||
|
||
function main() {
|
||
const dbPath = getDbPath()
|
||
console.log('➡️ Seeding skills into DB:', dbPath)
|
||
const db = new Database(dbPath)
|
||
try {
|
||
ensureTables(db)
|
||
const hierarchy = loadHierarchy()
|
||
const { catCount, subCount, skillCount } = seed(db, hierarchy)
|
||
console.log(`✅ Seeding completed. Inserted: ${catCount} categories, ${subCount} subcategories, ${skillCount} skills.`)
|
||
console.log('ℹ️ Re-open the Admin Panel to see Skills in hierarchy view.')
|
||
} catch (err) {
|
||
console.error('❌ Seeding failed:', err.message)
|
||
process.exitCode = 1
|
||
} finally {
|
||
try { db.close() } catch {}
|
||
}
|
||
}
|
||
|
||
main()
|
||
|