From 2aaeefb37f1314fa952d0824ac5b9db05db57681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Sun, 26 Oct 2025 18:22:11 +0100 Subject: [PATCH] fix: awsm labels --- CLAUDE.md | 184 ++++++++++++++++++++++++++++++++++++++++++++++ awsm/compose.yaml | 8 -- 2 files changed, 184 insertions(+), 8 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..d6f15a1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,184 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +Multi-service Docker Compose stack named "falcon" managing production services on pivoine.art domain. Uses Arty for configuration management with centralized environment variables and custom scripts. + +## Architecture + +### Compose Include Pattern +Root `compose.yaml` uses Docker Compose's `include` directive to orchestrate multiple service stacks: +- **core**: Shared PostgreSQL 16 + Redis 7 infrastructure +- **proxy**: Traefik reverse proxy with Let's Encrypt SSL +- **sexy**: Directus 11 CMS + SvelteKit frontend +- **awsm**: Next.js application with SQLite +- **track**: Umami analytics (PostgreSQL) +- **gotify**: Push notification server +- **vpn**: WireGuard VPN (wg-easy) + +All services connect to a single external Docker network (`falcon_network` by default, defined by `$NETWORK_NAME`). + +### Environment Management via Arty +Configuration is centralized in `arty.yml`: +- **envs.default**: All environment variables with sensible defaults +- **scripts**: Common Docker Compose and operational commands +- Variables follow naming pattern: `{SERVICE}_COMPOSE_PROJECT_NAME`, `{SERVICE}_TRAEFIK_HOST`, etc. + +Sensitive values (passwords, secrets) live in `.env` and override arty.yml defaults. + +### Traefik Routing Architecture +Services expose themselves via Docker labels: +- HTTP → HTTPS redirect on `web` entrypoint (port 80) +- SSL termination on `web-secure` entrypoint (port 443) +- Let's Encrypt certificates stored in `proxy` volume +- Path-based routing: `/api` routes to Directus backend, root to frontend +- Compression middleware applied via labels +- All routers scoped to `$NETWORK_NAME` network + +### Database Initialization +`core/postgres/init/01-init-databases.sh` runs on first PostgreSQL startup: +- Creates `directus` database for Sexy CMS +- Creates `umami` database for Track analytics +- Grants privileges to `$DB_USER` + +## Common Commands + +All commands use `pnpm arty` (leveraging scripts in arty.yml): + +### Stack Management +```bash +# Start all services +pnpm arty up + +# Stop all services +pnpm arty down + +# View running containers +pnpm arty ps + +# Follow logs for all services +pnpm arty logs + +# Restart all services +pnpm arty restart + +# Pull latest images +pnpm arty pull + +# View rendered configuration (with variables substituted) +pnpm arty config +``` + +### Network Setup +```bash +# Create external Docker network (required before first up) +pnpm arty net/create +``` + +### Database Operations (Sexy/Directus) +```bash +# Export Directus database + schema snapshot +pnpm arty db/dump + +# Import database dump + apply schema snapshot +pnpm arty db/import + +# Export Directus uploads directory +pnpm arty uploads/export + +# Import Directus uploads directory +pnpm arty uploads/import +``` + +### Deployment +```bash +# Sync .env file to remote VPS +pnpm arty env/sync +``` + +## Service-Specific Details + +### Core Services (core/compose.yaml) +- **postgres**: PostgreSQL 16 Alpine, exposed on host port 5432 + - Uses scram-sha-256 authentication + - Health check via `pg_isready` + - Init scripts mounted from `./postgres/init/` +- **redis**: Redis 7 Alpine for caching + - Used by Directus for cache and websocket storage + +### Sexy (sexy/compose.yaml) +Directus headless CMS + SvelteKit frontend: +- **directus**: Directus 11.12.0 + - Admin panel + GraphQL/REST API + - Traefik routes `/api` path to port 8055 + - Volumes: `directus_uploads` for media, `directus_bundle` for extensions + - Email via SMTP (IONOS configuration in .env) +- **frontend**: Custom SvelteKit app from ghcr.io/valknarxxx/sexy + - Serves on port 3000 + - Shared `directus_bundle` volume for Directus extensions + +### Proxy (proxy/compose.yaml) +Traefik 3.x reverse proxy: +- Global HTTP→HTTPS redirect +- Let's Encrypt via TLS challenge +- Dashboard disabled (`api.dashboard=false`) +- Reads labels from Docker socket (`/var/run/docker.sock`) +- Scoped to `$NETWORK_NAME` network via provider configuration + +### AWSM (awsm/compose.yaml) +Next.js app with embedded SQLite: +- Serves awesome-app list directory +- Optional GitHub token for API rate limits +- Optional webhook secret for database updates +- Database persisted in `awesome_data` volume + +## Important Environment Variables + +Key variables defined in `arty.yml` and overridden in `.env`: +- `NETWORK_NAME`: Docker network name (default: `falcon_network`) +- `ADMIN_EMAIL`: Used for Let's Encrypt and service admin accounts +- `DB_USER`, `DB_PASSWORD`: PostgreSQL credentials +- `CORE_DB_HOST`, `CORE_DB_PORT`: PostgreSQL connection (default: `postgres:5432`) +- `CORE_REDIS_HOST`, `CORE_REDIS_PORT`: Redis connection (default: `redis:6379`) +- `{SERVICE}_TRAEFIK_HOST`: Domain for each service +- `{SERVICE}_TRAEFIK_ENABLED`: Toggle Traefik exposure +- `SEXY_DIRECTUS_SECRET`: Directus security secret +- `TRACK_APP_SECRET`: Umami analytics secret + +## Volume Management + +Each service uses named volumes prefixed with project name: +- `core_postgres_data`, `core_redis_data`: Database persistence +- `core_directus_uploads`, `core_directus_bundle`: Directus media/extensions +- `awesome_data`: AWSM SQLite database +- `proxy_letsencrypt_data`: SSL certificates + +Volumes can be inspected with: +```bash +docker volume ls | grep falcon +docker volume inspect +``` + +## Troubleshooting + +### Services won't start +1. Ensure external network exists: `pnpm arty net/create` +2. Check if services reference correct `$NETWORK_NAME` in labels +3. Verify `.env` has required secrets (compare with `arty.yml` envs.default) + +### SSL certificates failing +1. Check `ADMIN_EMAIL` is set in `.env` +2. Ensure ports 80/443 are accessible from internet +3. Inspect Traefik logs: `docker logs proxy_app` + +### Database connection errors +1. Check PostgreSQL is healthy: `docker ps` (should show healthy status) +2. Verify database exists: `docker exec core_postgres psql -U $DB_USER -l` +3. Check credentials match between `.env` and service configs + +### Directus schema migration +- Export schema: `pnpm arty db/dump` (creates `sexy/directus.yaml`) +- Import to new instance: `pnpm arty db/import` (applies schema snapshot) +- Schema file stored in `sexy/directus.yaml` for version control diff --git a/awsm/compose.yaml b/awsm/compose.yaml index dbb5cda..1c459e9 100644 --- a/awsm/compose.yaml +++ b/awsm/compose.yaml @@ -43,14 +43,6 @@ services: - 'traefik.http.routers.${AWESOME_COMPOSE_PROJECT_NAME}-app-web-secure.middlewares=${AWESOME_COMPOSE_PROJECT_NAME}-app-web-secure-compress' - 'traefik.http.services.${AWESOME_COMPOSE_PROJECT_NAME}-app-web-secure.loadbalancer.server.port=3000' - 'traefik.docker.network=${NETWORK_NAME}' - - healthcheck: - test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/stats" ] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - volumes: awesome_data: name: ${AWESOME_COMPOSE_PROJECT_NAME}_data