Files
kzbkowskiandClaude Sonnet 5 b313c126ce
CI / PHP 8.2 (push) Failing after 1m40s
CI / PHP 8.3 (push) Failing after 55s
CI / PHP 8.4 (push) Failing after 1m11s
Release image / image (push) Successful in 2m33s
ADconsole v1.1.0
Config backup, a Docker dev/prod split, and a Gitea-built release image.

Added
- /settings -> General -> "Configuration backup": JSON export/import of the
  panel's general settings + attribute definitions
  (App\Services\ConfigBackupService); audited as config.export / config.import.
  Export can leave out the attribute-encryption key. No AD data included.
- docker/compose.dev.yaml: live-reload dev stack that bind-mounts the working
  tree. docker/php/Dockerfile is now multi-stage (base -> dev / prod).
- .github/workflows/release.yml: on every vX.Y.Z tag, builds the prod image and
  pushes gitea.kzbikowski.pl/kzbkowski/adconsole:{X.Y.Z,X.Y,latest}.

Changed
- docker/compose.yaml: self-contained prod image (app code + composer install
  --no-dev baked in via COPY); persistent state in docker/data/{app_storage,db};
  defaults to the released image (ADCONSOLE_VERSION pins a tag, ADCONSOLE_IMAGE
  replaces the ref). Apache now honours public/.htaccess (AllowOverride All).
  Run from the repo root with --env-file .env.
- Repo root now holds only README.md; CHANGELOG / CONTRIBUTING / SECURITY /
  CODE_OF_CONDUCT moved under docs/.

Upgrade notes: docs/upgrading.md#v110--docker-layout. Full log: docs/CHANGELOG.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JKT9p3bfP8RZesExdYCS52
2026-09-10 09:13:04 +02:00

102 lines
4.0 KiB
YAML

name: adconsole
# =============================================================================
# Production stack — a self-contained PHP/Apache image + MariaDB, behind an
# external Traefik proxy on the `traefik_public` network.
#
# By default this runs the image the Gitea release workflow publishes
# (built from docker/php/Dockerfile, target `prod` — code + `composer install
# --no-dev` baked in). `up -d` pulls it; `up -d --build` rebuilds from the
# working tree instead. Nothing from the tree is mounted except `.env`.
# Persistent state lives next to this file:
#
# docker/data/app_storage -> /var/www/html/storage (logs, framework cache)
# docker/data/db -> /var/lib/mysql (database — BACK UP)
#
# Run FROM THE REPO ROOT and point Compose at the repo-root .env for
# ${...} interpolation:
#
# cp .env.example .env # then fill it in
# docker compose --env-file .env -f docker/compose.yaml up -d
# docker compose --env-file .env -f docker/compose.yaml logs -f app
#
# No Traefik? Add the local port-publishing override:
# cp docker/compose.override.yaml.template docker/compose.override.yaml
# docker compose --env-file .env \
# -f docker/compose.yaml -f docker/compose.override.yaml up -d
# # -> http://localhost:8080 (set APP_URL to match)
# =============================================================================
services:
app:
# Default: the image the Gitea release workflow (.github/workflows/release.yml)
# publishes for the current release. `docker compose ... pull` fetches it;
# `... up -d --build` rebuilds it locally under the same name instead. Pin a
# different build with ADCONSOLE_VERSION, or override the whole ref with
# ADCONSOLE_IMAGE.
image: ${ADCONSOLE_IMAGE:-gitea.kzbikowski.pl/kzbkowski/adconsole:${ADCONSOLE_VERSION:-1.1.0}}
build:
context: ..
dockerfile: docker/php/Dockerfile
target: prod
container_name: adconsole_app
restart: unless-stopped
environment:
# Reach the DB service by name — overrides the dev-oriented DB_HOST in the
# bind-mounted .env (Laravel's dotenv does not override a real env var).
DB_HOST: mariadb
volumes:
# `.env` is git-ignored and holds the service-account password; it is
# provided at runtime, not baked into the image. Laravel reads it directly.
- ../.env:/var/www/html/.env
- ./data/app_storage:/var/www/html/storage
depends_on:
mariadb:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost/up"]
interval: 30s
timeout: 5s
retries: 5
start_period: 60s
networks:
- internal
- traefik_public
labels:
- traefik.enable=true
- traefik.docker.network=traefik_public
- traefik.http.routers.adconsole.rule=Host(`${APP_DOMAIN:-adconsole.localhost}`)
- traefik.http.routers.adconsole.entrypoints=websecure
- traefik.http.routers.adconsole.tls=true
# Uncomment and set your resolver to let Traefik obtain a certificate:
# - traefik.http.routers.adconsole.tls.certresolver=letsencrypt
- traefik.http.services.adconsole.loadbalancer.server.port=80
mariadb:
image: mariadb:11
container_name: adconsole_db
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-change-me-root}
MARIADB_DATABASE: ${DB_DATABASE:-adconsole}
MARIADB_USER: ${DB_USERNAME:-adconsole}
MARIADB_PASSWORD: ${DB_PASSWORD:-change-me}
MARIADB_AUTO_UPGRADE: "1"
volumes:
- ./data/db:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
networks:
- internal
networks:
internal:
# Provided by your Traefik deployment. If you use the port-publishing
# override instead, it redefines this as a local network.
traefik_public:
external: true