Files
doormile_backend/main.go
Suriya a2b9268189 fix: miler assignment lifecycle, pickup hub resolution, and hyperlocal delivery
Bugs found during live Coimbatore testing against production:

- GetMilerAssignments returned every assignment ever made to a miler with
  no status filter, so weeks-old Rejected assignments still showed up as
  actionable in the app. Now filters to Assigned/Accepted only.
- AcceptMilerAssignment overwrote assignmentstatus unconditionally, letting
  a stale Rejected assignment be silently reactivated (and pushing its
  booking back to Pickup_Scheduled). Now 400s unless currently Assigned,
  reporting the actual status.
- RejectMilerAssignment read `reason` from the query string instead of the
  JSON body, contradicting the API contract and every sibling endpoint.
- BookingPickupComplete resolved the origin hub via db.First(&hub) with no
  Where clause — i.e. the lowest hub ID in the table, unrelated to the
  booking or miler. Now uses the miler's own MilerProfile.Hubid, falling
  back to the old behaviour with a warning only when unassigned.
- No code path ever set a consignment to Out_for_Delivery, making
  MilerDeliverConsignment unreachable. BookingPickupComplete now goes
  straight to Out_for_Delivery when pickup and delivery pincodes share a
  3-digit postal-area prefix (same-miler hyperlocal), reusing the
  hubPincodePrefix convention. Cross-hub still lands at Inwarded_at_Hub.

Also allow https://app.doormile.com in CORS, and drop a stray Windows-path
log file that was committed by accident.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 11:04:01 +05:30

100 lines
2.4 KiB
Go

package main
import (
"os"
"os/signal"
"syscall"
"time"
"doormile/config"
"doormile/controllers"
"doormile/db"
"doormile/internal/notify"
"doormile/internal/worker"
"doormile/middlewares"
"doormile/migrations"
"doormile/routes"
"doormile/utils"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/joho/godotenv"
)
func main() {
// 1. Load configuration env variables
_ = godotenv.Load()
cfg := config.Load()
utils.Info("Starting Doormile Backend...")
// 2. Connect to Postgres, Redis & NATS
db.Connect(cfg)
db.InitRedis(cfg)
db.InitNATS(cfg)
notify.InitFCM()
// 3. Run GORM migrations for logistics tables
if db.DB != nil {
err := migrations.Migrate(db.DB)
if err != nil {
utils.Error("⚠️ Migration failed, continuing server boot...", "error", err.Error())
}
}
// 4. Initialize Fiber App
app := fiber.New(fiber.Config{
AppName: "Doormile Logistics Service API v1",
})
// CORS policy
app.Use(cors.New(cors.Config{
AllowHeaders: "Origin,Content-Type,Accept,Authorization",
AllowOrigins: "http://localhost:5173,http://localhost:5174,http://localhost:3000,http://localhost:3001,http://localhost:3002,http://localhost:8080,http://localhost:8081,https://doormile.com,https://www.doormile.com,https://admin.doormile.com,https://api.doormile.com,https://crm.doormile.com,https://console.doormile.com,https://app.doormile.com",
AllowCredentials: true,
AllowMethods: "GET,POST,PUT,DELETE,PATCH,OPTIONS",
}))
// Structured Zap logger middleware
app.Use(middlewares.ZapLogger())
// 5. Register routes
routes.RegisterRoutes(app, cfg)
// 6. Pre-warm Redis pricing cache from Postgres
controllers.WarmPricingCache()
// 7. Start NATS booking worker in background
go worker.StartBookingWorker()
// 7. Startup server in a background thread
go func() {
utils.Info("Server starting", "port", cfg.Port)
if err := app.Listen(":" + cfg.Port); err != nil {
utils.Logger.Fatalf("Server failed to bind: %v", err)
}
}()
// Graceful shutdown listener
gracefulShutdown(app)
}
func gracefulShutdown(app *fiber.App) {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c
utils.Info("Shutting down Doormile Backend...")
// Shutdown fiber
if err := app.Shutdown(); err != nil {
utils.Error("Fiber shutdown failed", "error", err)
}
// Close database pools
db.CloseDB()
time.Sleep(1 * time.Second)
utils.Info("Shutdown completed cleanly.")
}