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>
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
-- Locator receiver telemetry + device identity by serial number.
|
||||
-- NOTE: hand-edited — Prisma's diff wanted to drop the geom GIST index and the
|
||||
-- generated-column expression on locate_points.geom; those statements were removed.
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "LocateMode" AS ENUM ('PEAK', 'NULL', 'BROAD_PEAK', 'SONDE');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "devices" ALTER COLUMN "mqttUsername" DROP NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "locate_points" ADD COLUMN "compassDeg" DECIMAL(5,2),
|
||||
ADD COLUMN "currentMa" DECIMAL(9,3),
|
||||
ADD COLUMN "distortionPct" DECIMAL(5,2),
|
||||
ADD COLUMN "frequencyHz" INTEGER,
|
||||
ADD COLUMN "gainDb" DECIMAL(6,2),
|
||||
ADD COLUMN "hdop" DECIMAL(4,2),
|
||||
ADD COLUMN "locateMode" "LocateMode",
|
||||
ADD COLUMN "phaseDeg" DECIMAL(6,2),
|
||||
ADD COLUMN "satellites" INTEGER,
|
||||
ADD COLUMN "signalDb" DECIMAL(6,2),
|
||||
ADD COLUMN "vAccuracy" DECIMAL(7,3);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "devices_orgId_serialNumber_key" ON "devices"("orgId", "serialNumber");
|
||||
@@ -45,6 +45,14 @@ enum GpsFixType {
|
||||
FIXED_RTK
|
||||
}
|
||||
|
||||
// EM locator receiver antenna mode used when the point was captured
|
||||
enum LocateMode {
|
||||
PEAK
|
||||
NULL
|
||||
BROAD_PEAK
|
||||
SONDE
|
||||
}
|
||||
|
||||
model Organization {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
@@ -116,12 +124,16 @@ model Job {
|
||||
@@map("jobs")
|
||||
}
|
||||
|
||||
// A device is either a locator receiver (identified by serialNumber, usually
|
||||
// auto-registered from incoming data) or an MQTT publisher (app/gateway with
|
||||
// broker credentials, identified by mqttUsername) — or both, when a locator
|
||||
// connects to the broker directly.
|
||||
model Device {
|
||||
id String @id @default(cuid())
|
||||
orgId String
|
||||
name String
|
||||
serialNumber String?
|
||||
mqttUsername String @unique
|
||||
mqttUsername String? @unique
|
||||
isActive Boolean @default(true)
|
||||
lastSeenAt DateTime? @db.Timestamptz(6)
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
@@ -130,6 +142,7 @@ model Device {
|
||||
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
|
||||
points LocatePoint[]
|
||||
|
||||
@@unique([orgId, serialNumber])
|
||||
@@map("devices")
|
||||
}
|
||||
|
||||
@@ -140,15 +153,31 @@ model LocatePoint {
|
||||
lat Decimal @db.Decimal(10, 8)
|
||||
lng Decimal @db.Decimal(11, 8)
|
||||
altitude Decimal? @db.Decimal(8, 3)
|
||||
fixType GpsFixType @default(NONE)
|
||||
hAccuracy Decimal? @db.Decimal(7, 3)
|
||||
depth Decimal? @db.Decimal(6, 3)
|
||||
utilityType UtilityType @default(UNKNOWN)
|
||||
sequence Int?
|
||||
recordedAt DateTime @db.Timestamptz(6)
|
||||
receivedAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
raw Json?
|
||||
geom Unsupported("geometry(Point, 4326)")?
|
||||
|
||||
// GPS quality
|
||||
fixType GpsFixType @default(NONE)
|
||||
hAccuracy Decimal? @db.Decimal(7, 3) // meters
|
||||
vAccuracy Decimal? @db.Decimal(7, 3) // meters
|
||||
satellites Int?
|
||||
hdop Decimal? @db.Decimal(4, 2)
|
||||
|
||||
// Locator receiver telemetry
|
||||
depth Decimal? @db.Decimal(6, 3) // meters below grade
|
||||
frequencyHz Int? // active/passive locate frequency
|
||||
currentMa Decimal? @db.Decimal(9, 3) // signal current on the line
|
||||
signalDb Decimal? @db.Decimal(6, 2) // signal strength
|
||||
gainDb Decimal? @db.Decimal(6, 2) // receiver gain
|
||||
locateMode LocateMode?
|
||||
phaseDeg Decimal? @db.Decimal(6, 2)
|
||||
compassDeg Decimal? @db.Decimal(5, 2) // line direction, 0-360
|
||||
distortionPct Decimal? @db.Decimal(5, 2)
|
||||
|
||||
recordedAt DateTime @db.Timestamptz(6)
|
||||
receivedAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
raw Json?
|
||||
geom Unsupported("geometry(Point, 4326)")?
|
||||
|
||||
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
||||
device Device? @relation(fields: [deviceId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PrismaClient, GpsFixType, JobStatus, UtilityType } from '@prisma/client';
|
||||
import { PrismaClient, GpsFixType, JobStatus, LocateMode, UtilityType } from '@prisma/client';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
@@ -68,7 +68,17 @@ async function main() {
|
||||
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),
|
||||
|
||||
Reference in New Issue
Block a user