Add backend foundation and config-driven workbench
This commit is contained in:
64
backend/internal/app/app.go
Normal file
64
backend/internal/app/app.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"cmr-backend/internal/httpapi"
|
||||
"cmr-backend/internal/platform/jwtx"
|
||||
"cmr-backend/internal/platform/wechatmini"
|
||||
"cmr-backend/internal/service"
|
||||
"cmr-backend/internal/store/postgres"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
router http.Handler
|
||||
store *postgres.Store
|
||||
}
|
||||
|
||||
func New(ctx context.Context, cfg Config) (*App, error) {
|
||||
pool, err := postgres.Open(ctx, cfg.DatabaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
store := postgres.NewStore(pool)
|
||||
jwtManager := jwtx.NewManager(cfg.JWTIssuer, cfg.JWTAccessSecret, cfg.JWTAccessTTL)
|
||||
wechatMiniClient := wechatmini.NewClient(cfg.WechatMiniAppID, cfg.WechatMiniSecret, cfg.WechatMiniDevPrefix)
|
||||
authService := service.NewAuthService(service.AuthSettings{
|
||||
AppEnv: cfg.AppEnv,
|
||||
RefreshTTL: cfg.RefreshTTL,
|
||||
SMSCodeTTL: cfg.SMSCodeTTL,
|
||||
SMSCodeCooldown: cfg.SMSCodeCooldown,
|
||||
SMSProvider: cfg.SMSProvider,
|
||||
DevSMSCode: cfg.DevSMSCode,
|
||||
WechatMini: wechatMiniClient,
|
||||
}, store, jwtManager)
|
||||
entryService := service.NewEntryService(store)
|
||||
entryHomeService := service.NewEntryHomeService(store)
|
||||
eventService := service.NewEventService(store)
|
||||
eventPlayService := service.NewEventPlayService(store)
|
||||
configService := service.NewConfigService(store, cfg.LocalEventDir, cfg.AssetBaseURL)
|
||||
homeService := service.NewHomeService(store)
|
||||
profileService := service.NewProfileService(store)
|
||||
resultService := service.NewResultService(store)
|
||||
sessionService := service.NewSessionService(store)
|
||||
devService := service.NewDevService(cfg.AppEnv, store)
|
||||
meService := service.NewMeService(store)
|
||||
router := httpapi.NewRouter(cfg.AppEnv, jwtManager, authService, entryService, entryHomeService, eventService, eventPlayService, configService, homeService, profileService, resultService, sessionService, devService, meService)
|
||||
|
||||
return &App{
|
||||
router: router,
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *App) Router() http.Handler {
|
||||
return a.router
|
||||
}
|
||||
|
||||
func (a *App) Close() {
|
||||
if a.store != nil {
|
||||
a.store.Close()
|
||||
}
|
||||
}
|
||||
73
backend/internal/app/config.go
Normal file
73
backend/internal/app/config.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
AppEnv string
|
||||
HTTPAddr string
|
||||
DatabaseURL string
|
||||
JWTIssuer string
|
||||
JWTAccessSecret string
|
||||
JWTAccessTTL time.Duration
|
||||
RefreshTTL time.Duration
|
||||
SMSCodeTTL time.Duration
|
||||
SMSCodeCooldown time.Duration
|
||||
SMSProvider string
|
||||
DevSMSCode string
|
||||
WechatMiniAppID string
|
||||
WechatMiniSecret string
|
||||
WechatMiniDevPrefix string
|
||||
LocalEventDir string
|
||||
AssetBaseURL string
|
||||
}
|
||||
|
||||
func LoadConfigFromEnv() (Config, error) {
|
||||
cfg := Config{
|
||||
AppEnv: getEnv("APP_ENV", "development"),
|
||||
HTTPAddr: getEnv("HTTP_ADDR", ":8080"),
|
||||
DatabaseURL: os.Getenv("DATABASE_URL"),
|
||||
JWTIssuer: getEnv("JWT_ISSUER", "cmr-backend"),
|
||||
JWTAccessSecret: getEnv("JWT_ACCESS_SECRET", "change-me-in-production"),
|
||||
JWTAccessTTL: getDurationEnv("JWT_ACCESS_TTL", 2*time.Hour),
|
||||
RefreshTTL: getDurationEnv("AUTH_REFRESH_TTL", 30*24*time.Hour),
|
||||
SMSCodeTTL: getDurationEnv("AUTH_SMS_CODE_TTL", 10*time.Minute),
|
||||
SMSCodeCooldown: getDurationEnv("AUTH_SMS_COOLDOWN", 60*time.Second),
|
||||
SMSProvider: getEnv("AUTH_SMS_PROVIDER", "console"),
|
||||
DevSMSCode: os.Getenv("AUTH_DEV_SMS_CODE"),
|
||||
WechatMiniAppID: getEnv("WECHAT_MINI_APP_ID", ""),
|
||||
WechatMiniSecret: getEnv("WECHAT_MINI_APP_SECRET", ""),
|
||||
WechatMiniDevPrefix: getEnv("WECHAT_MINI_DEV_PREFIX", "dev-"),
|
||||
LocalEventDir: getEnv("LOCAL_EVENT_DIR", filepath.Clean("..\\event")),
|
||||
AssetBaseURL: getEnv("ASSET_BASE_URL", "https://oss-mbh5.colormaprun.com/gotomars"),
|
||||
}
|
||||
|
||||
if cfg.DatabaseURL == "" {
|
||||
return Config{}, fmt.Errorf("DATABASE_URL is required")
|
||||
}
|
||||
if cfg.JWTAccessSecret == "" {
|
||||
return Config{}, fmt.Errorf("JWT_ACCESS_SECRET is required")
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func getEnv(key, fallback string) string {
|
||||
if value := os.Getenv(key); value != "" {
|
||||
return value
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func getDurationEnv(key string, fallback time.Duration) time.Duration {
|
||||
if value := os.Getenv(key); value != "" {
|
||||
if parsed, err := time.ParseDuration(value); err == nil {
|
||||
return parsed
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
Reference in New Issue
Block a user