feat(web-app-chess): add castling.club role with ports, networks, and build setup

- Added network subnet (192.168.103.192/28) and port 8050 for web-app-chess
- Replaced stub README with usability-focused description of castling.club
- Implemented config, vars, meta, and tasks for web-app-chess
- Added Dockerfile, docker-compose.yml, env, and docker-entrypoint.sh templates
- Integrated entrypoint asset placement
- Updated meta to reflect usability and software features

Ref: https://chatgpt.com/share/68b6c65a-3de8-800f-86b2-a110920cd50e
This commit is contained in:
2025-09-02 13:21:15 +02:00
parent 3a83f3d14e
commit 6cac8085a8
12 changed files with 231 additions and 7 deletions

View File

@@ -96,6 +96,8 @@ defaults_networks:
subnet: 192.168.103.160/28
web-svc-logout:
subnet: 192.168.103.176/28
web-app-chess:
subnet: 192.168.103.192/28
# /24 Networks / 254 Usable Clients
web-app-bigbluebutton:

View File

@@ -71,6 +71,7 @@ ports:
web-app-mig: 8047
web-svc-logout: 8048
web-app-bookwyrm: 8049
web-app-chess: 8050
web-app-bigbluebutton: 48087 # This port is predefined by bbb. @todo Try to change this to a 8XXX port
public:
# The following ports should be changed to 22 on the subdomain via stream mapping

View File

@@ -1,2 +1,25 @@
# Todo
- Implement https://joinbookwyrm.com/de/
# web-app-chess
## Description
**castling.club** is a federated chess server built on the ActivityPub protocol.
It provides an open and decentralized way to play chess online, where games and moves are visible across the Fediverse.
## Overview
Instead of relying on closed platforms, castling.club uses an arbiter actor (“the King”) to validate moves and mediate matches.
This ensures fair play, federation with platforms like Mastodon or Friendica, and community visibility of ongoing games.
The service runs as a lightweight Node.js app backed by PostgreSQL.
## Features
- **Federated Chess Matches:** Challenge and play with others across the Fediverse.
- **Rule Enforcement:** The arbiter validates each move for correctness.
- **Open Identities:** Use your existing Fediverse account; no new silo account needed.
- **Game Visibility:** Matches and moves can appear in social timelines.
- **Lightweight Service:** Built with Node.js and PostgreSQL for efficiency.
## Further Resources
- [castling.club GitHub Repository](https://github.com/stephank/castling.club)
- [ActivityPub Specification (W3C)](https://www.w3.org/TR/activitypub/)

View File

@@ -0,0 +1,34 @@
# roles/web-app-chess/config/main.yml
credentials: {}
docker:
services:
database:
enabled: true # Use central DB role (recommended)
application:
image: "node" # Base image family; final image is custom
version: "20-bullseye" # >=16 as required upstream
name: "web-app-chess"
backup:
no_stop_required: true
volumes:
data: "chess_data"
features:
matomo: false
css: false
desktop: false
central_database: true
logout: false
oidc: false
server:
csp:
whitelist: {}
flags: {}
domains:
canonical:
- "chess.{{ PRIMARY_DOMAIN }}"
aliases: []
rbac:
roles: {}
source:
repo: "https://github.com/stephank/castling.club.git"
ref: "main"

View File

@@ -1,7 +1,7 @@
---
galaxy_info:
author: "Kevin Veen-Birchenbach"
description: "Stub role for deploying a Chess web application via Docker Compose (implementation pending)."
description: "Federated chess server based on ActivityPub. Play and follow games across the Fediverse with verified rules and open identities."
license: "Infinito.Nexus NonCommercial License"
license_url: "https://s.infinito.nexus/license"
company: |
@@ -10,13 +10,16 @@ galaxy_info:
https://www.veen.world
galaxy_tags:
- chess
- docker
- federation
- activitypub
- social
repository: "https://s.infinito.nexus/code"
issue_tracker_url: "https://s.infinito.nexus/issues"
documentation: "https://s.infinito.nexus/code/tree/main/roles/web-app-chess"
documentation: "https://github.com/stephank/castling.club"
logo:
class: "fas fa-chess-king"
min_ansible_version: "2.9"
platforms:
- name: Any
versions: [ all ]
dependencies: []

View File

@@ -0,0 +1,10 @@
- block:
- name: "load docker, db and proxy for {{ application_id }}"
include_role:
name: sys-stk-full-stateful
- name: "Place entrypoint and other assets"
include_tasks: 02_assets.yml
- include_tasks: utils/run_once.yml
when: run_once_web_app_chess is not defined

View File

@@ -0,0 +1,8 @@
---
- block:
- name: "load docker, db and proxy for {{ application_id }}"
include_role:
name: sys-stk-full-stateful
- include_tasks: utils/run_once.yml
when: run_once_web_app_chess is not defined

View File

@@ -0,0 +1,47 @@
# Multi-stage build for castling.club
# Stage 1: build
FROM node:{{ CHESS_VERSION }} AS build
ARG CHESS_REPO_URL={{ CHESS_REPO_URL }}
ARG CHESS_REPO_REF={{ CHESS_REPO_REF }}
RUN apt-get update && apt-get install -y --no-install-recommends \
git ca-certificates openssl dumb-init python3 build-essential \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
RUN git clone --depth 1 --branch "${CHESS_REPO_REF}" "${CHESS_REPO_URL}" ./
# Yarn is preinstalled in Node images via corepack; enable it.
RUN corepack enable
# Install deps and build TS
RUN yarn install --frozen-lockfile && yarn build
# Stage 2: runtime
FROM node:{{ CHESS_VERSION }}
ENV NODE_ENV=production
ENV PORT={{ container_port }}
WORKDIR /app
# Minimal runtime packages + dumb-init
RUN apt-get update && apt-get install -y --no-install-recommends \
openssl dumb-init postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Copy built app
COPY --from=build /src /app
# Create data dir for signing keys & cache
RUN mkdir -p /app/data && chown -R node:node /app
VOLUME ["/app/data"]
# Entrypoint script
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
USER node
EXPOSE {{ container_port }}
ENTRYPOINT ["dumb-init", "--"]
CMD ["docker-entrypoint.sh"]

View File

@@ -0,0 +1,29 @@
{% include 'roles/docker-compose/templates/base.yml.j2' %}
application:
build:
context: .
dockerfile: Dockerfile
args:
CHESS_REPO_URL: "{{ CHESS_REPO_URL }}"
CHESS_REPO_REF: "{{ CHESS_REPO_REF }}"
image: "castling_custom"
container_name: "{{ CHESS_CONTAINER }}"
hostname: "{{ CHESS_HOSTNAME }}"
environment:
- NODE_ENV=production
ports:
- "127.0.0.1:{{ ports.localhost.http[application_id] }}:{{ container_port }}"
volumes:
- 'data:/app/data'
env_file:
- .env
{% include 'roles/docker-container/templates/healthcheck/curl.yml.j2' %}
{% include 'roles/docker-container/templates/base.yml.j2' %}
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}
data:
name: {{ CHESS_DATA_VOLUME }}
{% include 'roles/docker-compose/templates/networks.yml.j2' %}

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
APP_KEY_FILE="${APP_KEY_FILE:-/app/data/{{ CHESS_KEY_FILENAME }}}"
APP_KEY_PUB="${APP_KEY_FILE}.pub"
# 1) Generate signing key pair if missing
if [[ ! -f "${APP_KEY_FILE}" || ! -f "${APP_KEY_PUB}" ]]; then
echo "[chess] generating RSA signing key pair at ${APP_KEY_FILE}"
/app/tools/gen-signing-key.sh "${APP_KEY_FILE}"
fi
# 2) Wait for PostgreSQL if env is provided
if [[ -n "${PGHOST:-}" ]]; then
echo "[chess] waiting for PostgreSQL at ${PGHOST}:${PGPORT:-5432}..."
until pg_isready -h "${PGHOST}" -p "${PGPORT:-5432}" -U "${PGUSER:-postgres}" >/dev/null 2>&1; do
sleep 1
done
fi
# 3) Run migrations (idempotent)
echo "[chess] running migrations"
yarn migrate up
# 4) Start app
echo "[chess] starting server on port ${PORT:-5080}"
exec yarn start

View File

@@ -0,0 +1,16 @@
# App basics
APP_SCHEME="{{ 'https' if WEB_PROTOCOL == 'https' else 'http' }}"
APP_DOMAIN="{{ CHESS_HOSTNAME }}"
APP_ADMIN_URL="{{ CHESS_ADMIN_URL }}"
APP_ADMIN_EMAIL="{{ CHESS_ADMIN_EMAIL }}"
APP_KEY_FILE="/app/data/{{ CHESS_KEY_FILENAME }}"
APP_HMAC_SECRET="{{ CHESS_HMAC_SECRET }}"
NODE_ENV="production"
PORT="{{ container_port }}"
# PostgreSQL (libpq envs)
PGHOST="{{ database_host }}"
PGPORT="{{ database_port }}"
PGDATABASE="{{ database_name }}"
PGUSER="{{ database_username }}"
PGPASSWORD="{{ database_password }}"

View File

@@ -1 +1,25 @@
application_id: web-app-chess
# General
application_id: "web-app-chess"
database_type: "postgres"
container_port: 5080
container_hostname: "{{ domains | get_domain(application_id) }}"
# App URLs & meta
#CHESS_URL: "{{ domains | get_url(application_id, WEB_PROTOCOL) }}"
CHESS_HOSTNAME: "{{ container_hostname }}"
CHESS_ADMIN_URL: ""
CHESS_ADMIN_EMAIL: ""
# Docker image
#CHESS_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.application.image') }}"
CHESS_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.application.version') }}"
CHESS_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.application.name') }}"
CHESS_DATA_VOLUME: "{{ applications | get_app_conf(application_id, 'docker.volumes.data') }}"
# Build source
CHESS_REPO_URL: "{{ applications | get_app_conf(application_id, 'source.repo') }}"
CHESS_REPO_REF: "{{ applications | get_app_conf(application_id, 'source.ref') }}"
# Security
CHESS_HMAC_SECRET: "{{ lookup('password', '/dev/null length=63 chars=ascii_letters,digits') }}"
CHESS_KEY_FILENAME: "signing-key"