diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7e46ec9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,54 @@ +# Database files +*.db +*.db-shm +*.db-wal + +# Binaries +mealprep +*.exe +*.dll +*.so +*.dylib + +# Test and coverage files +*.test +*.out +coverage.txt +*.coverprofile + +# Documentation +*.md +*.txt +IMPLEMENTATION_NOTES.txt +SECURITY_REPORT.txt + +# Git +.git +.gitignore + +# IDE and editor files +.vscode +.idea +*.swp +*.swo +*~ +.DS_Store + +# Logs +*.log +logs/ + +# Temporary files +tmp/ +temp/ +.env +.env.local + +# Build artifacts +dist/ +build/ + +# Docker files (no need to include in image) +Dockerfile +docker-compose.yml +.dockerignore diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e0f8ada --- /dev/null +++ b/Dockerfile @@ -0,0 +1,53 @@ +# Build stage +FROM golang:1.21-bookworm AS builder + +# Install build dependencies +RUN apt-get update && apt-get install -y \ + gcc \ + sqlite3 \ + libsqlite3-dev \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /build + +# Copy go mod files +COPY go.mod go.sum ./ + +# Download dependencies +RUN go mod download + +# Copy source code +COPY . . + +# Build the application +RUN CGO_ENABLED=1 go build -o mealprep -ldflags="-s -w" . + +# Runtime stage +FROM debian:bookworm-slim + +# Install runtime dependencies +RUN apt-get update && apt-get install -y \ + ca-certificates \ + sqlite3 \ + libsqlite3-0 \ + && rm -rf /var/lib/apt/lists/* + +# Create app directory and data directory +WORKDIR /app +RUN mkdir -p /app/data + +# Copy binary from builder +COPY --from=builder /build/mealprep . + +# Copy static files +COPY --from=builder /build/static ./static + +# Expose port +EXPOSE 8080 + +# Set environment variables +ENV DB_PATH=/app/data/mealprep.db + +# Run the application +CMD ["./mealprep"] diff --git a/Makefile b/Makefile index 6376c24..f8865e7 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,13 @@ -.PHONY: run build clean test deps install +.PHONY: all run build clean test deps install docker-build docker-up docker-down docker-logs docker-restart docker-clean help -# Run the application +# Default target: build and start with Docker +all: docker-up + +# Run the application locally run: go run main.go -# Build the binary +# Build the binary locally build: go build -o mealprep main.go @@ -33,14 +36,95 @@ test: install: go install +# Docker: Build the Docker image +docker-build: + docker build -t mealprep:latest . + +# Docker: Build and start containers +docker-up: + docker compose up -d + +# Docker: Build and start with logs +docker-up-logs: + docker compose up --build + +# Docker: Stop and remove containers +docker-down: + docker compose down + +# Docker: View logs +docker-logs: + docker compose logs -f + +# Docker: Restart containers +docker-restart: + docker compose restart + +# Docker: Stop containers +docker-stop: + docker compose stop + +# Docker: Start containers +docker-start: + docker compose start + +# Docker: Clean everything (containers, volumes, images) +docker-clean: + docker compose down -v + docker rmi mealprep:latest 2>/dev/null || true + +# Docker: Rebuild and restart +docker-rebuild: + docker compose down + docker compose build --no-cache + docker compose up -d + +# Docker: Shell into container +docker-shell: + docker exec -it mealprep-app /bin/sh + +# Docker: Show container status +docker-status: + docker compose ps + +# Deploy: Build and deploy to production +deploy: docker-build + @echo "Building and deploying to Docker server..." + docker compose up -d --build + @echo "Deployment complete!" + # Show help help: @echo "Available targets:" - @echo " run - Run the application" - @echo " build - Build the binary" - @echo " deps - Install dependencies" - @echo " clean - Remove binary and database" - @echo " clean-db - Remove only database" - @echo " test - Run tests" - @echo " install - Install binary to GOPATH" - @echo " help - Show this help message" + @echo "" + @echo "Default:" + @echo " make / all - Build and start with Docker (default)" + @echo "" + @echo "Local Development:" + @echo " run - Run the application locally" + @echo " build - Build the binary locally" + @echo " deps - Install dependencies" + @echo " clean - Remove binary and database" + @echo " clean-db - Remove only database" + @echo " dev - Run with auto-reload (requires air)" + @echo " test - Run tests" + @echo " install - Install binary to GOPATH" + @echo "" + @echo "Docker Commands:" + @echo " docker-build - Build the Docker image" + @echo " docker-up - Build and start containers in background" + @echo " docker-up-logs - Build and start with logs attached" + @echo " docker-down - Stop and remove containers" + @echo " docker-logs - View container logs" + @echo " docker-restart - Restart containers" + @echo " docker-stop - Stop containers" + @echo " docker-start - Start stopped containers" + @echo " docker-clean - Remove everything (containers, volumes, images)" + @echo " docker-rebuild - Rebuild from scratch and start" + @echo " docker-shell - Open shell in container" + @echo " docker-status - Show container status" + @echo "" + @echo "Deployment:" + @echo " deploy - Build and deploy to production" + @echo "" + @echo " help - Show this help message" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..403de0b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +services: + mealprep: + build: + context: . + dockerfile: Dockerfile + container_name: mealprep-app + ports: + - "8080:8080" + volumes: + - mealprep-data:/app/data + environment: + - DB_PATH=/app/data/mealprep.db + restart: unless-stopped + healthcheck: + test: + [ + "CMD", + "wget", + "--quiet", + "--tries=1", + "--spider", + "http://localhost:8080/health", + ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + +volumes: + mealprep-data: + driver: local diff --git a/main.go b/main.go index 1e9a7a9..befb640 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "mealprep/database" "mealprep/handlers" "net/http" + "os" "strings" ) @@ -15,8 +16,14 @@ func main() { // Print startup banner printBanner() + // Get database path from environment variable or use default + dbPath := os.Getenv("DB_PATH") + if dbPath == "" { + dbPath = "mealprep.db" + } + // Initialize database - if err := database.InitDB("mealprep.db"); err != nil { + if err := database.InitDB(dbPath); err != nil { log.Fatalf("Failed to initialize database: %v", err) } defer database.DB.Close() @@ -48,6 +55,12 @@ func main() { }) http.HandleFunc("/logout", handlers.LogoutHandler) + // Health check endpoint (public, for Docker) + http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte("OK")) + }) + // Protected routes http.HandleFunc("/", auth.RequireAuth(indexHandler))