feat(S2-a): ingest durable app MQTT points securely

This commit is contained in:
Brent Perteet
2026-08-20 15:22:40 -05:00
parent daa3407b9d
commit 8bcc12ec96
14 changed files with 979 additions and 59 deletions

View File

@@ -53,6 +53,22 @@ enum LocateMode {
SONDE
}
// Which producer a point originated from (telemetry-schema.md `origin`). Tagged now
// for SYN-6 path arbitration; no arbitration LOGIC runs yet (deferred, sprint-2 scope).
enum PointOrigin {
APP
LOCATOR
MAGLINK
}
// Which transport carried the point to the cloud (telemetry-schema.md `uploadPath`).
// Same forward-compat tagging as PointOrigin.
enum PointUploadPath {
APP_MQTT
DEVICE_MQTT
REST_BATCH
}
model Organization {
id String @id @default(cuid())
name String
@@ -185,6 +201,25 @@ model LocatePoint {
id BigInt @id @default(autoincrement())
jobId String
deviceId String?
// Client-generated UUIDv7, the idempotency key across every upload path
// (app MQTT, device-direct MQTT, REST batch — SRS §3.4.2 / telemetry-schema.md).
// A replayed UUID is ingested exactly once (unique constraint below). Nullable:
// the legacy device-direct path (LogIngest/PointsIngest) predates it and does not
// supply one yet; the app path (SYN-2) always does.
pointId String? @unique
// Provenance tags (telemetry-schema.md). Set on the app path now; carried for
// forward-compat with SYN-6 arbitration, which does not run yet.
origin PointOrigin @default(LOCATOR)
uploadPath PointUploadPath?
originClientId String?
// Event time asserted by the producer (record creation, telemetry-schema.md
// `createdAt`). Ingest orders and dedups by this, NOT by arrival (`receivedAt`),
// so replays and out-of-order delivery converge to the same stored ordering.
createdAt DateTime? @db.Timestamptz(6)
lat Decimal @db.Decimal(10, 8)
lng Decimal @db.Decimal(11, 8)
altitude Decimal? @db.Decimal(8, 3)
@@ -217,7 +252,11 @@ model LocatePoint {
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
device Device? @relation(fields: [deviceId], references: [id], onDelete: SetNull)
// (jobId, recordedAt) serves GPS-time reads; (jobId, createdAt) serves the
// event-time ordering the app path and portal read use (SRS-SYN-2). pointId is
// already uniquely indexed above — that index also backs the dedup lookup.
@@index([jobId, recordedAt])
@@index([jobId, createdAt])
@@map("locate_points")
}