Assignment decided who carried a booking but never what order to run several of them in -- the one capability jupiter had that Doormile did not. It turns out we already own the solver: routes.workolik.com is a live in-house Route Optimization API backed by Valhalla road-network routing, not the paid third party I had assumed. This is a client for it, not a solver. internal/routing posts a rider's active stops and writes back step, previouskms, cumulativekms and ETA onto BookingAssignment. HubBatchAssign calls it after committing a batch, which is exactly the case it exists for: a rider used to walk away with several bookings and no order to run them in. GetMilerAssignments now returns sequenced stops in step order, falling back to newest-first for anything unsequenced. Contract discovered by probing the live service -- the OpenAPI schema types the body as a bare object array, so the field names are not documented anywhere. They are pickuplat/pickuplong/deliverylat/ deliverylong, NOT pickuplatitude/deliverylatitude. Sending the wrong names does not fail: it returns HTTP 200 with every coordinate defaulted to "0.0", no reordering and all distances zero. That trap is recorded in a comment so the next person does not lose an afternoon to it. Numeric fields come back inconsistently typed -- previouskms as a number, actualkms and eta as strings, some decimal -- so they are decoded loosely and coerced, with tests pinning the coercion. Steps for deliveryids we did not send are discarded rather than written, so an echoed or stale id cannot reorder another rider's work. Sequencing is best-effort throughout and runs after assignments commit. The optimizer is a separate service over the network; it being down must leave bookings assigned but unordered, never undo the batch. Step 0 means "not sequenced", not "first". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
78 lines
2.6 KiB
Go
78 lines
2.6 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
)
|
|
|
|
type Config struct {
|
|
Env string
|
|
Port string
|
|
DBName string
|
|
DBUser string
|
|
DBPassword string
|
|
DBPort string
|
|
DBHost string
|
|
RedisHost string
|
|
RedisPort string
|
|
RedisUser string
|
|
RedisPassword string
|
|
JWTSecret string
|
|
NatsURL string
|
|
NatsUser string
|
|
NatsPassword string
|
|
AILayerBaseURL string // AI decision-engine service base URL (e.g. http://rider-api:8082)
|
|
|
|
// RouteOptimizerURL is the Route Optimization API that orders a rider's
|
|
// stops (Valhalla-backed road sequencing). Empty disables sequencing: stops
|
|
// stay unordered rather than assignment failing.
|
|
RouteOptimizerURL string
|
|
|
|
// TrustedProxies is a comma-separated list of reverse-proxy IPs/CIDRs that
|
|
// are allowed to set X-Forwarded-For. Rate limiting keys on the client IP,
|
|
// so behind a proxy this MUST be set — otherwise every request appears to
|
|
// come from the proxy and the whole fleet shares one limit bucket.
|
|
// Empty means "no proxy": the socket peer address is used as-is.
|
|
TrustedProxies string
|
|
SMTPHost string
|
|
SMTPPort string
|
|
SMTPUser string
|
|
SMTPPassword string
|
|
SMTPFrom string
|
|
}
|
|
|
|
func Load() *Config {
|
|
return &Config{
|
|
Env: getEnv("ENV", "development"),
|
|
Port: getEnv("APP_PORT", "8081"),
|
|
DBName: getEnv("DB_NAME", "logistics"),
|
|
DBUser: getEnv("DB_USER", "admin"),
|
|
DBPassword: getEnv("DB_PASSWORD", "Package@321#"),
|
|
DBPort: getEnv("DB_PORT", "5433"),
|
|
DBHost: getEnv("DB_HOST", "127.0.0.1"),
|
|
RedisHost: getEnv("REDIS_HOST", "127.0.0.1"),
|
|
RedisPort: getEnv("REDIS_PORT", "6379"),
|
|
RedisUser: getEnv("REDIS_USER", ""),
|
|
RedisPassword: getEnv("REDIS_PASSWORD", ""),
|
|
JWTSecret: getEnv("JWT_SECRET_KEY", "DoormileSuperSecretJWTKey2026!"),
|
|
NatsURL: getEnv("NATS_URL", "nats://66.116.226.161:4223"),
|
|
NatsUser: getEnv("NATS_USER", "doormile"),
|
|
NatsPassword: getEnv("NATS_PASSWORD", "Package@321#"),
|
|
AILayerBaseURL: getEnv("AI_LAYER_BASE_URL", "https://routemate.workolik.com"),
|
|
|
|
RouteOptimizerURL: getEnv("ROUTE_OPTIMIZER_URL", "https://routes.workolik.com"),
|
|
TrustedProxies: getEnv("TRUSTED_PROXIES", ""),
|
|
SMTPHost: getEnv("SMTP_HOST", ""),
|
|
SMTPPort: getEnv("SMTP_PORT", "465"),
|
|
SMTPUser: getEnv("SMTP_USER", ""),
|
|
SMTPPassword: getEnv("SMTP_PASSWORD", ""),
|
|
SMTPFrom: getEnv("SMTP_FROM", ""),
|
|
}
|
|
}
|
|
|
|
func getEnv(key, fallback string) string {
|
|
if v := os.Getenv(key); v != "" {
|
|
return v
|
|
}
|
|
return fallback
|
|
}
|