Files
food-ai/backend/cmd/server/providers.go
dbastrikin 6594013b53 refactor: introduce internal/domain/ layer, rename model.go → entity.go
Move all business-logic packages from internal/ root into internal/domain/:
  auth, cuisine, diary, dish, home, ingredient, language, menu, product,
  recipe, recognition, recommendation, savedrecipe, tag, units, user

Rename model.go → entity.go in packages that hold domain entities:
  diary, dish, home, ingredient, menu, product, recipe, savedrecipe, user

Update all import paths accordingly (adapters, infra/server, cmd/server,
tests). No logic changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 22:12:07 +02:00

205 lines
7.0 KiB
Go

package main
import (
"net/http"
"time"
"github.com/food-ai/backend/internal/domain/auth"
"github.com/food-ai/backend/internal/infra/config"
"github.com/food-ai/backend/internal/domain/diary"
"github.com/food-ai/backend/internal/domain/dish"
"github.com/food-ai/backend/internal/adapters/openai"
"github.com/food-ai/backend/internal/domain/home"
"github.com/food-ai/backend/internal/domain/ingredient"
"github.com/food-ai/backend/internal/domain/menu"
"github.com/food-ai/backend/internal/infra/middleware"
"github.com/food-ai/backend/internal/adapters/pexels"
"github.com/food-ai/backend/internal/domain/product"
"github.com/food-ai/backend/internal/domain/recipe"
"github.com/food-ai/backend/internal/domain/recognition"
"github.com/food-ai/backend/internal/domain/recommendation"
"github.com/food-ai/backend/internal/domain/savedrecipe"
"github.com/food-ai/backend/internal/domain/cuisine"
"github.com/food-ai/backend/internal/infra/server"
"github.com/food-ai/backend/internal/domain/tag"
"github.com/food-ai/backend/internal/domain/units"
"github.com/food-ai/backend/internal/domain/user"
"github.com/jackc/pgx/v5/pgxpool"
)
// ---------------------------------------------------------------------------
// Newtypes for config primitives — prevents Wire type collisions.
// ---------------------------------------------------------------------------
// Newtypes for list handlers — prevents Wire type collisions on http.HandlerFunc.
type unitsListHandler http.HandlerFunc
type cuisineListHandler http.HandlerFunc
type tagListHandler http.HandlerFunc
// ---------------------------------------------------------------------------
type openaiAPIKey string
type pexelsAPIKey string
type jwtSecret string
type jwtAccessDuration time.Duration
type jwtRefreshDuration time.Duration
type allowedOrigins []string
// ---------------------------------------------------------------------------
// Config extractors
// ---------------------------------------------------------------------------
func newOpenAIAPIKey(appConfig *config.Config) openaiAPIKey {
return openaiAPIKey(appConfig.OpenAIAPIKey)
}
func newPexelsAPIKey(appConfig *config.Config) pexelsAPIKey {
return pexelsAPIKey(appConfig.PexelsAPIKey)
}
func newJWTSecret(appConfig *config.Config) jwtSecret {
return jwtSecret(appConfig.JWTSecret)
}
func newJWTAccessDuration(appConfig *config.Config) jwtAccessDuration {
return jwtAccessDuration(appConfig.JWTAccessDuration)
}
func newJWTRefreshDuration(appConfig *config.Config) jwtRefreshDuration {
return jwtRefreshDuration(appConfig.JWTRefreshDuration)
}
func newAllowedOrigins(appConfig *config.Config) allowedOrigins {
return allowedOrigins(appConfig.AllowedOrigins)
}
// newFirebaseCredentialsFile is the only string that reaches NewFirebaseAuthOrNoop,
// so no newtype is needed here.
func newFirebaseCredentialsFile(appConfig *config.Config) string {
return appConfig.FirebaseCredentialsFile
}
// ---------------------------------------------------------------------------
// Constructor wrappers for functions that accept primitive newtypes
// ---------------------------------------------------------------------------
func newOpenAIClient(key openaiAPIKey) *openai.Client {
return openai.NewClient(string(key))
}
func newPexelsClient(key pexelsAPIKey) *pexels.Client {
return pexels.NewClient(string(key))
}
func newJWTManager(
secret jwtSecret,
accessDuration jwtAccessDuration,
refreshDuration jwtRefreshDuration,
) *auth.JWTManager {
return auth.NewJWTManager(string(secret), time.Duration(accessDuration), time.Duration(refreshDuration))
}
// ---------------------------------------------------------------------------
// List handler providers
// ---------------------------------------------------------------------------
func newUnitsListHandler(pool *pgxpool.Pool) unitsListHandler {
return unitsListHandler(units.NewListHandler(pool))
}
func newCuisineListHandler(pool *pgxpool.Pool) cuisineListHandler {
return cuisineListHandler(cuisine.NewListHandler(pool))
}
func newTagListHandler(pool *pgxpool.Pool) tagListHandler {
return tagListHandler(tag.NewListHandler(pool))
}
// ---------------------------------------------------------------------------
// newRouter wraps server.NewRouter to accept newtypes.
func newRouter(
pool *pgxpool.Pool,
authHandler *auth.Handler,
userHandler *user.Handler,
recommendationHandler *recommendation.Handler,
savedRecipeHandler *savedrecipe.Handler,
ingredientHandler *ingredient.Handler,
productHandler *product.Handler,
recognitionHandler *recognition.Handler,
menuHandler *menu.Handler,
diaryHandler *diary.Handler,
homeHandler *home.Handler,
dishHandler *dish.Handler,
recipeHandler *recipe.Handler,
authMiddleware func(http.Handler) http.Handler,
origins allowedOrigins,
unitsHandler unitsListHandler,
cuisineHandler cuisineListHandler,
tagHandler tagListHandler,
) http.Handler {
return server.NewRouter(
pool,
authHandler,
userHandler,
recommendationHandler,
savedRecipeHandler,
ingredientHandler,
productHandler,
recognitionHandler,
menuHandler,
diaryHandler,
homeHandler,
dishHandler,
recipeHandler,
authMiddleware,
[]string(origins),
http.HandlerFunc(unitsHandler),
http.HandlerFunc(cuisineHandler),
http.HandlerFunc(tagHandler),
)
}
// ---------------------------------------------------------------------------
// jwtAdapter — adapts *auth.JWTManager to middleware.AccessTokenValidator.
// ---------------------------------------------------------------------------
type jwtAdapter struct {
jwtManager *auth.JWTManager
}
func newJWTAdapter(jm *auth.JWTManager) *jwtAdapter {
return &jwtAdapter{jwtManager: jm}
}
func (adapter *jwtAdapter) ValidateAccessToken(tokenStr string) (*middleware.TokenClaims, error) {
claims, validationError := adapter.jwtManager.ValidateAccessToken(tokenStr)
if validationError != nil {
return nil, validationError
}
return &middleware.TokenClaims{
UserID: claims.UserID,
Plan: claims.Plan,
}, nil
}
// newAuthMiddleware wraps middleware.Auth for Wire injection.
func newAuthMiddleware(validator middleware.AccessTokenValidator) func(http.Handler) http.Handler {
return middleware.Auth(validator)
}
// ---------------------------------------------------------------------------
// Interface assertions (compile-time checks)
// ---------------------------------------------------------------------------
var _ middleware.AccessTokenValidator = (*jwtAdapter)(nil)
var _ menu.PhotoSearcher = (*pexels.Client)(nil)
var _ menu.UserLoader = (*user.Repository)(nil)
var _ menu.ProductLister = (*product.Repository)(nil)
var _ menu.RecipeSaver = (*dish.Repository)(nil)
var _ recommendation.PhotoSearcher = (*pexels.Client)(nil)
var _ recommendation.UserLoader = (*user.Repository)(nil)
var _ recommendation.ProductLister = (*product.Repository)(nil)
var _ recognition.IngredientRepository = (*ingredient.Repository)(nil)
var _ user.UserRepository = (*user.Repository)(nil)