144 lines
5.5 KiB
Go

package main
import (
"os"
"strconv"
"strings"
"time"
)
type config struct {
Port string
WebDir string
AppBaseURL string
MCPResourceURL string
CorsOrigins []string
DatabaseURL string
MinIOEndpoint string
MinIOBucket string
MinIOAccessKey string
MinIOSecretKey string
AssetEncryptionEnabled bool
AuthDisabled bool
KeycloakIssuer string
KeycloakIssuerInternal string
KeycloakAudience string
StripeSecretKey string
StripeAPIBaseURL string
StripeWebhookSecret string
StripeWebhookTolerance time.Duration
StripeAllowedPriceIDs []string
StripeCheckoutSuccessURL string
StripeCheckoutCancelURL string
BillingEventRetentionDays int
EntitlementHistoryRetentionDays int
EducationalRecordRetentionDays int
DefaultTrialDays int
DefaultFreeDays int
KeycloakThemeDeployEnabled bool
NotificationProvider string
SendGridAPIKey string
SendGridFromEmail string
SendGridAPIBaseURL string
ShutdownTimeout time.Duration
}
func loadConfig() config {
return config{
Port: getEnv("PORT", "8080"),
WebDir: strings.TrimSpace(getEnv("WEB_DIR", "")),
AppBaseURL: strings.TrimRight(getEnv("APP_BASE_URL", "http://localhost:5173"), "/"),
MCPResourceURL: strings.TrimRight(getEnv("MCP_RESOURCE_URL", "http://localhost:8080/api/mcp"), "/"),
CorsOrigins: parseList(getEnv("CORS_ALLOWED_ORIGINS", "*")),
DatabaseURL: getEnv("DATABASE_URL", "postgres://cms:cms@postgres:5432/cms?sslmode=disable"),
MinIOEndpoint: getEnv("MINIO_ENDPOINT", ""),
MinIOBucket: getEnv("MINIO_BUCKET", ""),
MinIOAccessKey: getEnv("MINIO_ACCESS_KEY", ""),
MinIOSecretKey: getEnv("MINIO_SECRET_KEY", ""),
AssetEncryptionEnabled: getEnvBool("ASSET_ENCRYPTION_ENABLED", false),
AuthDisabled: getEnvBool("AUTH_DISABLED", false),
KeycloakIssuer: getEnv("KEYCLOAK_ISSUER", "http://localhost:8081/realms/cms"),
KeycloakIssuerInternal: getEnv("KEYCLOAK_ISSUER_INTERNAL", "http://keycloak:8080/realms/cms"),
KeycloakAudience: getEnv("KEYCLOAK_AUDIENCE", "cms-backend"),
StripeSecretKey: getEnv("STRIPE_SECRET_KEY", ""),
StripeAPIBaseURL: getEnv("STRIPE_API_BASE_URL", "https://api.stripe.com"),
StripeWebhookSecret: getEnv("STRIPE_WEBHOOK_SECRET", ""),
StripeWebhookTolerance: time.Duration(getEnvInt("STRIPE_WEBHOOK_TOLERANCE_SECONDS", 300)) * time.Second,
StripeAllowedPriceIDs: parseOptionalList(getEnv("STRIPE_ALLOWED_PRICE_IDS", "")),
StripeCheckoutSuccessURL: getEnv("STRIPE_CHECKOUT_SUCCESS_URL", "http://localhost:5173/learn/billing?checkout=success"),
StripeCheckoutCancelURL: getEnv("STRIPE_CHECKOUT_CANCEL_URL", "http://localhost:5173/learn/billing?checkout=cancel"),
BillingEventRetentionDays: getEnvInt("BILLING_EVENT_RETENTION_DAYS", 365),
EntitlementHistoryRetentionDays: getEnvInt("ENTITLEMENT_HISTORY_RETENTION_DAYS", 730),
EducationalRecordRetentionDays: getEnvInt("EDUCATIONAL_RECORD_RETENTION_DAYS", 2555),
DefaultTrialDays: getEnvInt("DEFAULT_TRIAL_DAYS", 14),
DefaultFreeDays: getEnvInt("DEFAULT_FREE_ACCESS_DAYS", 3650),
KeycloakThemeDeployEnabled: getEnvBool("KEYCLOAK_THEME_DEPLOY_ENABLED", true),
NotificationProvider: strings.ToLower(getEnv("NOTIFICATION_PROVIDER", "noop")),
SendGridAPIKey: getEnv("SENDGRID_API_KEY", ""),
SendGridFromEmail: getEnv("SENDGRID_FROM_EMAIL", ""),
SendGridAPIBaseURL: getEnv("SENDGRID_API_BASE_URL", "https://api.sendgrid.com"),
ShutdownTimeout: time.Duration(getEnvInt("SHUTDOWN_TIMEOUT_SECONDS", 10)) * time.Second,
}
}
func getEnv(key, fallback string) string {
value, ok := os.LookupEnv(key)
if !ok || strings.TrimSpace(value) == "" {
return fallback
}
return value
}
func getEnvInt(key string, fallback int) int {
raw := strings.TrimSpace(getEnv(key, ""))
if raw == "" {
return fallback
}
value, err := strconv.Atoi(raw)
if err != nil {
return fallback
}
return value
}
func getEnvBool(key string, fallback bool) bool {
raw := strings.TrimSpace(strings.ToLower(getEnv(key, "")))
if raw == "" {
return fallback
}
return raw == "1" || raw == "true" || raw == "yes" || raw == "on"
}
func parseList(raw string) []string {
if strings.TrimSpace(raw) == "" {
return []string{"*"}
}
parts := strings.Split(raw, ",")
out := make([]string, 0, len(parts))
for _, part := range parts {
item := strings.TrimSpace(part)
if item != "" {
out = append(out, item)
}
}
if len(out) == 0 {
return []string{"*"}
}
return out
}
func parseOptionalList(raw string) []string {
if strings.TrimSpace(raw) == "" {
return []string{}
}
parts := strings.Split(raw, ",")
out := make([]string, 0, len(parts))
for _, part := range parts {
item := strings.TrimSpace(part)
if item != "" {
out = append(out, item)
}
}
return out
}