From 4a6f1c0e0167cf8b5f773c15ac2fd2f51f5ab88a Mon Sep 17 00:00:00 2001 From: Yury Kossakovsky Date: Fri, 16 Jan 2026 18:42:54 -0700 Subject: [PATCH] feat(postiz): add temporal server for workflow orchestration add temporal and temporal-ui services to the postiz profile for workflow orchestration. includes caddy reverse proxy with basic auth, secret generation, and welcome page integration. --- .claude/commands/add-new-service.md | 8 +++-- .env.example | 11 ++++++- CHANGELOG.md | 7 ++++ Caddyfile | 8 +++++ docker-compose.yml | 50 +++++++++++++++++++++++++++++ scripts/03_generate_secrets.sh | 4 ++- scripts/generate_welcome_page.sh | 14 ++++++++ welcome/app.js | 8 +++++ 8 files changed, 105 insertions(+), 5 deletions(-) diff --git a/.claude/commands/add-new-service.md b/.claude/commands/add-new-service.md index 2fe69b7..1c0b664 100644 --- a/.claude/commands/add-new-service.md +++ b/.claude/commands/add-new-service.md @@ -314,14 +314,16 @@ ${SERVICE_NAME_UPPER}_PASSWORD= ${SERVICE_NAME_UPPER}_PASSWORD_HASH= ``` -### 3.3 GOST_NO_PROXY (if using proxy-env) +### 3.3 GOST_NO_PROXY (REQUIRED for ALL services) -Add service to comma-separated list: +**CRITICAL:** Add ALL new service container names to the comma-separated list to prevent internal Docker traffic from going through the proxy: ```dotenv GOST_NO_PROXY=localhost,127.0.0.1,...existing...,$ARGUMENTS ``` +This applies to ALL services, not just those using `<<: *proxy-env`. Internal service-to-service communication must bypass the proxy. + --- ## STEP 4: scripts/03_generate_secrets.sh @@ -706,6 +708,7 @@ bash -n scripts/07_final_report.sh - [ ] `docker-compose.yml`: caddy environment vars (if external) - [ ] `Caddyfile`: reverse proxy block (if external) - [ ] `.env.example`: hostname added +- [ ] `.env.example`: service added to `GOST_NO_PROXY` (ALL internal services must be listed) - [ ] `scripts/03_generate_secrets.sh`: password in `VARS_TO_GENERATE` - [ ] `scripts/04_wizard.sh`: service in `base_services_data` - [ ] `scripts/generate_welcome_page.sh`: `SERVICES_ARRAY` entry @@ -722,7 +725,6 @@ bash -n scripts/07_final_report.sh ### If Outbound Proxy (AI API calls) - [ ] `docker-compose.yml`: `<<: *proxy-env` in environment -- [ ] `.env.example`: service added to `GOST_NO_PROXY` - [ ] `docker-compose.yml`: healthcheck bypasses proxy ### If Database Required diff --git a/.env.example b/.env.example index af2b29f..80e9b07 100644 --- a/.env.example +++ b/.env.example @@ -164,6 +164,7 @@ NOCODB_HOSTNAME=nocodb.yourdomain.com PADDLEOCR_HOSTNAME=paddleocr.yourdomain.com PORTAINER_HOSTNAME=portainer.yourdomain.com POSTIZ_HOSTNAME=postiz.yourdomain.com +TEMPORAL_UI_HOSTNAME=temporal.yourdomain.com PROMETHEUS_HOSTNAME=prometheus.yourdomain.com QDRANT_HOSTNAME=qdrant.yourdomain.com RAGAPP_HOSTNAME=ragapp.yourdomain.com @@ -433,7 +434,7 @@ GOST_UPSTREAM_PROXY= # Internal services bypass list (prevents internal Docker traffic from going through proxy) # Includes: Docker internal networks (172.16-31.*, 10.*), Docker DNS (127.0.0.11), and all service hostnames -GOST_NO_PROXY=localhost,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.local,postgres,postgres:5432,redis,redis:6379,caddy,ollama,neo4j,qdrant,weaviate,clickhouse,minio,searxng,crawl4ai,gotenberg,langfuse-web,langfuse-worker,flowise,n8n,n8n-import,n8n-worker-1,n8n-worker-2,n8n-worker-3,n8n-worker-4,n8n-worker-5,n8n-worker-6,n8n-worker-7,n8n-worker-8,n8n-worker-9,n8n-worker-10,n8n-runner-1,n8n-runner-2,n8n-runner-3,n8n-runner-4,n8n-runner-5,n8n-runner-6,n8n-runner-7,n8n-runner-8,n8n-runner-9,n8n-runner-10,letta,lightrag,docling,postiz,ragflow,ragflow-mysql,ragflow-minio,ragflow-redis,ragflow-elasticsearch,ragapp,open-webui,comfyui,waha,libretranslate,paddleocr,nocodb,db,studio,kong,auth,rest,realtime,storage,imgproxy,meta,functions,analytics,vector,supavisor,gost +GOST_NO_PROXY=localhost,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.local,postgres,postgres:5432,redis,redis:6379,caddy,ollama,neo4j,qdrant,weaviate,clickhouse,minio,searxng,crawl4ai,gotenberg,langfuse-web,langfuse-worker,flowise,n8n,n8n-import,n8n-worker-1,n8n-worker-2,n8n-worker-3,n8n-worker-4,n8n-worker-5,n8n-worker-6,n8n-worker-7,n8n-worker-8,n8n-worker-9,n8n-worker-10,n8n-runner-1,n8n-runner-2,n8n-runner-3,n8n-runner-4,n8n-runner-5,n8n-runner-6,n8n-runner-7,n8n-runner-8,n8n-runner-9,n8n-runner-10,letta,lightrag,docling,postiz,temporal,temporal-ui,ragflow,ragflow-mysql,ragflow-minio,ragflow-redis,ragflow-elasticsearch,ragapp,open-webui,comfyui,waha,libretranslate,paddleocr,nocodb,db,studio,kong,auth,rest,realtime,storage,imgproxy,meta,functions,analytics,vector,supavisor,gost ############ # Functions - Configuration for Functions @@ -489,6 +490,13 @@ RAGAPP_PASSWORD_HASH= POSTIZ_DISABLE_REGISTRATION=false +############ +# Temporal UI credentials (for Caddy basic auth) +############ +TEMPORAL_UI_USERNAME= +TEMPORAL_UI_PASSWORD= +TEMPORAL_UI_PASSWORD_HASH= + ############ # Postiz Social Media Integrations # Leave blank if not used. Provide credentials from each platform. @@ -539,6 +547,7 @@ MASTODON_URL=https://mastodon.social MASTODON_CLIENT_ID= MASTODON_CLIENT_SECRET= + ############ # WAHA (WhatsApp HTTP API) configuration # Engine: NOWEB | WEBJS | GOWS diff --git a/CHANGELOG.md b/CHANGELOG.md index b85fcda..d2f898a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [Unreleased] + +## [1.2.1] - 2026-01-16 + +### Added +- **Temporal** - Temporal server and UI for Postiz workflow orchestration (#33) + ## [1.2.0] - 2026-01-12 ### Added diff --git a/Caddyfile b/Caddyfile index 72ca155..cf573d4 100644 --- a/Caddyfile +++ b/Caddyfile @@ -81,6 +81,14 @@ reverse_proxy postiz:5000 } +# Temporal UI (workflow orchestration for Postiz) +{$TEMPORAL_UI_HOSTNAME} { + basic_auth { + {$TEMPORAL_UI_USERNAME} {$TEMPORAL_UI_PASSWORD_HASH} + } + reverse_proxy temporal-ui:8080 +} + # Databasus {$DATABASUS_HOSTNAME} { reverse_proxy databasus:4005 diff --git a/docker-compose.yml b/docker-compose.yml index 195128b..bb4abd6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -339,6 +339,9 @@ services: PORTAINER_HOSTNAME: ${PORTAINER_HOSTNAME} DATABASUS_HOSTNAME: ${DATABASUS_HOSTNAME} POSTIZ_HOSTNAME: ${POSTIZ_HOSTNAME} + TEMPORAL_UI_HOSTNAME: ${TEMPORAL_UI_HOSTNAME} + TEMPORAL_UI_USERNAME: ${TEMPORAL_UI_USERNAME} + TEMPORAL_UI_PASSWORD_HASH: ${TEMPORAL_UI_PASSWORD_HASH} PROMETHEUS_HOSTNAME: ${PROMETHEUS_HOSTNAME} PROMETHEUS_PASSWORD_HASH: ${PROMETHEUS_PASSWORD_HASH} PROMETHEUS_USERNAME: ${PROMETHEUS_USERNAME} @@ -778,6 +781,50 @@ services: - portainer_data:/data - ${DOCKER_SOCKET_LOCATION:-/var/run/docker.sock}:/var/run/docker.sock + temporal: + image: temporalio/auto-setup:latest + container_name: temporal + profiles: ["postiz"] + restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "1m" + max-file: "1" + environment: + DB: postgres12 + POSTGRES_USER: postgres + POSTGRES_PWD: ${POSTGRES_PASSWORD} + POSTGRES_SEEDS: postgres + DB_PORT: 5432 + TEMPORAL_UINAMESPACE: default + depends_on: + postgres: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "tctl cluster health | grep -q SERVING || exit 1"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 60s + + temporal-ui: + image: temporalio/ui:latest + container_name: temporal-ui + profiles: ["postiz"] + restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "1m" + max-file: "1" + environment: + TEMPORAL_UIADDRESS: temporal:7233 + TEMPORAL_UICORS_ORIGINS: http://localhost:3000 + depends_on: + temporal: + condition: service_healthy + postiz: image: ghcr.io/gitroomhq/postiz-app:latest container_name: postiz @@ -796,6 +843,7 @@ services: NEXT_PUBLIC_UPLOAD_DIRECTORY: "/uploads" REDIS_URL: "redis://redis:6379" STORAGE_PROVIDER: "local" + TEMPORAL_UIADDRESS: temporal:7233 UPLOAD_DIRECTORY: "/uploads" # Social Media API Settings X_API_KEY: ${X_API_KEY} @@ -837,6 +885,8 @@ services: condition: service_healthy redis: condition: service_healthy + temporal: + condition: service_healthy databasus: image: databasus/databasus:latest diff --git a/scripts/03_generate_secrets.sh b/scripts/03_generate_secrets.sh index a1e52e8..e11bada 100755 --- a/scripts/03_generate_secrets.sh +++ b/scripts/03_generate_secrets.sh @@ -55,6 +55,7 @@ EMAIL_VARS=( "PROMETHEUS_USERNAME" "RAGAPP_USERNAME" "SEARXNG_USERNAME" + "TEMPORAL_UI_USERNAME" "WAHA_DASHBOARD_USERNAME" "WEAVIATE_USERNAME" "WELCOME_USERNAME" @@ -114,6 +115,7 @@ declare -A VARS_TO_GENERATE=( ["RAGFLOW_REDIS_PASSWORD"]="password:32" ["SEARXNG_PASSWORD"]="password:32" # Added SearXNG admin password ["SECRET_KEY_BASE"]="base64:64" # 48 bytes -> 64 chars + ["TEMPORAL_UI_PASSWORD"]="password:32" # Temporal UI basic auth password ["VAULT_ENC_KEY"]="alphanum:32" ["WAHA_DASHBOARD_PASSWORD"]="password:32" ["WEAVIATE_API_KEY"]="secret:48" # API Key for Weaviate service (36 bytes -> 48 chars base64) @@ -564,7 +566,7 @@ if [[ -n "$template_no_proxy" ]]; then fi # Hash passwords using caddy with bcrypt (consolidated loop) -SERVICES_NEEDING_HASH=("PROMETHEUS" "SEARXNG" "COMFYUI" "PADDLEOCR" "RAGAPP" "LT" "DOCLING" "WELCOME") +SERVICES_NEEDING_HASH=("PROMETHEUS" "SEARXNG" "COMFYUI" "PADDLEOCR" "RAGAPP" "LT" "DOCLING" "TEMPORAL_UI" "WELCOME") for service in "${SERVICES_NEEDING_HASH[@]}"; do password_var="${service}_PASSWORD" diff --git a/scripts/generate_welcome_page.sh b/scripts/generate_welcome_page.sh index 25b9683..8c11e5f 100755 --- a/scripts/generate_welcome_page.sh +++ b/scripts/generate_welcome_page.sh @@ -327,6 +327,20 @@ if is_profile_active "postiz"; then }") fi +# Temporal UI +if is_profile_active "postiz"; then + SERVICES_ARRAY+=(" \"temporal-ui\": { + \"hostname\": \"$(json_escape "$TEMPORAL_UI_HOSTNAME")\", + \"credentials\": { + \"username\": \"$(json_escape "$TEMPORAL_UI_USERNAME")\", + \"password\": \"$(json_escape "$TEMPORAL_UI_PASSWORD")\" + }, + \"extra\": { + \"note\": \"Workflow orchestration admin for Postiz\" + } + }") +fi + # WAHA if is_profile_active "waha"; then SERVICES_ARRAY+=(" \"waha\": { diff --git a/welcome/app.js b/welcome/app.js index f1c9b40..fdd175f 100644 --- a/welcome/app.js +++ b/welcome/app.js @@ -340,6 +340,14 @@ category: 'tools', docsUrl: 'https://docs.postiz.com' }, + 'temporal-ui': { + name: 'Temporal UI', + description: 'Postiz Workflow Orchestration', + icon: 'TM', + color: 'bg-violet-500', + category: 'tools', + docsUrl: 'https://docs.temporal.io/' + }, 'waha': { name: 'WAHA', description: 'WhatsApp HTTP API',