generated from bisco/codex-bootstrap
feat: add wordpress site variant
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
# ADR-0001: WordPress single-page architecture
|
||||
|
||||
Date: 2026-06-24
|
||||
|
||||
Status: Accepted
|
||||
|
||||
## Context
|
||||
|
||||
Azione!Lab needs a warm editorial single page whose primary content can be edited by
|
||||
non-developers. This branch explicitly explores WordPress as an alternative product
|
||||
architecture and starts independently from `main`.
|
||||
|
||||
## Decision
|
||||
|
||||
Use pinned WordPress 7.0/PHP 8.3 with MariaDB 11.8 LTS. Build a dependency-free custom
|
||||
classic theme for exact semantic markup and responsive design. Store homepage fields as
|
||||
sanitized theme modifications, while a must-use plugin owns Shows and Gallery custom
|
||||
post types so structured content is not lost when changing themes.
|
||||
|
||||
NGINX is the only public entry point. WP-CLI provides an idempotent opt-in bootstrap;
|
||||
Certbot provides opt-in direct TLS. Docker networks isolate the database and functional
|
||||
tests use separate volumes.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Editors use familiar WordPress screens without a page builder or required plugin.
|
||||
- WordPress renders the page directly; there is no headless API/frontend deployment.
|
||||
- WordPress and MariaDB replace Astro, Wagtail, Django, and PostgreSQL in this branch.
|
||||
- Core/theme/plugin patches require an image rebuild in production.
|
||||
- Fixed participation cards remain code until editorial requirements justify another
|
||||
structured content type.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
- A block theme was not selected because the first version prioritizes controlled
|
||||
markup and a compact implementation over full-site editing.
|
||||
- A commercial/custom-fields plugin was rejected as an unnecessary dependency.
|
||||
- A headless WordPress frontend was rejected because it would recreate the operational
|
||||
complexity this variant is intended to remove.
|
||||
|
||||
## Security impact
|
||||
|
||||
The architecture inherits WordPress's public CMS attack surface. The implementation
|
||||
reduces it with network isolation, no direct application port, disabled file editing
|
||||
and XML-RPC, production immutability, sanitization/escaping, rate limiting, security
|
||||
headers, and fail-closed TLS. Admin MFA and allowlisting remain external controls.
|
||||
|
||||
## Operational impact
|
||||
|
||||
Database and WordPress files are coordinated state and must be backed up together.
|
||||
Operators must monitor upstream security releases and rebuild pinned images. SMTP and
|
||||
off-host storage are not part of this minimal base.
|
||||
|
||||
## Rollback
|
||||
|
||||
Revert the implementation commit and rebuild. Preserve WordPress, database, and
|
||||
certificate volumes unless data deletion is intentional. Restore data only from a
|
||||
verified coordinated backup.
|
||||
+19
-9
@@ -1,13 +1,23 @@
|
||||
# Architecture
|
||||
|
||||
Describe the project architecture here.
|
||||
NGINX is the only public entry point for `azionelab.org`. It proxies HTTP to the
|
||||
official WordPress 7.0/PHP 8.3 Apache image over the private `web` network. WordPress
|
||||
connects to MariaDB 11.8 LTS over a separate internal `data` network. Neither WordPress
|
||||
nor MariaDB publishes a host port.
|
||||
|
||||
Include:
|
||||
The custom `azionelab` classic theme renders the public single page. Theme modifications
|
||||
store the hero, manifesto, laboratory, teacher, lesson, and contact fields. The
|
||||
`azionelab-content` must-use plugin registers Shows and Gallery custom post types so
|
||||
structured editorial content survives a theme change. Images use WordPress featured
|
||||
images with local SVG fallbacks.
|
||||
|
||||
- main components;
|
||||
- runtime dependencies;
|
||||
- data flow;
|
||||
- persistence;
|
||||
- external integrations;
|
||||
- deployment topology;
|
||||
- relevant ADRs.
|
||||
WP-CLI is an opt-in tools-profile service. Its idempotent bootstrap installs WordPress,
|
||||
activates the theme, configures the site, and creates realistic demo content. Certbot is
|
||||
another optional service, enabled only for direct deployments. It shares challenge and
|
||||
certificate volumes with NGINX but has no container-control access.
|
||||
|
||||
Persistent state lives in `db_data`, `wordpress_data`, and the certificate volumes.
|
||||
Functional tests replace the first two with isolated test volumes and reach NGINX via
|
||||
an internal `azionelab.org` network alias.
|
||||
|
||||
See [ADR-0001](adr/0001-wordpress-single-page.md).
|
||||
|
||||
+37
-11
@@ -1,15 +1,41 @@
|
||||
# Deployment
|
||||
|
||||
Describe how this project is deployed.
|
||||
## Local
|
||||
|
||||
Include:
|
||||
Copy `.env.example` to `.env`, add `127.0.0.1 azionelab.org` to the hosts file, then:
|
||||
|
||||
- environments;
|
||||
- Docker/Compose usage;
|
||||
- required configuration;
|
||||
- secrets handling;
|
||||
- exposed ports;
|
||||
- volumes;
|
||||
- networks;
|
||||
- deployment commands;
|
||||
- rollback procedure.
|
||||
```bash
|
||||
docker compose up --build -d
|
||||
docker compose --profile tools run --rm wp-cli /scripts/bootstrap.sh
|
||||
```
|
||||
|
||||
NGINX binds to loopback ports 8080/8443. WordPress and MariaDB remain private. The
|
||||
bootstrap is safe to rerun and does not duplicate demo records.
|
||||
|
||||
## Production
|
||||
|
||||
Required controls:
|
||||
|
||||
- `WP_ENVIRONMENT_TYPE=production`;
|
||||
- unique non-placeholder MariaDB passwords of at least 16 characters;
|
||||
- `WORDPRESS_DEBUG=0` and a strong administrator password;
|
||||
- an HTTPS `WP_URL`;
|
||||
- managed secrets outside the Compose file;
|
||||
- either direct Let's Encrypt termination or a trusted external load balancer;
|
||||
- off-host database/file backups and monitoring.
|
||||
|
||||
When a load balancer terminates TLS, Certbot stays disabled. `TRUST_PROXY_HEADERS=1`
|
||||
is safe only when firewall/network policy makes the load balancer the sole NGINX
|
||||
caller and it overwrites `X-Forwarded-*` headers.
|
||||
|
||||
For direct TLS, public DNS and inbound ports 80/443 must reach NGINX. Start with
|
||||
`LETSENCRYPT_STAGING=1`; application HTTP returns 503 until a certificate exists, then
|
||||
redirects to HTTPS. Switch to the production CA only after validating DNS and firewall
|
||||
behavior, removing only the staging certificate volume when necessary.
|
||||
|
||||
## State and rollback
|
||||
|
||||
Database and WordPress file volumes must be backed up together. Code rollback is a
|
||||
container rebuild from a prior commit and does not require deleting volumes. Never use
|
||||
`docker compose down --volumes` where content must survive. Test database restoration
|
||||
in a disposable environment before any production restore.
|
||||
|
||||
+37
-9
@@ -1,13 +1,41 @@
|
||||
# Operations
|
||||
|
||||
Describe operational procedures.
|
||||
## Routine commands
|
||||
|
||||
Include:
|
||||
```bash
|
||||
docker compose up --build -d
|
||||
docker compose ps
|
||||
docker compose logs -f proxy wordpress db certbot
|
||||
docker compose --profile tools run --rm wp-cli -c 'wp core version'
|
||||
docker compose down
|
||||
```
|
||||
|
||||
- startup and shutdown;
|
||||
- health checks;
|
||||
- logs;
|
||||
- monitoring;
|
||||
- backup and restore;
|
||||
- routine maintenance;
|
||||
- known operational risks.
|
||||
The proxy healthcheck reaches WordPress, and WordPress health reaches its login route.
|
||||
MariaDB uses its official readiness check. WordPress access logs are disabled while
|
||||
PHP warnings/errors remain visible. NGINX is the request audit trail; apply an explicit
|
||||
retention policy because it contains client metadata.
|
||||
|
||||
## Updates
|
||||
|
||||
WordPress, PHP, MariaDB, NGINX, Certbot, and Playwright use explicit image versions.
|
||||
Review security releases routinely, update pins in a task branch, rebuild, run the full
|
||||
test suite, and deploy. Production disables WordPress web-based file modifications, so
|
||||
image rebuilds are the update path.
|
||||
|
||||
## Backup and restore
|
||||
|
||||
Create database and `wordpress_data` backups in one maintenance window. Backups contain
|
||||
credentials, accounts, contact information, and uploaded media; encrypt them, restrict
|
||||
access, set retention, and store copies off-host.
|
||||
|
||||
A restore is destructive. Validate it on isolated volumes, then stop WordPress, restore
|
||||
the database and file volume together, restart, and verify the homepage, media,
|
||||
`/wp-admin/`, and user accounts.
|
||||
|
||||
## Known risks
|
||||
|
||||
- Local named volumes are not backups.
|
||||
- SMTP is not configured; WordPress password-reset email needs an external mail service.
|
||||
- Admin MFA and network allowlisting are deployment concerns and are not bundled.
|
||||
- WordPress plugins expand the attack surface; install only reviewed, maintained,
|
||||
necessary plugins.
|
||||
|
||||
+21
-10
@@ -1,19 +1,30 @@
|
||||
# Runbook
|
||||
|
||||
Operational runbook for this project.
|
||||
## Installation screen remains visible
|
||||
|
||||
## Common tasks
|
||||
1. Check `docker compose ps` for healthy database and WordPress services.
|
||||
2. Run `docker compose --profile tools run --rm wp-cli /scripts/bootstrap.sh`.
|
||||
3. Inspect `docker compose logs wordpress db` without printing secret values.
|
||||
|
||||
Document routine operational tasks here.
|
||||
## NGINX returns 502
|
||||
|
||||
## Troubleshooting
|
||||
1. Run `docker compose ps` and `docker compose exec proxy nginx -t`.
|
||||
2. Check the WordPress health status and `docker compose logs proxy wordpress`.
|
||||
3. Confirm the request host is exactly `azionelab.org`; unknown hosts return 404.
|
||||
|
||||
Document known issues, symptoms, checks, and remediation steps.
|
||||
## Images or theme are missing
|
||||
|
||||
1. Confirm `wordpress_data` is mounted in both WordPress and WP-CLI.
|
||||
2. Run `docker compose --profile tools run --rm wp-cli -c 'wp theme status azionelab'`.
|
||||
3. Verify file ownership before changing permissions; never make the tree world-writable.
|
||||
|
||||
## Certificate issuance fails
|
||||
|
||||
Verify public DNS, inbound port 80, the operator email, and staging mode. Request a
|
||||
missing `/.well-known/acme-challenge/` path: an NGINX 404 confirms the route is yours.
|
||||
Avoid repeated production-CA retries while debugging.
|
||||
|
||||
## Rollback
|
||||
|
||||
Document rollback procedures here.
|
||||
|
||||
## Emergency contacts
|
||||
|
||||
Document project-specific escalation paths if appropriate.
|
||||
Revert the deployment commit and rebuild while preserving all named volumes. Restore
|
||||
database/files only for a data rollback and only from a verified coordinated backup.
|
||||
|
||||
+29
-13
@@ -1,16 +1,32 @@
|
||||
# Security
|
||||
|
||||
Describe security assumptions and controls.
|
||||
- NGINX is the only published service. MariaDB is restricted to an internal network;
|
||||
WordPress is reachable only from NGINX and the database network.
|
||||
- Production startup rejects placeholder or short database passwords. `.env` is
|
||||
ignored and real secrets must come from the deployment secret manager.
|
||||
- WordPress uses its normal capability, nonce, authentication, cookie, and password
|
||||
controls. Theme settings sanitize input and templates escape output.
|
||||
- File editing is always disabled. Production also disables web-based core, theme, and
|
||||
plugin changes; patched images are rebuilt and redeployed instead.
|
||||
- XML-RPC and comments are disabled. NGINX blocks PHP execution below uploads, dotfiles,
|
||||
and direct `wp-config.php` requests, and rate-limits login/public requests. Public
|
||||
REST user enumeration and author archives are disabled.
|
||||
- Security headers include CSP, same-origin framing, content-type protection, a strict
|
||||
referrer policy, and a restrictive Permissions Policy. WordPress compatibility still
|
||||
requires inline style/script CSP allowances; do not treat this CSP as an XSS sanitizer.
|
||||
- Forwarded client/protocol headers are overwritten by default. Trust mode is permitted
|
||||
only behind a restricted load balancer that overwrites those headers.
|
||||
- Direct TLS is fail-closed until a certificate exists. Certbot has a read-only root,
|
||||
no Docker socket, dropped capabilities, and narrowly scoped volumes.
|
||||
- Containers are not privileged and do not use host networking or the Docker socket.
|
||||
WordPress/Apache retains the capabilities needed by the official image internally,
|
||||
but no WordPress port is published.
|
||||
- WordPress/Apache access logs are disabled to avoid duplicate client metadata and
|
||||
healthcheck noise; NGINX remains the single request log and PHP warnings/errors stay
|
||||
visible.
|
||||
- Admin MFA, an IP/VPN allowlist, SMTP, malware scanning, log aggregation, and a secret
|
||||
manager remain production operator responsibilities.
|
||||
- Backups and uploads can contain personal data. Encrypt, restrict, retain, and delete
|
||||
them according to the applicable privacy policy.
|
||||
|
||||
Include:
|
||||
|
||||
- authentication;
|
||||
- authorization;
|
||||
- network exposure;
|
||||
- TLS/certificates;
|
||||
- secrets management;
|
||||
- logging of sensitive data;
|
||||
- container privileges;
|
||||
- filesystem permissions;
|
||||
- dependency management;
|
||||
- relevant ADRs.
|
||||
See [ADR-0001](adr/0001-wordpress-single-page.md).
|
||||
|
||||
+17
-16
@@ -1,23 +1,24 @@
|
||||
# Testing
|
||||
|
||||
Describe how tests are executed.
|
||||
|
||||
All tests should run inside Docker containers.
|
||||
|
||||
## Canonical test command
|
||||
All checks run inside Docker containers.
|
||||
|
||||
```bash
|
||||
CHANGE_ME
|
||||
docker compose run --rm --no-deps wordpress php -l /opt/azionelab/theme/functions.php
|
||||
docker compose run --rm --no-deps wordpress php -l /opt/azionelab/theme/front-page.php
|
||||
docker compose run --rm --no-deps wordpress php -l /opt/azionelab/azionelab-content.php
|
||||
docker compose run --rm --no-deps proxy nginx -t
|
||||
docker compose -f docker-compose.yml -f docker-compose.test.yml up --build -d db wordpress proxy
|
||||
docker compose -f docker-compose.yml -f docker-compose.test.yml --profile tools run --rm wp-cli /scripts/bootstrap.sh
|
||||
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
|
||||
```
|
||||
|
||||
## Test categories
|
||||
The override replaces normal database and WordPress volumes, maps `azionelab.org` to
|
||||
the internal proxy, and never publishes an extra port. Browser tests cover content and
|
||||
section order, contact actions, mobile overflow/navigation, semantic landmarks, image
|
||||
alternatives, admin routing, security headers, blocked sensitive routes, and unknown
|
||||
virtual hosts.
|
||||
|
||||
Describe applicable categories:
|
||||
|
||||
- unit tests;
|
||||
- integration tests;
|
||||
- linting;
|
||||
- formatting checks;
|
||||
- Ansible syntax checks;
|
||||
- Docker/Compose validation;
|
||||
- smoke tests.
|
||||
Subjective visual review and a real-device accessibility audit remain manual release
|
||||
checks.
|
||||
|
||||
Reference in New Issue
Block a user