From 6f2148c060891b90d9c32b504a02ac8bee4fab9a Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Mon, 3 Feb 2025 00:57:18 -0600 Subject: [PATCH 01/11] feat: add deployable option to randomize and prevent colission in duplicate templates --- .../compose/general/compose-file-editor.tsx | 2 + .../compose/general/randomize-deployable.tsx | 196 + .../drizzle/0064_previous_agent_brand.sql | 1 + apps/dokploy/drizzle/meta/0064_snapshot.json | 4485 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + apps/dokploy/server/api/routers/compose.ts | 16 + packages/server/src/db/schema/compose.ts | 1 + packages/server/src/index.ts | 1 + packages/server/src/utils/builders/compose.ts | 7 + packages/server/src/utils/docker/collision.ts | 51 + .../utils/docker/collision/container-name.ts | 26 + .../utils/docker/collision/root-network.ts | 62 + packages/server/src/utils/docker/domain.ts | 23 +- 13 files changed, 4872 insertions(+), 6 deletions(-) create mode 100644 apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx create mode 100644 apps/dokploy/drizzle/0064_previous_agent_brand.sql create mode 100644 apps/dokploy/drizzle/meta/0064_snapshot.json create mode 100644 packages/server/src/utils/docker/collision.ts create mode 100644 packages/server/src/utils/docker/collision/container-name.ts create mode 100644 packages/server/src/utils/docker/collision/root-network.ts diff --git a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx index b368aafc..3e51cf05 100644 --- a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx +++ b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx @@ -15,6 +15,7 @@ import { toast } from "sonner"; import { z } from "zod"; import { validateAndFormatYAML } from "../../application/advanced/traefik/update-traefik-config"; import { RandomizeCompose } from "./randomize-compose"; +import { RandomizeDeployable } from "./randomize-deployable"; interface Props { composeId: string; @@ -126,6 +127,7 @@ services:
+
+ + + + Randomize Deployable (Experimental) + + Use this in case you want to deploy the same compose file twice. + + +
+ + This will randomize the compose file and will add a suffix to the + property to avoid conflicts + +
    +
  • volumes
  • +
  • networks
  • +
  • services
  • +
+ + When you activate this option, we will include a env + `DOKPLOY_SUFFIX` variable to the compose file so you can use it in + your compose file, also we don't include the{" "} + dokploy-network to any of the services by default. + +
+ {isError && {error?.message}} +
+ + {isError && ( +
+ + + {error?.message} + +
+ )} + +
+
+ ( + +
+ Apply Randomize ({data?.appName}) + + Apply randomize to the compose file. + +
+ + + +
+ )} + /> +
+ +
+ +
+
+
+							
+						
+
+ +
+ + ); +}; diff --git a/apps/dokploy/drizzle/0064_previous_agent_brand.sql b/apps/dokploy/drizzle/0064_previous_agent_brand.sql new file mode 100644 index 00000000..73ab1035 --- /dev/null +++ b/apps/dokploy/drizzle/0064_previous_agent_brand.sql @@ -0,0 +1 @@ +ALTER TABLE "compose" ADD COLUMN "deployable" boolean DEFAULT false NOT NULL; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0064_snapshot.json b/apps/dokploy/drizzle/meta/0064_snapshot.json new file mode 100644 index 00000000..8e034af6 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0064_snapshot.json @@ -0,0 +1,4485 @@ +{ + "id": "c9ab7857-cc4c-475f-bd11-5f14f11017cc", + "prevId": "f2fb7162-4b29-4494-9f6a-ab2794b1be48", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_adminId_admin_adminId_fk": { + "name": "user_adminId_admin_adminId_fk", + "tableFrom": "user", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_authId_auth_id_fk": { + "name": "user_authId_auth_id_fk", + "tableFrom": "user", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.admin": { + "name": "admin", + "schema": "", + "columns": { + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripeCustomerId": { + "name": "stripeCustomerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripeSubscriptionId": { + "name": "stripeSubscriptionId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serversQuantity": { + "name": "serversQuantity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "admin_authId_auth_id_fk": { + "name": "admin_authId_auth_id_fk", + "tableFrom": "admin", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resetPasswordToken": { + "name": "resetPasswordToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resetPasswordExpiresAt": { + "name": "resetPasswordExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationToken": { + "name": "confirmationToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationExpiresAt": { + "name": "confirmationExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "project_adminId_admin_adminId_fk": { + "name": "project_adminId_admin_adminId_fk", + "tableFrom": "project", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.domain": { + "name": "domain", + "schema": "", + "columns": { + "domainId": { + "name": "domainId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "https": { + "name": "https", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domainType": { + "name": "domainType", + "type": "domainType", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'application'" + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "destination_adminId_admin_adminId_fk": { + "name": "destination_adminId_admin_adminId_fk", + "tableFrom": "destination", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment": { + "name": "deployment", + "schema": "", + "columns": { + "deploymentId": { + "name": "deploymentId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "deploymentStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'running'" + }, + "logPath": { + "name": "logPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "certificate_adminId_admin_adminId_fk": { + "name": "certificate_adminId_admin_adminId_fk", + "tableFrom": "certificate", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "certificate_serverId_server_serverId_fk": { + "name": "certificate_serverId_server_serverId_fk", + "tableFrom": "certificate", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "certificate_certificatePath_unique": { + "name": "certificate_certificatePath_unique", + "nullsNotDistinct": false, + "columns": [ + "certificatePath" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_auth_id_fk": { + "name": "session_user_id_auth_id_fk", + "tableFrom": "session", + "tableTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redirect": { + "name": "redirect", + "schema": "", + "columns": { + "redirectId": { + "name": "redirectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "regex": { + "name": "regex", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replacement": { + "name": "replacement", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permanent": { + "name": "permanent", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "redirect_applicationId_application_applicationId_fk": { + "name": "redirect_applicationId_application_applicationId_fk", + "tableFrom": "redirect", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.security": { + "name": "security", + "schema": "", + "columns": { + "securityId": { + "name": "securityId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "security_applicationId_application_applicationId_fk": { + "name": "security_applicationId_application_applicationId_fk", + "tableFrom": "security", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "security_username_applicationId_unique": { + "name": "security_username_applicationId_unique", + "nullsNotDistinct": false, + "columns": [ + "username", + "applicationId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.port": { + "name": "port", + "schema": "", + "columns": { + "portId": { + "name": "portId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publishedPort": { + "name": "publishedPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deployable": { + "name": "deployable", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_adminId_admin_adminId_fk": { + "name": "registry_adminId_admin_adminId_fk", + "tableFrom": "registry", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.discord": { + "name": "discord", + "schema": "", + "columns": { + "discordId": { + "name": "discordId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "decoration": { + "name": "decoration", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.email": { + "name": "email", + "schema": "", + "columns": { + "emailId": { + "name": "emailId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "smtpServer": { + "name": "smtpServer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "smtpPort": { + "name": "smtpPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fromAddress": { + "name": "fromAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "toAddress": { + "name": "toAddress", + "type": "text[]", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gotify": { + "name": "gotify", + "schema": "", + "columns": { + "gotifyId": { + "name": "gotifyId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverUrl": { + "name": "serverUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appToken": { + "name": "appToken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 5 + }, + "decoration": { + "name": "decoration", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notification": { + "name": "notification", + "schema": "", + "columns": { + "notificationId": { + "name": "notificationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appDeploy": { + "name": "appDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "appBuildError": { + "name": "appBuildError", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "databaseBackup": { + "name": "databaseBackup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dokployRestart": { + "name": "dokployRestart", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dockerCleanup": { + "name": "dockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "serverThreshold": { + "name": "serverThreshold", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "notificationType": { + "name": "notificationType", + "type": "notificationType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slackId": { + "name": "slackId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discordId": { + "name": "discordId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "emailId": { + "name": "emailId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gotifyId": { + "name": "gotifyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "notification_slackId_slack_slackId_fk": { + "name": "notification_slackId_slack_slackId_fk", + "tableFrom": "notification", + "tableTo": "slack", + "columnsFrom": [ + "slackId" + ], + "columnsTo": [ + "slackId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_telegramId_telegram_telegramId_fk": { + "name": "notification_telegramId_telegram_telegramId_fk", + "tableFrom": "notification", + "tableTo": "telegram", + "columnsFrom": [ + "telegramId" + ], + "columnsTo": [ + "telegramId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_discordId_discord_discordId_fk": { + "name": "notification_discordId_discord_discordId_fk", + "tableFrom": "notification", + "tableTo": "discord", + "columnsFrom": [ + "discordId" + ], + "columnsTo": [ + "discordId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_emailId_email_emailId_fk": { + "name": "notification_emailId_email_emailId_fk", + "tableFrom": "notification", + "tableTo": "email", + "columnsFrom": [ + "emailId" + ], + "columnsTo": [ + "emailId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_gotifyId_gotify_gotifyId_fk": { + "name": "notification_gotifyId_gotify_gotifyId_fk", + "tableFrom": "notification", + "tableTo": "gotify", + "columnsFrom": [ + "gotifyId" + ], + "columnsTo": [ + "gotifyId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_adminId_admin_adminId_fk": { + "name": "notification_adminId_admin_adminId_fk", + "tableFrom": "notification", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack": { + "name": "slack", + "schema": "", + "columns": { + "slackId": { + "name": "slackId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.telegram": { + "name": "telegram", + "schema": "", + "columns": { + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "botToken": { + "name": "botToken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chatId": { + "name": "chatId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ssh-key": { + "name": "ssh-key", + "schema": "", + "columns": { + "sshKeyId": { + "name": "sshKeyId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "publicKey": { + "name": "publicKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lastUsedAt": { + "name": "lastUsedAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "ssh-key_adminId_admin_adminId_fk": { + "name": "ssh-key_adminId_admin_adminId_fk", + "tableFrom": "ssh-key", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.git_provider": { + "name": "git_provider", + "schema": "", + "columns": { + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerType": { + "name": "providerType", + "type": "gitProviderType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "git_provider_adminId_admin_adminId_fk": { + "name": "git_provider_adminId_admin_adminId_fk", + "tableFrom": "git_provider", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bitbucket": { + "name": "bitbucket", + "schema": "", + "columns": { + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "bitbucketUsername": { + "name": "bitbucketUsername", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "appPassword": { + "name": "appPassword", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketWorkspaceName": { + "name": "bitbucketWorkspaceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bitbucket_gitProviderId_git_provider_gitProviderId_fk": { + "name": "bitbucket_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "bitbucket", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.github": { + "name": "github", + "schema": "", + "columns": { + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "githubAppName": { + "name": "githubAppName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubAppId": { + "name": "githubAppId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "githubClientId": { + "name": "githubClientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubClientSecret": { + "name": "githubClientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubInstallationId": { + "name": "githubInstallationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubPrivateKey": { + "name": "githubPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubWebhookSecret": { + "name": "githubWebhookSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "github_gitProviderId_git_provider_gitProviderId_fk": { + "name": "github_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "github", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gitlab": { + "name": "gitlab", + "schema": "", + "columns": { + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "gitlabUrl": { + "name": "gitlabUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'https://gitlab.com'" + }, + "application_id": { + "name": "application_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_name": { + "name": "group_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "gitlab_gitProviderId_git_provider_gitProviderId_fk": { + "name": "gitlab_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "gitlab", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.server": { + "name": "server", + "schema": "", + "columns": { + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'root'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverStatus": { + "name": "serverStatus", + "type": "serverStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "sshKeyId": { + "name": "sshKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Remote\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"urlCallback\":\"\",\"cronJob\":\"\",\"retentionDays\":2,\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + } + }, + "indexes": {}, + "foreignKeys": { + "server_adminId_admin_adminId_fk": { + "name": "server_adminId_admin_adminId_fk", + "tableFrom": "server", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "server_sshKeyId_ssh-key_sshKeyId_fk": { + "name": "server_sshKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "server", + "tableTo": "ssh-key", + "columnsFrom": [ + "sshKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.preview_deployments": { + "name": "preview_deployments", + "schema": "", + "columns": { + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pullRequestId": { + "name": "pullRequestId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pullRequestNumber": { + "name": "pullRequestNumber", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pullRequestURL": { + "name": "pullRequestURL", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pullRequestTitle": { + "name": "pullRequestTitle", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pullRequestCommentId": { + "name": "pullRequestCommentId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "previewStatus": { + "name": "previewStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domainId": { + "name": "domainId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "preview_deployments_applicationId_application_applicationId_fk": { + "name": "preview_deployments_applicationId_application_applicationId_fk", + "tableFrom": "preview_deployments", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "preview_deployments_domainId_domain_domainId_fk": { + "name": "preview_deployments_domainId_domain_domainId_fk", + "tableFrom": "preview_deployments", + "tableTo": "domain", + "columnsFrom": [ + "domainId" + ], + "columnsTo": [ + "domainId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "preview_deployments_appName_unique": { + "name": "preview_deployments_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 57530295..72a61688 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -449,6 +449,13 @@ "when": 1738522845992, "tag": "0063_panoramic_dreadnoughts", "breakpoints": true + }, + { + "idx": 64, + "version": "7", + "when": 1738564387043, + "tag": "0064_previous_agent_brand", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index dab37e78..9e42f935 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -46,6 +46,7 @@ import { findServerById, loadServices, randomizeComposeFile, + randomizeDeployableComposeFile, removeCompose, removeComposeDirectory, removeDeploymentsByComposeId, @@ -216,6 +217,21 @@ export const composeRouter = createTRPCRouter({ } return await randomizeComposeFile(input.composeId, input.suffix); }), + randomizeDeployableCompose: protectedProcedure + .input(apiRandomizeCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to randomize this compose", + }); + } + return await randomizeDeployableComposeFile( + input.composeId, + input.suffix, + ); + }), getConvertedCompose: protectedProcedure .input(apiFindCompose) .query(async ({ input, ctx }) => { diff --git a/packages/server/src/db/schema/compose.ts b/packages/server/src/db/schema/compose.ts index e0c4863b..8efcc314 100644 --- a/packages/server/src/db/schema/compose.ts +++ b/packages/server/src/db/schema/compose.ts @@ -69,6 +69,7 @@ export const compose = pgTable("compose", { composePath: text("composePath").notNull().default("./docker-compose.yml"), suffix: text("suffix").notNull().default(""), randomize: boolean("randomize").notNull().default(false), + deployable: boolean("deployable").notNull().default(false), composeStatus: applicationStatus("composeStatus").notNull().default("idle"), projectId: text("projectId") .notNull() diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index d83d525f..71549a38 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -73,6 +73,7 @@ export * from "./utils/builders/utils"; export * from "./utils/cluster/upload"; export * from "./utils/docker/compose"; +export * from "./utils/docker/collision"; export * from "./utils/docker/domain"; export * from "./utils/docker/utils"; export * from "./utils/docker/types"; diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts index 5e155271..d7dd0d74 100644 --- a/packages/server/src/utils/builders/compose.ts +++ b/packages/server/src/utils/builders/compose.ts @@ -34,6 +34,9 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => { await writeDomainsToCompose(compose, domains); createEnvFile(compose); + await execAsync( + `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}`, + ); const logContent = ` App Name: ${appName} Build Compose 🐳 @@ -73,6 +76,10 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => { }, ); + await execAsync( + `docker network connect tes-umami-e842bc $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1`, + ); + writeStream.write("Docker Compose Deployed: ✅"); } catch (error) { writeStream.write(`Error ❌ ${(error as Error).message}`); diff --git a/packages/server/src/utils/docker/collision.ts b/packages/server/src/utils/docker/collision.ts new file mode 100644 index 00000000..86817da0 --- /dev/null +++ b/packages/server/src/utils/docker/collision.ts @@ -0,0 +1,51 @@ +import { findComposeById } from "@dokploy/server/services/compose"; +import { addAppNameToAllContainerNames } from "./collision/container-name"; +import { addAppNameToAllServiceNames } from "./collision/root-network"; +import { addSuffixToAllVolumes } from "./compose/volume"; +import type { ComposeSpecification } from "./types"; +import { dump, load } from "js-yaml"; +import { generateRandomHash } from "./compose"; + +export const addAppNameToPreventCollision = ( + composeData: ComposeSpecification, + appName: string, +): ComposeSpecification => { + let updatedComposeData = { ...composeData }; + + updatedComposeData = addAppNameToAllContainerNames( + updatedComposeData, + appName, + ); + updatedComposeData = addAppNameToAllServiceNames(updatedComposeData, appName); + updatedComposeData = addSuffixToAllVolumes(updatedComposeData, appName); + return updatedComposeData; +}; + +export const randomizeDeployableComposeFile = async ( + composeId: string, + suffix?: string, +) => { + const compose = await findComposeById(composeId); + const composeFile = compose.composeFile; + const composeData = load(composeFile) as ComposeSpecification; + + const randomSuffix = suffix || compose.appName || generateRandomHash(); + + const newComposeFile = addAppNameToPreventCollision( + composeData, + randomSuffix, + ); + + return dump(newComposeFile); +}; + +export const randomizeDeployableSpecificationFile = ( + composeSpec: ComposeSpecification, + suffix?: string, +) => { + if (!suffix) { + return composeSpec; + } + const newComposeFile = addAppNameToPreventCollision(composeSpec, suffix); + return newComposeFile; +}; diff --git a/packages/server/src/utils/docker/collision/container-name.ts b/packages/server/src/utils/docker/collision/container-name.ts new file mode 100644 index 00000000..7838775f --- /dev/null +++ b/packages/server/src/utils/docker/collision/container-name.ts @@ -0,0 +1,26 @@ +import type { ComposeSpecification, DefinitionsService } from "../types"; +import _ from "lodash"; + +export const addAppNameToContainerNames = ( + services: { [key: string]: DefinitionsService }, + appName: string, +): { [key: string]: DefinitionsService } => { + return _.mapValues(services, (service, serviceName) => { + service.container_name = `${appName}-${serviceName}`; + return service; + }); +}; + +export const addAppNameToAllContainerNames = ( + composeData: ComposeSpecification, + appName: string, +): ComposeSpecification => { + const updatedComposeData = { ...composeData }; + if (updatedComposeData.services) { + updatedComposeData.services = addAppNameToContainerNames( + updatedComposeData.services, + appName, + ); + } + return updatedComposeData; +}; diff --git a/packages/server/src/utils/docker/collision/root-network.ts b/packages/server/src/utils/docker/collision/root-network.ts new file mode 100644 index 00000000..dee15019 --- /dev/null +++ b/packages/server/src/utils/docker/collision/root-network.ts @@ -0,0 +1,62 @@ +import type { ComposeSpecification, DefinitionsService } from "../types"; +import _ from "lodash"; + +export const addAppNameToRootNetwork = ( + composeData: ComposeSpecification, + appName: string, +): ComposeSpecification => { + const updatedComposeData = { ...composeData }; + + // Initialize networks if it doesn't exist + if (!updatedComposeData.networks) { + updatedComposeData.networks = {}; + } + + // Add the new network with the app name + updatedComposeData.networks[appName] = { + name: appName, + external: true, + }; + + return updatedComposeData; +}; + +export const addAppNameToServiceNetworks = ( + services: { [key: string]: DefinitionsService }, + appName: string, +): { [key: string]: DefinitionsService } => { + return _.mapValues(services, (service) => { + if (!service.networks) { + service.networks = [appName]; + return service; + } + + if (Array.isArray(service.networks)) { + if (!service.networks.includes(appName)) { + service.networks.push(appName); + } + } else { + service.networks[appName] = {}; + } + + return service; + }); +}; + +export const addAppNameToAllServiceNames = ( + composeData: ComposeSpecification, + appName: string, +): ComposeSpecification => { + let updatedComposeData = { ...composeData }; + + updatedComposeData = addAppNameToRootNetwork(updatedComposeData, appName); + + if (updatedComposeData.services) { + updatedComposeData.services = addAppNameToServiceNetworks( + updatedComposeData.services, + appName, + ); + } + + return updatedComposeData; +}; diff --git a/packages/server/src/utils/docker/domain.ts b/packages/server/src/utils/docker/domain.ts index 7e1f8476..35db00cf 100644 --- a/packages/server/src/utils/docker/domain.ts +++ b/packages/server/src/utils/docker/domain.ts @@ -33,6 +33,7 @@ import type { PropertiesNetworks, } from "./types"; import { encodeBase64 } from "./utils"; +import { randomizeDeployableSpecificationFile } from "./collision"; export const cloneCompose = async (compose: Compose) => { if (compose.sourceType === "github") { @@ -190,7 +191,13 @@ export const addDomainToCompose = async ( return null; } - if (compose.randomize) { + if (compose.deployable) { + const randomized = randomizeDeployableSpecificationFile( + result, + compose.suffix || compose.appName, + ); + result = randomized; + } else if (compose.randomize) { const randomized = randomizeSpecificationFile(result, compose.suffix); result = randomized; } @@ -240,14 +247,18 @@ export const addDomainToCompose = async ( labels.push(...httpLabels); } - // Add the dokploy-network to the service - result.services[serviceName].networks = addDokployNetworkToService( - result.services[serviceName].networks, - ); + if (!compose.deployable) { + // Add the dokploy-network to the service + result.services[serviceName].networks = addDokployNetworkToService( + result.services[serviceName].networks, + ); + } } // Add dokploy-network to the root of the compose file - result.networks = addDokployNetworkToRoot(result.networks); + if (!compose.deployable) { + result.networks = addDokployNetworkToRoot(result.networks); + } return result; }; From d424524d69cbb843213c7dd0da831fbb6be8def3 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Mon, 3 Feb 2025 00:57:27 -0600 Subject: [PATCH 02/11] refactor: lint --- packages/server/src/utils/docker/collision.ts | 4 ++-- packages/server/src/utils/docker/collision/container-name.ts | 2 +- packages/server/src/utils/docker/collision/root-network.ts | 2 +- packages/server/src/utils/docker/domain.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/server/src/utils/docker/collision.ts b/packages/server/src/utils/docker/collision.ts index 86817da0..ff17fc60 100644 --- a/packages/server/src/utils/docker/collision.ts +++ b/packages/server/src/utils/docker/collision.ts @@ -1,10 +1,10 @@ import { findComposeById } from "@dokploy/server/services/compose"; +import { dump, load } from "js-yaml"; import { addAppNameToAllContainerNames } from "./collision/container-name"; import { addAppNameToAllServiceNames } from "./collision/root-network"; +import { generateRandomHash } from "./compose"; import { addSuffixToAllVolumes } from "./compose/volume"; import type { ComposeSpecification } from "./types"; -import { dump, load } from "js-yaml"; -import { generateRandomHash } from "./compose"; export const addAppNameToPreventCollision = ( composeData: ComposeSpecification, diff --git a/packages/server/src/utils/docker/collision/container-name.ts b/packages/server/src/utils/docker/collision/container-name.ts index 7838775f..3b1f5888 100644 --- a/packages/server/src/utils/docker/collision/container-name.ts +++ b/packages/server/src/utils/docker/collision/container-name.ts @@ -1,5 +1,5 @@ -import type { ComposeSpecification, DefinitionsService } from "../types"; import _ from "lodash"; +import type { ComposeSpecification, DefinitionsService } from "../types"; export const addAppNameToContainerNames = ( services: { [key: string]: DefinitionsService }, diff --git a/packages/server/src/utils/docker/collision/root-network.ts b/packages/server/src/utils/docker/collision/root-network.ts index dee15019..ed36d4bd 100644 --- a/packages/server/src/utils/docker/collision/root-network.ts +++ b/packages/server/src/utils/docker/collision/root-network.ts @@ -1,5 +1,5 @@ -import type { ComposeSpecification, DefinitionsService } from "../types"; import _ from "lodash"; +import type { ComposeSpecification, DefinitionsService } from "../types"; export const addAppNameToRootNetwork = ( composeData: ComposeSpecification, diff --git a/packages/server/src/utils/docker/domain.ts b/packages/server/src/utils/docker/domain.ts index 35db00cf..6846c830 100644 --- a/packages/server/src/utils/docker/domain.ts +++ b/packages/server/src/utils/docker/domain.ts @@ -26,6 +26,7 @@ import { createComposeFileRaw, createComposeFileRawRemote, } from "../providers/raw"; +import { randomizeDeployableSpecificationFile } from "./collision"; import { randomizeSpecificationFile } from "./compose"; import type { ComposeSpecification, @@ -33,7 +34,6 @@ import type { PropertiesNetworks, } from "./types"; import { encodeBase64 } from "./utils"; -import { randomizeDeployableSpecificationFile } from "./collision"; export const cloneCompose = async (compose: Compose) => { if (compose.sourceType === "github") { From 56b26ce0d5ee04a2bbe88322030dab1e1efbb439 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:19:34 -0600 Subject: [PATCH 03/11] refactor: use appname in network connect --- packages/server/src/utils/builders/compose.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts index d7dd0d74..6fbc013b 100644 --- a/packages/server/src/utils/builders/compose.ts +++ b/packages/server/src/utils/builders/compose.ts @@ -77,7 +77,7 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => { ); await execAsync( - `docker network connect tes-umami-e842bc $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1`, + `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1`, ); writeStream.write("Docker Compose Deployed: ✅"); From b024060eed08b29360ac4dd282e9a3aac334b856 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:38:04 -0600 Subject: [PATCH 04/11] refactor: delete unneeded container_name --- apps/dokploy/templates/templates.ts | 5 ++-- packages/server/src/utils/docker/collision.ts | 5 ---- .../utils/docker/collision/container-name.ts | 26 ------------------- 3 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 packages/server/src/utils/docker/collision/container-name.ts diff --git a/apps/dokploy/templates/templates.ts b/apps/dokploy/templates/templates.ts index 650d3b13..2b801ccf 100644 --- a/apps/dokploy/templates/templates.ts +++ b/apps/dokploy/templates/templates.ts @@ -1467,8 +1467,8 @@ export const templates: TemplateData[] = [ }, tags: ["hrms", "payroll", "leaves", "expenses", "attendance", "performace"], load: () => import("./frappe-hr/index").then((m) => m.generate), - }, - { + }, + { id: "formbricks", name: "Formbricks", version: "v3.1.3", @@ -1482,6 +1482,5 @@ export const templates: TemplateData[] = [ }, tags: ["forms", "analytics"], load: () => import("./formbricks/index").then((m) => m.generate), - }, ]; diff --git a/packages/server/src/utils/docker/collision.ts b/packages/server/src/utils/docker/collision.ts index ff17fc60..b905d486 100644 --- a/packages/server/src/utils/docker/collision.ts +++ b/packages/server/src/utils/docker/collision.ts @@ -1,6 +1,5 @@ import { findComposeById } from "@dokploy/server/services/compose"; import { dump, load } from "js-yaml"; -import { addAppNameToAllContainerNames } from "./collision/container-name"; import { addAppNameToAllServiceNames } from "./collision/root-network"; import { generateRandomHash } from "./compose"; import { addSuffixToAllVolumes } from "./compose/volume"; @@ -12,10 +11,6 @@ export const addAppNameToPreventCollision = ( ): ComposeSpecification => { let updatedComposeData = { ...composeData }; - updatedComposeData = addAppNameToAllContainerNames( - updatedComposeData, - appName, - ); updatedComposeData = addAppNameToAllServiceNames(updatedComposeData, appName); updatedComposeData = addSuffixToAllVolumes(updatedComposeData, appName); return updatedComposeData; diff --git a/packages/server/src/utils/docker/collision/container-name.ts b/packages/server/src/utils/docker/collision/container-name.ts deleted file mode 100644 index 3b1f5888..00000000 --- a/packages/server/src/utils/docker/collision/container-name.ts +++ /dev/null @@ -1,26 +0,0 @@ -import _ from "lodash"; -import type { ComposeSpecification, DefinitionsService } from "../types"; - -export const addAppNameToContainerNames = ( - services: { [key: string]: DefinitionsService }, - appName: string, -): { [key: string]: DefinitionsService } => { - return _.mapValues(services, (service, serviceName) => { - service.container_name = `${appName}-${serviceName}`; - return service; - }); -}; - -export const addAppNameToAllContainerNames = ( - composeData: ComposeSpecification, - appName: string, -): ComposeSpecification => { - const updatedComposeData = { ...composeData }; - if (updatedComposeData.services) { - updatedComposeData.services = addAppNameToContainerNames( - updatedComposeData.services, - appName, - ); - } - return updatedComposeData; -}; From a71de72a3c79c357521cecf1263115fc770012a2 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:39:42 -0600 Subject: [PATCH 05/11] refactor: remove services --- .../compose/general/randomize-deployable.tsx | 317 +++++++++--------- 1 file changed, 158 insertions(+), 159 deletions(-) diff --git a/apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx b/apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx index 55b3c97a..6ed93605 100644 --- a/apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx +++ b/apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx @@ -3,21 +3,21 @@ import { CodeEditor } from "@/components/shared/code-editor"; import { Button } from "@/components/ui/button"; import { CardTitle } from "@/components/ui/card"; import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, - DialogTrigger, + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, } from "@/components/ui/dialog"; import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; @@ -30,167 +30,166 @@ import { toast } from "sonner"; import { z } from "zod"; interface Props { - composeId: string; + composeId: string; } const schema = z.object({ - deployable: z.boolean().optional(), + deployable: z.boolean().optional(), }); type Schema = z.infer; export const RandomizeDeployable = ({ composeId }: Props) => { - const utils = api.useUtils(); - const [compose, setCompose] = useState(""); - const [isOpen, setIsOpen] = useState(false); - const { mutateAsync, error, isError } = - api.compose.randomizeDeployableCompose.useMutation(); + const utils = api.useUtils(); + const [compose, setCompose] = useState(""); + const [isOpen, setIsOpen] = useState(false); + const { mutateAsync, error, isError } = + api.compose.randomizeDeployableCompose.useMutation(); - const { mutateAsync: updateCompose } = api.compose.update.useMutation(); + const { mutateAsync: updateCompose } = api.compose.update.useMutation(); - const { data, refetch } = api.compose.one.useQuery( - { composeId }, - { enabled: !!composeId }, - ); + const { data, refetch } = api.compose.one.useQuery( + { composeId }, + { enabled: !!composeId } + ); - const form = useForm({ - defaultValues: { - deployable: false, - }, - resolver: zodResolver(schema), - }); + const form = useForm({ + defaultValues: { + deployable: false, + }, + resolver: zodResolver(schema), + }); - useEffect(() => { - if (data) { - form.reset({ - deployable: data?.deployable || false, - }); - } - }, [form, form.reset, form.formState.isSubmitSuccessful, data]); + useEffect(() => { + if (data) { + form.reset({ + deployable: data?.deployable || false, + }); + } + }, [form, form.reset, form.formState.isSubmitSuccessful, data]); - const onSubmit = async (formData: Schema) => { - await updateCompose({ - composeId, - deployable: formData?.deployable || false, - }) - .then(async (data) => { - randomizeCompose(); - refetch(); - toast.success("Compose updated"); - }) - .catch(() => { - toast.error("Error randomizing the compose"); - }); - }; + const onSubmit = async (formData: Schema) => { + await updateCompose({ + composeId, + deployable: formData?.deployable || false, + }) + .then(async (data) => { + randomizeCompose(); + refetch(); + toast.success("Compose updated"); + }) + .catch(() => { + toast.error("Error randomizing the compose"); + }); + }; - const randomizeCompose = async () => { - await mutateAsync({ - composeId, - suffix: data?.appName || "", - }) - .then(async (data) => { - await utils.project.all.invalidate(); - setCompose(data); - toast.success("Compose randomized"); - }) - .catch(() => { - toast.error("Error randomizing the compose"); - }); - }; + const randomizeCompose = async () => { + await mutateAsync({ + composeId, + suffix: data?.appName || "", + }) + .then(async (data) => { + await utils.project.all.invalidate(); + setCompose(data); + toast.success("Compose randomized"); + }) + .catch(() => { + toast.error("Error randomizing the compose"); + }); + }; - return ( - - randomizeCompose()}> - - - - - Randomize Deployable (Experimental) - - Use this in case you want to deploy the same compose file twice. - - -
- - This will randomize the compose file and will add a suffix to the - property to avoid conflicts - -
    -
  • volumes
  • -
  • networks
  • -
  • services
  • -
- - When you activate this option, we will include a env - `DOKPLOY_SUFFIX` variable to the compose file so you can use it in - your compose file, also we don't include the{" "} - dokploy-network to any of the services by default. - -
- {isError && {error?.message}} -
- - {isError && ( -
- - - {error?.message} - -
- )} + return ( + + randomizeCompose()}> + + + + + Randomize Deployable (Experimental) + + Use this in case you want to deploy the same compose file twice. + + +
+ + This will randomize the compose file and will add a suffix to the + property to avoid conflicts + +
    +
  • volumes
  • +
  • networks
  • +
+ + When you activate this option, we will include a env + `DOKPLOY_SUFFIX` variable to the compose file so you can use it in + your compose file, also we don't include the{" "} + dokploy-network to any of the services by default. + +
+ {isError && {error?.message}} + + + {isError && ( +
+ + + {error?.message} + +
+ )} -
-
- ( - -
- Apply Randomize ({data?.appName}) - - Apply randomize to the compose file. - -
- - - -
- )} - /> -
+
+
+ ( + +
+ Apply Randomize ({data?.appName}) + + Apply randomize to the compose file. + +
+ + + +
+ )} + /> +
-
- -
-
-
-							
-						
- - - -
- ); +
+ +
+
+
+              
+            
+ + + + + ); }; From 8379068fe32e71da8ebe8bbd9f4e5423b8e94406 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:40:03 -0600 Subject: [PATCH 06/11] refactor: remove services --- .../compose/general/randomize-deployable.tsx | 316 +++++++++--------- 1 file changed, 158 insertions(+), 158 deletions(-) diff --git a/apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx b/apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx index 6ed93605..db0c5242 100644 --- a/apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx +++ b/apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx @@ -3,21 +3,21 @@ import { CodeEditor } from "@/components/shared/code-editor"; import { Button } from "@/components/ui/button"; import { CardTitle } from "@/components/ui/card"; import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, - DialogTrigger, + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, } from "@/components/ui/dialog"; import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; @@ -30,166 +30,166 @@ import { toast } from "sonner"; import { z } from "zod"; interface Props { - composeId: string; + composeId: string; } const schema = z.object({ - deployable: z.boolean().optional(), + deployable: z.boolean().optional(), }); type Schema = z.infer; export const RandomizeDeployable = ({ composeId }: Props) => { - const utils = api.useUtils(); - const [compose, setCompose] = useState(""); - const [isOpen, setIsOpen] = useState(false); - const { mutateAsync, error, isError } = - api.compose.randomizeDeployableCompose.useMutation(); + const utils = api.useUtils(); + const [compose, setCompose] = useState(""); + const [isOpen, setIsOpen] = useState(false); + const { mutateAsync, error, isError } = + api.compose.randomizeDeployableCompose.useMutation(); - const { mutateAsync: updateCompose } = api.compose.update.useMutation(); + const { mutateAsync: updateCompose } = api.compose.update.useMutation(); - const { data, refetch } = api.compose.one.useQuery( - { composeId }, - { enabled: !!composeId } - ); + const { data, refetch } = api.compose.one.useQuery( + { composeId }, + { enabled: !!composeId }, + ); - const form = useForm({ - defaultValues: { - deployable: false, - }, - resolver: zodResolver(schema), - }); + const form = useForm({ + defaultValues: { + deployable: false, + }, + resolver: zodResolver(schema), + }); - useEffect(() => { - if (data) { - form.reset({ - deployable: data?.deployable || false, - }); - } - }, [form, form.reset, form.formState.isSubmitSuccessful, data]); + useEffect(() => { + if (data) { + form.reset({ + deployable: data?.deployable || false, + }); + } + }, [form, form.reset, form.formState.isSubmitSuccessful, data]); - const onSubmit = async (formData: Schema) => { - await updateCompose({ - composeId, - deployable: formData?.deployable || false, - }) - .then(async (data) => { - randomizeCompose(); - refetch(); - toast.success("Compose updated"); - }) - .catch(() => { - toast.error("Error randomizing the compose"); - }); - }; + const onSubmit = async (formData: Schema) => { + await updateCompose({ + composeId, + deployable: formData?.deployable || false, + }) + .then(async (data) => { + randomizeCompose(); + refetch(); + toast.success("Compose updated"); + }) + .catch(() => { + toast.error("Error randomizing the compose"); + }); + }; - const randomizeCompose = async () => { - await mutateAsync({ - composeId, - suffix: data?.appName || "", - }) - .then(async (data) => { - await utils.project.all.invalidate(); - setCompose(data); - toast.success("Compose randomized"); - }) - .catch(() => { - toast.error("Error randomizing the compose"); - }); - }; + const randomizeCompose = async () => { + await mutateAsync({ + composeId, + suffix: data?.appName || "", + }) + .then(async (data) => { + await utils.project.all.invalidate(); + setCompose(data); + toast.success("Compose randomized"); + }) + .catch(() => { + toast.error("Error randomizing the compose"); + }); + }; - return ( - - randomizeCompose()}> - - - - - Randomize Deployable (Experimental) - - Use this in case you want to deploy the same compose file twice. - - -
- - This will randomize the compose file and will add a suffix to the - property to avoid conflicts - -
    -
  • volumes
  • -
  • networks
  • -
- - When you activate this option, we will include a env - `DOKPLOY_SUFFIX` variable to the compose file so you can use it in - your compose file, also we don't include the{" "} - dokploy-network to any of the services by default. - -
- {isError && {error?.message}} -
- - {isError && ( -
- - - {error?.message} - -
- )} + return ( + + randomizeCompose()}> + + + + + Randomize Deployable (Experimental) + + Use this in case you want to deploy the same compose file twice. + + +
+ + This will randomize the compose file and will add a suffix to the + property to avoid conflicts + +
    +
  • volumes
  • +
  • networks
  • +
+ + When you activate this option, we will include a env + `DOKPLOY_SUFFIX` variable to the compose file so you can use it in + your compose file, also we don't include the{" "} + dokploy-network to any of the services by default. + +
+ {isError && {error?.message}} + + + {isError && ( +
+ + + {error?.message} + +
+ )} -
-
- ( - -
- Apply Randomize ({data?.appName}) - - Apply randomize to the compose file. - -
- - - -
- )} - /> -
+
+
+ ( + +
+ Apply Randomize ({data?.appName}) + + Apply randomize to the compose file. + +
+ + + +
+ )} + /> +
-
- -
-
-
-              
-            
- - - -
- ); +
+ +
+ +
+							
+						
+ + +
+
+ ); }; From f44512a43773524c523c3be493c74cefc935644f Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 6 Feb 2025 01:52:53 -0600 Subject: [PATCH 07/11] refactor: add condition to deploy on remote servers --- packages/server/src/utils/builders/compose.ts | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts index 6fbc013b..f5cedfd7 100644 --- a/packages/server/src/utils/builders/compose.ts +++ b/packages/server/src/utils/builders/compose.ts @@ -34,9 +34,12 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => { await writeDomainsToCompose(compose, domains); createEnvFile(compose); - await execAsync( - `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}`, - ); + if (compose.deployable) { + await execAsync( + `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}`, + ); + } + const logContent = ` App Name: ${appName} Build Compose 🐳 @@ -76,9 +79,11 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => { }, ); - await execAsync( - `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1`, - ); + if (compose.deployable) { + await execAsync( + `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1`, + ); + } writeStream.write("Docker Compose Deployed: ✅"); } catch (error) { @@ -135,9 +140,10 @@ Compose Type: ${composeType} ✅`; cd "${projectPath}"; - ${exportEnvCommand} - + ${exportEnvCommand} + ${compose.deployable ? `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}` : ""} docker ${command.split(" ").join(" ")} >> "${logPath}" 2>&1 || { echo "Error: ❌ Docker command failed" >> "${logPath}"; exit 1; } + ${compose.deployable ? `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1` : ""} echo "Docker Compose Deployed: ✅" >> "${logPath}" } || { From 3e2cfe6eb8b1549b4532ae4b61270007391f4ebf Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 9 Feb 2025 02:20:28 -0600 Subject: [PATCH 08/11] refactor: agroupate utilities --- .../compose/general/compose-file-editor.tsx | 6 +- .../compose/general/isolated-deployment.tsx | 191 + .../compose/general/randomize-compose.tsx | 239 +- .../compose/general/randomize-deployable.tsx | 195 - .../compose/general/show-utilities.tsx | 46 + apps/dokploy/drizzle/0065_daily_zaladane.sql | 1 + apps/dokploy/drizzle/meta/0065_snapshot.json | 4485 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + apps/dokploy/server/api/routers/compose.ts | 826 +-- packages/server/src/db/schema/compose.ts | 272 +- packages/server/src/utils/builders/compose.ts | 322 +- packages/server/src/utils/docker/collision.ts | 50 +- packages/server/src/utils/docker/domain.ts | 494 +- 13 files changed, 5826 insertions(+), 1308 deletions(-) create mode 100644 apps/dokploy/components/dashboard/compose/general/isolated-deployment.tsx delete mode 100644 apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx create mode 100644 apps/dokploy/components/dashboard/compose/general/show-utilities.tsx create mode 100644 apps/dokploy/drizzle/0065_daily_zaladane.sql create mode 100644 apps/dokploy/drizzle/meta/0065_snapshot.json diff --git a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx index 3e51cf05..47497219 100644 --- a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx +++ b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx @@ -15,7 +15,8 @@ import { toast } from "sonner"; import { z } from "zod"; import { validateAndFormatYAML } from "../../application/advanced/traefik/update-traefik-config"; import { RandomizeCompose } from "./randomize-compose"; -import { RandomizeDeployable } from "./randomize-deployable"; +import { RandomizeDeployable } from "./isolated-deployment"; +import { ShowUtilities } from "./show-utilities"; interface Props { composeId: string; @@ -126,8 +127,7 @@ services:
- - +
+
+ +
+ +
+							
+						
+
+ + + + ); +}; diff --git a/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx b/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx index 59233acf..b1a00985 100644 --- a/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx @@ -1,14 +1,10 @@ import { AlertBlock } from "@/components/shared/alert-block"; import { CodeEditor } from "@/components/shared/code-editor"; import { Button } from "@/components/ui/button"; -import { CardTitle } from "@/components/ui/card"; import { - Dialog, - DialogContent, DialogDescription, DialogHeader, DialogTitle, - DialogTrigger, } from "@/components/ui/dialog"; import { Form, @@ -20,11 +16,6 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; -import { - InputOTP, - InputOTPGroup, - InputOTPSlot, -} from "@/components/ui/input-otp"; import { Switch } from "@/components/ui/switch"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; @@ -70,6 +61,7 @@ export const RandomizeCompose = ({ composeId }: Props) => { const suffix = form.watch("suffix"); useEffect(() => { + randomizeCompose(); if (data) { form.reset({ suffix: data?.suffix || "", @@ -110,126 +102,117 @@ export const RandomizeCompose = ({ composeId }: Props) => { }; return ( - - randomizeCompose()}> - - - - - Randomize Compose (Experimental) - - Use this in case you want to deploy the same compose file and you - have conflicts with some property like volumes, networks, etc. - - -
- - This will randomize the compose file and will add a suffix to the - property to avoid conflicts - -
    -
  • volumes
  • -
  • networks
  • -
  • services
  • -
  • configs
  • -
  • secrets
  • -
- - When you activate this option, we will include a env - `COMPOSE_PREFIX` variable to the compose file so you can use it in - your compose file. - -
- {isError && {error?.message}} -
- - {isError && ( -
- - - {error?.message} - -
- )} - -
-
- ( - - Suffix - - - - - - )} - /> - ( - -
- Apply Randomize - - Apply randomize to the compose file. - -
- - - -
- )} - /> -
- -
- - -
+
+ + Randomize Compose (Experimental) + + Use this in case you want to deploy the same compose file and you have + conflicts with some property like volumes, networks, etc. + + +
+ + This will randomize the compose file and will add a suffix to the + property to avoid conflicts + +
    +
  • volumes
  • +
  • networks
  • +
  • services
  • +
  • configs
  • +
  • secrets
  • +
+ + When you activate this option, we will include a env `COMPOSE_PREFIX` + variable to the compose file so you can use it in your compose file. + +
+ {isError && {error?.message}} + + + {isError && ( +
+ + + {error?.message} +
-
-							
+						
+ ( + + Suffix + + + + + + )} /> -
- - - -
+ ( + +
+ Apply Randomize + + Apply randomize to the compose file. + +
+ + + +
+ )} + /> + + +
+ + +
+ +
+						
+					
+ + + ); }; diff --git a/apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx b/apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx deleted file mode 100644 index db0c5242..00000000 --- a/apps/dokploy/components/dashboard/compose/general/randomize-deployable.tsx +++ /dev/null @@ -1,195 +0,0 @@ -import { AlertBlock } from "@/components/shared/alert-block"; -import { CodeEditor } from "@/components/shared/code-editor"; -import { Button } from "@/components/ui/button"; -import { CardTitle } from "@/components/ui/card"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { Switch } from "@/components/ui/switch"; -import { api } from "@/utils/api"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { AlertTriangle, Dices } from "lucide-react"; -import { useEffect, useState } from "react"; -import { useForm } from "react-hook-form"; -import { toast } from "sonner"; -import { z } from "zod"; - -interface Props { - composeId: string; -} - -const schema = z.object({ - deployable: z.boolean().optional(), -}); - -type Schema = z.infer; - -export const RandomizeDeployable = ({ composeId }: Props) => { - const utils = api.useUtils(); - const [compose, setCompose] = useState(""); - const [isOpen, setIsOpen] = useState(false); - const { mutateAsync, error, isError } = - api.compose.randomizeDeployableCompose.useMutation(); - - const { mutateAsync: updateCompose } = api.compose.update.useMutation(); - - const { data, refetch } = api.compose.one.useQuery( - { composeId }, - { enabled: !!composeId }, - ); - - const form = useForm({ - defaultValues: { - deployable: false, - }, - resolver: zodResolver(schema), - }); - - useEffect(() => { - if (data) { - form.reset({ - deployable: data?.deployable || false, - }); - } - }, [form, form.reset, form.formState.isSubmitSuccessful, data]); - - const onSubmit = async (formData: Schema) => { - await updateCompose({ - composeId, - deployable: formData?.deployable || false, - }) - .then(async (data) => { - randomizeCompose(); - refetch(); - toast.success("Compose updated"); - }) - .catch(() => { - toast.error("Error randomizing the compose"); - }); - }; - - const randomizeCompose = async () => { - await mutateAsync({ - composeId, - suffix: data?.appName || "", - }) - .then(async (data) => { - await utils.project.all.invalidate(); - setCompose(data); - toast.success("Compose randomized"); - }) - .catch(() => { - toast.error("Error randomizing the compose"); - }); - }; - - return ( - - randomizeCompose()}> - - - - - Randomize Deployable (Experimental) - - Use this in case you want to deploy the same compose file twice. - - -
- - This will randomize the compose file and will add a suffix to the - property to avoid conflicts - -
    -
  • volumes
  • -
  • networks
  • -
- - When you activate this option, we will include a env - `DOKPLOY_SUFFIX` variable to the compose file so you can use it in - your compose file, also we don't include the{" "} - dokploy-network to any of the services by default. - -
- {isError && {error?.message}} -
- - {isError && ( -
- - - {error?.message} - -
- )} - -
-
- ( - -
- Apply Randomize ({data?.appName}) - - Apply randomize to the compose file. - -
- - - -
- )} - /> -
- -
- -
-
-
-							
-						
-
- -
-
- ); -}; diff --git a/apps/dokploy/components/dashboard/compose/general/show-utilities.tsx b/apps/dokploy/components/dashboard/compose/general/show-utilities.tsx new file mode 100644 index 00000000..6a3721e4 --- /dev/null +++ b/apps/dokploy/components/dashboard/compose/general/show-utilities.tsx @@ -0,0 +1,46 @@ +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { IsolatedDeployment } from "./isolated-deployment"; +import { RandomizeCompose } from "./randomize-compose"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { useState } from "react"; +import { Button } from "@/components/ui/button"; + +interface Props { + composeId: string; +} + +export const ShowUtilities = ({ composeId }: Props) => { + const [isOpen, setIsOpen] = useState(false); + return ( + + + + + + + Utilities + Modify the application data + + + + Isolated Deployment + Randomize Compose + + + + + + + + + + + ); +}; diff --git a/apps/dokploy/drizzle/0065_daily_zaladane.sql b/apps/dokploy/drizzle/0065_daily_zaladane.sql new file mode 100644 index 00000000..dc5c0d14 --- /dev/null +++ b/apps/dokploy/drizzle/0065_daily_zaladane.sql @@ -0,0 +1 @@ +ALTER TABLE "compose" RENAME COLUMN "deployable" TO "isolatedDeployment"; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0065_snapshot.json b/apps/dokploy/drizzle/meta/0065_snapshot.json new file mode 100644 index 00000000..28eef618 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0065_snapshot.json @@ -0,0 +1,4485 @@ +{ + "id": "1240ec96-1751-4de3-b64f-cef9cb716786", + "prevId": "c9ab7857-cc4c-475f-bd11-5f14f11017cc", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_adminId_admin_adminId_fk": { + "name": "user_adminId_admin_adminId_fk", + "tableFrom": "user", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_authId_auth_id_fk": { + "name": "user_authId_auth_id_fk", + "tableFrom": "user", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.admin": { + "name": "admin", + "schema": "", + "columns": { + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripeCustomerId": { + "name": "stripeCustomerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripeSubscriptionId": { + "name": "stripeSubscriptionId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serversQuantity": { + "name": "serversQuantity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "admin_authId_auth_id_fk": { + "name": "admin_authId_auth_id_fk", + "tableFrom": "admin", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resetPasswordToken": { + "name": "resetPasswordToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resetPasswordExpiresAt": { + "name": "resetPasswordExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationToken": { + "name": "confirmationToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationExpiresAt": { + "name": "confirmationExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "project_adminId_admin_adminId_fk": { + "name": "project_adminId_admin_adminId_fk", + "tableFrom": "project", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.domain": { + "name": "domain", + "schema": "", + "columns": { + "domainId": { + "name": "domainId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "https": { + "name": "https", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domainType": { + "name": "domainType", + "type": "domainType", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'application'" + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "destination_adminId_admin_adminId_fk": { + "name": "destination_adminId_admin_adminId_fk", + "tableFrom": "destination", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment": { + "name": "deployment", + "schema": "", + "columns": { + "deploymentId": { + "name": "deploymentId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "deploymentStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'running'" + }, + "logPath": { + "name": "logPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "certificate_adminId_admin_adminId_fk": { + "name": "certificate_adminId_admin_adminId_fk", + "tableFrom": "certificate", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "certificate_serverId_server_serverId_fk": { + "name": "certificate_serverId_server_serverId_fk", + "tableFrom": "certificate", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "certificate_certificatePath_unique": { + "name": "certificate_certificatePath_unique", + "nullsNotDistinct": false, + "columns": [ + "certificatePath" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_auth_id_fk": { + "name": "session_user_id_auth_id_fk", + "tableFrom": "session", + "tableTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redirect": { + "name": "redirect", + "schema": "", + "columns": { + "redirectId": { + "name": "redirectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "regex": { + "name": "regex", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replacement": { + "name": "replacement", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permanent": { + "name": "permanent", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "redirect_applicationId_application_applicationId_fk": { + "name": "redirect_applicationId_application_applicationId_fk", + "tableFrom": "redirect", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.security": { + "name": "security", + "schema": "", + "columns": { + "securityId": { + "name": "securityId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "security_applicationId_application_applicationId_fk": { + "name": "security_applicationId_application_applicationId_fk", + "tableFrom": "security", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "security_username_applicationId_unique": { + "name": "security_username_applicationId_unique", + "nullsNotDistinct": false, + "columns": [ + "username", + "applicationId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.port": { + "name": "port", + "schema": "", + "columns": { + "portId": { + "name": "portId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publishedPort": { + "name": "publishedPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_adminId_admin_adminId_fk": { + "name": "registry_adminId_admin_adminId_fk", + "tableFrom": "registry", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.discord": { + "name": "discord", + "schema": "", + "columns": { + "discordId": { + "name": "discordId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "decoration": { + "name": "decoration", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.email": { + "name": "email", + "schema": "", + "columns": { + "emailId": { + "name": "emailId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "smtpServer": { + "name": "smtpServer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "smtpPort": { + "name": "smtpPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fromAddress": { + "name": "fromAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "toAddress": { + "name": "toAddress", + "type": "text[]", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gotify": { + "name": "gotify", + "schema": "", + "columns": { + "gotifyId": { + "name": "gotifyId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverUrl": { + "name": "serverUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appToken": { + "name": "appToken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 5 + }, + "decoration": { + "name": "decoration", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notification": { + "name": "notification", + "schema": "", + "columns": { + "notificationId": { + "name": "notificationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appDeploy": { + "name": "appDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "appBuildError": { + "name": "appBuildError", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "databaseBackup": { + "name": "databaseBackup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dokployRestart": { + "name": "dokployRestart", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dockerCleanup": { + "name": "dockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "serverThreshold": { + "name": "serverThreshold", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "notificationType": { + "name": "notificationType", + "type": "notificationType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slackId": { + "name": "slackId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discordId": { + "name": "discordId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "emailId": { + "name": "emailId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gotifyId": { + "name": "gotifyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "notification_slackId_slack_slackId_fk": { + "name": "notification_slackId_slack_slackId_fk", + "tableFrom": "notification", + "tableTo": "slack", + "columnsFrom": [ + "slackId" + ], + "columnsTo": [ + "slackId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_telegramId_telegram_telegramId_fk": { + "name": "notification_telegramId_telegram_telegramId_fk", + "tableFrom": "notification", + "tableTo": "telegram", + "columnsFrom": [ + "telegramId" + ], + "columnsTo": [ + "telegramId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_discordId_discord_discordId_fk": { + "name": "notification_discordId_discord_discordId_fk", + "tableFrom": "notification", + "tableTo": "discord", + "columnsFrom": [ + "discordId" + ], + "columnsTo": [ + "discordId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_emailId_email_emailId_fk": { + "name": "notification_emailId_email_emailId_fk", + "tableFrom": "notification", + "tableTo": "email", + "columnsFrom": [ + "emailId" + ], + "columnsTo": [ + "emailId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_gotifyId_gotify_gotifyId_fk": { + "name": "notification_gotifyId_gotify_gotifyId_fk", + "tableFrom": "notification", + "tableTo": "gotify", + "columnsFrom": [ + "gotifyId" + ], + "columnsTo": [ + "gotifyId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_adminId_admin_adminId_fk": { + "name": "notification_adminId_admin_adminId_fk", + "tableFrom": "notification", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack": { + "name": "slack", + "schema": "", + "columns": { + "slackId": { + "name": "slackId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.telegram": { + "name": "telegram", + "schema": "", + "columns": { + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "botToken": { + "name": "botToken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chatId": { + "name": "chatId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ssh-key": { + "name": "ssh-key", + "schema": "", + "columns": { + "sshKeyId": { + "name": "sshKeyId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "publicKey": { + "name": "publicKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lastUsedAt": { + "name": "lastUsedAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "ssh-key_adminId_admin_adminId_fk": { + "name": "ssh-key_adminId_admin_adminId_fk", + "tableFrom": "ssh-key", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.git_provider": { + "name": "git_provider", + "schema": "", + "columns": { + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerType": { + "name": "providerType", + "type": "gitProviderType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "git_provider_adminId_admin_adminId_fk": { + "name": "git_provider_adminId_admin_adminId_fk", + "tableFrom": "git_provider", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bitbucket": { + "name": "bitbucket", + "schema": "", + "columns": { + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "bitbucketUsername": { + "name": "bitbucketUsername", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "appPassword": { + "name": "appPassword", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketWorkspaceName": { + "name": "bitbucketWorkspaceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bitbucket_gitProviderId_git_provider_gitProviderId_fk": { + "name": "bitbucket_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "bitbucket", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.github": { + "name": "github", + "schema": "", + "columns": { + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "githubAppName": { + "name": "githubAppName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubAppId": { + "name": "githubAppId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "githubClientId": { + "name": "githubClientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubClientSecret": { + "name": "githubClientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubInstallationId": { + "name": "githubInstallationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubPrivateKey": { + "name": "githubPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubWebhookSecret": { + "name": "githubWebhookSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "github_gitProviderId_git_provider_gitProviderId_fk": { + "name": "github_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "github", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gitlab": { + "name": "gitlab", + "schema": "", + "columns": { + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "gitlabUrl": { + "name": "gitlabUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'https://gitlab.com'" + }, + "application_id": { + "name": "application_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_name": { + "name": "group_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "gitlab_gitProviderId_git_provider_gitProviderId_fk": { + "name": "gitlab_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "gitlab", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.server": { + "name": "server", + "schema": "", + "columns": { + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'root'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverStatus": { + "name": "serverStatus", + "type": "serverStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "sshKeyId": { + "name": "sshKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Remote\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"urlCallback\":\"\",\"cronJob\":\"\",\"retentionDays\":2,\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + } + }, + "indexes": {}, + "foreignKeys": { + "server_adminId_admin_adminId_fk": { + "name": "server_adminId_admin_adminId_fk", + "tableFrom": "server", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "server_sshKeyId_ssh-key_sshKeyId_fk": { + "name": "server_sshKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "server", + "tableTo": "ssh-key", + "columnsFrom": [ + "sshKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.preview_deployments": { + "name": "preview_deployments", + "schema": "", + "columns": { + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pullRequestId": { + "name": "pullRequestId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pullRequestNumber": { + "name": "pullRequestNumber", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pullRequestURL": { + "name": "pullRequestURL", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pullRequestTitle": { + "name": "pullRequestTitle", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pullRequestCommentId": { + "name": "pullRequestCommentId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "previewStatus": { + "name": "previewStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domainId": { + "name": "domainId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expiresAt": { + "name": "expiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "preview_deployments_applicationId_application_applicationId_fk": { + "name": "preview_deployments_applicationId_application_applicationId_fk", + "tableFrom": "preview_deployments", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "preview_deployments_domainId_domain_domainId_fk": { + "name": "preview_deployments_domainId_domain_domainId_fk", + "tableFrom": "preview_deployments", + "tableTo": "domain", + "columnsFrom": [ + "domainId" + ], + "columnsTo": [ + "domainId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "preview_deployments_appName_unique": { + "name": "preview_deployments_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 72a61688..588d36eb 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -456,6 +456,13 @@ "when": 1738564387043, "tag": "0064_previous_agent_brand", "breakpoints": true + }, + { + "idx": 65, + "version": "7", + "when": 1739087857244, + "tag": "0065_daily_zaladane", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index 9e42f935..380fc70f 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -1,22 +1,22 @@ import { slugify } from "@/lib/slug"; import { db } from "@/server/db"; import { - apiCreateCompose, - apiCreateComposeByTemplate, - apiDeleteCompose, - apiFetchServices, - apiFindCompose, - apiRandomizeCompose, - apiUpdateCompose, - compose, + apiCreateCompose, + apiCreateComposeByTemplate, + apiDeleteCompose, + apiFetchServices, + apiFindCompose, + apiRandomizeCompose, + apiUpdateCompose, + compose, } from "@/server/db/schema"; import { cleanQueuesByCompose, myQueue } from "@/server/queues/queueSetup"; import { templates } from "@/templates/templates"; import type { TemplatesKeys } from "@/templates/types/templates-data.type"; import { - generatePassword, - loadTemplateModule, - readTemplateComposeFile, + generatePassword, + loadTemplateModule, + readTemplateComposeFile, } from "@/templates/utils"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; @@ -28,443 +28,443 @@ import { createTRPCRouter, protectedProcedure } from "../trpc"; import type { DeploymentJob } from "@/server/queues/queue-types"; import { deploy } from "@/server/utils/deploy"; import { - IS_CLOUD, - addDomainToCompose, - addNewService, - checkServiceAccess, - cloneCompose, - cloneComposeRemote, - createCommand, - createCompose, - createComposeByTemplate, - createDomain, - createMount, - findAdminById, - findComposeById, - findDomainsByComposeId, - findProjectById, - findServerById, - loadServices, - randomizeComposeFile, - randomizeDeployableComposeFile, - removeCompose, - removeComposeDirectory, - removeDeploymentsByComposeId, - startCompose, - stopCompose, - updateCompose, + IS_CLOUD, + addDomainToCompose, + addNewService, + checkServiceAccess, + cloneCompose, + cloneComposeRemote, + createCommand, + createCompose, + createComposeByTemplate, + createDomain, + createMount, + findAdminById, + findComposeById, + findDomainsByComposeId, + findProjectById, + findServerById, + loadServices, + randomizeComposeFile, + randomizeIsolatedDeploymentComposeFile, + removeCompose, + removeComposeDirectory, + removeDeploymentsByComposeId, + startCompose, + stopCompose, + updateCompose, } from "@dokploy/server"; export const composeRouter = createTRPCRouter({ - create: protectedProcedure - .input(apiCreateCompose) - .mutation(async ({ ctx, input }) => { - try { - if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); - } + create: protectedProcedure + .input(apiCreateCompose) + .mutation(async ({ ctx, input }) => { + try { + if (ctx.user.rol === "user") { + await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + } - if (IS_CLOUD && !input.serverId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You need to use a server to create a compose", - }); - } - const project = await findProjectById(input.projectId); - if (project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to access this project", - }); - } - const newService = await createCompose(input); + if (IS_CLOUD && !input.serverId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You need to use a server to create a compose", + }); + } + const project = await findProjectById(input.projectId); + if (project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to access this project", + }); + } + const newService = await createCompose(input); - if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, newService.composeId); - } + if (ctx.user.rol === "user") { + await addNewService(ctx.user.authId, newService.composeId); + } - return newService; - } catch (error) { - throw error; - } - }), + return newService; + } catch (error) { + throw error; + } + }), - one: protectedProcedure - .input(apiFindCompose) - .query(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.composeId, "access"); - } + one: protectedProcedure + .input(apiFindCompose) + .query(async ({ input, ctx }) => { + if (ctx.user.rol === "user") { + await checkServiceAccess(ctx.user.authId, input.composeId, "access"); + } - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to access this compose", - }); - } - return compose; - }), + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to access this compose", + }); + } + return compose; + }), - update: protectedProcedure - .input(apiUpdateCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to update this compose", - }); - } - return updateCompose(input.composeId, input); - }), - delete: protectedProcedure - .input(apiDeleteCompose) - .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.composeId, "delete"); - } - const composeResult = await findComposeById(input.composeId); + update: protectedProcedure + .input(apiUpdateCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to update this compose", + }); + } + return updateCompose(input.composeId, input); + }), + delete: protectedProcedure + .input(apiDeleteCompose) + .mutation(async ({ input, ctx }) => { + if (ctx.user.rol === "user") { + await checkServiceAccess(ctx.user.authId, input.composeId, "delete"); + } + const composeResult = await findComposeById(input.composeId); - if (composeResult.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to delete this compose", - }); - } - 4; + if (composeResult.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to delete this compose", + }); + } + 4; - const result = await db - .delete(compose) - .where(eq(compose.composeId, input.composeId)) - .returning(); + const result = await db + .delete(compose) + .where(eq(compose.composeId, input.composeId)) + .returning(); - const cleanupOperations = [ - async () => await removeCompose(composeResult, input.deleteVolumes), - async () => await removeDeploymentsByComposeId(composeResult), - async () => await removeComposeDirectory(composeResult.appName), - ]; + const cleanupOperations = [ + async () => await removeCompose(composeResult, input.deleteVolumes), + async () => await removeDeploymentsByComposeId(composeResult), + async () => await removeComposeDirectory(composeResult.appName), + ]; - for (const operation of cleanupOperations) { - try { - await operation(); - } catch (error) {} - } + for (const operation of cleanupOperations) { + try { + await operation(); + } catch (error) {} + } - return result[0]; - }), - cleanQueues: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to clean this compose", - }); - } - await cleanQueuesByCompose(input.composeId); - }), + return result[0]; + }), + cleanQueues: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to clean this compose", + }); + } + await cleanQueuesByCompose(input.composeId); + }), - loadServices: protectedProcedure - .input(apiFetchServices) - .query(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to load this compose", - }); - } - return await loadServices(input.composeId, input.type); - }), - fetchSourceType: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - try { - const compose = await findComposeById(input.composeId); + loadServices: protectedProcedure + .input(apiFetchServices) + .query(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to load this compose", + }); + } + return await loadServices(input.composeId, input.type); + }), + fetchSourceType: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + try { + const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to fetch this compose", - }); - } - if (compose.serverId) { - await cloneComposeRemote(compose); - } else { - await cloneCompose(compose); - } - return compose.sourceType; - } catch (err) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error fetching source type", - cause: err, - }); - } - }), + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to fetch this compose", + }); + } + if (compose.serverId) { + await cloneComposeRemote(compose); + } else { + await cloneCompose(compose); + } + return compose.sourceType; + } catch (err) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Error fetching source type", + cause: err, + }); + } + }), - randomizeCompose: protectedProcedure - .input(apiRandomizeCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to randomize this compose", - }); - } - return await randomizeComposeFile(input.composeId, input.suffix); - }), - randomizeDeployableCompose: protectedProcedure - .input(apiRandomizeCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to randomize this compose", - }); - } - return await randomizeDeployableComposeFile( - input.composeId, - input.suffix, - ); - }), - getConvertedCompose: protectedProcedure - .input(apiFindCompose) - .query(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to get this compose", - }); - } - const domains = await findDomainsByComposeId(input.composeId); - const composeFile = await addDomainToCompose(compose, domains); - return dump(composeFile, { - lineWidth: 1000, - }); - }), + randomizeCompose: protectedProcedure + .input(apiRandomizeCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to randomize this compose", + }); + } + return await randomizeComposeFile(input.composeId, input.suffix); + }), + isolatedDeployment: protectedProcedure + .input(apiRandomizeCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to randomize this compose", + }); + } + return await randomizeIsolatedDeploymentComposeFile( + input.composeId, + input.suffix + ); + }), + getConvertedCompose: protectedProcedure + .input(apiFindCompose) + .query(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to get this compose", + }); + } + const domains = await findDomainsByComposeId(input.composeId); + const composeFile = await addDomainToCompose(compose, domains); + return dump(composeFile, { + lineWidth: 1000, + }); + }), - deploy: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); + deploy: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to deploy this compose", - }); - } - const jobData: DeploymentJob = { - composeId: input.composeId, - titleLog: "Manual deployment", - type: "deploy", - applicationType: "compose", - descriptionLog: "", - server: !!compose.serverId, - }; + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to deploy this compose", + }); + } + const jobData: DeploymentJob = { + composeId: input.composeId, + titleLog: "Manual deployment", + type: "deploy", + applicationType: "compose", + descriptionLog: "", + server: !!compose.serverId, + }; - if (IS_CLOUD && compose.serverId) { - jobData.serverId = compose.serverId; - await deploy(jobData); - return true; - } - await myQueue.add( - "deployments", - { ...jobData }, - { - removeOnComplete: true, - removeOnFail: true, - }, - ); - }), - redeploy: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to redeploy this compose", - }); - } - const jobData: DeploymentJob = { - composeId: input.composeId, - titleLog: "Rebuild deployment", - type: "redeploy", - applicationType: "compose", - descriptionLog: "", - server: !!compose.serverId, - }; - if (IS_CLOUD && compose.serverId) { - jobData.serverId = compose.serverId; - await deploy(jobData); - return true; - } - await myQueue.add( - "deployments", - { ...jobData }, - { - removeOnComplete: true, - removeOnFail: true, - }, - ); - }), - stop: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to stop this compose", - }); - } - await stopCompose(input.composeId); + if (IS_CLOUD && compose.serverId) { + jobData.serverId = compose.serverId; + await deploy(jobData); + return true; + } + await myQueue.add( + "deployments", + { ...jobData }, + { + removeOnComplete: true, + removeOnFail: true, + } + ); + }), + redeploy: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to redeploy this compose", + }); + } + const jobData: DeploymentJob = { + composeId: input.composeId, + titleLog: "Rebuild deployment", + type: "redeploy", + applicationType: "compose", + descriptionLog: "", + server: !!compose.serverId, + }; + if (IS_CLOUD && compose.serverId) { + jobData.serverId = compose.serverId; + await deploy(jobData); + return true; + } + await myQueue.add( + "deployments", + { ...jobData }, + { + removeOnComplete: true, + removeOnFail: true, + } + ); + }), + stop: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to stop this compose", + }); + } + await stopCompose(input.composeId); - return true; - }), - start: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to stop this compose", - }); - } - await startCompose(input.composeId); + return true; + }), + start: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to stop this compose", + }); + } + await startCompose(input.composeId); - return true; - }), - getDefaultCommand: protectedProcedure - .input(apiFindCompose) - .query(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); + return true; + }), + getDefaultCommand: protectedProcedure + .input(apiFindCompose) + .query(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to get this compose", - }); - } - const command = createCommand(compose); - return `docker ${command}`; - }), - refreshToken: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to refresh this compose", - }); - } - await updateCompose(input.composeId, { - refreshToken: nanoid(), - }); - return true; - }), - deployTemplate: protectedProcedure - .input(apiCreateComposeByTemplate) - .mutation(async ({ ctx, input }) => { - if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); - } + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to get this compose", + }); + } + const command = createCommand(compose); + return `docker ${command}`; + }), + refreshToken: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to refresh this compose", + }); + } + await updateCompose(input.composeId, { + refreshToken: nanoid(), + }); + return true; + }), + deployTemplate: protectedProcedure + .input(apiCreateComposeByTemplate) + .mutation(async ({ ctx, input }) => { + if (ctx.user.rol === "user") { + await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + } - if (IS_CLOUD && !input.serverId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You need to use a server to create a compose", - }); - } + if (IS_CLOUD && !input.serverId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You need to use a server to create a compose", + }); + } - const composeFile = await readTemplateComposeFile(input.id); + const composeFile = await readTemplateComposeFile(input.id); - const generate = await loadTemplateModule(input.id as TemplatesKeys); + const generate = await loadTemplateModule(input.id as TemplatesKeys); - const admin = await findAdminById(ctx.user.adminId); - let serverIp = admin.serverIp || "127.0.0.1"; + const admin = await findAdminById(ctx.user.adminId); + let serverIp = admin.serverIp || "127.0.0.1"; - const project = await findProjectById(input.projectId); + const project = await findProjectById(input.projectId); - if (input.serverId) { - const server = await findServerById(input.serverId); - serverIp = server.ipAddress; - } else if (process.env.NODE_ENV === "development") { - serverIp = "127.0.0.1"; - } - const projectName = slugify(`${project.name} ${input.id}`); - const { envs, mounts, domains } = generate({ - serverIp: serverIp || "", - projectName: projectName, - }); + if (input.serverId) { + const server = await findServerById(input.serverId); + serverIp = server.ipAddress; + } else if (process.env.NODE_ENV === "development") { + serverIp = "127.0.0.1"; + } + const projectName = slugify(`${project.name} ${input.id}`); + const { envs, mounts, domains } = generate({ + serverIp: serverIp || "", + projectName: projectName, + }); - const compose = await createComposeByTemplate({ - ...input, - composeFile: composeFile, - env: envs?.join("\n"), - serverId: input.serverId, - name: input.id, - sourceType: "raw", - appName: `${projectName}-${generatePassword(6)}`, - }); + const compose = await createComposeByTemplate({ + ...input, + composeFile: composeFile, + env: envs?.join("\n"), + serverId: input.serverId, + name: input.id, + sourceType: "raw", + appName: `${projectName}-${generatePassword(6)}`, + }); - if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, compose.composeId); - } + if (ctx.user.rol === "user") { + await addNewService(ctx.user.authId, compose.composeId); + } - if (mounts && mounts?.length > 0) { - for (const mount of mounts) { - await createMount({ - filePath: mount.filePath, - mountPath: "", - content: mount.content, - serviceId: compose.composeId, - serviceType: "compose", - type: "file", - }); - } - } + if (mounts && mounts?.length > 0) { + for (const mount of mounts) { + await createMount({ + filePath: mount.filePath, + mountPath: "", + content: mount.content, + serviceId: compose.composeId, + serviceType: "compose", + type: "file", + }); + } + } - if (domains && domains?.length > 0) { - for (const domain of domains) { - await createDomain({ - ...domain, - domainType: "compose", - certificateType: "none", - composeId: compose.composeId, - }); - } - } + if (domains && domains?.length > 0) { + for (const domain of domains) { + await createDomain({ + ...domain, + domainType: "compose", + certificateType: "none", + composeId: compose.composeId, + }); + } + } - return null; - }), + return null; + }), - templates: protectedProcedure.query(async () => { - const templatesData = templates.map((t) => ({ - name: t.name, - description: t.description, - id: t.id, - links: t.links, - tags: t.tags, - logo: t.logo, - version: t.version, - })); + templates: protectedProcedure.query(async () => { + const templatesData = templates.map((t) => ({ + name: t.name, + description: t.description, + id: t.id, + links: t.links, + tags: t.tags, + logo: t.logo, + version: t.version, + })); - return templatesData; - }), + return templatesData; + }), - getTags: protectedProcedure.query(async ({ input }) => { - const allTags = templates.flatMap((template) => template.tags); - const uniqueTags = _.uniq(allTags); - return uniqueTags; - }), + getTags: protectedProcedure.query(async ({ input }) => { + const allTags = templates.flatMap((template) => template.tags); + const uniqueTags = _.uniq(allTags); + return uniqueTags; + }), }); diff --git a/packages/server/src/db/schema/compose.ts b/packages/server/src/db/schema/compose.ts index 8efcc314..e0f13c29 100644 --- a/packages/server/src/db/schema/compose.ts +++ b/packages/server/src/db/schema/compose.ts @@ -16,170 +16,170 @@ import { sshKeys } from "./ssh-key"; import { generateAppName } from "./utils"; export const sourceTypeCompose = pgEnum("sourceTypeCompose", [ - "git", - "github", - "gitlab", - "bitbucket", - "raw", + "git", + "github", + "gitlab", + "bitbucket", + "raw", ]); export const composeType = pgEnum("composeType", ["docker-compose", "stack"]); export const compose = pgTable("compose", { - composeId: text("composeId") - .notNull() - .primaryKey() - .$defaultFn(() => nanoid()), - name: text("name").notNull(), - appName: text("appName") - .notNull() - .$defaultFn(() => generateAppName("compose")), - description: text("description"), - env: text("env"), - composeFile: text("composeFile").notNull().default(""), - refreshToken: text("refreshToken").$defaultFn(() => nanoid()), - sourceType: sourceTypeCompose("sourceType").notNull().default("github"), - composeType: composeType("composeType").notNull().default("docker-compose"), - // Github - repository: text("repository"), - owner: text("owner"), - branch: text("branch"), - autoDeploy: boolean("autoDeploy").$defaultFn(() => true), - // Gitlab - gitlabProjectId: integer("gitlabProjectId"), - gitlabRepository: text("gitlabRepository"), - gitlabOwner: text("gitlabOwner"), - gitlabBranch: text("gitlabBranch"), - gitlabPathNamespace: text("gitlabPathNamespace"), - // Bitbucket - bitbucketRepository: text("bitbucketRepository"), - bitbucketOwner: text("bitbucketOwner"), - bitbucketBranch: text("bitbucketBranch"), - // Git - customGitUrl: text("customGitUrl"), - customGitBranch: text("customGitBranch"), - customGitSSHKeyId: text("customGitSSHKeyId").references( - () => sshKeys.sshKeyId, - { - onDelete: "set null", - }, - ), - command: text("command").notNull().default(""), - // - composePath: text("composePath").notNull().default("./docker-compose.yml"), - suffix: text("suffix").notNull().default(""), - randomize: boolean("randomize").notNull().default(false), - deployable: boolean("deployable").notNull().default(false), - composeStatus: applicationStatus("composeStatus").notNull().default("idle"), - projectId: text("projectId") - .notNull() - .references(() => projects.projectId, { onDelete: "cascade" }), - createdAt: text("createdAt") - .notNull() - .$defaultFn(() => new Date().toISOString()), + composeId: text("composeId") + .notNull() + .primaryKey() + .$defaultFn(() => nanoid()), + name: text("name").notNull(), + appName: text("appName") + .notNull() + .$defaultFn(() => generateAppName("compose")), + description: text("description"), + env: text("env"), + composeFile: text("composeFile").notNull().default(""), + refreshToken: text("refreshToken").$defaultFn(() => nanoid()), + sourceType: sourceTypeCompose("sourceType").notNull().default("github"), + composeType: composeType("composeType").notNull().default("docker-compose"), + // Github + repository: text("repository"), + owner: text("owner"), + branch: text("branch"), + autoDeploy: boolean("autoDeploy").$defaultFn(() => true), + // Gitlab + gitlabProjectId: integer("gitlabProjectId"), + gitlabRepository: text("gitlabRepository"), + gitlabOwner: text("gitlabOwner"), + gitlabBranch: text("gitlabBranch"), + gitlabPathNamespace: text("gitlabPathNamespace"), + // Bitbucket + bitbucketRepository: text("bitbucketRepository"), + bitbucketOwner: text("bitbucketOwner"), + bitbucketBranch: text("bitbucketBranch"), + // Git + customGitUrl: text("customGitUrl"), + customGitBranch: text("customGitBranch"), + customGitSSHKeyId: text("customGitSSHKeyId").references( + () => sshKeys.sshKeyId, + { + onDelete: "set null", + } + ), + command: text("command").notNull().default(""), + // + composePath: text("composePath").notNull().default("./docker-compose.yml"), + suffix: text("suffix").notNull().default(""), + randomize: boolean("randomize").notNull().default(false), + isolatedDeployment: boolean("isolatedDeployment").notNull().default(false), + composeStatus: applicationStatus("composeStatus").notNull().default("idle"), + projectId: text("projectId") + .notNull() + .references(() => projects.projectId, { onDelete: "cascade" }), + createdAt: text("createdAt") + .notNull() + .$defaultFn(() => new Date().toISOString()), - githubId: text("githubId").references(() => github.githubId, { - onDelete: "set null", - }), - gitlabId: text("gitlabId").references(() => gitlab.gitlabId, { - onDelete: "set null", - }), - bitbucketId: text("bitbucketId").references(() => bitbucket.bitbucketId, { - onDelete: "set null", - }), - serverId: text("serverId").references(() => server.serverId, { - onDelete: "cascade", - }), + githubId: text("githubId").references(() => github.githubId, { + onDelete: "set null", + }), + gitlabId: text("gitlabId").references(() => gitlab.gitlabId, { + onDelete: "set null", + }), + bitbucketId: text("bitbucketId").references(() => bitbucket.bitbucketId, { + onDelete: "set null", + }), + serverId: text("serverId").references(() => server.serverId, { + onDelete: "cascade", + }), }); export const composeRelations = relations(compose, ({ one, many }) => ({ - project: one(projects, { - fields: [compose.projectId], - references: [projects.projectId], - }), - deployments: many(deployments), - mounts: many(mounts), - customGitSSHKey: one(sshKeys, { - fields: [compose.customGitSSHKeyId], - references: [sshKeys.sshKeyId], - }), - domains: many(domains), - github: one(github, { - fields: [compose.githubId], - references: [github.githubId], - }), - gitlab: one(gitlab, { - fields: [compose.gitlabId], - references: [gitlab.gitlabId], - }), - bitbucket: one(bitbucket, { - fields: [compose.bitbucketId], - references: [bitbucket.bitbucketId], - }), - server: one(server, { - fields: [compose.serverId], - references: [server.serverId], - }), + project: one(projects, { + fields: [compose.projectId], + references: [projects.projectId], + }), + deployments: many(deployments), + mounts: many(mounts), + customGitSSHKey: one(sshKeys, { + fields: [compose.customGitSSHKeyId], + references: [sshKeys.sshKeyId], + }), + domains: many(domains), + github: one(github, { + fields: [compose.githubId], + references: [github.githubId], + }), + gitlab: one(gitlab, { + fields: [compose.gitlabId], + references: [gitlab.gitlabId], + }), + bitbucket: one(bitbucket, { + fields: [compose.bitbucketId], + references: [bitbucket.bitbucketId], + }), + server: one(server, { + fields: [compose.serverId], + references: [server.serverId], + }), })); const createSchema = createInsertSchema(compose, { - name: z.string().min(1), - description: z.string(), - env: z.string().optional(), - composeFile: z.string().min(1), - projectId: z.string(), - customGitSSHKeyId: z.string().optional(), - command: z.string().optional(), - composePath: z.string().min(1), - composeType: z.enum(["docker-compose", "stack"]).optional(), + name: z.string().min(1), + description: z.string(), + env: z.string().optional(), + composeFile: z.string().min(1), + projectId: z.string(), + customGitSSHKeyId: z.string().optional(), + command: z.string().optional(), + composePath: z.string().min(1), + composeType: z.enum(["docker-compose", "stack"]).optional(), }); export const apiCreateCompose = createSchema.pick({ - name: true, - description: true, - projectId: true, - composeType: true, - appName: true, - serverId: true, + name: true, + description: true, + projectId: true, + composeType: true, + appName: true, + serverId: true, }); export const apiCreateComposeByTemplate = createSchema - .pick({ - projectId: true, - }) - .extend({ - id: z.string().min(1), - serverId: z.string().optional(), - }); + .pick({ + projectId: true, + }) + .extend({ + id: z.string().min(1), + serverId: z.string().optional(), + }); export const apiFindCompose = z.object({ - composeId: z.string().min(1), + composeId: z.string().min(1), }); export const apiDeleteCompose = z.object({ - composeId: z.string().min(1), - deleteVolumes: z.boolean(), + composeId: z.string().min(1), + deleteVolumes: z.boolean(), }); export const apiFetchServices = z.object({ - composeId: z.string().min(1), - type: z.enum(["fetch", "cache"]).optional().default("cache"), + composeId: z.string().min(1), + type: z.enum(["fetch", "cache"]).optional().default("cache"), }); export const apiUpdateCompose = createSchema - .partial() - .extend({ - composeId: z.string(), - composeFile: z.string().optional(), - command: z.string().optional(), - }) - .omit({ serverId: true }); + .partial() + .extend({ + composeId: z.string(), + composeFile: z.string().optional(), + command: z.string().optional(), + }) + .omit({ serverId: true }); export const apiRandomizeCompose = createSchema - .pick({ - composeId: true, - }) - .extend({ - suffix: z.string().optional(), - composeId: z.string().min(1), - }); + .pick({ + composeId: true, + }) + .extend({ + suffix: z.string().optional(), + composeId: z.string().min(1), + }); diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts index f5cedfd7..648b598f 100644 --- a/packages/server/src/utils/builders/compose.ts +++ b/packages/server/src/utils/builders/compose.ts @@ -1,117 +1,117 @@ import { - createWriteStream, - existsSync, - mkdirSync, - readFileSync, - writeFileSync, + createWriteStream, + existsSync, + mkdirSync, + readFileSync, + writeFileSync, } from "node:fs"; import { dirname, join } from "node:path"; import { paths } from "@dokploy/server/constants"; import type { InferResultType } from "@dokploy/server/types/with"; import boxen from "boxen"; import { - writeDomainsToCompose, - writeDomainsToComposeRemote, + writeDomainsToCompose, + writeDomainsToComposeRemote, } from "../docker/domain"; import { - encodeBase64, - getEnviromentVariablesObject, - prepareEnvironmentVariables, + encodeBase64, + getEnviromentVariablesObject, + prepareEnvironmentVariables, } from "../docker/utils"; import { execAsync, execAsyncRemote } from "../process/execAsync"; import { spawnAsync } from "../process/spawnAsync"; export type ComposeNested = InferResultType< - "compose", - { project: true; mounts: true; domains: true } + "compose", + { project: true; mounts: true; domains: true } >; export const buildCompose = async (compose: ComposeNested, logPath: string) => { - const writeStream = createWriteStream(logPath, { flags: "a" }); - const { sourceType, appName, mounts, composeType, domains } = compose; - try { - const { COMPOSE_PATH } = paths(); - const command = createCommand(compose); - await writeDomainsToCompose(compose, domains); - createEnvFile(compose); + const writeStream = createWriteStream(logPath, { flags: "a" }); + const { sourceType, appName, mounts, composeType, domains } = compose; + try { + const { COMPOSE_PATH } = paths(); + const command = createCommand(compose); + await writeDomainsToCompose(compose, domains); + createEnvFile(compose); - if (compose.deployable) { - await execAsync( - `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}`, - ); - } + if (compose.isolatedDeployment) { + await execAsync( + `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}` + ); + } - const logContent = ` + const logContent = ` App Name: ${appName} Build Compose 🐳 Detected: ${mounts.length} mounts 📂 Command: docker ${command} Source Type: docker ${sourceType} ✅ Compose Type: ${composeType} ✅`; - const logBox = boxen(logContent, { - padding: { - left: 1, - right: 1, - bottom: 1, - }, - width: 80, - borderStyle: "double", - }); - writeStream.write(`\n${logBox}\n`); - const projectPath = join(COMPOSE_PATH, compose.appName, "code"); + const logBox = boxen(logContent, { + padding: { + left: 1, + right: 1, + bottom: 1, + }, + width: 80, + borderStyle: "double", + }); + writeStream.write(`\n${logBox}\n`); + const projectPath = join(COMPOSE_PATH, compose.appName, "code"); - await spawnAsync( - "docker", - [...command.split(" ")], - (data) => { - if (writeStream.writable) { - writeStream.write(data.toString()); - } - }, - { - cwd: projectPath, - env: { - NODE_ENV: process.env.NODE_ENV, - PATH: process.env.PATH, - ...(composeType === "stack" && { - ...getEnviromentVariablesObject(compose.env, compose.project.env), - }), - }, - }, - ); + await spawnAsync( + "docker", + [...command.split(" ")], + (data) => { + if (writeStream.writable) { + writeStream.write(data.toString()); + } + }, + { + cwd: projectPath, + env: { + NODE_ENV: process.env.NODE_ENV, + PATH: process.env.PATH, + ...(composeType === "stack" && { + ...getEnviromentVariablesObject(compose.env, compose.project.env), + }), + }, + } + ); - if (compose.deployable) { - await execAsync( - `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1`, - ); - } + if (compose.isolatedDeployment) { + await execAsync( + `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1` + ); + } - writeStream.write("Docker Compose Deployed: ✅"); - } catch (error) { - writeStream.write(`Error ❌ ${(error as Error).message}`); - throw error; - } finally { - writeStream.end(); - } + writeStream.write("Docker Compose Deployed: ✅"); + } catch (error) { + writeStream.write(`Error ❌ ${(error as Error).message}`); + throw error; + } finally { + writeStream.end(); + } }; export const getBuildComposeCommand = async ( - compose: ComposeNested, - logPath: string, + compose: ComposeNested, + logPath: string ) => { - const { COMPOSE_PATH } = paths(true); - const { sourceType, appName, mounts, composeType, domains, composePath } = - compose; - const command = createCommand(compose); - const envCommand = getCreateEnvFileCommand(compose); - const projectPath = join(COMPOSE_PATH, compose.appName, "code"); - const exportEnvCommand = getExportEnvCommand(compose); + const { COMPOSE_PATH } = paths(true); + const { sourceType, appName, mounts, composeType, domains, composePath } = + compose; + const command = createCommand(compose); + const envCommand = getCreateEnvFileCommand(compose); + const projectPath = join(COMPOSE_PATH, compose.appName, "code"); + const exportEnvCommand = getExportEnvCommand(compose); - const newCompose = await writeDomainsToComposeRemote( - compose, - domains, - logPath, - ); - const logContent = ` + const newCompose = await writeDomainsToComposeRemote( + compose, + domains, + logPath + ); + const logContent = ` App Name: ${appName} Build Compose 🐳 Detected: ${mounts.length} mounts 📂 @@ -119,17 +119,17 @@ Command: docker ${command} Source Type: docker ${sourceType} ✅ Compose Type: ${composeType} ✅`; - const logBox = boxen(logContent, { - padding: { - left: 1, - right: 1, - bottom: 1, - }, - width: 80, - borderStyle: "double", - }); + const logBox = boxen(logContent, { + padding: { + left: 1, + right: 1, + bottom: 1, + }, + width: 80, + borderStyle: "double", + }); - const bashCommand = ` + const bashCommand = ` set -e { echo "${logBox}" >> "${logPath}" @@ -141,9 +141,9 @@ Compose Type: ${composeType} ✅`; cd "${projectPath}"; ${exportEnvCommand} - ${compose.deployable ? `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}` : ""} + ${compose.isolatedDeployment ? `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}` : ""} docker ${command.split(" ").join(" ")} >> "${logPath}" 2>&1 || { echo "Error: ❌ Docker command failed" >> "${logPath}"; exit 1; } - ${compose.deployable ? `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1` : ""} + ${compose.isolatedDeployment ? `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1` : ""} echo "Docker Compose Deployed: ✅" >> "${logPath}" } || { @@ -152,106 +152,106 @@ Compose Type: ${composeType} ✅`; } `; - return await execAsyncRemote(compose.serverId, bashCommand); + return await execAsyncRemote(compose.serverId, bashCommand); }; const sanitizeCommand = (command: string) => { - const sanitizedCommand = command.trim(); + const sanitizedCommand = command.trim(); - const parts = sanitizedCommand.split(/\s+/); + const parts = sanitizedCommand.split(/\s+/); - const restCommand = parts.map((arg) => arg.replace(/^"(.*)"$/, "$1")); + const restCommand = parts.map((arg) => arg.replace(/^"(.*)"$/, "$1")); - return restCommand.join(" "); + return restCommand.join(" "); }; export const createCommand = (compose: ComposeNested) => { - const { composeType, appName, sourceType } = compose; - if (compose.command) { - return `${sanitizeCommand(compose.command)}`; - } + const { composeType, appName, sourceType } = compose; + if (compose.command) { + return `${sanitizeCommand(compose.command)}`; + } - const path = - sourceType === "raw" ? "docker-compose.yml" : compose.composePath; - let command = ""; + const path = + sourceType === "raw" ? "docker-compose.yml" : compose.composePath; + let command = ""; - if (composeType === "docker-compose") { - command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`; - } else if (composeType === "stack") { - command = `stack deploy -c ${path} ${appName} --prune`; - } + if (composeType === "docker-compose") { + command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`; + } else if (composeType === "stack") { + command = `stack deploy -c ${path} ${appName} --prune`; + } - return command; + return command; }; const createEnvFile = (compose: ComposeNested) => { - const { COMPOSE_PATH } = paths(); - const { env, composePath, appName } = compose; - const composeFilePath = - join(COMPOSE_PATH, appName, "code", composePath) || - join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); + const { COMPOSE_PATH } = paths(); + const { env, composePath, appName } = compose; + const composeFilePath = + join(COMPOSE_PATH, appName, "code", composePath) || + join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); - const envFilePath = join(dirname(composeFilePath), ".env"); - let envContent = env || ""; - if (!envContent.includes("DOCKER_CONFIG")) { - envContent += "\nDOCKER_CONFIG=/root/.docker/config.json"; - } + const envFilePath = join(dirname(composeFilePath), ".env"); + let envContent = env || ""; + if (!envContent.includes("DOCKER_CONFIG")) { + envContent += "\nDOCKER_CONFIG=/root/.docker/config.json"; + } - if (compose.randomize) { - envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; - } + if (compose.randomize) { + envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; + } - const envFileContent = prepareEnvironmentVariables( - envContent, - compose.project.env, - ).join("\n"); + const envFileContent = prepareEnvironmentVariables( + envContent, + compose.project.env + ).join("\n"); - if (!existsSync(dirname(envFilePath))) { - mkdirSync(dirname(envFilePath), { recursive: true }); - } - writeFileSync(envFilePath, envFileContent); + if (!existsSync(dirname(envFilePath))) { + mkdirSync(dirname(envFilePath), { recursive: true }); + } + writeFileSync(envFilePath, envFileContent); }; export const getCreateEnvFileCommand = (compose: ComposeNested) => { - const { COMPOSE_PATH } = paths(true); - const { env, composePath, appName } = compose; - const composeFilePath = - join(COMPOSE_PATH, appName, "code", composePath) || - join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); + const { COMPOSE_PATH } = paths(true); + const { env, composePath, appName } = compose; + const composeFilePath = + join(COMPOSE_PATH, appName, "code", composePath) || + join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); - const envFilePath = join(dirname(composeFilePath), ".env"); + const envFilePath = join(dirname(composeFilePath), ".env"); - let envContent = env || ""; - if (!envContent.includes("DOCKER_CONFIG")) { - envContent += "\nDOCKER_CONFIG=/root/.docker/config.json"; - } + let envContent = env || ""; + if (!envContent.includes("DOCKER_CONFIG")) { + envContent += "\nDOCKER_CONFIG=/root/.docker/config.json"; + } - if (compose.randomize) { - envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; - } + if (compose.randomize) { + envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; + } - const envFileContent = prepareEnvironmentVariables( - envContent, - compose.project.env, - ).join("\n"); + const envFileContent = prepareEnvironmentVariables( + envContent, + compose.project.env + ).join("\n"); - const encodedContent = encodeBase64(envFileContent); - return ` + const encodedContent = encodeBase64(envFileContent); + return ` touch ${envFilePath}; echo "${encodedContent}" | base64 -d > "${envFilePath}"; `; }; const getExportEnvCommand = (compose: ComposeNested) => { - if (compose.composeType !== "stack") return ""; + if (compose.composeType !== "stack") return ""; - const envVars = getEnviromentVariablesObject( - compose.env, - compose.project.env, - ); - const exports = Object.entries(envVars) - .map(([key, value]) => `export ${key}=${JSON.stringify(value)}`) - .join("\n"); + const envVars = getEnviromentVariablesObject( + compose.env, + compose.project.env + ); + const exports = Object.entries(envVars) + .map(([key, value]) => `export ${key}=${JSON.stringify(value)}`) + .join("\n"); - return exports ? `\n# Export environment variables\n${exports}\n` : ""; + return exports ? `\n# Export environment variables\n${exports}\n` : ""; }; diff --git a/packages/server/src/utils/docker/collision.ts b/packages/server/src/utils/docker/collision.ts index b905d486..e0fa725a 100644 --- a/packages/server/src/utils/docker/collision.ts +++ b/packages/server/src/utils/docker/collision.ts @@ -6,41 +6,41 @@ import { addSuffixToAllVolumes } from "./compose/volume"; import type { ComposeSpecification } from "./types"; export const addAppNameToPreventCollision = ( - composeData: ComposeSpecification, - appName: string, + composeData: ComposeSpecification, + appName: string ): ComposeSpecification => { - let updatedComposeData = { ...composeData }; + let updatedComposeData = { ...composeData }; - updatedComposeData = addAppNameToAllServiceNames(updatedComposeData, appName); - updatedComposeData = addSuffixToAllVolumes(updatedComposeData, appName); - return updatedComposeData; + updatedComposeData = addAppNameToAllServiceNames(updatedComposeData, appName); + updatedComposeData = addSuffixToAllVolumes(updatedComposeData, appName); + return updatedComposeData; }; -export const randomizeDeployableComposeFile = async ( - composeId: string, - suffix?: string, +export const randomizeIsolatedDeploymentComposeFile = async ( + composeId: string, + suffix?: string ) => { - const compose = await findComposeById(composeId); - const composeFile = compose.composeFile; - const composeData = load(composeFile) as ComposeSpecification; + const compose = await findComposeById(composeId); + const composeFile = compose.composeFile; + const composeData = load(composeFile) as ComposeSpecification; - const randomSuffix = suffix || compose.appName || generateRandomHash(); + const randomSuffix = suffix || compose.appName || generateRandomHash(); - const newComposeFile = addAppNameToPreventCollision( - composeData, - randomSuffix, - ); + const newComposeFile = addAppNameToPreventCollision( + composeData, + randomSuffix + ); - return dump(newComposeFile); + return dump(newComposeFile); }; export const randomizeDeployableSpecificationFile = ( - composeSpec: ComposeSpecification, - suffix?: string, + composeSpec: ComposeSpecification, + suffix?: string ) => { - if (!suffix) { - return composeSpec; - } - const newComposeFile = addAppNameToPreventCollision(composeSpec, suffix); - return newComposeFile; + if (!suffix) { + return composeSpec; + } + const newComposeFile = addAppNameToPreventCollision(composeSpec, suffix); + return newComposeFile; }; diff --git a/packages/server/src/utils/docker/domain.ts b/packages/server/src/utils/docker/domain.ts index 6846c830..f9eade7d 100644 --- a/packages/server/src/utils/docker/domain.ts +++ b/packages/server/src/utils/docker/domain.ts @@ -7,346 +7,346 @@ import type { Domain } from "@dokploy/server/services/domain"; import { dump, load } from "js-yaml"; import { execAsyncRemote } from "../process/execAsync"; import { - cloneRawBitbucketRepository, - cloneRawBitbucketRepositoryRemote, + cloneRawBitbucketRepository, + cloneRawBitbucketRepositoryRemote, } from "../providers/bitbucket"; import { - cloneGitRawRepository, - cloneRawGitRepositoryRemote, + cloneGitRawRepository, + cloneRawGitRepositoryRemote, } from "../providers/git"; import { - cloneRawGithubRepository, - cloneRawGithubRepositoryRemote, + cloneRawGithubRepository, + cloneRawGithubRepositoryRemote, } from "../providers/github"; import { - cloneRawGitlabRepository, - cloneRawGitlabRepositoryRemote, + cloneRawGitlabRepository, + cloneRawGitlabRepositoryRemote, } from "../providers/gitlab"; import { - createComposeFileRaw, - createComposeFileRawRemote, + createComposeFileRaw, + createComposeFileRawRemote, } from "../providers/raw"; import { randomizeDeployableSpecificationFile } from "./collision"; import { randomizeSpecificationFile } from "./compose"; import type { - ComposeSpecification, - DefinitionsService, - PropertiesNetworks, + ComposeSpecification, + DefinitionsService, + PropertiesNetworks, } from "./types"; import { encodeBase64 } from "./utils"; export const cloneCompose = async (compose: Compose) => { - if (compose.sourceType === "github") { - await cloneRawGithubRepository(compose); - } else if (compose.sourceType === "gitlab") { - await cloneRawGitlabRepository(compose); - } else if (compose.sourceType === "bitbucket") { - await cloneRawBitbucketRepository(compose); - } else if (compose.sourceType === "git") { - await cloneGitRawRepository(compose); - } else if (compose.sourceType === "raw") { - await createComposeFileRaw(compose); - } + if (compose.sourceType === "github") { + await cloneRawGithubRepository(compose); + } else if (compose.sourceType === "gitlab") { + await cloneRawGitlabRepository(compose); + } else if (compose.sourceType === "bitbucket") { + await cloneRawBitbucketRepository(compose); + } else if (compose.sourceType === "git") { + await cloneGitRawRepository(compose); + } else if (compose.sourceType === "raw") { + await createComposeFileRaw(compose); + } }; export const cloneComposeRemote = async (compose: Compose) => { - if (compose.sourceType === "github") { - await cloneRawGithubRepositoryRemote(compose); - } else if (compose.sourceType === "gitlab") { - await cloneRawGitlabRepositoryRemote(compose); - } else if (compose.sourceType === "bitbucket") { - await cloneRawBitbucketRepositoryRemote(compose); - } else if (compose.sourceType === "git") { - await cloneRawGitRepositoryRemote(compose); - } else if (compose.sourceType === "raw") { - await createComposeFileRawRemote(compose); - } + if (compose.sourceType === "github") { + await cloneRawGithubRepositoryRemote(compose); + } else if (compose.sourceType === "gitlab") { + await cloneRawGitlabRepositoryRemote(compose); + } else if (compose.sourceType === "bitbucket") { + await cloneRawBitbucketRepositoryRemote(compose); + } else if (compose.sourceType === "git") { + await cloneRawGitRepositoryRemote(compose); + } else if (compose.sourceType === "raw") { + await createComposeFileRawRemote(compose); + } }; export const getComposePath = (compose: Compose) => { - const { COMPOSE_PATH } = paths(!!compose.serverId); - const { appName, sourceType, composePath } = compose; - let path = ""; + const { COMPOSE_PATH } = paths(!!compose.serverId); + const { appName, sourceType, composePath } = compose; + let path = ""; - if (sourceType === "raw") { - path = "docker-compose.yml"; - } else { - path = composePath; - } + if (sourceType === "raw") { + path = "docker-compose.yml"; + } else { + path = composePath; + } - return join(COMPOSE_PATH, appName, "code", path); + return join(COMPOSE_PATH, appName, "code", path); }; export const loadDockerCompose = async ( - compose: Compose, + compose: Compose ): Promise => { - const path = getComposePath(compose); + const path = getComposePath(compose); - if (existsSync(path)) { - const yamlStr = readFileSync(path, "utf8"); - const parsedConfig = load(yamlStr) as ComposeSpecification; - return parsedConfig; - } - return null; + if (existsSync(path)) { + const yamlStr = readFileSync(path, "utf8"); + const parsedConfig = load(yamlStr) as ComposeSpecification; + return parsedConfig; + } + return null; }; export const loadDockerComposeRemote = async ( - compose: Compose, + compose: Compose ): Promise => { - const path = getComposePath(compose); - try { - if (!compose.serverId) { - return null; - } - const { stdout, stderr } = await execAsyncRemote( - compose.serverId, - `cat ${path}`, - ); + const path = getComposePath(compose); + try { + if (!compose.serverId) { + return null; + } + const { stdout, stderr } = await execAsyncRemote( + compose.serverId, + `cat ${path}` + ); - if (stderr) { - return null; - } - if (!stdout) return null; - const parsedConfig = load(stdout) as ComposeSpecification; - return parsedConfig; - } catch (err) { - return null; - } + if (stderr) { + return null; + } + if (!stdout) return null; + const parsedConfig = load(stdout) as ComposeSpecification; + return parsedConfig; + } catch (err) { + return null; + } }; export const readComposeFile = async (compose: Compose) => { - const path = getComposePath(compose); - if (existsSync(path)) { - const yamlStr = readFileSync(path, "utf8"); - return yamlStr; - } - return null; + const path = getComposePath(compose); + if (existsSync(path)) { + const yamlStr = readFileSync(path, "utf8"); + return yamlStr; + } + return null; }; export const writeDomainsToCompose = async ( - compose: Compose, - domains: Domain[], + compose: Compose, + domains: Domain[] ) => { - if (!domains.length) { - return; - } - const composeConverted = await addDomainToCompose(compose, domains); + if (!domains.length) { + return; + } + const composeConverted = await addDomainToCompose(compose, domains); - const path = getComposePath(compose); - const composeString = dump(composeConverted, { lineWidth: 1000 }); - try { - await writeFile(path, composeString, "utf8"); - } catch (error) { - throw error; - } + const path = getComposePath(compose); + const composeString = dump(composeConverted, { lineWidth: 1000 }); + try { + await writeFile(path, composeString, "utf8"); + } catch (error) { + throw error; + } }; export const writeDomainsToComposeRemote = async ( - compose: Compose, - domains: Domain[], - logPath: string, + compose: Compose, + domains: Domain[], + logPath: string ) => { - if (!domains.length) { - return ""; - } + if (!domains.length) { + return ""; + } - try { - const composeConverted = await addDomainToCompose(compose, domains); - const path = getComposePath(compose); + try { + const composeConverted = await addDomainToCompose(compose, domains); + const path = getComposePath(compose); - if (!composeConverted) { - return ` + if (!composeConverted) { + return ` echo "❌ Error: Compose file not found" >> ${logPath}; exit 1; `; - } - if (compose.serverId) { - const composeString = dump(composeConverted, { lineWidth: 1000 }); - const encodedContent = encodeBase64(composeString); - return `echo "${encodedContent}" | base64 -d > "${path}";`; - } - } catch (error) { - // @ts-ignore - return `echo "❌ Has occured an error: ${error?.message || error}" >> ${logPath}; + } + if (compose.serverId) { + const composeString = dump(composeConverted, { lineWidth: 1000 }); + const encodedContent = encodeBase64(composeString); + return `echo "${encodedContent}" | base64 -d > "${path}";`; + } + } catch (error) { + // @ts-ignore + return `echo "❌ Has occured an error: ${error?.message || error}" >> ${logPath}; exit 1; `; - } + } }; // (node:59875) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGTERM listeners added to [process]. Use emitter.setMaxListeners() to increase limit export const addDomainToCompose = async ( - compose: Compose, - domains: Domain[], + compose: Compose, + domains: Domain[] ) => { - const { appName } = compose; + const { appName } = compose; - let result: ComposeSpecification | null; + let result: ComposeSpecification | null; - if (compose.serverId) { - result = await loadDockerComposeRemote(compose); // aca hay que ir al servidor e ir a traer el compose file al servidor - } else { - result = await loadDockerCompose(compose); - } + if (compose.serverId) { + result = await loadDockerComposeRemote(compose); // aca hay que ir al servidor e ir a traer el compose file al servidor + } else { + result = await loadDockerCompose(compose); + } - if (!result || domains.length === 0) { - return null; - } + if (!result || domains.length === 0) { + return null; + } - if (compose.deployable) { - const randomized = randomizeDeployableSpecificationFile( - result, - compose.suffix || compose.appName, - ); - result = randomized; - } else if (compose.randomize) { - const randomized = randomizeSpecificationFile(result, compose.suffix); - result = randomized; - } + if (compose.isolatedDeployment) { + const randomized = randomizeDeployableSpecificationFile( + result, + compose.suffix || compose.appName + ); + result = randomized; + } else if (compose.randomize) { + const randomized = randomizeSpecificationFile(result, compose.suffix); + result = randomized; + } - for (const domain of domains) { - const { serviceName, https } = domain; - if (!serviceName) { - throw new Error("Service name not found"); - } - if (!result?.services?.[serviceName]) { - throw new Error(`The service ${serviceName} not found in the compose`); - } + for (const domain of domains) { + const { serviceName, https } = domain; + if (!serviceName) { + throw new Error("Service name not found"); + } + if (!result?.services?.[serviceName]) { + throw new Error(`The service ${serviceName} not found in the compose`); + } - const httpLabels = await createDomainLabels(appName, domain, "web"); - if (https) { - const httpsLabels = await createDomainLabels( - appName, - domain, - "websecure", - ); - httpLabels.push(...httpsLabels); - } + const httpLabels = await createDomainLabels(appName, domain, "web"); + if (https) { + const httpsLabels = await createDomainLabels( + appName, + domain, + "websecure" + ); + httpLabels.push(...httpsLabels); + } - let labels: DefinitionsService["labels"] = []; - if (compose.composeType === "docker-compose") { - if (!result.services[serviceName].labels) { - result.services[serviceName].labels = []; - } + let labels: DefinitionsService["labels"] = []; + if (compose.composeType === "docker-compose") { + if (!result.services[serviceName].labels) { + result.services[serviceName].labels = []; + } - labels = result.services[serviceName].labels; - } else { - // Stack Case - if (!result.services[serviceName].deploy) { - result.services[serviceName].deploy = {}; - } - if (!result.services[serviceName].deploy.labels) { - result.services[serviceName].deploy.labels = []; - } + labels = result.services[serviceName].labels; + } else { + // Stack Case + if (!result.services[serviceName].deploy) { + result.services[serviceName].deploy = {}; + } + if (!result.services[serviceName].deploy.labels) { + result.services[serviceName].deploy.labels = []; + } - labels = result.services[serviceName].deploy.labels; - } + labels = result.services[serviceName].deploy.labels; + } - if (Array.isArray(labels)) { - if (!labels.includes("traefik.enable=true")) { - labels.push("traefik.enable=true"); - } - labels.push(...httpLabels); - } + if (Array.isArray(labels)) { + if (!labels.includes("traefik.enable=true")) { + labels.push("traefik.enable=true"); + } + labels.push(...httpLabels); + } - if (!compose.deployable) { - // Add the dokploy-network to the service - result.services[serviceName].networks = addDokployNetworkToService( - result.services[serviceName].networks, - ); - } - } + if (!compose.isolatedDeployment) { + // Add the dokploy-network to the service + result.services[serviceName].networks = addDokployNetworkToService( + result.services[serviceName].networks + ); + } + } - // Add dokploy-network to the root of the compose file - if (!compose.deployable) { - result.networks = addDokployNetworkToRoot(result.networks); - } + // Add dokploy-network to the root of the compose file + if (!compose.isolatedDeployment) { + result.networks = addDokployNetworkToRoot(result.networks); + } - return result; + return result; }; export const writeComposeFile = async ( - compose: Compose, - composeSpec: ComposeSpecification, + compose: Compose, + composeSpec: ComposeSpecification ) => { - const path = getComposePath(compose); + const path = getComposePath(compose); - try { - const composeFile = dump(composeSpec, { - lineWidth: 1000, - }); - fs.writeFileSync(path, composeFile, "utf8"); - } catch (e) { - console.error("Error saving the YAML config file:", e); - } + try { + const composeFile = dump(composeSpec, { + lineWidth: 1000, + }); + fs.writeFileSync(path, composeFile, "utf8"); + } catch (e) { + console.error("Error saving the YAML config file:", e); + } }; export const createDomainLabels = async ( - appName: string, - domain: Domain, - entrypoint: "web" | "websecure", + appName: string, + domain: Domain, + entrypoint: "web" | "websecure" ) => { - const { host, port, https, uniqueConfigKey, certificateType, path } = domain; - const routerName = `${appName}-${uniqueConfigKey}-${entrypoint}`; - const labels = [ - `traefik.http.routers.${routerName}.rule=Host(\`${host}\`)${path && path !== "/" ? ` && PathPrefix(\`${path}\`)` : ""}`, - `traefik.http.routers.${routerName}.entrypoints=${entrypoint}`, - `traefik.http.services.${routerName}.loadbalancer.server.port=${port}`, - `traefik.http.routers.${routerName}.service=${routerName}`, - ]; + const { host, port, https, uniqueConfigKey, certificateType, path } = domain; + const routerName = `${appName}-${uniqueConfigKey}-${entrypoint}`; + const labels = [ + `traefik.http.routers.${routerName}.rule=Host(\`${host}\`)${path && path !== "/" ? ` && PathPrefix(\`${path}\`)` : ""}`, + `traefik.http.routers.${routerName}.entrypoints=${entrypoint}`, + `traefik.http.services.${routerName}.loadbalancer.server.port=${port}`, + `traefik.http.routers.${routerName}.service=${routerName}`, + ]; - if (entrypoint === "web" && https) { - labels.push( - `traefik.http.routers.${routerName}.middlewares=redirect-to-https@file`, - ); - } + if (entrypoint === "web" && https) { + labels.push( + `traefik.http.routers.${routerName}.middlewares=redirect-to-https@file` + ); + } - if (entrypoint === "websecure") { - if (certificateType === "letsencrypt") { - labels.push( - `traefik.http.routers.${routerName}.tls.certresolver=letsencrypt`, - ); - } - } + if (entrypoint === "websecure") { + if (certificateType === "letsencrypt") { + labels.push( + `traefik.http.routers.${routerName}.tls.certresolver=letsencrypt` + ); + } + } - return labels; + return labels; }; export const addDokployNetworkToService = ( - networkService: DefinitionsService["networks"], + networkService: DefinitionsService["networks"] ) => { - let networks = networkService; - const network = "dokploy-network"; - if (!networks) { - networks = []; - } + let networks = networkService; + const network = "dokploy-network"; + if (!networks) { + networks = []; + } - if (Array.isArray(networks)) { - if (!networks.includes(network)) { - networks.push(network); - } - } else if (networks && typeof networks === "object") { - if (!(network in networks)) { - networks[network] = {}; - } - } + if (Array.isArray(networks)) { + if (!networks.includes(network)) { + networks.push(network); + } + } else if (networks && typeof networks === "object") { + if (!(network in networks)) { + networks[network] = {}; + } + } - return networks; + return networks; }; export const addDokployNetworkToRoot = ( - networkRoot: PropertiesNetworks | undefined, + networkRoot: PropertiesNetworks | undefined ) => { - let networks = networkRoot; - const network = "dokploy-network"; + let networks = networkRoot; + const network = "dokploy-network"; - if (!networks) { - networks = {}; - } + if (!networks) { + networks = {}; + } - if (networks[network] || !networks[network]) { - networks[network] = { - external: true, - }; - } + if (networks[network] || !networks[network]) { + networks[network] = { + external: true, + }; + } - return networks; + return networks; }; From a8f94540f9144e3170f5172ed0c4219053f53e4d Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 9 Feb 2025 02:20:40 -0600 Subject: [PATCH 09/11] refactor: lint --- .../compose/general/compose-file-editor.tsx | 2 +- .../compose/general/show-utilities.tsx | 8 +- apps/dokploy/server/api/routers/compose.ts | 826 +++++++++--------- packages/server/src/db/schema/compose.ts | 272 +++--- packages/server/src/utils/builders/compose.ts | 318 +++---- packages/server/src/utils/docker/collision.ts | 48 +- packages/server/src/utils/docker/domain.ts | 494 +++++------ 7 files changed, 984 insertions(+), 984 deletions(-) diff --git a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx index 47497219..71b92814 100644 --- a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx +++ b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx @@ -14,8 +14,8 @@ import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; import { validateAndFormatYAML } from "../../application/advanced/traefik/update-traefik-config"; -import { RandomizeCompose } from "./randomize-compose"; import { RandomizeDeployable } from "./isolated-deployment"; +import { RandomizeCompose } from "./randomize-compose"; import { ShowUtilities } from "./show-utilities"; interface Props { diff --git a/apps/dokploy/components/dashboard/compose/general/show-utilities.tsx b/apps/dokploy/components/dashboard/compose/general/show-utilities.tsx index 6a3721e4..214102ce 100644 --- a/apps/dokploy/components/dashboard/compose/general/show-utilities.tsx +++ b/apps/dokploy/components/dashboard/compose/general/show-utilities.tsx @@ -1,6 +1,4 @@ -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { IsolatedDeployment } from "./isolated-deployment"; -import { RandomizeCompose } from "./randomize-compose"; +import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, @@ -9,8 +7,10 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { useState } from "react"; -import { Button } from "@/components/ui/button"; +import { IsolatedDeployment } from "./isolated-deployment"; +import { RandomizeCompose } from "./randomize-compose"; interface Props { composeId: string; diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index 380fc70f..f28f33a1 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -1,22 +1,22 @@ import { slugify } from "@/lib/slug"; import { db } from "@/server/db"; import { - apiCreateCompose, - apiCreateComposeByTemplate, - apiDeleteCompose, - apiFetchServices, - apiFindCompose, - apiRandomizeCompose, - apiUpdateCompose, - compose, + apiCreateCompose, + apiCreateComposeByTemplate, + apiDeleteCompose, + apiFetchServices, + apiFindCompose, + apiRandomizeCompose, + apiUpdateCompose, + compose, } from "@/server/db/schema"; import { cleanQueuesByCompose, myQueue } from "@/server/queues/queueSetup"; import { templates } from "@/templates/templates"; import type { TemplatesKeys } from "@/templates/types/templates-data.type"; import { - generatePassword, - loadTemplateModule, - readTemplateComposeFile, + generatePassword, + loadTemplateModule, + readTemplateComposeFile, } from "@/templates/utils"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; @@ -28,443 +28,443 @@ import { createTRPCRouter, protectedProcedure } from "../trpc"; import type { DeploymentJob } from "@/server/queues/queue-types"; import { deploy } from "@/server/utils/deploy"; import { - IS_CLOUD, - addDomainToCompose, - addNewService, - checkServiceAccess, - cloneCompose, - cloneComposeRemote, - createCommand, - createCompose, - createComposeByTemplate, - createDomain, - createMount, - findAdminById, - findComposeById, - findDomainsByComposeId, - findProjectById, - findServerById, - loadServices, - randomizeComposeFile, - randomizeIsolatedDeploymentComposeFile, - removeCompose, - removeComposeDirectory, - removeDeploymentsByComposeId, - startCompose, - stopCompose, - updateCompose, + IS_CLOUD, + addDomainToCompose, + addNewService, + checkServiceAccess, + cloneCompose, + cloneComposeRemote, + createCommand, + createCompose, + createComposeByTemplate, + createDomain, + createMount, + findAdminById, + findComposeById, + findDomainsByComposeId, + findProjectById, + findServerById, + loadServices, + randomizeComposeFile, + randomizeIsolatedDeploymentComposeFile, + removeCompose, + removeComposeDirectory, + removeDeploymentsByComposeId, + startCompose, + stopCompose, + updateCompose, } from "@dokploy/server"; export const composeRouter = createTRPCRouter({ - create: protectedProcedure - .input(apiCreateCompose) - .mutation(async ({ ctx, input }) => { - try { - if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); - } + create: protectedProcedure + .input(apiCreateCompose) + .mutation(async ({ ctx, input }) => { + try { + if (ctx.user.rol === "user") { + await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + } - if (IS_CLOUD && !input.serverId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You need to use a server to create a compose", - }); - } - const project = await findProjectById(input.projectId); - if (project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to access this project", - }); - } - const newService = await createCompose(input); + if (IS_CLOUD && !input.serverId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You need to use a server to create a compose", + }); + } + const project = await findProjectById(input.projectId); + if (project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to access this project", + }); + } + const newService = await createCompose(input); - if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, newService.composeId); - } + if (ctx.user.rol === "user") { + await addNewService(ctx.user.authId, newService.composeId); + } - return newService; - } catch (error) { - throw error; - } - }), + return newService; + } catch (error) { + throw error; + } + }), - one: protectedProcedure - .input(apiFindCompose) - .query(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.composeId, "access"); - } + one: protectedProcedure + .input(apiFindCompose) + .query(async ({ input, ctx }) => { + if (ctx.user.rol === "user") { + await checkServiceAccess(ctx.user.authId, input.composeId, "access"); + } - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to access this compose", - }); - } - return compose; - }), + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to access this compose", + }); + } + return compose; + }), - update: protectedProcedure - .input(apiUpdateCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to update this compose", - }); - } - return updateCompose(input.composeId, input); - }), - delete: protectedProcedure - .input(apiDeleteCompose) - .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.composeId, "delete"); - } - const composeResult = await findComposeById(input.composeId); + update: protectedProcedure + .input(apiUpdateCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to update this compose", + }); + } + return updateCompose(input.composeId, input); + }), + delete: protectedProcedure + .input(apiDeleteCompose) + .mutation(async ({ input, ctx }) => { + if (ctx.user.rol === "user") { + await checkServiceAccess(ctx.user.authId, input.composeId, "delete"); + } + const composeResult = await findComposeById(input.composeId); - if (composeResult.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to delete this compose", - }); - } - 4; + if (composeResult.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to delete this compose", + }); + } + 4; - const result = await db - .delete(compose) - .where(eq(compose.composeId, input.composeId)) - .returning(); + const result = await db + .delete(compose) + .where(eq(compose.composeId, input.composeId)) + .returning(); - const cleanupOperations = [ - async () => await removeCompose(composeResult, input.deleteVolumes), - async () => await removeDeploymentsByComposeId(composeResult), - async () => await removeComposeDirectory(composeResult.appName), - ]; + const cleanupOperations = [ + async () => await removeCompose(composeResult, input.deleteVolumes), + async () => await removeDeploymentsByComposeId(composeResult), + async () => await removeComposeDirectory(composeResult.appName), + ]; - for (const operation of cleanupOperations) { - try { - await operation(); - } catch (error) {} - } + for (const operation of cleanupOperations) { + try { + await operation(); + } catch (error) {} + } - return result[0]; - }), - cleanQueues: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to clean this compose", - }); - } - await cleanQueuesByCompose(input.composeId); - }), + return result[0]; + }), + cleanQueues: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to clean this compose", + }); + } + await cleanQueuesByCompose(input.composeId); + }), - loadServices: protectedProcedure - .input(apiFetchServices) - .query(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to load this compose", - }); - } - return await loadServices(input.composeId, input.type); - }), - fetchSourceType: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - try { - const compose = await findComposeById(input.composeId); + loadServices: protectedProcedure + .input(apiFetchServices) + .query(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to load this compose", + }); + } + return await loadServices(input.composeId, input.type); + }), + fetchSourceType: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + try { + const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to fetch this compose", - }); - } - if (compose.serverId) { - await cloneComposeRemote(compose); - } else { - await cloneCompose(compose); - } - return compose.sourceType; - } catch (err) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error fetching source type", - cause: err, - }); - } - }), + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to fetch this compose", + }); + } + if (compose.serverId) { + await cloneComposeRemote(compose); + } else { + await cloneCompose(compose); + } + return compose.sourceType; + } catch (err) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Error fetching source type", + cause: err, + }); + } + }), - randomizeCompose: protectedProcedure - .input(apiRandomizeCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to randomize this compose", - }); - } - return await randomizeComposeFile(input.composeId, input.suffix); - }), - isolatedDeployment: protectedProcedure - .input(apiRandomizeCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to randomize this compose", - }); - } - return await randomizeIsolatedDeploymentComposeFile( - input.composeId, - input.suffix - ); - }), - getConvertedCompose: protectedProcedure - .input(apiFindCompose) - .query(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to get this compose", - }); - } - const domains = await findDomainsByComposeId(input.composeId); - const composeFile = await addDomainToCompose(compose, domains); - return dump(composeFile, { - lineWidth: 1000, - }); - }), + randomizeCompose: protectedProcedure + .input(apiRandomizeCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to randomize this compose", + }); + } + return await randomizeComposeFile(input.composeId, input.suffix); + }), + isolatedDeployment: protectedProcedure + .input(apiRandomizeCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to randomize this compose", + }); + } + return await randomizeIsolatedDeploymentComposeFile( + input.composeId, + input.suffix, + ); + }), + getConvertedCompose: protectedProcedure + .input(apiFindCompose) + .query(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to get this compose", + }); + } + const domains = await findDomainsByComposeId(input.composeId); + const composeFile = await addDomainToCompose(compose, domains); + return dump(composeFile, { + lineWidth: 1000, + }); + }), - deploy: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); + deploy: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to deploy this compose", - }); - } - const jobData: DeploymentJob = { - composeId: input.composeId, - titleLog: "Manual deployment", - type: "deploy", - applicationType: "compose", - descriptionLog: "", - server: !!compose.serverId, - }; + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to deploy this compose", + }); + } + const jobData: DeploymentJob = { + composeId: input.composeId, + titleLog: "Manual deployment", + type: "deploy", + applicationType: "compose", + descriptionLog: "", + server: !!compose.serverId, + }; - if (IS_CLOUD && compose.serverId) { - jobData.serverId = compose.serverId; - await deploy(jobData); - return true; - } - await myQueue.add( - "deployments", - { ...jobData }, - { - removeOnComplete: true, - removeOnFail: true, - } - ); - }), - redeploy: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to redeploy this compose", - }); - } - const jobData: DeploymentJob = { - composeId: input.composeId, - titleLog: "Rebuild deployment", - type: "redeploy", - applicationType: "compose", - descriptionLog: "", - server: !!compose.serverId, - }; - if (IS_CLOUD && compose.serverId) { - jobData.serverId = compose.serverId; - await deploy(jobData); - return true; - } - await myQueue.add( - "deployments", - { ...jobData }, - { - removeOnComplete: true, - removeOnFail: true, - } - ); - }), - stop: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to stop this compose", - }); - } - await stopCompose(input.composeId); + if (IS_CLOUD && compose.serverId) { + jobData.serverId = compose.serverId; + await deploy(jobData); + return true; + } + await myQueue.add( + "deployments", + { ...jobData }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); + }), + redeploy: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to redeploy this compose", + }); + } + const jobData: DeploymentJob = { + composeId: input.composeId, + titleLog: "Rebuild deployment", + type: "redeploy", + applicationType: "compose", + descriptionLog: "", + server: !!compose.serverId, + }; + if (IS_CLOUD && compose.serverId) { + jobData.serverId = compose.serverId; + await deploy(jobData); + return true; + } + await myQueue.add( + "deployments", + { ...jobData }, + { + removeOnComplete: true, + removeOnFail: true, + }, + ); + }), + stop: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to stop this compose", + }); + } + await stopCompose(input.composeId); - return true; - }), - start: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to stop this compose", - }); - } - await startCompose(input.composeId); + return true; + }), + start: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to stop this compose", + }); + } + await startCompose(input.composeId); - return true; - }), - getDefaultCommand: protectedProcedure - .input(apiFindCompose) - .query(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); + return true; + }), + getDefaultCommand: protectedProcedure + .input(apiFindCompose) + .query(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to get this compose", - }); - } - const command = createCommand(compose); - return `docker ${command}`; - }), - refreshToken: protectedProcedure - .input(apiFindCompose) - .mutation(async ({ input, ctx }) => { - const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to refresh this compose", - }); - } - await updateCompose(input.composeId, { - refreshToken: nanoid(), - }); - return true; - }), - deployTemplate: protectedProcedure - .input(apiCreateComposeByTemplate) - .mutation(async ({ ctx, input }) => { - if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); - } + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to get this compose", + }); + } + const command = createCommand(compose); + return `docker ${command}`; + }), + refreshToken: protectedProcedure + .input(apiFindCompose) + .mutation(async ({ input, ctx }) => { + const compose = await findComposeById(input.composeId); + if (compose.project.adminId !== ctx.user.adminId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to refresh this compose", + }); + } + await updateCompose(input.composeId, { + refreshToken: nanoid(), + }); + return true; + }), + deployTemplate: protectedProcedure + .input(apiCreateComposeByTemplate) + .mutation(async ({ ctx, input }) => { + if (ctx.user.rol === "user") { + await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + } - if (IS_CLOUD && !input.serverId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You need to use a server to create a compose", - }); - } + if (IS_CLOUD && !input.serverId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You need to use a server to create a compose", + }); + } - const composeFile = await readTemplateComposeFile(input.id); + const composeFile = await readTemplateComposeFile(input.id); - const generate = await loadTemplateModule(input.id as TemplatesKeys); + const generate = await loadTemplateModule(input.id as TemplatesKeys); - const admin = await findAdminById(ctx.user.adminId); - let serverIp = admin.serverIp || "127.0.0.1"; + const admin = await findAdminById(ctx.user.adminId); + let serverIp = admin.serverIp || "127.0.0.1"; - const project = await findProjectById(input.projectId); + const project = await findProjectById(input.projectId); - if (input.serverId) { - const server = await findServerById(input.serverId); - serverIp = server.ipAddress; - } else if (process.env.NODE_ENV === "development") { - serverIp = "127.0.0.1"; - } - const projectName = slugify(`${project.name} ${input.id}`); - const { envs, mounts, domains } = generate({ - serverIp: serverIp || "", - projectName: projectName, - }); + if (input.serverId) { + const server = await findServerById(input.serverId); + serverIp = server.ipAddress; + } else if (process.env.NODE_ENV === "development") { + serverIp = "127.0.0.1"; + } + const projectName = slugify(`${project.name} ${input.id}`); + const { envs, mounts, domains } = generate({ + serverIp: serverIp || "", + projectName: projectName, + }); - const compose = await createComposeByTemplate({ - ...input, - composeFile: composeFile, - env: envs?.join("\n"), - serverId: input.serverId, - name: input.id, - sourceType: "raw", - appName: `${projectName}-${generatePassword(6)}`, - }); + const compose = await createComposeByTemplate({ + ...input, + composeFile: composeFile, + env: envs?.join("\n"), + serverId: input.serverId, + name: input.id, + sourceType: "raw", + appName: `${projectName}-${generatePassword(6)}`, + }); - if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, compose.composeId); - } + if (ctx.user.rol === "user") { + await addNewService(ctx.user.authId, compose.composeId); + } - if (mounts && mounts?.length > 0) { - for (const mount of mounts) { - await createMount({ - filePath: mount.filePath, - mountPath: "", - content: mount.content, - serviceId: compose.composeId, - serviceType: "compose", - type: "file", - }); - } - } + if (mounts && mounts?.length > 0) { + for (const mount of mounts) { + await createMount({ + filePath: mount.filePath, + mountPath: "", + content: mount.content, + serviceId: compose.composeId, + serviceType: "compose", + type: "file", + }); + } + } - if (domains && domains?.length > 0) { - for (const domain of domains) { - await createDomain({ - ...domain, - domainType: "compose", - certificateType: "none", - composeId: compose.composeId, - }); - } - } + if (domains && domains?.length > 0) { + for (const domain of domains) { + await createDomain({ + ...domain, + domainType: "compose", + certificateType: "none", + composeId: compose.composeId, + }); + } + } - return null; - }), + return null; + }), - templates: protectedProcedure.query(async () => { - const templatesData = templates.map((t) => ({ - name: t.name, - description: t.description, - id: t.id, - links: t.links, - tags: t.tags, - logo: t.logo, - version: t.version, - })); + templates: protectedProcedure.query(async () => { + const templatesData = templates.map((t) => ({ + name: t.name, + description: t.description, + id: t.id, + links: t.links, + tags: t.tags, + logo: t.logo, + version: t.version, + })); - return templatesData; - }), + return templatesData; + }), - getTags: protectedProcedure.query(async ({ input }) => { - const allTags = templates.flatMap((template) => template.tags); - const uniqueTags = _.uniq(allTags); - return uniqueTags; - }), + getTags: protectedProcedure.query(async ({ input }) => { + const allTags = templates.flatMap((template) => template.tags); + const uniqueTags = _.uniq(allTags); + return uniqueTags; + }), }); diff --git a/packages/server/src/db/schema/compose.ts b/packages/server/src/db/schema/compose.ts index e0f13c29..ca8344ee 100644 --- a/packages/server/src/db/schema/compose.ts +++ b/packages/server/src/db/schema/compose.ts @@ -16,170 +16,170 @@ import { sshKeys } from "./ssh-key"; import { generateAppName } from "./utils"; export const sourceTypeCompose = pgEnum("sourceTypeCompose", [ - "git", - "github", - "gitlab", - "bitbucket", - "raw", + "git", + "github", + "gitlab", + "bitbucket", + "raw", ]); export const composeType = pgEnum("composeType", ["docker-compose", "stack"]); export const compose = pgTable("compose", { - composeId: text("composeId") - .notNull() - .primaryKey() - .$defaultFn(() => nanoid()), - name: text("name").notNull(), - appName: text("appName") - .notNull() - .$defaultFn(() => generateAppName("compose")), - description: text("description"), - env: text("env"), - composeFile: text("composeFile").notNull().default(""), - refreshToken: text("refreshToken").$defaultFn(() => nanoid()), - sourceType: sourceTypeCompose("sourceType").notNull().default("github"), - composeType: composeType("composeType").notNull().default("docker-compose"), - // Github - repository: text("repository"), - owner: text("owner"), - branch: text("branch"), - autoDeploy: boolean("autoDeploy").$defaultFn(() => true), - // Gitlab - gitlabProjectId: integer("gitlabProjectId"), - gitlabRepository: text("gitlabRepository"), - gitlabOwner: text("gitlabOwner"), - gitlabBranch: text("gitlabBranch"), - gitlabPathNamespace: text("gitlabPathNamespace"), - // Bitbucket - bitbucketRepository: text("bitbucketRepository"), - bitbucketOwner: text("bitbucketOwner"), - bitbucketBranch: text("bitbucketBranch"), - // Git - customGitUrl: text("customGitUrl"), - customGitBranch: text("customGitBranch"), - customGitSSHKeyId: text("customGitSSHKeyId").references( - () => sshKeys.sshKeyId, - { - onDelete: "set null", - } - ), - command: text("command").notNull().default(""), - // - composePath: text("composePath").notNull().default("./docker-compose.yml"), - suffix: text("suffix").notNull().default(""), - randomize: boolean("randomize").notNull().default(false), - isolatedDeployment: boolean("isolatedDeployment").notNull().default(false), - composeStatus: applicationStatus("composeStatus").notNull().default("idle"), - projectId: text("projectId") - .notNull() - .references(() => projects.projectId, { onDelete: "cascade" }), - createdAt: text("createdAt") - .notNull() - .$defaultFn(() => new Date().toISOString()), + composeId: text("composeId") + .notNull() + .primaryKey() + .$defaultFn(() => nanoid()), + name: text("name").notNull(), + appName: text("appName") + .notNull() + .$defaultFn(() => generateAppName("compose")), + description: text("description"), + env: text("env"), + composeFile: text("composeFile").notNull().default(""), + refreshToken: text("refreshToken").$defaultFn(() => nanoid()), + sourceType: sourceTypeCompose("sourceType").notNull().default("github"), + composeType: composeType("composeType").notNull().default("docker-compose"), + // Github + repository: text("repository"), + owner: text("owner"), + branch: text("branch"), + autoDeploy: boolean("autoDeploy").$defaultFn(() => true), + // Gitlab + gitlabProjectId: integer("gitlabProjectId"), + gitlabRepository: text("gitlabRepository"), + gitlabOwner: text("gitlabOwner"), + gitlabBranch: text("gitlabBranch"), + gitlabPathNamespace: text("gitlabPathNamespace"), + // Bitbucket + bitbucketRepository: text("bitbucketRepository"), + bitbucketOwner: text("bitbucketOwner"), + bitbucketBranch: text("bitbucketBranch"), + // Git + customGitUrl: text("customGitUrl"), + customGitBranch: text("customGitBranch"), + customGitSSHKeyId: text("customGitSSHKeyId").references( + () => sshKeys.sshKeyId, + { + onDelete: "set null", + }, + ), + command: text("command").notNull().default(""), + // + composePath: text("composePath").notNull().default("./docker-compose.yml"), + suffix: text("suffix").notNull().default(""), + randomize: boolean("randomize").notNull().default(false), + isolatedDeployment: boolean("isolatedDeployment").notNull().default(false), + composeStatus: applicationStatus("composeStatus").notNull().default("idle"), + projectId: text("projectId") + .notNull() + .references(() => projects.projectId, { onDelete: "cascade" }), + createdAt: text("createdAt") + .notNull() + .$defaultFn(() => new Date().toISOString()), - githubId: text("githubId").references(() => github.githubId, { - onDelete: "set null", - }), - gitlabId: text("gitlabId").references(() => gitlab.gitlabId, { - onDelete: "set null", - }), - bitbucketId: text("bitbucketId").references(() => bitbucket.bitbucketId, { - onDelete: "set null", - }), - serverId: text("serverId").references(() => server.serverId, { - onDelete: "cascade", - }), + githubId: text("githubId").references(() => github.githubId, { + onDelete: "set null", + }), + gitlabId: text("gitlabId").references(() => gitlab.gitlabId, { + onDelete: "set null", + }), + bitbucketId: text("bitbucketId").references(() => bitbucket.bitbucketId, { + onDelete: "set null", + }), + serverId: text("serverId").references(() => server.serverId, { + onDelete: "cascade", + }), }); export const composeRelations = relations(compose, ({ one, many }) => ({ - project: one(projects, { - fields: [compose.projectId], - references: [projects.projectId], - }), - deployments: many(deployments), - mounts: many(mounts), - customGitSSHKey: one(sshKeys, { - fields: [compose.customGitSSHKeyId], - references: [sshKeys.sshKeyId], - }), - domains: many(domains), - github: one(github, { - fields: [compose.githubId], - references: [github.githubId], - }), - gitlab: one(gitlab, { - fields: [compose.gitlabId], - references: [gitlab.gitlabId], - }), - bitbucket: one(bitbucket, { - fields: [compose.bitbucketId], - references: [bitbucket.bitbucketId], - }), - server: one(server, { - fields: [compose.serverId], - references: [server.serverId], - }), + project: one(projects, { + fields: [compose.projectId], + references: [projects.projectId], + }), + deployments: many(deployments), + mounts: many(mounts), + customGitSSHKey: one(sshKeys, { + fields: [compose.customGitSSHKeyId], + references: [sshKeys.sshKeyId], + }), + domains: many(domains), + github: one(github, { + fields: [compose.githubId], + references: [github.githubId], + }), + gitlab: one(gitlab, { + fields: [compose.gitlabId], + references: [gitlab.gitlabId], + }), + bitbucket: one(bitbucket, { + fields: [compose.bitbucketId], + references: [bitbucket.bitbucketId], + }), + server: one(server, { + fields: [compose.serverId], + references: [server.serverId], + }), })); const createSchema = createInsertSchema(compose, { - name: z.string().min(1), - description: z.string(), - env: z.string().optional(), - composeFile: z.string().min(1), - projectId: z.string(), - customGitSSHKeyId: z.string().optional(), - command: z.string().optional(), - composePath: z.string().min(1), - composeType: z.enum(["docker-compose", "stack"]).optional(), + name: z.string().min(1), + description: z.string(), + env: z.string().optional(), + composeFile: z.string().min(1), + projectId: z.string(), + customGitSSHKeyId: z.string().optional(), + command: z.string().optional(), + composePath: z.string().min(1), + composeType: z.enum(["docker-compose", "stack"]).optional(), }); export const apiCreateCompose = createSchema.pick({ - name: true, - description: true, - projectId: true, - composeType: true, - appName: true, - serverId: true, + name: true, + description: true, + projectId: true, + composeType: true, + appName: true, + serverId: true, }); export const apiCreateComposeByTemplate = createSchema - .pick({ - projectId: true, - }) - .extend({ - id: z.string().min(1), - serverId: z.string().optional(), - }); + .pick({ + projectId: true, + }) + .extend({ + id: z.string().min(1), + serverId: z.string().optional(), + }); export const apiFindCompose = z.object({ - composeId: z.string().min(1), + composeId: z.string().min(1), }); export const apiDeleteCompose = z.object({ - composeId: z.string().min(1), - deleteVolumes: z.boolean(), + composeId: z.string().min(1), + deleteVolumes: z.boolean(), }); export const apiFetchServices = z.object({ - composeId: z.string().min(1), - type: z.enum(["fetch", "cache"]).optional().default("cache"), + composeId: z.string().min(1), + type: z.enum(["fetch", "cache"]).optional().default("cache"), }); export const apiUpdateCompose = createSchema - .partial() - .extend({ - composeId: z.string(), - composeFile: z.string().optional(), - command: z.string().optional(), - }) - .omit({ serverId: true }); + .partial() + .extend({ + composeId: z.string(), + composeFile: z.string().optional(), + command: z.string().optional(), + }) + .omit({ serverId: true }); export const apiRandomizeCompose = createSchema - .pick({ - composeId: true, - }) - .extend({ - suffix: z.string().optional(), - composeId: z.string().min(1), - }); + .pick({ + composeId: true, + }) + .extend({ + suffix: z.string().optional(), + composeId: z.string().min(1), + }); diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts index 648b598f..6f2e8f4e 100644 --- a/packages/server/src/utils/builders/compose.ts +++ b/packages/server/src/utils/builders/compose.ts @@ -1,117 +1,117 @@ import { - createWriteStream, - existsSync, - mkdirSync, - readFileSync, - writeFileSync, + createWriteStream, + existsSync, + mkdirSync, + readFileSync, + writeFileSync, } from "node:fs"; import { dirname, join } from "node:path"; import { paths } from "@dokploy/server/constants"; import type { InferResultType } from "@dokploy/server/types/with"; import boxen from "boxen"; import { - writeDomainsToCompose, - writeDomainsToComposeRemote, + writeDomainsToCompose, + writeDomainsToComposeRemote, } from "../docker/domain"; import { - encodeBase64, - getEnviromentVariablesObject, - prepareEnvironmentVariables, + encodeBase64, + getEnviromentVariablesObject, + prepareEnvironmentVariables, } from "../docker/utils"; import { execAsync, execAsyncRemote } from "../process/execAsync"; import { spawnAsync } from "../process/spawnAsync"; export type ComposeNested = InferResultType< - "compose", - { project: true; mounts: true; domains: true } + "compose", + { project: true; mounts: true; domains: true } >; export const buildCompose = async (compose: ComposeNested, logPath: string) => { - const writeStream = createWriteStream(logPath, { flags: "a" }); - const { sourceType, appName, mounts, composeType, domains } = compose; - try { - const { COMPOSE_PATH } = paths(); - const command = createCommand(compose); - await writeDomainsToCompose(compose, domains); - createEnvFile(compose); + const writeStream = createWriteStream(logPath, { flags: "a" }); + const { sourceType, appName, mounts, composeType, domains } = compose; + try { + const { COMPOSE_PATH } = paths(); + const command = createCommand(compose); + await writeDomainsToCompose(compose, domains); + createEnvFile(compose); - if (compose.isolatedDeployment) { - await execAsync( - `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}` - ); - } + if (compose.isolatedDeployment) { + await execAsync( + `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}`, + ); + } - const logContent = ` + const logContent = ` App Name: ${appName} Build Compose 🐳 Detected: ${mounts.length} mounts 📂 Command: docker ${command} Source Type: docker ${sourceType} ✅ Compose Type: ${composeType} ✅`; - const logBox = boxen(logContent, { - padding: { - left: 1, - right: 1, - bottom: 1, - }, - width: 80, - borderStyle: "double", - }); - writeStream.write(`\n${logBox}\n`); - const projectPath = join(COMPOSE_PATH, compose.appName, "code"); + const logBox = boxen(logContent, { + padding: { + left: 1, + right: 1, + bottom: 1, + }, + width: 80, + borderStyle: "double", + }); + writeStream.write(`\n${logBox}\n`); + const projectPath = join(COMPOSE_PATH, compose.appName, "code"); - await spawnAsync( - "docker", - [...command.split(" ")], - (data) => { - if (writeStream.writable) { - writeStream.write(data.toString()); - } - }, - { - cwd: projectPath, - env: { - NODE_ENV: process.env.NODE_ENV, - PATH: process.env.PATH, - ...(composeType === "stack" && { - ...getEnviromentVariablesObject(compose.env, compose.project.env), - }), - }, - } - ); + await spawnAsync( + "docker", + [...command.split(" ")], + (data) => { + if (writeStream.writable) { + writeStream.write(data.toString()); + } + }, + { + cwd: projectPath, + env: { + NODE_ENV: process.env.NODE_ENV, + PATH: process.env.PATH, + ...(composeType === "stack" && { + ...getEnviromentVariablesObject(compose.env, compose.project.env), + }), + }, + }, + ); - if (compose.isolatedDeployment) { - await execAsync( - `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1` - ); - } + if (compose.isolatedDeployment) { + await execAsync( + `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1`, + ); + } - writeStream.write("Docker Compose Deployed: ✅"); - } catch (error) { - writeStream.write(`Error ❌ ${(error as Error).message}`); - throw error; - } finally { - writeStream.end(); - } + writeStream.write("Docker Compose Deployed: ✅"); + } catch (error) { + writeStream.write(`Error ❌ ${(error as Error).message}`); + throw error; + } finally { + writeStream.end(); + } }; export const getBuildComposeCommand = async ( - compose: ComposeNested, - logPath: string + compose: ComposeNested, + logPath: string, ) => { - const { COMPOSE_PATH } = paths(true); - const { sourceType, appName, mounts, composeType, domains, composePath } = - compose; - const command = createCommand(compose); - const envCommand = getCreateEnvFileCommand(compose); - const projectPath = join(COMPOSE_PATH, compose.appName, "code"); - const exportEnvCommand = getExportEnvCommand(compose); + const { COMPOSE_PATH } = paths(true); + const { sourceType, appName, mounts, composeType, domains, composePath } = + compose; + const command = createCommand(compose); + const envCommand = getCreateEnvFileCommand(compose); + const projectPath = join(COMPOSE_PATH, compose.appName, "code"); + const exportEnvCommand = getExportEnvCommand(compose); - const newCompose = await writeDomainsToComposeRemote( - compose, - domains, - logPath - ); - const logContent = ` + const newCompose = await writeDomainsToComposeRemote( + compose, + domains, + logPath, + ); + const logContent = ` App Name: ${appName} Build Compose 🐳 Detected: ${mounts.length} mounts 📂 @@ -119,17 +119,17 @@ Command: docker ${command} Source Type: docker ${sourceType} ✅ Compose Type: ${composeType} ✅`; - const logBox = boxen(logContent, { - padding: { - left: 1, - right: 1, - bottom: 1, - }, - width: 80, - borderStyle: "double", - }); + const logBox = boxen(logContent, { + padding: { + left: 1, + right: 1, + bottom: 1, + }, + width: 80, + borderStyle: "double", + }); - const bashCommand = ` + const bashCommand = ` set -e { echo "${logBox}" >> "${logPath}" @@ -152,106 +152,106 @@ Compose Type: ${composeType} ✅`; } `; - return await execAsyncRemote(compose.serverId, bashCommand); + return await execAsyncRemote(compose.serverId, bashCommand); }; const sanitizeCommand = (command: string) => { - const sanitizedCommand = command.trim(); + const sanitizedCommand = command.trim(); - const parts = sanitizedCommand.split(/\s+/); + const parts = sanitizedCommand.split(/\s+/); - const restCommand = parts.map((arg) => arg.replace(/^"(.*)"$/, "$1")); + const restCommand = parts.map((arg) => arg.replace(/^"(.*)"$/, "$1")); - return restCommand.join(" "); + return restCommand.join(" "); }; export const createCommand = (compose: ComposeNested) => { - const { composeType, appName, sourceType } = compose; - if (compose.command) { - return `${sanitizeCommand(compose.command)}`; - } + const { composeType, appName, sourceType } = compose; + if (compose.command) { + return `${sanitizeCommand(compose.command)}`; + } - const path = - sourceType === "raw" ? "docker-compose.yml" : compose.composePath; - let command = ""; + const path = + sourceType === "raw" ? "docker-compose.yml" : compose.composePath; + let command = ""; - if (composeType === "docker-compose") { - command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`; - } else if (composeType === "stack") { - command = `stack deploy -c ${path} ${appName} --prune`; - } + if (composeType === "docker-compose") { + command = `compose -p ${appName} -f ${path} up -d --build --remove-orphans`; + } else if (composeType === "stack") { + command = `stack deploy -c ${path} ${appName} --prune`; + } - return command; + return command; }; const createEnvFile = (compose: ComposeNested) => { - const { COMPOSE_PATH } = paths(); - const { env, composePath, appName } = compose; - const composeFilePath = - join(COMPOSE_PATH, appName, "code", composePath) || - join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); + const { COMPOSE_PATH } = paths(); + const { env, composePath, appName } = compose; + const composeFilePath = + join(COMPOSE_PATH, appName, "code", composePath) || + join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); - const envFilePath = join(dirname(composeFilePath), ".env"); - let envContent = env || ""; - if (!envContent.includes("DOCKER_CONFIG")) { - envContent += "\nDOCKER_CONFIG=/root/.docker/config.json"; - } + const envFilePath = join(dirname(composeFilePath), ".env"); + let envContent = env || ""; + if (!envContent.includes("DOCKER_CONFIG")) { + envContent += "\nDOCKER_CONFIG=/root/.docker/config.json"; + } - if (compose.randomize) { - envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; - } + if (compose.randomize) { + envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; + } - const envFileContent = prepareEnvironmentVariables( - envContent, - compose.project.env - ).join("\n"); + const envFileContent = prepareEnvironmentVariables( + envContent, + compose.project.env, + ).join("\n"); - if (!existsSync(dirname(envFilePath))) { - mkdirSync(dirname(envFilePath), { recursive: true }); - } - writeFileSync(envFilePath, envFileContent); + if (!existsSync(dirname(envFilePath))) { + mkdirSync(dirname(envFilePath), { recursive: true }); + } + writeFileSync(envFilePath, envFileContent); }; export const getCreateEnvFileCommand = (compose: ComposeNested) => { - const { COMPOSE_PATH } = paths(true); - const { env, composePath, appName } = compose; - const composeFilePath = - join(COMPOSE_PATH, appName, "code", composePath) || - join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); + const { COMPOSE_PATH } = paths(true); + const { env, composePath, appName } = compose; + const composeFilePath = + join(COMPOSE_PATH, appName, "code", composePath) || + join(COMPOSE_PATH, appName, "code", "docker-compose.yml"); - const envFilePath = join(dirname(composeFilePath), ".env"); + const envFilePath = join(dirname(composeFilePath), ".env"); - let envContent = env || ""; - if (!envContent.includes("DOCKER_CONFIG")) { - envContent += "\nDOCKER_CONFIG=/root/.docker/config.json"; - } + let envContent = env || ""; + if (!envContent.includes("DOCKER_CONFIG")) { + envContent += "\nDOCKER_CONFIG=/root/.docker/config.json"; + } - if (compose.randomize) { - envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; - } + if (compose.randomize) { + envContent += `\nCOMPOSE_PREFIX=${compose.suffix}`; + } - const envFileContent = prepareEnvironmentVariables( - envContent, - compose.project.env - ).join("\n"); + const envFileContent = prepareEnvironmentVariables( + envContent, + compose.project.env, + ).join("\n"); - const encodedContent = encodeBase64(envFileContent); - return ` + const encodedContent = encodeBase64(envFileContent); + return ` touch ${envFilePath}; echo "${encodedContent}" | base64 -d > "${envFilePath}"; `; }; const getExportEnvCommand = (compose: ComposeNested) => { - if (compose.composeType !== "stack") return ""; + if (compose.composeType !== "stack") return ""; - const envVars = getEnviromentVariablesObject( - compose.env, - compose.project.env - ); - const exports = Object.entries(envVars) - .map(([key, value]) => `export ${key}=${JSON.stringify(value)}`) - .join("\n"); + const envVars = getEnviromentVariablesObject( + compose.env, + compose.project.env, + ); + const exports = Object.entries(envVars) + .map(([key, value]) => `export ${key}=${JSON.stringify(value)}`) + .join("\n"); - return exports ? `\n# Export environment variables\n${exports}\n` : ""; + return exports ? `\n# Export environment variables\n${exports}\n` : ""; }; diff --git a/packages/server/src/utils/docker/collision.ts b/packages/server/src/utils/docker/collision.ts index e0fa725a..d3f131c6 100644 --- a/packages/server/src/utils/docker/collision.ts +++ b/packages/server/src/utils/docker/collision.ts @@ -6,41 +6,41 @@ import { addSuffixToAllVolumes } from "./compose/volume"; import type { ComposeSpecification } from "./types"; export const addAppNameToPreventCollision = ( - composeData: ComposeSpecification, - appName: string + composeData: ComposeSpecification, + appName: string, ): ComposeSpecification => { - let updatedComposeData = { ...composeData }; + let updatedComposeData = { ...composeData }; - updatedComposeData = addAppNameToAllServiceNames(updatedComposeData, appName); - updatedComposeData = addSuffixToAllVolumes(updatedComposeData, appName); - return updatedComposeData; + updatedComposeData = addAppNameToAllServiceNames(updatedComposeData, appName); + updatedComposeData = addSuffixToAllVolumes(updatedComposeData, appName); + return updatedComposeData; }; export const randomizeIsolatedDeploymentComposeFile = async ( - composeId: string, - suffix?: string + composeId: string, + suffix?: string, ) => { - const compose = await findComposeById(composeId); - const composeFile = compose.composeFile; - const composeData = load(composeFile) as ComposeSpecification; + const compose = await findComposeById(composeId); + const composeFile = compose.composeFile; + const composeData = load(composeFile) as ComposeSpecification; - const randomSuffix = suffix || compose.appName || generateRandomHash(); + const randomSuffix = suffix || compose.appName || generateRandomHash(); - const newComposeFile = addAppNameToPreventCollision( - composeData, - randomSuffix - ); + const newComposeFile = addAppNameToPreventCollision( + composeData, + randomSuffix, + ); - return dump(newComposeFile); + return dump(newComposeFile); }; export const randomizeDeployableSpecificationFile = ( - composeSpec: ComposeSpecification, - suffix?: string + composeSpec: ComposeSpecification, + suffix?: string, ) => { - if (!suffix) { - return composeSpec; - } - const newComposeFile = addAppNameToPreventCollision(composeSpec, suffix); - return newComposeFile; + if (!suffix) { + return composeSpec; + } + const newComposeFile = addAppNameToPreventCollision(composeSpec, suffix); + return newComposeFile; }; diff --git a/packages/server/src/utils/docker/domain.ts b/packages/server/src/utils/docker/domain.ts index f9eade7d..8a1b0608 100644 --- a/packages/server/src/utils/docker/domain.ts +++ b/packages/server/src/utils/docker/domain.ts @@ -7,346 +7,346 @@ import type { Domain } from "@dokploy/server/services/domain"; import { dump, load } from "js-yaml"; import { execAsyncRemote } from "../process/execAsync"; import { - cloneRawBitbucketRepository, - cloneRawBitbucketRepositoryRemote, + cloneRawBitbucketRepository, + cloneRawBitbucketRepositoryRemote, } from "../providers/bitbucket"; import { - cloneGitRawRepository, - cloneRawGitRepositoryRemote, + cloneGitRawRepository, + cloneRawGitRepositoryRemote, } from "../providers/git"; import { - cloneRawGithubRepository, - cloneRawGithubRepositoryRemote, + cloneRawGithubRepository, + cloneRawGithubRepositoryRemote, } from "../providers/github"; import { - cloneRawGitlabRepository, - cloneRawGitlabRepositoryRemote, + cloneRawGitlabRepository, + cloneRawGitlabRepositoryRemote, } from "../providers/gitlab"; import { - createComposeFileRaw, - createComposeFileRawRemote, + createComposeFileRaw, + createComposeFileRawRemote, } from "../providers/raw"; import { randomizeDeployableSpecificationFile } from "./collision"; import { randomizeSpecificationFile } from "./compose"; import type { - ComposeSpecification, - DefinitionsService, - PropertiesNetworks, + ComposeSpecification, + DefinitionsService, + PropertiesNetworks, } from "./types"; import { encodeBase64 } from "./utils"; export const cloneCompose = async (compose: Compose) => { - if (compose.sourceType === "github") { - await cloneRawGithubRepository(compose); - } else if (compose.sourceType === "gitlab") { - await cloneRawGitlabRepository(compose); - } else if (compose.sourceType === "bitbucket") { - await cloneRawBitbucketRepository(compose); - } else if (compose.sourceType === "git") { - await cloneGitRawRepository(compose); - } else if (compose.sourceType === "raw") { - await createComposeFileRaw(compose); - } + if (compose.sourceType === "github") { + await cloneRawGithubRepository(compose); + } else if (compose.sourceType === "gitlab") { + await cloneRawGitlabRepository(compose); + } else if (compose.sourceType === "bitbucket") { + await cloneRawBitbucketRepository(compose); + } else if (compose.sourceType === "git") { + await cloneGitRawRepository(compose); + } else if (compose.sourceType === "raw") { + await createComposeFileRaw(compose); + } }; export const cloneComposeRemote = async (compose: Compose) => { - if (compose.sourceType === "github") { - await cloneRawGithubRepositoryRemote(compose); - } else if (compose.sourceType === "gitlab") { - await cloneRawGitlabRepositoryRemote(compose); - } else if (compose.sourceType === "bitbucket") { - await cloneRawBitbucketRepositoryRemote(compose); - } else if (compose.sourceType === "git") { - await cloneRawGitRepositoryRemote(compose); - } else if (compose.sourceType === "raw") { - await createComposeFileRawRemote(compose); - } + if (compose.sourceType === "github") { + await cloneRawGithubRepositoryRemote(compose); + } else if (compose.sourceType === "gitlab") { + await cloneRawGitlabRepositoryRemote(compose); + } else if (compose.sourceType === "bitbucket") { + await cloneRawBitbucketRepositoryRemote(compose); + } else if (compose.sourceType === "git") { + await cloneRawGitRepositoryRemote(compose); + } else if (compose.sourceType === "raw") { + await createComposeFileRawRemote(compose); + } }; export const getComposePath = (compose: Compose) => { - const { COMPOSE_PATH } = paths(!!compose.serverId); - const { appName, sourceType, composePath } = compose; - let path = ""; + const { COMPOSE_PATH } = paths(!!compose.serverId); + const { appName, sourceType, composePath } = compose; + let path = ""; - if (sourceType === "raw") { - path = "docker-compose.yml"; - } else { - path = composePath; - } + if (sourceType === "raw") { + path = "docker-compose.yml"; + } else { + path = composePath; + } - return join(COMPOSE_PATH, appName, "code", path); + return join(COMPOSE_PATH, appName, "code", path); }; export const loadDockerCompose = async ( - compose: Compose + compose: Compose, ): Promise => { - const path = getComposePath(compose); + const path = getComposePath(compose); - if (existsSync(path)) { - const yamlStr = readFileSync(path, "utf8"); - const parsedConfig = load(yamlStr) as ComposeSpecification; - return parsedConfig; - } - return null; + if (existsSync(path)) { + const yamlStr = readFileSync(path, "utf8"); + const parsedConfig = load(yamlStr) as ComposeSpecification; + return parsedConfig; + } + return null; }; export const loadDockerComposeRemote = async ( - compose: Compose + compose: Compose, ): Promise => { - const path = getComposePath(compose); - try { - if (!compose.serverId) { - return null; - } - const { stdout, stderr } = await execAsyncRemote( - compose.serverId, - `cat ${path}` - ); + const path = getComposePath(compose); + try { + if (!compose.serverId) { + return null; + } + const { stdout, stderr } = await execAsyncRemote( + compose.serverId, + `cat ${path}`, + ); - if (stderr) { - return null; - } - if (!stdout) return null; - const parsedConfig = load(stdout) as ComposeSpecification; - return parsedConfig; - } catch (err) { - return null; - } + if (stderr) { + return null; + } + if (!stdout) return null; + const parsedConfig = load(stdout) as ComposeSpecification; + return parsedConfig; + } catch (err) { + return null; + } }; export const readComposeFile = async (compose: Compose) => { - const path = getComposePath(compose); - if (existsSync(path)) { - const yamlStr = readFileSync(path, "utf8"); - return yamlStr; - } - return null; + const path = getComposePath(compose); + if (existsSync(path)) { + const yamlStr = readFileSync(path, "utf8"); + return yamlStr; + } + return null; }; export const writeDomainsToCompose = async ( - compose: Compose, - domains: Domain[] + compose: Compose, + domains: Domain[], ) => { - if (!domains.length) { - return; - } - const composeConverted = await addDomainToCompose(compose, domains); + if (!domains.length) { + return; + } + const composeConverted = await addDomainToCompose(compose, domains); - const path = getComposePath(compose); - const composeString = dump(composeConverted, { lineWidth: 1000 }); - try { - await writeFile(path, composeString, "utf8"); - } catch (error) { - throw error; - } + const path = getComposePath(compose); + const composeString = dump(composeConverted, { lineWidth: 1000 }); + try { + await writeFile(path, composeString, "utf8"); + } catch (error) { + throw error; + } }; export const writeDomainsToComposeRemote = async ( - compose: Compose, - domains: Domain[], - logPath: string + compose: Compose, + domains: Domain[], + logPath: string, ) => { - if (!domains.length) { - return ""; - } + if (!domains.length) { + return ""; + } - try { - const composeConverted = await addDomainToCompose(compose, domains); - const path = getComposePath(compose); + try { + const composeConverted = await addDomainToCompose(compose, domains); + const path = getComposePath(compose); - if (!composeConverted) { - return ` + if (!composeConverted) { + return ` echo "❌ Error: Compose file not found" >> ${logPath}; exit 1; `; - } - if (compose.serverId) { - const composeString = dump(composeConverted, { lineWidth: 1000 }); - const encodedContent = encodeBase64(composeString); - return `echo "${encodedContent}" | base64 -d > "${path}";`; - } - } catch (error) { - // @ts-ignore - return `echo "❌ Has occured an error: ${error?.message || error}" >> ${logPath}; + } + if (compose.serverId) { + const composeString = dump(composeConverted, { lineWidth: 1000 }); + const encodedContent = encodeBase64(composeString); + return `echo "${encodedContent}" | base64 -d > "${path}";`; + } + } catch (error) { + // @ts-ignore + return `echo "❌ Has occured an error: ${error?.message || error}" >> ${logPath}; exit 1; `; - } + } }; // (node:59875) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGTERM listeners added to [process]. Use emitter.setMaxListeners() to increase limit export const addDomainToCompose = async ( - compose: Compose, - domains: Domain[] + compose: Compose, + domains: Domain[], ) => { - const { appName } = compose; + const { appName } = compose; - let result: ComposeSpecification | null; + let result: ComposeSpecification | null; - if (compose.serverId) { - result = await loadDockerComposeRemote(compose); // aca hay que ir al servidor e ir a traer el compose file al servidor - } else { - result = await loadDockerCompose(compose); - } + if (compose.serverId) { + result = await loadDockerComposeRemote(compose); // aca hay que ir al servidor e ir a traer el compose file al servidor + } else { + result = await loadDockerCompose(compose); + } - if (!result || domains.length === 0) { - return null; - } + if (!result || domains.length === 0) { + return null; + } - if (compose.isolatedDeployment) { - const randomized = randomizeDeployableSpecificationFile( - result, - compose.suffix || compose.appName - ); - result = randomized; - } else if (compose.randomize) { - const randomized = randomizeSpecificationFile(result, compose.suffix); - result = randomized; - } + if (compose.isolatedDeployment) { + const randomized = randomizeDeployableSpecificationFile( + result, + compose.suffix || compose.appName, + ); + result = randomized; + } else if (compose.randomize) { + const randomized = randomizeSpecificationFile(result, compose.suffix); + result = randomized; + } - for (const domain of domains) { - const { serviceName, https } = domain; - if (!serviceName) { - throw new Error("Service name not found"); - } - if (!result?.services?.[serviceName]) { - throw new Error(`The service ${serviceName} not found in the compose`); - } + for (const domain of domains) { + const { serviceName, https } = domain; + if (!serviceName) { + throw new Error("Service name not found"); + } + if (!result?.services?.[serviceName]) { + throw new Error(`The service ${serviceName} not found in the compose`); + } - const httpLabels = await createDomainLabels(appName, domain, "web"); - if (https) { - const httpsLabels = await createDomainLabels( - appName, - domain, - "websecure" - ); - httpLabels.push(...httpsLabels); - } + const httpLabels = await createDomainLabels(appName, domain, "web"); + if (https) { + const httpsLabels = await createDomainLabels( + appName, + domain, + "websecure", + ); + httpLabels.push(...httpsLabels); + } - let labels: DefinitionsService["labels"] = []; - if (compose.composeType === "docker-compose") { - if (!result.services[serviceName].labels) { - result.services[serviceName].labels = []; - } + let labels: DefinitionsService["labels"] = []; + if (compose.composeType === "docker-compose") { + if (!result.services[serviceName].labels) { + result.services[serviceName].labels = []; + } - labels = result.services[serviceName].labels; - } else { - // Stack Case - if (!result.services[serviceName].deploy) { - result.services[serviceName].deploy = {}; - } - if (!result.services[serviceName].deploy.labels) { - result.services[serviceName].deploy.labels = []; - } + labels = result.services[serviceName].labels; + } else { + // Stack Case + if (!result.services[serviceName].deploy) { + result.services[serviceName].deploy = {}; + } + if (!result.services[serviceName].deploy.labels) { + result.services[serviceName].deploy.labels = []; + } - labels = result.services[serviceName].deploy.labels; - } + labels = result.services[serviceName].deploy.labels; + } - if (Array.isArray(labels)) { - if (!labels.includes("traefik.enable=true")) { - labels.push("traefik.enable=true"); - } - labels.push(...httpLabels); - } + if (Array.isArray(labels)) { + if (!labels.includes("traefik.enable=true")) { + labels.push("traefik.enable=true"); + } + labels.push(...httpLabels); + } - if (!compose.isolatedDeployment) { - // Add the dokploy-network to the service - result.services[serviceName].networks = addDokployNetworkToService( - result.services[serviceName].networks - ); - } - } + if (!compose.isolatedDeployment) { + // Add the dokploy-network to the service + result.services[serviceName].networks = addDokployNetworkToService( + result.services[serviceName].networks, + ); + } + } - // Add dokploy-network to the root of the compose file - if (!compose.isolatedDeployment) { - result.networks = addDokployNetworkToRoot(result.networks); - } + // Add dokploy-network to the root of the compose file + if (!compose.isolatedDeployment) { + result.networks = addDokployNetworkToRoot(result.networks); + } - return result; + return result; }; export const writeComposeFile = async ( - compose: Compose, - composeSpec: ComposeSpecification + compose: Compose, + composeSpec: ComposeSpecification, ) => { - const path = getComposePath(compose); + const path = getComposePath(compose); - try { - const composeFile = dump(composeSpec, { - lineWidth: 1000, - }); - fs.writeFileSync(path, composeFile, "utf8"); - } catch (e) { - console.error("Error saving the YAML config file:", e); - } + try { + const composeFile = dump(composeSpec, { + lineWidth: 1000, + }); + fs.writeFileSync(path, composeFile, "utf8"); + } catch (e) { + console.error("Error saving the YAML config file:", e); + } }; export const createDomainLabels = async ( - appName: string, - domain: Domain, - entrypoint: "web" | "websecure" + appName: string, + domain: Domain, + entrypoint: "web" | "websecure", ) => { - const { host, port, https, uniqueConfigKey, certificateType, path } = domain; - const routerName = `${appName}-${uniqueConfigKey}-${entrypoint}`; - const labels = [ - `traefik.http.routers.${routerName}.rule=Host(\`${host}\`)${path && path !== "/" ? ` && PathPrefix(\`${path}\`)` : ""}`, - `traefik.http.routers.${routerName}.entrypoints=${entrypoint}`, - `traefik.http.services.${routerName}.loadbalancer.server.port=${port}`, - `traefik.http.routers.${routerName}.service=${routerName}`, - ]; + const { host, port, https, uniqueConfigKey, certificateType, path } = domain; + const routerName = `${appName}-${uniqueConfigKey}-${entrypoint}`; + const labels = [ + `traefik.http.routers.${routerName}.rule=Host(\`${host}\`)${path && path !== "/" ? ` && PathPrefix(\`${path}\`)` : ""}`, + `traefik.http.routers.${routerName}.entrypoints=${entrypoint}`, + `traefik.http.services.${routerName}.loadbalancer.server.port=${port}`, + `traefik.http.routers.${routerName}.service=${routerName}`, + ]; - if (entrypoint === "web" && https) { - labels.push( - `traefik.http.routers.${routerName}.middlewares=redirect-to-https@file` - ); - } + if (entrypoint === "web" && https) { + labels.push( + `traefik.http.routers.${routerName}.middlewares=redirect-to-https@file`, + ); + } - if (entrypoint === "websecure") { - if (certificateType === "letsencrypt") { - labels.push( - `traefik.http.routers.${routerName}.tls.certresolver=letsencrypt` - ); - } - } + if (entrypoint === "websecure") { + if (certificateType === "letsencrypt") { + labels.push( + `traefik.http.routers.${routerName}.tls.certresolver=letsencrypt`, + ); + } + } - return labels; + return labels; }; export const addDokployNetworkToService = ( - networkService: DefinitionsService["networks"] + networkService: DefinitionsService["networks"], ) => { - let networks = networkService; - const network = "dokploy-network"; - if (!networks) { - networks = []; - } + let networks = networkService; + const network = "dokploy-network"; + if (!networks) { + networks = []; + } - if (Array.isArray(networks)) { - if (!networks.includes(network)) { - networks.push(network); - } - } else if (networks && typeof networks === "object") { - if (!(network in networks)) { - networks[network] = {}; - } - } + if (Array.isArray(networks)) { + if (!networks.includes(network)) { + networks.push(network); + } + } else if (networks && typeof networks === "object") { + if (!(network in networks)) { + networks[network] = {}; + } + } - return networks; + return networks; }; export const addDokployNetworkToRoot = ( - networkRoot: PropertiesNetworks | undefined + networkRoot: PropertiesNetworks | undefined, ) => { - let networks = networkRoot; - const network = "dokploy-network"; + let networks = networkRoot; + const network = "dokploy-network"; - if (!networks) { - networks = {}; - } + if (!networks) { + networks = {}; + } - if (networks[network] || !networks[network]) { - networks[network] = { - external: true, - }; - } + if (networks[network] || !networks[network]) { + networks[network] = { + external: true, + }; + } - return networks; + return networks; }; From c0a00f4957aa4f15a8e536a95a328f9e1a23bac3 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 9 Feb 2025 02:31:01 -0600 Subject: [PATCH 10/11] refactor: remove dokploy-network --- apps/dokploy/server/api/routers/compose.ts | 1 + .../templates/activepieces/docker-compose.yml | 9 ++--- .../templates/answer/docker-compose.yml | 3 +- .../templates/aptabase/docker-compose.yml | 6 ++-- .../templates/budibase/docker-compose.yml | 21 ++++------- .../templates/calcom/docker-compose.yml | 3 +- .../templates/chatwoot/docker-compose.yml | 6 ++-- .../templates/checkmate/docker-compose.yml | 11 ++---- .../templates/coder/docker-compose.yml | 6 ++-- .../templates/directus/docker-compose.yml | 6 ++-- .../discord-tickets/docker-compose.yml | 6 ++-- .../templates/discourse/docker-compose.yml | 12 +++---- .../templates/docmost/docker-compose.yml | 9 ++--- .../templates/documenso/docker-compose.yml | 3 +- .../templates/drawio/docker-compose.yml | 9 ++--- .../templates/evolutionapi/docker-compose.yml | 9 ++--- .../templates/excalidraw/docker-compose.yml | 3 +- .../templates/formbricks/docker-compose.yml | 3 +- .../templates/ghost/docker-compose.yml | 3 +- .../templates/gitea/docker-compose.yml | 6 ++-- .../templates/glitchtip/docker-compose.yml | 12 +++---- .../dokploy/templates/glpi/docker-compose.yml | 6 ++-- .../templates/hi-events/docker-compose.yml | 3 +- .../dokploy/templates/huly/docker-compose.yml | 36 +++++++------------ .../templates/immich/docker-compose.yml | 12 +++---- .../templates/infisical/docker-compose.yml | 12 +++---- .../templates/invoiceshelf/docker-compose.yml | 6 ++-- .../templates/kimai/docker-compose.yml | 6 ++-- .../templates/langflow/docker-compose.yml | 6 ++-- .../templates/listmonk/docker-compose.yml | 6 ++-- .../templates/logto/docker-compose.yml | 6 ++-- .../templates/maybe/docker-compose.yml | 3 +- .../templates/metabase/docker-compose.yml | 3 +- .../nextcloud-aio/docker-compose.yml | 6 ++-- .../templates/nocodb/docker-compose.yml | 3 +- .../dokploy/templates/odoo/docker-compose.yml | 3 +- .../templates/open-webui/docker-compose.yml | 3 +- .../templates/penpot/docker-compose.yml | 18 ++++------ .../templates/peppermint/docker-compose.yml | 6 ++-- .../templates/photoprism/docker-compose.yml | 6 ++-- .../templates/phpmyadmin/docker-compose.yml | 3 +- .../templates/plausible/docker-compose.yml | 6 ++-- .../templates/portainer/docker-compose.yml | 3 +- .../templates/postiz/docker-compose.yml | 9 ++--- .../templates/rocketchat/docker-compose.yml | 3 +- .../templates/roundcube/docker-compose.yml | 3 +- .../dokploy/templates/ryot/docker-compose.yml | 6 ++-- .../templates/slash/docker-compose.yml | 6 ++-- .../templates/supabase/docker-compose.yml | 36 +++++++------------ .../templates/superset/docker-compose.yml | 6 ++-- .../templates/teable/docker-compose.yml | 6 ++-- .../templates/twenty/docker-compose.yml | 15 +++----- .../templates/typebot/docker-compose.yml | 3 +- .../templates/umami/docker-compose.yml | 3 +- .../templates/unifi/docker-compose.yml | 6 ++-- .../templates/unsend/docker-compose.yml | 12 +++---- .../templates/windmill/docker-compose.yml | 18 ++++------ .../templates/wordpress/docker-compose.yml | 2 -- .../templates/yourls/docker-compose.yml | 6 ++-- .../templates/zipline/docker-compose.yml | 3 +- 60 files changed, 150 insertions(+), 302 deletions(-) diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index f28f33a1..463d0398 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -415,6 +415,7 @@ export const composeRouter = createTRPCRouter({ name: input.id, sourceType: "raw", appName: `${projectName}-${generatePassword(6)}`, + isolatedDeployment: true, }); if (ctx.user.rol === "user") { diff --git a/apps/dokploy/templates/activepieces/docker-compose.yml b/apps/dokploy/templates/activepieces/docker-compose.yml index e990379b..a5511e7f 100644 --- a/apps/dokploy/templates/activepieces/docker-compose.yml +++ b/apps/dokploy/templates/activepieces/docker-compose.yml @@ -4,8 +4,7 @@ services: activepieces: image: activepieces/activepieces:0.35.0 restart: unless-stopped - networks: - - dokploy-network + depends_on: postgres: condition: service_healthy @@ -35,8 +34,7 @@ services: postgres: image: postgres:14 restart: unless-stopped - networks: - - dokploy-network + environment: POSTGRES_DB: activepieces POSTGRES_PASSWORD: ${AP_POSTGRES_PASSWORD} @@ -52,8 +50,7 @@ services: redis: image: redis:7 restart: unless-stopped - networks: - - dokploy-network + volumes: - redis_data:/data healthcheck: diff --git a/apps/dokploy/templates/answer/docker-compose.yml b/apps/dokploy/templates/answer/docker-compose.yml index e17a6d1e..2b9fc344 100644 --- a/apps/dokploy/templates/answer/docker-compose.yml +++ b/apps/dokploy/templates/answer/docker-compose.yml @@ -17,8 +17,7 @@ services: interval: 5s timeout: 5s retries: 5 - networks: - - dokploy-network + volumes: - db-data:/var/lib/postgresql/data environment: diff --git a/apps/dokploy/templates/aptabase/docker-compose.yml b/apps/dokploy/templates/aptabase/docker-compose.yml index 934fd1ee..dfde1cae 100644 --- a/apps/dokploy/templates/aptabase/docker-compose.yml +++ b/apps/dokploy/templates/aptabase/docker-compose.yml @@ -7,8 +7,7 @@ services: environment: POSTGRES_USER: aptabase POSTGRES_PASSWORD: sTr0NGp4ssw0rd - networks: - - dokploy-network + healthcheck: test: ["CMD-SHELL", "pg_isready -U aptabase"] interval: 10s @@ -27,8 +26,7 @@ services: nofile: soft: 262144 hard: 262144 - networks: - - dokploy-network + healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8123 || exit 1"] interval: 10s diff --git a/apps/dokploy/templates/budibase/docker-compose.yml b/apps/dokploy/templates/budibase/docker-compose.yml index 3f82de3e..d1d6744a 100644 --- a/apps/dokploy/templates/budibase/docker-compose.yml +++ b/apps/dokploy/templates/budibase/docker-compose.yml @@ -2,8 +2,7 @@ services: apps: image: budibase.docker.scarf.sh/budibase/apps:3.2.25 restart: unless-stopped - networks: - - dokploy-network + environment: SELF_HOSTED: 1 LOG_LEVEL: info @@ -43,8 +42,7 @@ services: worker: image: budibase.docker.scarf.sh/budibase/worker:3.2.25 restart: unless-stopped - networks: - - dokploy-network + environment: SELF_HOSTED: 1 LOG_LEVEL: info @@ -83,8 +81,7 @@ services: minio: image: minio/minio:RELEASE.2024-11-07T00-52-20Z restart: unless-stopped - networks: - - dokploy-network + volumes: - 'minio_data:/data' environment: @@ -104,8 +101,7 @@ services: proxy: image: budibase/proxy:3.2.25 restart: unless-stopped - networks: - - dokploy-network + environment: PROXY_RATE_LIMIT_WEBHOOKS_PER_SECOND: 10 PROXY_RATE_LIMIT_API_PER_SECOND: 20 @@ -137,8 +133,7 @@ services: couchdb: image: budibase/couchdb:v3.3.3 restart: unless-stopped - networks: - - dokploy-network + environment: COUCHDB_USER: budibase COUCHDB_PASSWORD: ${BB_COUCHDB_PASSWORD} @@ -157,8 +152,7 @@ services: - 'couchdb3_data:/opt/couchdb/data' redis: image: redis:7.2-alpine - networks: - - dokploy-network + restart: unless-stopped command: 'redis-server --requirepass "${BB_REDIS_PASSWORD}"' volumes: @@ -176,8 +170,7 @@ services: start_period: 10s watchtower: restart: unless-stopped - networks: - - dokploy-network + image: containrrr/watchtower:1.7.1 volumes: - '/var/run/docker.sock:/var/run/docker.sock' diff --git a/apps/dokploy/templates/calcom/docker-compose.yml b/apps/dokploy/templates/calcom/docker-compose.yml index 7a1d8c92..a309a1da 100644 --- a/apps/dokploy/templates/calcom/docker-compose.yml +++ b/apps/dokploy/templates/calcom/docker-compose.yml @@ -1,8 +1,7 @@ services: postgres: image: postgres:16-alpine - networks: - - dokploy-network + volumes: - calcom-data:/var/lib/postgresql/data environment: diff --git a/apps/dokploy/templates/chatwoot/docker-compose.yml b/apps/dokploy/templates/chatwoot/docker-compose.yml index 8b762e36..b24ca0b5 100644 --- a/apps/dokploy/templates/chatwoot/docker-compose.yml +++ b/apps/dokploy/templates/chatwoot/docker-compose.yml @@ -51,8 +51,7 @@ services: restart: always volumes: - chatwoot-postgres-data:/var/lib/postgresql/data - networks: - - dokploy-network + environment: - POSTGRES_DB=${POSTGRES_DATABASE} - POSTGRES_USER=${POSTGRES_USERNAME} @@ -63,8 +62,7 @@ services: restart: always volumes: - chatwoot-redis-data:/data - networks: - - dokploy-network + networks: dokploy-network: diff --git a/apps/dokploy/templates/checkmate/docker-compose.yml b/apps/dokploy/templates/checkmate/docker-compose.yml index dc83a28f..7a5fc898 100644 --- a/apps/dokploy/templates/checkmate/docker-compose.yml +++ b/apps/dokploy/templates/checkmate/docker-compose.yml @@ -9,8 +9,7 @@ services: - 443 depends_on: - server - networks: - - dokploy-network + server: image: bluewaveuptime/uptime_server:latest restart: always @@ -22,8 +21,7 @@ services: environment: - DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db - REDIS_HOST=redis - networks: - - dokploy-network + # volumes: # - /var/run/docker.sock:/var/run/docker.sock:ro redis: @@ -33,8 +31,7 @@ services: - 6379 volumes: - ../files/redis/data:/data - networks: - - dokploy-network + mongodb: image: bluewaveuptime/uptime_database_mongo:latest restart: always @@ -43,5 +40,3 @@ services: command: ["mongod", "--quiet"] ports: - 27017 - networks: - - dokploy-network \ No newline at end of file diff --git a/apps/dokploy/templates/coder/docker-compose.yml b/apps/dokploy/templates/coder/docker-compose.yml index 27bb14bd..875c7ae8 100644 --- a/apps/dokploy/templates/coder/docker-compose.yml +++ b/apps/dokploy/templates/coder/docker-compose.yml @@ -1,8 +1,7 @@ services: coder: image: ghcr.io/coder/coder:v2.15.3 - networks: - - dokploy-network + volumes: - /var/run/docker.sock:/var/run/docker.sock group_add: @@ -17,8 +16,7 @@ services: db: image: postgres:17 - networks: - - dokploy-network + environment: - POSTGRES_PASSWORD - POSTGRES_USER diff --git a/apps/dokploy/templates/directus/docker-compose.yml b/apps/dokploy/templates/directus/docker-compose.yml index 20f1b45d..52e64baf 100644 --- a/apps/dokploy/templates/directus/docker-compose.yml +++ b/apps/dokploy/templates/directus/docker-compose.yml @@ -3,8 +3,7 @@ services: image: postgis/postgis:13-master volumes: - directus_database:/var/lib/postgresql/data - networks: - - dokploy-network + environment: POSTGRES_USER: "directus" POSTGRES_PASSWORD: ${DATABASE_PASSWORD} @@ -26,8 +25,7 @@ services: retries: 5 start_interval: 5s start_period: 30s - networks: - - dokploy-network + directus: image: directus/directus:11.0.2 diff --git a/apps/dokploy/templates/discord-tickets/docker-compose.yml b/apps/dokploy/templates/discord-tickets/docker-compose.yml index e6e41288..f797a77b 100644 --- a/apps/dokploy/templates/discord-tickets/docker-compose.yml +++ b/apps/dokploy/templates/discord-tickets/docker-compose.yml @@ -4,8 +4,7 @@ services: tickets-postgres: image: mysql:8 restart: unless-stopped - networks: - - dokploy-network + volumes: - tickets-mysql-data:/var/lib/mysql environment: @@ -25,8 +24,7 @@ services: tickets-postgres: condition: service_healthy restart: unless-stopped - networks: - - dokploy-network + volumes: - tickets-app-data:/home/container/user - /etc/timezone:/etc/timezone:ro diff --git a/apps/dokploy/templates/discourse/docker-compose.yml b/apps/dokploy/templates/discourse/docker-compose.yml index ce6106be..2b938b85 100644 --- a/apps/dokploy/templates/discourse/docker-compose.yml +++ b/apps/dokploy/templates/discourse/docker-compose.yml @@ -3,8 +3,7 @@ version: '3.7' services: discourse-db: image: docker.io/bitnami/postgresql:17 - networks: - - dokploy-network + volumes: - discourse-postgresql-data:/bitnami/postgresql environment: @@ -20,8 +19,7 @@ services: discourse-redis: image: docker.io/bitnami/redis:7.4 - networks: - - dokploy-network + volumes: - discourse-redis-data:/bitnami/redis environment: @@ -35,8 +33,7 @@ services: discourse-app: image: docker.io/bitnami/discourse:3.3.2 - networks: - - dokploy-network + volumes: - discourse-data:/bitnami/discourse depends_on: @@ -63,8 +60,7 @@ services: discourse-sidekiq: image: docker.io/bitnami/discourse:3.3.2 - networks: - - dokploy-network + volumes: - discourse-sidekiq-data:/bitnami/discourse depends_on: diff --git a/apps/dokploy/templates/docmost/docker-compose.yml b/apps/dokploy/templates/docmost/docker-compose.yml index a6ebbd4f..b5995594 100644 --- a/apps/dokploy/templates/docmost/docker-compose.yml +++ b/apps/dokploy/templates/docmost/docker-compose.yml @@ -12,8 +12,7 @@ services: - DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public - REDIS_URL=redis://redis:6379 restart: unless-stopped - networks: - - dokploy-network + volumes: - docmost:/app/data/storage @@ -24,16 +23,14 @@ services: - POSTGRES_USER - POSTGRES_PASSWORD restart: unless-stopped - networks: - - dokploy-network + volumes: - db_docmost_data:/var/lib/postgresql/data redis: image: redis:7.2-alpine restart: unless-stopped - networks: - - dokploy-network + volumes: - redis_docmost_data:/data diff --git a/apps/dokploy/templates/documenso/docker-compose.yml b/apps/dokploy/templates/documenso/docker-compose.yml index 562fe498..9b8e8ed8 100644 --- a/apps/dokploy/templates/documenso/docker-compose.yml +++ b/apps/dokploy/templates/documenso/docker-compose.yml @@ -2,8 +2,7 @@ version: "3.8" services: postgres: image: postgres:16 - networks: - - dokploy-network + volumes: - documenso-data:/var/lib/postgresql/data environment: diff --git a/apps/dokploy/templates/drawio/docker-compose.yml b/apps/dokploy/templates/drawio/docker-compose.yml index 1712363f..a7d7b578 100644 --- a/apps/dokploy/templates/drawio/docker-compose.yml +++ b/apps/dokploy/templates/drawio/docker-compose.yml @@ -4,16 +4,14 @@ services: image: plantuml/plantuml-server ports: - "8080" - networks: - - dokploy-network + volumes: - fonts_volume:/usr/share/fonts/drawio image-export: image: jgraph/export-server ports: - "8000" - networks: - - dokploy-network + volumes: - fonts_volume:/usr/share/fonts/drawio environment: @@ -28,8 +26,7 @@ services: depends_on: - plantuml-server - image-export - networks: - - dokploy-network + environment: RAWIO_SELF_CONTAINED: 1 DRAWIO_USE_HTTP: 1 diff --git a/apps/dokploy/templates/evolutionapi/docker-compose.yml b/apps/dokploy/templates/evolutionapi/docker-compose.yml index 54657e87..d4803de1 100644 --- a/apps/dokploy/templates/evolutionapi/docker-compose.yml +++ b/apps/dokploy/templates/evolutionapi/docker-compose.yml @@ -4,8 +4,7 @@ services: restart: always volumes: - evolution-instances:/evolution/instances - networks: - - dokploy-network + environment: - SERVER_URL=${SERVER_URL} - AUTHENTICATION_TYPE=${AUTHENTICATION_TYPE} @@ -36,8 +35,7 @@ services: restart: always volumes: - evolution-postgres-data:/var/lib/postgresql/data - networks: - - dokploy-network + environment: - POSTGRES_DB=${POSTGRES_DATABASE} - POSTGRES_USER=${POSTGRES_USERNAME} @@ -48,8 +46,7 @@ services: restart: always volumes: - evolution-redis-data:/data - networks: - - dokploy-network + networks: dokploy-network: diff --git a/apps/dokploy/templates/excalidraw/docker-compose.yml b/apps/dokploy/templates/excalidraw/docker-compose.yml index 8743434b..3cf2fb1d 100644 --- a/apps/dokploy/templates/excalidraw/docker-compose.yml +++ b/apps/dokploy/templates/excalidraw/docker-compose.yml @@ -2,6 +2,5 @@ version: "3.8" services: excalidraw: - networks: - - dokploy-network + image: excalidraw/excalidraw:latest diff --git a/apps/dokploy/templates/formbricks/docker-compose.yml b/apps/dokploy/templates/formbricks/docker-compose.yml index 558f8b4d..ad1dcbcf 100644 --- a/apps/dokploy/templates/formbricks/docker-compose.yml +++ b/apps/dokploy/templates/formbricks/docker-compose.yml @@ -18,8 +18,7 @@ services: - postgres:/var/lib/postgresql/data environment: - POSTGRES_PASSWORD=postgres - networks: - - dokploy-network + formbricks: restart: always diff --git a/apps/dokploy/templates/ghost/docker-compose.yml b/apps/dokploy/templates/ghost/docker-compose.yml index 288c59e5..33c47f7f 100644 --- a/apps/dokploy/templates/ghost/docker-compose.yml +++ b/apps/dokploy/templates/ghost/docker-compose.yml @@ -17,8 +17,7 @@ services: db: image: mysql:8.0 restart: always - networks: - - dokploy-network + environment: MYSQL_ROOT_PASSWORD: example volumes: diff --git a/apps/dokploy/templates/gitea/docker-compose.yml b/apps/dokploy/templates/gitea/docker-compose.yml index 72e0754e..5127224c 100644 --- a/apps/dokploy/templates/gitea/docker-compose.yml +++ b/apps/dokploy/templates/gitea/docker-compose.yml @@ -11,8 +11,7 @@ services: - GITEA__database__USER=gitea - GITEA__database__PASSWD=gitea restart: always - networks: - - dokploy-network + volumes: - gitea_server:/data - /etc/timezone:/etc/timezone:ro @@ -27,8 +26,7 @@ services: - POSTGRES_USER=gitea - POSTGRES_PASSWORD=gitea - POSTGRES_DB=gitea - networks: - - dokploy-network + volumes: - gitea_db:/var/lib/postgresql/data diff --git a/apps/dokploy/templates/glitchtip/docker-compose.yml b/apps/dokploy/templates/glitchtip/docker-compose.yml index e45c7662..f47742f0 100644 --- a/apps/dokploy/templates/glitchtip/docker-compose.yml +++ b/apps/dokploy/templates/glitchtip/docker-compose.yml @@ -20,13 +20,11 @@ services: restart: unless-stopped volumes: - pg-data:/var/lib/postgresql/data - networks: - - dokploy-network + redis: image: redis restart: unless-stopped - networks: - - dokploy-network + web: image: glitchtip/glitchtip:v4.0 depends_on: *default-depends_on @@ -44,15 +42,13 @@ services: restart: unless-stopped volumes: - uploads:/code/uploads - networks: - - dokploy-network + migrate: image: glitchtip/glitchtip:v4.0 depends_on: *default-depends_on command: "./manage.py migrate" environment: *default-environment - networks: - - dokploy-network + volumes: pg-data: diff --git a/apps/dokploy/templates/glpi/docker-compose.yml b/apps/dokploy/templates/glpi/docker-compose.yml index f15cdafe..fa732fa3 100644 --- a/apps/dokploy/templates/glpi/docker-compose.yml +++ b/apps/dokploy/templates/glpi/docker-compose.yml @@ -4,8 +4,7 @@ services: restart: always volumes: - glpi-mysql-data:/var/lib/mysql - networks: - - dokploy-network + glpi-web: image: elestio/glpi:10.0.16 @@ -16,8 +15,7 @@ services: - glpi-www-data:/var/www/html/glpi environment: - TIMEZONE=Europe/Brussels - networks: - - dokploy-network + volumes: glpi-mysql-data: diff --git a/apps/dokploy/templates/hi-events/docker-compose.yml b/apps/dokploy/templates/hi-events/docker-compose.yml index 0ce5b7e7..cce45fec 100644 --- a/apps/dokploy/templates/hi-events/docker-compose.yml +++ b/apps/dokploy/templates/hi-events/docker-compose.yml @@ -28,8 +28,7 @@ services: postgres: image: elestio/postgres:16 restart: always - networks: - - dokploy-network + environment: - POSTGRES_DB - POSTGRES_USER diff --git a/apps/dokploy/templates/huly/docker-compose.yml b/apps/dokploy/templates/huly/docker-compose.yml index 471ee7e9..639b10d2 100644 --- a/apps/dokploy/templates/huly/docker-compose.yml +++ b/apps/dokploy/templates/huly/docker-compose.yml @@ -2,8 +2,7 @@ name: ${DOCKER_NAME} version: "3" services: nginx: - networks: - - dokploy-network + image: "nginx:1.21.3" ports: - 80 @@ -12,8 +11,7 @@ services: restart: unless-stopped mongodb: - networks: - - dokploy-network + image: "mongo:7-jammy" environment: - PUID=1000 @@ -23,8 +21,7 @@ services: restart: unless-stopped minio: - networks: - - dokploy-network + image: "minio/minio:RELEASE.2024-11-07T00-52-20Z" command: server /data --address ":9000" --console-address ":9001" volumes: @@ -32,8 +29,7 @@ services: restart: unless-stopped elastic: - networks: - - dokploy-network + image: "elasticsearch:7.14.2" command: | /bin/sh -c "./bin/elasticsearch-plugin list | grep -q ingest-attachment || yes | ./bin/elasticsearch-plugin install --silent ingest-attachment; @@ -54,8 +50,7 @@ services: restart: unless-stopped rekoni: - networks: - - dokploy-network + image: hardcoreeng/rekoni-service:${HULY_VERSION} environment: - SECRET=${SECRET} @@ -66,8 +61,7 @@ services: restart: unless-stopped transactor: - networks: - - dokploy-network + image: hardcoreeng/transactor:${HULY_VERSION} environment: - SERVER_PORT=3333 @@ -84,8 +78,7 @@ services: restart: unless-stopped collaborator: - networks: - - dokploy-network + image: hardcoreeng/collaborator:${HULY_VERSION} environment: - COLLABORATOR_PORT=3078 @@ -97,8 +90,7 @@ services: restart: unless-stopped account: - networks: - - dokploy-network + image: hardcoreeng/account:${HULY_VERSION} environment: - SERVER_PORT=3000 @@ -115,8 +107,7 @@ services: restart: unless-stopped workspace: - networks: - - dokploy-network + image: hardcoreeng/workspace:${HULY_VERSION} environment: - SERVER_SECRET=${SECRET} @@ -130,8 +121,7 @@ services: restart: unless-stopped front: - networks: - - dokploy-network + image: hardcoreeng/front:${HULY_VERSION} environment: - SERVER_PORT=8080 @@ -156,8 +146,7 @@ services: restart: unless-stopped fulltext: - networks: - - dokploy-network + image: hardcoreeng/fulltext:${HULY_VERSION} environment: - SERVER_SECRET=${SECRET} @@ -171,8 +160,7 @@ services: restart: unless-stopped stats: - networks: - - dokploy-network + image: hardcoreeng/stats:${HULY_VERSION} environment: - PORT=4900 diff --git a/apps/dokploy/templates/immich/docker-compose.yml b/apps/dokploy/templates/immich/docker-compose.yml index 2a9fb00b..743f70ac 100644 --- a/apps/dokploy/templates/immich/docker-compose.yml +++ b/apps/dokploy/templates/immich/docker-compose.yml @@ -3,8 +3,7 @@ version: "3.9" services: immich-server: image: ghcr.io/immich-app/immich-server:v1.121.0 - networks: - - dokploy-network + volumes: - immich-library:/usr/src/app/upload - /etc/localtime:/etc/localtime:ro @@ -38,8 +37,7 @@ services: immich-machine-learning: image: ghcr.io/immich-app/immich-machine-learning:v1.121.0 - networks: - - dokploy-network + volumes: - immich-model-cache:/cache environment: @@ -55,8 +53,7 @@ services: immich-redis: image: redis:6.2-alpine - networks: - - dokploy-network + volumes: - immich-redis-data:/data healthcheck: @@ -68,8 +65,7 @@ services: immich-database: image: tensorchord/pgvecto-rs:pg14-v0.2.0 - networks: - - dokploy-network + volumes: - immich-postgres:/var/lib/postgresql/data environment: diff --git a/apps/dokploy/templates/infisical/docker-compose.yml b/apps/dokploy/templates/infisical/docker-compose.yml index 3baca926..7566c898 100644 --- a/apps/dokploy/templates/infisical/docker-compose.yml +++ b/apps/dokploy/templates/infisical/docker-compose.yml @@ -19,8 +19,7 @@ services: - SMTP_SECURE=true command: npm run migration:latest pull_policy: always - networks: - - dokploy-network + backend: restart: unless-stopped @@ -46,8 +45,7 @@ services: - SMTP_USERNAME - SMTP_PASSWORD - SMTP_SECURE=true - networks: - - dokploy-network + redis: image: redis:7.4.1 @@ -55,8 +53,7 @@ services: restart: always environment: - ALLOW_EMPTY_PASSWORD=yes - networks: - - dokploy-network + volumes: - redis_infisical_data:/data @@ -69,8 +66,7 @@ services: - POSTGRES_DB volumes: - pg_infisical_data:/var/lib/postgresql/data - networks: - - dokploy-network + healthcheck: test: "pg_isready --username=${POSTGRES_USER} && psql --username=${POSTGRES_USER} --list" interval: 5s diff --git a/apps/dokploy/templates/invoiceshelf/docker-compose.yml b/apps/dokploy/templates/invoiceshelf/docker-compose.yml index 5afdd152..ef47f1c0 100644 --- a/apps/dokploy/templates/invoiceshelf/docker-compose.yml +++ b/apps/dokploy/templates/invoiceshelf/docker-compose.yml @@ -3,8 +3,7 @@ version: "3.8" services: invoiceshelf-postgres: image: postgres:15 - networks: - - dokploy-network + volumes: - invoiceshelf-postgres-data:/var/lib/postgresql/data environment: @@ -19,8 +18,7 @@ services: invoiceshelf-app: image: invoiceshelf/invoiceshelf:latest - networks: - - dokploy-network + volumes: - invoiceshelf-app-data:/data - invoiceshelf-app-conf:/conf diff --git a/apps/dokploy/templates/kimai/docker-compose.yml b/apps/dokploy/templates/kimai/docker-compose.yml index 6a04b3b9..253ecb00 100644 --- a/apps/dokploy/templates/kimai/docker-compose.yml +++ b/apps/dokploy/templates/kimai/docker-compose.yml @@ -16,8 +16,7 @@ services: depends_on: db: condition: service_healthy - networks: - - dokploy-network + db: image: mariadb:10.11 restart: unless-stopped @@ -39,8 +38,7 @@ services: timeout: 5s retries: 5 start_period: 30s - networks: - - dokploy-network + networks: dokploy-network: diff --git a/apps/dokploy/templates/langflow/docker-compose.yml b/apps/dokploy/templates/langflow/docker-compose.yml index 75bb73dd..a9628286 100644 --- a/apps/dokploy/templates/langflow/docker-compose.yml +++ b/apps/dokploy/templates/langflow/docker-compose.yml @@ -12,8 +12,7 @@ services: # This variable defines where the logs, file storage, monitor data and secret keys are stored. volumes: - langflow-data:/app/langflow - networks: - - dokploy-network + postgres-langflow: image: postgres:16 @@ -25,8 +24,7 @@ services: - 5432 volumes: - langflow-postgres:/var/lib/postgresql/data - networks: - - dokploy-network + volumes: langflow-postgres: diff --git a/apps/dokploy/templates/listmonk/docker-compose.yml b/apps/dokploy/templates/listmonk/docker-compose.yml index 17b09f41..9646a208 100644 --- a/apps/dokploy/templates/listmonk/docker-compose.yml +++ b/apps/dokploy/templates/listmonk/docker-compose.yml @@ -3,8 +3,7 @@ services: image: postgres:17-alpine ports: - 5432 - networks: - - dokploy-network + environment: - POSTGRES_PASSWORD=listmonk - POSTGRES_USER=listmonk @@ -20,8 +19,7 @@ services: setup: image: listmonk/listmonk:v4.1.0 - networks: - - dokploy-network + volumes: - ../files/config.toml:/listmonk/config.toml depends_on: diff --git a/apps/dokploy/templates/logto/docker-compose.yml b/apps/dokploy/templates/logto/docker-compose.yml index e1f7c46a..6f2b920a 100644 --- a/apps/dokploy/templates/logto/docker-compose.yml +++ b/apps/dokploy/templates/logto/docker-compose.yml @@ -8,8 +8,7 @@ services: ports: - 3001 - 3002 - networks: - - dokploy-network + environment: TRUST_PROXY_HEADER: 1 DB_URL: postgres://logto:${LOGTO_POSTGRES_PASSWORD}@postgres:5432/logto @@ -20,8 +19,7 @@ services: postgres: image: postgres:17-alpine user: postgres - networks: - - dokploy-network + environment: POSTGRES_USER: logto POSTGRES_PASSWORD: ${LOGTO_POSTGRES_PASSWORD} diff --git a/apps/dokploy/templates/maybe/docker-compose.yml b/apps/dokploy/templates/maybe/docker-compose.yml index 017ca29b..db529e0a 100644 --- a/apps/dokploy/templates/maybe/docker-compose.yml +++ b/apps/dokploy/templates/maybe/docker-compose.yml @@ -24,8 +24,7 @@ services: interval: 5s timeout: 5s retries: 5 - networks: - - dokploy-network + volumes: - db-data:/var/lib/postgresql/data environment: diff --git a/apps/dokploy/templates/metabase/docker-compose.yml b/apps/dokploy/templates/metabase/docker-compose.yml index 4dca4d01..43a03987 100644 --- a/apps/dokploy/templates/metabase/docker-compose.yml +++ b/apps/dokploy/templates/metabase/docker-compose.yml @@ -22,5 +22,4 @@ services: POSTGRES_USER: metabase POSTGRES_DB: metabaseappdb POSTGRES_PASSWORD: mysecretpassword - networks: - - dokploy-network + diff --git a/apps/dokploy/templates/nextcloud-aio/docker-compose.yml b/apps/dokploy/templates/nextcloud-aio/docker-compose.yml index e8381d2b..1e6d00fe 100644 --- a/apps/dokploy/templates/nextcloud-aio/docker-compose.yml +++ b/apps/dokploy/templates/nextcloud-aio/docker-compose.yml @@ -2,8 +2,7 @@ services: nextcloud: image: nextcloud:30.0.2 restart: always - networks: - - dokploy-network + ports: - 80 volumes: @@ -19,8 +18,7 @@ services: nextcloud_db: image: mariadb restart: always - networks: - - dokploy-network + volumes: - nextcloud_db_data:/var/lib/mysql environment: diff --git a/apps/dokploy/templates/nocodb/docker-compose.yml b/apps/dokploy/templates/nocodb/docker-compose.yml index 3d5c9ee7..7c4fd1e9 100644 --- a/apps/dokploy/templates/nocodb/docker-compose.yml +++ b/apps/dokploy/templates/nocodb/docker-compose.yml @@ -13,8 +13,7 @@ services: root_db: image: postgres:17 restart: always - networks: - - dokploy-network + environment: POSTGRES_DB: root_db POSTGRES_PASSWORD: password diff --git a/apps/dokploy/templates/odoo/docker-compose.yml b/apps/dokploy/templates/odoo/docker-compose.yml index 80b34f0c..7c1c7d3c 100644 --- a/apps/dokploy/templates/odoo/docker-compose.yml +++ b/apps/dokploy/templates/odoo/docker-compose.yml @@ -15,8 +15,7 @@ services: db: image: postgres:13 - networks: - - dokploy-network + environment: - POSTGRES_DB=postgres - POSTGRES_USER=odoo diff --git a/apps/dokploy/templates/open-webui/docker-compose.yml b/apps/dokploy/templates/open-webui/docker-compose.yml index d396dacc..ee179721 100644 --- a/apps/dokploy/templates/open-webui/docker-compose.yml +++ b/apps/dokploy/templates/open-webui/docker-compose.yml @@ -3,8 +3,7 @@ services: ollama: volumes: - ollama:/root/.ollama - networks: - - dokploy-network + pull_policy: always tty: true restart: unless-stopped diff --git a/apps/dokploy/templates/penpot/docker-compose.yml b/apps/dokploy/templates/penpot/docker-compose.yml index 55abdb53..3e0efe91 100644 --- a/apps/dokploy/templates/penpot/docker-compose.yml +++ b/apps/dokploy/templates/penpot/docker-compose.yml @@ -46,8 +46,7 @@ services: - penpot-backend - penpot-exporter - networks: - - dokploy-network + environment: PENPOT_FLAGS: disable-email-verification enable-smtp enable-prepl-server disable-secure-session-cookies @@ -63,8 +62,7 @@ services: - penpot-postgres - penpot-redis - networks: - - dokploy-network + ## Configuration envronment variables for the backend ## container. @@ -143,8 +141,7 @@ services: penpot-exporter: image: "penpotapp/exporter:2.3.2" restart: always - networks: - - dokploy-network + environment: # Don't touch it; this uses an internal docker network to @@ -162,8 +159,7 @@ services: volumes: - penpot_postgres_v15:/var/lib/postgresql/data - networks: - - dokploy-network + environment: - POSTGRES_INITDB_ARGS=--data-checksums @@ -174,8 +170,7 @@ services: penpot-redis: image: redis:7.2 restart: always - networks: - - dokploy-network + ## A mailcatch service, used as temporal SMTP server. You can access via HTTP to the ## port 1080 for read all emails the penpot platform has sent. Should be only used as a @@ -188,8 +183,7 @@ services: - '1025' ports: - 1080 - networks: - - dokploy-network + ## Example configuration of MiniIO (S3 compatible object storage service); If you don't ## have preference, then just use filesystem, this is here just for the completeness. diff --git a/apps/dokploy/templates/peppermint/docker-compose.yml b/apps/dokploy/templates/peppermint/docker-compose.yml index 305c5eb9..06fb46c6 100644 --- a/apps/dokploy/templates/peppermint/docker-compose.yml +++ b/apps/dokploy/templates/peppermint/docker-compose.yml @@ -4,8 +4,7 @@ services: peppermint-postgres: image: postgres:latest restart: always - networks: - - dokploy-network + volumes: - peppermint-postgres-data:/var/lib/postgresql/data environment: @@ -21,8 +20,7 @@ services: peppermint-app: image: pepperlabs/peppermint:latest restart: always - networks: - - dokploy-network + depends_on: peppermint-postgres: condition: service_healthy diff --git a/apps/dokploy/templates/photoprism/docker-compose.yml b/apps/dokploy/templates/photoprism/docker-compose.yml index 285f2ff8..56793dbd 100644 --- a/apps/dokploy/templates/photoprism/docker-compose.yml +++ b/apps/dokploy/templates/photoprism/docker-compose.yml @@ -7,8 +7,7 @@ services: security_opt: - seccomp:unconfined - apparmor:unconfined - networks: - - dokploy-network + environment: PHOTOPRISM_ADMIN_USER: "admin" PHOTOPRISM_ADMIN_PASSWORD: ${ADMIN_PASSWORD} @@ -57,8 +56,7 @@ services: image: mariadb:11 restart: unless-stopped stop_grace_period: 5s - networks: - - dokploy-network + security_opt: - seccomp:unconfined - apparmor:unconfined diff --git a/apps/dokploy/templates/phpmyadmin/docker-compose.yml b/apps/dokploy/templates/phpmyadmin/docker-compose.yml index 1f775f09..91674e87 100644 --- a/apps/dokploy/templates/phpmyadmin/docker-compose.yml +++ b/apps/dokploy/templates/phpmyadmin/docker-compose.yml @@ -10,8 +10,7 @@ services: MYSQL_PASSWORD: ${MYSQL_PASSWORD} volumes: - db_data:/var/lib/mysql - networks: - - dokploy-network + phpmyadmin: image: phpmyadmin/phpmyadmin:5.2.1 diff --git a/apps/dokploy/templates/plausible/docker-compose.yml b/apps/dokploy/templates/plausible/docker-compose.yml index bb267f65..f17bdfa3 100644 --- a/apps/dokploy/templates/plausible/docker-compose.yml +++ b/apps/dokploy/templates/plausible/docker-compose.yml @@ -3,8 +3,7 @@ services: plausible_db: image: postgres:16-alpine restart: always - networks: - - dokploy-network + volumes: - db-data:/var/lib/postgresql/data environment: @@ -13,8 +12,7 @@ services: plausible_events_db: image: clickhouse/clickhouse-server:24.3.3.102-alpine restart: always - networks: - - dokploy-network + volumes: - event-data:/var/lib/clickhouse - event-logs:/var/log/clickhouse-server diff --git a/apps/dokploy/templates/portainer/docker-compose.yml b/apps/dokploy/templates/portainer/docker-compose.yml index fa4fe410..19e67a3e 100644 --- a/apps/dokploy/templates/portainer/docker-compose.yml +++ b/apps/dokploy/templates/portainer/docker-compose.yml @@ -6,8 +6,7 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock - /var/lib/docker/volumes:/var/lib/docker/volumes - networks: - - dokploy-network + deploy: mode: global diff --git a/apps/dokploy/templates/postiz/docker-compose.yml b/apps/dokploy/templates/postiz/docker-compose.yml index f842c92d..cd06e795 100644 --- a/apps/dokploy/templates/postiz/docker-compose.yml +++ b/apps/dokploy/templates/postiz/docker-compose.yml @@ -4,8 +4,7 @@ services: postiz-app: image: ghcr.io/gitroomhq/postiz-app:latest restart: always - networks: - - dokploy-network + environment: MAIN_URL: "https://${POSTIZ_HOST}" FRONTEND_URL: "https://${POSTIZ_HOST}" @@ -30,8 +29,7 @@ services: postiz-postgres: image: postgres:17-alpine restart: always - networks: - - dokploy-network + environment: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_USER: ${DB_USER} @@ -47,8 +45,7 @@ services: postiz-redis: image: redis:7.2 restart: always - networks: - - dokploy-network + healthcheck: test: redis-cli ping interval: 10s diff --git a/apps/dokploy/templates/rocketchat/docker-compose.yml b/apps/dokploy/templates/rocketchat/docker-compose.yml index 751bd845..5119f5a4 100644 --- a/apps/dokploy/templates/rocketchat/docker-compose.yml +++ b/apps/dokploy/templates/rocketchat/docker-compose.yml @@ -28,8 +28,7 @@ services: MONGODB_ADVERTISED_HOSTNAME: mongodb MONGODB_ENABLE_JOURNAL: true ALLOW_EMPTY_PASSWORD: yes - networks: - - dokploy-network + volumes: mongodb_data: { driver: local } diff --git a/apps/dokploy/templates/roundcube/docker-compose.yml b/apps/dokploy/templates/roundcube/docker-compose.yml index 440f907d..e5ba4a8b 100644 --- a/apps/dokploy/templates/roundcube/docker-compose.yml +++ b/apps/dokploy/templates/roundcube/docker-compose.yml @@ -9,8 +9,7 @@ services: - ROUNDCUBEMAIL_SKIN=elastic - ROUNDCUBEMAIL_DEFAULT_HOST=${DEFAULT_HOST} - ROUNDCUBEMAIL_SMTP_SERVER=${SMTP_SERVER} - networks: - - dokploy-network + networks: dokploy-network: diff --git a/apps/dokploy/templates/ryot/docker-compose.yml b/apps/dokploy/templates/ryot/docker-compose.yml index 1fcd80ed..09a72707 100644 --- a/apps/dokploy/templates/ryot/docker-compose.yml +++ b/apps/dokploy/templates/ryot/docker-compose.yml @@ -3,8 +3,7 @@ version: '3.7' services: ryot-app: image: ignisda/ryot:v7.10 - networks: - - dokploy-network + environment: - DATABASE_URL=postgres://postgres:${POSTGRES_PASSWORD}@ryot-db:5432/postgres - SERVER_ADMIN_ACCESS_TOKEN=${ADMIN_ACCESS_TOKEN} @@ -19,8 +18,7 @@ services: ryot-db: image: postgres:16-alpine - networks: - - dokploy-network + volumes: - ryot-postgres-data:/var/lib/postgresql/data environment: diff --git a/apps/dokploy/templates/slash/docker-compose.yml b/apps/dokploy/templates/slash/docker-compose.yml index 75afc478..ee6cdf89 100644 --- a/apps/dokploy/templates/slash/docker-compose.yml +++ b/apps/dokploy/templates/slash/docker-compose.yml @@ -3,8 +3,7 @@ version: "3.8" services: slash-app: image: yourselfhosted/slash:latest - networks: - - dokploy-network + volumes: - slash-app-data:/var/opt/slash environment: @@ -17,8 +16,7 @@ services: slash-postgres: image: postgres:16-alpine - networks: - - dokploy-network + volumes: - slash-postgres-data:/var/lib/postgresql/data environment: diff --git a/apps/dokploy/templates/supabase/docker-compose.yml b/apps/dokploy/templates/supabase/docker-compose.yml index e1e187fd..89339736 100644 --- a/apps/dokploy/templates/supabase/docker-compose.yml +++ b/apps/dokploy/templates/supabase/docker-compose.yml @@ -11,8 +11,7 @@ services: studio: container_name: supabase-studio image: supabase/studio:20240729-ce42139 - networks: - - dokploy-network + restart: unless-stopped healthcheck: test: @@ -53,8 +52,7 @@ services: container_name: supabase-kong image: kong:2.8.1 restart: unless-stopped - networks: - - dokploy-network + # https://unix.stackexchange.com/a/294837 entrypoint: bash -c 'eval "echo \"$$(cat ~/temp.yml)\"" > ~/kong.yml && /docker-entrypoint.sh kong docker-start' #ports: @@ -85,8 +83,7 @@ services: auth: container_name: supabase-auth image: supabase/gotrue:v2.158.1 - networks: - - dokploy-network + depends_on: db: # Disable this if you are using an external Postgres database @@ -157,8 +154,7 @@ services: rest: container_name: supabase-rest image: postgrest/postgrest:v12.2.0 - networks: - - dokploy-network + depends_on: db: # Disable this if you are using an external Postgres database @@ -180,8 +176,7 @@ services: # This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain container_name: realtime-dev.supabase-realtime image: supabase/realtime:v2.30.23 - networks: - - dokploy-network + depends_on: db: # Disable this if you are using an external Postgres database @@ -226,8 +221,7 @@ services: storage: container_name: supabase-storage image: supabase/storage-api:v1.0.6 - networks: - - dokploy-network + depends_on: db: # Disable this if you are using an external Postgres database @@ -271,8 +265,7 @@ services: imgproxy: container_name: supabase-imgproxy image: darthsim/imgproxy:v3.8.0 - networks: - - dokploy-network + healthcheck: test: ["CMD", "imgproxy", "health"] timeout: 5s @@ -289,8 +282,7 @@ services: meta: container_name: supabase-meta image: supabase/postgres-meta:v0.83.2 - networks: - - dokploy-network + depends_on: db: # Disable this if you are using an external Postgres database @@ -310,8 +302,7 @@ services: container_name: supabase-edge-functions image: supabase/edge-runtime:v1.56.0 restart: unless-stopped - networks: - - dokploy-network + depends_on: analytics: condition: service_healthy @@ -333,8 +324,7 @@ services: analytics: container_name: supabase-analytics image: supabase/logflare:1.4.0 - networks: - - dokploy-network + healthcheck: test: ["CMD", "curl", "http://localhost:4000/health"] timeout: 5s @@ -380,8 +370,7 @@ services: db: container_name: supabase-db image: supabase/postgres:15.1.1.78 - networks: - - dokploy-network + healthcheck: test: pg_isready -U postgres -h localhost interval: 5s @@ -430,8 +419,7 @@ services: vector: container_name: supabase-vector image: timberio/vector:0.28.1-alpine - networks: - - dokploy-network + healthcheck: test: [ diff --git a/apps/dokploy/templates/superset/docker-compose.yml b/apps/dokploy/templates/superset/docker-compose.yml index e3fb3454..8dd1cd2d 100644 --- a/apps/dokploy/templates/superset/docker-compose.yml +++ b/apps/dokploy/templates/superset/docker-compose.yml @@ -43,8 +43,7 @@ services: interval: 30s timeout: 10s retries: 3 - networks: - - dokploy-network + superset_redis: image: redis @@ -57,8 +56,7 @@ services: interval: 30s timeout: 10s retries: 3 - networks: - - dokploy-network + volumes: superset_postgres_data: diff --git a/apps/dokploy/templates/teable/docker-compose.yml b/apps/dokploy/templates/teable/docker-compose.yml index 959de21c..386e3773 100644 --- a/apps/dokploy/templates/teable/docker-compose.yml +++ b/apps/dokploy/templates/teable/docker-compose.yml @@ -41,8 +41,7 @@ services: - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - networks: - - dokploy-network + healthcheck: test: [ @@ -58,8 +57,7 @@ services: environment: - TZ=${TIMEZONE} - PRISMA_DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} - networks: - - dokploy-network + depends_on: teable-db: condition: service_healthy diff --git a/apps/dokploy/templates/twenty/docker-compose.yml b/apps/dokploy/templates/twenty/docker-compose.yml index 34c70aeb..800e9a72 100644 --- a/apps/dokploy/templates/twenty/docker-compose.yml +++ b/apps/dokploy/templates/twenty/docker-compose.yml @@ -4,8 +4,7 @@ services: twenty-change-vol-ownership: image: ubuntu user: root - networks: - - dokploy-network + volumes: - twenty-server-local-data:/tmp/server-local-data - twenty-docker-data:/tmp/docker-data @@ -16,8 +15,7 @@ services: twenty-server: image: twentycrm/twenty:latest - networks: - - dokploy-network + volumes: - twenty-server-local-data:/app/packages/twenty-server/${STORAGE_LOCAL_PATH:-.local-storage} - twenty-docker-data:/app/docker-data @@ -45,8 +43,7 @@ services: twenty-worker: image: twentycrm/twenty:latest - networks: - - dokploy-network + command: ["yarn", "worker:prod"] environment: PG_DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@twenty-postgres:5432/twenty @@ -65,8 +62,7 @@ services: twenty-postgres: image: postgres:16-alpine - networks: - - dokploy-network + volumes: - twenty-postgres-data:/var/lib/postgresql/data environment: @@ -82,8 +78,7 @@ services: twenty-redis: image: redis:latest - networks: - - dokploy-network + volumes: - twenty-redis-data:/data healthcheck: diff --git a/apps/dokploy/templates/typebot/docker-compose.yml b/apps/dokploy/templates/typebot/docker-compose.yml index 739793fe..7881bd8f 100644 --- a/apps/dokploy/templates/typebot/docker-compose.yml +++ b/apps/dokploy/templates/typebot/docker-compose.yml @@ -13,8 +13,7 @@ services: POSTGRES_USER: typebot POSTGRES_DB: typebot POSTGRES_PASSWORD: typebot - networks: - - dokploy-network + typebot-builder: image: baptistearno/typebot-builder:2.27 diff --git a/apps/dokploy/templates/umami/docker-compose.yml b/apps/dokploy/templates/umami/docker-compose.yml index 191c4803..87568165 100644 --- a/apps/dokploy/templates/umami/docker-compose.yml +++ b/apps/dokploy/templates/umami/docker-compose.yml @@ -22,8 +22,7 @@ services: interval: 5s timeout: 5s retries: 5 - networks: - - dokploy-network + volumes: - db-data:/var/lib/postgresql/data environment: diff --git a/apps/dokploy/templates/unifi/docker-compose.yml b/apps/dokploy/templates/unifi/docker-compose.yml index ee531f67..cf0102c0 100644 --- a/apps/dokploy/templates/unifi/docker-compose.yml +++ b/apps/dokploy/templates/unifi/docker-compose.yml @@ -29,8 +29,7 @@ services: restart: unless-stopped depends_on: - unifi-db - networks: - - dokploy-network + unifi-db: image: mongo:4.4 @@ -40,8 +39,7 @@ services: ports: - 27017 restart: unless-stopped - networks: - - dokploy-network + networks: dokploy-network: diff --git a/apps/dokploy/templates/unsend/docker-compose.yml b/apps/dokploy/templates/unsend/docker-compose.yml index 67a1392c..714ec1e1 100644 --- a/apps/dokploy/templates/unsend/docker-compose.yml +++ b/apps/dokploy/templates/unsend/docker-compose.yml @@ -3,8 +3,7 @@ name: unsend-prod services: unsend-db-prod: image: postgres:16 - networks: - - dokploy-network + restart: always environment: - POSTGRES_USER=${POSTGRES_USER:?err} @@ -22,8 +21,7 @@ services: unsend-redis-prod: image: redis:7 - networks: - - dokploy-network + restart: always # ports: # - "6379:6379" @@ -33,8 +31,7 @@ services: unsend-storage-prod: image: minio/minio:RELEASE.2024-11-07T00-52-20Z - networks: - - dokploy-network + ports: - 9002 - 9001 @@ -48,8 +45,7 @@ services: unsend: image: unsend/unsend:v1.2.5 - networks: - - dokploy-network + restart: always ports: - ${PORT:-3000} diff --git a/apps/dokploy/templates/windmill/docker-compose.yml b/apps/dokploy/templates/windmill/docker-compose.yml index de91ee55..9e91fa0a 100644 --- a/apps/dokploy/templates/windmill/docker-compose.yml +++ b/apps/dokploy/templates/windmill/docker-compose.yml @@ -7,8 +7,7 @@ services: restart: unless-stopped volumes: - windmill-postgres-data:/var/lib/postgresql/data - networks: - - dokploy-network + environment: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: windmill @@ -20,8 +19,7 @@ services: windmill-server: image: ghcr.io/windmill-labs/windmill:main - networks: - - dokploy-network + restart: unless-stopped environment: - DATABASE_URL=${DATABASE_URL} @@ -42,8 +40,7 @@ services: cpus: "1" memory: 2048M restart: unless-stopped - networks: - - dokploy-network + environment: - DATABASE_URL=${DATABASE_URL} - MODE=worker @@ -65,8 +62,7 @@ services: cpus: "0.1" memory: 128M restart: unless-stopped - networks: - - dokploy-network + environment: - DATABASE_URL=${DATABASE_URL} - MODE=worker @@ -82,16 +78,14 @@ services: windmill-lsp: image: ghcr.io/windmill-labs/windmill-lsp:latest restart: unless-stopped - networks: - - dokploy-network + volumes: - windmill-lsp-cache:/root/.cache windmill-caddy: image: ghcr.io/windmill-labs/caddy-l4:latest restart: unless-stopped - networks: - - dokploy-network + volumes: - ../files/Caddyfile:/etc/caddy/Caddyfile environment: diff --git a/apps/dokploy/templates/wordpress/docker-compose.yml b/apps/dokploy/templates/wordpress/docker-compose.yml index 7647859d..f2fc4d9a 100644 --- a/apps/dokploy/templates/wordpress/docker-compose.yml +++ b/apps/dokploy/templates/wordpress/docker-compose.yml @@ -12,8 +12,6 @@ services: db: image: mysql:5.7.34 - networks: - - dokploy-network environment: MYSQL_DATABASE: exampledb MYSQL_USER: exampleuser diff --git a/apps/dokploy/templates/yourls/docker-compose.yml b/apps/dokploy/templates/yourls/docker-compose.yml index ff2e14d9..f4aa16e3 100644 --- a/apps/dokploy/templates/yourls/docker-compose.yml +++ b/apps/dokploy/templates/yourls/docker-compose.yml @@ -3,8 +3,7 @@ version: '3.7' services: yourls-app: image: yourls:1.9.2 - networks: - - dokploy-network + environment: YOURLS_SITE: https://${YOURLS_HOST} YOURLS_USER: ${YOURLS_ADMIN_USER} @@ -22,8 +21,7 @@ services: yourls-mysql: image: mysql:5.7 - networks: - - dokploy-network + environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: yourls diff --git a/apps/dokploy/templates/zipline/docker-compose.yml b/apps/dokploy/templates/zipline/docker-compose.yml index 808b0b89..e29132df 100644 --- a/apps/dokploy/templates/zipline/docker-compose.yml +++ b/apps/dokploy/templates/zipline/docker-compose.yml @@ -2,8 +2,7 @@ version: "3" services: postgres: image: postgres:15 - networks: - - dokploy-network + restart: unless-stopped environment: - POSTGRES_USER=postgres From 3a5ecb2f6492967b469512816b7130426d7d45f0 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 9 Feb 2025 02:33:30 -0600 Subject: [PATCH 11/11] refactor: remove unused imports --- .../dashboard/compose/general/compose-file-editor.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx index 71b92814..c4ce44e5 100644 --- a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx +++ b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx @@ -14,8 +14,6 @@ import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; import { validateAndFormatYAML } from "../../application/advanced/traefik/update-traefik-config"; -import { RandomizeDeployable } from "./isolated-deployment"; -import { RandomizeCompose } from "./randomize-compose"; import { ShowUtilities } from "./show-utilities"; interface Props {