From f06bacc8e0432e67cc412c5bf41b5b2585903340 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Thu, 23 Jul 2026 17:25:53 +0200 Subject: [PATCH] feat(services): add Buzz one-click service template (#11020) --- public/svgs/buzz.svg | 20 ++++ templates/compose/buzz.yaml | 126 ++++++++++++++++++++++++ templates/service-templates-latest.json | 28 +++++- templates/service-templates.json | 28 +++++- tests/Unit/BuzzServiceTemplateTest.php | 35 +++++++ 5 files changed, 229 insertions(+), 8 deletions(-) create mode 100644 public/svgs/buzz.svg create mode 100644 templates/compose/buzz.yaml create mode 100644 tests/Unit/BuzzServiceTemplateTest.php diff --git a/public/svgs/buzz.svg b/public/svgs/buzz.svg new file mode 100644 index 000000000..716bbd3dc --- /dev/null +++ b/public/svgs/buzz.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + diff --git a/templates/compose/buzz.yaml b/templates/compose/buzz.yaml new file mode 100644 index 000000000..6423f6400 --- /dev/null +++ b/templates/compose/buzz.yaml @@ -0,0 +1,126 @@ +# documentation: https://github.com/block/buzz +# slogan: Self-hostable workspace where humans and AI agents collaborate on a Nostr relay you own. +# category: messaging +# tags: buzz,chat,nostr,agents,ai,collaboration,relay,block +# logo: svgs/buzz.svg +# port: 3000 + +services: + buzz: + image: 'ghcr.io/block/buzz:${BUZZ_TAG:-main}' + environment: + - SERVICE_URL_BUZZ_3000 + - BUZZ_BIND_ADDR=0.0.0.0:3000 + - BUZZ_HEALTH_PORT=8080 + - BUZZ_METRICS_PORT=9102 + - RELAY_URL=wss://${SERVICE_FQDN_BUZZ} + - BUZZ_MEDIA_BASE_URL=${SERVICE_URL_BUZZ}/media + - BUZZ_MEDIA_SERVER_DOMAIN=${SERVICE_FQDN_BUZZ} + - BUZZ_CORS_ORIGINS=${SERVICE_URL_BUZZ} + - DATABASE_URL=postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/${POSTGRES_DB:-buzz} + - REDIS_URL=redis://:${SERVICE_PASSWORD_REDIS}@redis:6379 + - BUZZ_S3_ENDPOINT=http://minio:9000 + - BUZZ_S3_ACCESS_KEY=${SERVICE_USER_MINIO} + - BUZZ_S3_SECRET_KEY=${SERVICE_PASSWORD_MINIO} + - BUZZ_S3_BUCKET=${BUZZ_S3_BUCKET:-buzz-media} + - BUZZ_GIT_REPO_PATH=/data/git + - BUZZ_RELAY_PRIVATE_KEY=${SERVICE_HEX_64_RELAYKEY} + - BUZZ_GIT_HOOK_HMAC_SECRET=${SERVICE_HEX_64_GITHMAC} + - BUZZ_AUTO_MIGRATE=${BUZZ_AUTO_MIGRATE:-true} + - BUZZ_GIT_CONFORMANCE_PROBE=${BUZZ_GIT_CONFORMANCE_PROBE:-true} + - BUZZ_REQUIRE_AUTH_TOKEN=${BUZZ_REQUIRE_AUTH_TOKEN:-true} + - BUZZ_REQUIRE_RELAY_MEMBERSHIP=${BUZZ_REQUIRE_RELAY_MEMBERSHIP:-false} + - BUZZ_ALLOW_NIP_OA_AUTH=${BUZZ_ALLOW_NIP_OA_AUTH:-true} + - RELAY_OWNER_PUBKEY=${RELAY_OWNER_PUBKEY} + - RUST_LOG=${RUST_LOG:-buzz_relay=info,buzz_db=info,buzz_auth=info,buzz_pubsub=info,tower_http=info} + volumes: + - buzz-git-data:/data/git + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + minio: + condition: service_healthy + minio-init: + condition: service_completed_successfully + healthcheck: + test: + - CMD-SHELL + - "curl -fsS http://127.0.0.1:8080/_readiness >/dev/null || exit 1" + interval: 10s + timeout: 5s + retries: 12 + start_period: 45s + + postgres: + image: 'postgres:17-alpine' + environment: + - POSTGRES_USER=${SERVICE_USER_POSTGRES} + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} + - POSTGRES_DB=${POSTGRES_DB:-buzz} + - PGDATA=/var/lib/postgresql/data/pgdata + volumes: + - buzz-postgres-data:/var/lib/postgresql/data + healthcheck: + test: + - CMD-SHELL + - 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}' + interval: 5s + timeout: 5s + retries: 12 + start_period: 10s + + redis: + image: 'redis:7-alpine' + command: ['redis-server', '--appendonly', 'yes', '--requirepass', '${SERVICE_PASSWORD_REDIS}'] + environment: + - REDIS_PASSWORD=${SERVICE_PASSWORD_REDIS} + volumes: + - buzz-redis-data:/data + healthcheck: + test: + - CMD-SHELL + - 'redis-cli -a "$${REDIS_PASSWORD}" ping | grep -q PONG' + interval: 5s + timeout: 3s + retries: 12 + start_period: 5s + + minio: + image: 'minio/minio:RELEASE.2025-09-07T16-13-09Z' + command: 'server /data --console-address ":9001"' + environment: + - MINIO_ROOT_USER=${SERVICE_USER_MINIO} + - MINIO_ROOT_PASSWORD=${SERVICE_PASSWORD_MINIO} + volumes: + - buzz-minio-data:/data + healthcheck: + test: + - CMD + - curl + - '-f' + - 'http://127.0.0.1:9000/minio/health/live' + interval: 5s + timeout: 5s + retries: 12 + start_period: 10s + + minio-init: + image: 'minio/mc:RELEASE.2025-08-13T08-35-41Z' + depends_on: + minio: + condition: service_healthy + environment: + - BUZZ_S3_ACCESS_KEY=${SERVICE_USER_MINIO} + - BUZZ_S3_SECRET_KEY=${SERVICE_PASSWORD_MINIO} + - BUZZ_S3_BUCKET=${BUZZ_S3_BUCKET:-buzz-media} + entrypoint: + - /bin/sh + - '-euc' + - | + mc alias set local http://minio:9000 "$${BUZZ_S3_ACCESS_KEY}" "$${BUZZ_S3_SECRET_KEY}" + mc mb --ignore-existing "local/$${BUZZ_S3_BUCKET}" + mc anonymous set none "local/$${BUZZ_S3_BUCKET}" + restart: 'no' + exclude_from_hc: true diff --git a/templates/service-templates-latest.json b/templates/service-templates-latest.json index 7dd5d4c56..4c88a113c 100644 --- a/templates/service-templates-latest.json +++ b/templates/service-templates-latest.json @@ -64,7 +64,7 @@ "category": "productivity", "logo": "svgs/alexandrie.svg", "minversion": "0.0.0", - "template_last_updated_at": "2026-04-05T13:36:24+02:00", + "template_last_updated_at": "2026-07-07T13:24:35+02:00", "port": "8200" }, "anythingllm": { @@ -418,6 +418,26 @@ "template_last_updated_at": "2026-02-03T22:15:02+01:00", "port": "8000" }, + "buzz": { + "documentation": "https://github.com/block/buzz?utm_source=coolify.io", + "slogan": "Self-hostable workspace where humans and AI agents collaborate on a Nostr relay you own.", + "compose": "c2VydmljZXM6CiAgYnV6ejoKICAgIGltYWdlOiAnZ2hjci5pby9ibG9jay9idXp6OiR7QlVaWl9UQUc6LW1haW59JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfQlVaWl8zMDAwCiAgICAgIC0gJ0JVWlpfQklORF9BRERSPTAuMC4wLjA6MzAwMCcKICAgICAgLSBCVVpaX0hFQUxUSF9QT1JUPTgwODAKICAgICAgLSBCVVpaX01FVFJJQ1NfUE9SVD05MTAyCiAgICAgIC0gJ1JFTEFZX1VSTD13c3M6Ly8ke1NFUlZJQ0VfRlFETl9CVVpafScKICAgICAgLSAnQlVaWl9NRURJQV9CQVNFX1VSTD0ke1NFUlZJQ0VfVVJMX0JVWlp9L21lZGlhJwogICAgICAtICdCVVpaX01FRElBX1NFUlZFUl9ET01BSU49JHtTRVJWSUNFX0ZRRE5fQlVaWn0nCiAgICAgIC0gJ0JVWlpfQ09SU19PUklHSU5TPSR7U0VSVklDRV9VUkxfQlVaWn0nCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QHBvc3RncmVzOjU0MzIvJHtQT1NUR1JFU19EQjotYnV6en0nCiAgICAgIC0gJ1JFRElTX1VSTD1yZWRpczovLzoke1NFUlZJQ0VfUEFTU1dPUkRfUkVESVN9QHJlZGlzOjYzNzknCiAgICAgIC0gJ0JVWlpfUzNfRU5EUE9JTlQ9aHR0cDovL21pbmlvOjkwMDAnCiAgICAgIC0gJ0JVWlpfUzNfQUNDRVNTX0tFWT0ke1NFUlZJQ0VfVVNFUl9NSU5JT30nCiAgICAgIC0gJ0JVWlpfUzNfU0VDUkVUX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfTUlOSU99JwogICAgICAtICdCVVpaX1MzX0JVQ0tFVD0ke0JVWlpfUzNfQlVDS0VUOi1idXp6LW1lZGlhfScKICAgICAgLSBCVVpaX0dJVF9SRVBPX1BBVEg9L2RhdGEvZ2l0CiAgICAgIC0gJ0JVWlpfUkVMQVlfUFJJVkFURV9LRVk9JHtTRVJWSUNFX0hFWF82NF9SRUxBWUtFWX0nCiAgICAgIC0gJ0JVWlpfR0lUX0hPT0tfSE1BQ19TRUNSRVQ9JHtTRVJWSUNFX0hFWF82NF9HSVRITUFDfScKICAgICAgLSAnQlVaWl9BVVRPX01JR1JBVEU9JHtCVVpaX0FVVE9fTUlHUkFURTotdHJ1ZX0nCiAgICAgIC0gJ0JVWlpfR0lUX0NPTkZPUk1BTkNFX1BST0JFPSR7QlVaWl9HSVRfQ09ORk9STUFOQ0VfUFJPQkU6LXRydWV9JwogICAgICAtICdCVVpaX1JFUVVJUkVfQVVUSF9UT0tFTj0ke0JVWlpfUkVRVUlSRV9BVVRIX1RPS0VOOi10cnVlfScKICAgICAgLSAnQlVaWl9SRVFVSVJFX1JFTEFZX01FTUJFUlNISVA9JHtCVVpaX1JFUVVJUkVfUkVMQVlfTUVNQkVSU0hJUDotZmFsc2V9JwogICAgICAtICdCVVpaX0FMTE9XX05JUF9PQV9BVVRIPSR7QlVaWl9BTExPV19OSVBfT0FfQVVUSDotdHJ1ZX0nCiAgICAgIC0gJ1JFTEFZX09XTkVSX1BVQktFWT0ke1JFTEFZX09XTkVSX1BVQktFWX0nCiAgICAgIC0gJ1JVU1RfTE9HPSR7UlVTVF9MT0c6LWJ1enpfcmVsYXk9aW5mbyxidXp6X2RiPWluZm8sYnV6el9hdXRoPWluZm8sYnV6el9wdWJzdWI9aW5mbyx0b3dlcl9odHRwPWluZm99JwogICAgdm9sdW1lczoKICAgICAgLSAnYnV6ei1naXQtZGF0YTovZGF0YS9naXQnCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBtaW5pbzoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBtaW5pby1pbml0OgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9jb21wbGV0ZWRfc3VjY2Vzc2Z1bGx5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2N1cmwgLWZzUyBodHRwOi8vMTI3LjAuMC4xOjgwODAvX3JlYWRpbmVzcyA+L2Rldi9udWxsIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxMgogICAgICBzdGFydF9wZXJpb2Q6IDQ1cwogIHBvc3RncmVzOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNy1hbHBpbmUnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWJ1enp9JwogICAgICAtIFBHREFUQT0vdmFyL2xpYi9wb3N0Z3Jlc3FsL2RhdGEvcGdkYXRhCiAgICB2b2x1bWVzOgogICAgICAtICdidXp6LXBvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICQke1BPU1RHUkVTX1VTRVJ9IC1kICQke1BPU1RHUkVTX0RCfScKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEyCiAgICAgIHN0YXJ0X3BlcmlvZDogMTBzCiAgcmVkaXM6CiAgICBpbWFnZTogJ3JlZGlzOjctYWxwaW5lJwogICAgY29tbWFuZDoKICAgICAgLSByZWRpcy1zZXJ2ZXIKICAgICAgLSAnLS1hcHBlbmRvbmx5JwogICAgICAtICd5ZXMnCiAgICAgIC0gJy0tcmVxdWlyZXBhc3MnCiAgICAgIC0gJyR7U0VSVklDRV9QQVNTV09SRF9SRURJU30nCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnUkVESVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1JFRElTfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2J1enotcmVkaXMtZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncmVkaXMtY2xpIC1hICIkJHtSRURJU19QQVNTV09SRH0iIHBpbmcgfCBncmVwIC1xIFBPTkcnCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAzcwogICAgICByZXRyaWVzOiAxMgogICAgICBzdGFydF9wZXJpb2Q6IDVzCiAgbWluaW86CiAgICBpbWFnZTogJ21pbmlvL21pbmlvOlJFTEVBU0UuMjAyNS0wOS0wN1QxNi0xMy0wOVonCiAgICBjb21tYW5kOiAnc2VydmVyIC9kYXRhIC0tY29uc29sZS1hZGRyZXNzICI6OTAwMSInCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnTUlOSU9fUk9PVF9VU0VSPSR7U0VSVklDRV9VU0VSX01JTklPfScKICAgICAgLSAnTUlOSU9fUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTUlOSU99JwogICAgdm9sdW1lczoKICAgICAgLSAnYnV6ei1taW5pby1kYXRhOi9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjkwMDAvbWluaW8vaGVhbHRoL2xpdmUnCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxMgogICAgICBzdGFydF9wZXJpb2Q6IDEwcwogIG1pbmlvLWluaXQ6CiAgICBpbWFnZTogJ21pbmlvL21jOlJFTEVBU0UuMjAyNS0wOC0xM1QwOC0zNS00MVonCiAgICBkZXBlbmRzX29uOgogICAgICBtaW5pbzoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ0JVWlpfUzNfQUNDRVNTX0tFWT0ke1NFUlZJQ0VfVVNFUl9NSU5JT30nCiAgICAgIC0gJ0JVWlpfUzNfU0VDUkVUX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfTUlOSU99JwogICAgICAtICdCVVpaX1MzX0JVQ0tFVD0ke0JVWlpfUzNfQlVDS0VUOi1idXp6LW1lZGlhfScKICAgIGVudHJ5cG9pbnQ6CiAgICAgIC0gL2Jpbi9zaAogICAgICAtICctZXVjJwogICAgICAtICJtYyBhbGlhcyBzZXQgbG9jYWwgaHR0cDovL21pbmlvOjkwMDAgXCIkJHtCVVpaX1MzX0FDQ0VTU19LRVl9XCIgXCIkJHtCVVpaX1MzX1NFQ1JFVF9LRVl9XCJcbm1jIG1iIC0taWdub3JlLWV4aXN0aW5nIFwibG9jYWwvJCR7QlVaWl9TM19CVUNLRVR9XCJcbm1jIGFub255bW91cyBzZXQgbm9uZSBcImxvY2FsLyQke0JVWlpfUzNfQlVDS0VUfVwiIgogICAgcmVzdGFydDogJ25vJwogICAgZXhjbHVkZV9mcm9tX2hjOiB0cnVlCg==", + "tags": [ + "buzz", + "chat", + "nostr", + "agents", + "ai", + "collaboration", + "relay", + "block" + ], + "category": "messaging", + "logo": "svgs/buzz.svg", + "minversion": "0.0.0", + "template_last_updated_at": null, + "port": "3000" + }, "calibre-web-automated-book-downloader": { "documentation": "https://github.com/calibrain/calibre-web-automated-book-downloader?utm_source=coolify.io", "slogan": "An intuitive web interface for searching and requesting book downloads, designed to work seamlessly with Calibre-Web-Automated.", @@ -1322,7 +1342,7 @@ "category": "productivity", "logo": "svgs/espocrm.svg", "minversion": "0.0.0", - "template_last_updated_at": "2026-04-06T11:35:16-05:00", + "template_last_updated_at": "2026-07-03T15:15:43+03:00", "port": "80" }, "evolution-api": { @@ -2744,7 +2764,7 @@ "category": "devtools", "logo": "svgs/librespeed.png", "minversion": "0.0.0", - "template_last_updated_at": "2026-02-25T23:48:15Z", + "template_last_updated_at": "2026-02-25T23:48:15+00:00", "port": "82" }, "libretranslate": { @@ -2881,7 +2901,7 @@ "category": "auth", "logo": "svgs/logto_dark.svg", "minversion": "0.0.0", - "template_last_updated_at": "2026-04-01T13:19:47Z" + "template_last_updated_at": "2026-04-01T13:19:47+00:00" }, "lowcoder": { "documentation": "https://docs.lowcoder.cloud/?utm_source=coolify.io", diff --git a/templates/service-templates.json b/templates/service-templates.json index 26a4459ef..002017348 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -64,7 +64,7 @@ "category": "productivity", "logo": "svgs/alexandrie.svg", "minversion": "0.0.0", - "template_last_updated_at": "2026-04-05T13:36:24+02:00", + "template_last_updated_at": "2026-07-07T13:24:35+02:00", "port": "8200" }, "anythingllm": { @@ -418,6 +418,26 @@ "template_last_updated_at": "2026-02-03T22:15:02+01:00", "port": "8000" }, + "buzz": { + "documentation": "https://github.com/block/buzz?utm_source=coolify.io", + "slogan": "Self-hostable workspace where humans and AI agents collaborate on a Nostr relay you own.", + "compose": "c2VydmljZXM6CiAgYnV6ejoKICAgIGltYWdlOiAnZ2hjci5pby9ibG9jay9idXp6OiR7QlVaWl9UQUc6LW1haW59JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0JVWlpfMzAwMAogICAgICAtICdCVVpaX0JJTkRfQUREUj0wLjAuMC4wOjMwMDAnCiAgICAgIC0gQlVaWl9IRUFMVEhfUE9SVD04MDgwCiAgICAgIC0gQlVaWl9NRVRSSUNTX1BPUlQ9OTEwMgogICAgICAtICdSRUxBWV9VUkw9d3NzOi8vJHtTRVJWSUNFX0ZRRE5fQlVaWn0nCiAgICAgIC0gJ0JVWlpfTUVESUFfQkFTRV9VUkw9aHR0cHM6Ly8ke1NFUlZJQ0VfRlFETl9CVVpafS9tZWRpYScKICAgICAgLSAnQlVaWl9NRURJQV9TRVJWRVJfRE9NQUlOPSR7U0VSVklDRV9GUUROX0JVWlp9JwogICAgICAtICdCVVpaX0NPUlNfT1JJR0lOUz1odHRwczovLyR7U0VSVklDRV9GUUROX0JVWlp9JwogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXM6Ly8ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU306JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfUBwb3N0Z3Jlczo1NDMyLyR7UE9TVEdSRVNfREI6LWJ1enp9JwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly86JHtTRVJWSUNFX1BBU1NXT1JEX1JFRElTfUByZWRpczo2Mzc5JwogICAgICAtICdCVVpaX1MzX0VORFBPSU5UPWh0dHA6Ly9taW5pbzo5MDAwJwogICAgICAtICdCVVpaX1MzX0FDQ0VTU19LRVk9JHtTRVJWSUNFX1VTRVJfTUlOSU99JwogICAgICAtICdCVVpaX1MzX1NFQ1JFVF9LRVk9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfScKICAgICAgLSAnQlVaWl9TM19CVUNLRVQ9JHtCVVpaX1MzX0JVQ0tFVDotYnV6ei1tZWRpYX0nCiAgICAgIC0gQlVaWl9HSVRfUkVQT19QQVRIPS9kYXRhL2dpdAogICAgICAtICdCVVpaX1JFTEFZX1BSSVZBVEVfS0VZPSR7U0VSVklDRV9IRVhfNjRfUkVMQVlLRVl9JwogICAgICAtICdCVVpaX0dJVF9IT09LX0hNQUNfU0VDUkVUPSR7U0VSVklDRV9IRVhfNjRfR0lUSE1BQ30nCiAgICAgIC0gJ0JVWlpfQVVUT19NSUdSQVRFPSR7QlVaWl9BVVRPX01JR1JBVEU6LXRydWV9JwogICAgICAtICdCVVpaX0dJVF9DT05GT1JNQU5DRV9QUk9CRT0ke0JVWlpfR0lUX0NPTkZPUk1BTkNFX1BST0JFOi10cnVlfScKICAgICAgLSAnQlVaWl9SRVFVSVJFX0FVVEhfVE9LRU49JHtCVVpaX1JFUVVJUkVfQVVUSF9UT0tFTjotdHJ1ZX0nCiAgICAgIC0gJ0JVWlpfUkVRVUlSRV9SRUxBWV9NRU1CRVJTSElQPSR7QlVaWl9SRVFVSVJFX1JFTEFZX01FTUJFUlNISVA6LWZhbHNlfScKICAgICAgLSAnQlVaWl9BTExPV19OSVBfT0FfQVVUSD0ke0JVWlpfQUxMT1dfTklQX09BX0FVVEg6LXRydWV9JwogICAgICAtICdSRUxBWV9PV05FUl9QVUJLRVk9JHtSRUxBWV9PV05FUl9QVUJLRVl9JwogICAgICAtICdSVVNUX0xPRz0ke1JVU1RfTE9HOi1idXp6X3JlbGF5PWluZm8sYnV6el9kYj1pbmZvLGJ1enpfYXV0aD1pbmZvLGJ1enpfcHVic3ViPWluZm8sdG93ZXJfaHR0cD1pbmZvfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2J1enotZ2l0LWRhdGE6L2RhdGEvZ2l0JwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgcmVkaXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgbWluaW8taW5pdDoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfY29tcGxldGVkX3N1Y2Nlc3NmdWxseQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdjdXJsIC1mc1MgaHR0cDovLzEyNy4wLjAuMTo4MDgwL19yZWFkaW5lc3MgPi9kZXYvbnVsbCB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogMTIKICAgICAgc3RhcnRfcGVyaW9kOiA0NXMKICBwb3N0Z3JlczoKICAgIGltYWdlOiAncG9zdGdyZXM6MTctYWxwaW5lJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTX0RCOi1idXp6fScKICAgICAgLSBQR0RBVEE9L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhL3BnZGF0YQogICAgdm9sdW1lczoKICAgICAgLSAnYnV6ei1wb3N0Z3Jlcy1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAkJHtQT1NUR1JFU19VU0VSfSAtZCAkJHtQT1NUR1JFU19EQn0nCiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiAxMgogICAgICBzdGFydF9wZXJpb2Q6IDEwcwogIHJlZGlzOgogICAgaW1hZ2U6ICdyZWRpczo3LWFscGluZScKICAgIGNvbW1hbmQ6CiAgICAgIC0gcmVkaXMtc2VydmVyCiAgICAgIC0gJy0tYXBwZW5kb25seScKICAgICAgLSAneWVzJwogICAgICAtICctLXJlcXVpcmVwYXNzJwogICAgICAtICcke1NFUlZJQ0VfUEFTU1dPUkRfUkVESVN9JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1JFRElTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9SRURJU30nCiAgICB2b2x1bWVzOgogICAgICAtICdidXp6LXJlZGlzLWRhdGE6L2RhdGEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3JlZGlzLWNsaSAtYSAiJCR7UkVESVNfUEFTU1dPUkR9IiBwaW5nIHwgZ3JlcCAtcSBQT05HJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogM3MKICAgICAgcmV0cmllczogMTIKICAgICAgc3RhcnRfcGVyaW9kOiA1cwogIG1pbmlvOgogICAgaW1hZ2U6ICdtaW5pby9taW5pbzpSRUxFQVNFLjIwMjUtMDktMDdUMTYtMTMtMDlaJwogICAgY29tbWFuZDogJ3NlcnZlciAvZGF0YSAtLWNvbnNvbGUtYWRkcmVzcyAiOjkwMDEiJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ01JTklPX1JPT1RfVVNFUj0ke1NFUlZJQ0VfVVNFUl9NSU5JT30nCiAgICAgIC0gJ01JTklPX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2J1enotbWluaW8tZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTo5MDAwL21pbmlvL2hlYWx0aC9saXZlJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogMTIKICAgICAgc3RhcnRfcGVyaW9kOiAxMHMKICBtaW5pby1pbml0OgogICAgaW1hZ2U6ICdtaW5pby9tYzpSRUxFQVNFLjIwMjUtMDgtMTNUMDgtMzUtNDFaJwogICAgZGVwZW5kc19vbjoKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGVudmlyb25tZW50OgogICAgICAtICdCVVpaX1MzX0FDQ0VTU19LRVk9JHtTRVJWSUNFX1VTRVJfTUlOSU99JwogICAgICAtICdCVVpaX1MzX1NFQ1JFVF9LRVk9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfScKICAgICAgLSAnQlVaWl9TM19CVUNLRVQ9JHtCVVpaX1MzX0JVQ0tFVDotYnV6ei1tZWRpYX0nCiAgICBlbnRyeXBvaW50OgogICAgICAtIC9iaW4vc2gKICAgICAgLSAnLWV1YycKICAgICAgLSAibWMgYWxpYXMgc2V0IGxvY2FsIGh0dHA6Ly9taW5pbzo5MDAwIFwiJCR7QlVaWl9TM19BQ0NFU1NfS0VZfVwiIFwiJCR7QlVaWl9TM19TRUNSRVRfS0VZfVwiXG5tYyBtYiAtLWlnbm9yZS1leGlzdGluZyBcImxvY2FsLyQke0JVWlpfUzNfQlVDS0VUfVwiXG5tYyBhbm9ueW1vdXMgc2V0IG5vbmUgXCJsb2NhbC8kJHtCVVpaX1MzX0JVQ0tFVH1cIiIKICAgIHJlc3RhcnQ6ICdubycKICAgIGV4Y2x1ZGVfZnJvbV9oYzogdHJ1ZQo=", + "tags": [ + "buzz", + "chat", + "nostr", + "agents", + "ai", + "collaboration", + "relay", + "block" + ], + "category": "messaging", + "logo": "svgs/buzz.svg", + "minversion": "0.0.0", + "template_last_updated_at": null, + "port": "3000" + }, "calibre-web-automated-book-downloader": { "documentation": "https://github.com/calibrain/calibre-web-automated-book-downloader?utm_source=coolify.io", "slogan": "An intuitive web interface for searching and requesting book downloads, designed to work seamlessly with Calibre-Web-Automated.", @@ -1322,7 +1342,7 @@ "category": "productivity", "logo": "svgs/espocrm.svg", "minversion": "0.0.0", - "template_last_updated_at": "2026-04-06T11:35:16-05:00", + "template_last_updated_at": "2026-07-03T15:15:43+03:00", "port": "80" }, "evolution-api": { @@ -2744,7 +2764,7 @@ "category": "devtools", "logo": "svgs/librespeed.png", "minversion": "0.0.0", - "template_last_updated_at": "2026-02-25T23:48:15Z", + "template_last_updated_at": "2026-02-25T23:48:15+00:00", "port": "82" }, "libretranslate": { @@ -2881,7 +2901,7 @@ "category": "auth", "logo": "svgs/logto_dark.svg", "minversion": "0.0.0", - "template_last_updated_at": "2026-04-01T13:19:47Z" + "template_last_updated_at": "2026-04-01T13:19:47+00:00" }, "lowcoder": { "documentation": "https://docs.lowcoder.cloud/?utm_source=coolify.io", diff --git a/tests/Unit/BuzzServiceTemplateTest.php b/tests/Unit/BuzzServiceTemplateTest.php new file mode 100644 index 000000000..6a1d51e50 --- /dev/null +++ b/tests/Unit/BuzzServiceTemplateTest.php @@ -0,0 +1,35 @@ +toContain('ghcr.io/block/buzz:${BUZZ_TAG:-main}') + ->toContain('SERVICE_URL_BUZZ_3000') + ->toContain('RELAY_URL=wss://${SERVICE_FQDN_BUZZ}') + ->toContain('BUZZ_RELAY_PRIVATE_KEY=${SERVICE_HEX_64_RELAYKEY}') + ->toContain('BUZZ_AUTO_MIGRATE=${BUZZ_AUTO_MIGRATE:-true}') + ->toContain('minio-init') + ->toContain('exclude_from_hc: true') + ->toContain('postgres:17-alpine') + ->toContain('redis:7-alpine'); + + foreach (['service-templates.json', 'service-templates-latest.json'] as $templateFile) { + $templates = json_decode( + file_get_contents(__DIR__."/../../templates/{$templateFile}"), + associative: true, + flags: JSON_THROW_ON_ERROR, + ); + + expect($templates)->toHaveKey('buzz'); + expect($templates['buzz']['port'] ?? null)->toBe('3000'); + expect($templates['buzz']['logo'] ?? null)->toBe('svgs/buzz.svg'); + expect($templates['buzz']['category'] ?? null)->toBe('messaging'); + + $generatedCompose = base64_decode($templates['buzz']['compose'], strict: true); + + expect($generatedCompose) + ->toContain('ghcr.io/block/buzz:${BUZZ_TAG:-main}') + ->toContain('wss://'); + } +});