Part of #1029.
Context
Two independent services that unlock very different capabilities:
n8n is a self-hosted workflow automation platform with 400+ integrations. For gittensory it enables: multi-channel review notifications (Slack/Teams/email), webhook fan-out to multiple downstream systems, scheduled reports, GitHub issue auto-triage from review signals, and no-code custom automation without touching gittensory's codebase.
MinIO is an S3-compatible object store. For gittensory it enables: Litestream backup destination without an S3/B2 account, visual review screenshot artifact storage, Orb event archive, and a local alternative to Cloudflare R2 for any blob-storage need.
Both are fully optional. Neither the review engine nor any other profile depends on them.
Easy on/off
# Enable n8n only:
docker compose --profile workflows up -d
# OPTIONAL: N8N_ENCRYPTION_KEY and N8N_WEBHOOK_URL in .env for persistence + external webhooks
# Enable MinIO only:
docker compose --profile storage up -d
# MINIO_ROOT_USER + MINIO_ROOT_PASSWORD in .env (required by :? expansion)
# Enable both:
docker compose --profile workflows --profile storage up -d
# Disable either: stop the profile, remove env vars. Zero impact on other services.
n8n implementation
docker-compose.yml
n8n:
image: n8nio/n8n:latest
profiles: ["workflows"]
restart: unless-stopped
ports:
- "5678:5678"
volumes:
- n8n-data:/home/node/.n8n
environment:
N8N_BASIC_AUTH_ACTIVE: "true"
N8N_BASIC_AUTH_USER: ${N8N_USER:-admin}
N8N_BASIC_AUTH_PASSWORD: ${N8N_PASSWORD:?Set N8N_PASSWORD in .env}
WEBHOOK_URL: ${N8N_WEBHOOK_URL:-http://localhost:5678}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY:-} # persists credentials across restarts
GENERIC_TIMEZONE: ${TZ:-UTC}
Bundled workflow templates (n8n/workflows/)
review-slack-notify.json — posts review verdicts to a Slack channel when triggered by a gittensory webhook
gate-daily-summary.json — scheduled daily summary of merges/closes/blocks to a webhook
issue-auto-triage.json — when a PR is auto-closed, posts a comment with the reason to the linked issue
Import via http://localhost:5678/workflows/import or mount the directory and configure N8N_CUSTOM_EXTENSIONS_PATH.
.env.example additions
# n8n workflow automation (--profile workflows)
# N8N_PASSWORD=changeme # REQUIRED when using --profile workflows
# N8N_USER=admin
# N8N_WEBHOOK_URL=https://n8n.example.com # set to public URL if receiving external webhooks
# N8N_ENCRYPTION_KEY= # 32-char random string; persists credentials across restarts
MinIO implementation
docker-compose.yml
minio:
image: minio/minio:latest
profiles: ["storage"]
restart: unless-stopped
ports:
- "9000:9000" # S3 API
- "9001:9001" # Console UI
volumes:
- minio-data:/data
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:?Set MINIO_ROOT_USER in .env}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?Set MINIO_ROOT_PASSWORD in .env}
command: server /data --console-address ":9001"
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 30s
timeout: 5s
retries: 3
Litestream → MinIO integration
When --profile storage is active, set in .env:
LITESTREAM_ENDPOINT=http://minio:9000
LITESTREAM_ACCESS_KEY_ID=${MINIO_ROOT_USER}
LITESTREAM_SECRET_ACCESS_KEY=${MINIO_ROOT_PASSWORD}
This replaces the need for external S3/B2 for Litestream backups — everything stays local.
.env.example additions
# MinIO S3-compatible object storage (--profile storage)
# MINIO_ROOT_USER=minio # REQUIRED when using --profile storage
# MINIO_ROOT_PASSWORD=changeme # REQUIRED when using --profile storage
# MINIO_BUCKET=gittensory # default bucket name
# Console at http://localhost:9001
# S3 API at http://minio:9000 (from other containers) or http://localhost:9000 (from host)
Acceptance criteria
Part of #1029.
Context
Two independent services that unlock very different capabilities:
n8n is a self-hosted workflow automation platform with 400+ integrations. For gittensory it enables: multi-channel review notifications (Slack/Teams/email), webhook fan-out to multiple downstream systems, scheduled reports, GitHub issue auto-triage from review signals, and no-code custom automation without touching gittensory's codebase.
MinIO is an S3-compatible object store. For gittensory it enables: Litestream backup destination without an S3/B2 account, visual review screenshot artifact storage, Orb event archive, and a local alternative to Cloudflare R2 for any blob-storage need.
Both are fully optional. Neither the review engine nor any other profile depends on them.
Easy on/off
n8n implementation
docker-compose.yml
Bundled workflow templates (n8n/workflows/)
review-slack-notify.json— posts review verdicts to a Slack channel when triggered by a gittensory webhookgate-daily-summary.json— scheduled daily summary of merges/closes/blocks to a webhookissue-auto-triage.json— when a PR is auto-closed, posts a comment with the reason to the linked issueImport via
http://localhost:5678/workflows/importor mount the directory and configureN8N_CUSTOM_EXTENSIONS_PATH..env.example additions
MinIO implementation
docker-compose.yml
Litestream → MinIO integration
When
--profile storageis active, set in.env:This replaces the need for external S3/B2 for Litestream backups — everything stays local.
.env.example additions
Acceptance criteria
docker compose --profile workflows upstarts n8n at port 5678 with basic-auth gatedocker compose --profile storage upstarts MinIO at ports 9000/9001http://localhost:9001n8n/workflows/) checked in with at least the Slack notify templatesrc/**(Codecov scope clean).env.exampleupdated with both services' varsnpm run test:cigreen (no src changes = no coverage obligation beyond :? expansion logic)