backend requirements onthe xustomer app

This commit is contained in:
2026-09-07 10:55:11 +05:30
parent 35675d8a9b
commit 1b2690b21a
56 changed files with 13342 additions and 1071 deletions

View File

@@ -47,6 +47,19 @@ func Migrate(db *gorm.DB) error {
&models.MilerDutyLog{},
&models.MilerBreakLog{},
&models.MilerSupportTicket{},
// Customer app (doormile_cx). All additive: new tables plus new
// nullable/zero-default columns on pickupbookings, so an existing row
// and every console-created booking stay valid with no backfill.
&models.ServiceableState{},
&models.ServiceableDistrict{},
&models.PickupSlotTemplate{},
&models.CustomerBookingLimit{},
&models.BookingDestination{},
&models.BookingParcelPhoto{},
&models.BookingStageEvent{},
&models.CustomerRefreshToken{},
&models.CustomerDevice{},
)
if err != nil {
@@ -94,5 +107,47 @@ func Migrate(db *gorm.DB) error {
utils.Info("✅ consignments_status_check constraint includes Collected_By_Miler")
}
// Human-facing identifiers for the customer app: DM-###### for a pickup
// booking, DMX######## for an order. Sequence-backed rather than random,
// because both columns are UNIQUE and a random short id collides long
// before a short id runs out — a collision here is a failed booking at the
// moment of payment, not a retry.
//
// No CYCLE and no MAXVALUE on purpose: past 999999 the format simply grows
// a digit (DM-1000000) instead of wrapping onto an id that already exists.
// Existing rows keep their old DM-BK-/DM-TRK- strings; nothing parses
// either format, so the two coexist safely.
if res := db.Exec(`CREATE SEQUENCE IF NOT EXISTS cx_booking_reference_seq START 100000 INCREMENT 1`); res.Error != nil {
utils.Error("❌ Failed to create cx_booking_reference_seq", "error", res.Error)
} else {
utils.Info("✅ cx_booking_reference_seq ready")
}
if res := db.Exec(`CREATE SEQUENCE IF NOT EXISTS cx_tracking_seq START 10000000 INCREMENT 1`); res.Error != nil {
utils.Error("❌ Failed to create cx_tracking_seq", "error", res.Error)
} else {
utils.Info("✅ cx_tracking_seq ready")
}
// One booking must not hold two destinations at the same position: the
// customer addresses a destination by index in
// PATCH /customer/bookings/{ref}/destinations/{index}, so a duplicate seq
// makes that route ambiguous and would let an edit land on the wrong
// address.
if res := db.Exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_bookingdestinations_booking_seq
ON bookingdestinations (bookingid, seq)`); res.Error != nil {
utils.Error("❌ Failed to create bookingdestinations (bookingid, seq) unique index", "error", res.Error)
} else {
utils.Info("✅ bookingdestinations (bookingid, seq) unique index ready")
}
// The timeline is read as "every event for this booking, oldest first" on
// every tracking poll, which is the hottest customer read there is.
if res := db.Exec(`CREATE INDEX IF NOT EXISTS idx_bookingstageevents_booking_time
ON bookingstageevents (bookingid, occurredat)`); res.Error != nil {
utils.Error("❌ Failed to create bookingstageevents (bookingid, occurredat) index", "error", res.Error)
} else {
utils.Info("✅ bookingstageevents (bookingid, occurredat) index ready")
}
return nil
}