Files
ulweb/backend/prisma/seed.ts
ulhub 21f5a04133 Tie points to locator serial numbers and store receiver telemetry
Field setups often relay through a phone/gateway that owns the MQTT
connection, so the publishing credential and the instrument are now
separate concepts:

- Points messages carry a "serial" identifying the locator receiver;
  unknown serials are auto-registered as devices in the publisher's
  org (name "Locator <serial>"). Device.mqttUsername is now optional
  and serialNumber is unique per org.
- LocatePoint gains standard receiver telemetry: frequencyHz,
  currentMa, signalDb, gainDb, locateMode (PEAK/NULL/BROAD_PEAK/SONDE),
  phaseDeg, compassDeg, distortionPct, plus GPS quality columns
  vAccuracy, satellites, hdop. All optional; raw payload still kept.
- Migration hand-edited to preserve the generated geom column and its
  GIST index (Prisma diff wanted to drop both).
- REST create/point DTOs, map tooltips, job-detail latest-point
  readout, devices settings form, seed, and the sample publisher all
  carry the new fields.
- Added .dockerignore for backend/web: COPY . . was clobbering the
  image's freshly generated Prisma client with the host's stale
  node_modules, breaking image builds after schema changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 14:58:12 +00:00

99 lines
2.8 KiB
TypeScript

import { PrismaClient, GpsFixType, JobStatus, LocateMode, UtilityType } from '@prisma/client';
import * as bcrypt from 'bcryptjs';
const prisma = new PrismaClient();
const SEED_ADMIN_EMAIL = 'brent.perteet@gmail.com';
const SEED_ADMIN_PASSWORD = 'changeme123';
async function main() {
const org = await prisma.organization.upsert({
where: { slug: 'umagul' },
update: {},
create: { name: 'Umagul', slug: 'umagul' },
});
const admin = await prisma.user.upsert({
where: { email: SEED_ADMIN_EMAIL },
update: {},
create: {
email: SEED_ADMIN_EMAIL,
name: 'Brent Perteet',
passwordHash: await bcrypt.hash(SEED_ADMIN_PASSWORD, 12),
},
});
await prisma.orgMembership.upsert({
where: { orgId_userId: { orgId: org.id, userId: admin.id } },
update: { role: 'ORG_ADMIN' },
create: { orgId: org.id, userId: admin.id, role: 'ORG_ADMIN' },
});
const device = await prisma.device.upsert({
where: { mqttUsername: 'testuser' },
update: {},
create: {
orgId: org.id,
name: 'Demo locator',
mqttUsername: 'testuser',
serialNumber: 'DEMO-0001',
},
});
const job = await prisma.job.upsert({
where: { orgId_ticketNumber: { orgId: org.id, ticketNumber: 'TKT-2026-0001' } },
update: {},
create: {
orgId: org.id,
ticketNumber: 'TKT-2026-0001',
title: 'Gas line locate - Main St demo',
description: 'Seeded demo job with sample RTK points along a gas line.',
address: '100 Main St',
status: JobStatus.IN_PROGRESS,
createdById: admin.id,
assignedToId: admin.id,
},
});
const existing = await prisma.locatePoint.count({ where: { jobId: job.id } });
if (existing === 0) {
// A short run of points along a line (roughly northeast, ~1.5m spacing)
const startLat = 33.15012345;
const startLng = -96.83512345;
const points = Array.from({ length: 12 }, (_, i) => ({
jobId: job.id,
deviceId: device.id,
lat: startLat + i * 0.0000135,
lng: startLng + i * 0.0000042,
altitude: 187.4 + i * 0.02,
fixType: GpsFixType.FIXED_RTK,
hAccuracy: 0.014,
vAccuracy: 0.021,
satellites: 22,
hdop: 0.7,
depth: 1.2,
frequencyHz: 33000,
currentMa: 48.5 - i * 0.4,
signalDb: 62.1 - i * 0.3,
gainDb: 40,
locateMode: LocateMode.PEAK,
compassDeg: 17.5,
distortionPct: 4.2,
utilityType: UtilityType.GAS,
sequence: i + 1,
recordedAt: new Date(Date.now() - (12 - i) * 5000),
}));
await prisma.locatePoint.createMany({ data: points });
}
console.log(`Seeded org=${org.slug} admin=${admin.email} device=${device.mqttUsername} job=${job.ticketNumber}`);
console.log(`Admin password: ${SEED_ADMIN_PASSWORD}`);
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(() => prisma.$disconnect());