From 80664bbf4a065e925faa2bac984e2826b0f5fe24 Mon Sep 17 00:00:00 2001 From: ShadowArcanist <162910371+ShadowArcanist@users.noreply.github.com> Date: Thu, 28 Aug 2025 01:10:43 +0530 Subject: [PATCH 001/111] add elasticsearch-with-kibana.yaml --- .../compose/elasticsearch-with-kibana.yaml | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 templates/compose/elasticsearch-with-kibana.yaml diff --git a/templates/compose/elasticsearch-with-kibana.yaml b/templates/compose/elasticsearch-with-kibana.yaml new file mode 100644 index 000000000..b04594690 --- /dev/null +++ b/templates/compose/elasticsearch-with-kibana.yaml @@ -0,0 +1,95 @@ +# documentation: https://www.elastic.co/docs/deploy-manage/deploy/self-managed/install-kibana-with-docker +# slogan: Elastic + Kibana is a Free and Open Source Search, Monitoring, and Visualization Stack +# tags: elastic,kibana,elasticsearch,search,visualization,logging,monitoring,observability,analytics,stack,devops +# logo: svgs/elasticsearch.svg +# port: 5601 + +services: + elasticsearch: + image: 'elastic/elasticsearch:9.1.2' + container_name: elasticsearch + restart: unless-stopped + environment: + - ELASTIC_USER=elastic # Default built-in superuser (can't be changed); included here to avoid confusion about the username + - 'ELASTIC_PASSWORD=${SERVICE_PASSWORD_ELASTICSEARCH}' + - 'ES_JAVA_OPTS=-Xms512m -Xmx512m' # Limit JVM heap size to 512MB to prevent Elasticsearch from consuming all system memory + - discovery.type=single-node # Disable clustering; run as a standalone node (sufficient for most local or single-host setups) + - bootstrap.memory_lock=true # Prevent memory swapping by locking JVM memory (helps with performance/stability) + - xpack.security.http.ssl.enabled=false # SSL is unnecessary for HTTP traffic within the isolated Docker network + volumes: + - '/etc/localtime:/etc/localtime:ro' # Sync container timezone with host + - 'elasticsearch-data:/usr/share/elasticsearch/data' + healthcheck: + test: + - CMD-SHELL + - 'curl --user elastic:${SERVICE_PASSWORD_ELASTICSEARCH} --silent --fail http://localhost:9200/_cluster/health' + interval: 10s + timeout: 10s + retries: 24 + kibana: + image: 'kibana:9.1.2' + container_name: kibana + restart: unless-stopped + environment: + - SERVICE_URL_KIBANA_5601 + - 'KIBANA_PASSWORD=${SERVICE_PASSWORD_KIBANA}' + - 'ELASTICSEARCH_SERVICEACCOUNTTOKEN=${ELASTICSEARCH_SERVICEACCOUNTTOKEN}' # Kibana authenticates to Elasticsearch using this service token + - 'SERVER_NAME=${SERVICE_FQDN_KIBANA}' # For generating links and setting cookie domains + - 'SERVER_PUBLICBASEURL=${SERVICE_URL_KIBANA}' # Public URL used in generated links (reporting, alerting, etc.) + - 'ELASTICSEARCH_HOSTS=http://elasticsearch:9200' # Connect Kibana to Elasticsearch Service + - XPACK.SECURITY.ENABLED=true # Enable authentication and authorization (required for service tokens, roles, etc.) + - 'XPACK_SECURITY_ENCRYPTIONKEY=${SERVICE_PASSWORD_XPACKSECURITY}' # Required for encrypted session & auth tokens + - 'XPACK_REPORTING_ENCRYPTIONKEY=${SERVICE_PASSWORD_XPACKREPORTING}' # Required for reporting (PDFs, PNGs) + - 'XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY=${SERVICE_PASSWORD_XPACKENCRYPTEDSAVEDOBJECTS}' # Required for encrypting saved objects like alerts + - 'TELEMETRY_OPTIN=${TELEMETRY_OPTIN:-false}' # Disable telemetry by default (opt-in only) + volumes: + - '/etc/localtime:/etc/localtime:ro' # Sync container timezone with host + - 'kibana-data:/usr/share/kibana/data' + depends_on: + elasticsearch: + condition: service_healthy + healthcheck: + test: + - CMD-SHELL + - "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'" # Expect HTTP 302 (redirect) from Kibana login page + interval: 10s + timeout: 10s + retries: 120 + kibana-token-generator: + image: 'alpine:latest' + container_name: kibana-token-generator + depends_on: + elasticsearch: + condition: service_healthy + exclude_from_hc: true + environment: + - 'ELASTIC_PASSWORD=${SERVICE_PASSWORD_ELASTICSEARCH}' # Needed to authenticate the ELASTICSEARCH_SERVICEACCOUNTTOKEN creation request + entrypoint: + - sh + - '-c' + - | + apk add --no-cache curl jq >/dev/null 2>&1 + echo "Generating Kibana service token..." + + RESPONSE=$(curl -s -w "\n%{http_code}" -u elastic:"$${ELASTIC_PASSWORD}" -X POST "http://elasticsearch:9200/_security/service/elastic/kibana/credential/token/kibana-service-token") + HTTP_CODE=$$(echo "$${RESPONSE}" | tail -n1) + BODY=$$(echo "$${RESPONSE}" | head -n -1) + + if [ "$${HTTP_CODE}" = "200" ]; then + CREATED=$$(echo "$${BODY}" | jq -r '.created') + if [ "$${CREATED}" = "true" ]; then + TOKEN_VALUE=$$(echo "$${BODY}" | jq -r '.token.value') + echo "Token created successfully:" + echo "$${TOKEN_VALUE}" + else + echo "Unexpected response, token not created:" + echo "$${BODY}" + fi + elif [ "$${HTTP_CODE}" = "409" ]; then + echo "Token already exists. Skipping token creation." + else + echo "Failed to create token. HTTP code: $${HTTP_CODE}" + echo "$${BODY}" + exit 1 + fi + restart: 'no' # Run once to generate token, then exit From 3c126927d5dbcd757493afd12081fb08c61017f5 Mon Sep 17 00:00:00 2001 From: saurabhraghuvanshii Date: Thu, 28 Aug 2025 02:10:14 +0530 Subject: [PATCH 002/111] enhancement: allow deploy from container image hash --- app/Jobs/ApplicationDeploymentJob.php | 15 +- app/Livewire/Project/New/DockerImage.php | 4 + app/Services/DockerImageParser.php | 41 ++++++ .../project/application/general.blade.php | 6 +- .../project/new/docker-image.blade.php | 9 +- tests/Unit/DockerImageParserTest.php | 129 ++++++++++-------- 6 files changed, 145 insertions(+), 59 deletions(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 9037fa3e5..5a00a2dd6 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -410,7 +410,12 @@ private function deploy_dockerimage_buildpack() } else { $this->dockerImageTag = $this->application->docker_registry_image_tag; } - $this->application_deployment_queue->addLogEntry("Starting deployment of {$this->dockerImage}:{$this->dockerImageTag} to {$this->server->name}."); + + // Check if this is an image hash deployment + $isImageHash = str($this->dockerImageTag)->startsWith('sha256-'); + $displayName = $isImageHash ? "{$this->dockerImage}@sha256:".str($this->dockerImageTag)->after('sha256-') : "{$this->dockerImage}:{$this->dockerImageTag}"; + + $this->application_deployment_queue->addLogEntry("Starting deployment of {$displayName} to {$this->server->name}."); $this->generate_image_names(); $this->prepare_builder_image(); $this->generate_compose_file(); @@ -801,7 +806,13 @@ private function generate_image_names() $this->production_image_name = "{$this->application->uuid}:latest"; } } elseif ($this->application->build_pack === 'dockerimage') { - $this->production_image_name = "{$this->dockerImage}:{$this->dockerImageTag}"; + // Check if this is an image hash deployment + if (str($this->dockerImageTag)->startsWith('sha256-')) { + $hash = str($this->dockerImageTag)->after('sha256-'); + $this->production_image_name = "{$this->dockerImage}@sha256:{$hash}"; + } else { + $this->production_image_name = "{$this->dockerImage}:{$this->dockerImageTag}"; + } } elseif ($this->pull_request_id !== 0) { if ($this->application->docker_registry_image_name) { $this->build_image_name = "{$this->application->docker_registry_image_name}:pr-{$this->pull_request_id}-build"; diff --git a/app/Livewire/Project/New/DockerImage.php b/app/Livewire/Project/New/DockerImage.php index 7d68ce068..d78c61904 100644 --- a/app/Livewire/Project/New/DockerImage.php +++ b/app/Livewire/Project/New/DockerImage.php @@ -45,6 +45,10 @@ public function submit() $project = Project::where('uuid', $this->parameters['project_uuid'])->first(); $environment = $project->load(['environments'])->environments->where('uuid', $this->parameters['environment_uuid'])->first(); + + // Determine the image tag based on whether it's a hash or regular tag + $imageTag = $parser->isImageHash() ? 'sha256-'.$parser->getTag() : $parser->getTag(); + $application = Application::create([ 'name' => 'docker-image-'.new Cuid2, 'repository_project_id' => 0, diff --git a/app/Services/DockerImageParser.php b/app/Services/DockerImageParser.php index 1fd6625b3..1dd34c713 100644 --- a/app/Services/DockerImageParser.php +++ b/app/Services/DockerImageParser.php @@ -10,6 +10,8 @@ class DockerImageParser private string $tag = 'latest'; + private bool $isImageHash = false; + public function parse(string $imageString): self { // First split by : to handle the tag, but be careful with registry ports @@ -21,9 +23,13 @@ public function parse(string $imageString): self if ($lastColon !== false && (! $hasSlash || $lastColon > strrpos($imageString, '/'))) { $mainPart = substr($imageString, 0, $lastColon); $this->tag = substr($imageString, $lastColon + 1); + + // Check if the tag is a SHA256 hash + $this->isImageHash = $this->isSha256Hash($this->tag); } else { $mainPart = $imageString; $this->tag = 'latest'; + $this->isImageHash = false; } // Split the main part by / to handle registry and image name @@ -41,6 +47,37 @@ public function parse(string $imageString): self return $this; } + /** + * Check if the given string is a SHA256 hash + */ + private function isSha256Hash(string $hash): bool + { + // SHA256 hashes are 64 characters long and contain only hexadecimal characters + return preg_match('/^[a-f0-9]{64}$/i', $hash) === 1; + } + + /** + * Check if the current tag is an image hash + */ + public function isImageHash(): bool + { + return $this->isImageHash; + } + + /** + * Get the full image name with hash if present + */ + public function getFullImageNameWithHash(): string + { + $imageName = $this->getFullImageNameWithoutTag(); + + if ($this->isImageHash) { + return $imageName.'@sha256:'.$this->tag; + } + + return $imageName.':'.$this->tag; + } + public function getFullImageNameWithoutTag(): string { if ($this->registryUrl) { @@ -73,6 +110,10 @@ public function toString(): string } $parts[] = $this->imageName; + if ($this->isImageHash) { + return implode('/', $parts).'@sha256:'.$this->tag; + } + return implode('/', $parts).':'.$this->tag; } } diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index b833fc7bb..398e94191 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -163,12 +163,14 @@ class="underline" href="https://coolify.io/docs/knowledge-base/docker/registry" @if ($application->destination->server->isSwarm()) - @else - @endif @else diff --git a/resources/views/livewire/project/new/docker-image.blade.php b/resources/views/livewire/project/new/docker-image.blade.php index 4cc86710a..af1005a88 100644 --- a/resources/views/livewire/project/new/docker-image.blade.php +++ b/resources/views/livewire/project/new/docker-image.blade.php @@ -6,6 +6,13 @@

Docker Image

Save - +
+ +
diff --git a/tests/Unit/DockerImageParserTest.php b/tests/Unit/DockerImageParserTest.php index 35dffbab4..f41a9b170 100644 --- a/tests/Unit/DockerImageParserTest.php +++ b/tests/Unit/DockerImageParserTest.php @@ -3,92 +3,113 @@ namespace Tests\Unit; use App\Services\DockerImageParser; -use PHPUnit\Framework\Attributes\Test; -use PHPUnit\Framework\TestCase; +use Tests\TestCase; class DockerImageParserTest extends TestCase { - private DockerImageParser $parser; - - protected function setUp(): void + public function test_parses_regular_image_with_tag() { - parent::setUp(); - $this->parser = new DockerImageParser; + $parser = new DockerImageParser; + $parser->parse('nginx:latest'); + + $this->assertEquals('nginx', $parser->getImageName()); + $this->assertEquals('latest', $parser->getTag()); + $this->assertFalse($parser->isImageHash()); + $this->assertEquals('nginx:latest', $parser->toString()); } - #[Test] - public function it_parses_simple_image_name() + public function test_parses_image_with_sha256_hash() { - $this->parser->parse('nginx'); + $parser = new DockerImageParser; + $hash = '59e02939b1bf39f16c93138a28727aec520bb916da021180ae502c61626b3cf0'; + $parser->parse("ghcr.io/benjaminehowe/rail-disruptions:{$hash}"); - $this->assertEquals('', $this->parser->getRegistryUrl()); - $this->assertEquals('nginx', $this->parser->getImageName()); - $this->assertEquals('latest', $this->parser->getTag()); + $this->assertEquals('ghcr.io/benjaminehowe/rail-disruptions', $parser->getFullImageNameWithoutTag()); + $this->assertEquals($hash, $parser->getTag()); + $this->assertTrue($parser->isImageHash()); + $this->assertEquals("ghcr.io/benjaminehowe/rail-disruptions@sha256:{$hash}", $parser->toString()); + $this->assertEquals("ghcr.io/benjaminehowe/rail-disruptions@sha256:{$hash}", $parser->getFullImageNameWithHash()); } - #[Test] - public function it_parses_image_with_tag() + public function test_parses_registry_image_with_hash() { - $this->parser->parse('nginx:1.19'); + $parser = new DockerImageParser; + $hash = 'abc123def456789abcdef123456789abcdef123456789abcdef123456789abc1'; + $parser->parse("docker.io/library/nginx:{$hash}"); - $this->assertEquals('', $this->parser->getRegistryUrl()); - $this->assertEquals('nginx', $this->parser->getImageName()); - $this->assertEquals('1.19', $this->parser->getTag()); + $this->assertEquals('docker.io/library/nginx', $parser->getFullImageNameWithoutTag()); + $this->assertEquals($hash, $parser->getTag()); + $this->assertTrue($parser->isImageHash()); + $this->assertEquals("docker.io/library/nginx@sha256:{$hash}", $parser->toString()); } - #[Test] - public function it_parses_image_with_organization() + public function test_parses_image_without_tag_defaults_to_latest() { - $this->parser->parse('coollabs/coolify:latest'); + $parser = new DockerImageParser; + $parser->parse('nginx'); - $this->assertEquals('', $this->parser->getRegistryUrl()); - $this->assertEquals('coollabs/coolify', $this->parser->getImageName()); - $this->assertEquals('latest', $this->parser->getTag()); + $this->assertEquals('nginx', $parser->getImageName()); + $this->assertEquals('latest', $parser->getTag()); + $this->assertFalse($parser->isImageHash()); + $this->assertEquals('nginx:latest', $parser->toString()); } - #[Test] - public function it_parses_image_with_registry_url() + public function test_parses_registry_with_port() { - $this->parser->parse('ghcr.io/coollabs/coolify:v4'); + $parser = new DockerImageParser; + $parser->parse('registry.example.com:5000/myapp:latest'); - $this->assertEquals('ghcr.io', $this->parser->getRegistryUrl()); - $this->assertEquals('coollabs/coolify', $this->parser->getImageName()); - $this->assertEquals('v4', $this->parser->getTag()); + $this->assertEquals('registry.example.com:5000/myapp', $parser->getFullImageNameWithoutTag()); + $this->assertEquals('latest', $parser->getTag()); + $this->assertFalse($parser->isImageHash()); } - #[Test] - public function it_parses_image_with_port_in_registry() + public function test_parses_registry_with_port_and_hash() { - $this->parser->parse('localhost:5000/my-app:dev'); + $parser = new DockerImageParser; + $hash = '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'; + $parser->parse("registry.example.com:5000/myapp:{$hash}"); - $this->assertEquals('localhost:5000', $this->parser->getRegistryUrl()); - $this->assertEquals('my-app', $this->parser->getImageName()); - $this->assertEquals('dev', $this->parser->getTag()); + $this->assertEquals('registry.example.com:5000/myapp', $parser->getFullImageNameWithoutTag()); + $this->assertEquals($hash, $parser->getTag()); + $this->assertTrue($parser->isImageHash()); + $this->assertEquals("registry.example.com:5000/myapp@sha256:{$hash}", $parser->toString()); } - #[Test] - public function it_parses_image_without_tag() + public function test_identifies_valid_sha256_hashes() { - $this->parser->parse('ghcr.io/coollabs/coolify'); + $parser = new DockerImageParser; - $this->assertEquals('ghcr.io', $this->parser->getRegistryUrl()); - $this->assertEquals('coollabs/coolify', $this->parser->getImageName()); - $this->assertEquals('latest', $this->parser->getTag()); + // Valid SHA256 hashes + $validHashes = [ + '59e02939b1bf39f16c93138a28727aec520bb916da021180ae502c61626b3cf0', + '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', + 'abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890', + ]; + + foreach ($validHashes as $hash) { + $parser->parse("image:{$hash}"); + $this->assertTrue($parser->isImageHash(), "Hash {$hash} should be recognized as valid SHA256"); + } } - #[Test] - public function it_converts_back_to_string() + public function test_identifies_invalid_sha256_hashes() { - $originalString = 'ghcr.io/coollabs/coolify:v4'; - $this->parser->parse($originalString); + $parser = new DockerImageParser; - $this->assertEquals($originalString, $this->parser->toString()); - } + // Invalid SHA256 hashes + $invalidHashes = [ + 'latest', + 'v1.2.3', + 'abc123', // too short + '59e02939b1bf39f16c93138a28727aec520bb916da021180ae502c61626b3cf', // too short + '59e02939b1bf39f16c93138a28727aec520bb916da021180ae502c61626b3cf00', // too long + '59e02939b1bf39f16c93138a28727aec520bb916da021180ae502c61626b3cfg0', // invalid char + ]; - #[Test] - public function it_converts_to_string_with_default_tag() - { - $this->parser->parse('nginx'); - $this->assertEquals('nginx:latest', $this->parser->toString()); + foreach ($invalidHashes as $hash) { + $parser->parse("image:{$hash}"); + $this->assertFalse($parser->isImageHash(), "Hash {$hash} should not be recognized as valid SHA256"); + } } } From 1c3dbfb066743e7d5e9a3ba6bbb5e5653c1d26d5 Mon Sep 17 00:00:00 2001 From: sahil Date: Mon, 1 Sep 2025 14:32:02 +0530 Subject: [PATCH 003/111] Feat: ente config --- public/svgs/ente.png | Bin 0 -> 5096 bytes templates/compose/ente.yaml | 205 ++++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 public/svgs/ente.png create mode 100644 templates/compose/ente.yaml diff --git a/public/svgs/ente.png b/public/svgs/ente.png new file mode 100644 index 0000000000000000000000000000000000000000..737149125b4e84d6277bb4853494ae3ac4fe17bd GIT binary patch literal 5096 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 literal 0 HcmV?d00001 diff --git a/templates/compose/ente.yaml b/templates/compose/ente.yaml new file mode 100644 index 000000000..f754b7387 --- /dev/null +++ b/templates/compose/ente.yaml @@ -0,0 +1,205 @@ +# documentation: https://help.ente.io/ +# slogan: End-to-end encrypted photo backup and sharing platform +# category: media +# tags: photos, backup, encryption, sharing, privacy, media, storage, encryption, minio, postgresql +# logo: svgs/ente.png +# port: 3000, 3001, 3002, 3003, 3004, 8080, 3200 + +services: + museum: + image: ghcr.io/ente-io/server:latest + environment: + - SERVICE_PASSWORD_POSTGRES= ${SERVICE_PASSWORD_POSTGRES} + - SERVICE_URL_MUSEUM_8080=${SERVICE_URL_MUSEUM_8080} + - KEY_ENCRYPTION=${KEY_ENCRYPTION} + - KEY_HASH=${KEY_HASH} + - KEY_JWT=${KEY_JWT} + - ARE_LOCAL_S3=${ARE_LOCAL_S3} + - USE_PATH_STYLE_URLS_S3=${USE_PATH_STYLE_URLS_S3} + - ARE_LOCAL_B2=${ARE_LOCAL_B2} + - USE_PATH_STYLE_URLS_B2=${USE_PATH_STYLE_URLS_B2} + - KEY_B2=${KEY_B2} + - SECRET_B2=${SECRET_B2} + - REGION_B2=${REGION_B2} + - BUCKET_B2=${BUCKET_B2} + - ${ARE_LOCAL_WASABI} + - USE_PATH_STYLE_URLS_WASABI=${USE_PATH_STYLE_URLS_WASABI} + - KEY_WASABI=${KEY_WASABI} + - SECRET_WASABI=${SECRET_WASABI} + - REGION_WASABI=${REGION_WASABI} + - BUCKET_WASABI=${BUCKET_WASABI} + - COMPLIANCE_WASABI=${COMPLIANCE_WASABI} + - ARE_LOCAL_SCW=${ARE_LOCAL_SCW} + - USE_PATH_STYLE_URLS_SCW=${USE_PATH_STYLE_URLS_SCW} + - KEY_SCW=${KEY_SCW} + - SECRET_SCW=${SECRET_SCW} + - REGION_SCW=${REGION_SCW} + - BUCKET_SCW=${BUCKET_SCW} + depends_on: + postgres: + condition: service_healthy + volumes: + - museum-data:/data:ro + healthcheck: + test: ["CMD", "curl", "--fail", "http://localhost:8080/ping"] + interval: 60s + timeout: 5s + retries: 3 + start_period: 5s + restart: unless-stopped + command: | + sh -c ' + #!/bin/sh + + # Generate the museum.yaml configuration file + cat > /museum.yaml << EOF + db: + host: postgres + port: 5432 + name: ente_db + user: pguser + password: ${SERVICE_PASSWORD_POSTGRES} + + s3: + are_local_buckets: $ARE_LOCAL_S3 + use_path_style_urls: $USE_PATH_STYLE_URLS_S3 + b2-eu-cen: + are_local_buckets: ${ARE_LOCAL_B2:false} + use_path_style_urls: ${USE_PATH_STYLE_URLS_B2:false} + key: ${KEY_B2} + secret: ${SECRET_B2} + endpoint: ${SERVICE_URL_MINIO_3200} + region: ${REGION_B2} + bucket: ${BUCKET_B2} + wasabi-eu-central-2-v3: + are_local_buckets: ${ARE_LOCAL_WASABI:false} + use_path_style_urls: ${USE_PATH_STYLE_URLS_WASABI:false} + key: ${KEY_WASABI} + secret: ${SECRET_WASABI} + endpoint: ${SERVICE_URL_MINIO_3200} + region: ${REGION_WASABI} + bucket: ${BUCKET_WASABI} + compliance: ${COMPLIANCE_WASABI} + scw-eu-fr-v3: + are_local_buckets: ${ARE_LOCAL_SCW:false} + use_path_style_urls: ${USE_PATH_STYLE_URLS_SCW:false} + key: ${KEY_SCW} + secret: ${SECRET_SCW} + endpoint: ${SERVICE_URL_MINIO_3200} + region: ${REGION_SCW} + bucket: ${BUCKET_SCW} + + # Specify the base endpoints for various web apps + apps: + public-albums: ${SERVICE_URL_WEB_3002} + cast: ${SERVICE_URL_WEB_3004} + accounts: ${SERVICE_URL_WEB_3001} + + key: + encryption: ${KEY_ENCRYPTION} + hash: ${KEY_HASH} + + jwt: + secret: ${KEY_JWT} + + EOF + echo "Generated museum.yaml" + exec ./museum + ' + + socat: + image: alpine/socat:latest + network_mode: service:museum + depends_on: [museum] + command: "TCP-LISTEN:3200,fork,reuseaddr TCP:minio:3200" + restart: unless-stopped + healthcheck: + test: ["CMD", "nc", "-z", "localhost", "3200"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + + web: + image: ghcr.io/ente-io/web:latest + ports: + - 3000:3000 + - 3001:3001 + - 3002:3002 + - 3003:3003 + - 3004:3004 + environment: + - SERVICE_URL_WEB_3000 + - SERVICE_URL_WEB_3001 + - SERVICE_URL_WEB_3002 + - SERVICE_URL_WEB_3003 + - SERVICE_URL_WEB_3004 + - ENTE_API_ORIGIN=$SERVICE_URL_MUSEUM_8080 + - ENTE_ALBUMS_ORIGIN=$SERVICE_URL_WEB_3002 + - NODE_ENV=production + - ENTE_ACCOUNTS_ORIGIN=$SERVICE_URL_WEB_3001 + - ENTE_AUTH_ORIGIN=$SERVICE_URL_WEB_3003 + - ENTE_CAST_ORIGIN=$SERVICE_URL_WEB_3004 + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + + postgres: + image: postgres:15 + environment: + - POSTGRES_USER=pguser + - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES + - POSTGRES_DB=ente_db + volumes: + - postgres-data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U pguser -d ente_db"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + restart: unless-stopped + + minio: + image: minio/minio + environment: + - SERVICE_URL_MINIO_3200 + - MINIO_ROOT_USER=$SERVICE_USER_MINIO + - MINIO_ROOT_PASSWORD=$SERVICE_PASSWORD_MINIO + command: server /data --address ":3200" --console-address ":3201" + volumes: + - minio-data:/data + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3200/minio/health/live"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + restart: unless-stopped + post_start: + - command: | + sh -c ' + #!/bin/sh + + while ! mc alias set h0 http://minio:3200 $SERVICE_USER_MINIO $SERVICE_PASSWORD_MINIO 2>/dev/null + do + echo "Waiting for minio..." + sleep 0.5 + done + + mc mb -p b2-eu-cen + mc mb -p wasabi-eu-central-2-v3 + mc mb -p scw-eu-fr-v3 + ' + +volumes: + postgres-data: + minio-data: + museum-data: +networks: + default: + name: ente-network From db7b7d7b4cc830176d673d803cbaf4cb1a634824 Mon Sep 17 00:00:00 2001 From: Vishwanath Martur <64204611+vishwamartur@users.noreply.github.com> Date: Tue, 2 Sep 2025 15:26:42 +0530 Subject: [PATCH 004/111] feat: Add Ente Photos service template - Add Ente Photos service template with museum server, PostgreSQL, and MinIO - Include complete Docker Compose configuration with health checks - Add custom SVG logo for Ente Photos service - Support for end-to-end encrypted photo storage alternative to Google Photos - Auto-generate service templates JSON with proper categorization - Fix docker-compose.dev.yml network configuration for coolify service Resolves #6501 --- docker-compose.dev.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index e8402b7af..bf030080c 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -19,7 +19,10 @@ services: volumes: - .:/var/www/html/:cached - dev_backups_data:/var/www/html/storage/app/backups + networks: + - coolify postgres: + image: postgres:15-alpine pull_policy: always ports: - "${FORWARD_DB_PORT:-5432}:5432" @@ -32,7 +35,10 @@ services: POSTGRES_HOST_AUTH_METHOD: "trust" volumes: - dev_postgres_data:/var/lib/postgresql/data + networks: + - coolify redis: + image: redis:7-alpine pull_policy: always ports: - "${FORWARD_REDIS_PORT:-6379}:6379" @@ -40,6 +46,8 @@ services: - .env volumes: - dev_redis_data:/data + networks: + - coolify soketi: build: context: . From 0535335dd3e92812b6486fba9943dd20141afc06 Mon Sep 17 00:00:00 2001 From: Vishwanath Martur <64204611+vishwamartur@users.noreply.github.com> Date: Tue, 2 Sep 2025 15:28:10 +0530 Subject: [PATCH 005/111] Add Ente Photos service template files - Add ente-photos.yaml template with museum, postgres, and minio services - Add custom SVG logo for Ente Photos - Update service templates JSON files with new template --- public/svgs/ente-photos.svg | 27 ++++++++ templates/compose/ente-photos.yaml | 92 +++++++++++++++++++++++++ templates/service-templates-latest.json | 19 +++++ templates/service-templates.json | 19 +++++ 4 files changed, 157 insertions(+) create mode 100644 public/svgs/ente-photos.svg create mode 100644 templates/compose/ente-photos.yaml diff --git a/public/svgs/ente-photos.svg b/public/svgs/ente-photos.svg new file mode 100644 index 000000000..a3f9e7dea --- /dev/null +++ b/public/svgs/ente-photos.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templates/compose/ente-photos.yaml b/templates/compose/ente-photos.yaml new file mode 100644 index 000000000..6dcd19d41 --- /dev/null +++ b/templates/compose/ente-photos.yaml @@ -0,0 +1,92 @@ +# documentation: https://help.ente.io/self-hosting/installation/compose +# slogan: Ente Photos is a fully open source, End to End Encrypted alternative to Google Photos and Apple Photos. +# category: media +# tags: photos,gallery,backup,encryption,privacy,self-hosted,google-photos,alternative +# logo: svgs/ente-photos.svg +# port: 8080 + +services: + museum: + image: ghcr.io/ente-io/server:latest + environment: + - SERVICE_URL_MUSEUM_8080 + # Database configuration + - POSTGRES_HOST=postgres + - POSTGRES_PORT=5432 + - POSTGRES_DB=${POSTGRES_DB:-ente_db} + - POSTGRES_USER=${SERVICE_USER_POSTGRES} + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} + # S3/MinIO configuration + - S3_ARE_LOCAL_BUCKETS=true + - S3_USE_PATH_STYLE_URLS=true + - S3_B2_EU_CEN_KEY=${SERVICE_USER_MINIO} + - S3_B2_EU_CEN_SECRET=${SERVICE_PASSWORD_MINIO} + - S3_B2_EU_CEN_ENDPOINT=minio:3200 + - S3_B2_EU_CEN_REGION=eu-central-2 + - S3_B2_EU_CEN_BUCKET=b2-eu-cen + # Security keys + - ENCRYPTION_KEY=${SERVICE_PASSWORD_64_ENCRYPTION} + - HASH_KEY=${SERVICE_PASSWORD_64_HASH} + - JWT_SECRET=${SERVICE_PASSWORD_64_JWT} + # App URLs (optional - for web interface) + - APPS_PUBLIC_ALBUMS=${APPS_PUBLIC_ALBUMS:-} + - APPS_CAST=${APPS_CAST:-} + - APPS_ACCOUNTS=${APPS_ACCOUNTS:-} + volumes: + - museum-data:/data + - museum-config:/config + depends_on: + postgres: + condition: service_healthy + minio: + condition: service_started + healthcheck: + test: ["CMD", "curl", "-f", "http://127.0.0.1:8080/ping"] + interval: 30s + timeout: 10s + retries: 3 + + postgres: + image: postgres:15-alpine + environment: + - POSTGRES_USER=${SERVICE_USER_POSTGRES} + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} + - POSTGRES_DB=${POSTGRES_DB:-ente_db} + volumes: + - postgres-data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${SERVICE_USER_POSTGRES} -d ${POSTGRES_DB:-ente_db}"] + interval: 10s + timeout: 5s + retries: 5 + + minio: + image: minio/minio:latest + environment: + - MINIO_ROOT_USER=${SERVICE_USER_MINIO} + - MINIO_ROOT_PASSWORD=${SERVICE_PASSWORD_MINIO} + command: server /data --address ":3200" --console-address ":3201" + volumes: + - minio-data:/data + healthcheck: + test: ["CMD", "curl", "-f", "http://127.0.0.1:3200/minio/health/live"] + interval: 30s + timeout: 10s + retries: 3 + + minio-init: + image: minio/mc:latest + depends_on: + minio: + condition: service_healthy + environment: + - MINIO_ROOT_USER=${SERVICE_USER_MINIO} + - MINIO_ROOT_PASSWORD=${SERVICE_PASSWORD_MINIO} + entrypoint: > + /bin/sh -c " + mc alias set minio http://minio:3200 $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD}; + mc mb minio/b2-eu-cen --ignore-existing; + mc mb minio/wasabi-eu-central-2-v3 --ignore-existing; + mc mb minio/scw-eu-fr-v3 --ignore-existing; + echo 'MinIO buckets created successfully'; + " diff --git a/templates/service-templates-latest.json b/templates/service-templates-latest.json index 4ba6d0f2c..a5ea25386 100644 --- a/templates/service-templates-latest.json +++ b/templates/service-templates-latest.json @@ -948,6 +948,25 @@ "minversion": "0.0.0", "port": "6555" }, + "ente-photos": { + "documentation": "https://help.ente.io/self-hosting/installation/compose?utm_source=coolify.io", + "slogan": "Ente Photos is a fully open source, End to End Encrypted alternative to Google Photos and Apple Photos.", + "compose": "c2VydmljZXM6CiAgbXVzZXVtOgogICAgaW1hZ2U6ICdnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX01VU0VVTV84MDgwCiAgICAgIC0gUE9TVEdSRVNfSE9TVD1wb3N0Z3JlcwogICAgICAtIFBPU1RHUkVTX1BPUlQ9NTQzMgogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTX0RCOi1lbnRlX2RifScKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gUzNfQVJFX0xPQ0FMX0JVQ0tFVFM9dHJ1ZQogICAgICAtIFMzX1VTRV9QQVRIX1NUWUxFX1VSTFM9dHJ1ZQogICAgICAtICdTM19CMl9FVV9DRU5fS0VZPSR7U0VSVklDRV9VU0VSX01JTklPfScKICAgICAgLSAnUzNfQjJfRVVfQ0VOX1NFQ1JFVD0ke1NFUlZJQ0VfUEFTU1dPUkRfTUlOSU99JwogICAgICAtICdTM19CMl9FVV9DRU5fRU5EUE9JTlQ9bWluaW86MzIwMCcKICAgICAgLSBTM19CMl9FVV9DRU5fUkVHSU9OPWV1LWNlbnRyYWwtMgogICAgICAtIFMzX0IyX0VVX0NFTl9CVUNLRVQ9YjItZXUtY2VuCiAgICAgIC0gJ0VOQ1JZUFRJT05fS0VZPSR7U0VSVklDRV9QQVNTV09SRF82NF9FTkNSWVBUSU9OfScKICAgICAgLSAnSEFTSF9LRVk9JHtTRVJWSUNFX1BBU1NXT1JEXzY0X0hBU0h9JwogICAgICAtICdKV1RfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF82NF9KV1R9JwogICAgICAtICdBUFBTX1BVQkxJQ19BTEJVTVM9JHtBUFBTX1BVQkxJQ19BTEJVTVM6LX0nCiAgICAgIC0gJ0FQUFNfQ0FTVD0ke0FQUFNfQ0FTVDotfScKICAgICAgLSAnQVBQU19BQ0NPVU5UUz0ke0FQUFNfQUNDT1VOVFM6LX0nCiAgICB2b2x1bWVzOgogICAgICAtICdtdXNldW0tZGF0YTovZGF0YScKICAgICAgLSAnbXVzZXVtLWNvbmZpZzovY29uZmlnJwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX3N0YXJ0ZWQKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTo4MDgwL3BpbmcnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDMKICBwb3N0Z3JlczoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTX0RCOi1lbnRlX2RifScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3Bvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfSAtZCAke1BPU1RHUkVTX0RCOi1lbnRlX2RifScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgbWluaW86CiAgICBpbWFnZTogJ21pbmlvL21pbmlvOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtICdNSU5JT19ST09UX1VTRVI9JHtTRVJWSUNFX1VTRVJfTUlOSU99JwogICAgICAtICdNSU5JT19ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NSU5JT30nCiAgICBjb21tYW5kOiAnc2VydmVyIC9kYXRhIC0tYWRkcmVzcyAiOjMyMDAiIC0tY29uc29sZS1hZGRyZXNzICI6MzIwMSInCiAgICB2b2x1bWVzOgogICAgICAtICdtaW5pby1kYXRhOi9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjMyMDAvbWluaW8vaGVhbHRoL2xpdmUnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDMKICBtaW5pby1pbml0OgogICAgaW1hZ2U6ICdtaW5pby9tYzpsYXRlc3QnCiAgICBkZXBlbmRzX29uOgogICAgICBtaW5pbzoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ01JTklPX1JPT1RfVVNFUj0ke1NFUlZJQ0VfVVNFUl9NSU5JT30nCiAgICAgIC0gJ01JTklPX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfScKICAgIGVudHJ5cG9pbnQ6ICIvYmluL3NoIC1jIFwiIG1jIGFsaWFzIHNldCBtaW5pbyBodHRwOi8vbWluaW86MzIwMCAkJHtNSU5JT19ST09UX1VTRVJ9ICQke01JTklPX1JPT1RfUEFTU1dPUkR9OyBtYyBtYiBtaW5pby9iMi1ldS1jZW4gLS1pZ25vcmUtZXhpc3Rpbmc7IG1jIG1iIG1pbmlvL3dhc2FiaS1ldS1jZW50cmFsLTItdjMgLS1pZ25vcmUtZXhpc3Rpbmc7IG1jIG1iIG1pbmlvL3Njdy1ldS1mci12MyAtLWlnbm9yZS1leGlzdGluZzsgZWNobyAnTWluSU8gYnVja2V0cyBjcmVhdGVkIHN1Y2Nlc3NmdWxseSc7IFwiXG4iCg==", + "tags": [ + "photos", + "gallery", + "backup", + "encryption", + "privacy", + "self-hosted", + "google-photos", + "alternative" + ], + "category": "media", + "logo": "svgs/ente-photos.svg", + "minversion": "0.0.0", + "port": "8080" + }, "evolution-api": { "documentation": "https://doc.evolution-api.com/v1/pt/get-started/introduction?utm_source=coolify.io", "slogan": "Evolution API Installation with Postgres and Redis", diff --git a/templates/service-templates.json b/templates/service-templates.json index 19d5e0560..1dc45d3d0 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -948,6 +948,25 @@ "minversion": "0.0.0", "port": "6555" }, + "ente-photos": { + "documentation": "https://help.ente.io/self-hosting/installation/compose?utm_source=coolify.io", + "slogan": "Ente Photos is a fully open source, End to End Encrypted alternative to Google Photos and Apple Photos.", + "compose": "c2VydmljZXM6CiAgbXVzZXVtOgogICAgaW1hZ2U6ICdnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9NVVNFVU1fODA4MAogICAgICAtIFBPU1RHUkVTX0hPU1Q9cG9zdGdyZXMKICAgICAgLSBQT1NUR1JFU19QT1JUPTU0MzIKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotZW50ZV9kYn0nCiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtIFMzX0FSRV9MT0NBTF9CVUNLRVRTPXRydWUKICAgICAgLSBTM19VU0VfUEFUSF9TVFlMRV9VUkxTPXRydWUKICAgICAgLSAnUzNfQjJfRVVfQ0VOX0tFWT0ke1NFUlZJQ0VfVVNFUl9NSU5JT30nCiAgICAgIC0gJ1MzX0IyX0VVX0NFTl9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfScKICAgICAgLSAnUzNfQjJfRVVfQ0VOX0VORFBPSU5UPW1pbmlvOjMyMDAnCiAgICAgIC0gUzNfQjJfRVVfQ0VOX1JFR0lPTj1ldS1jZW50cmFsLTIKICAgICAgLSBTM19CMl9FVV9DRU5fQlVDS0VUPWIyLWV1LWNlbgogICAgICAtICdFTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfRU5DUllQVElPTn0nCiAgICAgIC0gJ0hBU0hfS0VZPSR7U0VSVklDRV9QQVNTV09SRF82NF9IQVNIfScKICAgICAgLSAnSldUX1NFQ1JFVD0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfSldUfScKICAgICAgLSAnQVBQU19QVUJMSUNfQUxCVU1TPSR7QVBQU19QVUJMSUNfQUxCVU1TOi19JwogICAgICAtICdBUFBTX0NBU1Q9JHtBUFBTX0NBU1Q6LX0nCiAgICAgIC0gJ0FQUFNfQUNDT1VOVFM9JHtBUFBTX0FDQ09VTlRTOi19JwogICAgdm9sdW1lczoKICAgICAgLSAnbXVzZXVtLWRhdGE6L2RhdGEnCiAgICAgIC0gJ211c2V1bS1jb25maWc6L2NvbmZpZycKICAgIGRlcGVuZHNfb246CiAgICAgIHBvc3RncmVzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIG1pbmlvOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9zdGFydGVkCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6ODA4MC9waW5nJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE1LWFscGluZScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotZW50ZV9kYn0nCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0Z3Jlcy1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30gLWQgJHtQT1NUR1JFU19EQjotZW50ZV9kYn0nCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQogIG1pbmlvOgogICAgaW1hZ2U6ICdtaW5pby9taW5pbzpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnTUlOSU9fUk9PVF9VU0VSPSR7U0VSVklDRV9VU0VSX01JTklPfScKICAgICAgLSAnTUlOSU9fUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTUlOSU99JwogICAgY29tbWFuZDogJ3NlcnZlciAvZGF0YSAtLWFkZHJlc3MgIjozMjAwIiAtLWNvbnNvbGUtYWRkcmVzcyAiOjMyMDEiJwogICAgdm9sdW1lczoKICAgICAgLSAnbWluaW8tZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTozMjAwL21pbmlvL2hlYWx0aC9saXZlJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgbWluaW8taW5pdDoKICAgIGltYWdlOiAnbWluaW8vbWM6bGF0ZXN0JwogICAgZGVwZW5kc19vbjoKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGVudmlyb25tZW50OgogICAgICAtICdNSU5JT19ST09UX1VTRVI9JHtTRVJWSUNFX1VTRVJfTUlOSU99JwogICAgICAtICdNSU5JT19ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NSU5JT30nCiAgICBlbnRyeXBvaW50OiAiL2Jpbi9zaCAtYyBcIiBtYyBhbGlhcyBzZXQgbWluaW8gaHR0cDovL21pbmlvOjMyMDAgJCR7TUlOSU9fUk9PVF9VU0VSfSAkJHtNSU5JT19ST09UX1BBU1NXT1JEfTsgbWMgbWIgbWluaW8vYjItZXUtY2VuIC0taWdub3JlLWV4aXN0aW5nOyBtYyBtYiBtaW5pby93YXNhYmktZXUtY2VudHJhbC0yLXYzIC0taWdub3JlLWV4aXN0aW5nOyBtYyBtYiBtaW5pby9zY3ctZXUtZnItdjMgLS1pZ25vcmUtZXhpc3Rpbmc7IGVjaG8gJ01pbklPIGJ1Y2tldHMgY3JlYXRlZCBzdWNjZXNzZnVsbHknOyBcIlxuIgo=", + "tags": [ + "photos", + "gallery", + "backup", + "encryption", + "privacy", + "self-hosted", + "google-photos", + "alternative" + ], + "category": "media", + "logo": "svgs/ente-photos.svg", + "minversion": "0.0.0", + "port": "8080" + }, "evolution-api": { "documentation": "https://doc.evolution-api.com/v1/pt/get-started/introduction?utm_source=coolify.io", "slogan": "Evolution API Installation with Postgres and Redis", From d42c531dabfd4a942b749533ee2fb74c2006a07f Mon Sep 17 00:00:00 2001 From: thesloppyguy Date: Tue, 2 Sep 2025 19:19:54 +0530 Subject: [PATCH 006/111] Feat: Cofig variables --- templates/compose/ente.yaml | 281 ++++++++++++++++++++---------------- 1 file changed, 156 insertions(+), 125 deletions(-) diff --git a/templates/compose/ente.yaml b/templates/compose/ente.yaml index f754b7387..830c21c43 100644 --- a/templates/compose/ente.yaml +++ b/templates/compose/ente.yaml @@ -3,173 +3,200 @@ # category: media # tags: photos, backup, encryption, sharing, privacy, media, storage, encryption, minio, postgresql # logo: svgs/ente.png -# port: 3000, 3001, 3002, 3003, 3004, 8080, 3200 +# port: 8081 3000, 3001, 3002, 3003, 3004, 3200 services: museum: image: ghcr.io/ente-io/server:latest + ports: + - 8081:8080 environment: - - SERVICE_PASSWORD_POSTGRES= ${SERVICE_PASSWORD_POSTGRES} - - SERVICE_URL_MUSEUM_8080=${SERVICE_URL_MUSEUM_8080} - - KEY_ENCRYPTION=${KEY_ENCRYPTION} - - KEY_HASH=${KEY_HASH} - - KEY_JWT=${KEY_JWT} - - ARE_LOCAL_S3=${ARE_LOCAL_S3} - - USE_PATH_STYLE_URLS_S3=${USE_PATH_STYLE_URLS_S3} - - ARE_LOCAL_B2=${ARE_LOCAL_B2} - - USE_PATH_STYLE_URLS_B2=${USE_PATH_STYLE_URLS_B2} - - KEY_B2=${KEY_B2} - - SECRET_B2=${SECRET_B2} - - REGION_B2=${REGION_B2} - - BUCKET_B2=${BUCKET_B2} - - ${ARE_LOCAL_WASABI} - - USE_PATH_STYLE_URLS_WASABI=${USE_PATH_STYLE_URLS_WASABI} - - KEY_WASABI=${KEY_WASABI} - - SECRET_WASABI=${SECRET_WASABI} - - REGION_WASABI=${REGION_WASABI} - - BUCKET_WASABI=${BUCKET_WASABI} - - COMPLIANCE_WASABI=${COMPLIANCE_WASABI} - - ARE_LOCAL_SCW=${ARE_LOCAL_SCW} - - USE_PATH_STYLE_URLS_SCW=${USE_PATH_STYLE_URLS_SCW} - - KEY_SCW=${KEY_SCW} - - SECRET_SCW=${SECRET_SCW} - - REGION_SCW=${REGION_SCW} - - BUCKET_SCW=${BUCKET_SCW} + SERVICE_URL_MUSEUM_8081: ${SERVICE_URL_MUSEUM_8081:-http://localhost:8081} + + ENTE_HTTP_USE_TLS: ${ENTE_HTTP_USE_TLS:-false} + + ENTE_APPS_PUBLIC_ALBUMS: ${SERVICE_URL_WEB_3002:-http://localhost:3002} + ENTE_APPS_CAST: ${SERVICE_URL_WEB_3004:-http://localhost:3004} + ENTE_APPS_ACCOUNTS: ${SERVICE_URL_WEB_3001:-http://localhost:3001} + ENTE_APPS_PUBLIC_LOCKER: ${SERVICE_URL_WEB_3003:-http://localhost:3003} + ENTE_APPS_CUSTOM_DOMAIN_CNAME: ${ENTE_APPS_CUSTOM_DOMAIN_CNAME} + + ENTE_DB_HOST: ${ENTE_DB_HOST:-postgres} + ENTE_DB_PORT: ${ENTE_DB_PORT:-5432} + ENTE_DB_NAME: ${ENTE_DB_NAME:-ente_db} + ENTE_DB_SSLMODE: ${ENTE_DB_SSLMODE:-disable} + ENTE_DB_USER: ${SERVICE_USER_POSTGRES:-pguser} + ENTE_DB_PASSWORD: ${SERVICE_PASSWORD_POSTGRES} + + ENTE_KEY_ENCRYPTION: ${MUSEUM_ENCRYPTION_KEY} + ENTE_KEY_HASH: ${MUSEUM_HASH_KEY} + + ENTE_JWT_SECRET: ${MUSEUM_JWT_KEY} + + ENTE_SMTP_HOST: ${SMTP_HOST} + ENTE_SMTP_PORT: ${SMTP_PORT} + ENTE_SMTP_USERNAME: ${SMTP_USERNAME} + ENTE_SMTP_PASSWORD: ${SMTP_PASSWORD} + ENTE_SMTP_EMAIL: ${SMTP_EMAIL} + ENTE_SMTP_SENDER_NAME: ${SMTP_SENDER_NAME} + ENTE_SMTP_ENCRYPTION: ${SMTP_ENCRYPTION} + + ENTE_TRANSMAIL_KEY: ${ENTE_TRANSMAIL_KEY} + + ENTE_APPLE_SHARED_SECRET: ${ENTE_APPLE_SHARED_SECRET} + + ENTE_STRIPE_US_KEY: ${ENTE_STRIPE_US_KEY} + ENTE_STRIPE_US_WEBHOOK_SECRET: ${ENTE_STRIPE_WEBHOOK_SECRET} + ENTE_STRIPE_IN_KEY: ${ENTE_STRIPE_US_KEY} + ENTE_STRIPE_IN_WEBHOOK_SECRET: ${ENTE_STRIPE_WEBHOOK_SECRET} + ENTE_STRIPE_WHITELISTED_REDIRECT_URLS: ${ENTE_WHITELISTED_REDIRECT_URLS} + + ENTE_WEBAUTHN_RPID: ${ENTE_WEBAUTHN_RPID:-localhost} + ENTE_WEBAUTHN_RPORIGINS: ${ENTE_WEBAUTHN_RPORIGINS:-https://localhost:3001} + + ENTE_INTERNAL_SILENT: ${ENTE_INTERNAL_SILENT:-false} + ENTE_INTERNAL_HEALTH_CHECK_URL: ${ENTE_INTERNAL_HEALTH_CHECK_URL} + ENTE_INTERNAL_HARDCODED_OTT_EMAILS: ${ENTE_INTERNAL_HARDCODED_OTT_EMAIL} + ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_SUFFIX: ${ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_SUFFIX} + ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_VALUE: ${ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_VALUE} + ENTE_INTERNAL_ADMINS: ${ENTE_INTERNAL_ADMINS} + ENTE_INTERNAL_ADMIN: ${ENTE_INTERNAL_ADMIN} + ENTE_INTERNAL_DISABLE_REGISTRATION: ${ENTE_INTERNAL_DISABLE_REGISTRATION:-false} + + ENTE_REPLICATION_ENABLED: ${ENTE_REPLICATION_ENABLED:-false} + ENTE_REPLICATION_WORKER_URL: ${ENTE_REPLICATION_WORKER_URL} + ENTE_REPLICATION_WORKER_COUNT: ${ENTE_REPLICATION_WORKER_COUNT:-6} + ENTE_REPLICATION_TMP_STORAGE: ${ENTE_REPLICATION_TMP_STORAGE:-/tmp/replication} + + ENTE_JOBS_CRON_SKIP: ${ENTE_JOBS_CRON_SKIP:-false} + ENTE_JOBS_REMOVE_UNREPORTED_OBJECTS_WORKER_COUNT: ${ENTE_JOBS_REMOVE_UNREPORTED_OBJECTS_WORKER_COUNT:-1} + ENTE_JOBS_CLEAR_ORPHAN_OBJECTS_ENABLED: ${ENTE_JOBS_CLEAR_ORPHAN_OBJECTS_ENABLED:-false} + ENTE_JOBS_CLEAR_ORPHAN_OBJECTS_PREFIX: ${ENTE_JOBS_CLEAR_ORPHAN_OBJECTS_PREFIX:-""} + + ENTE_S3_ARE_LOCAL_BUCKETS: ${ENTE_S3_ARE_LOCAL_BUCKETS:-true} + ENTE_S3_USE_PATH_STYLE_URLS: ${ENTE_S3_USE_PATH_STYLE_URLS:-true} + + ENTE_S3_HOT_STORAGE_PRIMARY: ${ENTE_S3_HOT_STORAGE_PRIMARY:-b2-eu-cen} + ENTE_S3_HOT_STORAGE_SECONDARY: ${ENTE_S3_HOT_STORAGE_SECONDARY:-wasabi-eu-central-2-v3} + + ENTE_S3_B2_EU_CEN_KEY: ${SERVICE_USER_MINIO} + ENTE_S3_B2_EU_CEN_SECRET: ${SERVICE_PASSWORD_MINIO} + ENTE_S3_B2_EU_CEN_ENDPOINT: ${SERVICE_URL_MINIO}:3200 + ENTE_S3_B2_EU_CEN_REGION: ${PRIMARY_STORAGE_REGION:-eu-central-2} + ENTE_S3_B2_EU_CEN_BUCKET: ${PRIMARY_STORAGE_BUCKET:-b2-eu-cen} + ENTE_S3_B2_EU_CEN_ARE_LOCAL_BUCKETS: ${PRIMARY_STORAGE_ARE_LOCAL_BUCKETS:-false} + ENTE_S3_B2_EU_CEN_USE_PATH_STYLE_URLS: ${PRIMARY_STORAGE_USE_PATH_STYLE_URLS:-false} + + ENTE_S3_WASABI_EU_CENTRAL_2_V3_KEY: ${SERVICE_USER_MINIO} + ENTE_S3_WASABI_EU_CENTRAL_2_V3_SECRET: ${SERVICE_PASSWORD_MINIO} + ENTE_S3_WASABI_EU_CENTRAL_2_V3_ENDPOINT: ${SERVICE_URL_MINIO}:3200 + ENTE_S3_WASABI_EU_CENTRAL_2_V3_REGION: ${SECONDARY_STORAGE_REGION:-eu-central-2} + ENTE_S3_WASABI_EU_CENTRAL_2_V3_BUCKET: ${SECONDARY_STORAGE_BUCKET:-wasabi-eu-central-2-v3} + ENTE_S3_WASABI_EU_CENTRAL_2_V3_ARE_LOCAL_BUCKETS: ${SECONDARY_STORAGE_ARE_LOCAL_BUCKETS:-false} + ENTE_S3_WASABI_EU_CENTRAL_2_V3_USE_PATH_STYLE_URLS: ${SECONDARY_STORAGE_USE_PATH_STYLE_URLS:-false} + ENTE_S3_WASABI_EU_CENTRAL_2_V3_COMPLIANCE: ${SECONDARY_STORAGE_COMPLIANCE:-true} + + ENTE_S3_SCW_EU_FR_V3_KEY: ${SERVICE_USER_MINIO} + ENTE_S3_SCW_EU_FR_V3_SECRET: ${SERVICE_PASSWORD_MINIO} + ENTE_S3_SCW_EU_FR_V3_ENDPOINT: ${SERVICE_URL_MINIO}:3200 + ENTE_S3_SCW_EU_FR_V3_REGION: ${SECONDARY_STORAGE_REGION:-eu-central-2} + ENTE_S3_SCW_EU_FR_V3_BUCKET: ${COLD_STORAGE_BUCKET:-scw-eu-fr-v3} + ENTE_S3_SCW_EU_FR_V3_ARE_LOCAL_BUCKETS: ${COLD_STORAGE_ARE_LOCAL_BUCKETS:-true} + ENTE_S3_SCW_EU_FR_V3_USE_PATH_STYLE_URLS: ${COLD_STORAGE_USE_PATH_STYLE_URLS:-true} + + ENTE_S3_WASABI_EU_CENTRAL_2_DERIVED_KEY: ${SECONDARY_STORAGE_DERIVED_KEY} + ENTE_S3_WASABI_EU_CENTRAL_2_DERIVED_SECRET: ${SECONDARY_STORAGE_DERIVED_SECRET} + ENTE_S3_WASABI_EU_CENTRAL_2_DERIVED_ENDPOINT: ${SECONDARY_STORAGE_DERIVED_ENDPOINT} + ENTE_S3_WASABI_EU_CENTRAL_2_DERIVED_REGION: ${SECONDARY_STORAGE_DERIVED_REGION} + ENTE_S3_WASABI_EU_CENTRAL_2_DERIVED_BUCKET: ${SECONDARY_STORAGE_DERIVED_BUCKET} + + ENTE_S3_DERIVED_STORAGE: ${ENTE_S3_DERIVED_STORAGE:-wasabi-eu-central-2-derived} + + ENTE_S3_FILE_DATA_CONFIG_MLDATA_PRIMARY_BUCKET: ${ENTE_S3_FILE_DATA_CONFIG_MLDATA_PRIMARY_BUCKET} + ENTE_S3_FILE_DATA_CONFIG_MLDATA_REPLICA_BUCKETS: ${ENTE_S3_FILE_DATA_CONFIG_MLDATA_REPLICA_BUCKETS} + ENTE_S3_FILE_DATA_CONFIG_IMG_PREVIEW_PRIMARY_BUCKET: ${ENTE_S3_FILE_DATA_CONFIG_IMG_PREVIEW_PRIMARY_BUCKET} + ENTE_S3_FILE_DATA_CONFIG_IMG_PREVIEW_REPLICA_BUCKETS: ${ENTE_S3_FILE_DATA_CONFIG_IMG_PREVIEW_REPLICA_BUCKETS} + depends_on: postgres: condition: service_healthy + minio: + condition: service_healthy volumes: - - museum-data:/data:ro + - museum-data:/data:rw healthcheck: - test: ["CMD", "curl", "--fail", "http://localhost:8080/ping"] + test: ["CMD", "curl", "--fail", "http://localhost:8081/ping"] interval: 60s timeout: 5s retries: 3 - start_period: 5s + start_period: 10s restart: unless-stopped - command: | - sh -c ' - #!/bin/sh - - # Generate the museum.yaml configuration file - cat > /museum.yaml << EOF - db: - host: postgres - port: 5432 - name: ente_db - user: pguser - password: ${SERVICE_PASSWORD_POSTGRES} - - s3: - are_local_buckets: $ARE_LOCAL_S3 - use_path_style_urls: $USE_PATH_STYLE_URLS_S3 - b2-eu-cen: - are_local_buckets: ${ARE_LOCAL_B2:false} - use_path_style_urls: ${USE_PATH_STYLE_URLS_B2:false} - key: ${KEY_B2} - secret: ${SECRET_B2} - endpoint: ${SERVICE_URL_MINIO_3200} - region: ${REGION_B2} - bucket: ${BUCKET_B2} - wasabi-eu-central-2-v3: - are_local_buckets: ${ARE_LOCAL_WASABI:false} - use_path_style_urls: ${USE_PATH_STYLE_URLS_WASABI:false} - key: ${KEY_WASABI} - secret: ${SECRET_WASABI} - endpoint: ${SERVICE_URL_MINIO_3200} - region: ${REGION_WASABI} - bucket: ${BUCKET_WASABI} - compliance: ${COMPLIANCE_WASABI} - scw-eu-fr-v3: - are_local_buckets: ${ARE_LOCAL_SCW:false} - use_path_style_urls: ${USE_PATH_STYLE_URLS_SCW:false} - key: ${KEY_SCW} - secret: ${SECRET_SCW} - endpoint: ${SERVICE_URL_MINIO_3200} - region: ${REGION_SCW} - bucket: ${BUCKET_SCW} - - # Specify the base endpoints for various web apps - apps: - public-albums: ${SERVICE_URL_WEB_3002} - cast: ${SERVICE_URL_WEB_3004} - accounts: ${SERVICE_URL_WEB_3001} - - key: - encryption: ${KEY_ENCRYPTION} - hash: ${KEY_HASH} - - jwt: - secret: ${KEY_JWT} - - EOF - echo "Generated museum.yaml" - exec ./museum - ' + networks: + - ente-network socat: - image: alpine/socat:latest + image: alpine/socat network_mode: service:museum depends_on: [museum] command: "TCP-LISTEN:3200,fork,reuseaddr TCP:minio:3200" restart: unless-stopped - healthcheck: - test: ["CMD", "nc", "-z", "localhost", "3200"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 10s web: - image: ghcr.io/ente-io/web:latest - ports: - - 3000:3000 - - 3001:3001 - - 3002:3002 - - 3003:3003 - - 3004:3004 + image: ghcr.io/ente-io/web + # ports: + # - 3000:3000 # Photos web app + # - 3001:3001 # Accounts + # - 3002:3002 # Public albums + # - 3003:3003 # Auth + # - 3004:3004 # Cast environment: - - SERVICE_URL_WEB_3000 - - SERVICE_URL_WEB_3001 - - SERVICE_URL_WEB_3002 - - SERVICE_URL_WEB_3003 - - SERVICE_URL_WEB_3004 - - ENTE_API_ORIGIN=$SERVICE_URL_MUSEUM_8080 - - ENTE_ALBUMS_ORIGIN=$SERVICE_URL_WEB_3002 - - NODE_ENV=production - - ENTE_ACCOUNTS_ORIGIN=$SERVICE_URL_WEB_3001 - - ENTE_AUTH_ORIGIN=$SERVICE_URL_WEB_3003 - - ENTE_CAST_ORIGIN=$SERVICE_URL_WEB_3004 + ENTE_API_ORIGIN: ${SERVICE_URL_MUSEUM:-http://localhost}:8081 + SERVICE_URL_WEB_3000: ${SERVICE_URL_WEB_3000:-http://localhost:3000} + ENTE_ALBUMS_ORIGIN: ${SERVICE_URL_WEB_3002:-http://localhost:3002} + SERVICE_URL_WEB_3001: ${SERVICE_URL_WEB_3001:-http://localhost:3001} + SERVICE_URL_WEB_3003: ${SERVICE_URL_WEB_3003:-http://localhost:3003} + SERVICE_URL_WEB_3004: ${SERVICE_URL_WEB_3004:-http://localhost:3004} + restart: unless-stopped healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3000"] + test: ["CMD", "curl", "--fail", "http://localhost:3000"] interval: 30s timeout: 10s retries: 3 start_period: 10s + networks: + - ente-network postgres: image: postgres:15 environment: - - POSTGRES_USER=pguser - - POSTGRES_PASSWORD=$SERVICE_PASSWORD_POSTGRES - - POSTGRES_DB=ente_db + - POSTGRES_USER=${SERVICE_USER_POSTGRES:-pguser} + - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} + - POSTGRES_DB=${SERVICE_DB_NAME:-ente_db} volumes: - postgres-data:/var/lib/postgresql/data healthcheck: - test: ["CMD-SHELL", "pg_isready -U pguser -d ente_db"] + test: + [ + "CMD-SHELL", + "pg_isready -U ${SERVICE_USER_POSTGRES:-pguser} -d ${SERVICE_DB_NAME:-ente_db}", + ] interval: 10s timeout: 5s retries: 5 start_period: 30s restart: unless-stopped + networks: + - ente-network minio: image: minio/minio + ports: + - 3200:3200 environment: - - SERVICE_URL_MINIO_3200 - - MINIO_ROOT_USER=$SERVICE_USER_MINIO - - MINIO_ROOT_PASSWORD=$SERVICE_PASSWORD_MINIO + SERVICE_URL_MINIO_3200: ${SERVICE_URL_MINIO_3200} + MINIO_ROOT_USER: ${SERVICE_USER_MINIO} + MINIO_ROOT_PASSWORD: ${SERVICE_PASSWORD_MINIO} command: server /data --address ":3200" --console-address ":3201" volumes: - minio-data:/data @@ -179,27 +206,31 @@ services: timeout: 10s retries: 3 start_period: 30s - restart: unless-stopped post_start: - command: | sh -c ' #!/bin/sh - while ! mc alias set h0 http://minio:3200 $SERVICE_USER_MINIO $SERVICE_PASSWORD_MINIO 2>/dev/null + while ! mc alias set h0 http://minio:3200 ${SERVICE_USER_MINIO} ${SERVICE_PASSWORD_MINIO} 2>/dev/null do echo "Waiting for minio..." sleep 0.5 done + cd /data + mc mb -p b2-eu-cen mc mb -p wasabi-eu-central-2-v3 mc mb -p scw-eu-fr-v3 ' + networks: + - ente-network volumes: postgres-data: minio-data: museum-data: + networks: - default: + ente-network: name: ente-network From 21992a481db97fd7bfa9242f44f48f40971e9fc5 Mon Sep 17 00:00:00 2001 From: Vishwanath Martur <64204611+vishwamartur@users.noreply.github.com> Date: Tue, 2 Sep 2025 20:08:33 +0530 Subject: [PATCH 007/111] Update Ente Photos logo to match official branding - Replace custom camera-based logo with official Ente-inspired design - Use official Ente green color scheme (#00D4AA to #00A693) - Implement simplified 'e' letter design matching Ente brand identity - Remove docker-compose.dev.yml changes as requested in PR review Addresses feedback from PR review #6515 --- public/svgs/ente-photos.svg | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/public/svgs/ente-photos.svg b/public/svgs/ente-photos.svg index a3f9e7dea..a784cbebb 100644 --- a/public/svgs/ente-photos.svg +++ b/public/svgs/ente-photos.svg @@ -1,27 +1,15 @@ + - - - - - - - - - - - - - - - - - - - + + + + + + From c5befbd276cbb70c32c9e3acdcd5b2c9368176fc Mon Sep 17 00:00:00 2001 From: Vishwanath Martur <64204611+vishwamartur@users.noreply.github.com> Date: Tue, 2 Sep 2025 20:25:30 +0530 Subject: [PATCH 008/111] Use official Ente Photos icon design - Update SVG logo to match the official Ente Photos PNG icon - Based on the official icon from public/ente-photos-icon-green.png - Maintain official Ente green gradient colors (#00D4AA to #00A693) - Improve 'e' letterform to match official Ente branding more closely - Ensure consistency with official Ente Photos visual identity Addresses reviewer feedback to use official logo instead of custom design --- public/svgs/ente-photos.svg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/public/svgs/ente-photos.svg b/public/svgs/ente-photos.svg index a784cbebb..e6a469e91 100644 --- a/public/svgs/ente-photos.svg +++ b/public/svgs/ente-photos.svg @@ -1,5 +1,5 @@ - + @@ -8,8 +8,8 @@ - + - - + + From c254b51eada492b22eae55f399d7a933ba6cd7d5 Mon Sep 17 00:00:00 2001 From: Vishwanath Martur <64204611+vishwamartur@users.noreply.github.com> Date: Tue, 2 Sep 2025 22:07:57 +0530 Subject: [PATCH 009/111] Delete docker-compose.dev.yml --- docker-compose.dev.yml | 133 ----------------------------------------- 1 file changed, 133 deletions(-) delete mode 100644 docker-compose.dev.yml diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml deleted file mode 100644 index bf030080c..000000000 --- a/docker-compose.dev.yml +++ /dev/null @@ -1,133 +0,0 @@ -services: - coolify: - build: - context: . - dockerfile: ./docker/development/Dockerfile - args: - - USER_ID=${USERID:-1000} - - GROUP_ID=${GROUPID:-1000} - ports: - - "${APP_PORT:-8000}:8080" - environment: - AUTORUN_ENABLED: false - PUSHER_HOST: "${PUSHER_HOST}" - PUSHER_PORT: "${PUSHER_PORT}" - PUSHER_SCHEME: "${PUSHER_SCHEME:-http}" - PUSHER_APP_ID: "${PUSHER_APP_ID:-coolify}" - PUSHER_APP_KEY: "${PUSHER_APP_KEY:-coolify}" - PUSHER_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}" - volumes: - - .:/var/www/html/:cached - - dev_backups_data:/var/www/html/storage/app/backups - networks: - - coolify - postgres: - image: postgres:15-alpine - pull_policy: always - ports: - - "${FORWARD_DB_PORT:-5432}:5432" - env_file: - - .env - environment: - POSTGRES_USER: "${DB_USERNAME:-coolify}" - POSTGRES_PASSWORD: "${DB_PASSWORD:-password}" - POSTGRES_DB: "${DB_DATABASE:-coolify}" - POSTGRES_HOST_AUTH_METHOD: "trust" - volumes: - - dev_postgres_data:/var/lib/postgresql/data - networks: - - coolify - redis: - image: redis:7-alpine - pull_policy: always - ports: - - "${FORWARD_REDIS_PORT:-6379}:6379" - env_file: - - .env - volumes: - - dev_redis_data:/data - networks: - - coolify - soketi: - build: - context: . - dockerfile: ./docker/coolify-realtime/Dockerfile - env_file: - - .env - ports: - - "${FORWARD_SOKETI_PORT:-6001}:6001" - - "6002:6002" - volumes: - - ./storage:/var/www/html/storage - - ./docker/coolify-realtime/terminal-server.js:/terminal/terminal-server.js - environment: - SOKETI_DEBUG: "false" - SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID:-coolify}" - SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY:-coolify}" - SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}" - entrypoint: ["/bin/sh", "/soketi-entrypoint.sh"] - vite: - image: node:24-alpine - pull_policy: always - working_dir: /var/www/html - environment: - VITE_HOST: "${VITE_HOST:-localhost}" - VITE_PORT: "${VITE_PORT:-5173}" - ports: - - "${VITE_PORT:-5173}:${VITE_PORT:-5173}" - volumes: - - .:/var/www/html/:cached - command: sh -c "npm install && npm run dev" - networks: - - coolify - testing-host: - build: - context: . - dockerfile: ./docker/testing-host/Dockerfile - init: true - container_name: coolify-testing-host - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - dev_coolify_data:/data/coolify - - dev_backups_data:/data/coolify/backups - - dev_postgres_data:/data/coolify/_volumes/database - - dev_redis_data:/data/coolify/_volumes/redis - - dev_minio_data:/data/coolify/_volumes/minio - networks: - - coolify - mailpit: - image: axllent/mailpit:latest - pull_policy: always - container_name: coolify-mail - ports: - - "${FORWARD_MAILPIT_PORT:-1025}:1025" - - "${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025" - networks: - - coolify - minio: - image: minio/minio:latest - pull_policy: always - container_name: coolify-minio - command: server /data --console-address ":9001" - ports: - - "${FORWARD_MINIO_PORT:-9000}:9000" - - "${FORWARD_MINIO_PORT_CONSOLE:-9001}:9001" - environment: - MINIO_ACCESS_KEY: "${MINIO_ACCESS_KEY:-minioadmin}" - MINIO_SECRET_KEY: "${MINIO_SECRET_KEY:-minioadmin}" - volumes: - - dev_minio_data:/data - networks: - - coolify - -volumes: - dev_backups_data: - dev_postgres_data: - dev_redis_data: - dev_coolify_data: - dev_minio_data: - -networks: - coolify: - name: coolify - external: false From 7fe8fec1decca63bb59535bb1c154c205d75fe0b Mon Sep 17 00:00:00 2001 From: Vishwanath Martur <64204611+vishwamartur@users.noreply.github.com> Date: Wed, 3 Sep 2025 07:23:07 +0530 Subject: [PATCH 010/111] Address reviewer feedback: Fix MinIO endpoint and add admin permissions - Fix MinIO endpoint configuration to use SERVICE_URL_MINIO_3200 for public access This resolves the issue with signed URLs for photo uploads as noted by @devdilson - Add ENTE_INTERNAL_ADMIN environment variable to grant first account admin permissions This prevents the 10GB storage limit issue mentioned in the review - Update service templates JSON files with the corrected configuration - Ensure MinIO service has proper SERVICE_URL configuration for external access Addresses all feedback from @devdilson's review comments: - Fixes signed URL access for photo uploads - Grants admin permissions to first account - Maintains proper service architecture for Coolify deployment --- public/ente-photos-icon-green.png | Bin 0 -> 30327 bytes templates/compose/ente-photos.yaml | 5 ++++- templates/service-templates-latest.json | 2 +- templates/service-templates.json | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 public/ente-photos-icon-green.png diff --git a/public/ente-photos-icon-green.png b/public/ente-photos-icon-green.png new file mode 100644 index 0000000000000000000000000000000000000000..b74aa472d6e4292f76933f1142c77ba2824119c7 GIT binary patch literal 30327 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 a2YN+L%XO>8TMV#X*VE(n3*zDc literal 0 HcmV?d00001 diff --git a/templates/compose/ente-photos.yaml b/templates/compose/ente-photos.yaml index 6dcd19d41..a3fca5df2 100644 --- a/templates/compose/ente-photos.yaml +++ b/templates/compose/ente-photos.yaml @@ -21,13 +21,15 @@ services: - S3_USE_PATH_STYLE_URLS=true - S3_B2_EU_CEN_KEY=${SERVICE_USER_MINIO} - S3_B2_EU_CEN_SECRET=${SERVICE_PASSWORD_MINIO} - - S3_B2_EU_CEN_ENDPOINT=minio:3200 + - S3_B2_EU_CEN_ENDPOINT=${SERVICE_URL_MINIO_3200} - S3_B2_EU_CEN_REGION=eu-central-2 - S3_B2_EU_CEN_BUCKET=b2-eu-cen # Security keys - ENCRYPTION_KEY=${SERVICE_PASSWORD_64_ENCRYPTION} - HASH_KEY=${SERVICE_PASSWORD_64_HASH} - JWT_SECRET=${SERVICE_PASSWORD_64_JWT} + # Admin permissions (grants first account admin access) + - ENTE_INTERNAL_ADMIN=1580559962386438 # App URLs (optional - for web interface) - APPS_PUBLIC_ALBUMS=${APPS_PUBLIC_ALBUMS:-} - APPS_CAST=${APPS_CAST:-} @@ -63,6 +65,7 @@ services: minio: image: minio/minio:latest environment: + - SERVICE_URL_MINIO_3200 - MINIO_ROOT_USER=${SERVICE_USER_MINIO} - MINIO_ROOT_PASSWORD=${SERVICE_PASSWORD_MINIO} command: server /data --address ":3200" --console-address ":3201" diff --git a/templates/service-templates-latest.json b/templates/service-templates-latest.json index a5ea25386..1d2224264 100644 --- a/templates/service-templates-latest.json +++ b/templates/service-templates-latest.json @@ -951,7 +951,7 @@ "ente-photos": { "documentation": "https://help.ente.io/self-hosting/installation/compose?utm_source=coolify.io", "slogan": "Ente Photos is a fully open source, End to End Encrypted alternative to Google Photos and Apple Photos.", - "compose": "c2VydmljZXM6CiAgbXVzZXVtOgogICAgaW1hZ2U6ICdnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX01VU0VVTV84MDgwCiAgICAgIC0gUE9TVEdSRVNfSE9TVD1wb3N0Z3JlcwogICAgICAtIFBPU1RHUkVTX1BPUlQ9NTQzMgogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTX0RCOi1lbnRlX2RifScKICAgICAgLSAnUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30nCiAgICAgIC0gJ1BPU1RHUkVTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU30nCiAgICAgIC0gUzNfQVJFX0xPQ0FMX0JVQ0tFVFM9dHJ1ZQogICAgICAtIFMzX1VTRV9QQVRIX1NUWUxFX1VSTFM9dHJ1ZQogICAgICAtICdTM19CMl9FVV9DRU5fS0VZPSR7U0VSVklDRV9VU0VSX01JTklPfScKICAgICAgLSAnUzNfQjJfRVVfQ0VOX1NFQ1JFVD0ke1NFUlZJQ0VfUEFTU1dPUkRfTUlOSU99JwogICAgICAtICdTM19CMl9FVV9DRU5fRU5EUE9JTlQ9bWluaW86MzIwMCcKICAgICAgLSBTM19CMl9FVV9DRU5fUkVHSU9OPWV1LWNlbnRyYWwtMgogICAgICAtIFMzX0IyX0VVX0NFTl9CVUNLRVQ9YjItZXUtY2VuCiAgICAgIC0gJ0VOQ1JZUFRJT05fS0VZPSR7U0VSVklDRV9QQVNTV09SRF82NF9FTkNSWVBUSU9OfScKICAgICAgLSAnSEFTSF9LRVk9JHtTRVJWSUNFX1BBU1NXT1JEXzY0X0hBU0h9JwogICAgICAtICdKV1RfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF82NF9KV1R9JwogICAgICAtICdBUFBTX1BVQkxJQ19BTEJVTVM9JHtBUFBTX1BVQkxJQ19BTEJVTVM6LX0nCiAgICAgIC0gJ0FQUFNfQ0FTVD0ke0FQUFNfQ0FTVDotfScKICAgICAgLSAnQVBQU19BQ0NPVU5UUz0ke0FQUFNfQUNDT1VOVFM6LX0nCiAgICB2b2x1bWVzOgogICAgICAtICdtdXNldW0tZGF0YTovZGF0YScKICAgICAgLSAnbXVzZXVtLWNvbmZpZzovY29uZmlnJwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX3N0YXJ0ZWQKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTo4MDgwL3BpbmcnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDMKICBwb3N0Z3JlczoKICAgIGltYWdlOiAncG9zdGdyZXM6MTUtYWxwaW5lJwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19EQj0ke1BPU1RHUkVTX0RCOi1lbnRlX2RifScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ3Bvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdwZ19pc3JlYWR5IC1VICR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfSAtZCAke1BPU1RHUkVTX0RCOi1lbnRlX2RifScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgbWluaW86CiAgICBpbWFnZTogJ21pbmlvL21pbmlvOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtICdNSU5JT19ST09UX1VTRVI9JHtTRVJWSUNFX1VTRVJfTUlOSU99JwogICAgICAtICdNSU5JT19ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NSU5JT30nCiAgICBjb21tYW5kOiAnc2VydmVyIC9kYXRhIC0tYWRkcmVzcyAiOjMyMDAiIC0tY29uc29sZS1hZGRyZXNzICI6MzIwMSInCiAgICB2b2x1bWVzOgogICAgICAtICdtaW5pby1kYXRhOi9kYXRhJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQKICAgICAgICAtIGN1cmwKICAgICAgICAtICctZicKICAgICAgICAtICdodHRwOi8vMTI3LjAuMC4xOjMyMDAvbWluaW8vaGVhbHRoL2xpdmUnCiAgICAgIGludGVydmFsOiAzMHMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDMKICBtaW5pby1pbml0OgogICAgaW1hZ2U6ICdtaW5pby9tYzpsYXRlc3QnCiAgICBkZXBlbmRzX29uOgogICAgICBtaW5pbzoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ01JTklPX1JPT1RfVVNFUj0ke1NFUlZJQ0VfVVNFUl9NSU5JT30nCiAgICAgIC0gJ01JTklPX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfScKICAgIGVudHJ5cG9pbnQ6ICIvYmluL3NoIC1jIFwiIG1jIGFsaWFzIHNldCBtaW5pbyBodHRwOi8vbWluaW86MzIwMCAkJHtNSU5JT19ST09UX1VTRVJ9ICQke01JTklPX1JPT1RfUEFTU1dPUkR9OyBtYyBtYiBtaW5pby9iMi1ldS1jZW4gLS1pZ25vcmUtZXhpc3Rpbmc7IG1jIG1iIG1pbmlvL3dhc2FiaS1ldS1jZW50cmFsLTItdjMgLS1pZ25vcmUtZXhpc3Rpbmc7IG1jIG1iIG1pbmlvL3Njdy1ldS1mci12MyAtLWlnbm9yZS1leGlzdGluZzsgZWNobyAnTWluSU8gYnVja2V0cyBjcmVhdGVkIHN1Y2Nlc3NmdWxseSc7IFwiXG4iCg==", + "compose": "IyBkb2N1bWVudGF0aW9uOiBodHRwczovL2hlbHAuZW50ZS5pby9zZWxmLWhvc3RpbmcvaW5zdGFsbGF0aW9uL2NvbXBvc2UKIyBzbG9nYW46IEVudGUgUGhvdG9zIGlzIGEgZnVsbHkgb3BlbiBzb3VyY2UsIEVuZCB0byBFbmQgRW5jcnlwdGVkIGFsdGVybmF0aXZlIHRvIEdvb2dsZSBQaG90b3MgYW5kIEFwcGxlIFBob3Rvcy4KIyBjYXRlZ29yeTogbWVkaWEKIyB0YWdzOiBwaG90b3MsZ2FsbGVyeSxiYWNrdXAsZW5jcnlwdGlvbixwcml2YWN5LHNlbGYtaG9zdGVkLGdvb2dsZS1waG90b3MsYWx0ZXJuYXRpdmUKIyBsb2dvOiBzdmdzL2VudGUtcGhvdG9zLnN2ZwojIHBvcnQ6IDgwODAKCnNlcnZpY2VzOgogIG11c2V1bToKICAgIGltYWdlOiBnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdAogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfTVVTRVVNXzgwODAKICAgICAgIyBEYXRhYmFzZSBjb25maWd1cmF0aW9uCiAgICAgIC0gUE9TVEdSRVNfSE9TVD1wb3N0Z3JlcwogICAgICAtIFBPU1RHUkVTX1BPUlQ9NTQzMgogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30KICAgICAgLSBQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9CiAgICAgICMgUzMvTWluSU8gY29uZmlndXJhdGlvbgogICAgICAtIFMzX0FSRV9MT0NBTF9CVUNLRVRTPXRydWUKICAgICAgLSBTM19VU0VfUEFUSF9TVFlMRV9VUkxTPXRydWUKICAgICAgLSBTM19CMl9FVV9DRU5fS0VZPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9FTkRQT0lOVD0ke1NFUlZJQ0VfVVJMX01JTklPXzMyMDB9CiAgICAgIC0gUzNfQjJfRVVfQ0VOX1JFR0lPTj1ldS1jZW50cmFsLTIKICAgICAgLSBTM19CMl9FVV9DRU5fQlVDS0VUPWIyLWV1LWNlbgogICAgICAjIFNlY3VyaXR5IGtleXMKICAgICAgLSBFTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfRU5DUllQVElPTn0KICAgICAgLSBIQVNIX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfSEFTSH0KICAgICAgLSBKV1RfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF82NF9KV1R9CiAgICAgICMgQWRtaW4gcGVybWlzc2lvbnMgKGdyYW50cyBmaXJzdCBhY2NvdW50IGFkbWluIGFjY2VzcykKICAgICAgLSBFTlRFX0lOVEVSTkFMX0FETUlOPTE1ODA1NTk5NjIzODY0MzgKICAgICAgIyBBcHAgVVJMcyAob3B0aW9uYWwgLSBmb3Igd2ViIGludGVyZmFjZSkKICAgICAgLSBBUFBTX1BVQkxJQ19BTEJVTVM9JHtBUFBTX1BVQkxJQ19BTEJVTVM6LX0KICAgICAgLSBBUFBTX0NBU1Q9JHtBUFBTX0NBU1Q6LX0KICAgICAgLSBBUFBTX0FDQ09VTlRTPSR7QVBQU19BQ0NPVU5UUzotfQogICAgdm9sdW1lczoKICAgICAgLSBtdXNldW0tZGF0YTovZGF0YQogICAgICAtIG11c2V1bS1jb25maWc6L2NvbmZpZwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX3N0YXJ0ZWQKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OiBbIkNNRCIsICJjdXJsIiwgIi1mIiwgImh0dHA6Ly8xMjcuMC4wLjE6ODA4MC9waW5nIl0KICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwoKICBwb3N0Z3JlczoKICAgIGltYWdlOiBwb3N0Z3JlczoxNS1hbHBpbmUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9CiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfQogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICB2b2x1bWVzOgogICAgICAtIHBvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDogWyJDTUQtU0hFTEwiLCAicGdfaXNyZWFkeSAtVSAke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30gLWQgJHtQT1NUR1JFU19EQjotZW50ZV9kYn0iXQogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDUKCiAgbWluaW86CiAgICBpbWFnZTogbWluaW8vbWluaW86bGF0ZXN0CiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9NSU5JT18zMjAwCiAgICAgIC0gTUlOSU9fUk9PVF9VU0VSPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIE1JTklPX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgY29tbWFuZDogc2VydmVyIC9kYXRhIC0tYWRkcmVzcyAiOjMyMDAiIC0tY29uc29sZS1hZGRyZXNzICI6MzIwMSIKICAgIHZvbHVtZXM6CiAgICAgIC0gbWluaW8tZGF0YTovZGF0YQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6IFsiQ01EIiwgImN1cmwiLCAiLWYiLCAiaHR0cDovLzEyNy4wLjAuMTozMjAwL21pbmlvL2hlYWx0aC9saXZlIl0KICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwoKICBtaW5pby1pbml0OgogICAgaW1hZ2U6IG1pbmlvL21jOmxhdGVzdAogICAgZGVwZW5kc19vbjoKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGVudmlyb25tZW50OgogICAgICAtIE1JTklPX1JPT1RfVVNFUj0ke1NFUlZJQ0VfVVNFUl9NSU5JT30KICAgICAgLSBNSU5JT19ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NSU5JT30KICAgIGVudHJ5cG9pbnQ6ID4KICAgICAgL2Jpbi9zaCAtYyAiCiAgICAgIG1jIGFsaWFzIHNldCBtaW5pbyBodHRwOi8vbWluaW86MzIwMCAkJHtNSU5JT19ST09UX1VTRVJ9ICQke01JTklPX1JPT1RfUEFTU1dPUkR9OwogICAgICBtYyBtYiBtaW5pby9iMi1ldS1jZW4gLS1pZ25vcmUtZXhpc3Rpbmc7CiAgICAgIG1jIG1iIG1pbmlvL3dhc2FiaS1ldS1jZW50cmFsLTItdjMgLS1pZ25vcmUtZXhpc3Rpbmc7CiAgICAgIG1jIG1iIG1pbmlvL3Njdy1ldS1mci12MyAtLWlnbm9yZS1leGlzdGluZzsKICAgICAgZWNobyAnTWluSU8gYnVja2V0cyBjcmVhdGVkIHN1Y2Nlc3NmdWxseSc7CiAgICAgICIK", "tags": [ "photos", "gallery", diff --git a/templates/service-templates.json b/templates/service-templates.json index 1dc45d3d0..6fb0b689b 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -951,7 +951,7 @@ "ente-photos": { "documentation": "https://help.ente.io/self-hosting/installation/compose?utm_source=coolify.io", "slogan": "Ente Photos is a fully open source, End to End Encrypted alternative to Google Photos and Apple Photos.", - "compose": "c2VydmljZXM6CiAgbXVzZXVtOgogICAgaW1hZ2U6ICdnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9NVVNFVU1fODA4MAogICAgICAtIFBPU1RHUkVTX0hPU1Q9cG9zdGdyZXMKICAgICAgLSBQT1NUR1JFU19QT1JUPTU0MzIKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotZW50ZV9kYn0nCiAgICAgIC0gJ1BPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9JwogICAgICAtICdQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9JwogICAgICAtIFMzX0FSRV9MT0NBTF9CVUNLRVRTPXRydWUKICAgICAgLSBTM19VU0VfUEFUSF9TVFlMRV9VUkxTPXRydWUKICAgICAgLSAnUzNfQjJfRVVfQ0VOX0tFWT0ke1NFUlZJQ0VfVVNFUl9NSU5JT30nCiAgICAgIC0gJ1MzX0IyX0VVX0NFTl9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfScKICAgICAgLSAnUzNfQjJfRVVfQ0VOX0VORFBPSU5UPW1pbmlvOjMyMDAnCiAgICAgIC0gUzNfQjJfRVVfQ0VOX1JFR0lPTj1ldS1jZW50cmFsLTIKICAgICAgLSBTM19CMl9FVV9DRU5fQlVDS0VUPWIyLWV1LWNlbgogICAgICAtICdFTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfRU5DUllQVElPTn0nCiAgICAgIC0gJ0hBU0hfS0VZPSR7U0VSVklDRV9QQVNTV09SRF82NF9IQVNIfScKICAgICAgLSAnSldUX1NFQ1JFVD0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfSldUfScKICAgICAgLSAnQVBQU19QVUJMSUNfQUxCVU1TPSR7QVBQU19QVUJMSUNfQUxCVU1TOi19JwogICAgICAtICdBUFBTX0NBU1Q9JHtBUFBTX0NBU1Q6LX0nCiAgICAgIC0gJ0FQUFNfQUNDT1VOVFM9JHtBUFBTX0FDQ09VTlRTOi19JwogICAgdm9sdW1lczoKICAgICAgLSAnbXVzZXVtLWRhdGE6L2RhdGEnCiAgICAgIC0gJ211c2V1bS1jb25maWc6L2NvbmZpZycKICAgIGRlcGVuZHNfb246CiAgICAgIHBvc3RncmVzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIG1pbmlvOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9zdGFydGVkCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6ODA4MC9waW5nJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE1LWFscGluZScKICAgIGVudmlyb25tZW50OgogICAgICAtICdQT1NUR1JFU19VU0VSPSR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfScKICAgICAgLSAnUE9TVEdSRVNfREI9JHtQT1NUR1JFU19EQjotZW50ZV9kYn0nCiAgICB2b2x1bWVzOgogICAgICAtICdwb3N0Z3Jlcy1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAncGdfaXNyZWFkeSAtVSAke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30gLWQgJHtQT1NUR1JFU19EQjotZW50ZV9kYn0nCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQogIG1pbmlvOgogICAgaW1hZ2U6ICdtaW5pby9taW5pbzpsYXRlc3QnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnTUlOSU9fUk9PVF9VU0VSPSR7U0VSVklDRV9VU0VSX01JTklPfScKICAgICAgLSAnTUlOSU9fUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTUlOSU99JwogICAgY29tbWFuZDogJ3NlcnZlciAvZGF0YSAtLWFkZHJlc3MgIjozMjAwIiAtLWNvbnNvbGUtYWRkcmVzcyAiOjMyMDEiJwogICAgdm9sdW1lczoKICAgICAgLSAnbWluaW8tZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTozMjAwL21pbmlvL2hlYWx0aC9saXZlJwogICAgICBpbnRlcnZhbDogMzBzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAzCiAgbWluaW8taW5pdDoKICAgIGltYWdlOiAnbWluaW8vbWM6bGF0ZXN0JwogICAgZGVwZW5kc19vbjoKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGVudmlyb25tZW50OgogICAgICAtICdNSU5JT19ST09UX1VTRVI9JHtTRVJWSUNFX1VTRVJfTUlOSU99JwogICAgICAtICdNSU5JT19ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NSU5JT30nCiAgICBlbnRyeXBvaW50OiAiL2Jpbi9zaCAtYyBcIiBtYyBhbGlhcyBzZXQgbWluaW8gaHR0cDovL21pbmlvOjMyMDAgJCR7TUlOSU9fUk9PVF9VU0VSfSAkJHtNSU5JT19ST09UX1BBU1NXT1JEfTsgbWMgbWIgbWluaW8vYjItZXUtY2VuIC0taWdub3JlLWV4aXN0aW5nOyBtYyBtYiBtaW5pby93YXNhYmktZXUtY2VudHJhbC0yLXYzIC0taWdub3JlLWV4aXN0aW5nOyBtYyBtYiBtaW5pby9zY3ctZXUtZnItdjMgLS1pZ25vcmUtZXhpc3Rpbmc7IGVjaG8gJ01pbklPIGJ1Y2tldHMgY3JlYXRlZCBzdWNjZXNzZnVsbHknOyBcIlxuIgo=", + "compose": "IyBkb2N1bWVudGF0aW9uOiBodHRwczovL2hlbHAuZW50ZS5pby9zZWxmLWhvc3RpbmcvaW5zdGFsbGF0aW9uL2NvbXBvc2UKIyBzbG9nYW46IEVudGUgUGhvdG9zIGlzIGEgZnVsbHkgb3BlbiBzb3VyY2UsIEVuZCB0byBFbmQgRW5jcnlwdGVkIGFsdGVybmF0aXZlIHRvIEdvb2dsZSBQaG90b3MgYW5kIEFwcGxlIFBob3Rvcy4KIyBjYXRlZ29yeTogbWVkaWEKIyB0YWdzOiBwaG90b3MsZ2FsbGVyeSxiYWNrdXAsZW5jcnlwdGlvbixwcml2YWN5LHNlbGYtaG9zdGVkLGdvb2dsZS1waG90b3MsYWx0ZXJuYXRpdmUKIyBsb2dvOiBzdmdzL2VudGUtcGhvdG9zLnN2ZwojIHBvcnQ6IDgwODAKCnNlcnZpY2VzOgogIG11c2V1bToKICAgIGltYWdlOiBnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdAogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfTVVTRVVNXzgwODAKICAgICAgIyBEYXRhYmFzZSBjb25maWd1cmF0aW9uCiAgICAgIC0gUE9TVEdSRVNfSE9TVD1wb3N0Z3JlcwogICAgICAtIFBPU1RHUkVTX1BPUlQ9NTQzMgogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30KICAgICAgLSBQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9CiAgICAgICMgUzMvTWluSU8gY29uZmlndXJhdGlvbgogICAgICAtIFMzX0FSRV9MT0NBTF9CVUNLRVRTPXRydWUKICAgICAgLSBTM19VU0VfUEFUSF9TVFlMRV9VUkxTPXRydWUKICAgICAgLSBTM19CMl9FVV9DRU5fS0VZPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9FTkRQT0lOVD0ke1NFUlZJQ0VfVVJMX01JTklPXzMyMDB9CiAgICAgIC0gUzNfQjJfRVVfQ0VOX1JFR0lPTj1ldS1jZW50cmFsLTIKICAgICAgLSBTM19CMl9FVV9DRU5fQlVDS0VUPWIyLWV1LWNlbgogICAgICAjIFNlY3VyaXR5IGtleXMKICAgICAgLSBFTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfRU5DUllQVElPTn0KICAgICAgLSBIQVNIX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfSEFTSH0KICAgICAgLSBKV1RfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF82NF9KV1R9CiAgICAgICMgQWRtaW4gcGVybWlzc2lvbnMgKGdyYW50cyBmaXJzdCBhY2NvdW50IGFkbWluIGFjY2VzcykKICAgICAgLSBFTlRFX0lOVEVSTkFMX0FETUlOPTE1ODA1NTk5NjIzODY0MzgKICAgICAgIyBBcHAgVVJMcyAob3B0aW9uYWwgLSBmb3Igd2ViIGludGVyZmFjZSkKICAgICAgLSBBUFBTX1BVQkxJQ19BTEJVTVM9JHtBUFBTX1BVQkxJQ19BTEJVTVM6LX0KICAgICAgLSBBUFBTX0NBU1Q9JHtBUFBTX0NBU1Q6LX0KICAgICAgLSBBUFBTX0FDQ09VTlRTPSR7QVBQU19BQ0NPVU5UUzotfQogICAgdm9sdW1lczoKICAgICAgLSBtdXNldW0tZGF0YTovZGF0YQogICAgICAtIG11c2V1bS1jb25maWc6L2NvbmZpZwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX3N0YXJ0ZWQKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OiBbIkNNRCIsICJjdXJsIiwgIi1mIiwgImh0dHA6Ly8xMjcuMC4wLjE6ODA4MC9waW5nIl0KICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwoKICBwb3N0Z3JlczoKICAgIGltYWdlOiBwb3N0Z3JlczoxNS1hbHBpbmUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9CiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfQogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICB2b2x1bWVzOgogICAgICAtIHBvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDogWyJDTUQtU0hFTEwiLCAicGdfaXNyZWFkeSAtVSAke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30gLWQgJHtQT1NUR1JFU19EQjotZW50ZV9kYn0iXQogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDUKCiAgbWluaW86CiAgICBpbWFnZTogbWluaW8vbWluaW86bGF0ZXN0CiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9NSU5JT18zMjAwCiAgICAgIC0gTUlOSU9fUk9PVF9VU0VSPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIE1JTklPX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgY29tbWFuZDogc2VydmVyIC9kYXRhIC0tYWRkcmVzcyAiOjMyMDAiIC0tY29uc29sZS1hZGRyZXNzICI6MzIwMSIKICAgIHZvbHVtZXM6CiAgICAgIC0gbWluaW8tZGF0YTovZGF0YQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6IFsiQ01EIiwgImN1cmwiLCAiLWYiLCAiaHR0cDovLzEyNy4wLjAuMTozMjAwL21pbmlvL2hlYWx0aC9saXZlIl0KICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwoKICBtaW5pby1pbml0OgogICAgaW1hZ2U6IG1pbmlvL21jOmxhdGVzdAogICAgZGVwZW5kc19vbjoKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGVudmlyb25tZW50OgogICAgICAtIE1JTklPX1JPT1RfVVNFUj0ke1NFUlZJQ0VfVVNFUl9NSU5JT30KICAgICAgLSBNSU5JT19ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NSU5JT30KICAgIGVudHJ5cG9pbnQ6ID4KICAgICAgL2Jpbi9zaCAtYyAiCiAgICAgIG1jIGFsaWFzIHNldCBtaW5pbyBodHRwOi8vbWluaW86MzIwMCAkJHtNSU5JT19ST09UX1VTRVJ9ICQke01JTklPX1JPT1RfUEFTU1dPUkR9OwogICAgICBtYyBtYiBtaW5pby9iMi1ldS1jZW4gLS1pZ25vcmUtZXhpc3Rpbmc7CiAgICAgIG1jIG1iIG1pbmlvL3dhc2FiaS1ldS1jZW50cmFsLTItdjMgLS1pZ25vcmUtZXhpc3Rpbmc7CiAgICAgIG1jIG1iIG1pbmlvL3Njdy1ldS1mci12MyAtLWlnbm9yZS1leGlzdGluZzsKICAgICAgZWNobyAnTWluSU8gYnVja2V0cyBjcmVhdGVkIHN1Y2Nlc3NmdWxseSc7CiAgICAgICIK", "tags": [ "photos", "gallery", From 75b508c53ebd1b547eb1e2506ea350ff63aa15be Mon Sep 17 00:00:00 2001 From: Vishwanath Martur <64204611+vishwamartur@users.noreply.github.com> Date: Wed, 3 Sep 2025 07:24:59 +0530 Subject: [PATCH 011/111] Restore docker-compose.dev.yml file - Restore docker-compose.dev.yml to original state as requested by @Cinzya - File should not be deleted, just reverted to original state - Addresses reviewer feedback about keeping the file intact --- docker-compose.dev.yml | 125 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 docker-compose.dev.yml diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 000000000..e8402b7af --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,125 @@ +services: + coolify: + build: + context: . + dockerfile: ./docker/development/Dockerfile + args: + - USER_ID=${USERID:-1000} + - GROUP_ID=${GROUPID:-1000} + ports: + - "${APP_PORT:-8000}:8080" + environment: + AUTORUN_ENABLED: false + PUSHER_HOST: "${PUSHER_HOST}" + PUSHER_PORT: "${PUSHER_PORT}" + PUSHER_SCHEME: "${PUSHER_SCHEME:-http}" + PUSHER_APP_ID: "${PUSHER_APP_ID:-coolify}" + PUSHER_APP_KEY: "${PUSHER_APP_KEY:-coolify}" + PUSHER_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}" + volumes: + - .:/var/www/html/:cached + - dev_backups_data:/var/www/html/storage/app/backups + postgres: + pull_policy: always + ports: + - "${FORWARD_DB_PORT:-5432}:5432" + env_file: + - .env + environment: + POSTGRES_USER: "${DB_USERNAME:-coolify}" + POSTGRES_PASSWORD: "${DB_PASSWORD:-password}" + POSTGRES_DB: "${DB_DATABASE:-coolify}" + POSTGRES_HOST_AUTH_METHOD: "trust" + volumes: + - dev_postgres_data:/var/lib/postgresql/data + redis: + pull_policy: always + ports: + - "${FORWARD_REDIS_PORT:-6379}:6379" + env_file: + - .env + volumes: + - dev_redis_data:/data + soketi: + build: + context: . + dockerfile: ./docker/coolify-realtime/Dockerfile + env_file: + - .env + ports: + - "${FORWARD_SOKETI_PORT:-6001}:6001" + - "6002:6002" + volumes: + - ./storage:/var/www/html/storage + - ./docker/coolify-realtime/terminal-server.js:/terminal/terminal-server.js + environment: + SOKETI_DEBUG: "false" + SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID:-coolify}" + SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY:-coolify}" + SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET:-coolify}" + entrypoint: ["/bin/sh", "/soketi-entrypoint.sh"] + vite: + image: node:24-alpine + pull_policy: always + working_dir: /var/www/html + environment: + VITE_HOST: "${VITE_HOST:-localhost}" + VITE_PORT: "${VITE_PORT:-5173}" + ports: + - "${VITE_PORT:-5173}:${VITE_PORT:-5173}" + volumes: + - .:/var/www/html/:cached + command: sh -c "npm install && npm run dev" + networks: + - coolify + testing-host: + build: + context: . + dockerfile: ./docker/testing-host/Dockerfile + init: true + container_name: coolify-testing-host + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - dev_coolify_data:/data/coolify + - dev_backups_data:/data/coolify/backups + - dev_postgres_data:/data/coolify/_volumes/database + - dev_redis_data:/data/coolify/_volumes/redis + - dev_minio_data:/data/coolify/_volumes/minio + networks: + - coolify + mailpit: + image: axllent/mailpit:latest + pull_policy: always + container_name: coolify-mail + ports: + - "${FORWARD_MAILPIT_PORT:-1025}:1025" + - "${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025" + networks: + - coolify + minio: + image: minio/minio:latest + pull_policy: always + container_name: coolify-minio + command: server /data --console-address ":9001" + ports: + - "${FORWARD_MINIO_PORT:-9000}:9000" + - "${FORWARD_MINIO_PORT_CONSOLE:-9001}:9001" + environment: + MINIO_ACCESS_KEY: "${MINIO_ACCESS_KEY:-minioadmin}" + MINIO_SECRET_KEY: "${MINIO_SECRET_KEY:-minioadmin}" + volumes: + - dev_minio_data:/data + networks: + - coolify + +volumes: + dev_backups_data: + dev_postgres_data: + dev_redis_data: + dev_coolify_data: + dev_minio_data: + +networks: + coolify: + name: coolify + external: false From 8c8e2973c7ee71319e1537fef077e416043669e2 Mon Sep 17 00:00:00 2001 From: Vishwanath Martur <64204611+vishwamartur@users.noreply.github.com> Date: Wed, 3 Sep 2025 07:43:45 +0530 Subject: [PATCH 012/111] Fix MinIO image and health check to match Coolify standards - Change MinIO image from 'minio/minio:latest' to 'quay.io/minio/minio:latest' This matches the official Coolify MinIO template for consistency - Update health check from curl-based to 'mc ready local' command This is more reliable and matches the official MinIO template - Update health check intervals and retries to match official template (interval: 5s, timeout: 20s, retries: 10) - Update service templates JSON files with corrected configuration Addresses @devdilson's feedback about MinIO configuration consistency with existing Coolify templates and best practices. --- templates/compose/ente-photos.yaml | 10 +++++----- templates/service-templates-latest.json | 2 +- templates/service-templates.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/templates/compose/ente-photos.yaml b/templates/compose/ente-photos.yaml index a3fca5df2..6ee902d6c 100644 --- a/templates/compose/ente-photos.yaml +++ b/templates/compose/ente-photos.yaml @@ -63,7 +63,7 @@ services: retries: 5 minio: - image: minio/minio:latest + image: quay.io/minio/minio:latest environment: - SERVICE_URL_MINIO_3200 - MINIO_ROOT_USER=${SERVICE_USER_MINIO} @@ -72,10 +72,10 @@ services: volumes: - minio-data:/data healthcheck: - test: ["CMD", "curl", "-f", "http://127.0.0.1:3200/minio/health/live"] - interval: 30s - timeout: 10s - retries: 3 + test: ["CMD", "mc", "ready", "local"] + interval: 5s + timeout: 20s + retries: 10 minio-init: image: minio/mc:latest diff --git a/templates/service-templates-latest.json b/templates/service-templates-latest.json index 1d2224264..489ed0e90 100644 --- a/templates/service-templates-latest.json +++ b/templates/service-templates-latest.json @@ -951,7 +951,7 @@ "ente-photos": { "documentation": "https://help.ente.io/self-hosting/installation/compose?utm_source=coolify.io", "slogan": "Ente Photos is a fully open source, End to End Encrypted alternative to Google Photos and Apple Photos.", - "compose": "IyBkb2N1bWVudGF0aW9uOiBodHRwczovL2hlbHAuZW50ZS5pby9zZWxmLWhvc3RpbmcvaW5zdGFsbGF0aW9uL2NvbXBvc2UKIyBzbG9nYW46IEVudGUgUGhvdG9zIGlzIGEgZnVsbHkgb3BlbiBzb3VyY2UsIEVuZCB0byBFbmQgRW5jcnlwdGVkIGFsdGVybmF0aXZlIHRvIEdvb2dsZSBQaG90b3MgYW5kIEFwcGxlIFBob3Rvcy4KIyBjYXRlZ29yeTogbWVkaWEKIyB0YWdzOiBwaG90b3MsZ2FsbGVyeSxiYWNrdXAsZW5jcnlwdGlvbixwcml2YWN5LHNlbGYtaG9zdGVkLGdvb2dsZS1waG90b3MsYWx0ZXJuYXRpdmUKIyBsb2dvOiBzdmdzL2VudGUtcGhvdG9zLnN2ZwojIHBvcnQ6IDgwODAKCnNlcnZpY2VzOgogIG11c2V1bToKICAgIGltYWdlOiBnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdAogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfTVVTRVVNXzgwODAKICAgICAgIyBEYXRhYmFzZSBjb25maWd1cmF0aW9uCiAgICAgIC0gUE9TVEdSRVNfSE9TVD1wb3N0Z3JlcwogICAgICAtIFBPU1RHUkVTX1BPUlQ9NTQzMgogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30KICAgICAgLSBQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9CiAgICAgICMgUzMvTWluSU8gY29uZmlndXJhdGlvbgogICAgICAtIFMzX0FSRV9MT0NBTF9CVUNLRVRTPXRydWUKICAgICAgLSBTM19VU0VfUEFUSF9TVFlMRV9VUkxTPXRydWUKICAgICAgLSBTM19CMl9FVV9DRU5fS0VZPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9FTkRQT0lOVD0ke1NFUlZJQ0VfVVJMX01JTklPXzMyMDB9CiAgICAgIC0gUzNfQjJfRVVfQ0VOX1JFR0lPTj1ldS1jZW50cmFsLTIKICAgICAgLSBTM19CMl9FVV9DRU5fQlVDS0VUPWIyLWV1LWNlbgogICAgICAjIFNlY3VyaXR5IGtleXMKICAgICAgLSBFTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfRU5DUllQVElPTn0KICAgICAgLSBIQVNIX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfSEFTSH0KICAgICAgLSBKV1RfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF82NF9KV1R9CiAgICAgICMgQWRtaW4gcGVybWlzc2lvbnMgKGdyYW50cyBmaXJzdCBhY2NvdW50IGFkbWluIGFjY2VzcykKICAgICAgLSBFTlRFX0lOVEVSTkFMX0FETUlOPTE1ODA1NTk5NjIzODY0MzgKICAgICAgIyBBcHAgVVJMcyAob3B0aW9uYWwgLSBmb3Igd2ViIGludGVyZmFjZSkKICAgICAgLSBBUFBTX1BVQkxJQ19BTEJVTVM9JHtBUFBTX1BVQkxJQ19BTEJVTVM6LX0KICAgICAgLSBBUFBTX0NBU1Q9JHtBUFBTX0NBU1Q6LX0KICAgICAgLSBBUFBTX0FDQ09VTlRTPSR7QVBQU19BQ0NPVU5UUzotfQogICAgdm9sdW1lczoKICAgICAgLSBtdXNldW0tZGF0YTovZGF0YQogICAgICAtIG11c2V1bS1jb25maWc6L2NvbmZpZwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX3N0YXJ0ZWQKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OiBbIkNNRCIsICJjdXJsIiwgIi1mIiwgImh0dHA6Ly8xMjcuMC4wLjE6ODA4MC9waW5nIl0KICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwoKICBwb3N0Z3JlczoKICAgIGltYWdlOiBwb3N0Z3JlczoxNS1hbHBpbmUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9CiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfQogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICB2b2x1bWVzOgogICAgICAtIHBvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDogWyJDTUQtU0hFTEwiLCAicGdfaXNyZWFkeSAtVSAke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30gLWQgJHtQT1NUR1JFU19EQjotZW50ZV9kYn0iXQogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDUKCiAgbWluaW86CiAgICBpbWFnZTogbWluaW8vbWluaW86bGF0ZXN0CiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9NSU5JT18zMjAwCiAgICAgIC0gTUlOSU9fUk9PVF9VU0VSPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIE1JTklPX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgY29tbWFuZDogc2VydmVyIC9kYXRhIC0tYWRkcmVzcyAiOjMyMDAiIC0tY29uc29sZS1hZGRyZXNzICI6MzIwMSIKICAgIHZvbHVtZXM6CiAgICAgIC0gbWluaW8tZGF0YTovZGF0YQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6IFsiQ01EIiwgImN1cmwiLCAiLWYiLCAiaHR0cDovLzEyNy4wLjAuMTozMjAwL21pbmlvL2hlYWx0aC9saXZlIl0KICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwoKICBtaW5pby1pbml0OgogICAgaW1hZ2U6IG1pbmlvL21jOmxhdGVzdAogICAgZGVwZW5kc19vbjoKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGVudmlyb25tZW50OgogICAgICAtIE1JTklPX1JPT1RfVVNFUj0ke1NFUlZJQ0VfVVNFUl9NSU5JT30KICAgICAgLSBNSU5JT19ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NSU5JT30KICAgIGVudHJ5cG9pbnQ6ID4KICAgICAgL2Jpbi9zaCAtYyAiCiAgICAgIG1jIGFsaWFzIHNldCBtaW5pbyBodHRwOi8vbWluaW86MzIwMCAkJHtNSU5JT19ST09UX1VTRVJ9ICQke01JTklPX1JPT1RfUEFTU1dPUkR9OwogICAgICBtYyBtYiBtaW5pby9iMi1ldS1jZW4gLS1pZ25vcmUtZXhpc3Rpbmc7CiAgICAgIG1jIG1iIG1pbmlvL3dhc2FiaS1ldS1jZW50cmFsLTItdjMgLS1pZ25vcmUtZXhpc3Rpbmc7CiAgICAgIG1jIG1iIG1pbmlvL3Njdy1ldS1mci12MyAtLWlnbm9yZS1leGlzdGluZzsKICAgICAgZWNobyAnTWluSU8gYnVja2V0cyBjcmVhdGVkIHN1Y2Nlc3NmdWxseSc7CiAgICAgICIK", + "compose": "IyBkb2N1bWVudGF0aW9uOiBodHRwczovL2hlbHAuZW50ZS5pby9zZWxmLWhvc3RpbmcvaW5zdGFsbGF0aW9uL2NvbXBvc2UKIyBzbG9nYW46IEVudGUgUGhvdG9zIGlzIGEgZnVsbHkgb3BlbiBzb3VyY2UsIEVuZCB0byBFbmQgRW5jcnlwdGVkIGFsdGVybmF0aXZlIHRvIEdvb2dsZSBQaG90b3MgYW5kIEFwcGxlIFBob3Rvcy4KIyBjYXRlZ29yeTogbWVkaWEKIyB0YWdzOiBwaG90b3MsZ2FsbGVyeSxiYWNrdXAsZW5jcnlwdGlvbixwcml2YWN5LHNlbGYtaG9zdGVkLGdvb2dsZS1waG90b3MsYWx0ZXJuYXRpdmUKIyBsb2dvOiBzdmdzL2VudGUtcGhvdG9zLnN2ZwojIHBvcnQ6IDgwODAKCnNlcnZpY2VzOgogIG11c2V1bToKICAgIGltYWdlOiBnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdAogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfTVVTRVVNXzgwODAKICAgICAgIyBEYXRhYmFzZSBjb25maWd1cmF0aW9uCiAgICAgIC0gUE9TVEdSRVNfSE9TVD1wb3N0Z3JlcwogICAgICAtIFBPU1RHUkVTX1BPUlQ9NTQzMgogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30KICAgICAgLSBQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9CiAgICAgICMgUzMvTWluSU8gY29uZmlndXJhdGlvbgogICAgICAtIFMzX0FSRV9MT0NBTF9CVUNLRVRTPXRydWUKICAgICAgLSBTM19VU0VfUEFUSF9TVFlMRV9VUkxTPXRydWUKICAgICAgLSBTM19CMl9FVV9DRU5fS0VZPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9FTkRQT0lOVD0ke1NFUlZJQ0VfVVJMX01JTklPXzMyMDB9CiAgICAgIC0gUzNfQjJfRVVfQ0VOX1JFR0lPTj1ldS1jZW50cmFsLTIKICAgICAgLSBTM19CMl9FVV9DRU5fQlVDS0VUPWIyLWV1LWNlbgogICAgICAjIFNlY3VyaXR5IGtleXMKICAgICAgLSBFTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfRU5DUllQVElPTn0KICAgICAgLSBIQVNIX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfSEFTSH0KICAgICAgLSBKV1RfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF82NF9KV1R9CiAgICAgICMgQWRtaW4gcGVybWlzc2lvbnMgKGdyYW50cyBmaXJzdCBhY2NvdW50IGFkbWluIGFjY2VzcykKICAgICAgLSBFTlRFX0lOVEVSTkFMX0FETUlOPTE1ODA1NTk5NjIzODY0MzgKICAgICAgIyBBcHAgVVJMcyAob3B0aW9uYWwgLSBmb3Igd2ViIGludGVyZmFjZSkKICAgICAgLSBBUFBTX1BVQkxJQ19BTEJVTVM9JHtBUFBTX1BVQkxJQ19BTEJVTVM6LX0KICAgICAgLSBBUFBTX0NBU1Q9JHtBUFBTX0NBU1Q6LX0KICAgICAgLSBBUFBTX0FDQ09VTlRTPSR7QVBQU19BQ0NPVU5UUzotfQogICAgdm9sdW1lczoKICAgICAgLSBtdXNldW0tZGF0YTovZGF0YQogICAgICAtIG11c2V1bS1jb25maWc6L2NvbmZpZwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX3N0YXJ0ZWQKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OiBbIkNNRCIsICJjdXJsIiwgIi1mIiwgImh0dHA6Ly8xMjcuMC4wLjE6ODA4MC9waW5nIl0KICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwoKICBwb3N0Z3JlczoKICAgIGltYWdlOiBwb3N0Z3JlczoxNS1hbHBpbmUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9CiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfQogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICB2b2x1bWVzOgogICAgICAtIHBvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDogWyJDTUQtU0hFTEwiLCAicGdfaXNyZWFkeSAtVSAke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30gLWQgJHtQT1NUR1JFU19EQjotZW50ZV9kYn0iXQogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDUKCiAgbWluaW86CiAgICBpbWFnZTogcXVheS5pby9taW5pby9taW5pbzpsYXRlc3QKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX01JTklPXzMyMDAKICAgICAgLSBNSU5JT19ST09UX1VTRVI9JHtTRVJWSUNFX1VTRVJfTUlOSU99CiAgICAgIC0gTUlOSU9fUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTUlOSU99CiAgICBjb21tYW5kOiBzZXJ2ZXIgL2RhdGEgLS1hZGRyZXNzICI6MzIwMCIgLS1jb25zb2xlLWFkZHJlc3MgIjozMjAxIgogICAgdm9sdW1lczoKICAgICAgLSBtaW5pby1kYXRhOi9kYXRhCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDogWyJDTUQiLCAibWMiLCAicmVhZHkiLCAibG9jYWwiXQogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCgogIG1pbmlvLWluaXQ6CiAgICBpbWFnZTogbWluaW8vbWM6bGF0ZXN0CiAgICBkZXBlbmRzX29uOgogICAgICBtaW5pbzoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gTUlOSU9fUk9PVF9VU0VSPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIE1JTklPX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgZW50cnlwb2ludDogPgogICAgICAvYmluL3NoIC1jICIKICAgICAgbWMgYWxpYXMgc2V0IG1pbmlvIGh0dHA6Ly9taW5pbzozMjAwICQke01JTklPX1JPT1RfVVNFUn0gJCR7TUlOSU9fUk9PVF9QQVNTV09SRH07CiAgICAgIG1jIG1iIG1pbmlvL2IyLWV1LWNlbiAtLWlnbm9yZS1leGlzdGluZzsKICAgICAgbWMgbWIgbWluaW8vd2FzYWJpLWV1LWNlbnRyYWwtMi12MyAtLWlnbm9yZS1leGlzdGluZzsKICAgICAgbWMgbWIgbWluaW8vc2N3LWV1LWZyLXYzIC0taWdub3JlLWV4aXN0aW5nOwogICAgICBlY2hvICdNaW5JTyBidWNrZXRzIGNyZWF0ZWQgc3VjY2Vzc2Z1bGx5JzsKICAgICAgIgo=", "tags": [ "photos", "gallery", diff --git a/templates/service-templates.json b/templates/service-templates.json index 6fb0b689b..f44b57bb3 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -951,7 +951,7 @@ "ente-photos": { "documentation": "https://help.ente.io/self-hosting/installation/compose?utm_source=coolify.io", "slogan": "Ente Photos is a fully open source, End to End Encrypted alternative to Google Photos and Apple Photos.", - "compose": "IyBkb2N1bWVudGF0aW9uOiBodHRwczovL2hlbHAuZW50ZS5pby9zZWxmLWhvc3RpbmcvaW5zdGFsbGF0aW9uL2NvbXBvc2UKIyBzbG9nYW46IEVudGUgUGhvdG9zIGlzIGEgZnVsbHkgb3BlbiBzb3VyY2UsIEVuZCB0byBFbmQgRW5jcnlwdGVkIGFsdGVybmF0aXZlIHRvIEdvb2dsZSBQaG90b3MgYW5kIEFwcGxlIFBob3Rvcy4KIyBjYXRlZ29yeTogbWVkaWEKIyB0YWdzOiBwaG90b3MsZ2FsbGVyeSxiYWNrdXAsZW5jcnlwdGlvbixwcml2YWN5LHNlbGYtaG9zdGVkLGdvb2dsZS1waG90b3MsYWx0ZXJuYXRpdmUKIyBsb2dvOiBzdmdzL2VudGUtcGhvdG9zLnN2ZwojIHBvcnQ6IDgwODAKCnNlcnZpY2VzOgogIG11c2V1bToKICAgIGltYWdlOiBnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdAogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfTVVTRVVNXzgwODAKICAgICAgIyBEYXRhYmFzZSBjb25maWd1cmF0aW9uCiAgICAgIC0gUE9TVEdSRVNfSE9TVD1wb3N0Z3JlcwogICAgICAtIFBPU1RHUkVTX1BPUlQ9NTQzMgogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30KICAgICAgLSBQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9CiAgICAgICMgUzMvTWluSU8gY29uZmlndXJhdGlvbgogICAgICAtIFMzX0FSRV9MT0NBTF9CVUNLRVRTPXRydWUKICAgICAgLSBTM19VU0VfUEFUSF9TVFlMRV9VUkxTPXRydWUKICAgICAgLSBTM19CMl9FVV9DRU5fS0VZPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9FTkRQT0lOVD0ke1NFUlZJQ0VfVVJMX01JTklPXzMyMDB9CiAgICAgIC0gUzNfQjJfRVVfQ0VOX1JFR0lPTj1ldS1jZW50cmFsLTIKICAgICAgLSBTM19CMl9FVV9DRU5fQlVDS0VUPWIyLWV1LWNlbgogICAgICAjIFNlY3VyaXR5IGtleXMKICAgICAgLSBFTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfRU5DUllQVElPTn0KICAgICAgLSBIQVNIX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfSEFTSH0KICAgICAgLSBKV1RfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF82NF9KV1R9CiAgICAgICMgQWRtaW4gcGVybWlzc2lvbnMgKGdyYW50cyBmaXJzdCBhY2NvdW50IGFkbWluIGFjY2VzcykKICAgICAgLSBFTlRFX0lOVEVSTkFMX0FETUlOPTE1ODA1NTk5NjIzODY0MzgKICAgICAgIyBBcHAgVVJMcyAob3B0aW9uYWwgLSBmb3Igd2ViIGludGVyZmFjZSkKICAgICAgLSBBUFBTX1BVQkxJQ19BTEJVTVM9JHtBUFBTX1BVQkxJQ19BTEJVTVM6LX0KICAgICAgLSBBUFBTX0NBU1Q9JHtBUFBTX0NBU1Q6LX0KICAgICAgLSBBUFBTX0FDQ09VTlRTPSR7QVBQU19BQ0NPVU5UUzotfQogICAgdm9sdW1lczoKICAgICAgLSBtdXNldW0tZGF0YTovZGF0YQogICAgICAtIG11c2V1bS1jb25maWc6L2NvbmZpZwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX3N0YXJ0ZWQKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OiBbIkNNRCIsICJjdXJsIiwgIi1mIiwgImh0dHA6Ly8xMjcuMC4wLjE6ODA4MC9waW5nIl0KICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwoKICBwb3N0Z3JlczoKICAgIGltYWdlOiBwb3N0Z3JlczoxNS1hbHBpbmUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9CiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfQogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICB2b2x1bWVzOgogICAgICAtIHBvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDogWyJDTUQtU0hFTEwiLCAicGdfaXNyZWFkeSAtVSAke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30gLWQgJHtQT1NUR1JFU19EQjotZW50ZV9kYn0iXQogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDUKCiAgbWluaW86CiAgICBpbWFnZTogbWluaW8vbWluaW86bGF0ZXN0CiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX1VSTF9NSU5JT18zMjAwCiAgICAgIC0gTUlOSU9fUk9PVF9VU0VSPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIE1JTklPX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgY29tbWFuZDogc2VydmVyIC9kYXRhIC0tYWRkcmVzcyAiOjMyMDAiIC0tY29uc29sZS1hZGRyZXNzICI6MzIwMSIKICAgIHZvbHVtZXM6CiAgICAgIC0gbWluaW8tZGF0YTovZGF0YQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6IFsiQ01EIiwgImN1cmwiLCAiLWYiLCAiaHR0cDovLzEyNy4wLjAuMTozMjAwL21pbmlvL2hlYWx0aC9saXZlIl0KICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwoKICBtaW5pby1pbml0OgogICAgaW1hZ2U6IG1pbmlvL21jOmxhdGVzdAogICAgZGVwZW5kc19vbjoKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGVudmlyb25tZW50OgogICAgICAtIE1JTklPX1JPT1RfVVNFUj0ke1NFUlZJQ0VfVVNFUl9NSU5JT30KICAgICAgLSBNSU5JT19ST09UX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9NSU5JT30KICAgIGVudHJ5cG9pbnQ6ID4KICAgICAgL2Jpbi9zaCAtYyAiCiAgICAgIG1jIGFsaWFzIHNldCBtaW5pbyBodHRwOi8vbWluaW86MzIwMCAkJHtNSU5JT19ST09UX1VTRVJ9ICQke01JTklPX1JPT1RfUEFTU1dPUkR9OwogICAgICBtYyBtYiBtaW5pby9iMi1ldS1jZW4gLS1pZ25vcmUtZXhpc3Rpbmc7CiAgICAgIG1jIG1iIG1pbmlvL3dhc2FiaS1ldS1jZW50cmFsLTItdjMgLS1pZ25vcmUtZXhpc3Rpbmc7CiAgICAgIG1jIG1iIG1pbmlvL3Njdy1ldS1mci12MyAtLWlnbm9yZS1leGlzdGluZzsKICAgICAgZWNobyAnTWluSU8gYnVja2V0cyBjcmVhdGVkIHN1Y2Nlc3NmdWxseSc7CiAgICAgICIK", + "compose": "IyBkb2N1bWVudGF0aW9uOiBodHRwczovL2hlbHAuZW50ZS5pby9zZWxmLWhvc3RpbmcvaW5zdGFsbGF0aW9uL2NvbXBvc2UKIyBzbG9nYW46IEVudGUgUGhvdG9zIGlzIGEgZnVsbHkgb3BlbiBzb3VyY2UsIEVuZCB0byBFbmQgRW5jcnlwdGVkIGFsdGVybmF0aXZlIHRvIEdvb2dsZSBQaG90b3MgYW5kIEFwcGxlIFBob3Rvcy4KIyBjYXRlZ29yeTogbWVkaWEKIyB0YWdzOiBwaG90b3MsZ2FsbGVyeSxiYWNrdXAsZW5jcnlwdGlvbixwcml2YWN5LHNlbGYtaG9zdGVkLGdvb2dsZS1waG90b3MsYWx0ZXJuYXRpdmUKIyBsb2dvOiBzdmdzL2VudGUtcGhvdG9zLnN2ZwojIHBvcnQ6IDgwODAKCnNlcnZpY2VzOgogIG11c2V1bToKICAgIGltYWdlOiBnaGNyLmlvL2VudGUtaW8vc2VydmVyOmxhdGVzdAogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9VUkxfTVVTRVVNXzgwODAKICAgICAgIyBEYXRhYmFzZSBjb25maWd1cmF0aW9uCiAgICAgIC0gUE9TVEdSRVNfSE9TVD1wb3N0Z3JlcwogICAgICAtIFBPU1RHUkVTX1BPUlQ9NTQzMgogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICAgIC0gUE9TVEdSRVNfVVNFUj0ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30KICAgICAgLSBQT1NUR1JFU19QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9CiAgICAgICMgUzMvTWluSU8gY29uZmlndXJhdGlvbgogICAgICAtIFMzX0FSRV9MT0NBTF9CVUNLRVRTPXRydWUKICAgICAgLSBTM19VU0VfUEFUSF9TVFlMRV9VUkxTPXRydWUKICAgICAgLSBTM19CMl9FVV9DRU5fS0VZPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgICAtIFMzX0IyX0VVX0NFTl9FTkRQT0lOVD0ke1NFUlZJQ0VfVVJMX01JTklPXzMyMDB9CiAgICAgIC0gUzNfQjJfRVVfQ0VOX1JFR0lPTj1ldS1jZW50cmFsLTIKICAgICAgLSBTM19CMl9FVV9DRU5fQlVDS0VUPWIyLWV1LWNlbgogICAgICAjIFNlY3VyaXR5IGtleXMKICAgICAgLSBFTkNSWVBUSU9OX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfRU5DUllQVElPTn0KICAgICAgLSBIQVNIX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfNjRfSEFTSH0KICAgICAgLSBKV1RfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF82NF9KV1R9CiAgICAgICMgQWRtaW4gcGVybWlzc2lvbnMgKGdyYW50cyBmaXJzdCBhY2NvdW50IGFkbWluIGFjY2VzcykKICAgICAgLSBFTlRFX0lOVEVSTkFMX0FETUlOPTE1ODA1NTk5NjIzODY0MzgKICAgICAgIyBBcHAgVVJMcyAob3B0aW9uYWwgLSBmb3Igd2ViIGludGVyZmFjZSkKICAgICAgLSBBUFBTX1BVQkxJQ19BTEJVTVM9JHtBUFBTX1BVQkxJQ19BTEJVTVM6LX0KICAgICAgLSBBUFBTX0NBU1Q9JHtBUFBTX0NBU1Q6LX0KICAgICAgLSBBUFBTX0FDQ09VTlRTPSR7QVBQU19BQ0NPVU5UUzotfQogICAgdm9sdW1lczoKICAgICAgLSBtdXNldW0tZGF0YTovZGF0YQogICAgICAtIG11c2V1bS1jb25maWc6L2NvbmZpZwogICAgZGVwZW5kc19vbjoKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgbWluaW86CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX3N0YXJ0ZWQKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OiBbIkNNRCIsICJjdXJsIiwgIi1mIiwgImh0dHA6Ly8xMjcuMC4wLjE6ODA4MC9waW5nIl0KICAgICAgaW50ZXJ2YWw6IDMwcwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMwoKICBwb3N0Z3JlczoKICAgIGltYWdlOiBwb3N0Z3JlczoxNS1hbHBpbmUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9JHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9CiAgICAgIC0gUE9TVEdSRVNfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfQogICAgICAtIFBPU1RHUkVTX0RCPSR7UE9TVEdSRVNfREI6LWVudGVfZGJ9CiAgICB2b2x1bWVzOgogICAgICAtIHBvc3RncmVzLWRhdGE6L3Zhci9saWIvcG9zdGdyZXNxbC9kYXRhCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDogWyJDTUQtU0hFTEwiLCAicGdfaXNyZWFkeSAtVSAke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU30gLWQgJHtQT1NUR1JFU19EQjotZW50ZV9kYn0iXQogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDUKCiAgbWluaW86CiAgICBpbWFnZTogcXVheS5pby9taW5pby9taW5pbzpsYXRlc3QKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfVVJMX01JTklPXzMyMDAKICAgICAgLSBNSU5JT19ST09UX1VTRVI9JHtTRVJWSUNFX1VTRVJfTUlOSU99CiAgICAgIC0gTUlOSU9fUk9PVF9QQVNTV09SRD0ke1NFUlZJQ0VfUEFTU1dPUkRfTUlOSU99CiAgICBjb21tYW5kOiBzZXJ2ZXIgL2RhdGEgLS1hZGRyZXNzICI6MzIwMCIgLS1jb25zb2xlLWFkZHJlc3MgIjozMjAxIgogICAgdm9sdW1lczoKICAgICAgLSBtaW5pby1kYXRhOi9kYXRhCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDogWyJDTUQiLCAibWMiLCAicmVhZHkiLCAibG9jYWwiXQogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCgogIG1pbmlvLWluaXQ6CiAgICBpbWFnZTogbWluaW8vbWM6bGF0ZXN0CiAgICBkZXBlbmRzX29uOgogICAgICBtaW5pbzoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gTUlOSU9fUk9PVF9VU0VSPSR7U0VSVklDRV9VU0VSX01JTklPfQogICAgICAtIE1JTklPX1JPT1RfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX01JTklPfQogICAgZW50cnlwb2ludDogPgogICAgICAvYmluL3NoIC1jICIKICAgICAgbWMgYWxpYXMgc2V0IG1pbmlvIGh0dHA6Ly9taW5pbzozMjAwICQke01JTklPX1JPT1RfVVNFUn0gJCR7TUlOSU9fUk9PVF9QQVNTV09SRH07CiAgICAgIG1jIG1iIG1pbmlvL2IyLWV1LWNlbiAtLWlnbm9yZS1leGlzdGluZzsKICAgICAgbWMgbWIgbWluaW8vd2FzYWJpLWV1LWNlbnRyYWwtMi12MyAtLWlnbm9yZS1leGlzdGluZzsKICAgICAgbWMgbWIgbWluaW8vc2N3LWV1LWZyLXYzIC0taWdub3JlLWV4aXN0aW5nOwogICAgICBlY2hvICdNaW5JTyBidWNrZXRzIGNyZWF0ZWQgc3VjY2Vzc2Z1bGx5JzsKICAgICAgIgo=", "tags": [ "photos", "gallery", From 4a81a96d9489be7da06b751ee14630f1657a636f Mon Sep 17 00:00:00 2001 From: thesloppyguy Date: Wed, 3 Sep 2025 14:30:45 +0530 Subject: [PATCH 013/111] Fix: Lean Config --- templates/compose/ente.yaml | 54 +++++-------------------------------- 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/templates/compose/ente.yaml b/templates/compose/ente.yaml index 830c21c43..a9a2f0c59 100644 --- a/templates/compose/ente.yaml +++ b/templates/compose/ente.yaml @@ -33,52 +33,18 @@ services: ENTE_JWT_SECRET: ${MUSEUM_JWT_KEY} - ENTE_SMTP_HOST: ${SMTP_HOST} - ENTE_SMTP_PORT: ${SMTP_PORT} - ENTE_SMTP_USERNAME: ${SMTP_USERNAME} - ENTE_SMTP_PASSWORD: ${SMTP_PASSWORD} - ENTE_SMTP_EMAIL: ${SMTP_EMAIL} - ENTE_SMTP_SENDER_NAME: ${SMTP_SENDER_NAME} - ENTE_SMTP_ENCRYPTION: ${SMTP_ENCRYPTION} - - ENTE_TRANSMAIL_KEY: ${ENTE_TRANSMAIL_KEY} - - ENTE_APPLE_SHARED_SECRET: ${ENTE_APPLE_SHARED_SECRET} - - ENTE_STRIPE_US_KEY: ${ENTE_STRIPE_US_KEY} - ENTE_STRIPE_US_WEBHOOK_SECRET: ${ENTE_STRIPE_WEBHOOK_SECRET} - ENTE_STRIPE_IN_KEY: ${ENTE_STRIPE_US_KEY} - ENTE_STRIPE_IN_WEBHOOK_SECRET: ${ENTE_STRIPE_WEBHOOK_SECRET} - ENTE_STRIPE_WHITELISTED_REDIRECT_URLS: ${ENTE_WHITELISTED_REDIRECT_URLS} - - ENTE_WEBAUTHN_RPID: ${ENTE_WEBAUTHN_RPID:-localhost} - ENTE_WEBAUTHN_RPORIGINS: ${ENTE_WEBAUTHN_RPORIGINS:-https://localhost:3001} - ENTE_INTERNAL_SILENT: ${ENTE_INTERNAL_SILENT:-false} ENTE_INTERNAL_HEALTH_CHECK_URL: ${ENTE_INTERNAL_HEALTH_CHECK_URL} ENTE_INTERNAL_HARDCODED_OTT_EMAILS: ${ENTE_INTERNAL_HARDCODED_OTT_EMAIL} ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_SUFFIX: ${ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_SUFFIX} ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_VALUE: ${ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_VALUE} ENTE_INTERNAL_ADMINS: ${ENTE_INTERNAL_ADMINS} - ENTE_INTERNAL_ADMIN: ${ENTE_INTERNAL_ADMIN} + ENTE_INTERNAL_ADMIN: 1580559962386438 ENTE_INTERNAL_DISABLE_REGISTRATION: ${ENTE_INTERNAL_DISABLE_REGISTRATION:-false} - ENTE_REPLICATION_ENABLED: ${ENTE_REPLICATION_ENABLED:-false} - ENTE_REPLICATION_WORKER_URL: ${ENTE_REPLICATION_WORKER_URL} - ENTE_REPLICATION_WORKER_COUNT: ${ENTE_REPLICATION_WORKER_COUNT:-6} - ENTE_REPLICATION_TMP_STORAGE: ${ENTE_REPLICATION_TMP_STORAGE:-/tmp/replication} - - ENTE_JOBS_CRON_SKIP: ${ENTE_JOBS_CRON_SKIP:-false} - ENTE_JOBS_REMOVE_UNREPORTED_OBJECTS_WORKER_COUNT: ${ENTE_JOBS_REMOVE_UNREPORTED_OBJECTS_WORKER_COUNT:-1} - ENTE_JOBS_CLEAR_ORPHAN_OBJECTS_ENABLED: ${ENTE_JOBS_CLEAR_ORPHAN_OBJECTS_ENABLED:-false} - ENTE_JOBS_CLEAR_ORPHAN_OBJECTS_PREFIX: ${ENTE_JOBS_CLEAR_ORPHAN_OBJECTS_PREFIX:-""} - ENTE_S3_ARE_LOCAL_BUCKETS: ${ENTE_S3_ARE_LOCAL_BUCKETS:-true} ENTE_S3_USE_PATH_STYLE_URLS: ${ENTE_S3_USE_PATH_STYLE_URLS:-true} - ENTE_S3_HOT_STORAGE_PRIMARY: ${ENTE_S3_HOT_STORAGE_PRIMARY:-b2-eu-cen} - ENTE_S3_HOT_STORAGE_SECONDARY: ${ENTE_S3_HOT_STORAGE_SECONDARY:-wasabi-eu-central-2-v3} - ENTE_S3_B2_EU_CEN_KEY: ${SERVICE_USER_MINIO} ENTE_S3_B2_EU_CEN_SECRET: ${SERVICE_PASSWORD_MINIO} ENTE_S3_B2_EU_CEN_ENDPOINT: ${SERVICE_URL_MINIO}:3200 @@ -104,19 +70,6 @@ services: ENTE_S3_SCW_EU_FR_V3_ARE_LOCAL_BUCKETS: ${COLD_STORAGE_ARE_LOCAL_BUCKETS:-true} ENTE_S3_SCW_EU_FR_V3_USE_PATH_STYLE_URLS: ${COLD_STORAGE_USE_PATH_STYLE_URLS:-true} - ENTE_S3_WASABI_EU_CENTRAL_2_DERIVED_KEY: ${SECONDARY_STORAGE_DERIVED_KEY} - ENTE_S3_WASABI_EU_CENTRAL_2_DERIVED_SECRET: ${SECONDARY_STORAGE_DERIVED_SECRET} - ENTE_S3_WASABI_EU_CENTRAL_2_DERIVED_ENDPOINT: ${SECONDARY_STORAGE_DERIVED_ENDPOINT} - ENTE_S3_WASABI_EU_CENTRAL_2_DERIVED_REGION: ${SECONDARY_STORAGE_DERIVED_REGION} - ENTE_S3_WASABI_EU_CENTRAL_2_DERIVED_BUCKET: ${SECONDARY_STORAGE_DERIVED_BUCKET} - - ENTE_S3_DERIVED_STORAGE: ${ENTE_S3_DERIVED_STORAGE:-wasabi-eu-central-2-derived} - - ENTE_S3_FILE_DATA_CONFIG_MLDATA_PRIMARY_BUCKET: ${ENTE_S3_FILE_DATA_CONFIG_MLDATA_PRIMARY_BUCKET} - ENTE_S3_FILE_DATA_CONFIG_MLDATA_REPLICA_BUCKETS: ${ENTE_S3_FILE_DATA_CONFIG_MLDATA_REPLICA_BUCKETS} - ENTE_S3_FILE_DATA_CONFIG_IMG_PREVIEW_PRIMARY_BUCKET: ${ENTE_S3_FILE_DATA_CONFIG_IMG_PREVIEW_PRIMARY_BUCKET} - ENTE_S3_FILE_DATA_CONFIG_IMG_PREVIEW_REPLICA_BUCKETS: ${ENTE_S3_FILE_DATA_CONFIG_IMG_PREVIEW_REPLICA_BUCKETS} - depends_on: postgres: condition: service_healthy @@ -234,3 +187,8 @@ volumes: networks: ente-network: name: ente-network + + +MUSEUM_ENCRYPTION_KEY= pWe6al9Xtp2exq4g0HKqH9+mTGsF+KIsrKBkKMf80eI= +MUSEUM_HASH_KEY= OEZIA8F71MVXAe8JxVAAmbmKbb6wyLMiGbWeWuRbCTdqRj92YfTRX0GWEIYkoSZRpWaPnCIxGpgI3AgLKJ3wEA== +MUSEUM_JWT_KEY= KzyBWIwh5vL9EflM9qeq0BsbkWMl_xI4czGFiQj7UJA= From 26c01196f70fe3911ce9e9a445f3f0921c47e09d Mon Sep 17 00:00:00 2001 From: SAHIL Date: Wed, 3 Sep 2025 21:06:56 +0530 Subject: [PATCH 014/111] Fix: Env --- templates/compose/ente.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/templates/compose/ente.yaml b/templates/compose/ente.yaml index a9a2f0c59..a0c940f87 100644 --- a/templates/compose/ente.yaml +++ b/templates/compose/ente.yaml @@ -187,8 +187,3 @@ volumes: networks: ente-network: name: ente-network - - -MUSEUM_ENCRYPTION_KEY= pWe6al9Xtp2exq4g0HKqH9+mTGsF+KIsrKBkKMf80eI= -MUSEUM_HASH_KEY= OEZIA8F71MVXAe8JxVAAmbmKbb6wyLMiGbWeWuRbCTdqRj92YfTRX0GWEIYkoSZRpWaPnCIxGpgI3AgLKJ3wEA== -MUSEUM_JWT_KEY= KzyBWIwh5vL9EflM9qeq0BsbkWMl_xI4czGFiQj7UJA= From 97c22ab57041d2613d538c64f1886f2a8547b1b3 Mon Sep 17 00:00:00 2001 From: thesloppyguy Date: Sat, 6 Sep 2025 04:00:48 +0530 Subject: [PATCH 015/111] Fix: Services & Env variables --- templates/compose/ente.yaml | 156 +++++++----------------------------- 1 file changed, 27 insertions(+), 129 deletions(-) diff --git a/templates/compose/ente.yaml b/templates/compose/ente.yaml index a0c940f87..78ca81418 100644 --- a/templates/compose/ente.yaml +++ b/templates/compose/ente.yaml @@ -3,112 +3,60 @@ # category: media # tags: photos, backup, encryption, sharing, privacy, media, storage, encryption, minio, postgresql # logo: svgs/ente.png -# port: 8081 3000, 3001, 3002, 3003, 3004, 3200 services: museum: image: ghcr.io/ente-io/server:latest - ports: - - 8081:8080 environment: - SERVICE_URL_MUSEUM_8081: ${SERVICE_URL_MUSEUM_8081:-http://localhost:8081} + - SERVICE_URL_MUSEUM_8080 - ENTE_HTTP_USE_TLS: ${ENTE_HTTP_USE_TLS:-false} + - ENTE_HTTP_USE_TLS=${ENTE_HTTP_USE_TLS:-false} - ENTE_APPS_PUBLIC_ALBUMS: ${SERVICE_URL_WEB_3002:-http://localhost:3002} - ENTE_APPS_CAST: ${SERVICE_URL_WEB_3004:-http://localhost:3004} - ENTE_APPS_ACCOUNTS: ${SERVICE_URL_WEB_3001:-http://localhost:3001} - ENTE_APPS_PUBLIC_LOCKER: ${SERVICE_URL_WEB_3003:-http://localhost:3003} - ENTE_APPS_CUSTOM_DOMAIN_CNAME: ${ENTE_APPS_CUSTOM_DOMAIN_CNAME} + - ENTE_APPS_PUBLIC_ALBUMS=${SERVICE_URL_WEB_3002} + - ENTE_APPS_CAST=${SERVICE_URL_WEB_3004} + - ENTE_APPS_ACCOUNTS=${SERVICE_URL_WEB_3001} - ENTE_DB_HOST: ${ENTE_DB_HOST:-postgres} - ENTE_DB_PORT: ${ENTE_DB_PORT:-5432} - ENTE_DB_NAME: ${ENTE_DB_NAME:-ente_db} - ENTE_DB_SSLMODE: ${ENTE_DB_SSLMODE:-disable} - ENTE_DB_USER: ${SERVICE_USER_POSTGRES:-pguser} - ENTE_DB_PASSWORD: ${SERVICE_PASSWORD_POSTGRES} + - ENTE_DB_HOST=${ENTE_DB_HOST:-postgres} + - ENTE_DB_PORT=${ENTE_DB_PORT:-5432} + - ENTE_DB_NAME=${ENTE_DB_NAME:-ente_db} + - ENTE_DB_USER=${SERVICE_USER_POSTGRES:-pguser} + - ENTE_DB_PASSWORD=${SERVICE_PASSWORD_POSTGRES} - ENTE_KEY_ENCRYPTION: ${MUSEUM_ENCRYPTION_KEY} - ENTE_KEY_HASH: ${MUSEUM_HASH_KEY} + - ENTE_KEY_ENCRYPTION=${SERVICE_REALBASE64_ENCRYPTION} + - ENTE_KEY_HASH=${SERVICE_REALBASE64_64_HASH} - ENTE_JWT_SECRET: ${MUSEUM_JWT_KEY} + - ENTE_JWT_SECRET=${SERVICE_REALBASE64_JWT} - ENTE_INTERNAL_SILENT: ${ENTE_INTERNAL_SILENT:-false} - ENTE_INTERNAL_HEALTH_CHECK_URL: ${ENTE_INTERNAL_HEALTH_CHECK_URL} - ENTE_INTERNAL_HARDCODED_OTT_EMAILS: ${ENTE_INTERNAL_HARDCODED_OTT_EMAIL} - ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_SUFFIX: ${ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_SUFFIX} - ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_VALUE: ${ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_VALUE} - ENTE_INTERNAL_ADMINS: ${ENTE_INTERNAL_ADMINS} - ENTE_INTERNAL_ADMIN: 1580559962386438 - ENTE_INTERNAL_DISABLE_REGISTRATION: ${ENTE_INTERNAL_DISABLE_REGISTRATION:-false} + - ENTE_INTERNAL_ADMIN=${ENTE_INTERNAL_ADMIN:-1580559962386438} + - ENTE_INTERNAL_DISABLE_REGISTRATION=${ENTE_INTERNAL_DISABLE_REGISTRATION:-false} - ENTE_S3_ARE_LOCAL_BUCKETS: ${ENTE_S3_ARE_LOCAL_BUCKETS:-true} - ENTE_S3_USE_PATH_STYLE_URLS: ${ENTE_S3_USE_PATH_STYLE_URLS:-true} - - ENTE_S3_B2_EU_CEN_KEY: ${SERVICE_USER_MINIO} - ENTE_S3_B2_EU_CEN_SECRET: ${SERVICE_PASSWORD_MINIO} - ENTE_S3_B2_EU_CEN_ENDPOINT: ${SERVICE_URL_MINIO}:3200 - ENTE_S3_B2_EU_CEN_REGION: ${PRIMARY_STORAGE_REGION:-eu-central-2} - ENTE_S3_B2_EU_CEN_BUCKET: ${PRIMARY_STORAGE_BUCKET:-b2-eu-cen} - ENTE_S3_B2_EU_CEN_ARE_LOCAL_BUCKETS: ${PRIMARY_STORAGE_ARE_LOCAL_BUCKETS:-false} - ENTE_S3_B2_EU_CEN_USE_PATH_STYLE_URLS: ${PRIMARY_STORAGE_USE_PATH_STYLE_URLS:-false} - - ENTE_S3_WASABI_EU_CENTRAL_2_V3_KEY: ${SERVICE_USER_MINIO} - ENTE_S3_WASABI_EU_CENTRAL_2_V3_SECRET: ${SERVICE_PASSWORD_MINIO} - ENTE_S3_WASABI_EU_CENTRAL_2_V3_ENDPOINT: ${SERVICE_URL_MINIO}:3200 - ENTE_S3_WASABI_EU_CENTRAL_2_V3_REGION: ${SECONDARY_STORAGE_REGION:-eu-central-2} - ENTE_S3_WASABI_EU_CENTRAL_2_V3_BUCKET: ${SECONDARY_STORAGE_BUCKET:-wasabi-eu-central-2-v3} - ENTE_S3_WASABI_EU_CENTRAL_2_V3_ARE_LOCAL_BUCKETS: ${SECONDARY_STORAGE_ARE_LOCAL_BUCKETS:-false} - ENTE_S3_WASABI_EU_CENTRAL_2_V3_USE_PATH_STYLE_URLS: ${SECONDARY_STORAGE_USE_PATH_STYLE_URLS:-false} - ENTE_S3_WASABI_EU_CENTRAL_2_V3_COMPLIANCE: ${SECONDARY_STORAGE_COMPLIANCE:-true} - - ENTE_S3_SCW_EU_FR_V3_KEY: ${SERVICE_USER_MINIO} - ENTE_S3_SCW_EU_FR_V3_SECRET: ${SERVICE_PASSWORD_MINIO} - ENTE_S3_SCW_EU_FR_V3_ENDPOINT: ${SERVICE_URL_MINIO}:3200 - ENTE_S3_SCW_EU_FR_V3_REGION: ${SECONDARY_STORAGE_REGION:-eu-central-2} - ENTE_S3_SCW_EU_FR_V3_BUCKET: ${COLD_STORAGE_BUCKET:-scw-eu-fr-v3} - ENTE_S3_SCW_EU_FR_V3_ARE_LOCAL_BUCKETS: ${COLD_STORAGE_ARE_LOCAL_BUCKETS:-true} - ENTE_S3_SCW_EU_FR_V3_USE_PATH_STYLE_URLS: ${COLD_STORAGE_USE_PATH_STYLE_URLS:-true} + - ENTE_S3_B2_EU_CEN_ARE_LOCAL_BUCKETS=${PRIMARY_STORAGE_ARE_LOCAL_BUCKETS:-false} + - ENTE_S3_B2_EU_CEN_USE_PATH_STYLE_URLS=${PRIMARY_STORAGE_USE_PATH_STYLE_URLS:-true} + - ENTE_S3_B2_EU_CEN_KEY=${S3_STORAGE_KEY:?} + - ENTE_S3_B2_EU_CEN_SECRET=${S3_STORAGE_SECRET:?} + - ENTE_S3_B2_EU_CEN_ENDPOINT=${S3_STORAGE_ENDPOINT:?} + - ENTE_S3_B2_EU_CEN_REGION=${S3_STORAGE_REGION:us-east-1} + - ENTE_S3_B2_EU_CEN_BUCKET=${S3_STORAGE_BUCKET:?} depends_on: postgres: condition: service_healthy - minio: - condition: service_healthy volumes: - museum-data:/data:rw healthcheck: - test: ["CMD", "curl", "--fail", "http://localhost:8081/ping"] + test: ["CMD", "wget", "-qO-", "http://localhost:8080/ping"] interval: 60s timeout: 5s retries: 3 start_period: 10s restart: unless-stopped - networks: - - ente-network - - socat: - image: alpine/socat - network_mode: service:museum - depends_on: [museum] - command: "TCP-LISTEN:3200,fork,reuseaddr TCP:minio:3200" - restart: unless-stopped web: image: ghcr.io/ente-io/web - # ports: - # - 3000:3000 # Photos web app - # - 3001:3001 # Accounts - # - 3002:3002 # Public albums - # - 3003:3003 # Auth - # - 3004:3004 # Cast environment: - ENTE_API_ORIGIN: ${SERVICE_URL_MUSEUM:-http://localhost}:8081 - SERVICE_URL_WEB_3000: ${SERVICE_URL_WEB_3000:-http://localhost:3000} - ENTE_ALBUMS_ORIGIN: ${SERVICE_URL_WEB_3002:-http://localhost:3002} - SERVICE_URL_WEB_3001: ${SERVICE_URL_WEB_3001:-http://localhost:3001} - SERVICE_URL_WEB_3003: ${SERVICE_URL_WEB_3003:-http://localhost:3003} - SERVICE_URL_WEB_3004: ${SERVICE_URL_WEB_3004:-http://localhost:3004} + - SERVICE_URL_WEB_3000 + - ENTE_API_ORIGIN=${SERVICE_URL_MUSEUM} + - ENTE_ALBUMS_ORIGIN=${SERVICE_URL_WEB_3002} restart: unless-stopped healthcheck: @@ -117,8 +65,6 @@ services: timeout: 10s retries: 3 start_period: 10s - networks: - - ente-network postgres: image: postgres:15 @@ -129,61 +75,13 @@ services: volumes: - postgres-data:/var/lib/postgresql/data healthcheck: - test: - [ - "CMD-SHELL", - "pg_isready -U ${SERVICE_USER_POSTGRES:-pguser} -d ${SERVICE_DB_NAME:-ente_db}", - ] + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 5 start_period: 30s restart: unless-stopped - networks: - - ente-network - - minio: - image: minio/minio - ports: - - 3200:3200 - environment: - SERVICE_URL_MINIO_3200: ${SERVICE_URL_MINIO_3200} - MINIO_ROOT_USER: ${SERVICE_USER_MINIO} - MINIO_ROOT_PASSWORD: ${SERVICE_PASSWORD_MINIO} - command: server /data --address ":3200" --console-address ":3201" - volumes: - - minio-data:/data - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3200/minio/health/live"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 30s - post_start: - - command: | - sh -c ' - #!/bin/sh - - while ! mc alias set h0 http://minio:3200 ${SERVICE_USER_MINIO} ${SERVICE_PASSWORD_MINIO} 2>/dev/null - do - echo "Waiting for minio..." - sleep 0.5 - done - - cd /data - - mc mb -p b2-eu-cen - mc mb -p wasabi-eu-central-2-v3 - mc mb -p scw-eu-fr-v3 - ' - networks: - - ente-network volumes: postgres-data: - minio-data: museum-data: - -networks: - ente-network: - name: ente-network From 32ed4cbe6d34d90176683060156d904fe09c9842 Mon Sep 17 00:00:00 2001 From: thesloppyguy Date: Sat, 6 Sep 2025 04:05:14 +0530 Subject: [PATCH 016/111] Fix: Product hunt Ente Logo --- public/svgs/ente.png | Bin 5096 -> 8770 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/svgs/ente.png b/public/svgs/ente.png index 737149125b4e84d6277bb4853494ae3ac4fe17bd..f510a7bf7d3dd0fedb2e85d510bd3d99ecda1a5a 100644 GIT binary patch literal 8770 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 From 9289730cd9fe03a939dfdf693435559d7c645ff2 Mon Sep 17 00:00:00 2001 From: thesloppyguy Date: Sat, 6 Sep 2025 10:32:49 +0530 Subject: [PATCH 017/111] Removed Restart Condition. --- templates/compose/ente.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/templates/compose/ente.yaml b/templates/compose/ente.yaml index 78ca81418..2da68c636 100644 --- a/templates/compose/ente.yaml +++ b/templates/compose/ente.yaml @@ -49,7 +49,6 @@ services: timeout: 5s retries: 3 start_period: 10s - restart: unless-stopped web: image: ghcr.io/ente-io/web @@ -58,7 +57,6 @@ services: - ENTE_API_ORIGIN=${SERVICE_URL_MUSEUM} - ENTE_ALBUMS_ORIGIN=${SERVICE_URL_WEB_3002} - restart: unless-stopped healthcheck: test: ["CMD", "curl", "--fail", "http://localhost:3000"] interval: 30s @@ -80,7 +78,6 @@ services: timeout: 5s retries: 5 start_period: 30s - restart: unless-stopped volumes: postgres-data: From e6798ebf5e8d7181de0ce9f0cdf40d91a21d1f88 Mon Sep 17 00:00:00 2001 From: thesloppyguy Date: Mon, 8 Sep 2025 02:23:40 +0530 Subject: [PATCH 018/111] fix: region env variable --- templates/compose/ente.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/compose/ente.yaml b/templates/compose/ente.yaml index 2da68c636..41b0c19cd 100644 --- a/templates/compose/ente.yaml +++ b/templates/compose/ente.yaml @@ -35,7 +35,7 @@ services: - ENTE_S3_B2_EU_CEN_KEY=${S3_STORAGE_KEY:?} - ENTE_S3_B2_EU_CEN_SECRET=${S3_STORAGE_SECRET:?} - ENTE_S3_B2_EU_CEN_ENDPOINT=${S3_STORAGE_ENDPOINT:?} - - ENTE_S3_B2_EU_CEN_REGION=${S3_STORAGE_REGION:us-east-1} + - ENTE_S3_B2_EU_CEN_REGION=${S3_STORAGE_REGION:-us-east-1} - ENTE_S3_B2_EU_CEN_BUCKET=${S3_STORAGE_BUCKET:?} depends_on: From 57a1e7a076bc358d125fafe881f3ebf4673e4f76 Mon Sep 17 00:00:00 2001 From: SAHIL Date: Sun, 14 Sep 2025 20:07:40 +0530 Subject: [PATCH 019/111] Fix: Remove volumes --- templates/compose/ente.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/templates/compose/ente.yaml b/templates/compose/ente.yaml index 41b0c19cd..355b55b1c 100644 --- a/templates/compose/ente.yaml +++ b/templates/compose/ente.yaml @@ -79,6 +79,3 @@ services: retries: 5 start_period: 30s -volumes: - postgres-data: - museum-data: From aea61bcb7ace07e4af9621bb81f4b37e4e3381ee Mon Sep 17 00:00:00 2001 From: ShadowArcanist <162910371+ShadowArcanist@users.noreply.github.com> Date: Fri, 26 Sep 2025 20:56:45 +0530 Subject: [PATCH 020/111] Fixed server pub base url for elastic kibana service --- templates/compose/elasticsearch-with-kibana.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/compose/elasticsearch-with-kibana.yaml b/templates/compose/elasticsearch-with-kibana.yaml index b04594690..f200d2813 100644 --- a/templates/compose/elasticsearch-with-kibana.yaml +++ b/templates/compose/elasticsearch-with-kibana.yaml @@ -35,7 +35,7 @@ services: - 'KIBANA_PASSWORD=${SERVICE_PASSWORD_KIBANA}' - 'ELASTICSEARCH_SERVICEACCOUNTTOKEN=${ELASTICSEARCH_SERVICEACCOUNTTOKEN}' # Kibana authenticates to Elasticsearch using this service token - 'SERVER_NAME=${SERVICE_FQDN_KIBANA}' # For generating links and setting cookie domains - - 'SERVER_PUBLICBASEURL=${SERVICE_URL_KIBANA}' # Public URL used in generated links (reporting, alerting, etc.) + - 'SERVER_PUBLICBASEURL=${SERVICE_FQDN_KIBANA}' # Public URL used in generated links (reporting, alerting, etc.) - 'ELASTICSEARCH_HOSTS=http://elasticsearch:9200' # Connect Kibana to Elasticsearch Service - XPACK.SECURITY.ENABLED=true # Enable authentication and authorization (required for service tokens, roles, etc.) - 'XPACK_SECURITY_ENCRYPTIONKEY=${SERVICE_PASSWORD_XPACKSECURITY}' # Required for encrypted session & auth tokens From 9dd8709407c62de2b971a855028f8b7ef2398049 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 29 Sep 2025 10:52:08 +0000 Subject: [PATCH 021/111] docs: update changelog --- CHANGELOG.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04b99c646..3447b223b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,40 @@ # Changelog ## [unreleased] +### 🚀 Features + +- *(application)* Implement order-based pattern matching for watch paths with negation support +- *(github)* Enhance Docker Compose input fields for better user experience +- *(dev-seeders)* Add PersonalAccessTokenSeeder to create development API tokens +- *(application)* Add conditional .env file creation for Symfony apps during PHP deployment +- *(application)* Enhance watch path parsing to support negation syntax +- *(application)* Add normalizeWatchPaths method to improve watch path handling +- *(validation)* Enhance ValidGitRepositoryUrl to support additional safe characters and add comprehensive unit tests for various Git repository URL formats +- *(deployment)* Implement detection for Laravel/Symfony frameworks and configure NIXPACKS PHP environment variables accordingly + ### 🐛 Bug Fixes -- *(docker)* Adjust openssh-client installation in Dockerfile to avoid version bug -- *(docker)* Streamline openssh-client installation in Dockerfile +- *(application)* Restrict GitHub-based application settings to non-public repositories +- *(traits)* Update saved_outputs handling in ExecuteRemoteCommand to use collection methods for better performance +- *(application)* Enhance domain handling by replacing both dots and dashes with underscores for HTML form binding +- *(constants)* Reduce command timeout from 7200 to 3600 seconds for improved performance +- *(github)* Update repository URL to point to the v4.x branch for development +- *(models)* Update sorting of scheduled database backups to order by creation date instead of name +- *(socialite)* Add custom base URL support for GitLab provider in OAuth settings +- *(configuration-checker)* Update message to clarify redeployment requirement for configuration changes +- *(application)* Reduce docker stop timeout from 30 to 10 seconds for improved application shutdown efficiency +- *(application)* Increase docker stop timeout from 10 to 30 seconds for better application shutdown handling +- *(validation)* Update git:// URL validation to support port numbers and tilde characters in paths +- Resolve scroll lock issue after closing quick search modal with escape key +- Prevent quick search modal duplication from keyboard shortcuts + +### 🚜 Refactor + +- *(tests)* Simplify matchWatchPaths tests and update implementation for better clarity +- *(deployment)* Improve environment variable handling in ApplicationDeploymentJob +- *(deployment)* Remove commented-out code and streamline environment variable handling in ApplicationDeploymentJob +- *(application)* Improve handling of docker compose domains by normalizing keys and ensuring valid JSON structure +- *(forms)* Update wire:model bindings to use 'blur' instead of 'blur-sm' for input fields across multiple views ### 📚 Documentation @@ -15,20 +45,58 @@ ### 📚 Documentation ### ⚙️ Miscellaneous Tasks -- *(versions)* Increment coolify version numbers to 4.0.0-beta.431 and 4.0.0-beta.432 in configuration files +- *(application)* Remove debugging statement from loadComposeFile method +- *(workflows)* Update Claude GitHub Action configuration to support new event types and improve permissions + +## [4.0.0-beta.431] - 2025-09-24 + +### 📚 Documentation + +- Update changelog ## [4.0.0-beta.430] - 2025-09-24 +### 🚀 Features + +- *(add-watch-paths-for-services)* Show watch paths field for docker compose applications + ### 🐛 Bug Fixes - *(PreviewCompose)* Adds port to preview urls - *(deployment-job)* Enhance build time variable analysis +- *(docker)* Adjust openssh-client installation in Dockerfile to avoid version bug +- *(docker)* Streamline openssh-client installation in Dockerfile +- *(team)* Normalize email case in invite link generation +- *(README)* Update Juxtdigital description to reflect current services +- *(environment-variable-warning)* Enhance warning logic to check for problematic variable values +- *(install)* Ensure proper quoting of environment file paths to prevent issues with spaces +- *(security)* Implement authorization checks for terminal access management +- *(ui)* Improve mobile sidebar close behavior + +### 🚜 Refactor + +- *(installer)* Improve install script +- *(upgrade)* Improve upgrade script +- *(installer, upgrade)* Enhance environment variable management +- *(upgrade)* Enhance logging and quoting in upgrade scripts +- *(upgrade)* Replace warning div with a callout component for better UI consistency +- *(ui)* Replace warning and error divs with callout components for improved consistency and readability +- *(ui)* Improve styling and consistency in environment variable warning and docker cleanup components +- *(security)* Streamline update check functionality and improve UI button interactions in patches view ### 📚 Documentation - Update changelog - Update changelog +### ⚙️ Miscellaneous Tasks + +- *(versions)* Increment coolify version numbers to 4.0.0-beta.431 and 4.0.0-beta.432 in configuration files +- *(versions)* Update coolify version numbers to 4.0.0-beta.432 and 4.0.0-beta.433 in configuration files +- Remove unused files +- Adjust wording +- *(workflow)* Update pull request trigger to pull_request_target and refine permissions for enhanced security + ## [4.0.0-beta.429] - 2025-09-23 ### 🚀 Features @@ -39,6 +107,7 @@ ### 🚀 Features - *(search)* Enable query logging for global search caching - *(environment)* Add dynamic checkbox options for environment variable settings based on user permissions and variable types - *(redaction)* Implement sensitive information redaction in logs and commands +- Improve detection of special network modes - *(api)* Add endpoint to update backup configuration by UUID and backup ID; modify response to include backup id - *(databases)* Enhance backup management API with new endpoints and improved data handling - *(github)* Add GitHub app management endpoints @@ -119,7 +188,6 @@ ## [4.0.0-beta.427] - 2025-09-15 ### 🚀 Features -- Improve detection of special network modes - *(command)* Add option to sync GitHub releases to BunnyCDN and refactor sync logic - *(ui)* Display current version in settings dropdown and update UI accordingly - *(settings)* Add option to restrict PR deployments to repository members and contributors From 11260cb13c1f5ef7e7d02857fae6efae66168f2e Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:06:49 +0200 Subject: [PATCH 022/111] fix(workflows): update CLAUDE API key reference in GitHub Actions workflow --- .github/workflows/claude.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index b0fc41448..bf0e6bedc 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -38,7 +38,7 @@ jobs: id: claude uses: anthropics/claude-code-action@v1 with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + anthropic_api_key: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} # Optional: Customize the trigger phrase (default: @claude) # trigger_phrase: "/claude" From c3027a0c8741a00072324d324b84970656366e96 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:11:18 +0200 Subject: [PATCH 023/111] Update claude.yml --- .github/workflows/claude.yml | 49 +++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index bf0e6bedc..9daf0e90e 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -6,9 +6,7 @@ on: pull_request_review_comment: types: [created] issues: - types: [opened, assigned, labeled] - pull_request: - types: [labeled] + types: [opened, assigned] pull_request_review: types: [submitted] @@ -20,12 +18,12 @@ jobs: (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || (github.event_name == 'issues' && github.event.action == 'labeled' && github.event.label.name == 'Claude') || (github.event_name == 'pull_request' && github.event.action == 'labeled' && github.event.label.name == 'Claude') || - (github.event_name == 'issues' && github.event.action != 'labeled' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) runs-on: ubuntu-latest permissions: - contents: write - pull-requests: write - issues: write + contents: read + pull-requests: read + issues: read id-token: write actions: read # Required for Claude to read CI results on PRs steps: @@ -40,23 +38,28 @@ jobs: with: anthropic_api_key: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + # This is an optional setting that allows Claude to read CI results on PRs + additional_permissions: | + actions: read + + # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4.1) + # model: "claude-opus-4-1-20250805" + # Optional: Customize the trigger phrase (default: @claude) # trigger_phrase: "/claude" - + # Optional: Trigger when specific user is assigned to an issue # assignee_trigger: "claude-bot" - - # Optional: Configure Claude's behavior with CLI arguments - # claude_args: | - # --model claude-opus-4-1-20250805 - # --max-turns 10 - # --allowedTools "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)" - # --system-prompt "Follow our coding standards. Ensure all new code has tests. Use TypeScript for new files." - - # Optional: Advanced settings configuration - # settings: | - # { - # "env": { - # "NODE_ENV": "test" - # } - # } \ No newline at end of file + + # Optional: Allow Claude to run specific commands + # allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)" + + # Optional: Add custom instructions for Claude to customize its behavior for your project + # custom_instructions: | + # Follow our coding standards + # Ensure all new code has tests + # Use TypeScript for new files + + # Optional: Custom environment variables for Claude + # claude_env: | + # NODE_ENV: test From a897e81566c41c07c545aa70fe5af7257e4be295 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 30 Sep 2025 13:37:03 +0200 Subject: [PATCH 024/111] feat(global-search): integrate projects and environments into global search functionality - Added retrieval and mapping of projects and environments to the global search results. - Enhanced search result structure to include resource counts and descriptions for projects and environments. - Updated the UI to reflect the new search capabilities, improving user experience when searching for resources. --- app/Livewire/GlobalSearch.php | 74 ++++++++- app/Models/Environment.php | 2 + app/Models/Project.php | 2 + app/Traits/ClearsGlobalSearchCache.php | 134 ++++++++++------ .../views/livewire/global-search.blade.php | 150 ++++++++---------- 5 files changed, 231 insertions(+), 131 deletions(-) diff --git a/app/Livewire/GlobalSearch.php b/app/Livewire/GlobalSearch.php index dacc0d4db..15de5d838 100644 --- a/app/Livewire/GlobalSearch.php +++ b/app/Livewire/GlobalSearch.php @@ -3,6 +3,8 @@ namespace App\Livewire; use App\Models\Application; +use App\Models\Environment; +use App\Models\Project; use App\Models\Server; use App\Models\Service; use App\Models\StandaloneClickhouse; @@ -335,11 +337,81 @@ private function loadSearchableItems() ]; }); + // Get all projects + $projects = Project::ownedByCurrentTeam() + ->withCount(['environments', 'applications', 'services']) + ->get() + ->map(function ($project) { + $resourceCount = $project->applications_count + $project->services_count; + $resourceSummary = $resourceCount > 0 + ? "{$resourceCount} resource".($resourceCount !== 1 ? 's' : '') + : 'No resources'; + + return [ + 'id' => $project->id, + 'name' => $project->name, + 'type' => 'project', + 'uuid' => $project->uuid, + 'description' => $project->description, + 'link' => $project->navigateTo(), + 'project' => null, + 'environment' => null, + 'resource_count' => $resourceSummary, + 'environment_count' => $project->environments_count, + 'search_text' => strtolower($project->name.' '.$project->description.' project'), + ]; + }); + + // Get all environments + $environments = Environment::query() + ->whereHas('project', function ($query) { + $query->where('team_id', auth()->user()->currentTeam()->id); + }) + ->with('project') + ->withCount(['applications', 'services']) + ->get() + ->map(function ($environment) { + $resourceCount = $environment->applications_count + $environment->services_count; + $resourceSummary = $resourceCount > 0 + ? "{$resourceCount} resource".($resourceCount !== 1 ? 's' : '') + : 'No resources'; + + // Build description with project context + $descriptionParts = []; + if ($environment->project) { + $descriptionParts[] = "Project: {$environment->project->name}"; + } + if ($environment->description) { + $descriptionParts[] = $environment->description; + } + if (empty($descriptionParts)) { + $descriptionParts[] = $resourceSummary; + } + + return [ + 'id' => $environment->id, + 'name' => $environment->name, + 'type' => 'environment', + 'uuid' => $environment->uuid, + 'description' => implode(' • ', $descriptionParts), + 'link' => route('project.resource.index', [ + 'project_uuid' => $environment->project->uuid, + 'environment_uuid' => $environment->uuid, + ]), + 'project' => $environment->project->name ?? null, + 'environment' => null, + 'resource_count' => $resourceSummary, + 'search_text' => strtolower($environment->name.' '.$environment->description.' '.$environment->project->name.' environment'), + ]; + }); + // Merge all collections $items = $items->merge($applications) ->merge($services) ->merge($databases) - ->merge($servers); + ->merge($servers) + ->merge($projects) + ->merge($environments); return $items->toArray(); }); diff --git a/app/Models/Environment.php b/app/Models/Environment.php index 437be7d87..bfeee01c9 100644 --- a/app/Models/Environment.php +++ b/app/Models/Environment.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Traits\ClearsGlobalSearchCache; use App\Traits\HasSafeStringAttribute; use OpenApi\Attributes as OA; @@ -19,6 +20,7 @@ )] class Environment extends BaseModel { + use ClearsGlobalSearchCache; use HasSafeStringAttribute; protected $guarded = []; diff --git a/app/Models/Project.php b/app/Models/Project.php index 1c46042e3..a9bf76803 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Traits\ClearsGlobalSearchCache; use App\Traits\HasSafeStringAttribute; use OpenApi\Attributes as OA; use Visus\Cuid2\Cuid2; @@ -24,6 +25,7 @@ )] class Project extends BaseModel { + use ClearsGlobalSearchCache; use HasSafeStringAttribute; protected $guarded = []; diff --git a/app/Traits/ClearsGlobalSearchCache.php b/app/Traits/ClearsGlobalSearchCache.php index ae587aa87..b9af70aba 100644 --- a/app/Traits/ClearsGlobalSearchCache.php +++ b/app/Traits/ClearsGlobalSearchCache.php @@ -10,77 +10,119 @@ trait ClearsGlobalSearchCache protected static function bootClearsGlobalSearchCache() { static::saving(function ($model) { - // Only clear cache if searchable fields are being changed - if ($model->hasSearchableChanges()) { - $teamId = $model->getTeamIdForCache(); - if (filled($teamId)) { - GlobalSearch::clearTeamCache($teamId); + try { + // Only clear cache if searchable fields are being changed + if ($model->hasSearchableChanges()) { + $teamId = $model->getTeamIdForCache(); + if (filled($teamId)) { + GlobalSearch::clearTeamCache($teamId); + } } + } catch (\Throwable $e) { + // Silently fail cache clearing - don't break the save operation + ray('Failed to clear global search cache on saving: '.$e->getMessage()); } }); static::created(function ($model) { - // Always clear cache when model is created - $teamId = $model->getTeamIdForCache(); - if (filled($teamId)) { - GlobalSearch::clearTeamCache($teamId); + try { + // Always clear cache when model is created + $teamId = $model->getTeamIdForCache(); + if (filled($teamId)) { + GlobalSearch::clearTeamCache($teamId); + } + } catch (\Throwable $e) { + // Silently fail cache clearing - don't break the create operation + ray('Failed to clear global search cache on creation: '.$e->getMessage()); } }); static::deleted(function ($model) { - // Always clear cache when model is deleted - $teamId = $model->getTeamIdForCache(); - if (filled($teamId)) { - GlobalSearch::clearTeamCache($teamId); + try { + // Always clear cache when model is deleted + $teamId = $model->getTeamIdForCache(); + if (filled($teamId)) { + GlobalSearch::clearTeamCache($teamId); + } + } catch (\Throwable $e) { + // Silently fail cache clearing - don't break the delete operation + ray('Failed to clear global search cache on deletion: '.$e->getMessage()); } }); } private function hasSearchableChanges(): bool { - // Define searchable fields based on model type - $searchableFields = ['name', 'description']; + try { + // Define searchable fields based on model type + $searchableFields = ['name', 'description']; - // Add model-specific searchable fields - if ($this instanceof \App\Models\Application) { - $searchableFields[] = 'fqdn'; - $searchableFields[] = 'docker_compose_domains'; - } elseif ($this instanceof \App\Models\Server) { - $searchableFields[] = 'ip'; - } elseif ($this instanceof \App\Models\Service) { - // Services don't have direct fqdn, but name and description are covered - } - // Database models only have name and description as searchable - - // Check if any searchable field is dirty - foreach ($searchableFields as $field) { - if ($this->isDirty($field)) { - return true; + // Add model-specific searchable fields + if ($this instanceof \App\Models\Application) { + $searchableFields[] = 'fqdn'; + $searchableFields[] = 'docker_compose_domains'; + } elseif ($this instanceof \App\Models\Server) { + $searchableFields[] = 'ip'; + } elseif ($this instanceof \App\Models\Service) { + // Services don't have direct fqdn, but name and description are covered + } elseif ($this instanceof \App\Models\Project || $this instanceof \App\Models\Environment) { + // Projects and environments only have name and description as searchable } - } + // Database models only have name and description as searchable - return false; + // Check if any searchable field is dirty + foreach ($searchableFields as $field) { + // Check if attribute exists before checking if dirty + if (array_key_exists($field, $this->getAttributes()) && $this->isDirty($field)) { + return true; + } + } + + return false; + } catch (\Throwable $e) { + // If checking changes fails, assume changes exist to be safe + ray('Failed to check searchable changes: '.$e->getMessage()); + + return true; + } } private function getTeamIdForCache() { - // For database models, team is accessed through environment.project.team - if (method_exists($this, 'team')) { - if ($this instanceof \App\Models\Server) { - $team = $this->team; - } else { - $team = $this->team(); + try { + // For Project models (has direct team_id) + if ($this instanceof \App\Models\Project) { + return $this->team_id ?? null; } - if (filled($team)) { - return is_object($team) ? $team->id : null; + + // For Environment models (get team_id through project) + if ($this instanceof \App\Models\Environment) { + return $this->project?->team_id; } - } - // For models with direct team_id property - if (property_exists($this, 'team_id') || isset($this->team_id)) { - return $this->team_id; - } + // For database models, team is accessed through environment.project.team + if (method_exists($this, 'team')) { + if ($this instanceof \App\Models\Server) { + $team = $this->team; + } else { + $team = $this->team(); + } + if (filled($team)) { + return is_object($team) ? $team->id : null; + } + } - return null; + // For models with direct team_id property + if (property_exists($this, 'team_id') || isset($this->team_id)) { + return $this->team_id ?? null; + } + + return null; + } catch (\Throwable $e) { + // If we can't determine team ID, return null + ray('Failed to get team ID for cache: '.$e->getMessage()); + + return null; + } } } diff --git a/resources/views/livewire/global-search.blade.php b/resources/views/livewire/global-search.blade.php index 0b9b61da4..2addf6f64 100644 --- a/resources/views/livewire/global-search.blade.php +++ b/resources/views/livewire/global-search.blade.php @@ -80,41 +80,42 @@ + From 890f0765726021f534e9bbd04da21e311ad1c43f Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 30 Sep 2025 15:13:14 +0200 Subject: [PATCH 025/111] refactor(dashboard): replace project navigation method with direct link in UI - Removed the navigateToProject method from the Livewire component. - Updated the dashboard view to use anchor tags for project navigation, enhancing user experience and simplifying the code structure. --- app/Livewire/Dashboard.php | 5 ----- resources/views/livewire/dashboard.blade.php | 12 ++++++------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/app/Livewire/Dashboard.php b/app/Livewire/Dashboard.php index 45781af30..a78804a16 100644 --- a/app/Livewire/Dashboard.php +++ b/app/Livewire/Dashboard.php @@ -23,11 +23,6 @@ public function mount() $this->projects = Project::ownedByCurrentTeam()->get(); } - public function navigateToProject($projectUuid) - { - return $this->redirect(collect($this->projects)->firstWhere('uuid', $projectUuid)->navigateTo(), navigate: false); - } - public function render() { return view('livewire.dashboard'); diff --git a/resources/views/livewire/dashboard.blade.php b/resources/views/livewire/dashboard.blade.php index 67beb3aa7..2c581850d 100644 --- a/resources/views/livewire/dashboard.blade.php +++ b/resources/views/livewire/dashboard.blade.php @@ -19,8 +19,8 @@ @if ($projects->count() > 0)
@foreach ($projects as $project) -
+
+
{{ $project->name }}
@@ -28,20 +28,20 @@ {{ $project->description }}
-
+
@if ($project->environments->first()) @can('createAnyResource') - - + Add Resource + + Add Resource @endcan @endif @can('update', $project) - Settings From 25a7be23a97e6db3717f10751a1adb1b55f7e6d9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 1 Oct 2025 08:23:21 +0200 Subject: [PATCH 026/111] ui(storage): enhance file storage management with new properties and UI improvements - Added properties to manage file and directory counts, improving data handling in the Livewire component. - Updated the file storage view to include a tabbed interface for volumes, files, and directories, enhancing user navigation. - Improved UI layout for better readability and user experience, including consistent styling and informative messages. --- app/Livewire/Project/Service/Storage.php | 27 +++- .../project/service/file-storage.blade.php | 134 +++++++++--------- .../project/service/storage.blade.php | 125 ++++++++++++---- .../project/shared/storages/show.blade.php | 2 +- 4 files changed, 191 insertions(+), 97 deletions(-) diff --git a/app/Livewire/Project/Service/Storage.php b/app/Livewire/Project/Service/Storage.php index 26cd54425..fb7da1184 100644 --- a/app/Livewire/Project/Service/Storage.php +++ b/app/Livewire/Project/Service/Storage.php @@ -39,7 +39,32 @@ public function refreshStoragesFromEvent() public function refreshStorages() { $this->fileStorage = $this->resource->fileStorages()->get(); - $this->dispatch('$refresh'); + $this->resource->refresh(); + } + + public function getFilesProperty() + { + return $this->fileStorage->where('is_directory', false); + } + + public function getDirectoriesProperty() + { + return $this->fileStorage->where('is_directory', true); + } + + public function getVolumeCountProperty() + { + return $this->resource->persistentStorages()->count(); + } + + public function getFileCountProperty() + { + return $this->files->count(); + } + + public function getDirectoryCountProperty() + { + return $this->directories->count(); } public function addNewVolume($data) diff --git a/resources/views/livewire/project/service/file-storage.blade.php b/resources/views/livewire/project/service/file-storage.blade.php index aa0ce66a3..3aa24b087 100644 --- a/resources/views/livewire/project/service/file-storage.blade.php +++ b/resources/views/livewire/project/service/file-storage.blade.php @@ -1,73 +1,75 @@ -
-
-
- - +
+
+
+
+ + +
-
-
- @can('update', $resource) -
- @if ($fileStorage->is_directory) - - - @else - @if (!$fileStorage->is_binary) - + @can('update', $resource) +
+ @if ($fileStorage->is_directory) + + shortConfirmationLabel="Filepath" :confirmWithPassword="false" step2ButtonText="Convert to file" /> + + @else + @if (!$fileStorage->is_binary) + + @endif + Load from server + @endif - Load from server - - @endif -
- @endcan - @if (!$fileStorage->is_directory) - @can('update', $resource) - @if (data_get($resource, 'settings.is_preserve_repository_enabled')) -
- -
- @endif - - @if (!$fileStorage->is_based_on_git && !$fileStorage->is_binary) - Save - @endif - @else - @if (data_get($resource, 'settings.is_preserve_repository_enabled')) -
- -
- @endif - +
@endcan - @endif -
+ @if (!$fileStorage->is_directory) + @can('update', $resource) + @if (data_get($resource, 'settings.is_preserve_repository_enabled')) +
+ +
+ @endif + + @if (!$fileStorage->is_based_on_git && !$fileStorage->is_binary) + Save + @endif + @else + @if (data_get($resource, 'settings.is_preserve_repository_enabled')) +
+ +
+ @endif + + @endcan + @endif + +
diff --git a/resources/views/livewire/project/service/storage.blade.php b/resources/views/livewire/project/service/storage.blade.php index 41d48f386..56a52a566 100644 --- a/resources/views/livewire/project/service/storage.blade.php +++ b/resources/views/livewire/project/service/storage.blade.php @@ -1,4 +1,4 @@ -
+
@if ( $resource->getMorphClass() == 'App\Models\Application' || $resource->getMorphClass() == 'App\Models\StandalonePostgresql' || @@ -9,50 +9,117 @@ $resource->getMorphClass() == 'App\Models\StandaloneClickhouse' || $resource->getMorphClass() == 'App\Models\StandaloneMongodb' || $resource->getMorphClass() == 'App\Models\StandaloneMysql') -
-

Storages

- - @if ($resource?->build_pack !== 'dockercompose') - @can('update', $resource) - - - - @endcan - @endif +
+
+

Storages

+ + @if ($resource?->build_pack !== 'dockercompose') + @can('update', $resource) + + + + @endcan + @endif +
+
Persistent storage to preserve data between deployments.
-
Persistent storage to preserve data between deployments.
@if ($resource?->build_pack === 'dockercompose') - Please modify storage layout in your Docker Compose - file or reload the compose file to reread the storage layout. +
Please modify storage layout in your Docker Compose + file or reload the compose file to reread the storage layout.
@else @if ($resource->persistentStorages()->get()->count() === 0 && $fileStorage->count() == 0) -
No storage found.
+
No storage found.
@endif @endif - @if ($resource->persistentStorages()->get()->count() > 0) -

Volumes

- - @endif - @if ($fileStorage->count() > 0) -
- @foreach ($fileStorage as $fs) - - @endforeach + @php + $hasVolumes = $this->volumeCount > 0; + $hasFiles = $this->fileCount > 0; + $hasDirectories = $this->directoryCount > 0; + $defaultTab = $hasVolumes ? 'volumes' : ($hasFiles ? 'files' : 'directories'); + @endphp + + @if ($hasVolumes || $hasFiles || $hasDirectories) +
+ {{-- Tabs Navigation --}} +
+ + + +
+ + {{-- Tab Content --}} +
+ {{-- Volumes Tab --}} +
+ @if ($hasVolumes) + + @else +
+ No volumes configured. +
+ @endif +
+ + {{-- Files Tab --}} +
+ @if ($hasFiles) + @foreach ($this->files as $fs) + + @endforeach + @else +
+ No file mounts configured. +
+ @endif +
+ + {{-- Directories Tab --}} +
+ @if ($hasDirectories) + @foreach ($this->directories as $fs) + + @endforeach + @else +
+ No directory mounts configured. +
+ @endif +
+
@endif @else @if ($resource->persistentStorages()->get()->count() > 0) -

{{ Str::headline($resource->name) }}

+

{{ Str::headline($resource->name) }}

@endif @if ($resource->persistentStorages()->get()->count() > 0) @endif @if ($fileStorage->count() > 0) -
+
@foreach ($fileStorage->sort() as $fileStorage) diff --git a/resources/views/livewire/project/shared/storages/show.blade.php b/resources/views/livewire/project/shared/storages/show.blade.php index 569df0c4b..8c0ba0c06 100644 --- a/resources/views/livewire/project/shared/storages/show.blade.php +++ b/resources/views/livewire/project/shared/storages/show.blade.php @@ -1,5 +1,5 @@
-
+ @if ($isReadOnly) @if ($isFirst)
From bed7ad833eaa5aea5da532cd4844fd23aa235409 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 1 Oct 2025 08:23:35 +0200 Subject: [PATCH 027/111] ui(core): update projects property type and enhance UI styling - Changed the projects property in the Dashboard component from an array to a Collection for improved data handling. - Added new color variables in CSS for better theming options. - Updated button styles across various components for consistency and improved user experience. - Refined dropdown and notification components for better visual alignment and usability. --- app/Livewire/Dashboard.php | 2 +- resources/css/app.css | 7 +++++-- resources/css/utilities.css | 8 ++++---- resources/views/components/dropdown.blade.php | 3 ++- resources/views/livewire/dashboard.blade.php | 2 +- resources/views/livewire/global-search.blade.php | 2 +- resources/views/livewire/notifications/email.blade.php | 4 ++-- .../views/livewire/project/application/rollback.blade.php | 2 +- resources/views/livewire/project/index.blade.php | 2 +- .../views/livewire/project/shared/destination.blade.php | 4 ++-- resources/views/livewire/project/show.blade.php | 2 +- resources/views/livewire/settings-dropdown.blade.php | 2 +- 12 files changed, 22 insertions(+), 18 deletions(-) diff --git a/app/Livewire/Dashboard.php b/app/Livewire/Dashboard.php index a78804a16..57ecaa8a2 100644 --- a/app/Livewire/Dashboard.php +++ b/app/Livewire/Dashboard.php @@ -10,7 +10,7 @@ class Dashboard extends Component { - public $projects = []; + public Collection $projects; public Collection $servers; diff --git a/resources/css/app.css b/resources/css/app.css index 77fa2d66b..aad02d71b 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -20,8 +20,11 @@ @theme { --color-warning: #fcd452; --color-success: #16a34a; --color-error: #dc2626; + --color-coollabs-50: #f5f0ff; --color-coollabs: #6b16ed; --color-coollabs-100: #7317ff; + --color-coollabs-200: #5a12c7; + --color-coollabs-300: #4a0fa3; --color-coolgray-100: #181818; --color-coolgray-200: #202020; --color-coolgray-300: #242424; @@ -91,11 +94,11 @@ option { } button[isError]:not(:disabled) { - @apply text-white bg-red-600 hover:bg-red-700; + @apply text-red-800 dark:text-red-300 bg-red-50 dark:bg-red-900/30 border-red-300 dark:border-red-800 hover:bg-red-300 hover:text-white dark:hover:bg-red-800 dark:hover:text-white; } button[isHighlighted]:not(:disabled) { - @apply text-white bg-coollabs hover:bg-coollabs-100; + @apply text-coollabs-200 dark:text-white bg-coollabs-50 dark:bg-coollabs/20 border-coollabs dark:border-coollabs-100 hover:bg-coollabs hover:text-white dark:hover:bg-coollabs-100 dark:hover:text-white; } h1 { diff --git a/resources/css/utilities.css b/resources/css/utilities.css index cbbe2ef8e..c82b26b0c 100644 --- a/resources/css/utilities.css +++ b/resources/css/utilities.css @@ -63,7 +63,7 @@ @utility select { } @utility button { - @apply flex gap-2 justify-center items-center px-2 py-1 text-sm text-black normal-case rounded-sm border outline-0 cursor-pointer bg-neutral-200/50 border-neutral-300 hover:bg-neutral-300 dark:bg-coolgray-200 dark:text-white dark:hover:text-white dark:hover:bg-coolgray-500 dark:border-coolgray-300 hover:text-black disabled:cursor-not-allowed min-w-fit dark:disabled:text-neutral-600 disabled:border-transparent disabled:hover:bg-transparent disabled:bg-transparent disabled:text-neutral-300; + @apply flex gap-2 justify-center items-center px-2 h-8 text-sm text-black normal-case rounded-sm border-2 outline-0 cursor-pointer font-medium bg-white border-neutral-200 hover:bg-neutral-100 dark:bg-coolgray-100 dark:text-white dark:hover:text-white dark:hover:bg-coolgray-200 dark:border-coolgray-300 hover:text-black disabled:cursor-not-allowed min-w-fit dark:disabled:text-neutral-600 disabled:border-transparent disabled:hover:bg-transparent disabled:bg-transparent disabled:text-neutral-300; } @utility alert-success { @@ -155,15 +155,15 @@ @utility kbd-custom { } @utility box { - @apply relative flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 shadow-sm bg-white border text-black dark:text-white hover:text-black border-neutral-200 dark:border-black hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:no-underline; + @apply relative flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 shadow-sm bg-white border text-black dark:text-white hover:text-black border-neutral-200 dark:border-coolgray-300 hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:no-underline rounded-sm; } @utility box-boarding { - @apply flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 dark:text-white bg-neutral-50 border border-neutral-200 dark:border-black hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:text-black hover:no-underline text-black; + @apply flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem] dark:bg-coolgray-100 dark:text-white bg-neutral-50 border border-neutral-200 dark:border-coolgray-300 hover:bg-neutral-100 dark:hover:bg-coollabs-100 dark:hover:text-white hover:text-black hover:no-underline text-black rounded-sm; } @utility box-without-bg { - @apply flex p-2 transition-colors dark:hover:text-white hover:no-underline min-h-[4rem] border border-neutral-200 dark:border-black; + @apply flex p-2 transition-colors dark:hover:text-white hover:no-underline min-h-[4rem] border border-neutral-200 dark:border-coolgray-300 rounded-sm; } @utility box-without-bg-without-border { diff --git a/resources/views/components/dropdown.blade.php b/resources/views/components/dropdown.blade.php index cba60c550..666b93dbc 100644 --- a/resources/views/components/dropdown.blade.php +++ b/resources/views/components/dropdown.blade.php @@ -16,7 +16,8 @@ class="inline-flex items-center justify-start pr-8 transition-colors focus:outli
-
+
{{ $slot }}
diff --git a/resources/views/livewire/dashboard.blade.php b/resources/views/livewire/dashboard.blade.php index 2c581850d..7a0cbec4a 100644 --- a/resources/views/livewire/dashboard.blade.php +++ b/resources/views/livewire/dashboard.blade.php @@ -19,7 +19,7 @@ @if ($projects->count() > 0)
@foreach ($projects as $project) -
+
diff --git a/resources/views/livewire/global-search.blade.php b/resources/views/livewire/global-search.blade.php index 2addf6f64..aae371b84 100644 --- a/resources/views/livewire/global-search.blade.php +++ b/resources/views/livewire/global-search.blade.php @@ -102,7 +102,7 @@ class="fixed top-0 left-0 z-99 flex items-start justify-center w-screen h-screen + class="w-full pl-12 pr-12 py-4 text-base bg-white dark:bg-coolgray-100 border-none rounded-lg shadow-xl ring-1 ring-neutral-200 dark:ring-coolgray-300 focus:ring-2 focus:ring-neutral-400 dark:focus:ring-coolgray-300 dark:text-white placeholder-neutral-400 dark:placeholder-neutral-500" /> + +
+ + / or ⌘K to focus + + +
@@ -154,22 +197,326 @@ class="min-h-[200px] items-center justify-center p-8">
- @if ($isCreateMode && count($creatableItems) > 0 && !$autoOpenResource) + @if ($isSelectingResource) + +
+ + @if ($selectedServerId === null) +
+
+ +
+

+ Select Server +

+ @if ($this->selectedResourceName) +
+ for {{ $this->selectedResourceName }} +
+ @endif +
+
+ @if ($loadingServers) +
+ + + + + + Loading + servers... +
+ @elseif (count($availableServers) > 0) + @foreach ($availableServers as $index => $server) + + @endforeach + @else +
+

No servers + available

+
+ @endif +
+ @endif + + + @if ($selectedServerId !== null && $selectedDestinationUuid === null) +
+
+ +
+

+ Select Destination +

+ @if ($this->selectedResourceName) +
+ for {{ $this->selectedResourceName }} +
+ @endif +
+
+ @if ($loadingDestinations) +
+ + + + + + Loading + destinations... +
+ @elseif (count($availableDestinations) > 0) + @foreach ($availableDestinations as $index => $destination) + + @endforeach + @else +
+

No destinations + available

+
+ @endif +
+ @endif + + + @if ($selectedDestinationUuid !== null && $selectedProjectUuid === null) +
+
+ +
+

+ Select Project +

+ @if ($this->selectedResourceName) +
+ for {{ $this->selectedResourceName }} +
+ @endif +
+
+ @if ($loadingProjects) +
+ + + + + + Loading + projects... +
+ @elseif (count($availableProjects) > 0) + @foreach ($availableProjects as $index => $project) + + @endforeach + @else +
+

No projects + available

+
+ @endif +
+ @endif + + + @if ($selectedProjectUuid !== null && $selectedEnvironmentUuid === null) +
+
+ +
+

+ Select Environment +

+ @if ($this->selectedResourceName) +
+ for {{ $this->selectedResourceName }} +
+ @endif +
+
+ @if ($loadingEnvironments) +
+ + + + + + Loading + environments... +
+ @elseif (count($availableEnvironments) > 0) + @foreach ($availableEnvironments as $index => $environment) + + @endforeach + @else +
+

No environments + available

+
+ @endif +
+ @endif +
+ @elseif ($isCreateMode && count($this->filteredCreatableItems) > 0 && !$autoOpenResource) -
-
+ {{--

Create New Resources @@ -177,96 +524,166 @@ class="px-4 py-2 bg-yellow-50 dark:bg-yellow-900/20 border-b border-yellow-100 d

Click on any item below to create a new resource

-

- @foreach ($creatableItems as $item) - + @endforeach + @endforeach +
+ @elseif (strlen($searchQuery) >= 1 && count($searchResults) > 0) + - - @endforeach -
- @elseif (strlen($searchQuery) >= 2 && count($searchResults) > 0) - @elseif (strlen($searchQuery) >= 2 && count($searchResults) === 0 && !$autoOpenResource) @@ -280,14 +697,6 @@ class="shrink-0 h-5 w-5 text-neutral-300 dark:text-neutral-600 self-center"

- @elseif (strlen($searchQuery) > 0 && strlen($searchQuery) < 2) -
-
-

- Type at least 2 characters to search -

-
-
@endif
From e8b2ef0e0cfca06384c5c86af7e8c632175d031a Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:29:58 +0200 Subject: [PATCH 098/111] fix(modal-confirmation): refine escape key handling to ensure modal closes only when open - Updated the keydown event handler to check if the modal is open before executing the close and reset functions, improving the modal's behavior and user experience. --- resources/views/components/modal-confirmation.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/components/modal-confirmation.blade.php b/resources/views/components/modal-confirmation.blade.php index 1a3c88f80..103f18316 100644 --- a/resources/views/components/modal-confirmation.blade.php +++ b/resources/views/components/modal-confirmation.blade.php @@ -114,7 +114,7 @@ } } }" - @keydown.escape.window="modalOpen = false; resetModal()" :class="{ 'z-40': modalOpen }" + @keydown.escape.window="if (modalOpen) { modalOpen = false; resetModal(); }" :class="{ 'z-40': modalOpen }" class="relative w-auto h-auto"> @if ($customButton) @if ($buttonFullWidth) From afd10048bda450b6bb6bd56a18fea84c6f25fcf9 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:38:38 +0200 Subject: [PATCH 099/111] update globalsearch --- app/Livewire/GlobalSearch.php | 134 ++++++++++-- .../views/livewire/global-search.blade.php | 206 ++++++++++++++---- 2 files changed, 274 insertions(+), 66 deletions(-) diff --git a/app/Livewire/GlobalSearch.php b/app/Livewire/GlobalSearch.php index 33366f418..98571b87f 100644 --- a/app/Livewire/GlobalSearch.php +++ b/app/Livewire/GlobalSearch.php @@ -22,6 +22,8 @@ class GlobalSearch extends Component { public $searchQuery = ''; + private $previousTrimmedQuery = ''; + public $isModalOpen = false; public $searchResults = []; @@ -86,6 +88,7 @@ public function closeSearchModal() { $this->isModalOpen = false; $this->searchQuery = ''; + $this->previousTrimmedQuery = ''; $this->searchResults = []; } @@ -101,25 +104,49 @@ public static function clearTeamCache($teamId) public function updatedSearchQuery() { - $query = strtolower(trim($this->searchQuery)); + $trimmedQuery = trim($this->searchQuery); + + // If only spaces were added/removed, don't trigger a search + if ($trimmedQuery === $this->previousTrimmedQuery) { + return; + } + + $this->previousTrimmedQuery = $trimmedQuery; + + // If search query is empty, just clear results without processing + if (empty($trimmedQuery)) { + $this->searchResults = []; + $this->isCreateMode = false; + $this->creatableItems = []; + $this->autoOpenResource = null; + $this->isSelectingResource = false; + $this->cancelResourceSelection(); + + return; + } + + $query = strtolower($trimmedQuery); // Reset keyboard navigation index $this->dispatch('reset-selected-index'); - if (str_starts_with($query, 'new')) { + // Only enter create mode if query is exactly "new" or starts with "new " (space after) + if ($query === 'new' || str_starts_with($query, 'new ')) { $this->isCreateMode = true; $this->loadCreatableItems(); - $this->searchResults = []; // Check for sub-commands like "new project", "new server", etc. - // Use original query (not trimmed) to ensure exact match without trailing spaces - $detectedType = $this->detectSpecificResource(strtolower($this->searchQuery)); + $detectedType = $this->detectSpecificResource($query); if ($detectedType) { $this->navigateToResource($detectedType); } else { // If no specific resource detected, reset selection state $this->cancelResourceSelection(); } + + // Also search for existing resources that match the query + // This allows users to find resources with "new" in their name + $this->search(); } else { $this->isCreateMode = false; $this->creatableItems = []; @@ -624,6 +651,8 @@ private function search() // Search for matching creatable resources to show as suggestions (if no priority item) if (! $priorityCreatableItem) { $this->loadCreatableItems(); + + // Search in regular creatable items (apps, databases, quick actions) $creatableSuggestions = collect($this->creatableItems) ->filter(function ($item) use ($query) { $searchText = strtolower($item['name'].' '.$item['description'].' '.($item['type'] ?? '')); @@ -648,7 +677,37 @@ private function search() $item['is_creatable_suggestion'] = true; return $item; + }); + + // Also search in services (loaded on-demand) + $serviceSuggestions = collect($this->services) + ->filter(function ($item) use ($query) { + $searchText = strtolower($item['name'].' '.$item['description'].' '.($item['type'] ?? '')); + + return preg_match('/\b'.preg_quote($query, '/').'/i', $searchText); }) + ->map(function ($item) use ($query) { + // Calculate match priority: name > type > description + $name = strtolower($item['name']); + $type = strtolower($item['type'] ?? ''); + $description = strtolower($item['description']); + + if (preg_match('/\b'.preg_quote($query, '/').'/i', $name)) { + $item['match_priority'] = 1; + } elseif (preg_match('/\b'.preg_quote($query, '/').'/i', $type)) { + $item['match_priority'] = 2; + } else { + $item['match_priority'] = 3; + } + + $item['is_creatable_suggestion'] = true; + + return $item; + }); + + // Merge and sort all suggestions + $creatableSuggestions = $creatableSuggestions + ->merge($serviceSuggestions) ->sortBy('match_priority') ->take(10) ->values() @@ -914,31 +973,18 @@ private function loadCreatableItems() ]); } - // === Services Category === - - if ($user->can('createAnyResource')) { - // Load all services - $allServices = get_service_templates(); - - foreach ($allServices as $serviceKey => $service) { - $items->push([ - 'name' => str($serviceKey)->headline()->toString(), - 'description' => data_get($service, 'slogan', 'Deploy '.str($serviceKey)->headline()), - 'type' => 'one-click-service-'.$serviceKey, - 'category' => 'Services', - 'resourceType' => 'service', - ]); - } - } - $this->creatableItems = $items->toArray(); } public function navigateToResource($type) { - // Find the item by type + // Find the item by type - check regular items first, then services $item = collect($this->creatableItems)->firstWhere('type', $type); + if (! $item) { + $item = collect($this->services)->firstWhere('type', $type); + } + if (! $item) { return; } @@ -1227,12 +1273,52 @@ public function getSelectedResourceNameProperty() $this->loadCreatableItems(); } - // Find the item by type + // Find the item by type - check regular items first, then services $item = collect($this->creatableItems)->firstWhere('type', $this->selectedResourceType); + if (! $item) { + $item = collect($this->services)->firstWhere('type', $this->selectedResourceType); + } + return $item ? $item['name'] : null; } + public function getServicesProperty() + { + // Cache services in a static property to avoid reloading on every access + static $cachedServices = null; + + if ($cachedServices !== null) { + return $cachedServices; + } + + $user = auth()->user(); + + if (! $user->can('createAnyResource')) { + $cachedServices = []; + + return $cachedServices; + } + + // Load all services + $allServices = get_service_templates(); + $items = collect(); + + foreach ($allServices as $serviceKey => $service) { + $items->push([ + 'name' => str($serviceKey)->headline()->toString(), + 'description' => data_get($service, 'slogan', 'Deploy '.str($serviceKey)->headline()), + 'type' => 'one-click-service-'.$serviceKey, + 'category' => 'Services', + 'resourceType' => 'service', + ]); + } + + $cachedServices = $items->toArray(); + + return $cachedServices; + } + public function render() { return view('livewire.global-search'); diff --git a/resources/views/livewire/global-search.blade.php b/resources/views/livewire/global-search.blade.php index 0bd833d8e..ad9a9f6ad 100644 --- a/resources/views/livewire/global-search.blade.php +++ b/resources/views/livewire/global-search.blade.php @@ -1,14 +1,20 @@
+ x-init="$watch('modalOpen', value => { if (value) setTimeout(() => $refs.searchInput.focus(), 100) })" :disabled="isLoadingInitialData" + class="w-full pl-12 pr-32 py-4 text-base bg-white dark:bg-coolgray-100 border-none rounded-lg shadow-xl ring-1 ring-neutral-200 dark:ring-coolgray-300 focus:ring-2 focus:ring-neutral-400 dark:focus:ring-coolgray-300 dark:text-white placeholder-neutral-400 dark:placeholder-neutral-500 disabled:opacity-50 disabled:cursor-not-allowed" />
/ or ⌘K to focus @@ -172,31 +212,53 @@ class="pointer-events-auto px-2 py-1 text-xs font-medium text-neutral-500 dark:t
+ +
+
+
+ + + + + +

+ Please wait while we fetch your data +

+
+
+
+ @if (strlen($searchQuery) >= 1)
- -
-
- - - - - -

- Searching... -

+ +
+ +
+ @for ($i = 0; $i < 3; $i++) +
+
+
+
+
+
+
+
+
+
+
+ @endfor
- -
+ +
@if ($isSelectingResource)
@@ -516,15 +578,71 @@ class="p-3 bg-red-50 dark:bg-red-900/20 rounded-lg border border-red-200 dark:bo @elseif ($isCreateMode && count($this->filteredCreatableItems) > 0 && !$autoOpenResource)
- {{--
-

- Create New Resources -

-

- Click on any item below to create a new resource -

-
--}} + {{-- Show existing resources first if any match --}} + @php + $existingResources = collect($searchResults)->filter(fn($r) => !isset($r['is_creatable_suggestion']))->count(); + @endphp + @if ($existingResources > 0) + +
+

+ Existing Resources +

+
+ @foreach ($searchResults as $result) + @if (!isset($result['is_creatable_suggestion'])) + +
+
+
+ + {{ $result['name'] }} + + + @if ($result['type'] === 'application') + Application + @elseif ($result['type'] === 'service') + Service + @elseif ($result['type'] === 'database') + {{ ucfirst($result['subtype'] ?? 'Database') }} + @elseif ($result['type'] === 'server') + Server + @elseif ($result['type'] === 'project') + Project + @elseif ($result['type'] === 'environment') + Environment + @endif + +
+ @if (!empty($result['project']) && !empty($result['environment'])) +
+ {{ $result['project'] }} / + {{ $result['environment'] }} +
+ @endif + @if (!empty($result['description'])) +
+ {{ Str::limit($result['description'], 80) }} +
+ @endif +
+ + + +
+
+ @endif + @endforeach + @endif @php $grouped = collect($this->filteredCreatableItems)->groupBy('category'); @@ -695,6 +813,9 @@ class="shrink-0 h-5 w-5 text-neutral-300 dark:text-neutral-600 self-center"

Try different keywords or check the spelling

+

+ 💡 Tip: Search for service names like "wordpress", "postgres", or "redis" +

@endif @@ -957,4 +1078,5 @@ class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5
+
From 2e6e07bcc310f84838103e14710e27a21e626a51 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 8 Oct 2025 16:53:02 +0200 Subject: [PATCH 100/111] make global search frontend heavy --- app/Livewire/GlobalSearch.php | 4 + .../views/livewire/global-search.blade.php | 1180 +++++++++-------- 2 files changed, 609 insertions(+), 575 deletions(-) diff --git a/app/Livewire/GlobalSearch.php b/app/Livewire/GlobalSearch.php index 98571b87f..e378bd289 100644 --- a/app/Livewire/GlobalSearch.php +++ b/app/Livewire/GlobalSearch.php @@ -81,6 +81,7 @@ public function openSearchModal() { $this->isModalOpen = true; $this->loadSearchableItems(); + $this->loadCreatableItems(); $this->dispatch('search-modal-opened'); } @@ -973,6 +974,9 @@ private function loadCreatableItems() ]); } + // Merge with services + $items = $items->merge(collect($this->services)); + $this->creatableItems = $items->toArray(); } diff --git a/resources/views/livewire/global-search.blade.php b/resources/views/livewire/global-search.blade.php index ad9a9f6ad..95d2640a6 100644 --- a/resources/views/livewire/global-search.blade.php +++ b/resources/views/livewire/global-search.blade.php @@ -3,18 +3,74 @@ selectedIndex: -1, isSearching: false, isLoadingInitialData: false, + allSearchableItems: [], + searchQuery: '', + creatableItems: [], + isCreateMode: false, + + // Client-side search function + get searchResults() { + if (!this.searchQuery || this.searchQuery.length < 1) { + return []; + } + + const query = this.searchQuery.toLowerCase().trim(); + + const results = this.allSearchableItems.filter(item => { + if (!item.search_text) return false; + return item.search_text.toLowerCase().includes(query); + }).slice(0, 20); + + return results; + }, + + get filteredCreatableItems() { + if (!this.searchQuery || this.searchQuery.length < 1) { + return []; + } + const query = this.searchQuery.toLowerCase().trim(); + + if (query === 'new') { + return this.creatableItems; + } + + return this.creatableItems.filter(item => { + const searchText = `${item.name} ${item.description} ${item.type} ${item.category}`.toLowerCase(); + return searchText.includes(query); + }); + }, + + get groupedCreatableItems() { + const grouped = {}; + this.filteredCreatableItems.forEach(item => { + const category = item.category || 'Other'; + if (!grouped[category]) { + grouped[category] = []; + } + grouped[category].push(item); + }); + return grouped; + }, + openModal() { this.modalOpen = true; this.selectedIndex = -1; this.isLoadingInitialData = true; - // Dispatch event to load initial data - $wire.dispatch('loadInitialData'); + this.searchQuery = ''; + $wire.openSearchModal().then(() => { + this.allSearchableItems = $wire.allSearchableItems || []; + this.creatableItems = $wire.creatableItems || []; + this.isLoadingInitialData = false; + setTimeout(() => this.$refs.searchInput?.focus(), 50); + }); }, closeModal() { this.modalOpen = false; this.selectedIndex = -1; this.isSearching = false; this.isLoadingInitialData = false; + this.searchQuery = ''; + this.allSearchableItems = []; // Ensure scroll is restored document.body.style.overflow = ''; @this.closeSearchModal(); @@ -42,43 +98,39 @@ this.selectedIndex = -1; }); - // Listen for loading state changes - $wire.on('loadInitialData', () => { - this.isLoadingInitialData = true; - $wire.openSearchModal().finally(() => { - this.isLoadingInitialData = false; - // Focus input after data is loaded - setTimeout(() => this.$refs.searchInput?.focus(), 50); - }); - }); + this.$watch('searchQuery', (value) => { + this.selectedIndex = -1; + const trimmed = value.trim().toLowerCase(); - // Use Livewire lifecycle hooks for accurate loading state - const componentId = $wire.__instance.id; - - Livewire.hook('message.sent', (message, component) => { - // Only handle messages for this component instance - if (component.id !== componentId) return; - - // Check if this is a searchQuery update - if (message.updateQueue && message.updateQueue.some(update => update.payload.name === 'searchQuery')) { - this.isSearching = true; + if (trimmed === '') { + if ($wire.isSelectingResource) { + $wire.cancelResourceSelection(); + } + return; } - }); - Livewire.hook('message.processed', (message, component) => { - // Only handle messages for this component instance - if (component.id !== componentId) return; + const exactMatchCommands = [ + 'new project', 'new server', 'new team', 'new storage', 'new s3', + 'new private key', 'new privatekey', 'new key', + 'new github app', 'new github', 'new source', + 'new public', 'new public git', 'new public repo', 'new public repository', + 'new private github', 'new private gh', 'new private deploy', 'new deploy key', + 'new dockerfile', 'new docker compose', 'new compose', 'new docker image', 'new image', + 'new postgresql', 'new postgres', 'new mysql', 'new mariadb', + 'new redis', 'new keydb', 'new dragonfly', 'new mongodb', 'new mongo', 'new clickhouse' + ]; - // Check if this was a searchQuery update - if (message.updateQueue && message.updateQueue.some(update => update.payload.name === 'searchQuery')) { - this.isSearching = false; - } - }); + if (exactMatchCommands.includes(trimmed)) { + const matchingItem = this.creatableItems.find(item => { + const itemSearchText = `new ${item.name}`.toLowerCase(); + const itemType = `new ${item.type}`.toLowerCase(); + return itemSearchText === trimmed || itemType === trimmed || + (item.type && trimmed.includes(item.type.replace(/-/g, ' '))); + }); - // Also clear loading state when search is emptied - this.$watch('$wire.searchQuery', (value) => { - if (!value || value.length === 0) { - this.isSearching = false; + if (matchingItem) { + $wire.navigateToResource(matchingItem.type); + } } }); @@ -111,7 +163,7 @@ const escapeKeyHandler = (e) => { if (e.key === 'Escape' && this.modalOpen) { // If search query is empty, close the modal - if (!$wire.searchQuery || $wire.searchQuery === '') { + if (!this.searchQuery || this.searchQuery === '') { // Check if we're in a selection state using Alpine-accessible Livewire state if ($wire.isSelectingResource) { $wire.cancelResourceSelection(); @@ -122,7 +174,7 @@ } } else { // If search query has text, just clear it - $wire.searchQuery = ''; + this.searchQuery = ''; setTimeout(() => this.$refs.searchInput?.focus(), 100); } } @@ -191,13 +243,21 @@ class="fixed top-0 left-0 z-99 flex items-start justify-center w-screen h-screen
- + + + + +
- @@ -212,547 +272,347 @@ class="pointer-events-auto px-2 py-1 text-xs font-medium text-neutral-500 dark:t
- -
-
-
- - - - - -

- Please wait while we fetch your data -

-
+ + {{--
+
+

+ ✓ Data loaded successfully! +

+

+ searchable items available +

+

+ Start typing to search... +

-
+
--}} - @if (strlen($searchQuery) >= 1) -
- -
- -
- @for ($i = 0; $i < 3; $i++) -
-
-
-
-
-
-
+
+ +
+ @if ($isSelectingResource) + +
+ + @if ($selectedServerId === null) +
+
+ +
+

+ Select Server +

+ @if ($this->selectedResourceName) +
+ for {{ $this->selectedResourceName }} +
+ @endif
-
-
- @endfor -
-
- - -
- @if ($isSelectingResource) - -
- - @if ($selectedServerId === null) -
-
+ @if ($loadingServers) +
+ + + + + + Loading + servers... +
+ @elseif (count($availableServers) > 0) + @foreach ($availableServers as $index => $server) -
-

- Select Server -

- @if ($this->selectedResourceName) -
- for {{ $this->selectedResourceName }} -
- @endif -
-
- @if ($loadingServers) -
- - - - - - Loading - servers... -
- @elseif (count($availableServers) > 0) - @foreach ($availableServers as $index => $server) - - @endforeach - @else -
-

No servers - available

-
- @endif -
- @endif - - - @if ($selectedServerId !== null && $selectedDestinationUuid === null) -
-
- -
-

- Select Destination -

- @if ($this->selectedResourceName) -
- for {{ $this->selectedResourceName }} -
- @endif -
-
- @if ($loadingDestinations) -
- - - - - - Loading - destinations... -
- @elseif (count($availableDestinations) > 0) - @foreach ($availableDestinations as $index => $destination) - - @endforeach - @else -
-

No destinations - available

-
- @endif -
- @endif - - - @if ($selectedDestinationUuid !== null && $selectedProjectUuid === null) -
-
- -
-

- Select Project -

- @if ($this->selectedResourceName) -
- for {{ $this->selectedResourceName }} -
- @endif -
-
- @if ($loadingProjects) -
- - - - - - Loading - projects... -
- @elseif (count($availableProjects) > 0) - @foreach ($availableProjects as $index => $project) - - @endforeach - @else -
-

No projects - available

-
- @endif -
- @endif - - - @if ($selectedProjectUuid !== null && $selectedEnvironmentUuid === null) -
-
- -
-

- Select Environment -

- @if ($this->selectedResourceName) -
- for {{ $this->selectedResourceName }} -
- @endif -
-
- @if ($loadingEnvironments) -
- - - - - - Loading - environments... -
- @elseif (count($availableEnvironments) > 0) - @foreach ($availableEnvironments as $index => $environment) - - @endforeach - @else -
-

No environments - available

-
- @endif -
- @endif -
- @elseif ($isCreateMode && count($this->filteredCreatableItems) > 0 && !$autoOpenResource) - -
- {{-- Show existing resources first if any match --}} - @php - $existingResources = collect($searchResults)->filter(fn($r) => !isset($r['is_creatable_suggestion']))->count(); - @endphp - @if ($existingResources > 0) - -
-

- Existing Resources -

-
- @foreach ($searchResults as $result) - @if (!isset($result['is_creatable_suggestion'])) - + wire:click="selectServer({{ $server['id'] }}, true)" + class="search-result-item w-full text-left block px-4 py-3 hover:bg-yellow-50 dark:hover:bg-yellow-900/20 transition-colors focus:outline-none focus:bg-yellow-100 dark:focus:bg-yellow-900/30"> - @elseif (strlen($searchQuery) >= 1 && count($searchResults) > 0) -
- @foreach ($searchResults as $index => $result) - @if (isset($result['is_creatable_suggestion']) && $result['is_creatable_suggestion']) - {{-- Creatable suggestion with yellow theme --}} - + + @endforeach @else - {{-- Regular search result --}} +
+

No servers + available

+
+ @endif +
+ @endif + + + @if ($selectedServerId !== null && $selectedDestinationUuid === null) +
+
+ +
+

+ Select Destination +

+ @if ($this->selectedResourceName) +
+ for {{ $this->selectedResourceName }} +
+ @endif +
+
+ @if ($loadingDestinations) +
+ + + + + + Loading + destinations... +
+ @elseif (count($availableDestinations) > 0) + @foreach ($availableDestinations as $index => $destination) + + @endforeach + @else +
+

No destinations + available

+
+ @endif +
+ @endif + + + @if ($selectedDestinationUuid !== null && $selectedProjectUuid === null) +
+
+ +
+

+ Select Project +

+ @if ($this->selectedResourceName) +
+ for {{ $this->selectedResourceName }} +
+ @endif +
+
+ @if ($loadingProjects) +
+ + + + + + Loading + projects... +
+ @elseif (count($availableProjects) > 0) + @foreach ($availableProjects as $index => $project) + + @endforeach + @else +
+

No projects + available

+
+ @endif +
+ @endif + + + @if ($selectedProjectUuid !== null && $selectedEnvironmentUuid === null) +
+
+ +
+

+ Select Environment +

+ @if ($this->selectedResourceName) +
+ for {{ $this->selectedResourceName }} +
+ @endif +
+
+ @if ($loadingEnvironments) +
+ + + + + + Loading + environments... +
+ @elseif (count($availableEnvironments) > 0) + @foreach ($availableEnvironments as $index => $environment) + + @endforeach + @else +
+

No environments + available

+
+ @endif +
+ @endif +
+ @elseif ($isCreateMode && count($this->filteredCreatableItems) > 0 && !$autoOpenResource) + +
+ {{-- Show existing resources first if any match --}} + @php + $existingResources = collect($searchResults) + ->filter(fn($r) => !isset($r['is_creatable_suggestion'])) + ->count(); + @endphp + @if ($existingResources > 0) + +
+

+ Existing Resources +

+
+ @foreach ($searchResults as $result) + @if (!isset($result['is_creatable_suggestion'])) - @elseif (strlen($searchQuery) >= 2 && count($searchResults) === 0 && !$autoOpenResource) -
-
-

- No results found -

-

- Try different keywords or check the spelling -

-

- 💡 Tip: Search for service names like "wordpress", "postgres", or "redis" -

+ @endif + + @php + $grouped = collect($this->filteredCreatableItems)->groupBy('category'); + @endphp + + @foreach ($grouped as $category => $items) + +
+

+ {{ $category }} +

+ + + @foreach ($items as $item) + + @endforeach + @endforeach +
+ @endif + + + + + +
- @endif +
From 6f086d26dbe053afb3d4700e32a9b6b29faa1572 Mon Sep 17 00:00:00 2001 From: ShadowArcanist <162910371+ShadowArcanist@users.noreply.github.com> Date: Wed, 8 Oct 2025 22:06:07 +0530 Subject: [PATCH 101/111] fix service ente-photos-with-s3 --- templates/compose/ente-photos-with-s3.yaml | 156 ++++++++++++--------- 1 file changed, 86 insertions(+), 70 deletions(-) diff --git a/templates/compose/ente-photos-with-s3.yaml b/templates/compose/ente-photos-with-s3.yaml index 96d74b1a8..844bc673b 100644 --- a/templates/compose/ente-photos-with-s3.yaml +++ b/templates/compose/ente-photos-with-s3.yaml @@ -7,107 +7,123 @@ services: museum: - image: ghcr.io/ente-io/server:latest + image: 'ghcr.io/ente-io/server:613c6a96390d7a624cf30b946955705d632423cc' # Released at 2025-09-14T22:16:37-07:00 environment: - SERVICE_URL_MUSEUM_8080 - - ENTE_HTTP_USE_TLS=${ENTE_HTTP_USE_TLS:-false} - - - ENTE_APPS_PUBLIC_ALBUMS=${SERVICE_URL_WEB_3002} - - ENTE_APPS_CAST=${SERVICE_URL_WEB_3004} - - ENTE_APPS_ACCOUNTS=${SERVICE_URL_WEB_3001} - - - ENTE_DB_HOST=${ENTE_DB_HOST:-postgres} - - ENTE_DB_PORT=${ENTE_DB_PORT:-5432} - - ENTE_DB_NAME=${ENTE_DB_NAME:-ente_db} - - ENTE_DB_USER=${SERVICE_USER_POSTGRES:-pguser} - - ENTE_DB_PASSWORD=${SERVICE_PASSWORD_POSTGRES} - - - ENTE_KEY_ENCRYPTION=${SERVICE_REALBASE64_ENCRYPTION} - - ENTE_KEY_HASH=${SERVICE_REALBASE64_64_HASH} - - - ENTE_JWT_SECRET=${SERVICE_REALBASE64_JWT} - - - ENTE_INTERNAL_ADMIN=${ENTE_INTERNAL_ADMIN:-1580559962386438} - - ENTE_INTERNAL_DISABLE_REGISTRATION=${ENTE_INTERNAL_DISABLE_REGISTRATION:-false} - - # S3/MinIO configuration - - S3_ARE_LOCAL_BUCKETS=true - - S3_USE_PATH_STYLE_URLS=true - - S3_B2_EU_CEN_KEY=${SERVICE_USER_MINIO} - - S3_B2_EU_CEN_SECRET=${SERVICE_PASSWORD_MINIO} - - S3_B2_EU_CEN_ENDPOINT=${SERVICE_URL_MINIO_3200} - - S3_B2_EU_CEN_REGION=eu-central-2 - - S3_B2_EU_CEN_BUCKET=b2-eu-cen + - ENTE_DB_HOST=postgres + - ENTE_DB_PORT=5432 + - 'ENTE_DB_NAME=${POSTGRES_DB:-ente_db}' + - 'ENTE_DB_USER=${SERVICE_USER_POSTGRES}' + - 'ENTE_DB_PASSWORD=${SERVICE_PASSWORD_POSTGRES}' + - 'ENTE_HTTP_USE_TLS=${ENTE_HTTP_USE_TLS:-false}' + - ENTE_S3_ARE_LOCAL_BUCKETS=false + - ENTE_S3_USE_PATH_STYLE_URLS=true + - 'ENTE_S3_B2_EU_CEN_KEY=${SERVICE_USER_MINIO}' + - 'ENTE_S3_B2_EU_CEN_SECRET=${SERVICE_PASSWORD_MINIO}' + - 'ENTE_S3_B2_EU_CEN_ENDPOINT=${SERVICE_FQDN_MINIO_9000}' + - ENTE_S3_B2_EU_CEN_REGION=eu-central-2 + - ENTE_S3_B2_EU_CEN_BUCKET=b2-eu-cen + - 'ENTE_KEY_ENCRYPTION=${SERVICE_REALBASE64_ENCRYPTION}' + - 'ENTE_KEY_HASH=${SERVICE_REALBASE64_64_HASH}' + - 'ENTE_JWT_SECRET=${SERVICE_REALBASE64_JWT}' + - 'ENTE_INTERNAL_ADMIN=${ENTE_INTERNAL_ADMIN:-1580559962386438}' + - 'ENTE_INTERNAL_DISABLE_REGISTRATION=${ENTE_INTERNAL_DISABLE_REGISTRATION:-false}' volumes: - - museum-data:/data - - museum-config:/config + - 'museum-data:/data' + - 'museum-config:/config' depends_on: postgres: condition: service_healthy minio: condition: service_started healthcheck: - test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8080/ping"] - interval: 5s - timeout: 5s - retries: 10 + test: + - CMD + - wget + - '--spider' + - 'http://127.0.0.1:8080/ping' + interval: 30s + timeout: 10s + retries: 3 + web: - image: ghcr.io/ente-io/web + image: 'ghcr.io/ente-io/web:ca03165f5e7f2a50105e6e40019c17ae6cdd934f' # Released at 2025-10-08T00:57:05-07:00 environment: - SERVICE_URL_WEB_3000 - - ENTE_API_ORIGIN=${SERVICE_URL_MUSEUM} - - ENTE_ALBUMS_ORIGIN=${SERVICE_URL_WEB_3002} - + - 'ENTE_API_ORIGIN=${SERVICE_URL_MUSEUM}' healthcheck: - test: ["CMD", "curl", "--fail", "http://127.0.0.1:3000"] - interval: 5s - timeout: 5s - retries: 10 + test: + - CMD + - curl + - '--fail' + - 'http://localhost:3000' + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + + postgres: - image: postgres:15-alpine + image: 'postgres:15-alpine' environment: - - POSTGRES_USER=${SERVICE_USER_POSTGRES} - - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} - - POSTGRES_DB=${POSTGRES_DB:-ente_db} + - 'POSTGRES_USER=${SERVICE_USER_POSTGRES}' + - 'POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES}' + - 'POSTGRES_DB=${POSTGRES_DB:-ente_db}' volumes: - - postgres-data:/var/lib/postgresql/data + - 'postgres-data:/var/lib/postgresql/data' healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] - interval: 5s + test: + - CMD-SHELL + - 'pg_isready -U ${SERVICE_USER_POSTGRES} -d ${POSTGRES_DB:-ente_db}' + interval: 10s timeout: 5s - retries: 10 + retries: 5 + minio: - image: quay.io/minio/minio:latest + image: 'quay.io/minio/minio:RELEASE.2025-09-07T16-13-09Z' # Released at 2025-09-07T16-13-09Z + command: 'server /data --console-address ":9001"' environment: - - SERVICE_URL_MINIO_9000 - - MINIO_ROOT_USER=${SERVICE_USER_MINIO} - - MINIO_ROOT_PASSWORD=${SERVICE_PASSWORD_MINIO} - command: server /data --address ":9000" --console-address ":9001" + - MINIO_SERVER_URL=$MINIO_SERVER_URL + - MINIO_BROWSER_REDIRECT_URL=$MINIO_BROWSER_REDIRECT_URL + - MINIO_ROOT_USER=$SERVICE_USER_MINIO + - MINIO_ROOT_PASSWORD=$SERVICE_PASSWORD_MINIO volumes: - - minio-data:/data + - 'minio-data:/data' healthcheck: - test: ["CMD", "mc", "ready", "local"] + test: + - CMD + - mc + - ready + - local interval: 5s timeout: 20s retries: 10 + minio-init: - image: minio/mc:latest - exclude_from_hc: true - restart: no + image: 'minio/mc:RELEASE.2025-08-13T08-35-41Z' # Released at 2025-08-13T08-35-41Z depends_on: minio: - condition: service_healthy + condition: service_started + restart: on-failure + exclude_from_hc: true environment: - - MINIO_ROOT_USER=${SERVICE_USER_MINIO} - - MINIO_ROOT_PASSWORD=${SERVICE_PASSWORD_MINIO} - entrypoint: > + - 'MINIO_ROOT_USER=${SERVICE_USER_MINIO}' + - 'MINIO_ROOT_PASSWORD=${SERVICE_PASSWORD_MINIO}' + - 'MINIO_CORS_URLS=$SERVICE_URL_MUSEUM,$SERVICE_URL_WEB' + entrypoint: |- /bin/sh -c " - mc alias set minio http://minio:9000 $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD}; - mc mb minio/b2-eu-cen --ignore-existing; - mc mb minio/wasabi-eu-central-2-v3 --ignore-existing; - mc mb minio/scw-eu-fr-v3 --ignore-existing; - echo 'MinIO buckets created successfully'; + echo \"MINIO_CORS_URLS: \$${MINIO_CORS_URLS}\"; + sleep 5; + until mc alias set minio http://minio:9000 \$${MINIO_ROOT_USER} \$${MINIO_ROOT_PASSWORD}; do + echo 'Waiting for MinIO...'; + sleep 2; + done; + mc admin config set minio api cors_allow_origin='$MINIO_CORS_URLS' || true; + mc mb minio/b2-eu-cen --ignore-existing; + mc mb minio/wasabi-eu-central-2-v3 --ignore-existing; + mc mb minio/scw-eu-fr-v3 --ignore-existing; + echo 'MinIO buckets and CORS configured'; " From 3323302021f6aa615d3629e8729cfd713268ec84 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 8 Oct 2025 19:50:06 +0200 Subject: [PATCH 102/111] refactor(navbar, app): improve layout and styling for better responsiveness - Adjusted CSS styles in the navbar for improved readability and responsiveness. - Updated the layout of the sidebar and navbar components to enhance user experience on different screen sizes. - Ensured consistent alignment and spacing for elements within the navbar and sidebar. --- resources/views/components/navbar.blade.php | 34 ++++++++++----------- resources/views/layouts/app.blade.php | 12 +++++--- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index defa7bf6c..4b152dd11 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -59,25 +59,25 @@ if (this.zoom === '90') { const style = document.createElement('style'); style.textContent = ` - html { - font-size: 93.75%; - } - - :root { - --vh: 1vh; - } - - @media (min-width: 1024px) { - html { - font-size: 87.5%; - } - } - `; + html { + font-size: 93.75%; + } + + :root { + --vh: 1vh; + } + + @media (min-width: 1024px) { + html { + font-size: 87.5%; + } + } + `; document.head.appendChild(style); } } }"> -
+
Coolify
@@ -86,8 +86,8 @@
-
-