Skip to content

selfhost(workflows): n8n orchestration + MinIO object storage — automation and artifact persistence #1219

Description

@JSONbored

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

  • docker compose --profile workflows up starts n8n at port 5678 with basic-auth gate
  • docker compose --profile storage up starts MinIO at ports 9000/9001
  • MinIO console accessible at http://localhost:9001
  • Litestream env vars documented for pointing at MinIO instead of external S3
  • n8n workflow templates directory (n8n/workflows/) checked in with at least the Slack notify template
  • Neither service has any code dependency in src/** (Codecov scope clean)
  • .env.example updated with both services' vars
  • npm run test:ci green (no src changes = no coverage obligation beyond :? expansion logic)

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions