diff --git a/Makefile b/Makefile index 54e6a0b..cea32de 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,10 @@ endif # Override with: CONTAINER_RUNTIME=podman make rebuild-app CONTAINER_RUNTIME ?= $(shell command -v docker 2>/dev/null || command -v podman 2>/dev/null) +# Dev compose stack: base prod file merged with the dev override (local build + tests). +# Prod deploy does NOT use this — it runs plain `docker compose` against the base file only. +COMPOSE := $(CONTAINER_RUNTIME) compose -f docker-compose.yml -f docker-compose.dev.yml + # Default target help: @echo "Available targets:" @@ -48,9 +52,9 @@ test: # Run integration tests in containers (matches production environment) test-integration: @echo "Building test containers..." - $(CONTAINER_RUNTIME) compose --profile tests build + $(COMPOSE) --profile tests build @echo "Starting application containers..." - $(CONTAINER_RUNTIME) compose up -d db app + $(COMPOSE) up -d db app @echo "Waiting for services to be healthy..." @until $(CONTAINER_RUNTIME) exec bookhoard_db pg_isready -U postgres > /dev/null 2>&1; do \ echo " Database not ready yet..."; \ @@ -64,7 +68,7 @@ test-integration: echo " ✓ Application is ready" @echo "" @echo "Running integration tests in container..." - $(CONTAINER_RUNTIME) compose --profile tests run --rm tests + $(COMPOSE) --profile tests run --rm tests @echo "" @echo "✅ Integration tests completed!" @echo "📝 Containers are still running. Use 'make logs' to view logs or 'make clean' to stop." @@ -75,67 +79,67 @@ test-all: test test-integration # Rebuild app container only (preserve DB, with cache) rebuild-app: @echo "Rebuilding app container (database stays running)..." - $(CONTAINER_RUNTIME) compose up --build --force-recreate -d app + $(COMPOSE) up --build --force-recreate -d app @echo "✓ App container rebuilt and restarted" # Rebuild app container only (preserve DB, no cache) rebuild-app-force: @echo "Force rebuilding app container (database stays running, no cache)..." - $(CONTAINER_RUNTIME) compose build --no-cache app - $(CONTAINER_RUNTIME) compose up --force-recreate -d app + $(COMPOSE) build --no-cache app + $(COMPOSE) up --force-recreate -d app @echo "✓ App container rebuilt and restarted" # Rebuild all containers (preserve DB, with cache) rebuild: @echo "Rebuilding all containers (database preserved)..." - $(CONTAINER_RUNTIME) compose up --build --force-recreate -d + $(COMPOSE) up --build --force-recreate -d @echo "✓ All containers rebuilt and restarted" # Rebuild all containers (preserve DB, no cache) rebuild-force: @echo "Force rebuilding all containers (database preserved, no cache)..." - $(CONTAINER_RUNTIME) compose build --no-cache - $(CONTAINER_RUNTIME) compose up --force-recreate -d + $(COMPOSE) build --no-cache + $(COMPOSE) up --force-recreate -d @echo "✓ All containers rebuilt and restarted" # Rebuild all containers (remove DB, no cache) rebuild-force-db: @echo "Force rebuilding all containers (database will be DELETED, no cache)..." - $(CONTAINER_RUNTIME) compose down -v - $(CONTAINER_RUNTIME) compose build --no-cache - $(CONTAINER_RUNTIME) compose up --force-recreate -d + $(COMPOSE) down -v + $(COMPOSE) build --no-cache + $(COMPOSE) up --force-recreate -d @echo "✓ All containers rebuilt and restarted" # Stop and remove containers clean: - $(CONTAINER_RUNTIME) compose down -v + $(COMPOSE) down -v # Quick start (if already built) up: - $(CONTAINER_RUNTIME) compose up -d + $(COMPOSE) up -d # Stop all containers (alias for clean) down: - $(CONTAINER_RUNTIME) compose down + $(COMPOSE) down # Restart app container (preserves database) restart: @echo "Restarting app container (database stays running)..." - $(CONTAINER_RUNTIME) compose restart app + $(COMPOSE) restart app @echo "✓ App container restarted" # Show container status ps: - $(CONTAINER_RUNTIME) compose ps + $(COMPOSE) ps # Show container logs logs: - $(CONTAINER_RUNTIME) compose logs -f + $(COMPOSE) logs -f # Start containers with test mode enabled for manual testing test-env-up: @echo "Starting containers with test mode enabled..." - TEST_MODE=true RATE_LIMIT_ENABLED=false REQUESTS_PER_MINUTE=1000 $(CONTAINER_RUNTIME) compose up --build --force-recreate -d + TEST_MODE=true RATE_LIMIT_ENABLED=false REQUESTS_PER_MINUTE=1000 $(COMPOSE) up --build --force-recreate -d @echo "Waiting for services to be ready..." @until $(CONTAINER_RUNTIME) exec bookhoard_db pg_isready -U postgres > /dev/null 2>&1; do sleep 1; done @until $(CONTAINER_RUNTIME) exec bookhoard curl -sf http://localhost:8765/health > /dev/null 2>&1; do sleep 1; done @@ -144,7 +148,7 @@ test-env-up: # Stop test environment test-env-down: - $(CONTAINER_RUNTIME) compose down -v + $(COMPOSE) down -v # Verify project guidelines compliance verify-guidelines: diff --git a/README.md b/README.md index 0cf835f..08caec9 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ A modern self-hosted media library system built with Go, PostgreSQL, HTMX, and T ```bash # 1. Clone the repository -git clone https://github.com/yourusername/bookhoard.git +git clone https://git.linuxhg.com/Bookhoard/bookhoard.git cd bookhoard # 2. Set up environment @@ -35,8 +35,10 @@ cp .env.example .env # DBPASS: openssl rand -hex 16 # Edit .env with your generated values -# 3. Start the server -podman-compose up --build -d # or: docker-compose up --build -d +# 3. Pull images and start the server +docker compose pull +docker compose up -d +# Optionally pin a specific version: set IMAGE_TAG in .env (defaults to "latest") # 4. Open your browser open http://localhost:8765 diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..8f43223 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,57 @@ +# Development override — merged on top of docker-compose.yml (the base/prod file). +# Activated by all `make` targets via: +# COMPOSE = compose -f docker-compose.yml -f docker-compose.dev.yml +# +# What this adds over prod: +# - Local image BUILDING (prod pulls a prebuilt image from the registry) +# - The integration-tests service (dev only, gated behind the "tests" profile) +# Everything else (env vars, volumes, ports, healthchecks) is inherited from the base file. +services: + # Build the app image locally instead of pulling from the registry + app: + build: + context: . + dockerfile: ./Dockerfile + + # Integration Tests - runs against containerized app and db (dev only) + tests: + build: + context: . + dockerfile: ./Dockerfile + target: test-runner + container_name: bookhoard_tests + environment: + # Database Configuration + DATABASE_HOST: db + DATABASE_PORT: "5432" + DATABASE_USER: postgres + DATABASE_PASSWORD: ${DBPASS} + DATABASE_NAME: bookhoard + COOKIE_SECURE: false + + # Application Configuration + JWT_SECRET: ${JWT_SECRET} + SERVER_PORT: "8765" + + # Test Configuration + TEST_MODE: "true" + RATE_LIMIT_ENABLED: "false" + REQUESTS_PER_MINUTE: 1000 + + # Conversion Service Configuration + BOOKHOARD_CONVERSION_CACHE_DIR: /app/cache/kepub + BOOKHOARD_CONVERSION_TOOL: /usr/bin/kepubify + BOOKHOARD_CONVERSION_CACHE_TTL: 24h + + # Test upload path (inside container) + TEST_UPLOAD_PATH: /app/uploads + depends_on: + db: + condition: service_healthy + app: + condition: service_healthy + volumes: + - ./uploads:/app/uploads + - bookhoard_conversion_cache:/app/cache/kepub + profiles: + - tests diff --git a/docker-compose.yml b/docker-compose.yml index c652ef1..c43d3e5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,10 +27,10 @@ services: - .env # Bookhoard Application + # In production this image is pulled from the Gitea container registry. + # Override IMAGE_TAG in .env to pin or rollback a specific version (defaults to "latest"). app: - build: - context: . - dockerfile: ./Dockerfile + image: git.linuxhg.com/bookhoard/bookhoard:${IMAGE_TAG:-latest} container_name: bookhoard environment: # Database Configuration @@ -76,49 +76,6 @@ services: retries: 3 start_period: 10s - # Integration Tests - runs against containerized app and db - tests: - build: - context: . - dockerfile: ./Dockerfile - target: test-runner - container_name: bookhoard_tests - environment: - # Database Configuration - DATABASE_HOST: db - DATABASE_PORT: "5432" - DATABASE_USER: postgres - DATABASE_PASSWORD: ${DBPASS} - DATABASE_NAME: bookhoard - COOKIE_SECURE: false - - # Application Configuration - JWT_SECRET: ${JWT_SECRET} - SERVER_PORT: "8765" - - # Test Configuration - TEST_MODE: "true" - RATE_LIMIT_ENABLED: "false" - REQUESTS_PER_MINUTE: 1000 - - # Conversion Service Configuration - BOOKHOARD_CONVERSION_CACHE_DIR: /app/cache/kepub - BOOKHOARD_CONVERSION_TOOL: /usr/bin/kepubify - BOOKHOARD_CONVERSION_CACHE_TTL: 24h - - # Test upload path (inside container) - TEST_UPLOAD_PATH: /app/uploads - depends_on: - db: - condition: service_healthy - app: - condition: service_healthy - volumes: - - ./uploads:/app/uploads - - bookhoard_conversion_cache:/app/cache/kepub - profiles: - - tests - # Named Volumes volumes: postgres_data: