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

@@ -27,6 +27,17 @@ type Config struct {
// stay unordered rather than assignment failing.
RouteOptimizerURL string
// GeocoderURL is the Nominatim-compatible geocoding service the customer
// app'''s place search and reverse geocode are proxied through. Proxied on
// purpose: the legacy rider app shipped a Google Maps key inside the
// binary and it had to be revoked, so the customer app is never handed a
// key at all — it asks this service and this service asks the geocoder.
GeocoderURL string
// GeocoderEmail is the contact address Nominatim'''s usage policy asks
// callers to identify themselves with. Sent as the User-Agent contact;
// requests without one are throttled or blocked.
GeocoderEmail 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
@@ -60,6 +71,8 @@ func Load() *Config {
AILayerBaseURL: getEnv("AI_LAYER_BASE_URL", "https://routemate.workolik.com"),
RouteOptimizerURL: getEnv("ROUTE_OPTIMIZER_URL", "https://routes.workolik.com"),
GeocoderURL: getEnv("GEOCODER_URL", "https://nominatim.openstreetmap.org"),
GeocoderEmail: getEnv("GEOCODER_EMAIL", ""),
TrustedProxies: getEnv("TRUSTED_PROXIES", ""),
SMTPHost: getEnv("SMTP_HOST", ""),
SMTPPort: getEnv("SMTP_PORT", "465"),

92
config/config_test.go Normal file
View File

@@ -0,0 +1,92 @@
package config
import (
"os"
"testing"
)
// Config is read once at startup, so a mistyped env key fails silently: the
// service boots on a default and points at the wrong host, or ships with a
// security switch left off. Cheap to pin.
func setEnv(t *testing.T, key, value string) {
t.Helper()
previous, had := os.LookupEnv(key)
if value == "" {
_ = os.Unsetenv(key)
} else {
_ = os.Setenv(key, value)
}
t.Cleanup(func() {
if had {
_ = os.Setenv(key, previous)
} else {
_ = os.Unsetenv(key)
}
})
}
// The geocoder settings added for the customer app. GEOCODER_URL is what the
// place search proxies through — the app is never handed a map key, after the
// legacy rider app's key had to be revoked.
func TestGeocoderDefaultsAndOverrides(t *testing.T) {
setEnv(t, "GEOCODER_URL", "")
setEnv(t, "GEOCODER_EMAIL", "")
cfg := Load()
if cfg.GeocoderURL != "https://nominatim.openstreetmap.org" {
t.Errorf("GeocoderURL default = %q, want the Nominatim host", cfg.GeocoderURL)
}
if cfg.GeocoderEmail != "" {
t.Errorf("GeocoderEmail default = %q, want empty", cfg.GeocoderEmail)
}
setEnv(t, "GEOCODER_URL", "https://nominatim.internal")
setEnv(t, "GEOCODER_EMAIL", "ops@doormile.com")
cfg = Load()
if cfg.GeocoderURL != "https://nominatim.internal" {
t.Errorf("GEOCODER_URL was not read: got %q", cfg.GeocoderURL)
}
if cfg.GeocoderEmail != "ops@doormile.com" {
t.Errorf("GEOCODER_EMAIL was not read: got %q", cfg.GeocoderEmail)
}
}
// Every env key the service reads must actually take effect. A typo in the key
// name means the override is ignored and the default is used — which is how a
// deploy silently points at the wrong database.
func TestEnvironmentOverridesAreRead(t *testing.T) {
cases := []struct {
key string
value string
read func(*Config) string
}{
{"ENV", "production", func(c *Config) string { return c.Env }},
{"APP_PORT", "9999", func(c *Config) string { return c.Port }},
{"DB_HOST", "db.internal", func(c *Config) string { return c.DBHost }},
{"DB_NAME", "logistics_staging", func(c *Config) string { return c.DBName }},
{"DB_PORT", "6543", func(c *Config) string { return c.DBPort }},
{"REDIS_HOST", "redis.internal", func(c *Config) string { return c.RedisHost }},
{"JWT_SECRET_KEY", "a-different-secret", func(c *Config) string { return c.JWTSecret }},
{"TRUSTED_PROXIES", "10.0.0.0/8", func(c *Config) string { return c.TrustedProxies }},
{"AI_LAYER_BASE_URL", "http://ai.internal", func(c *Config) string { return c.AILayerBaseURL }},
{"ROUTE_OPTIMIZER_URL", "http://routes.internal", func(c *Config) string { return c.RouteOptimizerURL }},
}
for _, tc := range cases {
setEnv(t, tc.key, tc.value)
if got := tc.read(Load()); got != tc.value {
t.Errorf("%s set to %q but Load() read %q", tc.key, tc.value, got)
}
}
}
// An empty env var must fall through to the default rather than blanking the
// setting — an empty DB host is a service that cannot start with no clue why.
func TestEmptyEnvFallsBackToTheDefault(t *testing.T) {
setEnv(t, "DB_NAME", "")
if got := Load().DBName; got == "" {
t.Error("DBName is empty when DB_NAME is unset; a default is required")
}
}