feat: implement CORS and externalize payments config
This commit is contained in:
parent
42f72f5f43
commit
fc4e3df02d
6 changed files with 62 additions and 17 deletions
7
backend/.env.example
Normal file
7
backend/.env.example
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
DATABASE_URL=postgres://user:password@host:port/dbname?sslmode=disable
|
||||||
|
PORT=8080
|
||||||
|
DB_MAX_OPEN_CONNS=25
|
||||||
|
DB_MAX_IDLE_CONNS=25
|
||||||
|
DB_CONN_MAX_IDLE=15m
|
||||||
|
MERCADOPAGO_BASE_URL=https://api.mercadopago.com
|
||||||
|
MARKETPLACE_COMMISSION=2.5
|
||||||
|
|
@ -9,24 +9,28 @@ import (
|
||||||
|
|
||||||
// Config centralizes runtime configuration loaded from the environment.
|
// Config centralizes runtime configuration loaded from the environment.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
AppName string
|
AppName string
|
||||||
Port string
|
Port string
|
||||||
DatabaseURL string
|
DatabaseURL string
|
||||||
MaxOpenConns int
|
MaxOpenConns int
|
||||||
MaxIdleConns int
|
MaxIdleConns int
|
||||||
ConnMaxIdle time.Duration
|
ConnMaxIdle time.Duration
|
||||||
|
MercadoPagoBaseURL string
|
||||||
|
MarketplaceCommission float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load reads configuration from environment variables and applies sane defaults
|
// Load reads configuration from environment variables and applies sane defaults
|
||||||
// for local development.
|
// for local development.
|
||||||
func Load() Config {
|
func Load() Config {
|
||||||
cfg := Config{
|
cfg := Config{
|
||||||
AppName: getEnv("APP_NAME", "saveinmed-performance-core"),
|
AppName: getEnv("APP_NAME", "saveinmed-performance-core"),
|
||||||
Port: getEnv("PORT", "8080"),
|
Port: getEnv("PORT", "8080"),
|
||||||
DatabaseURL: getEnv("DATABASE_URL", "postgres://postgres:postgres@localhost:5432/saveinmed?sslmode=disable"),
|
DatabaseURL: getEnv("DATABASE_URL", "postgres://postgres:postgres@localhost:5432/saveinmed?sslmode=disable"),
|
||||||
MaxOpenConns: getEnvInt("DB_MAX_OPEN_CONNS", 15),
|
MaxOpenConns: getEnvInt("DB_MAX_OPEN_CONNS", 15),
|
||||||
MaxIdleConns: getEnvInt("DB_MAX_IDLE_CONNS", 5),
|
MaxIdleConns: getEnvInt("DB_MAX_IDLE_CONNS", 5),
|
||||||
ConnMaxIdle: getEnvDuration("DB_CONN_MAX_IDLE", 5*time.Minute),
|
ConnMaxIdle: getEnvDuration("DB_CONN_MAX_IDLE", 5*time.Minute),
|
||||||
|
MercadoPagoBaseURL: getEnv("MERCADOPAGO_BASE_URL", "https://api.mercadopago.com"),
|
||||||
|
MarketplaceCommission: getEnvFloat("MARKETPLACE_COMMISSION", 2.5),
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
@ -61,3 +65,12 @@ func getEnvDuration(key string, fallback time.Duration) time.Duration {
|
||||||
}
|
}
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getEnvFloat(key string, fallback float64) float64 {
|
||||||
|
if value := os.Getenv(key); value != "" {
|
||||||
|
if parsed, err := strconv.ParseFloat(value, 64); err == nil {
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
|
||||||
22
backend/internal/http/middleware/cors.go
Normal file
22
backend/internal/http/middleware/cors.go
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// CORS adds Cross-Origin Resource Sharing headers to the response.
|
||||||
|
// For now, it allows all origins (*).
|
||||||
|
func CORS(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
||||||
|
w.Header().Set("Access-Control-Max-Age", "86400")
|
||||||
|
|
||||||
|
// Handle preflight requests
|
||||||
|
if r.Method == http.MethodOptions {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -14,10 +14,10 @@ type MercadoPagoGateway struct {
|
||||||
BaseURL string
|
BaseURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMercadoPagoGateway() *MercadoPagoGateway {
|
func NewMercadoPagoGateway(baseURL string, commission float64) *MercadoPagoGateway {
|
||||||
return &MercadoPagoGateway{
|
return &MercadoPagoGateway{
|
||||||
MarketplaceCommission: 2.5,
|
MarketplaceCommission: commission,
|
||||||
BaseURL: "https://api.mercadopago.com",
|
BaseURL: baseURL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ func New(cfg config.Config) (*Server, error) {
|
||||||
db.SetConnMaxIdleTime(cfg.ConnMaxIdle)
|
db.SetConnMaxIdleTime(cfg.ConnMaxIdle)
|
||||||
|
|
||||||
repo := postgres.New(db)
|
repo := postgres.New(db)
|
||||||
gateway := payments.NewMercadoPagoGateway()
|
gateway := payments.NewMercadoPagoGateway(cfg.MercadoPagoBaseURL, cfg.MarketplaceCommission)
|
||||||
svc := usecase.NewService(repo, gateway)
|
svc := usecase.NewService(repo, gateway)
|
||||||
h := handler.New(svc)
|
h := handler.New(svc)
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ func (s *Server) Start(ctx context.Context) error {
|
||||||
|
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Addr: s.cfg.Addr(),
|
Addr: s.cfg.Addr(),
|
||||||
Handler: s.mux,
|
Handler: middleware.CORS(s.mux),
|
||||||
ReadHeaderTimeout: 5 * time.Second,
|
ReadHeaderTimeout: 5 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
3
backoffice/.env.example
Normal file
3
backoffice/.env.example
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
DATABASE_URL=postgresql://user:password@host:port/dbname?schema=public
|
||||||
|
JWT_SECRET=secret-key
|
||||||
|
PORT=3000
|
||||||
Loading…
Reference in a new issue