Files
azionelab-v2/README.md
T
2026-06-24 11:06:33 +02:00

208 lines
7.9 KiB
Markdown

# Azione!Lab
A warm, editorial single-page website for a contemporary theatre workshop. Wagtail
provides an editor-friendly headless CMS, Astro renders the public site, PostgreSQL
stores content, and Docker Compose supplies a reproducible local environment.
## Architecture
- `backend/`: Django and Wagtail admin, content models, media uploads, and the
aggregate read-only API at `GET /api/site/home/`.
- `frontend/`: Astro components, responsive design system, typed API adapter, and
Italian fallback content for development when the CMS is unavailable.
- `nginx/`: reverse proxy for `azionelab.org`, with optional HTTPS termination and
automatic reload after certificate renewal.
- `certbot/`: optional Let's Encrypt HTTP-01 issue/renew loop for direct deployments.
- `db`: persistent PostgreSQL database.
- Docker volumes persist PostgreSQL, media, ACME challenges, and certificates.
See [the architecture document](docs/architecture.md),
[ADR-0001](docs/adr/0001-headless-wagtail-astro.md), and
[ADR-0002](docs/adr/0002-nginx-reverse-proxy.md), and
[ADR-0003](docs/adr/0003-optional-letsencrypt.md) for the rationale.
## Prerequisites
- Docker Engine with Docker Compose v2.
- Ports `8080`, `8443`, `4321`, and `8000` available on localhost.
- A local hosts-file entry mapping `azionelab.org` to `127.0.0.1`.
No host Python or Node.js installation is required.
## Start locally
```bash
cp .env.example .env
docker compose up --build -d
docker compose ps
docker compose exec backend python manage.py seed_demo
```
For local domain resolution, add this line to `/etc/hosts` using your normal system
administration workflow:
```text
127.0.0.1 azionelab.org
```
Open:
- public site: <http://azionelab.org:8080>
- Wagtail admin: <http://azionelab.org:8080/admin/>
- aggregate API: <http://azionelab.org:8080/api/site/home/>
Direct loopback ports `4321` and `8000` remain available for local diagnostics only.
The frontend remains usable with curated fallback content if the API is unavailable.
On first startup the backend applies migrations and collects static files before
starting Gunicorn. Wait until the four default services report healthy. The optional
`certbot` service has zero replicas while `LETSENCRYPT_ENABLED=0`.
## Optional HTTPS with Let's Encrypt
Keep `LETSENCRYPT_ENABLED=0` when a load balancer terminates TLS. For direct public
exposure, first point the domain DNS records to the host and make TCP ports 80 and 443
reachable, then set:
```dotenv
LETSENCRYPT_ENABLED=1
LETSENCRYPT_DOMAIN=azionelab.org
LETSENCRYPT_EMAIL=operator@example.org
LETSENCRYPT_STAGING=1
NGINX_BIND_ADDRESS=0.0.0.0
NGINX_HTTP_PORT=80
NGINX_HTTPS_PORT=443
WAGTAILADMIN_BASE_URL=https://azionelab.org
DJANGO_DEBUG=false
```
Start with the staging CA to validate DNS and firewall configuration without consuming
production rate limits. Then change `LETSENCRYPT_STAGING=0` and remove the staging
certificate volume before requesting the trusted certificate; staging certificates
cannot be converted in place. See [deployment](docs/deployment.md) for the exact reset
and production commands.
## Create an editor account
```bash
docker compose exec backend python manage.py createsuperuser
```
Sign in to Wagtail at <http://azionelab.org:8080/admin/>. The public site has no user
accounts or authentication.
## Demo content
The seed command is idempotent and creates or updates the initial home page, site
settings, participation cards, teacher, lessons, shows, gallery entries, and local
placeholder images:
```bash
docker compose exec backend python manage.py seed_demo
```
Re-run it only when you intentionally want to restore the demo records. Content edited
after seeding may be overwritten for records managed by the command.
## Editing content
1. Open Wagtail admin and select **Pages** to edit the home hero, introduction,
laboratory section, and the three participation cards.
2. Select **Settings > Site settings** for the workshop name and contact details.
3. Use **Snippets** for the teacher, lessons, shows, and gallery.
4. Publish page changes. Snippet and settings changes are returned immediately by the
aggregate endpoint.
The frontend reads `PUBLIC_CMS_API_URL`; inside Compose it defaults to
`http://backend:8000`. Media URLs use `WAGTAILADMIN_BASE_URL` so browsers receive the
public reverse-proxy address. Change both values for another environment.
The standard published-page endpoint is also available at `/api/v2/pages/`.
The PostgreSQL service is named `db`. Existing `.env` files should replace `@postgres:`
with `@db:` in `DATABASE_URL`; a compatibility network alias keeps older local values
working during the transition.
## Useful commands
```bash
# Follow application logs
docker compose logs -f db backend frontend proxy certbot
# Run database migrations
docker compose exec backend python manage.py migrate
# Run all required checks in containers
docker compose run --rm backend python manage.py test
docker compose run --rm frontend npm run check
docker compose run --rm frontend npm run build
docker compose run --rm proxy nginx -t
docker compose -f docker-compose.yml -f docker-compose.test.yml --profile test run --rm backend python manage.py seed_demo
docker compose -f docker-compose.yml -f docker-compose.test.yml --profile test run --build --rm functional-tests
docker compose config --quiet
LETSENCRYPT_ENABLED=1 docker compose config --quiet
# Stop the stack without deleting content
docker compose down
# Stop and permanently delete local database and uploaded media
docker compose down --volumes
```
The final command is destructive. It is useful only when intentionally resetting the
local environment; run the seed command again after the next startup.
## Directory structure
```text
.
├── backend/ # Wagtail/Django CMS and API
├── certbot/ # Optional Let's Encrypt renewal loop
├── frontend/ # Astro public website
├── nginx/ # Reverse proxy and dynamic TLS configuration
├── tests/functional/ # Playwright browser tests
├── docker-compose.test.yml # Functional-test Compose override
├── docs/ # Architecture, operations, security, and ADRs
├── docker-compose.yml
├── .env.example
└── README.md
```
## Functional tests
The Compose test override builds a pinned Playwright image, exposes `azionelab.org` on
the internal Docker network, and runs the browser suite against NGINX. It replaces the
database mount with the isolated `test_postgres_data` volume, so the normal CMS data is
not changed. Refresh the idempotent test seed first:
```bash
docker compose -f docker-compose.yml -f docker-compose.test.yml --profile test run --rm backend python manage.py seed_demo
docker compose -f docker-compose.yml -f docker-compose.test.yml --profile test run --build --rm functional-tests
```
The suite covers page content and section order, contact actions, mobile navigation,
responsive overflow, semantic landmarks, image alternatives, the aggregate API and
media, Wagtail admin routing, and rejection of unknown virtual hosts.
## Database and media backups
Database rows and uploaded files must be backed up together:
```bash
mkdir -p backups/media
docker compose stop frontend backend
docker compose exec -T db sh -c 'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"' > backups/database.sql
docker compose cp backend:/app/media/. backups/media/
docker compose start backend frontend
```
This brief maintenance window keeps database rows and uploaded files in sync. See
[operations](docs/operations.md) for the destructive restore procedure and its
cautions. Do not commit database dumps, `.env`, or uploaded media.
## Production TODOs
This repository deliberately targets a simple, working local deployment. Before a
public production launch, configure either the optional direct TLS mode or TLS at the
load balancer, plus production-grade static/media serving, off-host backups,
monitoring, and a deployment-specific secret manager.