This repository has been archived on 2026-10-05. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
dnd-manager/backend/prisma/seed.js
T
joshuaandClaude Opus 5.5 94067f1268 V1.0.1: Aldenfell campaign seed, content library, party overview
- Seed now resets the database and seeds the Aldenfell campaign from the
  campaign book: admin DM user, default weapons, locations, bestiary,
  pre-built encounters, and DM/shared notes
- Default weapon/spell/monster library, character profile fields,
  locations and dice mode (new migration)
- Party overview page, pagination, info tips, build preview calc
- Remove stale demo-login hint; notes preserve line breaks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 10:24:48 +02:00

111 lines
3.8 KiB
JavaScript

// Resets the database and seeds the Aldenfell campaign (see
// docs/Aldenfell - Full Campaign Book.docx and seed-data/aldenfell.js).
//
// DESTRUCTIVE: every user, campaign, character, note, etc. is deleted first.
//
// Species/classes/skills are NOT seeded as rows — they're fixed game-rule
// tables ported into src/game/data/*.js, as is the default weapon/spell/monster
// library DMs pull from. The default weapons (seed-data/weapons.json) ARE
// seeded, into the campaign, since weapons are per-campaign in the schema.
const path = require('path');
const bcrypt = require('bcrypt');
const { PrismaClient } = require('@prisma/client');
const { generateInviteCode } = require('../src/utils/inviteCode');
const prisma = new PrismaClient();
const weapons = require(path.join(__dirname, '..', 'seed-data', 'weapons.json'));
const aldenfell = require(path.join(__dirname, '..', 'seed-data', 'aldenfell.js'));
const ADMIN_EMAIL = 'joshua@crosscode.co.za';
const ADMIN_PASSWORD = '12345678';
async function resetDatabase() {
// Truncating the two roots cascades through every table that references them.
await prisma.$executeRawUnsafe('TRUNCATE TABLE "users", "campaigns" RESTART IDENTITY CASCADE');
}
async function main() {
await resetDatabase();
const admin = await prisma.user.create({
data: {
email: ADMIN_EMAIL,
passwordHash: await bcrypt.hash(ADMIN_PASSWORD, 12),
displayName: 'Joshua',
},
});
const campaign = await prisma.campaign.create({
data: {
...aldenfell.campaign,
inviteCode: generateInviteCode(),
ownerId: admin.id,
members: { create: { userId: admin.id, role: 'DM' } },
},
});
await prisma.weapon.createMany({ data: weapons.map((w) => ({ ...w, campaignId: campaign.id })) });
await prisma.location.createMany({
data: aldenfell.locations.map((l) => ({ ...l, campaignId: campaign.id })),
});
const monsterByName = {};
for (const monster of aldenfell.monsters) {
const created = await prisma.monster.create({ data: { ...monster, campaignId: campaign.id } });
monsterByName[created.name] = created;
}
for (const enc of aldenfell.encounters) {
const participants = [];
for (const [name, count] of enc.monsters) {
const monster = monsterByName[name];
if (!monster) throw new Error(`Encounter "${enc.name}" references unknown monster "${name}"`);
for (let i = 1; i <= count; i++) {
participants.push({
monsterId: monster.id,
displayName: count > 1 ? `${monster.name} #${i}` : monster.name,
currentHp: monster.maxHp,
maxHp: monster.maxHp,
isMonster: true,
});
}
}
await prisma.encounter.create({
data: { campaignId: campaign.id, name: enc.name, participants: { create: participants } },
});
}
// Notes list newest-first, so stamp them in reverse to keep book order on screen.
const allNotes = [
...aldenfell.sharedNotes.map((body) => ({ body, visibility: 'SHARED' })),
...aldenfell.dmNotes.map((body) => ({ body, visibility: 'DM_ONLY' })),
];
const now = Date.now();
await prisma.note.createMany({
data: allNotes.map((n, i) => ({
...n,
campaignId: campaign.id,
authorId: admin.id,
createdAt: new Date(now - i * 1000),
})),
});
console.log('Seed complete.');
console.log(` Admin/DM login: ${ADMIN_EMAIL} / ${ADMIN_PASSWORD}`);
console.log(` Campaign: ${campaign.name} — invite code ${campaign.inviteCode}`);
console.log(
` ${weapons.length} weapons, ${aldenfell.locations.length} locations, ${aldenfell.monsters.length} monsters, ` +
`${aldenfell.encounters.length} encounters, ${allNotes.length} notes`,
);
}
main()
.catch((err) => {
console.error(err);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});