244 lines
6.9 KiB
TypeScript
244 lines
6.9 KiB
TypeScript
#!/usr/bin/env tsx
|
||
|
||
import { config } from 'dotenv';
|
||
import { drizzle } from 'drizzle-orm/postgres-js';
|
||
import postgres from 'postgres';
|
||
import * as schema from '../src/schemas/database/schema';
|
||
import { hashPassword } from '../src/lib/utils/passwordHash';
|
||
import { v4 as uuidv4 } from 'uuid';
|
||
|
||
// Load environment variables from .env file
|
||
config();
|
||
|
||
async function seed() {
|
||
const databaseUrl = process.env.DATABASE_URL;
|
||
if (!databaseUrl) {
|
||
throw new Error('DATABASE_URL environment variable is not set');
|
||
}
|
||
|
||
console.log('🌱 Starting database seeding...');
|
||
|
||
const client = postgres(databaseUrl);
|
||
const db = drizzle(client, { schema });
|
||
|
||
try {
|
||
// Create admin user
|
||
console.log('👤 Creating admin user...');
|
||
const adminPasswordHash = await hashPassword('admin123');
|
||
|
||
const adminUser = await db
|
||
.insert(schema.managementUsers)
|
||
.values({
|
||
firstName: 'Admin',
|
||
lastName: 'User',
|
||
username: 'admin',
|
||
passwordHash: adminPasswordHash,
|
||
role: 'ADMIN',
|
||
enabled: true
|
||
})
|
||
.returning()
|
||
.onConflictDoNothing();
|
||
|
||
if (adminUser.length > 0) {
|
||
console.log('✅ Admin user created with username: admin, password: admin123');
|
||
} else {
|
||
console.log('ℹ️ Admin user already exists');
|
||
}
|
||
|
||
// Create sample members
|
||
console.log('👥 Creating sample members...');
|
||
const members = [
|
||
{
|
||
firstName: 'Max',
|
||
lastName: 'Mustermann',
|
||
email: 'max.mustermann@example.com',
|
||
membershipNumber: 'MEM001',
|
||
phoneMobile: '+49123456789',
|
||
joinedAt: new Date('2024-01-15')
|
||
},
|
||
{
|
||
firstName: 'Anna',
|
||
lastName: 'Schmidt',
|
||
email: 'anna.schmidt@example.com',
|
||
membershipNumber: 'MEM002',
|
||
phoneMobile: '+49987654321',
|
||
joinedAt: new Date('2024-02-20')
|
||
},
|
||
{
|
||
firstName: 'Peter',
|
||
lastName: 'Müller',
|
||
email: 'peter.mueller@example.com',
|
||
membershipNumber: 'MEM003',
|
||
phoneMobile: '+49555666777',
|
||
joinedAt: new Date('2024-03-10')
|
||
}
|
||
];
|
||
|
||
const createdMembers = [];
|
||
for (const member of members) {
|
||
const result = await db
|
||
.insert(schema.members)
|
||
.values(member)
|
||
.returning()
|
||
.onConflictDoNothing();
|
||
|
||
if (result.length > 0) {
|
||
createdMembers.push(result[0]);
|
||
console.log(`✅ Created member: ${member.firstName} ${member.lastName}`);
|
||
}
|
||
}
|
||
|
||
// Create sample RFID cards
|
||
console.log('🆔 Creating sample RFID cards...');
|
||
const rfidCards = [
|
||
{ rfidId: 'ABC123456789', status: 'NEW' as const },
|
||
{ rfidId: 'DEF987654321', status: 'NEW' as const },
|
||
{ rfidId: 'GHI456789123', status: 'ENGRAVED' as const },
|
||
{ rfidId: 'JKL789123456', status: 'NEW' as const },
|
||
{ rfidId: 'MNO321654987', status: 'NEW' as const }
|
||
];
|
||
|
||
const createdCards = [];
|
||
for (const card of rfidCards) {
|
||
const result = await db
|
||
.insert(schema.rfidCards)
|
||
.values(card)
|
||
.returning()
|
||
.onConflictDoNothing();
|
||
|
||
if (result.length > 0) {
|
||
createdCards.push(result[0]);
|
||
console.log(`✅ Created RFID card: ${card.rfidId} (${card.status})`);
|
||
}
|
||
}
|
||
|
||
// Create sample assignments
|
||
console.log('🔗 Creating sample card assignments...');
|
||
const assignments = [
|
||
{
|
||
memberId: createdMembers[0]?.id,
|
||
cardId: createdCards[0]?.id,
|
||
status: 'ASSIGNED' as const,
|
||
issuedAt: new Date('2024-01-20')
|
||
},
|
||
{
|
||
memberId: createdMembers[1]?.id,
|
||
cardId: createdCards[1]?.id,
|
||
status: 'ASSIGNED' as const,
|
||
issuedAt: new Date('2024-02-25')
|
||
},
|
||
{
|
||
memberId: createdMembers[2]?.id,
|
||
cardId: createdCards[2]?.id,
|
||
status: 'ASSIGNED' as const,
|
||
issuedAt: new Date('2024-03-15')
|
||
}
|
||
];
|
||
|
||
for (const assignment of assignments) {
|
||
if (assignment.memberId && assignment.cardId) {
|
||
const result = await db
|
||
.insert(schema.memberRfidCards)
|
||
.values(assignment)
|
||
.returning()
|
||
.onConflictDoNothing();
|
||
|
||
if (result.length > 0) {
|
||
console.log(
|
||
`✅ Assigned card ${createdCards.find((c) => c.id === assignment.cardId)?.rfidId} to ${createdMembers.find((m) => m.id === assignment.memberId)?.firstName} ${createdMembers.find((m) => m.id === assignment.memberId)?.lastName}`
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Create sample devices
|
||
console.log('📱 Creating sample devices...');
|
||
const devices = [
|
||
{
|
||
name: 'Main Entrance Scanner',
|
||
apiKey: 'dev_' + uuidv4().replace(/-/g, ''),
|
||
type: 'RFID_SCANNER' as const
|
||
},
|
||
{
|
||
name: 'Office Door Lock',
|
||
apiKey: 'dev_' + uuidv4().replace(/-/g, ''),
|
||
type: 'LOCK_SYSTEM' as const
|
||
}
|
||
];
|
||
|
||
const createdDevices = [];
|
||
for (const device of devices) {
|
||
const result = await db
|
||
.insert(schema.devices)
|
||
.values(device)
|
||
.returning()
|
||
.onConflictDoNothing();
|
||
|
||
if (result.length > 0) {
|
||
createdDevices.push(result[0]);
|
||
console.log(`✅ Created device: ${device.name} (${device.type})`);
|
||
}
|
||
}
|
||
|
||
// Get all members and devices for access logs
|
||
const allMembers = await db.select().from(schema.members);
|
||
const allDevices = await db.select().from(schema.devices);
|
||
|
||
if (allMembers.length === 0 || allDevices.length === 0) {
|
||
console.log('⚠️ No members or devices found, skipping access log creation');
|
||
} else {
|
||
// Create sample access logs for the last 30 days
|
||
console.log('📊 Creating sample access logs...');
|
||
const accessLogs = [];
|
||
const now = new Date();
|
||
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
||
|
||
for (let i = 0; i < 30; i++) {
|
||
const date = new Date(thirtyDaysAgo.getTime() + i * 24 * 60 * 60 * 1000);
|
||
// Random number of accesses per day (5-50)
|
||
const accessesPerDay = Math.floor(Math.random() * 46) + 5;
|
||
|
||
for (let j = 0; j < accessesPerDay; j++) {
|
||
const randomMember = allMembers[Math.floor(Math.random() * allMembers.length)];
|
||
const randomDevice = allDevices[Math.floor(Math.random() * allDevices.length)];
|
||
const randomHour = Math.floor(Math.random() * 24);
|
||
const randomMinute = Math.floor(Math.random() * 60);
|
||
const accessedAt = new Date(date);
|
||
accessedAt.setHours(randomHour, randomMinute, 0, 0);
|
||
|
||
accessLogs.push({
|
||
memberId: randomMember.id,
|
||
deviceId: randomDevice.id,
|
||
accessedAt,
|
||
accessGranted: Math.random() > 0.05 // 95% success rate
|
||
});
|
||
}
|
||
}
|
||
|
||
for (const log of accessLogs) {
|
||
await db.insert(schema.accessLogs).values(log).onConflictDoNothing();
|
||
}
|
||
console.log(`✅ Created ${accessLogs.length} sample access logs over the last 30 days`);
|
||
}
|
||
|
||
console.log('🎉 Database seeding completed successfully!');
|
||
console.log('\n📋 Summary:');
|
||
console.log('- Admin user: admin / admin123');
|
||
console.log('- Sample members, RFID cards, and assignments created');
|
||
console.log('- Sample devices created');
|
||
if (allMembers.length > 0 && allDevices.length > 0) {
|
||
console.log('- Sample access logs created for chart testing');
|
||
}
|
||
} catch (error) {
|
||
console.error('❌ Error during seeding:', error);
|
||
process.exit(1);
|
||
} finally {
|
||
await client.end();
|
||
}
|
||
}
|
||
|
||
seed().catch((error) => {
|
||
console.error('❌ Seeding failed:', error);
|
||
process.exit(1);
|
||
});
|