feat(backend): update main entry and test DB utilities

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-06-18 16:26:50 +01:00
co-authored by Sisyphus
parent 2dbb1486b0
commit f7cc278423
2 changed files with 35 additions and 6 deletions
+28 -5
View File
@@ -127,12 +127,13 @@ func main() {
initDav()
initS3()
initSquare()
auth.StartJTICleanup()
r := chi.NewRouter()
// --- Global Middleware ---
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.ClientIPFromHeader("X-Real-IP"))
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.Timeout(15 * time.Second))
@@ -145,6 +146,23 @@ func main() {
w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
// TODO: Enable Referrer-Policy in production
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
w.Header().Set("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'")
// Reflect origin (not wildcard '*') so credentialed cross-origin
// requests with Authorization: Bearer work in browsers.
origin := r.Header.Get("Origin")
if origin != "" {
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Vary", "Origin")
}
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, Idempotency-Key")
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
return
}
next.ServeHTTP(w, r)
})
})
@@ -159,11 +177,11 @@ func main() {
r.Get("/services/eligible-for/{user_id}", services.ServicesEligibleForUserHandler)
})
// Registration: 10/min to prevent spam
r.With(mw.RateLimit(10, time.Minute), limitBody(defaultBodyLimit)).Post("/register", authHandlers.RegisterHandler)
// Registration: 10/min to prevent spam + progressive per-IP backoff
r.With(mw.ProgressiveRateLimit, mw.RateLimit(10, time.Minute), limitBody(defaultBodyLimit)).Post("/register", authHandlers.RegisterHandler)
// Login: Has its own internal rate limiting
r.With(mw.RateLimit(10, time.Minute), limitBody(defaultBodyLimit)).Post("/login", authHandlers.LoginHandler)
// Login: Has its own internal rate limiting + progressive per-IP backoff
r.With(mw.ProgressiveRateLimit, mw.RateLimit(10, time.Minute), limitBody(defaultBodyLimit)).Post("/login", authHandlers.LoginHandler)
// Logout: requires valid token
r.With(mw.RequireAuth).Post("/logout", authHandlers.LogoutHandler)
@@ -257,11 +275,16 @@ func main() {
// User payment routes
r.Post("/bookings/{id}/payment", payments.CreateBookingPayment)
r.Post("/bookings/{id}/apply-redemption", payments.ApplyLoyaltyRedemption)
r.Post("/bookings/{id}/payment-lock", payments.AcquirePaymentLock)
r.Delete("/bookings/{id}/payment-lock", payments.ReleasePaymentLock)
r.Get("/user/payment-methods", payments.GetUserPaymentMethods)
r.Post("/user/payment-methods", payments.CreatePaymentMethod)
r.Delete("/user/payment-methods/{id}", payments.DeletePaymentMethod)
r.Post("/bookings/{id}/tip", payments.CreateTipPayment)
r.Get("/bookings/{id}/payment-summary", payments.GetBookingPaymentSummary)
r.With(mw.RateLimit(10, time.Minute), limitBody(defaultBodyLimit)).
Get("/bookings/{id}/discount-preview", payments.GetDiscountPreviewHandler)
// User gift card routes
r.Post("/user/giftcards/redeem", payments.RedeemGiftCard)