feat: update environment configuration and seed admin user in database
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "debian-openssl-3.0.x"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
|
||||
@@ -1,433 +1,27 @@
|
||||
import 'dotenv/config';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import bcrypt from 'bcryptjs';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('Seeding database…');
|
||||
const username = process.env.ADMIN_USERNAME;
|
||||
const email = process.env.ADMIN_EMAIL;
|
||||
const password = process.env.ADMIN_PASSWORD;
|
||||
|
||||
// ── Users ──────────────────────────────────────────────────────────────────
|
||||
|
||||
const password = await bcrypt.hash('password123', 10);
|
||||
|
||||
const u1 = await prisma.user.upsert({
|
||||
where: { email: 'kestrel@crowmate.dev' },
|
||||
update: {},
|
||||
create: { id: 'u1', username: 'Kestrel', email: 'kestrel@crowmate.dev', password, role: 'dev', isAdmin: true, createdAt: new Date('2023-09-01T08:00:00Z') },
|
||||
});
|
||||
const u2 = await prisma.user.upsert({
|
||||
where: { email: 'vesper@crowmate.dev' },
|
||||
update: {},
|
||||
create: { id: 'u2', username: 'Vesper', email: 'vesper@crowmate.dev', password, role: 'com', isAdmin: false, createdAt: new Date('2023-09-03T10:00:00Z') },
|
||||
});
|
||||
const u3 = await prisma.user.upsert({
|
||||
where: { email: 'glitch@mail.com' },
|
||||
update: {},
|
||||
create: { id: 'u3', username: 'GlitchHunter', email: 'glitch@mail.com', password, role: 'user', createdAt: new Date('2024-01-15T14:22:00Z') },
|
||||
});
|
||||
const u4 = await prisma.user.upsert({
|
||||
where: { email: 'null@mail.com' },
|
||||
update: {},
|
||||
create: { id: 'u4', username: 'NullPointer', email: 'null@mail.com', password, role: 'user', createdAt: new Date('2024-02-20T09:11:00Z') },
|
||||
});
|
||||
const u5 = await prisma.user.upsert({
|
||||
where: { email: 'xeno@mail.com' },
|
||||
update: {},
|
||||
create: { id: 'u5', username: 'XenoArch', email: 'xeno@mail.com', password, role: 'user', createdAt: new Date('2024-03-05T16:44:00Z') },
|
||||
});
|
||||
await prisma.user.upsert({
|
||||
where: { email: 'phantom@mail.com' },
|
||||
update: {},
|
||||
create: { id: 'u6', username: 'Phantom404', email: 'phantom@mail.com', password, role: 'user', isBanned: true, createdAt: new Date('2024-04-12T12:00:00Z') },
|
||||
});
|
||||
const u7 = await prisma.user.upsert({
|
||||
where: { email: 'neon@mail.com' },
|
||||
update: {},
|
||||
create: { id: 'u7', username: 'NeonCrawler', email: 'neon@mail.com', password, role: 'user', createdAt: new Date('2024-05-01T08:30:00Z') },
|
||||
});
|
||||
const u8 = await prisma.user.upsert({
|
||||
where: { email: 'byte@mail.com' },
|
||||
update: {},
|
||||
create: { id: 'u8', username: 'ByteWitch', email: 'byte@mail.com', password, role: 'dev', createdAt: new Date('2023-09-10T11:00:00Z') },
|
||||
});
|
||||
|
||||
console.log('✓ Users seeded');
|
||||
|
||||
// ── Forum Categories ────────────────────────────────────────────────────────
|
||||
|
||||
const cat1 = await prisma.forumCategory.upsert({
|
||||
where: { id: 'cat1' },
|
||||
update: {},
|
||||
create: { id: 'cat1', name: 'General Discussion', description: 'Everything and anything about Headless Hazard.', icon: '///' },
|
||||
});
|
||||
const cat2 = await prisma.forumCategory.upsert({
|
||||
where: { id: 'cat2' },
|
||||
update: {},
|
||||
create: { id: 'cat2', name: 'Game Suggestions', description: 'Share your ideas to improve the game.', icon: '[!]' },
|
||||
});
|
||||
const cat3 = await prisma.forumCategory.upsert({
|
||||
where: { id: 'cat3' },
|
||||
update: {},
|
||||
create: { id: 'cat3', name: 'Multiplayer', description: 'Find teammates, share strategies, report cheaters.', icon: '>>' },
|
||||
});
|
||||
const cat4 = await prisma.forumCategory.upsert({
|
||||
where: { id: 'cat4' },
|
||||
update: {},
|
||||
create: { id: 'cat4', name: 'Lore & Theories', description: 'Dig into the deep lore of the corporate complex.', icon: '[?]' },
|
||||
});
|
||||
await prisma.forumCategory.upsert({
|
||||
where: { id: 'cat5' },
|
||||
update: {},
|
||||
create: { id: 'cat5', name: 'Off Topic', description: 'Chat about anything not related to the game.', icon: '~' },
|
||||
});
|
||||
const cat6 = await prisma.forumCategory.upsert({
|
||||
where: { id: 'cat6' },
|
||||
update: {},
|
||||
create: { id: 'cat6', name: 'Technical Support', description: 'Having trouble running the game? Ask here.', icon: '[X]' },
|
||||
});
|
||||
|
||||
console.log('✓ Forum categories seeded');
|
||||
|
||||
// ── Forum Threads ───────────────────────────────────────────────────────────
|
||||
|
||||
const th1 = await prisma.forumThread.upsert({
|
||||
where: { id: 'th1' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'th1', title: 'Official Welcome Thread — Read Before Posting!',
|
||||
content: `Welcome to the official Headless Hazard community forum. Before you post, please read our community guidelines.\n\n1. Be respectful\n2. No spoilers without tags\n3. Use the bug report page for bugs, not the forum\n\nHappy gaming — and watch out for rogue security protocols.`,
|
||||
isPinned: true, authorId: u2.id, categoryId: cat1.id,
|
||||
createdAt: new Date('2025-11-01T10:00:00Z'), updatedAt: new Date('2026-01-10T08:00:00Z'),
|
||||
},
|
||||
});
|
||||
const th2 = await prisma.forumThread.upsert({
|
||||
where: { id: 'th2' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'th2', title: 'The head physics feel clunky — how do you control it?',
|
||||
content: `I've been playing for 3 hours and I still can't wrap my head (lol) around the head movement controls. The inertia system is wild. Anyone have tips?\n\nI keep slamming the head into walls when I try to look around corners.`,
|
||||
authorId: u3.id, categoryId: cat1.id,
|
||||
createdAt: new Date('2026-01-20T15:30:00Z'), updatedAt: new Date('2026-01-22T11:00:00Z'),
|
||||
},
|
||||
});
|
||||
const th3 = await prisma.forumThread.upsert({
|
||||
where: { id: 'th3' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'th3', title: 'SUGGESTION: Let us name the girl!',
|
||||
content: `She's referred to as "the girl" throughout the whole game. I think we should be able to name her. It would add so much to the emotional connection.\n\nSome candidates I thought of: Zara, Pip, Elodie, Mira...`,
|
||||
authorId: u4.id, categoryId: cat2.id,
|
||||
createdAt: new Date('2026-01-25T09:00:00Z'), updatedAt: new Date('2026-02-10T17:30:00Z'),
|
||||
},
|
||||
});
|
||||
await prisma.forumThread.upsert({
|
||||
where: { id: 'th4' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'th4', title: 'Looking for co-op partner — Floor 3 boss is brutal',
|
||||
content: `Floor 3 boss: The Sentinel Prime. It tracks the body AND the head simultaneously. Solo is nearly impossible on hard mode.\n\nAnyone want to team up? I'm online weekday evenings UTC+1.`,
|
||||
authorId: u5.id, categoryId: cat3.id,
|
||||
createdAt: new Date('2026-02-01T20:00:00Z'), updatedAt: new Date('2026-02-03T09:15:00Z'),
|
||||
},
|
||||
});
|
||||
const th5 = await prisma.forumThread.upsert({
|
||||
where: { id: 'th5' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'th5', title: 'THEORY: The girl is the daughter of the [BLEEP] CEO',
|
||||
content: `Hear me out. There's a family portrait in the executive suite on floor 5. The girl in the painting has the same red hair as our protagonist. AND the security clearance codes found in the vault match a name that's always been redacted...\n\nI think her father IS the corporation. This changes everything about why the protocols went haywire.`,
|
||||
authorId: u7.id, categoryId: cat4.id,
|
||||
createdAt: new Date('2026-02-05T11:00:00Z'), updatedAt: new Date('2026-02-17T22:10:00Z'),
|
||||
},
|
||||
});
|
||||
const th6 = await prisma.forumThread.upsert({
|
||||
where: { id: 'th6' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'th6', title: 'Game crashes on startup — Windows 11 RTX 4080',
|
||||
content: `Getting a DirectX 12 error on startup. Already tried reinstalling, verifying files, and updating drivers.\n\nError: DXGI_ERROR_DEVICE_REMOVED\nOS: Windows 11 22H2\nGPU: RTX 4080`,
|
||||
authorId: u3.id, categoryId: cat6.id,
|
||||
createdAt: new Date('2026-02-10T14:20:00Z'), updatedAt: new Date('2026-02-11T10:00:00Z'),
|
||||
},
|
||||
});
|
||||
const th7 = await prisma.forumThread.upsert({
|
||||
where: { id: 'th7' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'th7', title: 'The VHS aesthetic is a MASTERPIECE — appreciation post',
|
||||
content: `Just want to say: whoever did the visual design deserves an award. The scan lines, the color grading, the way the CRT flickers when the head rolls across a monitor screen — *chef's kiss*.\n\nThis is what indie games are about.`,
|
||||
authorId: u4.id, categoryId: cat1.id,
|
||||
createdAt: new Date('2026-02-12T08:45:00Z'), updatedAt: new Date('2026-02-16T19:30:00Z'),
|
||||
},
|
||||
});
|
||||
await prisma.forumThread.upsert({
|
||||
where: { id: 'th8' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'th8', title: 'Speedrun strats — sub 45min run possible?',
|
||||
content: `Current WR is 48:32 by user HexBlade (not on this forum). I think sub-45 is possible with the elevator skip on floor 2 and the head-throw glitch to open the airlock.\n\nLet's document all known skips here.`,
|
||||
authorId: u5.id, categoryId: cat3.id,
|
||||
createdAt: new Date('2026-02-14T17:00:00Z'), updatedAt: new Date('2026-02-18T06:00:00Z'),
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✓ Forum threads seeded');
|
||||
|
||||
// ── Forum Replies ───────────────────────────────────────────────────────────
|
||||
|
||||
const replies = [
|
||||
{ id: 'r1', content: 'Thanks for the welcome! Excited to dive into this game. The concept sounds wild.', authorId: u3.id, threadId: th1.id, createdAt: new Date('2025-11-02T09:00:00Z') },
|
||||
{ id: 'r2', content: 'Read the guidelines. Solid rules. Looking forward to theorizing about the lore!', authorId: u7.id, threadId: th1.id, createdAt: new Date('2025-11-05T14:00:00Z') },
|
||||
{ id: 'r3', content: "The trick is to use short bursts. Don't hold the direction key — tap it. The head has massive momentum.", authorId: u5.id, threadId: th2.id, createdAt: new Date('2026-01-20T16:00:00Z') },
|
||||
{ id: 'r4', content: 'Also check your sensitivity settings. Mine was at 100% by default which is insane. I dropped it to 35%.', authorId: u4.id, threadId: th2.id, createdAt: new Date('2026-01-21T09:30:00Z') },
|
||||
{ id: 'r5', content: "I've been calling her Mira since day one. Feels right.", authorId: u7.id, threadId: th3.id, createdAt: new Date('2026-01-25T10:00:00Z') },
|
||||
{ id: 'r6', content: "Hard disagree — the ambiguity is part of the point. She's every lost child. Naming her loses that.", authorId: u8.id, threadId: th3.id, createdAt: new Date('2026-01-25T11:30:00Z') },
|
||||
{ id: 'r7', content: 'Voting for Pip. Short, punchy, and weirdly adorable for someone causing this much chaos.', authorId: u5.id, threadId: th3.id, createdAt: new Date('2026-01-26T08:15:00Z') },
|
||||
{ id: 'r8', content: "I noticed that too! The hair is definitely the same shade. And there's a memo on floor 3 signed with a heavily redacted name with only the initials visible...", authorId: u3.id, threadId: th5.id, createdAt: new Date('2026-02-05T12:00:00Z') },
|
||||
{ id: 'r9', content: "The developers confirmed on stream that the girl's backstory will be explored in a DLC. This theory might be onto something.", authorId: u8.id, threadId: th5.id, createdAt: new Date('2026-02-06T15:00:00Z') },
|
||||
{ id: 'r10', content: "We're aware of this crash on certain Nvidia configurations. A patch is being prepared. ETA: next week. Sorry for the inconvenience.", authorId: u2.id, threadId: th6.id, createdAt: new Date('2026-02-11T10:00:00Z') },
|
||||
{ id: 'r11', content: 'Agreed 100%. The moment I saw the first CRT flicker I knew this was something special.', authorId: u3.id, threadId: th7.id, createdAt: new Date('2026-02-12T10:00:00Z') },
|
||||
{ id: 'r12', content: 'Thanks for the kind words! The visual team worked incredibly hard on those effects. More surprises coming in future updates.', authorId: u1.id, threadId: th7.id, createdAt: new Date('2026-02-13T09:00:00Z') },
|
||||
];
|
||||
|
||||
for (const r of replies) {
|
||||
await prisma.forumReply.upsert({ where: { id: r.id }, update: {}, create: r });
|
||||
if (!username || !email || !password) {
|
||||
throw new Error('ADMIN_USERNAME, ADMIN_EMAIL and ADMIN_PASSWORD must be set in .env');
|
||||
}
|
||||
|
||||
console.log('✓ Forum replies seeded');
|
||||
const hashed = await bcrypt.hash(password, 10);
|
||||
|
||||
// ── Bug Reports ─────────────────────────────────────────────────────────────
|
||||
|
||||
const bug1 = await prisma.bugReport.upsert({
|
||||
where: { id: 'bug1' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'bug1', uniqueCode: 'HH-0001',
|
||||
title: 'Head clips through floor geometry on ramp sections',
|
||||
description: 'When rolling the head down the maintenance ramp on floor 2, the head occasionally clips through the floor and falls into the void. This causes a soft reset but loses all checkpoint progress.',
|
||||
stepsToReproduce: '1. Reach Floor 2, section C\n2. Roll head down the maintenance ramp at full speed\n3. Head clips through at approximately 80% of the way down\n4. Game enters a permanent loading state',
|
||||
severity: 'high', gameVersion: '0.9.3-alpha', status: 'in_progress',
|
||||
submittedById: u3.id, assignedToId: u8.id,
|
||||
createdAt: new Date('2026-01-15T18:00:00Z'), updatedAt: new Date('2026-01-16T09:00:00Z'),
|
||||
},
|
||||
});
|
||||
const bug2 = await prisma.bugReport.upsert({
|
||||
where: { id: 'bug2' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'bug2', uniqueCode: 'HH-0002',
|
||||
title: 'Audio desync in co-op mode after host migration',
|
||||
description: 'When the host player disconnects and host migration occurs, all audio becomes desynced. Sound effects play 2-3 seconds after the triggering event.',
|
||||
stepsToReproduce: '1. Start a co-op session with 3+ players\n2. Have the host disconnect mid-game\n3. Continue playing after host migration completes\n4. Observe audio desync within 30 seconds',
|
||||
severity: 'medium', gameVersion: '0.9.3-alpha', status: 'open',
|
||||
submittedById: u5.id,
|
||||
createdAt: new Date('2026-01-28T14:00:00Z'), updatedAt: new Date('2026-01-28T14:00:00Z'),
|
||||
},
|
||||
});
|
||||
const bug3 = await prisma.bugReport.upsert({
|
||||
where: { id: 'bug3' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'bug3', uniqueCode: 'HH-0003',
|
||||
title: 'Game crashes on startup — DirectX 12 error',
|
||||
description: 'Game fails to launch with DXGI_ERROR_DEVICE_REMOVED on RTX 4080 with specific Nvidia driver versions (566.x series).',
|
||||
stepsToReproduce: '1. Install Nvidia driver 566.03 or higher\n2. Attempt to launch Headless Hazard\n3. Game shows splash screen then crashes\n4. Windows Event Viewer shows DXGI_ERROR_DEVICE_REMOVED',
|
||||
severity: 'critical', gameVersion: '0.9.3-alpha', status: 'in_progress',
|
||||
submittedById: u3.id, assignedToId: u1.id,
|
||||
createdAt: new Date('2026-02-10T14:20:00Z'), updatedAt: new Date('2026-02-11T11:00:00Z'),
|
||||
},
|
||||
});
|
||||
await prisma.bugReport.upsert({
|
||||
where: { id: 'bug4' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'bug4', uniqueCode: 'HH-0004',
|
||||
title: 'Girl NPC gets stuck in T-pose near elevator door',
|
||||
description: 'The girl character enters a T-pose animation state when the elevator door closes while she is within 1 meter of the door. She remains stuck until the player rolls the head near her.',
|
||||
stepsToReproduce: '1. Floor 1, elevator B\n2. Position the girl next to the closed elevator door\n3. Call the elevator\n4. As doors close, T-pose triggers',
|
||||
severity: 'low', gameVersion: '0.9.2-alpha', status: 'resolved',
|
||||
submittedById: u4.id, assignedToId: u8.id,
|
||||
createdAt: new Date('2025-12-20T10:00:00Z'), updatedAt: new Date('2026-01-05T16:00:00Z'),
|
||||
},
|
||||
});
|
||||
const bug5 = await prisma.bugReport.upsert({
|
||||
where: { id: 'bug5' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'bug5', uniqueCode: 'HH-0005',
|
||||
title: 'Save corruption when quitting during cutscene',
|
||||
description: 'Alt+F4 or force-quitting during any cutscene corrupts the save file. The save file becomes unreadable and the game starts fresh on next launch.',
|
||||
stepsToReproduce: '1. Trigger any in-game cutscene\n2. While the cutscene is playing, alt+F4 the game\n3. Relaunch the game\n4. Game shows "Save file corrupted" and resets progress',
|
||||
severity: 'critical', gameVersion: '0.9.3-alpha', status: 'open',
|
||||
submittedById: u7.id,
|
||||
createdAt: new Date('2026-02-14T19:30:00Z'), updatedAt: new Date('2026-02-14T19:30:00Z'),
|
||||
},
|
||||
});
|
||||
await prisma.bugReport.upsert({
|
||||
where: { id: 'bug6' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'bug6', uniqueCode: 'HH-0006',
|
||||
title: 'Head-camera view flickers when standing near florescent lights',
|
||||
description: 'Minor visual bug: when viewing through the head camera near certain florescent light fixtures, the camera feed flickers at approximately 60hz in an uncomfortable strobing pattern.',
|
||||
stepsToReproduce: '1. Floor 0 server room\n2. Position head under the overhead fluorescent tubes\n3. Open the head camera view\n4. Observe strobing flicker',
|
||||
severity: 'low', gameVersion: '0.9.3-alpha', status: 'closed',
|
||||
submittedById: u5.id,
|
||||
createdAt: new Date('2026-01-10T11:00:00Z'), updatedAt: new Date('2026-01-12T14:00:00Z'),
|
||||
},
|
||||
const user = await prisma.user.upsert({
|
||||
where: { email },
|
||||
update: { username, password: hashed, role: 'dev', isAdmin: true },
|
||||
create: { username, email, password: hashed, role: 'dev', isAdmin: true },
|
||||
});
|
||||
|
||||
console.log('✓ Bug reports seeded');
|
||||
|
||||
// ── Bug Notes (staff internal) ──────────────────────────────────────────────
|
||||
|
||||
await prisma.bugReportNote.upsert({
|
||||
where: { id: 'n1' },
|
||||
update: {},
|
||||
create: { id: 'n1', bugReportId: bug1.id, authorId: u1.id, content: 'Reproduced internally. Relates to the head collision hitbox on slopes. Assigning to ByteWitch for physics review.', createdAt: new Date('2026-01-16T09:00:00Z') },
|
||||
});
|
||||
await prisma.bugReportNote.upsert({
|
||||
where: { id: 'n2' },
|
||||
update: {},
|
||||
create: { id: 'n2', bugReportId: bug3.id, authorId: u8.id, content: 'This is the DirectX 12 feature level issue. Nvidia driver 566.x introduced a regression. Workaround: force DX11 via launch options.', createdAt: new Date('2026-02-11T11:00:00Z') },
|
||||
});
|
||||
|
||||
// ── Bug Comments ────────────────────────────────────────────────────────────
|
||||
|
||||
const bugComments = [
|
||||
{ id: 'bc1', bugReportId: bug1.id, authorId: u5.id, content: 'Can confirm this happens to me too. Specifically when the head reaches full speed before the curve at the bottom.', createdAt: new Date('2026-01-16T10:00:00Z') },
|
||||
{ id: 'bc2', bugReportId: bug1.id, authorId: u4.id, content: 'Workaround: slow down before the bend. Tap the brake key twice. Annoying but it prevents the clip.', createdAt: new Date('2026-01-17T08:30:00Z') },
|
||||
{ id: 'bc3', bugReportId: bug3.id, authorId: u4.id, content: 'Downgrading to driver 565.90 fixed it for me. Not ideal but at least I can play.', createdAt: new Date('2026-02-11T14:00:00Z') },
|
||||
{ id: 'bc4', bugReportId: bug3.id, authorId: u7.id, content: 'The DX11 workaround mentioned in the internal note also works. Add -dx11 to launch options in Steam.', createdAt: new Date('2026-02-12T09:00:00Z') },
|
||||
{ id: 'bc5', bugReportId: bug5.id, authorId: u3.id, content: 'This wiped my 6-hour playthrough. Please prioritize this fix.', createdAt: new Date('2026-02-14T20:00:00Z') },
|
||||
{ id: 'bc6', bugReportId: bug5.id, authorId: u4.id, content: 'Same here. Lost floor 4 and 5 progress. The auto-save system really needs to not write mid-cutscene.', createdAt: new Date('2026-02-15T11:00:00Z') },
|
||||
];
|
||||
for (const c of bugComments) {
|
||||
await prisma.bugComment.upsert({ where: { id: c.id }, update: {}, create: c });
|
||||
}
|
||||
|
||||
// ── MeTooBugs ───────────────────────────────────────────────────────────────
|
||||
|
||||
const meTooPairs = [
|
||||
{ userId: u4.id, bugReportId: bug1.id }, { userId: u5.id, bugReportId: bug1.id }, { userId: u7.id, bugReportId: bug1.id },
|
||||
{ userId: u3.id, bugReportId: bug2.id },
|
||||
{ userId: u4.id, bugReportId: bug3.id }, { userId: u5.id, bugReportId: bug3.id }, { userId: u7.id, bugReportId: bug3.id }, { userId: u2.id, bugReportId: bug3.id },
|
||||
{ userId: u3.id, bugReportId: bug5.id }, { userId: u4.id, bugReportId: bug5.id }, { userId: u8.id, bugReportId: bug5.id },
|
||||
{ userId: u4.id, bugReportId: 'bug6' },
|
||||
];
|
||||
for (const pair of meTooPairs) {
|
||||
await prisma.meTooBug.upsert({ where: { userId_bugReportId: pair }, update: {}, create: pair });
|
||||
}
|
||||
|
||||
console.log('✓ Bug comments, notes, and me-too seeded');
|
||||
|
||||
// ── Staff Feed ──────────────────────────────────────────────────────────────
|
||||
|
||||
const feedPosts = [
|
||||
{ id: 'sp1', authorId: u1.id, content: 'Physics patch is ready for internal testing. ByteWitch, can you check the head-ramp collision fix before EOD?', createdAt: new Date('2026-02-18T08:30:00Z') },
|
||||
{ id: 'sp2', authorId: u2.id, content: 'Social media post about the co-op update went live. Already 400 likes in 2 hours. The community is really excited.', createdAt: new Date('2026-02-18T09:15:00Z') },
|
||||
{ id: 'sp3', authorId: u8.id, content: 'Checked the ramp fix — collision normals are now correct. Still seeing minor jitter at the bottom but nothing game-breaking. Marking as good to merge.', createdAt: new Date('2026-02-18T11:00:00Z') },
|
||||
{ id: 'sp4', authorId: u1.id, content: 'Merging physics fix. Will bundle with the DirectX hotfix into patch 0.9.4. Target: Monday release.', createdAt: new Date('2026-02-18T11:45:00Z') },
|
||||
{ id: 'sp5', authorId: u2.id, content: "Reminder: community AMA is scheduled for Wednesday 7pm UTC. I'll be handling questions, feel free to DM me answers for anything technical.", createdAt: new Date('2026-02-17T16:00:00Z') },
|
||||
{ id: 'sp6', authorId: u8.id, content: "Save corruption bug (HH-0005) root cause identified: file handle wasn't being closed before force-quit. Simple fix, will be in next patch.", createdAt: new Date('2026-02-15T14:30:00Z') },
|
||||
];
|
||||
for (const p of feedPosts) {
|
||||
await prisma.staffPost.upsert({ where: { id: p.id }, update: {}, create: p });
|
||||
}
|
||||
|
||||
console.log('✓ Staff feed seeded');
|
||||
|
||||
// ── Events & Polls ──────────────────────────────────────────────────────────
|
||||
|
||||
// Create events without polls first
|
||||
const evt1 = await prisma.eventPost.upsert({
|
||||
where: { id: 'evt1' },
|
||||
update: {},
|
||||
create: { id: 'evt1', type: 'milestone', title: 'Version 0.9.5 Released!', content: 'We are excited to announce version 0.9.5 is now live! This update includes major performance improvements, the new "Factory District" map, and over 30 bug fixes. Check the changelog for full details. Thank you to everyone who participated in testing!', authorId: u1.id, isPublic: true, createdAt: new Date('2026-02-17T14:00:00Z'), updatedAt: new Date('2026-02-17T14:00:00Z') },
|
||||
});
|
||||
const evt2 = await prisma.eventPost.upsert({
|
||||
where: { id: 'evt2' },
|
||||
update: {},
|
||||
create: { id: 'evt2', type: 'poll', title: 'Community Poll: Next Feature Priority', content: 'Help us decide what to work on next! We want to hear from you about which feature would enhance your experience the most. Vote below and feel free to discuss in the forum.', authorId: u2.id, isPublic: true, createdAt: new Date('2026-02-16T10:00:00Z'), updatedAt: new Date('2026-02-16T10:00:00Z') },
|
||||
});
|
||||
await prisma.eventPost.upsert({
|
||||
where: { id: 'evt3' },
|
||||
update: {},
|
||||
create: { id: 'evt3', type: 'announcement', title: 'Server Maintenance Scheduled', content: 'We will be performing server maintenance on February 20th from 2:00 AM to 6:00 AM UTC. Multiplayer services will be unavailable during this time. Single-player mode will remain accessible. We apologize for any inconvenience!', authorId: u8.id, isPublic: true, createdAt: new Date('2026-02-15T16:30:00Z'), updatedAt: new Date('2026-02-15T16:30:00Z') },
|
||||
});
|
||||
await prisma.eventPost.upsert({
|
||||
where: { id: 'evt4' },
|
||||
update: {},
|
||||
create: { id: 'evt4', type: 'update', title: 'Co-op Mode Development Progress', content: "Quick update on co-op mode development: networking code is 80% complete, and we've successfully tested 4-player sessions internally. Still working on some sync issues with physics objects, but overall progress is excellent. Aiming for beta testing in March!", authorId: u1.id, isPublic: true, createdAt: new Date('2026-02-14T11:20:00Z'), updatedAt: new Date('2026-02-14T11:20:00Z') },
|
||||
});
|
||||
const evt5 = await prisma.eventPost.upsert({
|
||||
where: { id: 'evt5' },
|
||||
update: {},
|
||||
create: { id: 'evt5', type: 'poll', title: 'Devlog Content Poll', content: "We want to make our devlogs more interesting for you! Let us know what kind of behind-the-scenes content you'd like to see more of. You can vote for multiple options.", authorId: u2.id, isPublic: true, createdAt: new Date('2026-02-01T09:00:00Z'), updatedAt: new Date('2026-02-01T09:00:00Z') },
|
||||
});
|
||||
await prisma.eventPost.upsert({
|
||||
where: { id: 'evt6' },
|
||||
update: {},
|
||||
create: { id: 'evt6', type: 'announcement', title: 'Community AMA This Wednesday', content: 'Join us for a live AMA (Ask Me Anything) session this Wednesday at 7:00 PM UTC! The dev team will be answering questions about the game, upcoming features, and the development process. Post your questions in the forum thread beforehand or ask live during the session.', authorId: u2.id, isPublic: true, createdAt: new Date('2026-02-12T14:00:00Z'), updatedAt: new Date('2026-02-12T14:00:00Z') },
|
||||
});
|
||||
await prisma.eventPost.upsert({
|
||||
where: { id: 'evt7' },
|
||||
update: {},
|
||||
create: { id: 'evt7', type: 'update', title: 'New Character Model Work in Progress', content: "Our art team has been working on updated character models with more detailed textures while maintaining the retro aesthetic. Early tests look fantastic! We'll share some screenshots next week. This won't affect performance - we're being very careful about optimization.", authorId: u1.id, isPublic: true, createdAt: new Date('2026-02-08T10:15:00Z'), updatedAt: new Date('2026-02-08T10:15:00Z') },
|
||||
});
|
||||
|
||||
// Polls
|
||||
const poll1 = await prisma.poll.upsert({
|
||||
where: { id: 'poll1' },
|
||||
update: {},
|
||||
create: { id: 'poll1', eventId: evt2.id, question: 'Which feature should we prioritize for the next major update?', isActive: true, endsAt: new Date('2026-02-28T23:59:59Z'), allowMultipleVotes: false, createdAt: new Date('2026-02-16T10:00:00Z') },
|
||||
});
|
||||
const opt1 = await prisma.pollOption.upsert({ where: { id: 'opt1' }, update: {}, create: { id: 'opt1', pollId: poll1.id, text: 'New multiplayer maps' } });
|
||||
const opt2 = await prisma.pollOption.upsert({ where: { id: 'opt2' }, update: {}, create: { id: 'opt2', pollId: poll1.id, text: 'Co-op campaign mode' } });
|
||||
await prisma.pollOption.upsert({ where: { id: 'opt3' }, update: {}, create: { id: 'opt3', pollId: poll1.id, text: 'Advanced physics system' } });
|
||||
await prisma.pollOption.upsert({ where: { id: 'opt4' }, update: {}, create: { id: 'opt4', pollId: poll1.id, text: 'Character customization' } });
|
||||
|
||||
// Votes for poll1
|
||||
const poll1Votes = [
|
||||
{ userId: u3.id, pollOptionId: opt1.id }, { userId: u4.id, pollOptionId: opt1.id },
|
||||
{ userId: u5.id, pollOptionId: opt1.id }, { userId: u7.id, pollOptionId: opt1.id },
|
||||
{ userId: u1.id, pollOptionId: opt2.id }, { userId: u2.id, pollOptionId: opt2.id }, { userId: u8.id, pollOptionId: opt2.id },
|
||||
];
|
||||
for (const v of poll1Votes) {
|
||||
await prisma.pollVote.upsert({ where: { userId_pollOptionId: v }, update: {}, create: v });
|
||||
}
|
||||
|
||||
const poll2 = await prisma.poll.upsert({
|
||||
where: { id: 'poll2' },
|
||||
update: {},
|
||||
create: { id: 'poll2', eventId: evt5.id, question: 'What type of content would you like to see more of in our devlogs?', isActive: false, endsAt: new Date('2026-02-10T23:59:59Z'), allowMultipleVotes: true, createdAt: new Date('2026-02-01T09:00:00Z') },
|
||||
});
|
||||
await prisma.pollOption.upsert({ where: { id: 'opt5' }, update: {}, create: { id: 'opt5', pollId: poll2.id, text: 'Behind-the-scenes coding' } });
|
||||
await prisma.pollOption.upsert({ where: { id: 'opt6' }, update: {}, create: { id: 'opt6', pollId: poll2.id, text: 'Art process & concept art' } });
|
||||
await prisma.pollOption.upsert({ where: { id: 'opt7' }, update: {}, create: { id: 'opt7', pollId: poll2.id, text: 'Level design breakdown' } });
|
||||
await prisma.pollOption.upsert({ where: { id: 'opt8' }, update: {}, create: { id: 'opt8', pollId: poll2.id, text: 'Bug fix explanations' } });
|
||||
|
||||
// Unused event references to avoid unused variable warnings
|
||||
void evt1; void evt5;
|
||||
|
||||
console.log('✓ Events and polls seeded');
|
||||
|
||||
// ── Team Members ────────────────────────────────────────────────────────────
|
||||
|
||||
const teamMembers = [
|
||||
{ id: 'tm1', name: 'Alexei Voronov', role: 'Studio Director & Lead Developer', bio: 'Former AAA engine programmer turned indie. Obsessed with physics simulations and 80s science fiction. The brains behind the detached head mechanic.', avatarInitials: 'AV', twitterHandle: '@alexei_dev', githubHandle: 'alexei-v' },
|
||||
{ id: 'tm2', name: 'Sadie Mercier', role: 'Lead Artist & Art Director', bio: 'Pixel art veteran and VHS enthusiast. Responsible for the retro-futuristic visual identity of Headless Hazard. Also makes incredible cheese.', avatarInitials: 'SM', twitterHandle: '@sadie_pixels', githubHandle: null },
|
||||
{ id: 'tm3', name: 'Rio Tanaka', role: 'Game Designer & Narrative Lead', bio: 'Wrote the full lore bible for the Headless Hazard universe, including 300 pages that will never see daylight. Loves bureaucratic dystopias.', avatarInitials: 'RT', twitterHandle: '@rio_writes', githubHandle: 'rio-tanaka' },
|
||||
{ id: 'tm4', name: 'Misha Devereux', role: 'Sound Designer & Composer', bio: 'Creates audio using a mix of synthesizers, field recordings in abandoned factories, and heavily processed VHS tapes. The soundscape of HH is entirely his.', avatarInitials: 'MD', twitterHandle: '@misha_sounds', githubHandle: null },
|
||||
{ id: 'tm5', name: 'Priya Anand', role: 'Backend & Infrastructure Engineer', bio: 'Keeps the multiplayer servers alive and the databases sane. Dark mode absolutist. Currently obsessed with Rust.', avatarInitials: 'PA', twitterHandle: null, githubHandle: 'priya-anand-dev' },
|
||||
{ id: 'tm6', name: 'Camille Dupont', role: 'Community Manager & QA Lead', bio: 'The bridge between the studio and the players. Has played through the full game 47 times for QA purposes and still finds it fun somehow.', avatarInitials: 'CD', twitterHandle: '@camille_crow', githubHandle: null },
|
||||
];
|
||||
for (const m of teamMembers) {
|
||||
await prisma.teamMember.upsert({ where: { id: m.id }, update: {}, create: m });
|
||||
}
|
||||
|
||||
console.log('✓ Team members seeded');
|
||||
console.log('\nDone! All users use password: password123');
|
||||
console.log(`Admin user ready: ${user.username} <${user.email}>`);
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user