revert: drop the jupiter->Doormile telemetry bridge
Doormile should not be wired to jupiter's APIs at all. The ingest routes, the legacy identity middleware and the worker-side fan-out existed to copy jupiter's rider GPS into Doormile, which was never the goal: Doormile needs its own JetStream in front of its own endpoints, not a pipe from someone else's. Removed here: /internal/miler/* ingest, LegacyMilerIdentity, and the legacyuserid field on the miler update payload. The worker-side shadow forward and its k8s secret are removed separately in the Kubernetes repo; jupiter forwarding is untouched and verified still healthy. MilerProfile.Legacyuserid is deliberately kept. Nothing reads it now, but it records which jupiter rider each of the six migrated riders came from, which is worth having during the cutover. Dropping a populated column buys nothing and AutoMigrate would not drop it anyway. Kept from that work because they are unrelated to jupiter and fix real bugs: db.EnsureStreams (four subjects were publishing to no stream and being dropped silently) and the tenantlocationid column. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1843,11 +1843,6 @@ func UpdateMiler(c *fiber.Ctx) error {
|
||||
Displayname string `json:"displayname"`
|
||||
Defaultvehicletype string `json:"defaultvehicletype"`
|
||||
Hubid *int `json:"hubid"`
|
||||
// Legacyuserid links this rider to their old jupiter userid, so telemetry
|
||||
// still arriving over the jupiter NATS chain resolves to them. Writable
|
||||
// here because there is no other way to set it — the column is populated
|
||||
// by ops for migrated riders, never by the rider themselves.
|
||||
Legacyuserid *int `json:"legacyuserid"`
|
||||
}
|
||||
|
||||
req := new(MilerUpdate)
|
||||
@@ -1864,9 +1859,6 @@ func UpdateMiler(c *fiber.Ctx) error {
|
||||
if req.Hubid != nil {
|
||||
profile.Hubid = req.Hubid
|
||||
}
|
||||
if req.Legacyuserid != nil {
|
||||
profile.Legacyuserid = req.Legacyuserid
|
||||
}
|
||||
profile.Updatedat = time.Now()
|
||||
|
||||
if err := db.DB.Save(profile).Error; err != nil {
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"doormile/db"
|
||||
"doormile/models"
|
||||
"doormile/utils"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// LegacyMilerIdentity resolves a rider identity for machine-to-machine ingest
|
||||
// and puts it in c.Locals("userid"), which is exactly where the normal miler
|
||||
// handlers read it from. That is the whole point: the ingest routes reuse the
|
||||
// existing handlers unchanged rather than growing a parallel set with their own
|
||||
// (inevitably drifting) validation.
|
||||
//
|
||||
// It must be mounted *behind* InternalKeyAuth. On its own it is not
|
||||
// authentication — it names a rider, it does not prove anything about the
|
||||
// caller. The X-Internal-Key check is what makes that safe, and it is the reason
|
||||
// this cannot be reached from the public internet.
|
||||
//
|
||||
// Two headers, checked in order:
|
||||
//
|
||||
// X-Miler-Userid a Doormile userid, used directly
|
||||
// X-Legacy-Userid a jupiter/Nearle userid, resolved via MilerProfile.Legacyuserid
|
||||
//
|
||||
// The identity deliberately does NOT come from the request body. The miler
|
||||
// telemetry handlers overwrite any body-supplied userid with the token's, which
|
||||
// is what stops one rider writing another's GPS trail; taking it from the body
|
||||
// here would reopen that hole from behind the internal key. A header keeps the
|
||||
// rule intact and works for POST /consignments/logs, whose body is a bare JSON
|
||||
// array with nowhere to put an id anyway.
|
||||
func LegacyMilerIdentity(c *fiber.Ctx) error {
|
||||
if raw := c.Get("X-Miler-Userid"); raw != "" {
|
||||
userID, err := strconv.Atoi(raw)
|
||||
if err != nil || userID <= 0 {
|
||||
return utils.BadRequest(c, "invalid X-Miler-Userid")
|
||||
}
|
||||
|
||||
var count int64
|
||||
if err := db.DB.Model(&models.MilerProfile{}).
|
||||
Where("userid = ?", userID).Count(&count).Error; err != nil {
|
||||
return utils.Internal(c, "failed to resolve miler")
|
||||
}
|
||||
if count == 0 {
|
||||
return utils.NotFound(c, "no miler with that userid")
|
||||
}
|
||||
|
||||
c.Locals("userid", userID)
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
raw := c.Get("X-Legacy-Userid")
|
||||
if raw == "" {
|
||||
return utils.BadRequest(c, "X-Miler-Userid or X-Legacy-Userid header is required")
|
||||
}
|
||||
|
||||
legacyID, err := strconv.Atoi(raw)
|
||||
if err != nil || legacyID <= 0 {
|
||||
return utils.BadRequest(c, "invalid X-Legacy-Userid")
|
||||
}
|
||||
|
||||
var profile models.MilerProfile
|
||||
if err := db.DB.Where("legacyuserid = ?", legacyID).First(&profile).Error; err != nil {
|
||||
// Unmapped is the expected case for every rider who was never migrated
|
||||
// from jupiter, so this is a routine 404 rather than an error condition.
|
||||
// The forwarder treats it as "drop, do not retry" — retrying cannot
|
||||
// invent a mapping, and NAK-looping on it would wedge the consumer.
|
||||
return utils.NotFound(c, "no Doormile miler mapped to that legacy userid")
|
||||
}
|
||||
|
||||
c.Locals("userid", profile.Userid)
|
||||
return c.Next()
|
||||
}
|
||||
@@ -92,12 +92,11 @@ type MilerProfile struct {
|
||||
Profilephotourl string `json:"profilephotourl" gorm:"column:profilephotourl"`
|
||||
Vehicleid *int `json:"vehicleid" gorm:"column:vehicleid"`
|
||||
Hubid *int `json:"hubid" gorm:"column:hubid"`
|
||||
// Legacyuserid is this rider's userid in the old jupiter/Nearle system, for
|
||||
// riders migrated from it. It exists so telemetry still arriving over the
|
||||
// jupiter NATS chain — which identifies a rider by jupiter's userid and has
|
||||
// no Doormile token — can be resolved to a Doormile rider. Nil for riders
|
||||
// created natively in Doormile, which is the normal case. Never used for
|
||||
// authentication: it identifies, the X-Internal-Key authenticates.
|
||||
// Legacyuserid holds this rider's userid in the old jupiter system for the
|
||||
// six riders migrated from it. Nothing reads it any more — the jupiter
|
||||
// telemetry bridge it existed for was removed — but it is kept as a record
|
||||
// of where each migrated rider came from, which is worth having during the
|
||||
// cutover. Nil for riders created natively in Doormile.
|
||||
Legacyuserid *int `json:"legacyuserid,omitempty" gorm:"column:legacyuserid;index"`
|
||||
Defaultvehicletype string `json:"defaultvehicletype" gorm:"column:defaultvehicletype"`
|
||||
Currentlatitude float64 `json:"currentlatitude" gorm:"column:currentlatitude"`
|
||||
|
||||
@@ -417,23 +417,6 @@ func RegisterRoutes(app *fiber.App, cfg *config.Config) {
|
||||
internal.Get("/agent-decisions/similar", controllers.FindSimilarDecisions)
|
||||
internal.Patch("/agent-decisions/:id/outcome", controllers.UpdateDecisionOutcome)
|
||||
|
||||
// Rider telemetry ingest for the jupiter NATS chain. The forwarding worker
|
||||
// holds no rider JWT — the rider app is still jupiter-shaped and its token is
|
||||
// jupiter's — so identity arrives as a header and LegacyMilerIdentity turns
|
||||
// it into c.Locals("userid"). These are the *same handlers* the miler app
|
||||
// hits under /miler; only the way identity is established differs, so
|
||||
// validation and storage cannot drift between the two paths.
|
||||
//
|
||||
// Only fire-and-forget telemetry is exposed this way. Transactional actions
|
||||
// (pickup-complete, deliver, payment) are deliberately absent: the rider
|
||||
// needs a real answer from those, which a queue in front of them cannot give.
|
||||
ingest := internal.Group("/miler", middlewares.LegacyMilerIdentity)
|
||||
ingest.Post("/logs", controllers.CreateMilerPeriodicLog)
|
||||
ingest.Post("/status", controllers.CreateMilerStatus)
|
||||
ingest.Post("/consignments/logs", controllers.PublishConsignmentLogs)
|
||||
ingest.Post("/breaks/start", controllers.MilerStartBreak)
|
||||
ingest.Put("/breaks/end", controllers.MilerEndBreak)
|
||||
|
||||
// --------------------
|
||||
// WEBSOCKET — live miler tracking (no auth, public tracking link)
|
||||
// --------------------
|
||||
|
||||
Reference in New Issue
Block a user