Merge pull request #135 from Tria-plc/alpha-fix

Alpha fix
This commit is contained in:
Sennay
2026-06-11 14:04:14 +03:00
committed by GitHub
3 changed files with 57 additions and 31 deletions

View File

@@ -1,4 +1,4 @@
import { Prisma, PrismaClient } from '@prisma/client'; import { PrismaClient } from '@prisma/client';
import * as bcrypt from 'bcrypt'; import * as bcrypt from 'bcrypt';
import { randomUUID as uuidv4 } from 'crypto'; import { randomUUID as uuidv4 } from 'crypto';
@@ -224,12 +224,10 @@ async function seedCoaches() {
create: coach, create: coach,
}); });
// Rebuild the coach's seats from scratch. A plain upsert keyed on // Idempotently reconcile the coach's seats. Upsert keyed on the
// coachId_seatNumber can't reconcile a changed layout (it's blind to the // @@unique([coachId, row, col]) constraint so a re-seed updates existing
// @@unique([coachId, row, col]) constraint), so stale row/col data collides. // rows in place instead of deleting them. Deleting Seats fails with a P2003
await prisma.seat.deleteMany({ where: { coachId: c.id } }); // FK violation once BookingSeat/SeatBlock/TicketSeat rows reference them.
const seats: Prisma.SeatCreateManyInput[] = [];
let seatIndex = 1; let seatIndex = 1;
for (let row = 1; row <= Math.ceil(coach.capacity / 2); row++) { for (let row = 1; row <= Math.ceil(coach.capacity / 2); row++) {
for (const col of ['A', 'B', 'C', 'D']) { for (const col of ['A', 'B', 'C', 'D']) {
@@ -241,19 +239,21 @@ async function seedCoaches() {
else bedPosition = 'lower'; else bedPosition = 'lower';
} }
seats.push({ const seatData = {
coachId: c.id,
seatNumber: seatIndex.toString(), seatNumber: seatIndex.toString(),
row,
col,
isWindow: col === 'A' || col === 'D', isWindow: col === 'A' || col === 'D',
isAisle: col === 'B' || col === 'C', isAisle: col === 'B' || col === 'C',
bedPosition, bedPosition,
};
await prisma.seat.upsert({
where: { coachId_row_col: { coachId: c.id, row, col } },
update: seatData,
create: { coachId: c.id, row, col, ...seatData },
}); });
seatIndex++; seatIndex++;
} }
} }
await prisma.seat.createMany({ data: seats });
totalSeats += coach.capacity; totalSeats += coach.capacity;
} }
console.log(`${coaches.length} coaches with ${totalSeats} seats created`); console.log(`${coaches.length} coaches with ${totalSeats} seats created`);
@@ -552,25 +552,49 @@ async function seedFraudRules() {
console.log(`${rules.length} fraud detection rules created`); console.log(`${rules.length} fraud detection rules created`);
} }
// Run a seed step in isolation: if it throws (FK conflict, duplicate row,
// missing record, etc.) log the error and keep going so the rest of the seed —
// and the API startup that follows it — are never blocked by one bad step.
async function runStep(name: string, step: () => Promise<void>): Promise<boolean> {
try {
await step();
return true;
} catch (e) {
console.error(`⚠️ Seed step "${name}" failed — skipping and continuing:`, e);
return false;
}
}
async function main() { async function main() {
console.log('🌱 Comprehensive EDR Seed Starting...\n'); console.log('🌱 Comprehensive EDR Seed Starting...\n');
await seedSystemUsers(); const steps: Array<[string, () => Promise<void>]> = [
await seedStations(); ['system users', seedSystemUsers],
await seedCoachTypesAndClasses(); ['stations', seedStations],
await seedRoute(); ['coach types & classes', seedCoachTypesAndClasses],
await seedCoaches(); ['route', seedRoute],
await seedTrips(); ['coaches', seedCoaches],
await seedFareRules(); ['trips', seedTrips],
await seedCurrency(); ['fare rules', seedFareRules],
await seedPaymentMethods(); ['currency', seedCurrency],
await seedNotificationTemplates(); ['payment methods', seedPaymentMethods],
await seedMenuAndFood(); ['notification templates', seedNotificationTemplates],
await seedPromotions(); ['menu & food', seedMenuAndFood],
await seedFAQ(); ['promotions', seedPromotions],
await seedFraudRules(); ['FAQ', seedFAQ],
['fraud rules', seedFraudRules],
];
console.log('\n✅ Seed complete!\n'); let failed = 0;
for (const [name, step] of steps) {
if (!(await runStep(name, step))) failed++;
}
if (failed > 0) {
console.warn(`\n⚠ Seed finished with ${failed}/${steps.length} step(s) failed (see logs above).\n`);
} else {
console.log('\n✅ Seed complete!\n');
}
console.log('🔑 System Users:'); console.log('🔑 System Users:');
console.log(' Admin: admin@edr-platform.com / admin123'); console.log(' Admin: admin@edr-platform.com / admin123');
console.log(' Passenger: kelemu@email.com / password123'); console.log(' Passenger: kelemu@email.com / password123');
@@ -581,8 +605,10 @@ async function main() {
main() main()
.catch((e) => { .catch((e) => {
console.error('❌ Seed failed:', e); // Intentionally do NOT process.exit(1): the docker entrypoint runs under
process.exit(1); // `set -e`, so a non-zero exit here would abort container startup and the
// API would never boot. Log and exit cleanly instead.
console.error('❌ Seed crashed unexpectedly — continuing so the API can start:', e);
}) })
.finally(async () => { .finally(async () => {
await prisma.$disconnect(); await prisma.$disconnect();

View File

@@ -37,4 +37,4 @@ module.exports = {
}, },
}, },
plugins: [], plugins: [],
}; };

View File

@@ -89,4 +89,4 @@ export default {
}, },
}, },
plugins: [], plugins: [],
}; };