feat: add Docker deployment and application configuration
Add package declarations across the Go scaffold, YAML configuration loading and validation, and a minimal API entry point. Add development and production Compose files, a multi-stage Docker image, configuration template, and Make targets. Remove the directory scaffolding script.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
package app
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const defaultConfigPath = "configs/config.example.yaml"
|
||||
|
||||
// Config contains the settings required to start the application.
|
||||
type Config struct {
|
||||
Environment string `yaml:"environment"`
|
||||
HTTP HTTPConfig `yaml:"http"`
|
||||
Database DatabaseConfig `yaml:"database"`
|
||||
}
|
||||
|
||||
type HTTPConfig struct {
|
||||
Address string `yaml:"address"`
|
||||
}
|
||||
|
||||
type DatabaseConfig struct {
|
||||
URL string `yaml:"url"`
|
||||
}
|
||||
|
||||
// LoadConfig reads configuration from YAML, applies environment overrides,
|
||||
// and validates the result. An empty path uses CONFIG_FILE when set.
|
||||
func LoadConfig(path string) (Config, error) {
|
||||
if path == "" {
|
||||
path = os.Getenv("CONFIG_FILE")
|
||||
}
|
||||
if path == "" {
|
||||
path = defaultConfigPath
|
||||
}
|
||||
|
||||
contents, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf("read config %q: %w", path, err)
|
||||
}
|
||||
|
||||
var config Config
|
||||
if err := yaml.Unmarshal(contents, &config); err != nil {
|
||||
return Config{}, fmt.Errorf("parse config %q: %w", path, err)
|
||||
}
|
||||
|
||||
applyEnvironment(&config)
|
||||
if err := config.Validate(); err != nil {
|
||||
return Config{}, fmt.Errorf("validate config: %w", err)
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (config Config) Validate() error {
|
||||
var missing []string
|
||||
if strings.TrimSpace(config.Environment) == "" {
|
||||
missing = append(missing, "environment")
|
||||
}
|
||||
if strings.TrimSpace(config.HTTP.Address) == "" {
|
||||
missing = append(missing, "http.address")
|
||||
}
|
||||
if strings.TrimSpace(config.Database.URL) == "" {
|
||||
missing = append(missing, "database.url")
|
||||
}
|
||||
if len(missing) > 0 {
|
||||
return errors.New("missing required values: " + strings.Join(missing, ", "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyEnvironment(config *Config) {
|
||||
if value := os.Getenv("APP_ENVIRONMENT"); value != "" {
|
||||
config.Environment = value
|
||||
}
|
||||
if value := os.Getenv("APP_HTTP_ADDRESS"); value != "" {
|
||||
config.HTTP.Address = value
|
||||
}
|
||||
if value := os.Getenv("APP_DATABASE_URL"); value != "" {
|
||||
config.Database.URL = value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package auth
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package auth
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package auth
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package catalog
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package catalog
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package catalog
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package catalog
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package catalog
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package command
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package command
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package command
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package http
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package http
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package postgres
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package postgres
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package postgres
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package postgres
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package user
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package user
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package user
|
||||
|
||||
Reference in New Issue
Block a user