Files
kevinveenbirkenbachandClaude Opus 5.5 73b21eef98 fix(web-app-fider): bootstrap the tenant without SSO
00_core.yml included 01_setup_oidc.yml only when services.sso.enabled
was true, but that file carried the whole tenant bootstrap: wait for
HTTP, count tenants, POST /_api/tenants, create the admin user and
activate the tenant. Only its last task configured the Keycloak
provider. With SSO off no tenant was ever created.

Fider's RequireTenant middleware then answers every tenant route,
/api/v1/tags included, with 307 to /signup, and /signup is open to any
visitor, who can claim the fresh installation and become its
administrator. The MCP read fider_list_tags got that 307 in the swarm
SSO-off matrix row.

The tenant bootstrap moves unchanged into tasks/01_tenant.yml, which
00_core.yml includes on the stack host regardless of SSO. The OIDC file
becomes tasks/02_setup_oidc.yml and keeps only the provider upsert,
still gated on services.sso.enabled. The README states which bootstrap
steps run without SSO.

A unit test evaluates the include and task guards for every SSO,
stack-host and deploy-mode state: a fresh stack host posts exactly one
tenant with and without SSO, an existing tenant is never posted again,
the Keycloak provider is written only with SSO, and a non-stack host
runs none of it. The compose matrix row with SSO off stayed green
because nothing there read a tenant route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 23:55:01 +01:00
..

Fider

Description

Fider is an open-source community feedback and voting platform that allows teams to collect, prioritize, and track feature requests and ideas.

Overview

This role deploys Fider as part of the Infinito.Nexus stack using a single Docker Compose container backed by PostgreSQL. It configures SSO via Keycloak automatically on first deploy, optional email notifications via Mailu, and HTTPS via NGINX reverse proxy.

The setup tasks handle the full first-deploy bootstrap automatically. Steps 1 to 3 run on every deploy, with or without SSO; step 4 runs only when services.sso.enabled is true:

  1. Tenant bootstrap: calls Fider's POST /_api/tenants API to create the initial tenant.
  2. Admin user creation: inserts the admin user directly into the users table, bypassing email verification. Idempotent via WHERE NOT EXISTS.
  3. Tenant activation: sets status=1 on the tenant row so Fider serves the public page.
  4. OIDC provider: inserts the Keycloak provider into oauth_providers. Idempotent via ON CONFLICT (tenant_id, provider) DO UPDATE.

When a user logs in via Keycloak for the first time, Fider matches their email to the existing admin user and links the OIDC provider automatically. To enable SSO, set services.sso.enabled: true (the default) and ensure OIDC.CLIENT.SECRET is configured.

Cosmos

The diagram places Fider in the Infinito.Nexus cosmos: the components it deploys (capabilities), the central services it consumes (dependencies), and its outward reach (federation and bridged external networks).

flowchart LR
    subgraph deps [Dependencies]
        dep_svc_db_postgres["svc-db-postgres 🐳🐝"]
        dep_svc_db_redis["svc-db-redis 🐳🐝"]
        dep_svc_net_tor["svc-net-tor 🐳🐝"]
        dep_web_app_dashboard["web-app-dashboard 🐳🐝"]
        dep_web_app_hermes["web-app-hermes 🐳🐝"]
        dep_web_app_keycloak["web-app-keycloak 🐳🐝"]
        dep_web_app_matomo["web-app-matomo 🐳🐝"]
        dep_web_app_openclaw["web-app-openclaw 🐳🐝"]
        dep_web_app_openwebui["web-app-openwebui 🐳🐝"]
        dep_web_app_prometheus["web-app-prometheus 🐳🐝"]
        dep_web_app_seaweedfs["web-app-seaweedfs 🐳🐝"]
        dep_web_app_stalwart["web-app-stalwart 🐳🐝"]
        dep_web_svc_css["web-svc-css 💻"]
        dep_web_svc_logout["web-svc-logout 🐳🐝"]
    end
    subgraph role [web-app-fider 🐳🐝]
        svc_sso["sso"]
        svc_email["email"]
        svc_logout["logout"]
        svc_dashboard["dashboard"]
        svc_matomo["matomo"]
        svc_postgres["postgres"]
        svc_fider["fider"]
        svc_redis["redis"]
        svc_css["css"]
        svc_javascript["javascript"]
        svc_prometheus["prometheus"]
        svc_seaweedfs["seaweedfs"]
        svc_fidermcp["fidermcp"]
        svc_tor["tor"]
        svc_openwebui["openwebui"]
        svc_hermes["hermes"]
        svc_openclaw["openclaw"]
        svc_flowise["flowise ❌"]
    end
    dep_svc_db_postgres -. "0..1" .-> svc_postgres
    dep_svc_db_redis -. "0..1" .-> svc_redis
    dep_svc_net_tor -. "0..1" .-> svc_tor
    dep_web_app_dashboard -. "0..1" .-> svc_dashboard
    dep_web_app_hermes -. "0..1" .-> svc_hermes
    dep_web_app_keycloak -. "0..1" .-> svc_sso
    dep_web_app_matomo -. "0..1" .-> svc_matomo
    dep_web_app_openclaw -. "0..1" .-> svc_openclaw
    dep_web_app_openwebui -. "0..1" .-> svc_openwebui
    dep_web_app_prometheus -. "0..1" .-> svc_prometheus
    dep_web_app_seaweedfs -. "0..1" .-> svc_seaweedfs
    dep_web_app_stalwart -. "0..1" .-> svc_email
    dep_web_svc_css -. "0..1" .-> svc_css
    dep_web_svc_logout -. "0..1" .-> svc_logout

Solid 1:1 edges are fixed relationships; dashed 0..1 edges are conditional (enabled only in matching deployments); red 0..0 edges are turned off in this role. Node markers show the role's deploy modes (💻 host, 🐳 compose, 🐝 swarm); ❌ marks a service that is explicitly turned off, and ⚙️ an Ansible role dependency declared in meta/main.yml.

Features

  • Single-container deployment via Docker Compose.
  • PostgreSQL database: all data including attachments stored in the database, no extra volumes needed.
  • SSO via Keycloak: configured automatically on first deploy.
  • Email notifications via Mailu (optional).
  • HTTPS enforced via NGINX reverse proxy.

Quick Setup

Development

Clone, set up the workstation, and deploy Fider onto the local stack:

git clone https://github.com/infinito-nexus/core.git
cd core
make onboard
make compose-deploy mode=reinstall apps=web-app-fider full_cycle=false

Production

Run the published image to provision the inventory and deploy Fider to a managed server (the mounted volume persists the inventory):

APP=web-app-fider
HOST=<your-server>
DOMAIN=<your-domain>
TLS_MODE=self_signed
SSH_PUBLIC_KEY="<your-ssh-public-key>"

docker run --rm -it \
  -v "$PWD/inventories:/etc/infinito.nexus/inventories" \
  -e APP="$APP" -e HOST="$HOST" -e DOMAIN="$DOMAIN" -e TLS_MODE="$TLS_MODE" -e SSH_PUBLIC_KEY="$SSH_PUBLIC_KEY" \
  ghcr.io/infinito-nexus/core/debian bash -c '
    INVENTORY=/etc/infinito.nexus/inventories/production
    infinito administration inventory provision "$INVENTORY" \
      --inventory-file "$INVENTORY/devices.yml" \
      --host "$HOST" \
      --include "$APP" \
      --vars "{\"TLS_MODE\": \"$TLS_MODE\", \"DOMAIN_PRIMARY\": \"$DOMAIN\", \"users\": {\"administrator\": {\"authorized_keys\": [\"$SSH_PUBLIC_KEY\"]}}}" &&
    infinito administration deploy dedicated "$INVENTORY/devices.yml" \
      --password-file "$INVENTORY/.password" \
      --diff -vv'

Configuration

Key settings in meta/services.yml and meta/server.yml:

Key Default Description
services.sso.enabled true Automate Keycloak OIDC setup
services.postgres.enabled true Enable PostgreSQL for Fider
services.postgres.shared true Reuse the shared PostgreSQL provider
services.fider.version stable Docker image tag
domains.canonical fider.{{ DOMAIN_PRIMARY }} Public domain
server.status_codes.default [200, 301, 302, 405] Expected HTTP codes for health check (405 because Fider returns 405 on HEAD requests to /)

Further resources

Persona contract opt-outs

The shared biber and administrator persona journeys are opted out via PERSONA_BIBER_BLOCKED / PERSONA_ADMINISTRATOR_BLOCKED in templates/playwright.env.j2. Fider's SSO entry is a two-step modal: the header "Sign in" button only opens the provider dialog, and a second click on "Continue with … SSO" performs the Keycloak redirect, whereas the shared helper clicks exactly once and never reaches the IdP. Both journeys are covered end-to-end by this role's own fider: admin sso login and fider: biber sso login as regular user scenarios in files/playwright/playwright.spec.js; the opt-out lapses once the shared helper learns Fider's modal.

Credits

Implemented by Alejandro Roman Ibanez. Part of the Infinito.Nexus Project and maintained by Kevin Veen-Birkenbach. Licensed under the Infinito.Nexus Community License (Non-Commercial).