feat: implement Iteration 0 foundation (backend + Flutter client)
Backend (Go): - Project structure with chi router, pgxpool, goose migrations - JWT auth (access/refresh tokens) with Firebase token verification - NoopTokenVerifier for local dev without Firebase credentials - PostgreSQL user repository with atomic profile updates (transactions) - Mifflin-St Jeor calorie calculation based on profile data - REST API: POST /auth/login, /auth/refresh, /auth/logout, GET/PUT /profile, GET /health - Middleware: auth, CORS (localhost wildcard), logging, recovery, request_id - Unit tests (51 passing) and integration tests (testcontainers) - Docker Compose setup with postgres healthcheck and graceful shutdown Flutter client: - Riverpod state management with GoRouter navigation - Firebase Auth (email/password + Google sign-in with web popup support) - Platform-aware API URLs (web/Android/iOS) - Dio HTTP client with JWT auth interceptor and concurrent refresh handling - Secure token storage - Screens: Login, Register, Home (tabs: Menu, Recipes, Products, Profile) - Unit tests (17 passing) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
61
backend/internal/server/server.go
Normal file
61
backend/internal/server/server.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/food-ai/backend/internal/auth"
|
||||
"github.com/food-ai/backend/internal/middleware"
|
||||
"github.com/food-ai/backend/internal/user"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func NewRouter(
|
||||
pool *pgxpool.Pool,
|
||||
authHandler *auth.Handler,
|
||||
userHandler *user.Handler,
|
||||
authMiddleware func(http.Handler) http.Handler,
|
||||
allowedOrigins []string,
|
||||
) *chi.Mux {
|
||||
r := chi.NewRouter()
|
||||
|
||||
// Global middleware
|
||||
r.Use(middleware.RequestID)
|
||||
r.Use(middleware.Logging)
|
||||
r.Use(middleware.Recovery)
|
||||
r.Use(middleware.CORS(allowedOrigins))
|
||||
|
||||
// Public
|
||||
r.Get("/health", healthCheck(pool))
|
||||
r.Route("/auth", func(r chi.Router) {
|
||||
r.Post("/login", authHandler.Login)
|
||||
r.Post("/refresh", authHandler.Refresh)
|
||||
r.Post("/logout", authHandler.Logout)
|
||||
})
|
||||
|
||||
// Protected
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(authMiddleware)
|
||||
r.Get("/profile", userHandler.Get)
|
||||
r.Put("/profile", userHandler.Update)
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func healthCheck(pool *pgxpool.Pool) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
dbStatus := "connected"
|
||||
if err := pool.Ping(r.Context()); err != nil {
|
||||
dbStatus = "disconnected"
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "ok",
|
||||
"version": "0.1.0",
|
||||
"db": dbStatus,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user