feat: initial commit — backend API + student cabinet frontend
- Go backend: auth (JWT), points earn/spend, QR token generation, partners, admin grant/stats endpoints with chi router - Next.js 14 frontend: login, student dashboard, transaction history, QR display, partners list - PostgreSQL migrations (4 tables), Redis cache, Docker Compose - CORS middleware, role-based route protection, Zustand auth store Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
// Package config loads all runtime configuration from environment variables.
|
||||
// All other packages must read settings through this package — no magic strings elsewhere.
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config holds all application settings read from environment variables.
|
||||
type Config struct {
|
||||
DatabaseURL string
|
||||
RedisURL string
|
||||
JWTSecret string
|
||||
JWTAccessTTL time.Duration
|
||||
JWTRefreshTTL time.Duration
|
||||
Port string
|
||||
Env string
|
||||
}
|
||||
|
||||
// Load reads environment variables and returns a populated Config.
|
||||
// Returns an error if any required variable is missing or cannot be parsed.
|
||||
func Load() (*Config, error) {
|
||||
cfg := &Config{
|
||||
DatabaseURL: os.Getenv("DATABASE_URL"),
|
||||
RedisURL: os.Getenv("REDIS_URL"),
|
||||
JWTSecret: os.Getenv("JWT_SECRET"),
|
||||
Port: envOrDefault("PORT", "8080"),
|
||||
Env: envOrDefault("ENV", "development"),
|
||||
}
|
||||
|
||||
for _, req := range []struct{ name, val string }{
|
||||
{"DATABASE_URL", cfg.DatabaseURL},
|
||||
{"REDIS_URL", cfg.RedisURL},
|
||||
{"JWT_SECRET", cfg.JWTSecret},
|
||||
} {
|
||||
if req.val == "" {
|
||||
return nil, fmt.Errorf("config.Load: required env var %s is not set", req.name)
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
cfg.JWTAccessTTL, err = time.ParseDuration(envOrDefault("JWT_ACCESS_TTL", "15m"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("config.Load: invalid JWT_ACCESS_TTL: %w", err)
|
||||
}
|
||||
cfg.JWTRefreshTTL, err = time.ParseDuration(envOrDefault("JWT_REFRESH_TTL", "168h"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("config.Load: invalid JWT_REFRESH_TTL: %w", err)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func envOrDefault(key, fallback string) string {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
return v
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
Reference in New Issue
Block a user