- Add POLineItem.name column; migrate existing description→name; description is now optional - NameCell component: name input with fuzzy product search, description input stacked below - Read-only view shows name prominently, description in subdued text below - All server actions (create, edit, manager edit, import) updated to read/write name - ParsedImportLine.description renamed to .name throughout import parser and form - Seed data updated; CLAUDE.md added Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
655 lines
17 KiB
TypeScript
655 lines
17 KiB
TypeScript
import { PrismaClient, Role } from "@prisma/client";
|
||
import bcrypt from "bcryptjs";
|
||
|
||
const db = new PrismaClient();
|
||
|
||
async function main() {
|
||
console.log("Seeding database...");
|
||
|
||
const hash = (p: string) => bcrypt.hash(p, 12);
|
||
|
||
// Users
|
||
const admin = await db.user.upsert({
|
||
where: { email: "admin@pelagia.local" },
|
||
update: {},
|
||
create: {
|
||
employeeId: "EMP-001",
|
||
email: "admin@pelagia.local",
|
||
name: "System Admin",
|
||
passwordHash: await hash("admin1234"),
|
||
role: Role.ADMIN,
|
||
},
|
||
});
|
||
|
||
const manager = await db.user.upsert({
|
||
where: { email: "manager@pelagia.local" },
|
||
update: {},
|
||
create: {
|
||
employeeId: "EMP-002",
|
||
email: "manager@pelagia.local",
|
||
name: "James Hartwell",
|
||
passwordHash: await hash("manager1234"),
|
||
role: Role.MANAGER,
|
||
},
|
||
});
|
||
|
||
const technical = await db.user.upsert({
|
||
where: { email: "tech@pelagia.local" },
|
||
update: {},
|
||
create: {
|
||
employeeId: "EMP-003",
|
||
email: "tech@pelagia.local",
|
||
name: "Maria Santos",
|
||
passwordHash: await hash("tech1234"),
|
||
role: Role.TECHNICAL,
|
||
},
|
||
});
|
||
|
||
const accounts = await db.user.upsert({
|
||
where: { email: "accounts@pelagia.local" },
|
||
update: {},
|
||
create: {
|
||
employeeId: "EMP-004",
|
||
email: "accounts@pelagia.local",
|
||
name: "Chen Wei",
|
||
passwordHash: await hash("accounts1234"),
|
||
role: Role.ACCOUNTS,
|
||
},
|
||
});
|
||
|
||
await db.user.upsert({
|
||
where: { email: "manning@pelagia.local" },
|
||
update: {},
|
||
create: {
|
||
employeeId: "EMP-005",
|
||
email: "manning@pelagia.local",
|
||
name: "Raj Patel",
|
||
passwordHash: await hash("manning1234"),
|
||
role: Role.MANNING,
|
||
},
|
||
});
|
||
|
||
// Vessels
|
||
const mv1 = await db.vessel.upsert({
|
||
where: { imoNumber: "IMO9876543" },
|
||
update: {},
|
||
create: { name: "MV Pelagia Star", imoNumber: "IMO9876543" },
|
||
});
|
||
|
||
const mv2 = await db.vessel.upsert({
|
||
where: { imoNumber: "IMO9123456" },
|
||
update: {},
|
||
create: { name: "MV Aegean Wind", imoNumber: "IMO9123456" },
|
||
});
|
||
|
||
await db.vessel.upsert({
|
||
where: { imoNumber: "IMO9654321" },
|
||
update: {},
|
||
create: { name: "MV Poseidon", imoNumber: "IMO9654321" },
|
||
});
|
||
|
||
// Accounts
|
||
const acc1 = await db.account.upsert({
|
||
where: { code: "TECH-OPS" },
|
||
update: {},
|
||
create: { code: "TECH-OPS", name: "Technical Operations", description: "Engine and deck equipment" },
|
||
});
|
||
|
||
const acc2 = await db.account.upsert({
|
||
where: { code: "CREW-MGT" },
|
||
update: {},
|
||
create: { code: "CREW-MGT", name: "Crew Management", description: "Manning and crew welfare" },
|
||
});
|
||
|
||
await db.account.upsert({
|
||
where: { code: "FUEL-BNK" },
|
||
update: {},
|
||
create: { code: "FUEL-BNK", name: "Fuel & Bunkers", description: "Fuel procurement" },
|
||
});
|
||
|
||
// Vendors
|
||
const vendor1 = await db.vendor.upsert({
|
||
where: { vendorId: "VND-0001" },
|
||
update: {},
|
||
create: {
|
||
name: "Marine Parts International",
|
||
vendorId: "VND-0001",
|
||
contactName: "Tony Nguyen",
|
||
contactEmail: "tnguyen@marinepartsinternational.com",
|
||
address: "Plot 12, MIDC Industrial Area, Turbhe, Navi Mumbai 400705",
|
||
gstin: "27AABCM1234A1Z5",
|
||
isVerified: true,
|
||
},
|
||
});
|
||
|
||
await db.vendor.upsert({
|
||
where: { vendorId: "VND-0002" },
|
||
update: {},
|
||
create: {
|
||
name: "Global Crew Supplies",
|
||
vendorId: "VND-0002",
|
||
contactName: "Sarah Kim",
|
||
contactEmail: "sarah@globalcrewsupplies.com",
|
||
address: "14B, Harbour Street, Mazgaon, Mumbai 400010",
|
||
isVerified: true,
|
||
},
|
||
});
|
||
|
||
await db.vendor.upsert({
|
||
where: { vendorId: "VND-0003" },
|
||
update: {},
|
||
create: {
|
||
name: "Atlas Ship Chandlers",
|
||
vendorId: "VND-0003",
|
||
contactName: "Marco Rossi",
|
||
contactEmail: "marco@atlaschandlers.com",
|
||
address: "Unit 7, Sassoon Dock, Colaba, Mumbai 400005",
|
||
isVerified: false,
|
||
},
|
||
});
|
||
|
||
await db.vendor.upsert({
|
||
where: { vendorId: "VND-0004" },
|
||
update: {},
|
||
create: {
|
||
name: "Apar Industries Ltd",
|
||
vendorId: "VND-0004",
|
||
contactName: "Nikhil Mumbaikar",
|
||
contactMobile: "7208055636",
|
||
contactEmail: "nikhil.mumbaikar@apar.com",
|
||
address: "18, TTC MIDC Industrial Area, Thane Belapur Road, Opp Rabale Railway Stn, Navi Mumbai 400701",
|
||
gstin: "27AAACG1840M1ZL",
|
||
isVerified: true,
|
||
},
|
||
});
|
||
|
||
await db.vendor.upsert({
|
||
where: { vendorId: "VND-0005" },
|
||
update: {},
|
||
create: {
|
||
name: "Neptune Marine Stores",
|
||
vendorId: "VND-0005",
|
||
contactName: "Ravi Sharma",
|
||
contactMobile: "9821234567",
|
||
contactEmail: "ravi@neptunemarine.in",
|
||
address: "B-204, Jogeshwari Industrial Estate, Mumbai 400060",
|
||
gstin: "27AADCN5678B1ZK",
|
||
isVerified: true,
|
||
},
|
||
});
|
||
|
||
await db.vendor.upsert({
|
||
where: { vendorId: "VND-0006" },
|
||
update: {},
|
||
create: {
|
||
name: "Seaview Hydraulics Pvt Ltd",
|
||
vendorId: "VND-0006",
|
||
contactName: "Anand Pillai",
|
||
contactMobile: "9867543210",
|
||
contactEmail: "anand@seaviewhydraulics.com",
|
||
address: "Plot 45, Phase II, Ambad MIDC, Nashik 422010",
|
||
gstin: "27AABCS9876C1ZM",
|
||
isVerified: true,
|
||
},
|
||
});
|
||
|
||
await db.vendor.upsert({
|
||
where: { vendorId: "VND-0007" },
|
||
update: {},
|
||
create: {
|
||
name: "Pacific Safety Equipment",
|
||
vendorId: "VND-0007",
|
||
contactName: "Priya Nair",
|
||
contactEmail: "priya@pacificsafety.com",
|
||
address: "22, Linking Road, Bandra West, Mumbai 400050",
|
||
isVerified: true,
|
||
},
|
||
});
|
||
|
||
await db.vendor.upsert({
|
||
where: { vendorId: "VND-0008" },
|
||
update: {},
|
||
create: {
|
||
name: "Mumbai Ship Stores",
|
||
vendorId: "VND-0008",
|
||
contactName: "Deepak Mehta",
|
||
contactMobile: "9876543210",
|
||
contactEmail: "deepak@mumbaishipstores.com",
|
||
address: "78, Ballard Estate, Fort, Mumbai 400001",
|
||
gstin: "27AAACM4567D1ZJ",
|
||
isVerified: true,
|
||
},
|
||
});
|
||
|
||
await db.vendor.upsert({
|
||
where: { vendorId: "VND-0009" },
|
||
update: {},
|
||
create: {
|
||
name: "Bharat Navigation Systems",
|
||
vendorId: "VND-0009",
|
||
contactName: "Suresh Kumar",
|
||
contactEmail: "suresh@bharatnav.in",
|
||
address: "67, M.G. Road, Pune 411001",
|
||
isVerified: false,
|
||
},
|
||
});
|
||
|
||
await db.vendor.upsert({
|
||
where: { vendorId: "VND-0010" },
|
||
update: {},
|
||
create: {
|
||
name: "Coastal Rope & Rigging",
|
||
vendorId: "VND-0010",
|
||
contactName: "James D'Souza",
|
||
contactMobile: "9823456789",
|
||
contactEmail: "james@coastalrope.com",
|
||
address: "Sector 12, Kandivali East, Mumbai 400101",
|
||
gstin: "27AABCC2345E1ZP",
|
||
isVerified: true,
|
||
},
|
||
});
|
||
|
||
await db.vendor.upsert({
|
||
where: { vendorId: "VND-0011" },
|
||
update: {},
|
||
create: {
|
||
name: "Indotech Filters & Fluids",
|
||
vendorId: "VND-0011",
|
||
contactName: "Meenakshi Srinivasan",
|
||
contactEmail: "msrinivasan@indotech.co.in",
|
||
address: "E-12, Peenya Industrial Area Phase 1, Bengaluru 560058",
|
||
gstin: "29AABCI5678F1ZL",
|
||
isVerified: true,
|
||
},
|
||
});
|
||
|
||
await db.vendor.upsert({
|
||
where: { vendorId: "VND-0012" },
|
||
update: {},
|
||
create: {
|
||
name: "Eastern Electro Marine",
|
||
vendorId: "VND-0012",
|
||
contactName: "Rahul Das",
|
||
contactMobile: "9432167890",
|
||
contactEmail: "rahul.das@easternelectro.com",
|
||
address: "12A, Strand Road, Kolkata 700001",
|
||
gstin: "19AABCE6789G1ZK",
|
||
isVerified: false,
|
||
},
|
||
});
|
||
|
||
// Products
|
||
const prod1 = await db.product.upsert({
|
||
where: { code: "PART-TURBO-SEAL" },
|
||
update: {},
|
||
create: {
|
||
code: "PART-TURBO-SEAL",
|
||
name: "Turbocharger Seal Kit",
|
||
description: "Replacement seal kit for main engine turbocharger",
|
||
lastPrice: 1200,
|
||
},
|
||
});
|
||
|
||
const prod2 = await db.product.upsert({
|
||
where: { code: "PART-FP-PUMP" },
|
||
update: {},
|
||
create: {
|
||
code: "PART-FP-PUMP",
|
||
name: "High-Pressure Fuel Pump",
|
||
description: "Main engine high-pressure fuel pump assembly",
|
||
lastPrice: 4800,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "SAFE-LIFEJKT" },
|
||
update: {},
|
||
create: {
|
||
code: "SAFE-LIFEJKT",
|
||
name: "Life Jacket (SOLAS)",
|
||
description: "SOLAS-approved adult life jacket",
|
||
lastPrice: 120,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "SAFE-EXTG-9KG" },
|
||
update: {},
|
||
create: {
|
||
code: "SAFE-EXTG-9KG",
|
||
name: "Fire Extinguisher 9kg",
|
||
description: "Dry powder fire extinguisher, 9kg",
|
||
lastPrice: 200,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "LUBE-EP80W90" },
|
||
update: {},
|
||
create: {
|
||
code: "LUBE-EP80W90",
|
||
name: "Gear Oil EP 80W90",
|
||
description: "Eni EP 80W90 gear oil for marine gearboxes",
|
||
lastPrice: 182,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "LUBE-HYD46" },
|
||
update: {},
|
||
create: {
|
||
code: "LUBE-HYD46",
|
||
name: "Hydraulic Oil ISO 46",
|
||
description: "Anti-wear hydraulic oil ISO VG 46 for deck machinery",
|
||
lastPrice: 155,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "LUBE-MEO30" },
|
||
update: {},
|
||
create: {
|
||
code: "LUBE-MEO30",
|
||
name: "Main Engine Oil SAE 30",
|
||
description: "Trunk piston engine oil SAE 30 for 4-stroke engines",
|
||
lastPrice: 210,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "FILT-OIL-ME" },
|
||
update: {},
|
||
create: {
|
||
code: "FILT-OIL-ME",
|
||
name: "Main Engine Lube Oil Filter",
|
||
description: "Spin-on lube oil filter for main engine",
|
||
lastPrice: 850,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "FILT-FUEL-ME" },
|
||
update: {},
|
||
create: {
|
||
code: "FILT-FUEL-ME",
|
||
name: "Main Engine Fuel Filter",
|
||
description: "Duplex fuel oil filter element for main engine",
|
||
lastPrice: 1100,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "FILT-AIR-ME" },
|
||
update: {},
|
||
create: {
|
||
code: "FILT-AIR-ME",
|
||
name: "Air Filter Element",
|
||
description: "Air cleaner filter element for main engine air intake",
|
||
lastPrice: 650,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "PART-ORING-ASST" },
|
||
update: {},
|
||
create: {
|
||
code: "PART-ORING-ASST",
|
||
name: "O-Ring Assortment Pack",
|
||
description: "Mixed O-ring kit with Nitrile and Viton rings, 500 pcs",
|
||
lastPrice: 250,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "PART-GASKET-SET" },
|
||
update: {},
|
||
create: {
|
||
code: "PART-GASKET-SET",
|
||
name: "Exhaust Gasket Set",
|
||
description: "Full set of exhaust manifold gaskets for main engine",
|
||
lastPrice: 3200,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "ELEC-LAMP-LED" },
|
||
update: {},
|
||
create: {
|
||
code: "ELEC-LAMP-LED",
|
||
name: "LED Navigation Lamp",
|
||
description: "SOLAS-compliant LED navigation light, white masthead",
|
||
lastPrice: 4500,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "ELEC-BATT-12V" },
|
||
update: {},
|
||
create: {
|
||
code: "ELEC-BATT-12V",
|
||
name: "Starting Battery 12V 100Ah",
|
||
description: "Sealed lead-acid starting battery for emergency equipment",
|
||
lastPrice: 6500,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "ELEC-CABLE-3C" },
|
||
update: {},
|
||
create: {
|
||
code: "ELEC-CABLE-3C",
|
||
name: "Marine Cable 3-Core 2.5mm²",
|
||
description: "Tinned copper 3-core marine electrical cable, per metre",
|
||
lastPrice: 85,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "ROPE-MOORING-40" },
|
||
update: {},
|
||
create: {
|
||
code: "ROPE-MOORING-40",
|
||
name: "Mooring Rope 40mm × 200m",
|
||
description: "3-strand polypropylene mooring rope, 40mm dia, 200m coil",
|
||
lastPrice: 18500,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "ROPE-PILOT-18" },
|
||
update: {},
|
||
create: {
|
||
code: "ROPE-PILOT-18",
|
||
name: "Pilot Ladder Rope 18mm",
|
||
description: "Manilla pilot ladder rope, 18mm, certified per metre",
|
||
lastPrice: 320,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "SAFE-IMMSUIT" },
|
||
update: {},
|
||
create: {
|
||
code: "SAFE-IMMSUIT",
|
||
name: "Immersion Suit (SOLAS)",
|
||
description: "SOLAS-approved adult immersion suit, insulated",
|
||
lastPrice: 5500,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "SAFE-EPIRB" },
|
||
update: {},
|
||
create: {
|
||
code: "SAFE-EPIRB",
|
||
name: "EPIRB (406 MHz)",
|
||
description: "Category I float-free EPIRB, 406 MHz COSPAS-SARSAT",
|
||
lastPrice: 45000,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "SAFE-FLARE-HAND" },
|
||
update: {},
|
||
create: {
|
||
code: "SAFE-FLARE-HAND",
|
||
name: "Hand Flare (SOLAS)",
|
||
description: "Red hand flare for distress signalling, pack of 6",
|
||
lastPrice: 1800,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "PAINT-ANTIFOUL" },
|
||
update: {},
|
||
create: {
|
||
code: "PAINT-ANTIFOUL",
|
||
name: "Antifouling Paint 20L",
|
||
description: "Self-polishing antifouling paint for hull below waterline",
|
||
lastPrice: 8200,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "PAINT-PRIMER" },
|
||
update: {},
|
||
create: {
|
||
code: "PAINT-PRIMER",
|
||
name: "Epoxy Primer 5L",
|
||
description: "Two-component epoxy primer for steel and aluminium surfaces",
|
||
lastPrice: 3400,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "TOOL-GRINDER-4" },
|
||
update: {},
|
||
create: {
|
||
code: "TOOL-GRINDER-4",
|
||
name: "Angle Grinder 4-inch",
|
||
description: "Heavy-duty 4-inch angle grinder, 850W, with guard",
|
||
lastPrice: 2800,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "CHART-INT-1" },
|
||
update: {},
|
||
create: {
|
||
code: "CHART-INT-1",
|
||
name: "INT Chart Folio Update",
|
||
description: "Annual update pack for navigational charts, Indian Ocean folio",
|
||
lastPrice: 950,
|
||
},
|
||
});
|
||
|
||
await db.product.upsert({
|
||
where: { code: "CHEM-BOWTREATER" },
|
||
update: {},
|
||
create: {
|
||
code: "CHEM-BOWTREATER",
|
||
name: "Boiler Water Treatment Chemical 25L",
|
||
description: "Liquid boiler water treatment and scale inhibitor",
|
||
lastPrice: 3600,
|
||
},
|
||
});
|
||
|
||
// Sample POs — upsert so re-running seed is safe
|
||
const po1 = await db.purchaseOrder.upsert({
|
||
where: { poNumber: "PO-2026-00001" },
|
||
update: { currency: "INR", totalAmount: 9971.0 },
|
||
create: {
|
||
poNumber: "PO-2026-00001",
|
||
title: "Engine Room Spare Parts — MV Pelagia Star",
|
||
status: "MGR_REVIEW",
|
||
totalAmount: 9971.0, // 8450 taxable × 1.18 GST
|
||
currency: "INR",
|
||
submittedAt: new Date(),
|
||
submitterId: technical.id,
|
||
vesselId: mv1.id,
|
||
accountId: acc1.id,
|
||
vendorId: vendor1.id,
|
||
lineItems: {
|
||
create: [
|
||
{ name: "Turbocharger seal kit", quantity: 2, unit: "set", unitPrice: 1200, totalPrice: 2400, sortOrder: 0, productId: prod1.id },
|
||
{ name: "High-pressure fuel pump", quantity: 1, unit: "pc", unitPrice: 4800, totalPrice: 4800, sortOrder: 1, productId: prod2.id },
|
||
{ name: "O-ring assortment pack", quantity: 5, unit: "pk", unitPrice: 250, totalPrice: 1250, sortOrder: 2 },
|
||
],
|
||
},
|
||
actions: {
|
||
create: [
|
||
{ actionType: "CREATED", actorId: technical.id },
|
||
{ actionType: "SUBMITTED", actorId: technical.id },
|
||
],
|
||
},
|
||
},
|
||
});
|
||
|
||
await db.purchaseOrder.upsert({
|
||
where: { poNumber: "PO-2026-00002" },
|
||
update: { currency: "INR", totalAmount: 3776.0 },
|
||
create: {
|
||
poNumber: "PO-2026-00002",
|
||
title: "Crew Safety Equipment — MV Aegean Wind",
|
||
status: "DRAFT",
|
||
totalAmount: 3776.0, // 3200 taxable × 1.18 GST
|
||
currency: "INR",
|
||
submitterId: technical.id,
|
||
vesselId: mv2.id,
|
||
accountId: acc2.id,
|
||
lineItems: {
|
||
create: [
|
||
{ name: "Life jackets (SOLAS)", quantity: 20, unit: "pc", unitPrice: 120, totalPrice: 2400, sortOrder: 0 },
|
||
{ name: "Fire extinguisher — 9kg", quantity: 4, unit: "pc", unitPrice: 200, totalPrice: 800, sortOrder: 1 },
|
||
],
|
||
},
|
||
actions: {
|
||
create: [{ actionType: "CREATED", actorId: technical.id }],
|
||
},
|
||
},
|
||
});
|
||
|
||
await db.purchaseOrder.upsert({
|
||
where: { poNumber: "PO-2026-00003" },
|
||
update: { currency: "INR", totalAmount: 1121.0 },
|
||
create: {
|
||
poNumber: "PO-2026-00003",
|
||
title: "Navigation Charts Update — Fleet",
|
||
status: "MGR_APPROVED",
|
||
totalAmount: 1121.0, // 950 taxable × 1.18 GST
|
||
currency: "INR",
|
||
submittedAt: new Date(Date.now() - 5 * 86400000),
|
||
approvedAt: new Date(Date.now() - 2 * 86400000),
|
||
submitterId: technical.id,
|
||
vesselId: mv1.id,
|
||
accountId: acc1.id,
|
||
lineItems: {
|
||
create: [
|
||
{ name: "INT chart folio update", quantity: 1, unit: "set", unitPrice: 950, totalPrice: 950, sortOrder: 0 },
|
||
],
|
||
},
|
||
actions: {
|
||
create: [
|
||
{ actionType: "CREATED", actorId: technical.id },
|
||
{ actionType: "SUBMITTED", actorId: technical.id },
|
||
{ actionType: "APPROVED", actorId: manager.id, note: "Approved — update due before next voyage." },
|
||
],
|
||
},
|
||
},
|
||
});
|
||
|
||
console.log("Seed complete.");
|
||
console.log("\nDev login credentials:");
|
||
console.log(" Admin: admin@pelagia.local / admin1234");
|
||
console.log(" Manager: manager@pelagia.local / manager1234");
|
||
console.log(" Tech: tech@pelagia.local / tech1234");
|
||
console.log(" Accounts: accounts@pelagia.local / accounts1234");
|
||
console.log(" Manning: manning@pelagia.local / manning1234");
|
||
}
|
||
|
||
main()
|
||
.catch((e) => {
|
||
console.error(e);
|
||
process.exit(1);
|
||
})
|
||
.finally(() => db.$disconnect());
|