add env files
This commit is contained in:
5
.env
Normal file
5
.env
Normal file
@@ -0,0 +1,5 @@
|
||||
# Base Configuration
|
||||
DATABASE_URL=postgres://postgres:password@localhost:5432/counter_db?sslmode=disable
|
||||
PORT=8080
|
||||
LOG_LEVEL=info
|
||||
GIN_MODE=debug
|
||||
7
.env.development
Normal file
7
.env.development
Normal file
@@ -0,0 +1,7 @@
|
||||
# Development Environment
|
||||
ENVIRONMENT=development
|
||||
DATABASE_URL=postgres://postgres:password@postgres:5432/counter_db?sslmode=disable
|
||||
JWT_SECRET=dev-secret-key-change-in-production
|
||||
PORT=8080
|
||||
GIN_MODE=debug
|
||||
LOG_LEVEL=debug
|
||||
7
.env.production
Normal file
7
.env.production
Normal file
@@ -0,0 +1,7 @@
|
||||
# Production Environment
|
||||
ENVIRONMENT=production
|
||||
DATABASE_URL=postgres://postgres:password@postgres:5432/counter_db?sslmode=disable
|
||||
JWT_SECRET=super-secure-production-secret-change-this
|
||||
PORT=8080
|
||||
GIN_MODE=release
|
||||
LOG_LEVEL=warn
|
||||
7
.env.staging
Normal file
7
.env.staging
Normal file
@@ -0,0 +1,7 @@
|
||||
# Staging Environment
|
||||
ENVIRONMENT=staging
|
||||
DATABASE_URL=postgres://postgres:password@postgres:5432/counter_db?sslmode=disable
|
||||
JWT_SECRET=staging-secret-key-change-this
|
||||
PORT=8080
|
||||
GIN_MODE=release
|
||||
LOG_LEVEL=info
|
||||
12
.gitignore
vendored
12
.gitignore
vendored
@@ -17,12 +17,12 @@
|
||||
# Go workspace file
|
||||
go.work
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
# Environment variables (keeping all env files in git as requested)
|
||||
# .env
|
||||
# .env.local
|
||||
# .env.development.local
|
||||
# .env.test.local
|
||||
# .env.production.local
|
||||
|
||||
# Node.js
|
||||
node_modules/
|
||||
|
||||
@@ -9,8 +9,9 @@ COPY go.mod go.sum ./
|
||||
# Download dependencies
|
||||
RUN go mod download
|
||||
|
||||
# Copy source code
|
||||
# Copy source code and environment files
|
||||
COPY *.go ./
|
||||
COPY .env* ./
|
||||
|
||||
# Build the application
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
|
||||
@@ -43,6 +44,9 @@ WORKDIR /root/
|
||||
# Copy the Go binary from go-builder stage
|
||||
COPY --from=go-builder /app/main .
|
||||
|
||||
# Copy environment files from go-builder stage
|
||||
COPY --from=go-builder /app/.env* ./
|
||||
|
||||
# Copy the React build from frontend-builder stage
|
||||
COPY --from=frontend-builder /app/frontend/build ./frontend/build
|
||||
|
||||
|
||||
7
auth.go
7
auth.go
@@ -17,7 +17,7 @@ import (
|
||||
|
||||
var jwtSecret []byte
|
||||
|
||||
// InitJWT initializes JWT secret
|
||||
// InitJWT initializes JWT secret (legacy function)
|
||||
func InitJWT() {
|
||||
secret := os.Getenv("JWT_SECRET")
|
||||
if secret == "" {
|
||||
@@ -28,6 +28,11 @@ func InitJWT() {
|
||||
jwtSecret = []byte(secret)
|
||||
}
|
||||
|
||||
// InitJWTWithConfig initializes JWT secret with configuration
|
||||
func InitJWTWithConfig(config *Config) {
|
||||
jwtSecret = []byte(config.JWTSecret)
|
||||
}
|
||||
|
||||
// generateRandomSecret generates a random secret for JWT
|
||||
func generateRandomSecret() string {
|
||||
b := make([]byte, 32)
|
||||
|
||||
216
config.go
Normal file
216
config.go
Normal file
@@ -0,0 +1,216 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
type Environment string
|
||||
|
||||
const (
|
||||
Development Environment = "development"
|
||||
Staging Environment = "staging"
|
||||
Production Environment = "production"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Environment Environment
|
||||
DatabaseURL string
|
||||
JWTSecret string
|
||||
Port string
|
||||
GinMode string
|
||||
LogLevel string
|
||||
Debug bool
|
||||
}
|
||||
|
||||
// LoadConfig loads configuration with proper environment file precedence
|
||||
func LoadConfig() *Config {
|
||||
// Load environment files in priority order
|
||||
loadEnvironmentFiles()
|
||||
|
||||
// Get environment
|
||||
env := getEnvironment()
|
||||
|
||||
// Load configuration
|
||||
config := &Config{
|
||||
Environment: env,
|
||||
DatabaseURL: getEnv("DATABASE_URL", getDefaultDatabaseURL(env)),
|
||||
JWTSecret: getRequiredEnv("JWT_SECRET"),
|
||||
Port: getEnv("PORT", "8080"),
|
||||
GinMode: getGinMode(env),
|
||||
LogLevel: getLogLevel(env),
|
||||
Debug: env == Development,
|
||||
}
|
||||
|
||||
// Log configuration (without sensitive data)
|
||||
logConfig(config)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// loadEnvironmentFiles loads environment files in priority order
|
||||
func loadEnvironmentFiles() {
|
||||
// Get environment first (from system env or default)
|
||||
env := getEnvironmentFromSystem()
|
||||
|
||||
log.Printf("🔍 Detected environment: %s", env)
|
||||
|
||||
// Define file loading order (later files override earlier ones)
|
||||
files := []string{
|
||||
".env", // Base configuration
|
||||
fmt.Sprintf(".env.%s", env), // Environment-specific
|
||||
}
|
||||
|
||||
// Load files in order
|
||||
for _, file := range files {
|
||||
if _, err := os.Stat(file); err == nil {
|
||||
if err := godotenv.Load(file); err != nil {
|
||||
log.Printf("⚠️ Warning: Could not load %s: %v", file, err)
|
||||
} else {
|
||||
log.Printf("✅ Loaded: %s", file)
|
||||
}
|
||||
} else {
|
||||
log.Printf("❌ Not found: %s", file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getEnvironmentFromSystem gets environment from system variables only
|
||||
func getEnvironmentFromSystem() string {
|
||||
// Check if ENVIRONMENT is already set
|
||||
if env := os.Getenv("ENVIRONMENT"); env != "" {
|
||||
return strings.ToLower(env)
|
||||
}
|
||||
|
||||
// Fallback detection
|
||||
if ginMode := os.Getenv("GIN_MODE"); ginMode == "release" {
|
||||
return "production"
|
||||
}
|
||||
|
||||
return "development"
|
||||
}
|
||||
|
||||
// getEnvironment gets the current environment
|
||||
func getEnvironment() Environment {
|
||||
env := strings.ToLower(getEnv("ENVIRONMENT", "development"))
|
||||
|
||||
switch env {
|
||||
case "development", "dev":
|
||||
return Development
|
||||
case "staging", "stage":
|
||||
return Staging
|
||||
case "production", "prod":
|
||||
return Production
|
||||
default:
|
||||
log.Printf("⚠️ Unknown environment '%s', defaulting to development", env)
|
||||
return Development
|
||||
}
|
||||
}
|
||||
|
||||
// getGinMode returns the appropriate Gin mode for the environment
|
||||
func getGinMode(env Environment) string {
|
||||
switch env {
|
||||
case Production, Staging:
|
||||
return "release"
|
||||
case Development:
|
||||
return "debug"
|
||||
default:
|
||||
return "debug"
|
||||
}
|
||||
}
|
||||
|
||||
// getLogLevel returns the appropriate log level for the environment
|
||||
func getLogLevel(env Environment) string {
|
||||
switch env {
|
||||
case Production:
|
||||
return "warn"
|
||||
case Staging:
|
||||
return "info"
|
||||
case Development:
|
||||
return "debug"
|
||||
default:
|
||||
return "debug"
|
||||
}
|
||||
}
|
||||
|
||||
// getDefaultDatabaseURL returns default database URL for environment
|
||||
func getDefaultDatabaseURL(env Environment) string {
|
||||
switch env {
|
||||
case Development:
|
||||
return "postgres://postgres:password@localhost:5432/counter_db?sslmode=disable"
|
||||
case Staging:
|
||||
return "postgres://postgres:password@postgres:5432/counter_db?sslmode=disable"
|
||||
case Production:
|
||||
return "postgres://postgres:password@postgres:5432/counter_db?sslmode=require"
|
||||
default:
|
||||
return "postgres://postgres:password@localhost:5432/counter_db?sslmode=disable"
|
||||
}
|
||||
}
|
||||
|
||||
// getEnv gets environment variable with default value
|
||||
func getEnv(key, defaultValue string) string {
|
||||
if value := os.Getenv(key); value != "" {
|
||||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// getRequiredEnv gets required environment variable
|
||||
func getRequiredEnv(key string) string {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
log.Fatalf("❌ Required environment variable %s is not set", key)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// logConfig logs configuration (without sensitive data)
|
||||
func logConfig(config *Config) {
|
||||
// Environment banner
|
||||
log.Printf("")
|
||||
log.Printf("╔══════════════════════════════════════════════════════════════╗")
|
||||
log.Printf("║ COUNTER APPLICATION ║")
|
||||
log.Printf("║ ║")
|
||||
log.Printf("║ 🌍 ENVIRONMENT: %-15s ║", strings.ToUpper(string(config.Environment)))
|
||||
log.Printf("║ 🚀 MODE: %-20s ║", config.GinMode)
|
||||
log.Printf("║ 🔧 DEBUG: %-20s ║", fmt.Sprintf("%t", config.Debug))
|
||||
log.Printf("║ 📊 LOG LEVEL: %-15s ║", config.LogLevel)
|
||||
log.Printf("║ 🌐 PORT: %-20s ║", config.Port)
|
||||
log.Printf("║ ║")
|
||||
log.Printf("║ 📁 Configuration Files Loaded: ║")
|
||||
log.Printf("║ • .env (base configuration) ║")
|
||||
log.Printf("║ • .env.%s (environment-specific) ║", config.Environment)
|
||||
log.Printf("║ ║")
|
||||
log.Printf("║ 🔐 Security: ║")
|
||||
log.Printf("║ • Database: %s ║", maskDatabaseURL(config.DatabaseURL))
|
||||
log.Printf("║ • JWT Secret: %s ║", maskSecret(config.JWTSecret))
|
||||
log.Printf("║ ║")
|
||||
log.Printf("╚══════════════════════════════════════════════════════════════╝")
|
||||
log.Printf("")
|
||||
}
|
||||
|
||||
// maskDatabaseURL masks sensitive parts of database URL
|
||||
func maskDatabaseURL(url string) string {
|
||||
// Simple masking - replace password with ***
|
||||
if strings.Contains(url, "://") {
|
||||
parts := strings.Split(url, "://")
|
||||
if len(parts) == 2 {
|
||||
// Replace password in connection string
|
||||
masked := strings.Replace(parts[1], ":", ":***@", 1)
|
||||
return parts[0] + "://" + masked
|
||||
}
|
||||
}
|
||||
return "***"
|
||||
}
|
||||
|
||||
// maskSecret masks JWT secret for logging
|
||||
func maskSecret(secret string) string {
|
||||
if len(secret) <= 8 {
|
||||
return "***"
|
||||
}
|
||||
return secret[:4] + "***" + secret[len(secret)-4:]
|
||||
}
|
||||
16
database.go
16
database.go
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
var db *sql.DB
|
||||
|
||||
// InitDB initializes the database connection
|
||||
// InitDB initializes the database connection (legacy function)
|
||||
func InitDB() error {
|
||||
// Get database URL from environment variable
|
||||
dbURL := os.Getenv("DATABASE_URL")
|
||||
@@ -19,6 +19,16 @@ func InitDB() error {
|
||||
// Default for local development
|
||||
dbURL = "postgres://postgres:password@localhost:5432/counter_db?sslmode=disable"
|
||||
}
|
||||
return initDBWithURL(dbURL)
|
||||
}
|
||||
|
||||
// InitDBWithConfig initializes the database connection with configuration
|
||||
func InitDBWithConfig(config *Config) error {
|
||||
return initDBWithURL(config.DatabaseURL)
|
||||
}
|
||||
|
||||
// initDBWithURL initializes the database connection with a specific URL
|
||||
func initDBWithURL(dbURL string) error {
|
||||
|
||||
var err error
|
||||
db, err = sql.Open("postgres", dbURL)
|
||||
@@ -31,7 +41,7 @@ func InitDB() error {
|
||||
return fmt.Errorf("failed to ping database: %w", err)
|
||||
}
|
||||
|
||||
log.Println("Database connection established")
|
||||
log.Println("✅ Database connection established successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -72,7 +82,7 @@ func CreateTables() error {
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Database tables created successfully")
|
||||
log.Println("✅ Database tables created successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
6
docker-compose.prod.yml
Normal file
6
docker-compose.prod.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
services:
|
||||
app:
|
||||
environment:
|
||||
- ENVIRONMENT=production
|
||||
env_file:
|
||||
- .env.production
|
||||
6
docker-compose.staging.yml
Normal file
6
docker-compose.staging.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
services:
|
||||
app:
|
||||
environment:
|
||||
- ENVIRONMENT=staging
|
||||
env_file:
|
||||
- .env.staging
|
||||
@@ -20,9 +20,9 @@ services:
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
DATABASE_URL: postgres://postgres:password@postgres:5432/counter_db?sslmode=disable
|
||||
JWT_SECRET: your-super-secret-jwt-key-change-in-production
|
||||
GIN_MODE: release
|
||||
- ENVIRONMENT=development
|
||||
env_file:
|
||||
- .env.development
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
||||
4
frontend/.env
Normal file
4
frontend/.env
Normal file
@@ -0,0 +1,4 @@
|
||||
# Base Frontend Configuration
|
||||
REACT_APP_API_URL=http://localhost:8080/api/v1
|
||||
REACT_APP_ENVIRONMENT=development
|
||||
REACT_APP_DEBUG=true
|
||||
5
frontend/.env.development
Normal file
5
frontend/.env.development
Normal file
@@ -0,0 +1,5 @@
|
||||
# Development Frontend Configuration
|
||||
REACT_APP_API_URL=http://localhost:8080/api/v1
|
||||
REACT_APP_ENVIRONMENT=development
|
||||
REACT_APP_DEBUG=true
|
||||
REACT_APP_LOG_LEVEL=debug
|
||||
5
frontend/.env.production
Normal file
5
frontend/.env.production
Normal file
@@ -0,0 +1,5 @@
|
||||
# Production Frontend Configuration
|
||||
REACT_APP_API_URL=/api/v1
|
||||
REACT_APP_ENVIRONMENT=production
|
||||
REACT_APP_DEBUG=false
|
||||
REACT_APP_LOG_LEVEL=warn
|
||||
5
frontend/.env.staging
Normal file
5
frontend/.env.staging
Normal file
@@ -0,0 +1,5 @@
|
||||
# Staging Frontend Configuration
|
||||
REACT_APP_API_URL=https://staging-api.yourdomain.com/api/v1
|
||||
REACT_APP_ENVIRONMENT=staging
|
||||
REACT_APP_DEBUG=false
|
||||
REACT_APP_LOG_LEVEL=info
|
||||
102
frontend/src/config/environment.ts
Normal file
102
frontend/src/config/environment.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
// Environment configuration for React frontend
|
||||
export type Environment = 'development' | 'staging' | 'production';
|
||||
|
||||
export interface AppConfig {
|
||||
environment: Environment;
|
||||
apiUrl: string;
|
||||
debug: boolean;
|
||||
logLevel: string;
|
||||
}
|
||||
|
||||
// Get environment from process.env
|
||||
export const getEnvironment = (): Environment => {
|
||||
const env = process.env.REACT_APP_ENVIRONMENT as Environment;
|
||||
|
||||
// Fallback to NODE_ENV if REACT_APP_ENVIRONMENT is not set
|
||||
if (!env) {
|
||||
const nodeEnv = process.env.NODE_ENV;
|
||||
switch (nodeEnv) {
|
||||
case 'production':
|
||||
return 'production';
|
||||
case 'development':
|
||||
return 'development';
|
||||
default:
|
||||
return 'development';
|
||||
}
|
||||
}
|
||||
|
||||
return env;
|
||||
};
|
||||
|
||||
// Get API URL based on environment
|
||||
export const getApiUrl = (): string => {
|
||||
const apiUrl = process.env.REACT_APP_API_URL;
|
||||
|
||||
if (apiUrl) {
|
||||
return apiUrl;
|
||||
}
|
||||
|
||||
// Fallback based on environment
|
||||
const env = getEnvironment();
|
||||
switch (env) {
|
||||
case 'production':
|
||||
return '/api/v1'; // Relative URL for production
|
||||
case 'staging':
|
||||
return 'https://staging-api.yourdomain.com/api/v1';
|
||||
case 'development':
|
||||
default:
|
||||
return 'http://localhost:8080/api/v1';
|
||||
}
|
||||
};
|
||||
|
||||
// Get debug flag
|
||||
export const isDebugMode = (): boolean => {
|
||||
const debug = process.env.REACT_APP_DEBUG;
|
||||
if (debug !== undefined) {
|
||||
return debug === 'true';
|
||||
}
|
||||
|
||||
// Fallback based on environment
|
||||
return getEnvironment() === 'development';
|
||||
};
|
||||
|
||||
// Get log level
|
||||
export const getLogLevel = (): string => {
|
||||
return process.env.REACT_APP_LOG_LEVEL || 'info';
|
||||
};
|
||||
|
||||
// Get complete app configuration
|
||||
export const getAppConfig = (): AppConfig => {
|
||||
return {
|
||||
environment: getEnvironment(),
|
||||
apiUrl: getApiUrl(),
|
||||
debug: isDebugMode(),
|
||||
logLevel: getLogLevel(),
|
||||
};
|
||||
};
|
||||
|
||||
// Environment checks
|
||||
export const isDevelopment = (): boolean => {
|
||||
return getEnvironment() === 'development';
|
||||
};
|
||||
|
||||
export const isStaging = (): boolean => {
|
||||
return getEnvironment() === 'staging';
|
||||
};
|
||||
|
||||
export const isProduction = (): boolean => {
|
||||
return getEnvironment() === 'production';
|
||||
};
|
||||
|
||||
// Log configuration (only in development)
|
||||
export const logConfig = (): void => {
|
||||
if (isDevelopment()) {
|
||||
const config = getAppConfig();
|
||||
console.log('🚀 Frontend Configuration:', {
|
||||
environment: config.environment,
|
||||
apiUrl: config.apiUrl,
|
||||
debug: config.debug,
|
||||
logLevel: config.logLevel,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -12,8 +12,11 @@ import {
|
||||
CounterStats,
|
||||
User,
|
||||
} from '../types';
|
||||
import { getApiUrl, logConfig } from '../config/environment';
|
||||
|
||||
const API_BASE_URL = process.env.REACT_APP_API_URL || '/api/v1';
|
||||
// Initialize configuration
|
||||
logConfig();
|
||||
const API_BASE_URL = getApiUrl();
|
||||
|
||||
// Create axios instance
|
||||
const api = axios.create({
|
||||
|
||||
52
main.go
52
main.go
@@ -2,24 +2,23 @@ package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Load environment variables
|
||||
if err := godotenv.Load(); err != nil {
|
||||
log.Println("No .env file found, using system environment variables")
|
||||
}
|
||||
// Load configuration with environment file precedence
|
||||
config := LoadConfig()
|
||||
|
||||
// Initialize JWT
|
||||
InitJWT()
|
||||
// Set Gin mode based on configuration
|
||||
gin.SetMode(config.GinMode)
|
||||
|
||||
// Initialize database
|
||||
if err := InitDB(); err != nil {
|
||||
// Initialize JWT with configuration
|
||||
InitJWTWithConfig(config)
|
||||
|
||||
// Initialize database with configuration
|
||||
if err := InitDBWithConfig(config); err != nil {
|
||||
log.Fatal("Failed to initialize database:", err)
|
||||
}
|
||||
|
||||
@@ -28,21 +27,16 @@ func main() {
|
||||
log.Fatal("Failed to create tables:", err)
|
||||
}
|
||||
|
||||
// Set Gin mode
|
||||
if os.Getenv("GIN_MODE") == "release" {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
// Create Gin router
|
||||
r := gin.Default()
|
||||
|
||||
// Configure CORS
|
||||
config := cors.DefaultConfig()
|
||||
config.AllowOrigins = []string{"http://localhost:3000", "http://localhost:5173"} // React dev servers
|
||||
config.AllowMethods = []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}
|
||||
config.AllowHeaders = []string{"Origin", "Content-Type", "Accept", "Authorization"}
|
||||
config.AllowCredentials = true
|
||||
r.Use(cors.New(config))
|
||||
corsConfig := cors.DefaultConfig()
|
||||
corsConfig.AllowOrigins = []string{"http://localhost:3000", "http://localhost:5173"} // React dev servers
|
||||
corsConfig.AllowMethods = []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}
|
||||
corsConfig.AllowHeaders = []string{"Origin", "Content-Type", "Accept", "Authorization"}
|
||||
corsConfig.AllowCredentials = true
|
||||
r.Use(cors.New(corsConfig))
|
||||
|
||||
// Health check endpoint
|
||||
r.GET("/health", func(c *gin.Context) {
|
||||
@@ -83,11 +77,17 @@ func main() {
|
||||
})
|
||||
|
||||
// Start server
|
||||
port := os.Getenv("PORT")
|
||||
if port == "" {
|
||||
port = "8080"
|
||||
}
|
||||
port := config.Port
|
||||
|
||||
log.Printf("")
|
||||
log.Printf("🚀 Starting Counter Application Server...")
|
||||
log.Printf(" 🌐 Listening on: http://localhost:%s", port)
|
||||
log.Printf(" 📊 Health check: http://localhost:%s/health", port)
|
||||
log.Printf(" 🔗 API endpoint: http://localhost:%s/api/v1", port)
|
||||
log.Printf(" 🎨 Frontend: http://localhost:%s/", port)
|
||||
log.Printf("")
|
||||
log.Printf("✅ Server is ready and accepting connections!")
|
||||
log.Printf("")
|
||||
|
||||
log.Printf("Server starting on port %s", port)
|
||||
log.Fatal(r.Run(":" + port))
|
||||
}
|
||||
|
||||
10
scripts/dev.sh
Executable file
10
scripts/dev.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# Development environment script
|
||||
|
||||
echo "🚀 Starting Counter app in development mode..."
|
||||
|
||||
# Set environment
|
||||
export ENVIRONMENT=development
|
||||
|
||||
# Start with development configuration
|
||||
docker-compose -f docker-compose.yml up --build
|
||||
10
scripts/prod.sh
Executable file
10
scripts/prod.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# Production environment script
|
||||
|
||||
echo "🚀 Starting Counter app in production mode..."
|
||||
|
||||
# Set environment
|
||||
export ENVIRONMENT=production
|
||||
|
||||
# Start with production configuration
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up --build -d
|
||||
10
scripts/staging.sh
Executable file
10
scripts/staging.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# Staging environment script
|
||||
|
||||
echo "🚀 Starting Counter app in staging mode..."
|
||||
|
||||
# Set environment
|
||||
export ENVIRONMENT=staging
|
||||
|
||||
# Start with staging configuration
|
||||
docker-compose -f docker-compose.yml -f docker-compose.staging.yml up --build -d
|
||||
Reference in New Issue
Block a user