Files
festipod/docker-compose.coolify.yml
T
Sylvain Duchesne 5e3e821e2a Run locally like the sibling apps: fixed ports, the pod provider in Docker, the app outside
Festipod now follows the local convention of welcometomyplace, mutual-aid.app
and portejunes: one fixed port pair per app (Festipod defaults: backend 3005,
app 4005; pod provider 3000/5000), overridable in backend/.env and .env.
`make start` runs docker-compose-dev.yml (the local pod provider from images,
Fuseki, Redis, mailcatcher, Arena); the backend and the app run outside Docker
with `cd backend && pnpm dev` and `pnpm dev`. pnpm stays the package manager.

The old docker-compose.yml, which containerized Festipod's own frontend and
backend and could not reach the host's Fuseki and Redis, is gone; portless is
dropped from the dev script, since the backend declares a single OIDC redirect
URI. The local backend runs without a Redis cache, as the sibling apps do. The
e2e suites and validate read the app, backend and pod provider URLs from the
env files instead of hardcoding them.

The deployment and local cookbook leaves record the traps met while resetting
datasets: a dataset re-created under the same name needs a Fuseki restart
(ClosedException otherwise), the anonymous WebACL probe at boot is expected,
and a change of the backend's URL leaves persistent accounts with a
participations collection the new app identity cannot control.
2026-11-01 11:40:27 +01:00

109 lines
5.5 KiB
YAML

# Docker Compose definition used by Coolify to build and run Festipod straight from the
# git repository: one stack for the branch it follows (the test environment). The images
# are built on the Coolify server from the two Dockerfiles of this repository (the app at
# the root, the backend in /backend); nothing is pulled from a registry.
#
# Before `docker compose build` and `up`, Coolify writes a .env file next to this file
# with the variables defined in its UI plus generated ones. The generated ones used here:
# SERVICE_FQDN_BACKEND / SERVICE_FQDN_FRONTEND host of each service, as set in its
# Domains field
# SERVICE_NAME_BACKEND / SERVICE_NAME_FESTIPOD_REDIS service names (Coolify suffixes
# them with "-pr-<n>" in a preview)
# A value starting with `${` becomes an editable variable in Coolify (with its default);
# the other `${...}` references are only interpolated by docker compose.
#
# One base URL per environment, as for the other ActivityPods apps on this Coolify (it is
# what lets a pull request preview live on a single host): the frontend's domain serves the
# app, and the backend is served on the same host under `/api` and `/.well-known` — its
# Domains field is `https://<host>/api,https://<host>/.well-known`. The proxy must pass those
# paths through unchanged — Coolify's "Strip Prefixes" OFF, as on the other apps: the backend
# mounts its routes under `/api` itself, from its base URL, and keeps its `/.well-known` ones
# at the origin root (backend/services/base-path.js). With the prefixes stripped, every
# backend request would be refused (404).
#
# The backend registers its app actor in its main dataset on the first boot, with the
# domain it had at that time: set the domains in Coolify BEFORE the first deployment. The
# main dataset must be a SECURE one (WebACL is on): the backend creates it so when it does
# not exist, and refuses to start on an existing one that is not secure. To start again from
# nothing (the domains changed, or the main dataset was created before WebACL was on):
# 1. delete the two datasets in Fuseki. Fuseki's delete leaves a secure dataset's files on
# disk — remove `databases/<main>`, `databases/<main>Acl`, `databases/<main>Mirror` and
# `configuration/<main>.ttl` under the Fuseki base too, or a dataset created again under
# the same name reopens the old data;
# Fuseki then keeps the closed storage of the deleted dataset: re-creating one under the
# SAME name fails every query with `ClosedException: already closed` until Fuseki restarts
# (the shared one, on the test server) — or set new MAIN_DATASET / SETTINGS_DATASET names;
# 2. empty this stack's Redis (the `redis-data` volume): its cache outlives the datasets and
# would keep serving the old app actor, keys and access needs;
# 3. redeploy.
#
# Fuseki is the one shared with the other apps (shared-infra, in the "infra" project): the
# backend joins the "coolify" network to reach it, with its own pair of datasets. Redis
# runs inside the stack (on the stack's private network only, under a name that cannot be
# confused with the shared one).
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile
restart: always
depends_on:
- festipod-redis
expose:
- '3003'
# Coolify adds the stack's own network to every service; only the backend also needs
# the shared one, where Fuseki lives.
networks:
- coolify
environment:
SEMAPPS_APP_NAME: ${APP_NAME:-Festipod}
SEMAPPS_APP_DESCRIPTION: ${APP_DESCRIPTION:-Points de rencontre sur les événements publics}
SEMAPPS_APP_LANG: ${APP_LANG:-en,fr}
SEMAPPS_HOME_URL: https://${SERVICE_FQDN_BACKEND}/api/
SEMAPPS_FRONT_URL: https://${SERVICE_FQDN_FRONTEND}
SEMAPPS_PORT: '3003'
SEMAPPS_SHAPE_REPOSITORY_URL: ${SHAPE_REPOSITORY_URL:-https://shapes.activitypods.org/}
SEMAPPS_SPARQL_ENDPOINT: ${SPARQL_ENDPOINT}
SEMAPPS_JENA_USER: ${JENA_USER:-admin}
SEMAPPS_JENA_PASSWORD: ${JENA_PASSWORD}
# A pair of datasets named after DATASET_PREFIX and the backend's service name, e.g.
# festipod-backend / settings-festipod-backend (…-backend-pr-<n> in a preview). Two
# non-preview stacks on the same Fuseki would share them: give the second its own
# DATASET_PREFIX (or MAIN_DATASET / SETTINGS_DATASET).
SEMAPPS_MAIN_DATASET: ${MAIN_DATASET:-${DATASET_PREFIX:-festipod}-${SERVICE_NAME_BACKEND}}
SEMAPPS_AUTH_ACCOUNTS_DATASET_NAME: ${SETTINGS_DATASET:-settings-${DATASET_PREFIX:-festipod}-${SERVICE_NAME_BACKEND}}
SEMAPPS_REDIS_CACHE_URL: redis://${SERVICE_NAME_FESTIPOD_REDIS}:6379/0
SEMAPPS_QUEUE_SERVICE_URL: redis://${SERVICE_NAME_FESTIPOD_REDIS}:6379/1
frontend:
build:
context: .
dockerfile: Dockerfile
restart: always
depends_on:
- backend
expose:
- '3000'
# Read by the server on every request to /festipod-config.json, not inlined at build
# time: changing one needs a restart, not a rebuild.
environment:
PORT: '3000'
VITE_BACKEND_URL: https://${SERVICE_FQDN_BACKEND}/api
# The Pod provider the login screen offers in one click; any other can be typed in.
VITE_POD_PROVIDER_URL: ${POD_PROVIDER_URL:-https://mypod.store}
festipod-redis:
image: redis:7-alpine
restart: always
command: ['redis-server', '--appendonly', 'yes']
volumes:
- redis-data:/data
volumes:
redis-data:
networks:
coolify:
external: true