@if (!$is_redis_credential)
@if ($type === 'service')
+
@else
+
@if ($is_multiline === false)
@if (!$is_redis_credential)
@if ($type === 'service')
+
@else
+
@if ($is_multiline === false)
Date: Thu, 11 Sep 2025 20:23:02 +0200
Subject: [PATCH 09/71] fix(security): update contact email for reporting
vulnerabilities to enhance privacy
---
SECURITY.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SECURITY.md b/SECURITY.md
index 0711bf5b5..7384fc82a 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -18,7 +18,7 @@ ## Reporting a Vulnerability
If you discover a security vulnerability, please follow these steps:
1. **DO NOT** disclose the vulnerability publicly.
-2. Send a detailed report to: `hi@coollabs.io`.
+2. Send a detailed report to: `privacy@coollabs.io`.
3. Include in your report:
- A description of the vulnerability
- Steps to reproduce the issue
From a0b08fae5dd3be20ee8607400412b1431c0b77b3 Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Thu, 11 Sep 2025 20:23:07 +0200
Subject: [PATCH 10/71] fix(feedback): update feedback email address to improve
communication with users
---
app/Livewire/Help.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/Livewire/Help.php b/app/Livewire/Help.php
index 913710588..490515875 100644
--- a/app/Livewire/Help.php
+++ b/app/Livewire/Help.php
@@ -42,7 +42,7 @@ public function submit()
'content' => 'User: `'.auth()->user()?->email.'` with subject: `'.$this->subject.'` has the following problem: `'.$this->description.'`',
]);
} else {
- send_user_an_email($mail, auth()->user()?->email, 'hi@coollabs.io');
+ send_user_an_email($mail, auth()->user()?->email, 'feedback@coollabs.io');
}
$this->dispatch('success', 'Feedback sent.', 'We will get in touch with you as soon as possible.');
$this->reset('description', 'subject');
From c6b47da1e903f5d8ee827ff78744000b7e524378 Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Fri, 12 Sep 2025 11:47:13 +0200
Subject: [PATCH 11/71] feat(templates): add n8n service with PostgreSQL and
worker support for enhanced workflow automation
---
.../compose/n8n-with-postgres-and-worker.yaml | 103 ++++++++++++++++++
templates/service-templates-latest.json | 21 ++++
templates/service-templates.json | 21 ++++
3 files changed, 145 insertions(+)
create mode 100644 templates/compose/n8n-with-postgres-and-worker.yaml
diff --git a/templates/compose/n8n-with-postgres-and-worker.yaml b/templates/compose/n8n-with-postgres-and-worker.yaml
new file mode 100644
index 000000000..3b9520c20
--- /dev/null
+++ b/templates/compose/n8n-with-postgres-and-worker.yaml
@@ -0,0 +1,103 @@
+# documentation: https://n8n.io
+# slogan: n8n is an extendable workflow automation tool with queue mode and workers.
+# category: automation
+# tags: n8n,workflow,automation,open,source,low,code,queue,worker,scalable
+# logo: svgs/n8n.png
+# port: 5678
+
+services:
+ n8n:
+ image: docker.n8n.io/n8nio/n8n
+ environment:
+ - SERVICE_URL_N8N_5678
+ - N8N_EDITOR_BASE_URL=${SERVICE_URL_N8N}
+ - WEBHOOK_URL=${SERVICE_URL_N8N}
+ - N8N_HOST=${SERVICE_URL_N8N}
+ - GENERIC_TIMEZONE=${GENERIC_TIMEZONE:-Europe/Berlin}
+ - TZ=${TZ:-Europe/Berlin}
+ - DB_TYPE=postgresdb
+ - DB_POSTGRESDB_DATABASE=${POSTGRES_DB:-n8n}
+ - DB_POSTGRESDB_HOST=postgresql
+ - DB_POSTGRESDB_PORT=5432
+ - DB_POSTGRESDB_USER=$SERVICE_USER_POSTGRES
+ - DB_POSTGRESDB_SCHEMA=public
+ - DB_POSTGRESDB_PASSWORD=$SERVICE_PASSWORD_POSTGRES
+ - EXECUTIONS_MODE=queue
+ - QUEUE_BULL_REDIS_HOST=redis
+ - QUEUE_HEALTH_CHECK_ACTIVE=true
+ - N8N_ENCRYPTION_KEY=${SERVICE_PASSWORD_ENCRYPTION}
+ - N8N_RUNNERS_ENABLED=true
+ - OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true
+ - N8N_BLOCK_ENV_ACCESS_IN_NODE=${N8N_BLOCK_ENV_ACCESS_IN_NODE:-true}
+ - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=${N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS:-true}
+ volumes:
+ - n8n-data:/home/node/.n8n
+ depends_on:
+ postgresql:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+ healthcheck:
+ test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:5678/"]
+ interval: 5s
+ timeout: 20s
+ retries: 10
+
+ n8n-worker:
+ image: docker.n8n.io/n8nio/n8n
+ command: worker
+ environment:
+ - GENERIC_TIMEZONE=${GENERIC_TIMEZONE:-Europe/Berlin}
+ - TZ=${TZ:-Europe/Berlin}
+ - DB_TYPE=postgresdb
+ - DB_POSTGRESDB_DATABASE=${POSTGRES_DB:-n8n}
+ - DB_POSTGRESDB_HOST=postgresql
+ - DB_POSTGRESDB_PORT=5432
+ - DB_POSTGRESDB_USER=$SERVICE_USER_POSTGRES
+ - DB_POSTGRESDB_SCHEMA=public
+ - DB_POSTGRESDB_PASSWORD=$SERVICE_PASSWORD_POSTGRES
+ - EXECUTIONS_MODE=queue
+ - QUEUE_BULL_REDIS_HOST=redis
+ - QUEUE_HEALTH_CHECK_ACTIVE=true
+ - N8N_ENCRYPTION_KEY=${SERVICE_PASSWORD_ENCRYPTION}
+ - N8N_RUNNERS_ENABLED=true
+ - N8N_BLOCK_ENV_ACCESS_IN_NODE=${N8N_BLOCK_ENV_ACCESS_IN_NODE:-true}
+ - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=${N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS:-true}
+ volumes:
+ - n8n-data:/home/node/.n8n
+ healthcheck:
+ test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:5678/healthz"]
+ interval: 5s
+ timeout: 20s
+ retries: 10
+ depends_on:
+ n8n:
+ condition: service_healthy
+ postgresql:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+
+ postgresql:
+ image: postgres:16-alpine
+ volumes:
+ - postgresql-data:/var/lib/postgresql/data
+ environment:
+ - POSTGRES_USER=$SERVICE_USER_POSTGRES
+ - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES
+ - POSTGRES_DB=${POSTGRES_DB:-n8n}
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
+ interval: 5s
+ timeout: 20s
+ retries: 10
+
+ redis:
+ image: redis:6-alpine
+ volumes:
+ - redis-data:/data
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 5s
+ timeout: 5s
+ retries: 10
\ No newline at end of file
diff --git a/templates/service-templates-latest.json b/templates/service-templates-latest.json
index 2796f3738..35bdd37c0 100644
--- a/templates/service-templates-latest.json
+++ b/templates/service-templates-latest.json
@@ -2443,6 +2443,27 @@
"minversion": "0.0.0",
"port": "1883"
},
+ "n8n-with-postgres-and-worker": {
+ "documentation": "https://n8n.io?utm_source=coolify.io",
+ "slogan": "n8n is an extendable workflow automation tool with queue mode and workers.",
+ "compose": "c2VydmljZXM6CiAgbjhuOgogICAgaW1hZ2U6IGRvY2tlci5uOG4uaW8vbjhuaW8vbjhuCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9OOE5fNTY3OAogICAgICAtICdOOE5fRURJVE9SX0JBU0VfVVJMPSR7U0VSVklDRV9VUkxfTjhOfScKICAgICAgLSAnV0VCSE9PS19VUkw9JHtTRVJWSUNFX1VSTF9OOE59JwogICAgICAtICdOOE5fSE9TVD0ke1NFUlZJQ0VfVVJMX044Tn0nCiAgICAgIC0gJ0dFTkVSSUNfVElNRVpPTkU9JHtHRU5FUklDX1RJTUVaT05FOi1FdXJvcGUvQmVybGlufScKICAgICAgLSAnVFo9JHtUWjotRXVyb3BlL0Jlcmxpbn0nCiAgICAgIC0gREJfVFlQRT1wb3N0Z3Jlc2RiCiAgICAgIC0gJ0RCX1BPU1RHUkVTREJfREFUQUJBU0U9JHtQT1NUR1JFU19EQjotbjhufScKICAgICAgLSBEQl9QT1NUR1JFU0RCX0hPU1Q9cG9zdGdyZXNxbAogICAgICAtIERCX1BPU1RHUkVTREJfUE9SVD01NDMyCiAgICAgIC0gREJfUE9TVEdSRVNEQl9VU0VSPSRTRVJWSUNFX1VTRVJfUE9TVEdSRVMKICAgICAgLSBEQl9QT1NUR1JFU0RCX1NDSEVNQT1wdWJsaWMKICAgICAgLSBEQl9QT1NUR1JFU0RCX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gRVhFQ1VUSU9OU19NT0RFPXF1ZXVlCiAgICAgIC0gUVVFVUVfQlVMTF9SRURJU19IT1NUPXJlZGlzCiAgICAgIC0gUVVFVUVfSEVBTFRIX0NIRUNLX0FDVElWRT10cnVlCiAgICAgIC0gJ044Tl9FTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfRU5DUllQVElPTn0nCiAgICAgIC0gTjhOX1JVTk5FUlNfRU5BQkxFRD10cnVlCiAgICAgIC0gT0ZGTE9BRF9NQU5VQUxfRVhFQ1VUSU9OU19UT19XT1JLRVJTPXRydWUKICAgICAgLSAnTjhOX0JMT0NLX0VOVl9BQ0NFU1NfSU5fTk9ERT0ke044Tl9CTE9DS19FTlZfQUNDRVNTX0lOX05PREU6LXRydWV9JwogICAgICAtICdOOE5fRU5GT1JDRV9TRVRUSU5HU19GSUxFX1BFUk1JU1NJT05TPSR7TjhOX0VORk9SQ0VfU0VUVElOR1NfRklMRV9QRVJNSVNTSU9OUzotdHJ1ZX0nCiAgICB2b2x1bWVzOgogICAgICAtICduOG4tZGF0YTovaG9tZS9ub2RlLy5uOG4nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHJlZGlzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3dnZXQgLXFPLSBodHRwOi8vMTI3LjAuMC4xOjU2NzgvJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgbjhuLXdvcmtlcjoKICAgIGltYWdlOiBkb2NrZXIubjhuLmlvL244bmlvL244bgogICAgY29tbWFuZDogd29ya2VyCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnR0VORVJJQ19USU1FWk9ORT0ke0dFTkVSSUNfVElNRVpPTkU6LUV1cm9wZS9CZXJsaW59JwogICAgICAtICdUWj0ke1RaOi1FdXJvcGUvQmVybGlufScKICAgICAgLSBEQl9UWVBFPXBvc3RncmVzZGIKICAgICAgLSAnREJfUE9TVEdSRVNEQl9EQVRBQkFTRT0ke1BPU1RHUkVTX0RCOi1uOG59JwogICAgICAtIERCX1BPU1RHUkVTREJfSE9TVD1wb3N0Z3Jlc3FsCiAgICAgIC0gREJfUE9TVEdSRVNEQl9QT1JUPTU0MzIKICAgICAgLSBEQl9QT1NUR1JFU0RCX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIERCX1BPU1RHUkVTREJfU0NIRU1BPXB1YmxpYwogICAgICAtIERCX1BPU1RHUkVTREJfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVMKICAgICAgLSBFWEVDVVRJT05TX01PREU9cXVldWUKICAgICAgLSBRVUVVRV9CVUxMX1JFRElTX0hPU1Q9cmVkaXMKICAgICAgLSBRVUVVRV9IRUFMVEhfQ0hFQ0tfQUNUSVZFPXRydWUKICAgICAgLSAnTjhOX0VOQ1JZUFRJT05fS0VZPSR7U0VSVklDRV9QQVNTV09SRF9FTkNSWVBUSU9OfScKICAgICAgLSBOOE5fUlVOTkVSU19FTkFCTEVEPXRydWUKICAgICAgLSAnTjhOX0JMT0NLX0VOVl9BQ0NFU1NfSU5fTk9ERT0ke044Tl9CTE9DS19FTlZfQUNDRVNTX0lOX05PREU6LXRydWV9JwogICAgICAtICdOOE5fRU5GT1JDRV9TRVRUSU5HU19GSUxFX1BFUk1JU1NJT05TPSR7TjhOX0VORk9SQ0VfU0VUVElOR1NfRklMRV9QRVJNSVNTSU9OUzotdHJ1ZX0nCiAgICB2b2x1bWVzOgogICAgICAtICduOG4tZGF0YTovaG9tZS9ub2RlLy5uOG4nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3dnZXQgLXFPLSBodHRwOi8vMTI3LjAuMC4xOjU2NzgvaGVhbHRoeicKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogICAgZGVwZW5kc19vbjoKICAgICAgbjhuOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHBvc3RncmVzcWw6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgcmVkaXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICBwb3N0Z3Jlc3FsOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0Z3Jlc3FsLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVMKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotbjhufScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAKICByZWRpczoKICAgIGltYWdlOiAncmVkaXM6Ni1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdyZWRpcy1kYXRhOi9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIHJlZGlzLWNsaQogICAgICAgIC0gcGluZwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogMTAK",
+ "tags": [
+ "n8n",
+ "workflow",
+ "automation",
+ "open",
+ "source",
+ "low",
+ "code",
+ "queue",
+ "worker",
+ "scalable"
+ ],
+ "category": "automation",
+ "logo": "svgs/n8n.png",
+ "minversion": "0.0.0",
+ "port": "5678"
+ },
"n8n-with-postgresql": {
"documentation": "https://n8n.io?utm_source=coolify.io",
"slogan": "n8n is an extendable workflow automation tool.",
diff --git a/templates/service-templates.json b/templates/service-templates.json
index 458167ba0..34154ad0f 100644
--- a/templates/service-templates.json
+++ b/templates/service-templates.json
@@ -2443,6 +2443,27 @@
"minversion": "0.0.0",
"port": "1883"
},
+ "n8n-with-postgres-and-worker": {
+ "documentation": "https://n8n.io?utm_source=coolify.io",
+ "slogan": "n8n is an extendable workflow automation tool with queue mode and workers.",
+ "compose": "c2VydmljZXM6CiAgbjhuOgogICAgaW1hZ2U6IGRvY2tlci5uOG4uaW8vbjhuaW8vbjhuCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fTjhOXzU2NzgKICAgICAgLSAnTjhOX0VESVRPUl9CQVNFX1VSTD0ke1NFUlZJQ0VfRlFETl9OOE59JwogICAgICAtICdXRUJIT09LX1VSTD0ke1NFUlZJQ0VfRlFETl9OOE59JwogICAgICAtICdOOE5fSE9TVD0ke1NFUlZJQ0VfRlFETl9OOE59JwogICAgICAtICdHRU5FUklDX1RJTUVaT05FPSR7R0VORVJJQ19USU1FWk9ORTotRXVyb3BlL0Jlcmxpbn0nCiAgICAgIC0gJ1RaPSR7VFo6LUV1cm9wZS9CZXJsaW59JwogICAgICAtIERCX1RZUEU9cG9zdGdyZXNkYgogICAgICAtICdEQl9QT1NUR1JFU0RCX0RBVEFCQVNFPSR7UE9TVEdSRVNfREI6LW44bn0nCiAgICAgIC0gREJfUE9TVEdSRVNEQl9IT1NUPXBvc3RncmVzcWwKICAgICAgLSBEQl9QT1NUR1JFU0RCX1BPUlQ9NTQzMgogICAgICAtIERCX1BPU1RHUkVTREJfVVNFUj0kU0VSVklDRV9VU0VSX1BPU1RHUkVTCiAgICAgIC0gREJfUE9TVEdSRVNEQl9TQ0hFTUE9cHVibGljCiAgICAgIC0gREJfUE9TVEdSRVNEQl9QQVNTV09SRD0kU0VSVklDRV9QQVNTV09SRF9QT1NUR1JFUwogICAgICAtIEVYRUNVVElPTlNfTU9ERT1xdWV1ZQogICAgICAtIFFVRVVFX0JVTExfUkVESVNfSE9TVD1yZWRpcwogICAgICAtIFFVRVVFX0hFQUxUSF9DSEVDS19BQ1RJVkU9dHJ1ZQogICAgICAtICdOOE5fRU5DUllQVElPTl9LRVk9JHtTRVJWSUNFX1BBU1NXT1JEX0VOQ1JZUFRJT059JwogICAgICAtIE44Tl9SVU5ORVJTX0VOQUJMRUQ9dHJ1ZQogICAgICAtIE9GRkxPQURfTUFOVUFMX0VYRUNVVElPTlNfVE9fV09SS0VSUz10cnVlCiAgICAgIC0gJ044Tl9CTE9DS19FTlZfQUNDRVNTX0lOX05PREU9JHtOOE5fQkxPQ0tfRU5WX0FDQ0VTU19JTl9OT0RFOi10cnVlfScKICAgICAgLSAnTjhOX0VORk9SQ0VfU0VUVElOR1NfRklMRV9QRVJNSVNTSU9OUz0ke044Tl9FTkZPUkNFX1NFVFRJTkdTX0ZJTEVfUEVSTUlTU0lPTlM6LXRydWV9JwogICAgdm9sdW1lczoKICAgICAgLSAnbjhuLWRhdGE6L2hvbWUvbm9kZS8ubjhuJwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXNxbDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICd3Z2V0IC1xTy0gaHR0cDovLzEyNy4wLjAuMTo1Njc4LycKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDIwcwogICAgICByZXRyaWVzOiAxMAogIG44bi13b3JrZXI6CiAgICBpbWFnZTogZG9ja2VyLm44bi5pby9uOG5pby9uOG4KICAgIGNvbW1hbmQ6IHdvcmtlcgogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ0dFTkVSSUNfVElNRVpPTkU9JHtHRU5FUklDX1RJTUVaT05FOi1FdXJvcGUvQmVybGlufScKICAgICAgLSAnVFo9JHtUWjotRXVyb3BlL0Jlcmxpbn0nCiAgICAgIC0gREJfVFlQRT1wb3N0Z3Jlc2RiCiAgICAgIC0gJ0RCX1BPU1RHUkVTREJfREFUQUJBU0U9JHtQT1NUR1JFU19EQjotbjhufScKICAgICAgLSBEQl9QT1NUR1JFU0RCX0hPU1Q9cG9zdGdyZXNxbAogICAgICAtIERCX1BPU1RHUkVTREJfUE9SVD01NDMyCiAgICAgIC0gREJfUE9TVEdSRVNEQl9VU0VSPSRTRVJWSUNFX1VTRVJfUE9TVEdSRVMKICAgICAgLSBEQl9QT1NUR1JFU0RCX1NDSEVNQT1wdWJsaWMKICAgICAgLSBEQl9QT1NUR1JFU0RCX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gRVhFQ1VUSU9OU19NT0RFPXF1ZXVlCiAgICAgIC0gUVVFVUVfQlVMTF9SRURJU19IT1NUPXJlZGlzCiAgICAgIC0gUVVFVUVfSEVBTFRIX0NIRUNLX0FDVElWRT10cnVlCiAgICAgIC0gJ044Tl9FTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfRU5DUllQVElPTn0nCiAgICAgIC0gTjhOX1JVTk5FUlNfRU5BQkxFRD10cnVlCiAgICAgIC0gJ044Tl9CTE9DS19FTlZfQUNDRVNTX0lOX05PREU9JHtOOE5fQkxPQ0tfRU5WX0FDQ0VTU19JTl9OT0RFOi10cnVlfScKICAgICAgLSAnTjhOX0VORk9SQ0VfU0VUVElOR1NfRklMRV9QRVJNSVNTSU9OUz0ke044Tl9FTkZPUkNFX1NFVFRJTkdTX0ZJTEVfUEVSTUlTU0lPTlM6LXRydWV9JwogICAgdm9sdW1lczoKICAgICAgLSAnbjhuLWRhdGE6L2hvbWUvbm9kZS8ubjhuJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICd3Z2V0IC1xTy0gaHR0cDovLzEyNy4wLjAuMTo1Njc4L2hlYWx0aHonCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAKICAgIGRlcGVuZHNfb246CiAgICAgIG44bjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBwb3N0Z3Jlc3FsOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHJlZGlzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgcG9zdGdyZXNxbDoKICAgIGltYWdlOiAncG9zdGdyZXM6MTYtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncG9zdGdyZXNxbC1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JFNFUlZJQ0VfVVNFUl9QT1NUR1JFUwogICAgICAtIFBPU1RHUkVTX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LW44bn0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3BnX2lzcmVhZHkgLVUgJCR7UE9TVEdSRVNfVVNFUn0gLWQgJCR7UE9TVEdSRVNfREJ9JwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCiAgcmVkaXM6CiAgICBpbWFnZTogJ3JlZGlzOjYtYWxwaW5lJwogICAgdm9sdW1lczoKICAgICAgLSAncmVkaXMtZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSByZWRpcy1jbGkKICAgICAgICAtIHBpbmcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCg==",
+ "tags": [
+ "n8n",
+ "workflow",
+ "automation",
+ "open",
+ "source",
+ "low",
+ "code",
+ "queue",
+ "worker",
+ "scalable"
+ ],
+ "category": "automation",
+ "logo": "svgs/n8n.png",
+ "minversion": "0.0.0",
+ "port": "5678"
+ },
"n8n-with-postgresql": {
"documentation": "https://n8n.io?utm_source=coolify.io",
"slogan": "n8n is an extendable workflow automation tool.",
From 8e155f25b3ae3915fe5f6467b045c53c3aded038 Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Fri, 12 Sep 2025 12:09:03 +0200
Subject: [PATCH 12/71] refactor(environment): streamline environment variable
handling by replacing sorting methods with direct property access and
enhancing query ordering for improved performance
---
.../Shared/EnvironmentVariable/All.php | 34 ++++++++++---------
app/Models/Application.php | 18 ++++++++--
app/Models/Service.php | 16 ++++-----
app/Models/StandaloneClickhouse.php | 9 ++++-
app/Models/StandaloneDragonfly.php | 9 ++++-
app/Models/StandaloneKeydb.php | 9 ++++-
app/Models/StandaloneMariadb.php | 9 ++++-
app/Models/StandaloneMongodb.php | 9 ++++-
app/Models/StandaloneMysql.php | 9 ++++-
app/Models/StandalonePostgresql.php | 9 ++++-
app/Models/StandaloneRedis.php | 9 ++++-
.../shared/environment-variable/all.blade.php | 11 ++----
12 files changed, 108 insertions(+), 43 deletions(-)
diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/All.php b/app/Livewire/Project/Shared/EnvironmentVariable/All.php
index 92c1d16f9..9429c5f25 100644
--- a/app/Livewire/Project/Shared/EnvironmentVariable/All.php
+++ b/app/Livewire/Project/Shared/EnvironmentVariable/All.php
@@ -40,7 +40,7 @@ public function mount()
if (str($this->resourceClass)->contains($resourceWithPreviews) && ! $simpleDockerfile) {
$this->showPreview = true;
}
- $this->sortEnvironmentVariables();
+ $this->getDevView();
}
public function instantSave()
@@ -50,33 +50,36 @@ public function instantSave()
$this->resource->settings->is_env_sorting_enabled = $this->is_env_sorting_enabled;
$this->resource->settings->save();
- $this->sortEnvironmentVariables();
+ $this->getDevView();
$this->dispatch('success', 'Environment variable settings updated.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
- public function sortEnvironmentVariables()
+ public function getEnvironmentVariablesProperty()
{
if ($this->is_env_sorting_enabled === false) {
- if ($this->resource->environment_variables) {
- $this->resource->environment_variables = $this->resource->environment_variables->sortBy('order')->values();
- }
-
- if ($this->resource->environment_variables_preview) {
- $this->resource->environment_variables_preview = $this->resource->environment_variables_preview->sortBy('order')->values();
- }
+ return $this->resource->environment_variables()->orderBy('order')->get();
}
- $this->getDevView();
+ return $this->resource->environment_variables;
+ }
+
+ public function getEnvironmentVariablesPreviewProperty()
+ {
+ if ($this->is_env_sorting_enabled === false) {
+ return $this->resource->environment_variables_preview()->orderBy('order')->get();
+ }
+
+ return $this->resource->environment_variables_preview;
}
public function getDevView()
{
- $this->variables = $this->formatEnvironmentVariables($this->resource->environment_variables);
+ $this->variables = $this->formatEnvironmentVariables($this->environmentVariables);
if ($this->showPreview) {
- $this->variablesPreview = $this->formatEnvironmentVariables($this->resource->environment_variables_preview);
+ $this->variablesPreview = $this->formatEnvironmentVariables($this->environmentVariablesPreview);
}
}
@@ -97,7 +100,7 @@ private function formatEnvironmentVariables($variables)
public function switch()
{
$this->view = $this->view === 'normal' ? 'dev' : 'normal';
- $this->sortEnvironmentVariables();
+ $this->getDevView();
}
public function submit($data = null)
@@ -111,7 +114,7 @@ public function submit($data = null)
}
$this->updateOrder();
- $this->sortEnvironmentVariables();
+ $this->getDevView();
} catch (\Throwable $e) {
return handleError($e, $this);
} finally {
@@ -292,7 +295,6 @@ private function updateOrCreateVariables($isPreview, $variables)
public function refreshEnvs()
{
$this->resource->refresh();
- $this->sortEnvironmentVariables();
$this->getDevView();
}
}
diff --git a/app/Models/Application.php b/app/Models/Application.php
index 30be56523..c98d83641 100644
--- a/app/Models/Application.php
+++ b/app/Models/Application.php
@@ -728,7 +728,14 @@ public function environment_variables()
{
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
->where('is_preview', false)
- ->orderBy('key', 'asc');
+ ->orderByRaw("
+ CASE
+ WHEN LOWER(key) LIKE 'service_%' THEN 1
+ WHEN is_required = true AND (value IS NULL OR value = '') THEN 2
+ ELSE 3
+ END,
+ LOWER(key) ASC
+ ");
}
public function runtime_environment_variables()
@@ -749,7 +756,14 @@ public function environment_variables_preview()
{
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
->where('is_preview', true)
- ->orderByRaw("LOWER(key) LIKE LOWER('SERVICE%') DESC, LOWER(key) ASC");
+ ->orderByRaw("
+ CASE
+ WHEN LOWER(key) LIKE 'service_%' THEN 1
+ WHEN is_required = true AND (value IS NULL OR value = '') THEN 2
+ ELSE 3
+ END,
+ LOWER(key) ASC
+ ");
}
public function runtime_environment_variables_preview()
diff --git a/app/Models/Service.php b/app/Models/Service.php
index 108575d56..615789e64 100644
--- a/app/Models/Service.php
+++ b/app/Models/Service.php
@@ -1229,14 +1229,14 @@ public function scheduled_tasks(): HasMany
public function environment_variables()
{
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
- }
-
- public function environment_variables_preview()
- {
- return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->where('is_preview', true)
- ->orderByRaw("LOWER(key) LIKE LOWER('SERVICE%') DESC, LOWER(key) ASC");
+ ->orderByRaw("
+ CASE
+ WHEN LOWER(key) LIKE 'service_%' THEN 1
+ WHEN is_required = true AND (value IS NULL OR value = '') THEN 2
+ ELSE 3
+ END,
+ LOWER(key) ASC
+ ");
}
public function workdir()
diff --git a/app/Models/StandaloneClickhouse.php b/app/Models/StandaloneClickhouse.php
index 88142066f..87c5c3422 100644
--- a/app/Models/StandaloneClickhouse.php
+++ b/app/Models/StandaloneClickhouse.php
@@ -266,7 +266,14 @@ public function destination()
public function environment_variables()
{
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
+ ->orderByRaw("
+ CASE
+ WHEN LOWER(key) LIKE 'service_%' THEN 1
+ WHEN is_required = true AND (value IS NULL OR value = '') THEN 2
+ ELSE 3
+ END,
+ LOWER(key) ASC
+ ");
}
public function runtime_environment_variables()
diff --git a/app/Models/StandaloneDragonfly.php b/app/Models/StandaloneDragonfly.php
index b7d22a2ce..118c72726 100644
--- a/app/Models/StandaloneDragonfly.php
+++ b/app/Models/StandaloneDragonfly.php
@@ -341,6 +341,13 @@ public function isBackupSolutionAvailable()
public function environment_variables()
{
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
+ ->orderByRaw("
+ CASE
+ WHEN LOWER(key) LIKE 'service_%' THEN 1
+ WHEN is_required = true AND (value IS NULL OR value = '') THEN 2
+ ELSE 3
+ END,
+ LOWER(key) ASC
+ ");
}
}
diff --git a/app/Models/StandaloneKeydb.php b/app/Models/StandaloneKeydb.php
index 807728a36..9d674b6c2 100644
--- a/app/Models/StandaloneKeydb.php
+++ b/app/Models/StandaloneKeydb.php
@@ -341,6 +341,13 @@ public function isBackupSolutionAvailable()
public function environment_variables()
{
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
+ ->orderByRaw("
+ CASE
+ WHEN LOWER(key) LIKE 'service_%' THEN 1
+ WHEN is_required = true AND (value IS NULL OR value = '') THEN 2
+ ELSE 3
+ END,
+ LOWER(key) ASC
+ ");
}
}
diff --git a/app/Models/StandaloneMariadb.php b/app/Models/StandaloneMariadb.php
index 8d602c27d..616d536c1 100644
--- a/app/Models/StandaloneMariadb.php
+++ b/app/Models/StandaloneMariadb.php
@@ -262,7 +262,14 @@ public function destination(): MorphTo
public function environment_variables()
{
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
+ ->orderByRaw("
+ CASE
+ WHEN LOWER(key) LIKE 'service_%' THEN 1
+ WHEN is_required = true AND (value IS NULL OR value = '') THEN 2
+ ELSE 3
+ END,
+ LOWER(key) ASC
+ ");
}
public function runtime_environment_variables()
diff --git a/app/Models/StandaloneMongodb.php b/app/Models/StandaloneMongodb.php
index f222b0e5c..b26b6c967 100644
--- a/app/Models/StandaloneMongodb.php
+++ b/app/Models/StandaloneMongodb.php
@@ -363,6 +363,13 @@ public function isBackupSolutionAvailable()
public function environment_variables()
{
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
+ ->orderByRaw("
+ CASE
+ WHEN LOWER(key) LIKE 'service_%' THEN 1
+ WHEN is_required = true AND (value IS NULL OR value = '') THEN 2
+ ELSE 3
+ END,
+ LOWER(key) ASC
+ ");
}
}
diff --git a/app/Models/StandaloneMysql.php b/app/Models/StandaloneMysql.php
index e4693c76a..7b6f1b94e 100644
--- a/app/Models/StandaloneMysql.php
+++ b/app/Models/StandaloneMysql.php
@@ -345,6 +345,13 @@ public function isBackupSolutionAvailable()
public function environment_variables()
{
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
+ ->orderByRaw("
+ CASE
+ WHEN LOWER(key) LIKE 'service_%' THEN 1
+ WHEN is_required = true AND (value IS NULL OR value = '') THEN 2
+ ELSE 3
+ END,
+ LOWER(key) ASC
+ ");
}
}
diff --git a/app/Models/StandalonePostgresql.php b/app/Models/StandalonePostgresql.php
index 47c984ff7..f13e6ffab 100644
--- a/app/Models/StandalonePostgresql.php
+++ b/app/Models/StandalonePostgresql.php
@@ -296,7 +296,14 @@ public function scheduledBackups()
public function environment_variables()
{
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
+ ->orderByRaw("
+ CASE
+ WHEN LOWER(key) LIKE 'service_%' THEN 1
+ WHEN is_required = true AND (value IS NULL OR value = '') THEN 2
+ ELSE 3
+ END,
+ LOWER(key) ASC
+ ");
}
public function isBackupSolutionAvailable()
diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php
index 79c6572ab..9f7c96a08 100644
--- a/app/Models/StandaloneRedis.php
+++ b/app/Models/StandaloneRedis.php
@@ -388,6 +388,13 @@ public function redisUsername(): Attribute
public function environment_variables()
{
return $this->morphMany(EnvironmentVariable::class, 'resourceable')
- ->orderBy('key', 'asc');
+ ->orderByRaw("
+ CASE
+ WHEN LOWER(key) LIKE 'service_%' THEN 1
+ WHEN is_required = true AND (value IS NULL OR value = '') THEN 2
+ ELSE 3
+ END,
+ LOWER(key) ASC
+ ");
}
}
diff --git a/resources/views/livewire/project/shared/environment-variable/all.blade.php b/resources/views/livewire/project/shared/environment-variable/all.blade.php
index c75407179..4518420dd 100644
--- a/resources/views/livewire/project/shared/environment-variable/all.blade.php
+++ b/resources/views/livewire/project/shared/environment-variable/all.blade.php
@@ -45,14 +45,7 @@
Production Environment Variables
Environment (secrets) variables for Production.
- @php
- $requiredEmptyVars = $resource->environment_variables->filter(function ($env) {
- return $env->is_required && empty($env->value);
- });
-
- $otherVars = $resource->environment_variables->diff($requiredEmptyVars);
- @endphp
- @forelse ($requiredEmptyVars->merge($otherVars) as $env)
+ @forelse ($this->environmentVariables as $env)
Environment (secrets) variables for Preview Deployments.
- @foreach ($resource->environment_variables_preview as $env)
+ @foreach ($this->environmentVariablesPreview as $env)