Creat Service BPJS

This commit is contained in:
2025-08-18 18:09:41 +07:00
parent f953f6d646
commit 1c4f65ffd8
19 changed files with 1073 additions and 3323 deletions

View File

@@ -1,6 +1,11 @@
package config
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"fmt"
"log"
"os"
"strconv"
@@ -9,10 +14,11 @@ import (
)
type Config struct {
Server ServerConfig
Databases map[string]DatabaseConfig
Server ServerConfig
Databases map[string]DatabaseConfig
ReadReplicas map[string][]DatabaseConfig // For read replicas
Keycloak KeycloakConfig
Keycloak KeycloakConfig
Bpjs BpjsConfig
}
type ServerConfig struct {
@@ -21,20 +27,20 @@ type ServerConfig struct {
}
type DatabaseConfig struct {
Name string
Type string // postgres, mysql, sqlserver, sqlite, mongodb
Host string
Port int
Username string
Password string
Database string
Schema string
SSLMode string
Path string // For SQLite
Options string // Additional connection options
MaxOpenConns int // Max open connections
MaxIdleConns int // Max idle connections
ConnMaxLifetime time.Duration // Connection max lifetime
Name string
Type string // postgres, mysql, sqlserver, sqlite, mongodb
Host string
Port int
Username string
Password string
Database string
Schema string
SSLMode string
Path string // For SQLite
Options string // Additional connection options
MaxOpenConns int // Max open connections
MaxIdleConns int // Max idle connections
ConnMaxLifetime time.Duration // Connection max lifetime
}
type KeycloakConfig struct {
@@ -44,6 +50,52 @@ type KeycloakConfig struct {
Enabled bool
}
type BpjsConfig struct {
BaseURL string `json:"base_url"`
ConsID string `json:"cons_id"`
UserKey string `json:"user_key"`
SecretKey string `json:"secret_key"`
Timeout time.Duration `json:"timeout"`
}
// SetHeader generates required headers for BPJS VClaim API
func (cfg BpjsConfig) SetHeader() (string, string, string, string, string) {
timenow := time.Now().UTC()
t, err := time.Parse(time.RFC3339, "1970-01-01T00:00:00Z")
if err != nil {
log.Fatal(err)
}
tstamp := timenow.Unix() - t.Unix()
secret := []byte(cfg.SecretKey)
message := []byte(cfg.ConsID + "&" + fmt.Sprint(tstamp))
hash := hmac.New(sha256.New, secret)
hash.Write(message)
// to lowercase hexits
hex.EncodeToString(hash.Sum(nil))
// to base64
xSignature := base64.StdEncoding.EncodeToString(hash.Sum(nil))
return cfg.ConsID, cfg.SecretKey, cfg.UserKey, fmt.Sprint(tstamp), xSignature
}
type ConfigBpjs struct {
Cons_id string
Secret_key string
User_key string
}
// SetHeader for backward compatibility
func (cfg ConfigBpjs) SetHeader() (string, string, string, string, string) {
bpjsConfig := BpjsConfig{
ConsID: cfg.Cons_id,
SecretKey: cfg.Secret_key,
UserKey: cfg.User_key,
}
return bpjsConfig.SetHeader()
}
func LoadConfig() *Config {
config := &Config{
Server: ServerConfig{
@@ -58,11 +110,18 @@ func LoadConfig() *Config {
JwksURL: getEnv("KEYCLOAK_JWKS_URL", "https://keycloak.example.com/auth/realms/yourrealm/protocol/openid-connect/certs"),
Enabled: getEnvAsBool("KEYCLOAK_ENABLED", true),
},
Bpjs: BpjsConfig{
BaseURL: getEnv("BPJS_BASEURL", "https://apijkn.bpjs-kesehatan.go.id"),
ConsID: getEnv("BPJS_CONSID", ""),
UserKey: getEnv("BPJS_USERKEY", ""),
SecretKey: getEnv("BPJS_SECRETKEY", ""),
Timeout: parseDuration(getEnv("BPJS_TIMEOUT", "30s")),
},
}
// Load database configurations
config.loadDatabaseConfigs()
// Load read replica configurations
config.loadReadReplicaConfigs()
@@ -72,21 +131,21 @@ func LoadConfig() *Config {
func (c *Config) loadDatabaseConfigs() {
// Simplified approach: Directly load from environment variables
// This ensures we get the exact values specified in .env
// Primary database configuration
c.Databases["default"] = DatabaseConfig{
Name: "default",
Type: getEnv("DB_CONNECTION", "postgres"),
Host: getEnv("DB_HOST", "localhost"),
Port: getEnvAsInt("DB_PORT", 5432),
Username: getEnv("DB_USERNAME", ""),
Password: getEnv("DB_PASSWORD", ""),
Database: getEnv("DB_DATABASE", "satu_db"),
Schema: getEnv("DB_SCHEMA", "public"),
SSLMode: getEnv("DB_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("DB_MAX_OPEN_CONNS", 25),
MaxIdleConns: getEnvAsInt("DB_MAX_IDLE_CONNS", 25),
ConnMaxLifetime: parseDuration(getEnv("DB_CONN_MAX_LIFETIME", "5m")),
Name: "default",
Type: getEnv("DB_CONNECTION", "postgres"),
Host: getEnv("DB_HOST", "localhost"),
Port: getEnvAsInt("DB_PORT", 5432),
Username: getEnv("DB_USERNAME", ""),
Password: getEnv("DB_PASSWORD", ""),
Database: getEnv("DB_DATABASE", "satu_db"),
Schema: getEnv("DB_SCHEMA", "public"),
SSLMode: getEnv("DB_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("DB_MAX_OPEN_CONNS", 25),
MaxIdleConns: getEnvAsInt("DB_MAX_IDLE_CONNS", 25),
ConnMaxLifetime: parseDuration(getEnv("DB_CONN_MAX_LIFETIME", "5m")),
}
// SATUDATA database configuration
@@ -110,16 +169,16 @@ func (c *Config) loadDatabaseConfigs() {
value := parts[1]
// Parse specific database configurations
if strings.HasSuffix(key, "_CONNECTION") || strings.HasSuffix(key, "_HOST") ||
strings.HasSuffix(key, "_DATABASE") || strings.HasSuffix(key, "_USERNAME") ||
strings.HasSuffix(key, "_PASSWORD") || strings.HasSuffix(key, "_PORT") ||
strings.HasSuffix(key, "_NAME") {
if strings.HasSuffix(key, "_CONNECTION") || strings.HasSuffix(key, "_HOST") ||
strings.HasSuffix(key, "_DATABASE") || strings.HasSuffix(key, "_USERNAME") ||
strings.HasSuffix(key, "_PASSWORD") || strings.HasSuffix(key, "_PORT") ||
strings.HasSuffix(key, "_NAME") {
segments := strings.Split(key, "_")
if len(segments) >= 2 {
dbName := strings.ToLower(strings.Join(segments[:len(segments)-1], "_"))
property := strings.ToLower(segments[len(segments)-1])
if dbConfigs[dbName] == nil {
dbConfigs[dbName] = make(map[string]string)
}
@@ -131,25 +190,25 @@ func (c *Config) loadDatabaseConfigs() {
// Create DatabaseConfig from parsed configurations for additional databases
for name, config := range dbConfigs {
// Skip empty configurations or system configurations
if name == "" || strings.Contains(name, "chrome_crashpad_pipe") || name == "primary" {
if name == "" || strings.Contains(name, "chrome_crashpad_pipe") || name == "primary" {
continue
}
dbConfig := DatabaseConfig{
Name: name,
Type: getEnvFromMap(config, "connection", getEnvFromMap(config, "type", "postgres")),
Host: getEnvFromMap(config, "host", "localhost"),
Port: getEnvAsIntFromMap(config, "port", 5432),
Username: getEnvFromMap(config, "username", ""),
Password: getEnvFromMap(config, "password", ""),
Database: getEnvFromMap(config, "database", getEnvFromMap(config, "name", name)),
Schema: getEnvFromMap(config, "schema", "public"),
SSLMode: getEnvFromMap(config, "sslmode", "disable"),
Path: getEnvFromMap(config, "path", ""),
Options: getEnvFromMap(config, "options", ""),
MaxOpenConns: getEnvAsIntFromMap(config, "max_open_conns", 25),
MaxIdleConns: getEnvAsIntFromMap(config, "max_idle_conns", 25),
ConnMaxLifetime: parseDuration(getEnvFromMap(config, "conn_max_lifetime", "5m")),
Name: name,
Type: getEnvFromMap(config, "connection", getEnvFromMap(config, "type", "postgres")),
Host: getEnvFromMap(config, "host", "localhost"),
Port: getEnvAsIntFromMap(config, "port", 5432),
Username: getEnvFromMap(config, "username", ""),
Password: getEnvFromMap(config, "password", ""),
Database: getEnvFromMap(config, "database", getEnvFromMap(config, "name", name)),
Schema: getEnvFromMap(config, "schema", "public"),
SSLMode: getEnvFromMap(config, "sslmode", "disable"),
Path: getEnvFromMap(config, "path", ""),
Options: getEnvFromMap(config, "options", ""),
MaxOpenConns: getEnvAsIntFromMap(config, "max_open_conns", 25),
MaxIdleConns: getEnvAsIntFromMap(config, "max_idle_conns", 25),
ConnMaxLifetime: parseDuration(getEnvFromMap(config, "conn_max_lifetime", "5m")),
}
// Skip if username is empty and it's not a system config
@@ -182,7 +241,7 @@ func (c *Config) loadReadReplicaConfigs() {
property := strings.ToLower(strings.Join(segments[4:], "_"))
replicaKey := dbName + "_replica_" + replicaIndex
if c.ReadReplicas[dbName] == nil {
c.ReadReplicas[dbName] = []DatabaseConfig{}
}
@@ -199,18 +258,18 @@ func (c *Config) loadReadReplicaConfigs() {
if replicaConfig == nil {
// Create new replica config
newConfig := DatabaseConfig{
Name: replicaKey,
Type: c.Databases[dbName].Type,
Host: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_HOST", c.Databases[dbName].Host),
Port: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_PORT", c.Databases[dbName].Port),
Username: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_USERNAME", c.Databases[dbName].Username),
Password: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_PASSWORD", c.Databases[dbName].Password),
Database: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_DATABASE", c.Databases[dbName].Database),
Schema: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_SCHEMA", c.Databases[dbName].Schema),
SSLMode: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_SSLMODE", c.Databases[dbName].SSLMode),
MaxOpenConns: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_MAX_OPEN_CONNS", c.Databases[dbName].MaxOpenConns),
MaxIdleConns: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_MAX_IDLE_CONNS", c.Databases[dbName].MaxIdleConns),
ConnMaxLifetime: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_CONN_MAX_LIFETIME", "5m")),
Name: replicaKey,
Type: c.Databases[dbName].Type,
Host: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_HOST", c.Databases[dbName].Host),
Port: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_PORT", c.Databases[dbName].Port),
Username: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_USERNAME", c.Databases[dbName].Username),
Password: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_PASSWORD", c.Databases[dbName].Password),
Database: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_DATABASE", c.Databases[dbName].Database),
Schema: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_SCHEMA", c.Databases[dbName].Schema),
SSLMode: getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_SSLMODE", c.Databases[dbName].SSLMode),
MaxOpenConns: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_MAX_OPEN_CONNS", c.Databases[dbName].MaxOpenConns),
MaxIdleConns: getEnvAsInt("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_MAX_IDLE_CONNS", c.Databases[dbName].MaxIdleConns),
ConnMaxLifetime: parseDuration(getEnv("DB_"+strings.ToUpper(dbName)+"_REPLICA_"+replicaIndex+"_CONN_MAX_LIFETIME", "5m")),
}
c.ReadReplicas[dbName] = append(c.ReadReplicas[dbName], newConfig)
replicaConfig = &c.ReadReplicas[dbName][len(c.ReadReplicas[dbName])-1]
@@ -249,167 +308,167 @@ func (c *Config) addSpecificDatabase(prefix, defaultType string) {
host := getEnv(strings.ToUpper(prefix)+"_HOST", "")
if host != "" {
dbConfig := DatabaseConfig{
Name: prefix,
Type: connection,
Host: host,
Port: getEnvAsInt(strings.ToUpper(prefix)+"_PORT", 5432),
Username: getEnv(strings.ToUpper(prefix)+"_USERNAME", ""),
Password: getEnv(strings.ToUpper(prefix)+"_PASSWORD", ""),
Database: getEnv(strings.ToUpper(prefix)+"_DATABASE", getEnv(strings.ToUpper(prefix)+"_NAME", prefix)),
Schema: getEnv(strings.ToUpper(prefix)+"_SCHEMA", "public"),
SSLMode: getEnv(strings.ToUpper(prefix)+"_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt(strings.ToUpper(prefix)+"_MAX_OPEN_CONNS", 25),
MaxIdleConns: getEnvAsInt(strings.ToUpper(prefix)+"_MAX_IDLE_CONNS", 25),
ConnMaxLifetime: parseDuration(getEnv(strings.ToUpper(prefix)+"_CONN_MAX_LIFETIME", "5m")),
Name: prefix,
Type: connection,
Host: host,
Port: getEnvAsInt(strings.ToUpper(prefix)+"_PORT", 5432),
Username: getEnv(strings.ToUpper(prefix)+"_USERNAME", ""),
Password: getEnv(strings.ToUpper(prefix)+"_PASSWORD", ""),
Database: getEnv(strings.ToUpper(prefix)+"_DATABASE", getEnv(strings.ToUpper(prefix)+"_NAME", prefix)),
Schema: getEnv(strings.ToUpper(prefix)+"_SCHEMA", "public"),
SSLMode: getEnv(strings.ToUpper(prefix)+"_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt(strings.ToUpper(prefix)+"_MAX_OPEN_CONNS", 25),
MaxIdleConns: getEnvAsInt(strings.ToUpper(prefix)+"_MAX_IDLE_CONNS", 25),
ConnMaxLifetime: parseDuration(getEnv(strings.ToUpper(prefix)+"_CONN_MAX_LIFETIME", "5m")),
}
c.Databases[prefix] = dbConfig
}
}
// PostgreSQL database
func (c *Config) addPostgreSQLConfigs() {
// SATUDATA database configuration
// defaultPOSTGRESHost := getEnv("POSTGRES_HOST", "localhost")
// if defaultPOSTGRESHost != "" {
// c.Databases["postgres"] = DatabaseConfig{
// Name: "postgres",
// Type: getEnv("POSTGRES_CONNECTION", "postgres"),
// Host: defaultPOSTGRESHost,
// Port: getEnvAsInt("POSTGRES_PORT", 5432),
// Username: getEnv("POSTGRES_USERNAME", ""),
// Password: getEnv("POSTGRES_PASSWORD", ""),
// Database: getEnv("POSTGRES_DATABASE", "postgres"),
// Schema: getEnv("POSTGRES_SCHEMA", "public"),
// SSLMode: getEnv("POSTGRES_SSLMODE", "disable"),
// MaxOpenConns: getEnvAsInt("POSTGRES_MAX_OPEN_CONNS", 25),
// MaxIdleConns: getEnvAsInt("POSTGRES_MAX_IDLE_CONNS", 25),
// ConnMaxLifetime: parseDuration(getEnv("POSTGRES_CONN_MAX_LIFETIME", "5m")),
// }
// }
// SATUDATA database configuration
// defaultPOSTGRESHost := getEnv("POSTGRES_HOST", "localhost")
// if defaultPOSTGRESHost != "" {
// c.Databases["postgres"] = DatabaseConfig{
// Name: "postgres",
// Type: getEnv("POSTGRES_CONNECTION", "postgres"),
// Host: defaultPOSTGRESHost,
// Port: getEnvAsInt("POSTGRES_PORT", 5432),
// Username: getEnv("POSTGRES_USERNAME", ""),
// Password: getEnv("POSTGRES_PASSWORD", ""),
// Database: getEnv("POSTGRES_DATABASE", "postgres"),
// Schema: getEnv("POSTGRES_SCHEMA", "public"),
// SSLMode: getEnv("POSTGRES_SSLMODE", "disable"),
// MaxOpenConns: getEnvAsInt("POSTGRES_MAX_OPEN_CONNS", 25),
// MaxIdleConns: getEnvAsInt("POSTGRES_MAX_IDLE_CONNS", 25),
// ConnMaxLifetime: parseDuration(getEnv("POSTGRES_CONN_MAX_LIFETIME", "5m")),
// }
// }
// Support for custom PostgreSQL configurations with POSTGRES_ prefix
envVars := os.Environ()
for _, envVar := range envVars {
parts := strings.SplitN(envVar, "=", 2)
if len(parts) != 2 {
continue
}
// Support for custom PostgreSQL configurations with POSTGRES_ prefix
envVars := os.Environ()
for _, envVar := range envVars {
parts := strings.SplitN(envVar, "=", 2)
if len(parts) != 2 {
continue
}
key := parts[0]
// Parse PostgreSQL configurations (format: POSTGRES_[NAME]_[PROPERTY])
if strings.HasPrefix(key, "POSTGRES_") && strings.Contains(key, "_") {
segments := strings.Split(key, "_")
if len(segments) >= 3 {
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
// Skip if it's a standard PostgreSQL configuration
if dbName == "connection" || dbName == "dev" || dbName == "default" || dbName == "satudata" {
continue
}
key := parts[0]
// Parse PostgreSQL configurations (format: POSTGRES_[NAME]_[PROPERTY])
if strings.HasPrefix(key, "POSTGRES_") && strings.Contains(key, "_") {
segments := strings.Split(key, "_")
if len(segments) >= 3 {
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
// Create or update PostgreSQL configuration
if _, exists := c.Databases[dbName]; !exists {
c.Databases[dbName] = DatabaseConfig{
Name: dbName,
Type: "postgres",
Host: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_HOST", "localhost"),
Port: getEnvAsInt("POSTGRES_"+strings.ToUpper(dbName)+"_PORT", 5432),
Username: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_USERNAME", ""),
Password: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_PASSWORD", ""),
Database: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_DATABASE", dbName),
Schema: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_SCHEMA", "public"),
SSLMode: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("POSTGRES_MAX_OPEN_CONNS", 25),
MaxIdleConns: getEnvAsInt("POSTGRES_MAX_IDLE_CONNS", 25),
ConnMaxLifetime: parseDuration(getEnv("POSTGRES_CONN_MAX_LIFETIME", "5m")),
}
}
}
}
}
// Skip if it's a standard PostgreSQL configuration
if dbName == "connection" || dbName == "dev" || dbName == "default" || dbName == "satudata" {
continue
}
// Create or update PostgreSQL configuration
if _, exists := c.Databases[dbName]; !exists {
c.Databases[dbName] = DatabaseConfig{
Name: dbName,
Type: "postgres",
Host: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_HOST", "localhost"),
Port: getEnvAsInt("POSTGRES_"+strings.ToUpper(dbName)+"_PORT", 5432),
Username: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_USERNAME", ""),
Password: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_PASSWORD", ""),
Database: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_DATABASE", dbName),
Schema: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_SCHEMA", "public"),
SSLMode: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("POSTGRES_MAX_OPEN_CONNS", 25),
MaxIdleConns: getEnvAsInt("POSTGRES_MAX_IDLE_CONNS", 25),
ConnMaxLifetime: parseDuration(getEnv("POSTGRES_CONN_MAX_LIFETIME", "5m")),
}
}
}
}
}
}
// addMYSQLConfigs adds MYSQL database
func (c *Config) addMySQLConfigs() {
// Primary MySQL configuration
defaultMySQLHost := getEnv("MYSQL_HOST", "")
if defaultMySQLHost != "" {
c.Databases["mysql"] = DatabaseConfig{
Name: "mysql",
Type: getEnv("MYSQL_CONNECTION", "mysql"),
Host: defaultMySQLHost,
Port: getEnvAsInt("MYSQL_PORT", 3306),
Username: getEnv("MYSQL_USERNAME", ""),
Password: getEnv("MYSQL_PASSWORD", ""),
Database: getEnv("MYSQL_DATABASE", "mysql"),
SSLMode: getEnv("MYSQL_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("MYSQL_MAX_OPEN_CONNS", 25),
MaxIdleConns: getEnvAsInt("MYSQL_MAX_IDLE_CONNS", 25),
ConnMaxLifetime: parseDuration(getEnv("MYSQL_CONN_MAX_LIFETIME", "5m")),
}
}
// Primary MySQL configuration
defaultMySQLHost := getEnv("MYSQL_HOST", "")
if defaultMySQLHost != "" {
c.Databases["mysql"] = DatabaseConfig{
Name: "mysql",
Type: getEnv("MYSQL_CONNECTION", "mysql"),
Host: defaultMySQLHost,
Port: getEnvAsInt("MYSQL_PORT", 3306),
Username: getEnv("MYSQL_USERNAME", ""),
Password: getEnv("MYSQL_PASSWORD", ""),
Database: getEnv("MYSQL_DATABASE", "mysql"),
SSLMode: getEnv("MYSQL_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("MYSQL_MAX_OPEN_CONNS", 25),
MaxIdleConns: getEnvAsInt("MYSQL_MAX_IDLE_CONNS", 25),
ConnMaxLifetime: parseDuration(getEnv("MYSQL_CONN_MAX_LIFETIME", "5m")),
}
}
// Support for custom MySQL configurations with MYSQL_ prefix
envVars := os.Environ()
for _, envVar := range envVars {
parts := strings.SplitN(envVar, "=", 2)
if len(parts) != 2 {
continue
}
// Support for custom MySQL configurations with MYSQL_ prefix
envVars := os.Environ()
for _, envVar := range envVars {
parts := strings.SplitN(envVar, "=", 2)
if len(parts) != 2 {
continue
}
key := parts[0]
// Parse MySQL configurations (format: MYSQL_[NAME]_[PROPERTY])
if strings.HasPrefix(key, "MYSQL_") && strings.Contains(key, "_") {
segments := strings.Split(key, "_")
if len(segments) >= 3 {
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
// Skip if it's a standard MySQL configuration
if dbName == "connection" || dbName == "dev" || dbName == "max" || dbName == "conn" {
continue
}
key := parts[0]
// Parse MySQL configurations (format: MYSQL_[NAME]_[PROPERTY])
if strings.HasPrefix(key, "MYSQL_") && strings.Contains(key, "_") {
segments := strings.Split(key, "_")
if len(segments) >= 3 {
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
// Create or update MySQL configuration
if _, exists := c.Databases[dbName]; !exists {
mysqlHost := getEnv("MYSQL_"+strings.ToUpper(dbName)+"_HOST", "")
if mysqlHost != "" {
c.Databases[dbName] = DatabaseConfig{
Name: dbName,
Type: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_CONNECTION", "mysql"),
Host: mysqlHost,
Port: getEnvAsInt("MYSQL_"+strings.ToUpper(dbName)+"_PORT", 3306),
Username: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_USERNAME", ""),
Password: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_PASSWORD", ""),
Database: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_DATABASE", dbName),
SSLMode: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("MYSQL_MAX_OPEN_CONNS", 25),
MaxIdleConns: getEnvAsInt("MYSQL_MAX_IDLE_CONNS", 25),
ConnMaxLifetime: parseDuration(getEnv("MYSQL_CONN_MAX_LIFETIME", "5m")),
}
}
}
}
}
}
// Skip if it's a standard MySQL configuration
if dbName == "connection" || dbName == "dev" || dbName == "max" || dbName == "conn" {
continue
}
// Create or update MySQL configuration
if _, exists := c.Databases[dbName]; !exists {
mysqlHost := getEnv("MYSQL_"+strings.ToUpper(dbName)+"_HOST", "")
if mysqlHost != "" {
c.Databases[dbName] = DatabaseConfig{
Name: dbName,
Type: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_CONNECTION", "mysql"),
Host: mysqlHost,
Port: getEnvAsInt("MYSQL_"+strings.ToUpper(dbName)+"_PORT", 3306),
Username: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_USERNAME", ""),
Password: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_PASSWORD", ""),
Database: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_DATABASE", dbName),
SSLMode: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("MYSQL_MAX_OPEN_CONNS", 25),
MaxIdleConns: getEnvAsInt("MYSQL_MAX_IDLE_CONNS", 25),
ConnMaxLifetime: parseDuration(getEnv("MYSQL_CONN_MAX_LIFETIME", "5m")),
}
}
}
}
}
}
}
// addMongoDBConfigs adds MongoDB database configurations from environment variables
func (c *Config) addMongoDBConfigs() {
// Primary MongoDB configuration
mongoHost := getEnv("MONGODB_HOST", "")
if mongoHost != "" {
c.Databases["mongodb"] = DatabaseConfig{
Name: "mongodb",
Type: getEnv("MONGODB_CONNECTION", "mongodb"),
Host: mongoHost,
Port: getEnvAsInt("MONGODB_PORT", 27017),
Username: getEnv("MONGODB_USER", ""),
Password: getEnv("MONGODB_PASS", ""),
Database: getEnv("MONGODB_MASTER", "master"),
SSLMode: getEnv("MONGODB_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("MONGODB_MAX_OPEN_CONNS", 100),
MaxIdleConns: getEnvAsInt("MONGODB_MAX_IDLE_CONNS", 10),
ConnMaxLifetime: parseDuration(getEnv("MONGODB_CONN_MAX_LIFETIME", "30m")),
Name: "mongodb",
Type: getEnv("MONGODB_CONNECTION", "mongodb"),
Host: mongoHost,
Port: getEnvAsInt("MONGODB_PORT", 27017),
Username: getEnv("MONGODB_USER", ""),
Password: getEnv("MONGODB_PASS", ""),
Database: getEnv("MONGODB_MASTER", "master"),
SSLMode: getEnv("MONGODB_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("MONGODB_MAX_OPEN_CONNS", 100),
MaxIdleConns: getEnvAsInt("MONGODB_MAX_IDLE_CONNS", 10),
ConnMaxLifetime: parseDuration(getEnv("MONGODB_CONN_MAX_LIFETIME", "30m")),
}
}
@@ -417,17 +476,17 @@ func (c *Config) addMongoDBConfigs() {
mongoLocalHost := getEnv("MONGODB_LOCAL_HOST", "")
if mongoLocalHost != "" {
c.Databases["mongodb_local"] = DatabaseConfig{
Name: "mongodb_local",
Type: getEnv("MONGODB_CONNECTION", "mongodb"),
Host: mongoLocalHost,
Port: getEnvAsInt("MONGODB_LOCAL_PORT", 27017),
Username: getEnv("MONGODB_LOCAL_USER", ""),
Password: getEnv("MONGODB_LOCAL_PASS", ""),
Database: getEnv("MONGODB_LOCAL_DB", "local"),
SSLMode: getEnv("MONGOD_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("MONGODB_MAX_OPEN_CONNS", 100),
MaxIdleConns: getEnvAsInt("MONGODB_MAX_IDLE_CONNS", 10),
ConnMaxLifetime: parseDuration(getEnv("MONGODB_CONN_MAX_LIFETIME", "30m")),
Name: "mongodb_local",
Type: getEnv("MONGODB_CONNECTION", "mongodb"),
Host: mongoLocalHost,
Port: getEnvAsInt("MONGODB_LOCAL_PORT", 27017),
Username: getEnv("MONGODB_LOCAL_USER", ""),
Password: getEnv("MONGODB_LOCAL_PASS", ""),
Database: getEnv("MONGODB_LOCAL_DB", "local"),
SSLMode: getEnv("MONGOD_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("MONGODB_MAX_OPEN_CONNS", 100),
MaxIdleConns: getEnvAsInt("MONGODB_MAX_IDLE_CONNS", 10),
ConnMaxLifetime: parseDuration(getEnv("MONGODB_CONN_MAX_LIFETIME", "30m")),
}
}
@@ -444,7 +503,7 @@ func (c *Config) addMongoDBConfigs() {
if strings.HasPrefix(key, "MONGODB_") && strings.Contains(key, "_") {
segments := strings.Split(key, "_")
if len(segments) >= 3 {
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
// Skip if it's a standard MongoDB configuration
if dbName == "connection" || dbName == "dev" || dbName == "local" {
continue
@@ -453,17 +512,17 @@ func (c *Config) addMongoDBConfigs() {
// Create or update MongoDB configuration
if _, exists := c.Databases[dbName]; !exists {
c.Databases[dbName] = DatabaseConfig{
Name: dbName,
Type: "mongodb",
Host: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_HOST", "localhost"),
Port: getEnvAsInt("MONGODB_"+strings.ToUpper(dbName)+"_PORT", 27017),
Username: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_USER", ""),
Password: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_PASS", ""),
Database: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_DB", dbName),
SSLMode: getEnv("MONGOD_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("MONGODB_MAX_OPEN_CONNS", 100),
MaxIdleConns: getEnvAsInt("MONGODB_MAX_IDLE_CONNS", 10),
ConnMaxLifetime: parseDuration(getEnv("MONGODB_CONN_MAX_LIFETIME", "30m")),
Name: dbName,
Type: "mongodb",
Host: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_HOST", "localhost"),
Port: getEnvAsInt("MONGODB_"+strings.ToUpper(dbName)+"_PORT", 27017),
Username: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_USER", ""),
Password: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_PASS", ""),
Database: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_DB", dbName),
SSLMode: getEnv("MONGOD_SSLMODE", "disable"),
MaxOpenConns: getEnvAsInt("MONGODB_MAX_OPEN_CONNS", 100),
MaxIdleConns: getEnvAsInt("MONGODB_MAX_IDLE_CONNS", 10),
ConnMaxLifetime: parseDuration(getEnv("MONGODB_CONN_MAX_LIFETIME", "30m")),
}
}
}
@@ -537,6 +596,19 @@ func (c *Config) Validate() error {
}
}
if c.Bpjs.BaseURL == "" {
log.Fatal("BPJS Base URL is required")
}
if c.Bpjs.ConsID == "" {
log.Fatal("BPJS Consumer ID is required")
}
if c.Bpjs.UserKey == "" {
log.Fatal("BPJS User Key is required")
}
if c.Bpjs.SecretKey == "" {
log.Fatal("BPJS Secret Key is required")
}
// Validate Keycloak configuration if enabled
if c.Keycloak.Enabled {
if c.Keycloak.Issuer == "" {