Swaps real-looking organisation domains in seed fixtures for the virkN.dk placeholder pattern, so demos and screenshots can't be misread as implying real-world relationships with the originals. - mette@ssi.dk → mette@virk1.dk - lars@rigspolitiet.dk → lars@virk2.dk - jonathan@fenja.ai → jonathan@studio.test (separate fake domain for the team account, kept distinct from the council virkN namespace) - anna@kommune.dk → anna@virk3.dk - soren@energinet.dk → soren@virk4.dk - henriette@dnv.dk → henriette@virk5.dk Organisation strings get the same treatment ('Virksomhed 1' …). Also fixes two latent bugs surfaced while re-seeding: - seed.js's INSERT didn't populate the slug column added in migration 0003. After a re-seed the three base users had NULL slugs. Add a kebab-from-name fallback in the INSERT so slugs round-trip. - seed.js's DELETE chain pre-dated the Phase 1/2 schema additions and failed FK constraints (pulses/dispatches/events/votes/activity/ join_requests/roadmap_attributions). Extend the wipe order so all user-referencing tables clear before users. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
150 lines
4.9 KiB
JavaScript
150 lines
4.9 KiB
JavaScript
#!/usr/bin/env node
|
|
import Database from 'better-sqlite3';
|
|
import bcrypt from 'bcryptjs';
|
|
import { join, dirname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const db = new Database(join(__dirname, '..', 'bifrost.db'));
|
|
db.pragma('journal_mode = WAL');
|
|
db.pragma('foreign_keys = ON');
|
|
|
|
// Verify schema exists
|
|
try {
|
|
db.prepare('SELECT id FROM users LIMIT 1').get();
|
|
} catch {
|
|
console.error('Error: database tables not found. Run `pnpm db:migrate` first.');
|
|
process.exit(1);
|
|
}
|
|
|
|
// Wipe existing seed data (idempotent). Order matters: every table that
|
|
// FK-references users (without ON DELETE CASCADE) must be cleared first.
|
|
db.exec(`
|
|
DELETE FROM activity;
|
|
DELETE FROM votes;
|
|
DELETE FROM dispatches;
|
|
DELETE FROM events;
|
|
DELETE FROM pulses;
|
|
DELETE FROM roadmap_attributions;
|
|
DELETE FROM reactions;
|
|
DELETE FROM replies;
|
|
DELETE FROM contributions;
|
|
DELETE FROM attendance;
|
|
DELETE FROM join_requests;
|
|
DELETE FROM invites;
|
|
DELETE FROM sessions;
|
|
DELETE FROM users;
|
|
`);
|
|
|
|
const ROUNDS = 10;
|
|
|
|
const users = [
|
|
{
|
|
email: 'mette@virk1.dk',
|
|
password: 'pilot123',
|
|
name: 'Mette Hansen',
|
|
organisation: 'Virksomhed 1',
|
|
role: 'pilot',
|
|
},
|
|
{
|
|
email: 'lars@virk2.dk',
|
|
password: 'cab123',
|
|
name: 'Lars Thomsen',
|
|
organisation: 'Virksomhed 2',
|
|
role: 'cab',
|
|
},
|
|
{
|
|
email: 'jonathan@studio.test',
|
|
password: 'fenja123',
|
|
name: 'Jonathan',
|
|
organisation: 'Fenja AI',
|
|
role: 'fenja',
|
|
},
|
|
];
|
|
|
|
const insertUser = db.prepare(`
|
|
INSERT INTO users (email, password_hash, name, organisation, role, bio, slug)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
`);
|
|
|
|
const userIds = {};
|
|
for (const u of users) {
|
|
const hash = bcrypt.hashSync(u.password, ROUNDS);
|
|
const slug = u.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
const result = insertUser.run(u.email, hash, u.name, u.organisation, u.role, '', slug);
|
|
userIds[u.role] = Number(result.lastInsertRowid);
|
|
console.log(` created user: ${u.name} (${u.role}) — password: ${u.password}`);
|
|
}
|
|
|
|
// Sample contributions
|
|
const insertContrib = db.prepare(`
|
|
INSERT INTO contributions (user_id, type, body_md, created_at)
|
|
VALUES (?, ?, ?, ?)
|
|
`);
|
|
|
|
const now = new Date();
|
|
const minus20 = new Date(now.getTime() - 20 * 60 * 1000).toISOString();
|
|
const minus2h = new Date(now.getTime() - 2 * 60 * 60 * 1000).toISOString();
|
|
const minus1d = new Date(now.getTime() - 24 * 60 * 60 * 1000).toISOString();
|
|
const minus3d = new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000).toISOString();
|
|
|
|
const c1 = insertContrib.run(
|
|
userIds['pilot'],
|
|
'idea',
|
|
'What if the system could **auto-summarise meetings** and link the summary back to the relevant roadmap item? Would save a lot of manual work after each CAB session.',
|
|
minus1d
|
|
);
|
|
const c2 = insertContrib.run(
|
|
userIds['cab'],
|
|
'question',
|
|
'How will the system handle documents in **multiple languages**? Most of our operational docs are in Danish, but some legal references are in English or German.',
|
|
minus2h
|
|
);
|
|
const c3 = insertContrib.run(
|
|
userIds['pilot'],
|
|
'inspiration',
|
|
'Came across this framing of knowledge management in regulated industries — the idea of an "institutional memory" that stays even when staff rotate. Feels very aligned with what Fenja is building.',
|
|
minus3d
|
|
);
|
|
const c4 = insertContrib.run(
|
|
userIds['fenja'],
|
|
'idea',
|
|
'Consider department-level access scoping for v1.1 — some organisations may want certain documents visible only to specific teams, even within the pilot group.',
|
|
minus20
|
|
);
|
|
|
|
// Reactions
|
|
const insertReaction = db.prepare(`
|
|
INSERT INTO reactions (user_id, contribution_id) VALUES (?, ?)
|
|
`);
|
|
insertReaction.run(userIds['cab'], c1.lastInsertRowid);
|
|
insertReaction.run(userIds['fenja'], c1.lastInsertRowid);
|
|
insertReaction.run(userIds['pilot'], c3.lastInsertRowid);
|
|
|
|
// Fenja reply on c1
|
|
db.prepare(`
|
|
INSERT INTO replies (contribution_id, user_id, body_md)
|
|
VALUES (?, ?, ?)
|
|
`).run(
|
|
c1.lastInsertRowid,
|
|
userIds['fenja'],
|
|
'Great idea — meeting summaries are on our Q3 roadmap. The link back to roadmap items is something we hadn\'t explicitly planned; adding it to the backlog now.'
|
|
);
|
|
|
|
// Sample attendance
|
|
const insertAttendance = db.prepare(`
|
|
INSERT OR REPLACE INTO attendance (user_id, meeting_slug, status, updated_at)
|
|
VALUES (?, ?, ?, datetime('now'))
|
|
`);
|
|
insertAttendance.run(userIds['pilot'], '2026-03-20-kickoff', 'yes');
|
|
insertAttendance.run(userIds['cab'], '2026-03-20-kickoff', 'yes');
|
|
insertAttendance.run(userIds['fenja'], '2026-03-20-kickoff', 'yes');
|
|
insertAttendance.run(userIds['pilot'], '2026-04-25-cab-q2-session', 'yes');
|
|
insertAttendance.run(userIds['cab'], '2026-04-25-cab-q2-session', 'no');
|
|
|
|
console.log('\n Seed complete.');
|
|
console.log('\n Test credentials:');
|
|
console.log(' mette@virk1.dk / pilot123 (pilot)');
|
|
console.log(' lars@virk2.dk / cab123 (cab)');
|
|
console.log(' jonathan@studio.test / fenja123 (fenja)');
|
|
db.close();
|