From f2ae39aa8645fb89b115323e82dd10edd58f532d Mon Sep 17 00:00:00 2001 From: PiquelChips <63727792+PiquelChips@users.noreply.github.com> Date: Wed, 23 Jul 2025 21:39:54 +0200 Subject: [PATCH 01/49] feat: preview deployments for pull requests with specific labels --- .../show-preview-settings.tsx | 17 +++++++++++++++++ apps/dokploy/pages/api/deploy/github.ts | 13 +++++++++++++ packages/server/src/db/schema/application.ts | 1 + 3 files changed, 31 insertions(+) diff --git a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx index a0f6ae0e4..7da10ea37 100644 --- a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx +++ b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx @@ -42,6 +42,7 @@ const schema = z wildcardDomain: z.string(), port: z.number(), previewLimit: z.number(), + previewLabels: z.string(), previewHttps: z.boolean(), previewPath: z.string(), previewCertificateType: z.enum(["letsencrypt", "none", "custom"]), @@ -81,6 +82,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { wildcardDomain: "*.traefik.me", port: 3000, previewLimit: 3, + previewLabels: "", previewHttps: false, previewPath: "/", previewCertificateType: "none", @@ -102,6 +104,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { buildArgs: data.previewBuildArgs || "", wildcardDomain: data.previewWildcard || "*.traefik.me", port: data.previewPort || 3000, + previewLabels: data.previewLabels || "", previewLimit: data.previewLimit || 3, previewHttps: data.previewHttps || false, previewPath: data.previewPath || "/", @@ -119,6 +122,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { previewBuildArgs: formData.buildArgs, previewWildcard: formData.wildcardDomain, previewPort: formData.port, + previewLabels: formData.previewLabels, applicationId, previewLimit: formData.previewLimit, previewHttps: formData.previewHttps, @@ -200,6 +204,19 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { )} /> + ( + + Labels + + + + + + )} + /> previewLimit) { continue; diff --git a/packages/server/src/db/schema/application.ts b/packages/server/src/db/schema/application.ts index 40793fc88..7ccd44b36 100644 --- a/packages/server/src/db/schema/application.ts +++ b/packages/server/src/db/schema/application.ts @@ -119,6 +119,7 @@ export const applications = pgTable("application", { previewEnv: text("previewEnv"), watchPaths: text("watchPaths").array(), previewBuildArgs: text("previewBuildArgs"), + previewLabels: text("previewLabels"), previewWildcard: text("previewWildcard"), previewPort: integer("previewPort").default(3000), previewHttps: boolean("previewHttps").notNull().default(false), From a5bc384d77df6e461c0e44be4c34438373302b59 Mon Sep 17 00:00:00 2001 From: PiquelChips <63727792+PiquelChips@users.noreply.github.com> Date: Thu, 24 Jul 2025 19:02:50 +0200 Subject: [PATCH 02/49] run database migration --- .../dokploy/drizzle/0104_yummy_silver_fox.sql | 1 + apps/dokploy/drizzle/meta/0104_snapshot.json | 6142 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + 3 files changed, 6150 insertions(+) create mode 100644 apps/dokploy/drizzle/0104_yummy_silver_fox.sql create mode 100644 apps/dokploy/drizzle/meta/0104_snapshot.json diff --git a/apps/dokploy/drizzle/0104_yummy_silver_fox.sql b/apps/dokploy/drizzle/0104_yummy_silver_fox.sql new file mode 100644 index 000000000..4f3dd4654 --- /dev/null +++ b/apps/dokploy/drizzle/0104_yummy_silver_fox.sql @@ -0,0 +1 @@ +ALTER TABLE "application" ADD COLUMN "previewLabels" text; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0104_snapshot.json b/apps/dokploy/drizzle/meta/0104_snapshot.json new file mode 100644 index 000000000..b01c25118 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0104_snapshot.json @@ -0,0 +1,6142 @@ +{ + "id": "55b7955d-30af-4d68-b9df-6e39cc6a5137", + "prevId": "8bf085dd-e054-4ae6-811b-1d1a68dab752", + "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 + }, + "watchPaths": { + "name": "watchPaths", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewLabels": { + "name": "previewLabels", + "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'" + }, + "previewCustomCertResolver": { + "name": "previewCustomCertResolver", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewRequireCollaboratorPermissions": { + "name": "previewRequireCollaboratorPermissions", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "rollbackActive": { + "name": "rollbackActive", + "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'" + }, + "cleanCache": { + "name": "cleanCache", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "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": "'/'" + }, + "triggerType": { + "name": "triggerType", + "type": "triggerType", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'push'" + }, + "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 + }, + "giteaRepository": { + "name": "giteaRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaOwner": { + "name": "giteaOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaBranch": { + "name": "giteaBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaBuildPath": { + "name": "giteaBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "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 + }, + "enableSubmodules": { + "name": "enableSubmodules", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": 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 + }, + "isStaticSpa": { + "name": "isStaticSpa", + "type": "boolean", + "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 + }, + "giteaId": { + "name": "giteaId", + "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_giteaId_gitea_giteaId_fk": { + "name": "application_giteaId_gitea_giteaId_fk", + "tableFrom": "application", + "tableTo": "gitea", + "columnsFrom": [ + "giteaId" + ], + "columnsTo": [ + "giteaId" + ], + "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_temp": { + "name": "user_temp", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "banned": { + "name": "banned", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "https": { + "name": "https", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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 + }, + "logCleanupCron": { + "name": "logCleanupCron", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'0 0 * * *'" + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'user'" + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "allowImpersonation": { + "name": "allowImpersonation", + "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 + }, + "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 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_temp_email_unique": { + "name": "user_temp_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 + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "project_organizationId_organization_id_fk": { + "name": "project_organizationId_organization_id_fk", + "tableFrom": "project", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "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 + }, + "customCertResolver": { + "name": "customCertResolver", + "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'" + }, + "internalPath": { + "name": "internalPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "stripPath": { + "name": "stripPath", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "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 + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "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 + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keepLatestCount": { + "name": "keepLatestCount", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "backupType": { + "name": "backupType", + "type": "backupType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'database'" + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "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_composeId_compose_composeId_fk": { + "name": "backup_composeId_compose_composeId_fk", + "tableFrom": "backup", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "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" + }, + "backup_userId_user_temp_id_fk": { + "name": "backup_userId_user_temp_id_fk", + "tableFrom": "backup", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "backup_appName_unique": { + "name": "backup_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "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 + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "destination_organizationId_organization_id_fk": { + "name": "destination_organizationId_organization_id_fk", + "tableFrom": "destination", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "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 + }, + "pid": { + "name": "pid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "startedAt": { + "name": "startedAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "finishedAt": { + "name": "finishedAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scheduleId": { + "name": "scheduleId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "rollbackId": { + "name": "rollbackId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeBackupId": { + "name": "volumeBackupId", + "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" + }, + "deployment_scheduleId_schedule_scheduleId_fk": { + "name": "deployment_scheduleId_schedule_scheduleId_fk", + "tableFrom": "deployment", + "tableTo": "schedule", + "columnsFrom": [ + "scheduleId" + ], + "columnsTo": [ + "scheduleId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_backupId_backup_backupId_fk": { + "name": "deployment_backupId_backup_backupId_fk", + "tableFrom": "deployment", + "tableTo": "backup", + "columnsFrom": [ + "backupId" + ], + "columnsTo": [ + "backupId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_rollbackId_rollback_rollbackId_fk": { + "name": "deployment_rollbackId_rollback_rollbackId_fk", + "tableFrom": "deployment", + "tableTo": "rollback", + "columnsFrom": [ + "rollbackId" + ], + "columnsTo": [ + "rollbackId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_volumeBackupId_volume_backup_volumeBackupId_fk": { + "name": "deployment_volumeBackupId_volume_backup_volumeBackupId_fk", + "tableFrom": "deployment", + "tableTo": "volume_backup", + "columnsFrom": [ + "volumeBackupId" + ], + "columnsTo": [ + "volumeBackupId" + ], + "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 + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "certificate_organizationId_organization_id_fk": { + "name": "certificate_organizationId_organization_id_fk", + "tableFrom": "certificate", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "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_temp": { + "name": "session_temp", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "session_temp_user_id_user_temp_id_fk": { + "name": "session_temp_user_id_user_temp_id_fk", + "tableFrom": "session_temp", + "tableTo": "user_temp", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_temp_token_unique": { + "name": "session_temp_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "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 + }, + "publishMode": { + "name": "publishMode", + "type": "publishModeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'host'" + }, + "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 + }, + "giteaRepository": { + "name": "giteaRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaOwner": { + "name": "giteaOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaBranch": { + "name": "giteaBranch", + "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": "''" + }, + "enableSubmodules": { + "name": "enableSubmodules", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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 + }, + "isolatedDeploymentsVolume": { + "name": "isolatedDeploymentsVolume", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "triggerType": { + "name": "triggerType", + "type": "triggerType", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'push'" + }, + "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 + }, + "watchPaths": { + "name": "watchPaths", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "giteaId": { + "name": "giteaId", + "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_giteaId_gitea_giteaId_fk": { + "name": "compose_giteaId_gitea_giteaId_fk", + "tableFrom": "compose", + "tableTo": "gitea", + "columnsFrom": [ + "giteaId" + ], + "columnsTo": [ + "giteaId" + ], + "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'" + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_organizationId_organization_id_fk": { + "name": "registry_organizationId_organization_id_fk", + "tableFrom": "registry", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "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 + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "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_organizationId_organization_id_fk": { + "name": "notification_organizationId_organization_id_fk", + "tableFrom": "notification", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "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 + }, + "messageThreadId": { + "name": "messageThreadId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "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 + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "ssh-key_organizationId_organization_id_fk": { + "name": "ssh-key_organizationId_organization_id_fk", + "tableFrom": "ssh-key", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "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 + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "git_provider_organizationId_organization_id_fk": { + "name": "git_provider_organizationId_organization_id_fk", + "tableFrom": "git_provider", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "git_provider_userId_user_temp_id_fk": { + "name": "git_provider_userId_user_temp_id_fk", + "tableFrom": "git_provider", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "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.gitea": { + "name": "gitea", + "schema": "", + "columns": { + "giteaId": { + "name": "giteaId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "giteaUrl": { + "name": "giteaUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'https://gitea.com'" + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_secret": { + "name": "client_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'repo,repo:status,read:user,read:org'" + }, + "last_authenticated_at": { + "name": "last_authenticated_at", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "gitea_gitProviderId_git_provider_gitProviderId_fk": { + "name": "gitea_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "gitea", + "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 + }, + "organizationId": { + "name": "organizationId", + "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_organizationId_organization_id_fk": { + "name": "server_organizationId_organization_id_fk", + "tableFrom": "server", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "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 + }, + "public.ai": { + "name": "ai", + "schema": "", + "columns": { + "aiId": { + "name": "aiId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "apiUrl": { + "name": "apiUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isEnabled": { + "name": "isEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "ai_organizationId_organization_id_fk": { + "name": "ai_organizationId_organization_id_fk", + "tableFrom": "ai", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "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": { + "account_user_id_user_temp_id_fk": { + "name": "account_user_id_user_temp_id_fk", + "tableFrom": "account", + "tableTo": "user_temp", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.apikey": { + "name": "apikey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start": { + "name": "start", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refill_interval": { + "name": "refill_interval", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "refill_amount": { + "name": "refill_amount", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "rate_limit_enabled": { + "name": "rate_limit_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "rate_limit_time_window": { + "name": "rate_limit_time_window", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "rate_limit_max": { + "name": "rate_limit_max", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "request_count": { + "name": "request_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "remaining": { + "name": "remaining", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_request": { + "name": "last_request", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "apikey_user_id_user_temp_id_fk": { + "name": "apikey_user_id_user_temp_id_fk", + "tableFrom": "apikey", + "tableTo": "user_temp", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invitation": { + "name": "invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_inviter_id_user_temp_id_fk": { + "name": "invitation_inviter_id_user_temp_id_fk", + "tableFrom": "invitation", + "tableTo": "user_temp", + "columnsFrom": [ + "inviter_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.member": { + "name": "member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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[]" + } + }, + "indexes": {}, + "foreignKeys": { + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_user_id_user_temp_id_fk": { + "name": "member_user_id_user_temp_id_fk", + "tableFrom": "member", + "tableTo": "user_temp", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization": { + "name": "organization", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "organization_owner_id_user_temp_id_fk": { + "name": "organization_owner_id_user_temp_id_fk", + "tableFrom": "organization", + "tableTo": "user_temp", + "columnsFrom": [ + "owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.two_factor": { + "name": "two_factor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "backup_codes": { + "name": "backup_codes", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "two_factor_user_id_user_temp_id_fk": { + "name": "two_factor_user_id_user_temp_id_fk", + "tableFrom": "two_factor", + "tableTo": "user_temp", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.schedule": { + "name": "schedule", + "schema": "", + "columns": { + "scheduleId": { + "name": "scheduleId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cronExpression": { + "name": "cronExpression", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "shellType": { + "name": "shellType", + "type": "shellType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'bash'" + }, + "scheduleType": { + "name": "scheduleType", + "type": "scheduleType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "script": { + "name": "script", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "schedule_applicationId_application_applicationId_fk": { + "name": "schedule_applicationId_application_applicationId_fk", + "tableFrom": "schedule", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "schedule_composeId_compose_composeId_fk": { + "name": "schedule_composeId_compose_composeId_fk", + "tableFrom": "schedule", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "schedule_serverId_server_serverId_fk": { + "name": "schedule_serverId_server_serverId_fk", + "tableFrom": "schedule", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "schedule_userId_user_temp_id_fk": { + "name": "schedule_userId_user_temp_id_fk", + "tableFrom": "schedule", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rollback": { + "name": "rollback", + "schema": "", + "columns": { + "rollbackId": { + "name": "rollbackId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "deploymentId": { + "name": "deploymentId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fullContext": { + "name": "fullContext", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "rollback_deploymentId_deployment_deploymentId_fk": { + "name": "rollback_deploymentId_deployment_deploymentId_fk", + "tableFrom": "rollback", + "tableTo": "deployment", + "columnsFrom": [ + "deploymentId" + ], + "columnsTo": [ + "deploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.volume_backup": { + "name": "volume_backup", + "schema": "", + "columns": { + "volumeBackupId": { + "name": "volumeBackupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "turnOff": { + "name": "turnOff", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cronExpression": { + "name": "cronExpression", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keepLatestCount": { + "name": "keepLatestCount", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "volume_backup_applicationId_application_applicationId_fk": { + "name": "volume_backup_applicationId_application_applicationId_fk", + "tableFrom": "volume_backup", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_postgresId_postgres_postgresId_fk": { + "name": "volume_backup_postgresId_postgres_postgresId_fk", + "tableFrom": "volume_backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_mariadbId_mariadb_mariadbId_fk": { + "name": "volume_backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "volume_backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_mongoId_mongo_mongoId_fk": { + "name": "volume_backup_mongoId_mongo_mongoId_fk", + "tableFrom": "volume_backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_mysqlId_mysql_mysqlId_fk": { + "name": "volume_backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "volume_backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_redisId_redis_redisId_fk": { + "name": "volume_backup_redisId_redis_redisId_fk", + "tableFrom": "volume_backup", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_composeId_compose_composeId_fk": { + "name": "volume_backup_composeId_compose_composeId_fk", + "tableFrom": "volume_backup", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_destinationId_destination_destinationId_fk": { + "name": "volume_backup_destinationId_destination_destinationId_fk", + "tableFrom": "volume_backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static", + "railpack" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "gitea", + "drop" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.backupType": { + "name": "backupType", + "schema": "public", + "values": [ + "database", + "compose" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo", + "web-server" + ] + }, + "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.publishModeType": { + "name": "publishModeType", + "schema": "public", + "values": [ + "ingress", + "host" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none", + "custom" + ] + }, + "public.triggerType": { + "name": "triggerType", + "schema": "public", + "values": [ + "push", + "tag" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "gitea", + "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", + "gitea" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + }, + "public.scheduleType": { + "name": "scheduleType", + "schema": "public", + "values": [ + "application", + "compose", + "server", + "dokploy-server" + ] + }, + "public.shellType": { + "name": "shellType", + "schema": "public", + "values": [ + "bash", + "sh" + ] + } + }, + "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 d998792f5..0b7c8bbdf 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -729,6 +729,13 @@ "when": 1752465764072, "tag": "0103_cultured_pestilence", "breakpoints": true + }, + { + "idx": 104, + "version": "7", + "when": 1753376537774, + "tag": "0104_yummy_silver_fox", + "breakpoints": true } ] } \ No newline at end of file From a0bbf7be23ffaf661e25d28d2bab86dcecc8afc3 Mon Sep 17 00:00:00 2001 From: PiquelChips <63727792+PiquelChips@users.noreply.github.com> Date: Thu, 24 Jul 2025 19:35:33 +0200 Subject: [PATCH 03/49] add check for presence of labels --- apps/dokploy/pages/api/deploy/github.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/dokploy/pages/api/deploy/github.ts b/apps/dokploy/pages/api/deploy/github.ts index 6430255f1..5ea99989e 100644 --- a/apps/dokploy/pages/api/deploy/github.ts +++ b/apps/dokploy/pages/api/deploy/github.ts @@ -443,17 +443,19 @@ export default async function handler( for (const app of secureApps) { // check for labels - let hasLabel: boolean = false; - const labels = githubBody?.pull_request?.labels; - const previewLabels = app?.previewLabels?.split(","); - for (const label of labels) { - if (previewLabels.contains(label.name)) { - hasLabel = true; - break; + if (app?.previewLabels != "") { + const previewLabels = app?.previewLabels?.split(","); + let hasLabel: boolean = false; + const labels = githubBody?.pull_request?.labels; + for (const label of labels) { + if (previewLabels.contains(label.name)) { + hasLabel = true; + break; + } } - } - if (hasLabel) - continue; + if (hasLabel) + continue; + } const previewLimit = app?.previewLimit || 0; if (app?.previewDeployments?.length > previewLimit) { From 1f9ef473f16dfd931d7952ef2bedf1e3762e8d4d Mon Sep 17 00:00:00 2001 From: PiquelChips <63727792+PiquelChips@users.noreply.github.com> Date: Thu, 24 Jul 2025 19:45:43 +0200 Subject: [PATCH 04/49] format some files --- .../preview-deployments/show-preview-settings.tsx | 8 ++++---- apps/dokploy/pages/api/deploy/github.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx index 7da10ea37..569f75257 100644 --- a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx +++ b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx @@ -42,7 +42,7 @@ const schema = z wildcardDomain: z.string(), port: z.number(), previewLimit: z.number(), - previewLabels: z.string(), + previewLabels: z.string(), previewHttps: z.boolean(), previewPath: z.string(), previewCertificateType: z.enum(["letsencrypt", "none", "custom"]), @@ -82,7 +82,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { wildcardDomain: "*.traefik.me", port: 3000, previewLimit: 3, - previewLabels: "", + previewLabels: "", previewHttps: false, previewPath: "/", previewCertificateType: "none", @@ -104,7 +104,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { buildArgs: data.previewBuildArgs || "", wildcardDomain: data.previewWildcard || "*.traefik.me", port: data.previewPort || 3000, - previewLabels: data.previewLabels || "", + previewLabels: data.previewLabels || "", previewLimit: data.previewLimit || 3, previewHttps: data.previewHttps || false, previewPath: data.previewPath || "/", @@ -122,7 +122,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { previewBuildArgs: formData.buildArgs, previewWildcard: formData.wildcardDomain, previewPort: formData.port, - previewLabels: formData.previewLabels, + previewLabels: formData.previewLabels, applicationId, previewLimit: formData.previewLimit, previewHttps: formData.previewHttps, diff --git a/apps/dokploy/pages/api/deploy/github.ts b/apps/dokploy/pages/api/deploy/github.ts index 5ea99989e..22fc5446d 100644 --- a/apps/dokploy/pages/api/deploy/github.ts +++ b/apps/dokploy/pages/api/deploy/github.ts @@ -443,8 +443,8 @@ export default async function handler( for (const app of secureApps) { // check for labels - if (app?.previewLabels != "") { - const previewLabels = app?.previewLabels?.split(","); + if (app?.previewLabels != "") { + const previewLabels = app?.previewLabels?.split(","); let hasLabel: boolean = false; const labels = githubBody?.pull_request?.labels; for (const label of labels) { @@ -454,8 +454,8 @@ export default async function handler( } } if (hasLabel) - continue; - } + continue; + } const previewLimit = app?.previewLimit || 0; if (app?.previewDeployments?.length > previewLimit) { From 9baafb83ff5d19224bc55298340894d3779382a4 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 07:38:28 +0000 Subject: [PATCH 05/49] [autofix.ci] apply automated fixes --- .../preview-deployments/show-preview-settings.tsx | 5 ++++- apps/dokploy/pages/api/deploy/github.ts | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx index 569f75257..7e59482d4 100644 --- a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx +++ b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx @@ -211,7 +211,10 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { Labels - + diff --git a/apps/dokploy/pages/api/deploy/github.ts b/apps/dokploy/pages/api/deploy/github.ts index 22fc5446d..3ef822c18 100644 --- a/apps/dokploy/pages/api/deploy/github.ts +++ b/apps/dokploy/pages/api/deploy/github.ts @@ -453,8 +453,7 @@ export default async function handler( break; } } - if (hasLabel) - continue; + if (hasLabel) continue; } const previewLimit = app?.previewLimit || 0; From 429c1e4cd8e292df3b0ebd6579b0c4ff140d83e5 Mon Sep 17 00:00:00 2001 From: PiquelChips <63727792+PiquelChips@users.noreply.github.com> Date: Mon, 11 Aug 2025 14:03:30 +0200 Subject: [PATCH 06/49] feat: better UI for submitting labels --- .../show-preview-settings.tsx | 111 +- .../dokploy/drizzle/0104_yummy_silver_fox.sql | 1 - apps/dokploy/drizzle/0106_purple_maggott.sql | 1 + apps/dokploy/drizzle/meta/0106_snapshot.json | 6424 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + apps/dokploy/pages/api/deploy/github.ts | 5 +- packages/server/src/db/schema/application.ts | 2 +- 7 files changed, 6526 insertions(+), 25 deletions(-) delete mode 100644 apps/dokploy/drizzle/0104_yummy_silver_fox.sql create mode 100644 apps/dokploy/drizzle/0106_purple_maggott.sql create mode 100644 apps/dokploy/drizzle/meta/0106_snapshot.json diff --git a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx index 7e59482d4..0aa676057 100644 --- a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx +++ b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx @@ -1,4 +1,5 @@ import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; import { Dialog, DialogContent, @@ -27,9 +28,15 @@ import { SelectValue, } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { Settings2 } from "lucide-react"; +import { HelpCircle, Plus, Settings2, X } from "lucide-react"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; @@ -42,7 +49,7 @@ const schema = z wildcardDomain: z.string(), port: z.number(), previewLimit: z.number(), - previewLabels: z.string(), + previewLabels: z.array(z.string()).optional(), previewHttps: z.boolean(), previewPath: z.string(), previewCertificateType: z.enum(["letsencrypt", "none", "custom"]), @@ -82,7 +89,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { wildcardDomain: "*.traefik.me", port: 3000, previewLimit: 3, - previewLabels: "", + previewLabels: [], previewHttps: false, previewPath: "/", previewCertificateType: "none", @@ -104,7 +111,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { buildArgs: data.previewBuildArgs || "", wildcardDomain: data.previewWildcard || "*.traefik.me", port: data.previewPort || 3000, - previewLabels: data.previewLabels || "", + previewLabels: data.previewLabels || [], previewLimit: data.previewLimit || 3, previewHttps: data.previewHttps || false, previewPath: data.previewPath || "/", @@ -204,22 +211,86 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { )} /> - ( - - Labels - - - - - - )} - /> + ( + +
+ Preview Labels + + + + + + +

+ Add a labels that will trigger a preview deployment + for a pull request. If no labels are specified, all + pull requests will trigger a preview deployment. +

+
+
+
+
+
+ {field.value?.map((label, index) => ( + + {label} + { + const newLabels = [...(field.value || [])]; + newLabels.splice(index, 1); + field.onChange(newLabels); + }} + /> + + ))} +
+
+ + { + if (e.key === "Enter") { + e.preventDefault(); + const input = e.currentTarget; + const label = input.value.trim(); + if (label) { + field.onChange([...(field.value || []), label]); + input.value = ""; + } + } + }} + /> + + +
+ +
+ )} + /> 0) { let hasLabel: boolean = false; const labels = githubBody?.pull_request?.labels; for (const label of labels) { - if (previewLabels.contains(label.name)) { + if (app?.previewLabels.contains(label.name)) { hasLabel = true; break; } diff --git a/packages/server/src/db/schema/application.ts b/packages/server/src/db/schema/application.ts index 7263b895f..21ee9fbda 100644 --- a/packages/server/src/db/schema/application.ts +++ b/packages/server/src/db/schema/application.ts @@ -79,7 +79,7 @@ export const applications = pgTable("application", { previewEnv: text("previewEnv"), watchPaths: text("watchPaths").array(), previewBuildArgs: text("previewBuildArgs"), - previewLabels: text("previewLabels"), + previewLabels: text("previewLabels").array(), previewWildcard: text("previewWildcard"), previewPort: integer("previewPort").default(3000), previewHttps: boolean("previewHttps").notNull().default(false), From 15e62961e8f5c595f9d53d530822c340abf54653 Mon Sep 17 00:00:00 2001 From: PiquelChips <63727792+PiquelChips@users.noreply.github.com> Date: Mon, 11 Aug 2025 14:09:02 +0200 Subject: [PATCH 07/49] fix: would only create previews if none of the labels were present --- apps/dokploy/pages/api/deploy/github.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/pages/api/deploy/github.ts b/apps/dokploy/pages/api/deploy/github.ts index bdb0c7fe2..7e3df5444 100644 --- a/apps/dokploy/pages/api/deploy/github.ts +++ b/apps/dokploy/pages/api/deploy/github.ts @@ -452,7 +452,7 @@ export default async function handler( break; } } - if (hasLabel) continue; + if (!hasLabel) continue; } const previewLimit = app?.previewLimit || 0; From 3864c50deb3f4592b3440726c4b5c93eccf4c7fb Mon Sep 17 00:00:00 2001 From: Vyacheslav Scherbinin Date: Wed, 13 Aug 2025 08:23:30 +0700 Subject: [PATCH 08/49] bump: Traefik v3.5.0 --- apps/dokploy/setup.ts | 51 +- packages/server/src/setup/traefik-setup.ts | 696 ++++++++++----------- 2 files changed, 362 insertions(+), 385 deletions(-) diff --git a/apps/dokploy/setup.ts b/apps/dokploy/setup.ts index 7abf9fa2d..22dea48d3 100644 --- a/apps/dokploy/setup.ts +++ b/apps/dokploy/setup.ts @@ -1,31 +1,28 @@ -import { execAsync } from "@dokploy/server"; -import { setupDirectories } from "@dokploy/server/setup/config-paths"; -import { initializePostgres } from "@dokploy/server/setup/postgres-setup"; -import { initializeRedis } from "@dokploy/server/setup/redis-setup"; +import { execAsync } from '@dokploy/server'; +import { setupDirectories } from '@dokploy/server/setup/config-paths'; +import { initializePostgres } from '@dokploy/server/setup/postgres-setup'; +import { initializeRedis } from '@dokploy/server/setup/redis-setup'; +import { initializeNetwork, initializeSwarm } from '@dokploy/server/setup/setup'; import { - initializeNetwork, - initializeSwarm, -} from "@dokploy/server/setup/setup"; -import { - createDefaultMiddlewares, - createDefaultServerTraefikConfig, - createDefaultTraefikConfig, - initializeStandaloneTraefik, -} from "@dokploy/server/setup/traefik-setup"; + createDefaultMiddlewares, + createDefaultServerTraefikConfig, + createDefaultTraefikConfig, + initializeStandaloneTraefik, +} from '@dokploy/server/setup/traefik-setup'; (async () => { - try { - setupDirectories(); - createDefaultMiddlewares(); - await initializeSwarm(); - await initializeNetwork(); - createDefaultTraefikConfig(); - createDefaultServerTraefikConfig(); - await execAsync("docker pull traefik:v3.1.2"); - await initializeStandaloneTraefik(); - await initializeRedis(); - await initializePostgres(); - } catch (e) { - console.error("Error in dokploy setup", e); - } + try { + setupDirectories(); + createDefaultMiddlewares(); + await initializeSwarm(); + await initializeNetwork(); + createDefaultTraefikConfig(); + createDefaultServerTraefikConfig(); + await execAsync('docker pull traefik:v3.5.0'); + await initializeStandaloneTraefik(); + await initializeRedis(); + await initializePostgres(); + } catch (e) { + console.error('Error in dokploy setup', e); + } })(); diff --git a/packages/server/src/setup/traefik-setup.ts b/packages/server/src/setup/traefik-setup.ts index ccdfa30f8..9022aeb12 100644 --- a/packages/server/src/setup/traefik-setup.ts +++ b/packages/server/src/setup/traefik-setup.ts @@ -1,402 +1,382 @@ -import { chmodSync, existsSync, mkdirSync, writeFileSync } from "node:fs"; -import path from "node:path"; -import type { ContainerCreateOptions, CreateServiceOptions } from "dockerode"; -import { dump } from "js-yaml"; -import { paths } from "../constants"; -import { getRemoteDocker } from "../utils/servers/remote-docker"; -import type { FileConfig } from "../utils/traefik/file-types"; -import type { MainTraefikConfig } from "../utils/traefik/types"; +import { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import type { ContainerCreateOptions, CreateServiceOptions } from 'dockerode'; +import { dump } from 'js-yaml'; +import { paths } from '../constants'; +import { getRemoteDocker } from '../utils/servers/remote-docker'; +import type { FileConfig } from '../utils/traefik/file-types'; +import type { MainTraefikConfig } from '../utils/traefik/types'; -export const TRAEFIK_SSL_PORT = - Number.parseInt(process.env.TRAEFIK_SSL_PORT!, 10) || 443; -export const TRAEFIK_PORT = - Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80; -export const TRAEFIK_HTTP3_PORT = - Number.parseInt(process.env.TRAEFIK_HTTP3_PORT!, 10) || 443; -export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || "3.1.2"; +export const TRAEFIK_SSL_PORT = Number.parseInt(process.env.TRAEFIK_SSL_PORT!, 10) || 443; +export const TRAEFIK_PORT = Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80; +export const TRAEFIK_HTTP3_PORT = Number.parseInt(process.env.TRAEFIK_HTTP3_PORT!, 10) || 443; +export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || '3.5.0'; export interface TraefikOptions { - env?: string[]; - serverId?: string; - additionalPorts?: { - targetPort: number; - publishedPort: number; - protocol?: string; - }[]; + env?: string[]; + serverId?: string; + additionalPorts?: { + targetPort: number; + publishedPort: number; + protocol?: string; + }[]; } -export const initializeStandaloneTraefik = async ({ - env, - serverId, - additionalPorts = [], -}: TraefikOptions = {}) => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); - const imageName = `traefik:v${TRAEFIK_VERSION}`; - const containerName = "dokploy-traefik"; +export const initializeStandaloneTraefik = async ({ env, serverId, additionalPorts = [] }: TraefikOptions = {}) => { + const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); + const imageName = `traefik:v${TRAEFIK_VERSION}`; + const containerName = 'dokploy-traefik'; - const exposedPorts: Record = { - [`${TRAEFIK_PORT}/tcp`]: {}, - [`${TRAEFIK_SSL_PORT}/tcp`]: {}, - [`${TRAEFIK_HTTP3_PORT}/udp`]: {}, - }; + const exposedPorts: Record = { + [`${TRAEFIK_PORT}/tcp`]: {}, + [`${TRAEFIK_SSL_PORT}/tcp`]: {}, + [`${TRAEFIK_HTTP3_PORT}/udp`]: {}, + }; - const portBindings: Record> = { - [`${TRAEFIK_PORT}/tcp`]: [{ HostPort: TRAEFIK_PORT.toString() }], - [`${TRAEFIK_SSL_PORT}/tcp`]: [{ HostPort: TRAEFIK_SSL_PORT.toString() }], - [`${TRAEFIK_HTTP3_PORT}/udp`]: [ - { HostPort: TRAEFIK_HTTP3_PORT.toString() }, - ], - }; + const portBindings: Record> = { + [`${TRAEFIK_PORT}/tcp`]: [{ HostPort: TRAEFIK_PORT.toString() }], + [`${TRAEFIK_SSL_PORT}/tcp`]: [{ HostPort: TRAEFIK_SSL_PORT.toString() }], + [`${TRAEFIK_HTTP3_PORT}/udp`]: [{ HostPort: TRAEFIK_HTTP3_PORT.toString() }], + }; - const enableDashboard = additionalPorts.some( - (port) => port.targetPort === 8080, - ); + const enableDashboard = additionalPorts.some((port) => port.targetPort === 8080); - if (enableDashboard) { - exposedPorts["8080/tcp"] = {}; - portBindings["8080/tcp"] = [{ HostPort: "8080" }]; - } + if (enableDashboard) { + exposedPorts['8080/tcp'] = {}; + portBindings['8080/tcp'] = [{ HostPort: '8080' }]; + } - for (const port of additionalPorts) { - const portKey = `${port.targetPort}/${port.protocol ?? "tcp"}`; - exposedPorts[portKey] = {}; - portBindings[portKey] = [{ HostPort: port.publishedPort.toString() }]; - } + for (const port of additionalPorts) { + const portKey = `${port.targetPort}/${port.protocol ?? 'tcp'}`; + exposedPorts[portKey] = {}; + portBindings[portKey] = [{ HostPort: port.publishedPort.toString() }]; + } - const settings: ContainerCreateOptions = { - name: containerName, - Image: imageName, - NetworkingConfig: { - EndpointsConfig: { - "dokploy-network": {}, - }, - }, - ExposedPorts: exposedPorts, - HostConfig: { - RestartPolicy: { - Name: "always", - }, - Binds: [ - `${MAIN_TRAEFIK_PATH}/traefik.yml:/etc/traefik/traefik.yml`, - `${DYNAMIC_TRAEFIK_PATH}:/etc/dokploy/traefik/dynamic`, - "/var/run/docker.sock:/var/run/docker.sock", - ], - PortBindings: portBindings, - }, - Env: env, - }; + const settings: ContainerCreateOptions = { + name: containerName, + Image: imageName, + NetworkingConfig: { + EndpointsConfig: { + 'dokploy-network': {}, + }, + }, + ExposedPorts: exposedPorts, + HostConfig: { + RestartPolicy: { + Name: 'always', + }, + Binds: [ + `${MAIN_TRAEFIK_PATH}/traefik.yml:/etc/traefik/traefik.yml`, + `${DYNAMIC_TRAEFIK_PATH}:/etc/dokploy/traefik/dynamic`, + '/var/run/docker.sock:/var/run/docker.sock', + ], + PortBindings: portBindings, + }, + Env: env, + }; - const docker = await getRemoteDocker(serverId); - try { - const container = docker.getContainer(containerName); - await container.remove({ force: true }); - await new Promise((resolve) => setTimeout(resolve, 5000)); - } catch {} + const docker = await getRemoteDocker(serverId); + try { + const container = docker.getContainer(containerName); + await container.remove({ force: true }); + await new Promise((resolve) => setTimeout(resolve, 5000)); + } catch {} - await docker.createContainer(settings); - const newContainer = docker.getContainer(containerName); - await newContainer.start(); - console.log("Traefik Started ✅"); + await docker.createContainer(settings); + const newContainer = docker.getContainer(containerName); + await newContainer.start(); + console.log('Traefik Started ✅'); }; -export const initializeTraefikService = async ({ - env, - additionalPorts = [], - serverId, -}: TraefikOptions) => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); - const imageName = `traefik:v${TRAEFIK_VERSION}`; - const appName = "dokploy-traefik"; +export const initializeTraefikService = async ({ env, additionalPorts = [], serverId }: TraefikOptions) => { + const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); + const imageName = `traefik:v${TRAEFIK_VERSION}`; + const appName = 'dokploy-traefik'; - const settings: CreateServiceOptions = { - Name: appName, - TaskTemplate: { - ContainerSpec: { - Image: imageName, - Env: env, - Mounts: [ - { - Type: "bind", - Source: `${MAIN_TRAEFIK_PATH}/traefik.yml`, - Target: "/etc/traefik/traefik.yml", - }, - { - Type: "bind", - Source: DYNAMIC_TRAEFIK_PATH, - Target: "/etc/dokploy/traefik/dynamic", - }, - { - Type: "bind", - Source: "/var/run/docker.sock", - Target: "/var/run/docker.sock", - }, - ], - }, - Networks: [{ Target: "dokploy-network" }], - Placement: { - Constraints: ["node.role==manager"], - }, - }, - Mode: { - Replicated: { - Replicas: 1, - }, - }, - EndpointSpec: { - Ports: [ - { - TargetPort: 443, - PublishedPort: TRAEFIK_SSL_PORT, - PublishMode: "host", - Protocol: "tcp", - }, - { - TargetPort: 443, - PublishedPort: TRAEFIK_SSL_PORT, - PublishMode: "host", - Protocol: "udp", - }, - { - TargetPort: 80, - PublishedPort: TRAEFIK_PORT, - PublishMode: "host", - Protocol: "tcp", - }, + const settings: CreateServiceOptions = { + Name: appName, + TaskTemplate: { + ContainerSpec: { + Image: imageName, + Env: env, + Mounts: [ + { + Type: 'bind', + Source: `${MAIN_TRAEFIK_PATH}/traefik.yml`, + Target: '/etc/traefik/traefik.yml', + }, + { + Type: 'bind', + Source: DYNAMIC_TRAEFIK_PATH, + Target: '/etc/dokploy/traefik/dynamic', + }, + { + Type: 'bind', + Source: '/var/run/docker.sock', + Target: '/var/run/docker.sock', + }, + ], + }, + Networks: [{ Target: 'dokploy-network' }], + Placement: { + Constraints: ['node.role==manager'], + }, + }, + Mode: { + Replicated: { + Replicas: 1, + }, + }, + EndpointSpec: { + Ports: [ + { + TargetPort: 443, + PublishedPort: TRAEFIK_SSL_PORT, + PublishMode: 'host', + Protocol: 'tcp', + }, + { + TargetPort: 443, + PublishedPort: TRAEFIK_SSL_PORT, + PublishMode: 'host', + Protocol: 'udp', + }, + { + TargetPort: 80, + PublishedPort: TRAEFIK_PORT, + PublishMode: 'host', + Protocol: 'tcp', + }, - ...additionalPorts.map((port) => ({ - TargetPort: port.targetPort, - PublishedPort: port.publishedPort, - Protocol: port.protocol as "tcp" | "udp" | "sctp" | undefined, - PublishMode: "host" as const, - })), - ], - }, - }; - const docker = await getRemoteDocker(serverId); - try { - const service = docker.getService(appName); - const inspect = await service.inspect(); + ...additionalPorts.map((port) => ({ + TargetPort: port.targetPort, + PublishedPort: port.publishedPort, + Protocol: port.protocol as 'tcp' | 'udp' | 'sctp' | undefined, + PublishMode: 'host' as const, + })), + ], + }, + }; + const docker = await getRemoteDocker(serverId); + try { + const service = docker.getService(appName); + const inspect = await service.inspect(); - await service.update({ - version: Number.parseInt(inspect.Version.Index), - ...settings, - TaskTemplate: { - ...settings.TaskTemplate, - ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1, - }, - }); - console.log("Traefik Updated ✅"); - } catch { - await docker.createService(settings); - console.log("Traefik Started ✅"); - } + await service.update({ + version: Number.parseInt(inspect.Version.Index), + ...settings, + TaskTemplate: { + ...settings.TaskTemplate, + ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1, + }, + }); + console.log('Traefik Updated ✅'); + } catch { + await docker.createService(settings); + console.log('Traefik Started ✅'); + } }; export const createDefaultServerTraefikConfig = () => { - const { DYNAMIC_TRAEFIK_PATH } = paths(); - const configFilePath = path.join(DYNAMIC_TRAEFIK_PATH, "dokploy.yml"); + const { DYNAMIC_TRAEFIK_PATH } = paths(); + const configFilePath = path.join(DYNAMIC_TRAEFIK_PATH, 'dokploy.yml'); - if (existsSync(configFilePath)) { - console.log("Default traefik config already exists"); - return; - } + if (existsSync(configFilePath)) { + console.log('Default traefik config already exists'); + return; + } - const appName = "dokploy"; - const serviceURLDefault = `http://${appName}:${process.env.PORT || 3000}`; - const config: FileConfig = { - http: { - routers: { - [`${appName}-router-app`]: { - rule: `Host(\`${appName}.docker.localhost\`) && PathPrefix(\`/\`)`, - service: `${appName}-service-app`, - entryPoints: ["web"], - }, - }, - services: { - [`${appName}-service-app`]: { - loadBalancer: { - servers: [{ url: serviceURLDefault }], - passHostHeader: true, - }, - }, - }, - }, - }; + const appName = 'dokploy'; + const serviceURLDefault = `http://${appName}:${process.env.PORT || 3000}`; + const config: FileConfig = { + http: { + routers: { + [`${appName}-router-app`]: { + rule: `Host(\`${appName}.docker.localhost\`) && PathPrefix(\`/\`)`, + service: `${appName}-service-app`, + entryPoints: ['web'], + }, + }, + services: { + [`${appName}-service-app`]: { + loadBalancer: { + servers: [{ url: serviceURLDefault }], + passHostHeader: true, + }, + }, + }, + }, + }; - const yamlStr = dump(config); - mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); - writeFileSync( - path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`), - yamlStr, - "utf8", - ); + const yamlStr = dump(config); + mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); + writeFileSync(path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`), yamlStr, 'utf8'); }; export const getDefaultTraefikConfig = () => { - const configObject: MainTraefikConfig = { - global: { - sendAnonymousUsage: false, - }, - providers: { - ...(process.env.NODE_ENV === "development" - ? { - docker: { - defaultRule: - "Host(`{{ trimPrefix `/` .Name }}.docker.localhost`)", - }, - } - : { - swarm: { - exposedByDefault: false, - watch: true, - }, - docker: { - exposedByDefault: false, - watch: true, - network: "dokploy-network", - }, - }), - file: { - directory: "/etc/dokploy/traefik/dynamic", - watch: true, - }, - }, - entryPoints: { - web: { - address: `:${TRAEFIK_PORT}`, - }, - websecure: { - address: `:${TRAEFIK_SSL_PORT}`, - http3: { - advertisedPort: TRAEFIK_HTTP3_PORT, - }, - ...(process.env.NODE_ENV === "production" && { - http: { - tls: { - certResolver: "letsencrypt", - }, - }, - }), - }, - }, - api: { - insecure: true, - }, - ...(process.env.NODE_ENV === "production" && { - certificatesResolvers: { - letsencrypt: { - acme: { - email: "test@localhost.com", - storage: "/etc/dokploy/traefik/dynamic/acme.json", - httpChallenge: { - entryPoint: "web", - }, - }, - }, - }, - }), - }; + const configObject: MainTraefikConfig = { + global: { + sendAnonymousUsage: false, + }, + providers: { + ...(process.env.NODE_ENV === 'development' + ? { + docker: { + defaultRule: 'Host(`{{ trimPrefix `/` .Name }}.docker.localhost`)', + }, + } + : { + swarm: { + exposedByDefault: false, + watch: true, + }, + docker: { + exposedByDefault: false, + watch: true, + network: 'dokploy-network', + }, + }), + file: { + directory: '/etc/dokploy/traefik/dynamic', + watch: true, + }, + }, + entryPoints: { + web: { + address: `:${TRAEFIK_PORT}`, + }, + websecure: { + address: `:${TRAEFIK_SSL_PORT}`, + http3: { + advertisedPort: TRAEFIK_HTTP3_PORT, + }, + ...(process.env.NODE_ENV === 'production' && { + http: { + tls: { + certResolver: 'letsencrypt', + }, + }, + }), + }, + }, + api: { + insecure: true, + }, + ...(process.env.NODE_ENV === 'production' && { + certificatesResolvers: { + letsencrypt: { + acme: { + email: 'test@localhost.com', + storage: '/etc/dokploy/traefik/dynamic/acme.json', + httpChallenge: { + entryPoint: 'web', + }, + }, + }, + }, + }), + }; - const yamlStr = dump(configObject); + const yamlStr = dump(configObject); - return yamlStr; + return yamlStr; }; export const getDefaultServerTraefikConfig = () => { - const configObject: MainTraefikConfig = { - providers: { - swarm: { - exposedByDefault: false, - watch: true, - }, - docker: { - exposedByDefault: false, - watch: true, - network: "dokploy-network", - }, - file: { - directory: "/etc/dokploy/traefik/dynamic", - watch: true, - }, - }, - entryPoints: { - web: { - address: `:${TRAEFIK_PORT}`, - }, - websecure: { - address: `:${TRAEFIK_SSL_PORT}`, - http3: { - advertisedPort: TRAEFIK_HTTP3_PORT, - }, - http: { - tls: { - certResolver: "letsencrypt", - }, - }, - }, - }, - api: { - insecure: true, - }, - certificatesResolvers: { - letsencrypt: { - acme: { - email: "test@localhost.com", - storage: "/etc/dokploy/traefik/dynamic/acme.json", - httpChallenge: { - entryPoint: "web", - }, - }, - }, - }, - }; + const configObject: MainTraefikConfig = { + providers: { + swarm: { + exposedByDefault: false, + watch: true, + }, + docker: { + exposedByDefault: false, + watch: true, + network: 'dokploy-network', + }, + file: { + directory: '/etc/dokploy/traefik/dynamic', + watch: true, + }, + }, + entryPoints: { + web: { + address: `:${TRAEFIK_PORT}`, + }, + websecure: { + address: `:${TRAEFIK_SSL_PORT}`, + http3: { + advertisedPort: TRAEFIK_HTTP3_PORT, + }, + http: { + tls: { + certResolver: 'letsencrypt', + }, + }, + }, + }, + api: { + insecure: true, + }, + certificatesResolvers: { + letsencrypt: { + acme: { + email: 'test@localhost.com', + storage: '/etc/dokploy/traefik/dynamic/acme.json', + httpChallenge: { + entryPoint: 'web', + }, + }, + }, + }, + }; - const yamlStr = dump(configObject); + const yamlStr = dump(configObject); - return yamlStr; + return yamlStr; }; export const createDefaultTraefikConfig = () => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(); - const mainConfig = path.join(MAIN_TRAEFIK_PATH, "traefik.yml"); - const acmeJsonPath = path.join(DYNAMIC_TRAEFIK_PATH, "acme.json"); + const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(); + const mainConfig = path.join(MAIN_TRAEFIK_PATH, 'traefik.yml'); + const acmeJsonPath = path.join(DYNAMIC_TRAEFIK_PATH, 'acme.json'); - if (existsSync(acmeJsonPath)) { - chmodSync(acmeJsonPath, "600"); - } - if (existsSync(mainConfig)) { - console.log("Main config already exists"); - return; - } - const yamlStr = getDefaultTraefikConfig(); - mkdirSync(MAIN_TRAEFIK_PATH, { recursive: true }); - writeFileSync(mainConfig, yamlStr, "utf8"); + if (existsSync(acmeJsonPath)) { + chmodSync(acmeJsonPath, '600'); + } + if (existsSync(mainConfig)) { + console.log('Main config already exists'); + return; + } + const yamlStr = getDefaultTraefikConfig(); + mkdirSync(MAIN_TRAEFIK_PATH, { recursive: true }); + writeFileSync(mainConfig, yamlStr, 'utf8'); }; export const getDefaultMiddlewares = () => { - const defaultMiddlewares = { - http: { - middlewares: { - "redirect-to-https": { - redirectScheme: { - scheme: "https", - permanent: true, - }, - }, - }, - }, - }; - const yamlStr = dump(defaultMiddlewares); - return yamlStr; + const defaultMiddlewares = { + http: { + middlewares: { + 'redirect-to-https': { + redirectScheme: { + scheme: 'https', + permanent: true, + }, + }, + }, + }, + }; + const yamlStr = dump(defaultMiddlewares); + return yamlStr; }; export const createDefaultMiddlewares = () => { - const { DYNAMIC_TRAEFIK_PATH } = paths(); - const middlewaresPath = path.join(DYNAMIC_TRAEFIK_PATH, "middlewares.yml"); - if (existsSync(middlewaresPath)) { - console.log("Default middlewares already exists"); - return; - } - const yamlStr = getDefaultMiddlewares(); - mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); - writeFileSync(middlewaresPath, yamlStr, "utf8"); + const { DYNAMIC_TRAEFIK_PATH } = paths(); + const middlewaresPath = path.join(DYNAMIC_TRAEFIK_PATH, 'middlewares.yml'); + if (existsSync(middlewaresPath)) { + console.log('Default middlewares already exists'); + return; + } + const yamlStr = getDefaultMiddlewares(); + mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); + writeFileSync(middlewaresPath, yamlStr, 'utf8'); }; From 2c591cbd03510d24c3f5c9f072bd9a2747b12b49 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 13 Aug 2025 01:25:30 +0000 Subject: [PATCH 09/49] [autofix.ci] apply automated fixes --- apps/dokploy/setup.ts | 51 +- packages/server/src/setup/traefik-setup.ts | 696 +++++++++++---------- 2 files changed, 385 insertions(+), 362 deletions(-) diff --git a/apps/dokploy/setup.ts b/apps/dokploy/setup.ts index 22dea48d3..13590e4e7 100644 --- a/apps/dokploy/setup.ts +++ b/apps/dokploy/setup.ts @@ -1,28 +1,31 @@ -import { execAsync } from '@dokploy/server'; -import { setupDirectories } from '@dokploy/server/setup/config-paths'; -import { initializePostgres } from '@dokploy/server/setup/postgres-setup'; -import { initializeRedis } from '@dokploy/server/setup/redis-setup'; -import { initializeNetwork, initializeSwarm } from '@dokploy/server/setup/setup'; +import { execAsync } from "@dokploy/server"; +import { setupDirectories } from "@dokploy/server/setup/config-paths"; +import { initializePostgres } from "@dokploy/server/setup/postgres-setup"; +import { initializeRedis } from "@dokploy/server/setup/redis-setup"; import { - createDefaultMiddlewares, - createDefaultServerTraefikConfig, - createDefaultTraefikConfig, - initializeStandaloneTraefik, -} from '@dokploy/server/setup/traefik-setup'; + initializeNetwork, + initializeSwarm, +} from "@dokploy/server/setup/setup"; +import { + createDefaultMiddlewares, + createDefaultServerTraefikConfig, + createDefaultTraefikConfig, + initializeStandaloneTraefik, +} from "@dokploy/server/setup/traefik-setup"; (async () => { - try { - setupDirectories(); - createDefaultMiddlewares(); - await initializeSwarm(); - await initializeNetwork(); - createDefaultTraefikConfig(); - createDefaultServerTraefikConfig(); - await execAsync('docker pull traefik:v3.5.0'); - await initializeStandaloneTraefik(); - await initializeRedis(); - await initializePostgres(); - } catch (e) { - console.error('Error in dokploy setup', e); - } + try { + setupDirectories(); + createDefaultMiddlewares(); + await initializeSwarm(); + await initializeNetwork(); + createDefaultTraefikConfig(); + createDefaultServerTraefikConfig(); + await execAsync("docker pull traefik:v3.5.0"); + await initializeStandaloneTraefik(); + await initializeRedis(); + await initializePostgres(); + } catch (e) { + console.error("Error in dokploy setup", e); + } })(); diff --git a/packages/server/src/setup/traefik-setup.ts b/packages/server/src/setup/traefik-setup.ts index 9022aeb12..17c48d0ff 100644 --- a/packages/server/src/setup/traefik-setup.ts +++ b/packages/server/src/setup/traefik-setup.ts @@ -1,382 +1,402 @@ -import { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs'; -import path from 'node:path'; -import type { ContainerCreateOptions, CreateServiceOptions } from 'dockerode'; -import { dump } from 'js-yaml'; -import { paths } from '../constants'; -import { getRemoteDocker } from '../utils/servers/remote-docker'; -import type { FileConfig } from '../utils/traefik/file-types'; -import type { MainTraefikConfig } from '../utils/traefik/types'; +import { chmodSync, existsSync, mkdirSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import type { ContainerCreateOptions, CreateServiceOptions } from "dockerode"; +import { dump } from "js-yaml"; +import { paths } from "../constants"; +import { getRemoteDocker } from "../utils/servers/remote-docker"; +import type { FileConfig } from "../utils/traefik/file-types"; +import type { MainTraefikConfig } from "../utils/traefik/types"; -export const TRAEFIK_SSL_PORT = Number.parseInt(process.env.TRAEFIK_SSL_PORT!, 10) || 443; -export const TRAEFIK_PORT = Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80; -export const TRAEFIK_HTTP3_PORT = Number.parseInt(process.env.TRAEFIK_HTTP3_PORT!, 10) || 443; -export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || '3.5.0'; +export const TRAEFIK_SSL_PORT = + Number.parseInt(process.env.TRAEFIK_SSL_PORT!, 10) || 443; +export const TRAEFIK_PORT = + Number.parseInt(process.env.TRAEFIK_PORT!, 10) || 80; +export const TRAEFIK_HTTP3_PORT = + Number.parseInt(process.env.TRAEFIK_HTTP3_PORT!, 10) || 443; +export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || "3.5.0"; export interface TraefikOptions { - env?: string[]; - serverId?: string; - additionalPorts?: { - targetPort: number; - publishedPort: number; - protocol?: string; - }[]; + env?: string[]; + serverId?: string; + additionalPorts?: { + targetPort: number; + publishedPort: number; + protocol?: string; + }[]; } -export const initializeStandaloneTraefik = async ({ env, serverId, additionalPorts = [] }: TraefikOptions = {}) => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); - const imageName = `traefik:v${TRAEFIK_VERSION}`; - const containerName = 'dokploy-traefik'; +export const initializeStandaloneTraefik = async ({ + env, + serverId, + additionalPorts = [], +}: TraefikOptions = {}) => { + const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); + const imageName = `traefik:v${TRAEFIK_VERSION}`; + const containerName = "dokploy-traefik"; - const exposedPorts: Record = { - [`${TRAEFIK_PORT}/tcp`]: {}, - [`${TRAEFIK_SSL_PORT}/tcp`]: {}, - [`${TRAEFIK_HTTP3_PORT}/udp`]: {}, - }; + const exposedPorts: Record = { + [`${TRAEFIK_PORT}/tcp`]: {}, + [`${TRAEFIK_SSL_PORT}/tcp`]: {}, + [`${TRAEFIK_HTTP3_PORT}/udp`]: {}, + }; - const portBindings: Record> = { - [`${TRAEFIK_PORT}/tcp`]: [{ HostPort: TRAEFIK_PORT.toString() }], - [`${TRAEFIK_SSL_PORT}/tcp`]: [{ HostPort: TRAEFIK_SSL_PORT.toString() }], - [`${TRAEFIK_HTTP3_PORT}/udp`]: [{ HostPort: TRAEFIK_HTTP3_PORT.toString() }], - }; + const portBindings: Record> = { + [`${TRAEFIK_PORT}/tcp`]: [{ HostPort: TRAEFIK_PORT.toString() }], + [`${TRAEFIK_SSL_PORT}/tcp`]: [{ HostPort: TRAEFIK_SSL_PORT.toString() }], + [`${TRAEFIK_HTTP3_PORT}/udp`]: [ + { HostPort: TRAEFIK_HTTP3_PORT.toString() }, + ], + }; - const enableDashboard = additionalPorts.some((port) => port.targetPort === 8080); + const enableDashboard = additionalPorts.some( + (port) => port.targetPort === 8080, + ); - if (enableDashboard) { - exposedPorts['8080/tcp'] = {}; - portBindings['8080/tcp'] = [{ HostPort: '8080' }]; - } + if (enableDashboard) { + exposedPorts["8080/tcp"] = {}; + portBindings["8080/tcp"] = [{ HostPort: "8080" }]; + } - for (const port of additionalPorts) { - const portKey = `${port.targetPort}/${port.protocol ?? 'tcp'}`; - exposedPorts[portKey] = {}; - portBindings[portKey] = [{ HostPort: port.publishedPort.toString() }]; - } + for (const port of additionalPorts) { + const portKey = `${port.targetPort}/${port.protocol ?? "tcp"}`; + exposedPorts[portKey] = {}; + portBindings[portKey] = [{ HostPort: port.publishedPort.toString() }]; + } - const settings: ContainerCreateOptions = { - name: containerName, - Image: imageName, - NetworkingConfig: { - EndpointsConfig: { - 'dokploy-network': {}, - }, - }, - ExposedPorts: exposedPorts, - HostConfig: { - RestartPolicy: { - Name: 'always', - }, - Binds: [ - `${MAIN_TRAEFIK_PATH}/traefik.yml:/etc/traefik/traefik.yml`, - `${DYNAMIC_TRAEFIK_PATH}:/etc/dokploy/traefik/dynamic`, - '/var/run/docker.sock:/var/run/docker.sock', - ], - PortBindings: portBindings, - }, - Env: env, - }; + const settings: ContainerCreateOptions = { + name: containerName, + Image: imageName, + NetworkingConfig: { + EndpointsConfig: { + "dokploy-network": {}, + }, + }, + ExposedPorts: exposedPorts, + HostConfig: { + RestartPolicy: { + Name: "always", + }, + Binds: [ + `${MAIN_TRAEFIK_PATH}/traefik.yml:/etc/traefik/traefik.yml`, + `${DYNAMIC_TRAEFIK_PATH}:/etc/dokploy/traefik/dynamic`, + "/var/run/docker.sock:/var/run/docker.sock", + ], + PortBindings: portBindings, + }, + Env: env, + }; - const docker = await getRemoteDocker(serverId); - try { - const container = docker.getContainer(containerName); - await container.remove({ force: true }); - await new Promise((resolve) => setTimeout(resolve, 5000)); - } catch {} + const docker = await getRemoteDocker(serverId); + try { + const container = docker.getContainer(containerName); + await container.remove({ force: true }); + await new Promise((resolve) => setTimeout(resolve, 5000)); + } catch {} - await docker.createContainer(settings); - const newContainer = docker.getContainer(containerName); - await newContainer.start(); - console.log('Traefik Started ✅'); + await docker.createContainer(settings); + const newContainer = docker.getContainer(containerName); + await newContainer.start(); + console.log("Traefik Started ✅"); }; -export const initializeTraefikService = async ({ env, additionalPorts = [], serverId }: TraefikOptions) => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); - const imageName = `traefik:v${TRAEFIK_VERSION}`; - const appName = 'dokploy-traefik'; +export const initializeTraefikService = async ({ + env, + additionalPorts = [], + serverId, +}: TraefikOptions) => { + const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); + const imageName = `traefik:v${TRAEFIK_VERSION}`; + const appName = "dokploy-traefik"; - const settings: CreateServiceOptions = { - Name: appName, - TaskTemplate: { - ContainerSpec: { - Image: imageName, - Env: env, - Mounts: [ - { - Type: 'bind', - Source: `${MAIN_TRAEFIK_PATH}/traefik.yml`, - Target: '/etc/traefik/traefik.yml', - }, - { - Type: 'bind', - Source: DYNAMIC_TRAEFIK_PATH, - Target: '/etc/dokploy/traefik/dynamic', - }, - { - Type: 'bind', - Source: '/var/run/docker.sock', - Target: '/var/run/docker.sock', - }, - ], - }, - Networks: [{ Target: 'dokploy-network' }], - Placement: { - Constraints: ['node.role==manager'], - }, - }, - Mode: { - Replicated: { - Replicas: 1, - }, - }, - EndpointSpec: { - Ports: [ - { - TargetPort: 443, - PublishedPort: TRAEFIK_SSL_PORT, - PublishMode: 'host', - Protocol: 'tcp', - }, - { - TargetPort: 443, - PublishedPort: TRAEFIK_SSL_PORT, - PublishMode: 'host', - Protocol: 'udp', - }, - { - TargetPort: 80, - PublishedPort: TRAEFIK_PORT, - PublishMode: 'host', - Protocol: 'tcp', - }, + const settings: CreateServiceOptions = { + Name: appName, + TaskTemplate: { + ContainerSpec: { + Image: imageName, + Env: env, + Mounts: [ + { + Type: "bind", + Source: `${MAIN_TRAEFIK_PATH}/traefik.yml`, + Target: "/etc/traefik/traefik.yml", + }, + { + Type: "bind", + Source: DYNAMIC_TRAEFIK_PATH, + Target: "/etc/dokploy/traefik/dynamic", + }, + { + Type: "bind", + Source: "/var/run/docker.sock", + Target: "/var/run/docker.sock", + }, + ], + }, + Networks: [{ Target: "dokploy-network" }], + Placement: { + Constraints: ["node.role==manager"], + }, + }, + Mode: { + Replicated: { + Replicas: 1, + }, + }, + EndpointSpec: { + Ports: [ + { + TargetPort: 443, + PublishedPort: TRAEFIK_SSL_PORT, + PublishMode: "host", + Protocol: "tcp", + }, + { + TargetPort: 443, + PublishedPort: TRAEFIK_SSL_PORT, + PublishMode: "host", + Protocol: "udp", + }, + { + TargetPort: 80, + PublishedPort: TRAEFIK_PORT, + PublishMode: "host", + Protocol: "tcp", + }, - ...additionalPorts.map((port) => ({ - TargetPort: port.targetPort, - PublishedPort: port.publishedPort, - Protocol: port.protocol as 'tcp' | 'udp' | 'sctp' | undefined, - PublishMode: 'host' as const, - })), - ], - }, - }; - const docker = await getRemoteDocker(serverId); - try { - const service = docker.getService(appName); - const inspect = await service.inspect(); + ...additionalPorts.map((port) => ({ + TargetPort: port.targetPort, + PublishedPort: port.publishedPort, + Protocol: port.protocol as "tcp" | "udp" | "sctp" | undefined, + PublishMode: "host" as const, + })), + ], + }, + }; + const docker = await getRemoteDocker(serverId); + try { + const service = docker.getService(appName); + const inspect = await service.inspect(); - await service.update({ - version: Number.parseInt(inspect.Version.Index), - ...settings, - TaskTemplate: { - ...settings.TaskTemplate, - ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1, - }, - }); - console.log('Traefik Updated ✅'); - } catch { - await docker.createService(settings); - console.log('Traefik Started ✅'); - } + await service.update({ + version: Number.parseInt(inspect.Version.Index), + ...settings, + TaskTemplate: { + ...settings.TaskTemplate, + ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1, + }, + }); + console.log("Traefik Updated ✅"); + } catch { + await docker.createService(settings); + console.log("Traefik Started ✅"); + } }; export const createDefaultServerTraefikConfig = () => { - const { DYNAMIC_TRAEFIK_PATH } = paths(); - const configFilePath = path.join(DYNAMIC_TRAEFIK_PATH, 'dokploy.yml'); + const { DYNAMIC_TRAEFIK_PATH } = paths(); + const configFilePath = path.join(DYNAMIC_TRAEFIK_PATH, "dokploy.yml"); - if (existsSync(configFilePath)) { - console.log('Default traefik config already exists'); - return; - } + if (existsSync(configFilePath)) { + console.log("Default traefik config already exists"); + return; + } - const appName = 'dokploy'; - const serviceURLDefault = `http://${appName}:${process.env.PORT || 3000}`; - const config: FileConfig = { - http: { - routers: { - [`${appName}-router-app`]: { - rule: `Host(\`${appName}.docker.localhost\`) && PathPrefix(\`/\`)`, - service: `${appName}-service-app`, - entryPoints: ['web'], - }, - }, - services: { - [`${appName}-service-app`]: { - loadBalancer: { - servers: [{ url: serviceURLDefault }], - passHostHeader: true, - }, - }, - }, - }, - }; + const appName = "dokploy"; + const serviceURLDefault = `http://${appName}:${process.env.PORT || 3000}`; + const config: FileConfig = { + http: { + routers: { + [`${appName}-router-app`]: { + rule: `Host(\`${appName}.docker.localhost\`) && PathPrefix(\`/\`)`, + service: `${appName}-service-app`, + entryPoints: ["web"], + }, + }, + services: { + [`${appName}-service-app`]: { + loadBalancer: { + servers: [{ url: serviceURLDefault }], + passHostHeader: true, + }, + }, + }, + }, + }; - const yamlStr = dump(config); - mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); - writeFileSync(path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`), yamlStr, 'utf8'); + const yamlStr = dump(config); + mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); + writeFileSync( + path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`), + yamlStr, + "utf8", + ); }; export const getDefaultTraefikConfig = () => { - const configObject: MainTraefikConfig = { - global: { - sendAnonymousUsage: false, - }, - providers: { - ...(process.env.NODE_ENV === 'development' - ? { - docker: { - defaultRule: 'Host(`{{ trimPrefix `/` .Name }}.docker.localhost`)', - }, - } - : { - swarm: { - exposedByDefault: false, - watch: true, - }, - docker: { - exposedByDefault: false, - watch: true, - network: 'dokploy-network', - }, - }), - file: { - directory: '/etc/dokploy/traefik/dynamic', - watch: true, - }, - }, - entryPoints: { - web: { - address: `:${TRAEFIK_PORT}`, - }, - websecure: { - address: `:${TRAEFIK_SSL_PORT}`, - http3: { - advertisedPort: TRAEFIK_HTTP3_PORT, - }, - ...(process.env.NODE_ENV === 'production' && { - http: { - tls: { - certResolver: 'letsencrypt', - }, - }, - }), - }, - }, - api: { - insecure: true, - }, - ...(process.env.NODE_ENV === 'production' && { - certificatesResolvers: { - letsencrypt: { - acme: { - email: 'test@localhost.com', - storage: '/etc/dokploy/traefik/dynamic/acme.json', - httpChallenge: { - entryPoint: 'web', - }, - }, - }, - }, - }), - }; + const configObject: MainTraefikConfig = { + global: { + sendAnonymousUsage: false, + }, + providers: { + ...(process.env.NODE_ENV === "development" + ? { + docker: { + defaultRule: + "Host(`{{ trimPrefix `/` .Name }}.docker.localhost`)", + }, + } + : { + swarm: { + exposedByDefault: false, + watch: true, + }, + docker: { + exposedByDefault: false, + watch: true, + network: "dokploy-network", + }, + }), + file: { + directory: "/etc/dokploy/traefik/dynamic", + watch: true, + }, + }, + entryPoints: { + web: { + address: `:${TRAEFIK_PORT}`, + }, + websecure: { + address: `:${TRAEFIK_SSL_PORT}`, + http3: { + advertisedPort: TRAEFIK_HTTP3_PORT, + }, + ...(process.env.NODE_ENV === "production" && { + http: { + tls: { + certResolver: "letsencrypt", + }, + }, + }), + }, + }, + api: { + insecure: true, + }, + ...(process.env.NODE_ENV === "production" && { + certificatesResolvers: { + letsencrypt: { + acme: { + email: "test@localhost.com", + storage: "/etc/dokploy/traefik/dynamic/acme.json", + httpChallenge: { + entryPoint: "web", + }, + }, + }, + }, + }), + }; - const yamlStr = dump(configObject); + const yamlStr = dump(configObject); - return yamlStr; + return yamlStr; }; export const getDefaultServerTraefikConfig = () => { - const configObject: MainTraefikConfig = { - providers: { - swarm: { - exposedByDefault: false, - watch: true, - }, - docker: { - exposedByDefault: false, - watch: true, - network: 'dokploy-network', - }, - file: { - directory: '/etc/dokploy/traefik/dynamic', - watch: true, - }, - }, - entryPoints: { - web: { - address: `:${TRAEFIK_PORT}`, - }, - websecure: { - address: `:${TRAEFIK_SSL_PORT}`, - http3: { - advertisedPort: TRAEFIK_HTTP3_PORT, - }, - http: { - tls: { - certResolver: 'letsencrypt', - }, - }, - }, - }, - api: { - insecure: true, - }, - certificatesResolvers: { - letsencrypt: { - acme: { - email: 'test@localhost.com', - storage: '/etc/dokploy/traefik/dynamic/acme.json', - httpChallenge: { - entryPoint: 'web', - }, - }, - }, - }, - }; + const configObject: MainTraefikConfig = { + providers: { + swarm: { + exposedByDefault: false, + watch: true, + }, + docker: { + exposedByDefault: false, + watch: true, + network: "dokploy-network", + }, + file: { + directory: "/etc/dokploy/traefik/dynamic", + watch: true, + }, + }, + entryPoints: { + web: { + address: `:${TRAEFIK_PORT}`, + }, + websecure: { + address: `:${TRAEFIK_SSL_PORT}`, + http3: { + advertisedPort: TRAEFIK_HTTP3_PORT, + }, + http: { + tls: { + certResolver: "letsencrypt", + }, + }, + }, + }, + api: { + insecure: true, + }, + certificatesResolvers: { + letsencrypt: { + acme: { + email: "test@localhost.com", + storage: "/etc/dokploy/traefik/dynamic/acme.json", + httpChallenge: { + entryPoint: "web", + }, + }, + }, + }, + }; - const yamlStr = dump(configObject); + const yamlStr = dump(configObject); - return yamlStr; + return yamlStr; }; export const createDefaultTraefikConfig = () => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(); - const mainConfig = path.join(MAIN_TRAEFIK_PATH, 'traefik.yml'); - const acmeJsonPath = path.join(DYNAMIC_TRAEFIK_PATH, 'acme.json'); + const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(); + const mainConfig = path.join(MAIN_TRAEFIK_PATH, "traefik.yml"); + const acmeJsonPath = path.join(DYNAMIC_TRAEFIK_PATH, "acme.json"); - if (existsSync(acmeJsonPath)) { - chmodSync(acmeJsonPath, '600'); - } - if (existsSync(mainConfig)) { - console.log('Main config already exists'); - return; - } - const yamlStr = getDefaultTraefikConfig(); - mkdirSync(MAIN_TRAEFIK_PATH, { recursive: true }); - writeFileSync(mainConfig, yamlStr, 'utf8'); + if (existsSync(acmeJsonPath)) { + chmodSync(acmeJsonPath, "600"); + } + if (existsSync(mainConfig)) { + console.log("Main config already exists"); + return; + } + const yamlStr = getDefaultTraefikConfig(); + mkdirSync(MAIN_TRAEFIK_PATH, { recursive: true }); + writeFileSync(mainConfig, yamlStr, "utf8"); }; export const getDefaultMiddlewares = () => { - const defaultMiddlewares = { - http: { - middlewares: { - 'redirect-to-https': { - redirectScheme: { - scheme: 'https', - permanent: true, - }, - }, - }, - }, - }; - const yamlStr = dump(defaultMiddlewares); - return yamlStr; + const defaultMiddlewares = { + http: { + middlewares: { + "redirect-to-https": { + redirectScheme: { + scheme: "https", + permanent: true, + }, + }, + }, + }, + }; + const yamlStr = dump(defaultMiddlewares); + return yamlStr; }; export const createDefaultMiddlewares = () => { - const { DYNAMIC_TRAEFIK_PATH } = paths(); - const middlewaresPath = path.join(DYNAMIC_TRAEFIK_PATH, 'middlewares.yml'); - if (existsSync(middlewaresPath)) { - console.log('Default middlewares already exists'); - return; - } - const yamlStr = getDefaultMiddlewares(); - mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); - writeFileSync(middlewaresPath, yamlStr, 'utf8'); + const { DYNAMIC_TRAEFIK_PATH } = paths(); + const middlewaresPath = path.join(DYNAMIC_TRAEFIK_PATH, "middlewares.yml"); + if (existsSync(middlewaresPath)) { + console.log("Default middlewares already exists"); + return; + } + const yamlStr = getDefaultMiddlewares(); + mkdirSync(DYNAMIC_TRAEFIK_PATH, { recursive: true }); + writeFileSync(middlewaresPath, yamlStr, "utf8"); }; From e3979d2c481cb87293b5bcca314a988365685b88 Mon Sep 17 00:00:00 2001 From: Vyacheslav Scherbinin Date: Sun, 17 Aug 2025 12:09:26 +0700 Subject: [PATCH 10/49] fix(ui): fixed viewport --- apps/dokploy/components/ui/sidebar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/components/ui/sidebar.tsx b/apps/dokploy/components/ui/sidebar.tsx index a042a6180..b7f79f5ed 100644 --- a/apps/dokploy/components/ui/sidebar.tsx +++ b/apps/dokploy/components/ui/sidebar.tsx @@ -148,7 +148,7 @@ const SidebarProvider = React.forwardRef< } as React.CSSProperties } className={cn( - "group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar", + "group/sidebar-wrapper flex h-svh w-full has-[[data-variant=inset]]:bg-sidebar", className, )} ref={ref} From 6d9a1db8af022b31fc68d97a06a391148c2399f3 Mon Sep 17 00:00:00 2001 From: Vyacheslav Scherbinin Date: Sun, 17 Aug 2025 12:36:40 +0700 Subject: [PATCH 11/49] fix(ui): scrollbar gutter stable --- apps/dokploy/components/ui/sidebar.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/dokploy/components/ui/sidebar.tsx b/apps/dokploy/components/ui/sidebar.tsx index b7f79f5ed..bb9d940a1 100644 --- a/apps/dokploy/components/ui/sidebar.tsx +++ b/apps/dokploy/components/ui/sidebar.tsx @@ -329,10 +329,11 @@ const SidebarInset = React.forwardRef<
); From 8cc054389abc87c651888ec8112a2a17b07a83df Mon Sep 17 00:00:00 2001 From: Scai <59282365+alexevladgabriel@users.noreply.github.com> Date: Mon, 18 Aug 2025 02:04:23 +0300 Subject: [PATCH 12/49] feat: add self reference for env variables --- apps/dokploy/__test__/env/shared.test.ts | 74 +++++++++++++++++++++++ packages/server/src/utils/docker/utils.ts | 8 +++ 2 files changed, 82 insertions(+) diff --git a/apps/dokploy/__test__/env/shared.test.ts b/apps/dokploy/__test__/env/shared.test.ts index 4a8448aa9..5e231a5cc 100644 --- a/apps/dokploy/__test__/env/shared.test.ts +++ b/apps/dokploy/__test__/env/shared.test.ts @@ -177,3 +177,77 @@ COMPLEX_VAR="'Prefix \"DoubleQuoted\" and \${{project.APP_NAME}}'" ]); }); }); + +describe("prepareEnvironmentVariables (self references)", () => { + it("resolves self references correctly", () => { + const serviceEnv = ` +ENVIRONMENT=staging +DATABASE_URL=postgres://postgres:postgres@localhost:5432/project_db +SELF_REF=\${{ENVIRONMENT}} +`; + + const resolved = prepareEnvironmentVariables(serviceEnv, ""); + + expect(resolved).toEqual([ + "ENVIRONMENT=staging", + "DATABASE_URL=postgres://postgres:postgres@localhost:5432/project_db", + "SELF_REF=staging", + ]); + }); + + it("throws on undefined self references", () => { + const serviceEnv = ` +MISSING_VAR=\${{UNDEFINED_VAR}} +`; + + expect(() => prepareEnvironmentVariables(serviceEnv, "")).toThrow( + "Invalid service environment variable: UNDEFINED_VAR", + ); + }); + + it("allows overriding and still resolving from self", () => { + const serviceEnv = ` +ENVIRONMENT=production +OVERRIDE_ENV=\${{ENVIRONMENT}} +`; + + const resolved = prepareEnvironmentVariables(serviceEnv, ""); + + expect(resolved).toEqual([ + "ENVIRONMENT=production", + "OVERRIDE_ENV=production", + ]); + }); + + it("resolves multiple self references inside one value", () => { + const serviceEnv = ` +ENVIRONMENT=staging +APP_NAME=MyApp +COMPLEX=\${{APP_NAME}}-\${{ENVIRONMENT}}-\${{APP_NAME}} +`; + + const resolved = prepareEnvironmentVariables(serviceEnv, ""); + + expect(resolved).toEqual([ + "ENVIRONMENT=staging", + "APP_NAME=MyApp", + "COMPLEX=MyApp-staging-MyApp", + ]); + }); + + it("handles quotes with self references", () => { + const serviceEnv = ` +ENVIRONMENT=production +QUOTED="'\${{ENVIRONMENT}}'" +MIXED="\"Double \${{ENVIRONMENT}}\"" +`; + + const resolved = prepareEnvironmentVariables(serviceEnv, ""); + + expect(resolved).toEqual([ + "ENVIRONMENT=production", + "QUOTED='production'", + 'MIXED="Double production"', + ]); + }); +}); diff --git a/packages/server/src/utils/docker/utils.ts b/packages/server/src/utils/docker/utils.ts index 12f46218f..ef7abf613 100644 --- a/packages/server/src/utils/docker/utils.ts +++ b/packages/server/src/utils/docker/utils.ts @@ -273,6 +273,14 @@ export const prepareEnvironmentVariables = ( throw new Error(`Invalid project environment variable: project.${ref}`); }); } + + resolvedValue = resolvedValue.replace(/\$\{\{(.*?)\}\}/g, (_, ref) => { + if (serviceVars[ref] !== undefined) { + return serviceVars[ref]; + } + throw new Error(`Invalid service environment variable: ${ref}`); + }); + return `${key}=${resolvedValue}`; }); From b4d5935875065929e0804ca40a0a09482d0b11b4 Mon Sep 17 00:00:00 2001 From: Vyacheslav Scherbinin Date: Mon, 18 Aug 2025 23:27:49 +0700 Subject: [PATCH 13/49] fix(ui): modal popover handle close --- apps/dokploy/components/ui/dialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/components/ui/dialog.tsx b/apps/dokploy/components/ui/dialog.tsx index a51ab243c..27c8e35c3 100644 --- a/apps/dokploy/components/ui/dialog.tsx +++ b/apps/dokploy/components/ui/dialog.tsx @@ -123,7 +123,7 @@ const DialogContent = React.forwardRef< {/* Custom overlay for modal=false - no click handler to avoid Command conflicts */}
Date: Mon, 18 Aug 2025 23:52:30 +0700 Subject: [PATCH 14/49] fix(ui): modal pointer events predefine --- apps/dokploy/components/ui/dialog.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/ui/dialog.tsx b/apps/dokploy/components/ui/dialog.tsx index 27c8e35c3..e1237f70c 100644 --- a/apps/dokploy/components/ui/dialog.tsx +++ b/apps/dokploy/components/ui/dialog.tsx @@ -123,16 +123,17 @@ const DialogContent = React.forwardRef< {/* Custom overlay for modal=false - no click handler to avoid Command conflicts */}
event.preventDefault()} {...props} > From a4041185f1bac4c65b4996f6042a2774e3f64de5 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Tue, 19 Aug 2025 00:14:50 -0600 Subject: [PATCH 15/49] feat(ui): add alert blocks for running services in delete confirmation dialogs --- .../dashboard/compose/delete-service.tsx | 15 ++++++++ .../pages/dashboard/project/[projectId].tsx | 36 ++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/apps/dokploy/components/dashboard/compose/delete-service.tsx b/apps/dokploy/components/dashboard/compose/delete-service.tsx index cae27c264..438af954a 100644 --- a/apps/dokploy/components/dashboard/compose/delete-service.tsx +++ b/apps/dokploy/components/dashboard/compose/delete-service.tsx @@ -7,6 +7,7 @@ import { useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; +import { AlertBlock } from "@/components/shared/alert-block"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; @@ -114,6 +115,12 @@ export const DeleteService = ({ id, type }: Props) => { } }; + const isDisabled = + (data && + "applicationStatus" in data && + data?.applicationStatus === "running") || + (data && "composeStatus" in data && data?.composeStatus === "running"); + return ( @@ -202,6 +209,12 @@ export const DeleteService = ({ id, type }: Props) => {
+ {isDisabled && ( + + Cannot delete the service while it is running. Please wait for the + build to finish and then try again. + + )} + + + + +
From ba1f4dbd3a76c0079de2ea28417a5dc243e2f577 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 23 Aug 2025 16:04:13 -0600 Subject: [PATCH 30/49] feat(ui): add bulk deploy functionality for services in project dashboard --- .../pages/dashboard/project/[projectId].tsx | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index a32bae06f..65f7d064d 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -10,6 +10,7 @@ import { FolderInput, GlobeIcon, Loader2, + Play, PlusIcon, Search, ServerIcon, @@ -312,6 +313,7 @@ const Project = ( stop: api.compose.stop.useMutation(), move: api.compose.move.useMutation(), delete: api.compose.delete.useMutation(), + deploy: api.compose.deploy.useMutation(), }; const applicationActions = { @@ -319,6 +321,7 @@ const Project = ( stop: api.application.stop.useMutation(), move: api.application.move.useMutation(), delete: api.application.delete.useMutation(), + deploy: api.application.deploy.useMutation(), }; const postgresActions = { @@ -326,6 +329,7 @@ const Project = ( stop: api.postgres.stop.useMutation(), move: api.postgres.move.useMutation(), delete: api.postgres.remove.useMutation(), + deploy: api.postgres.deploy.useMutation(), }; const mysqlActions = { @@ -333,6 +337,7 @@ const Project = ( stop: api.mysql.stop.useMutation(), move: api.mysql.move.useMutation(), delete: api.mysql.remove.useMutation(), + deploy: api.mysql.deploy.useMutation(), }; const mariadbActions = { @@ -340,6 +345,7 @@ const Project = ( stop: api.mariadb.stop.useMutation(), move: api.mariadb.move.useMutation(), delete: api.mariadb.remove.useMutation(), + deploy: api.mariadb.deploy.useMutation(), }; const redisActions = { @@ -347,6 +353,7 @@ const Project = ( stop: api.redis.stop.useMutation(), move: api.redis.move.useMutation(), delete: api.redis.remove.useMutation(), + deploy: api.redis.deploy.useMutation(), }; const mongoActions = { @@ -354,6 +361,7 @@ const Project = ( stop: api.mongo.stop.useMutation(), move: api.mongo.move.useMutation(), delete: api.mongo.remove.useMutation(), + deploy: api.mongo.deploy.useMutation(), }; const handleBulkStart = async () => { @@ -586,6 +594,83 @@ const Project = ( setIsBulkActionLoading(false); }; + const handleBulkDeploy = async () => { + let success = 0; + let failed = 0; + setIsBulkActionLoading(true); + + for (const serviceId of selectedServices) { + try { + const service = filteredServices.find((s) => s.id === serviceId); + if (!service) continue; + + switch (service.type) { + case "application": + await applicationActions.deploy.mutateAsync({ + applicationId: serviceId, + }); + break; + case "compose": + await composeActions.deploy.mutateAsync({ + composeId: serviceId, + }); + + break; + case "postgres": + await postgresActions.deploy.mutateAsync({ + postgresId: serviceId, + }); + + break; + case "mysql": + await mysqlActions.deploy.mutateAsync({ + mysqlId: serviceId, + }); + + break; + case "mariadb": + await mariadbActions.deploy.mutateAsync({ + mariadbId: serviceId, + }); + + break; + case "redis": + await redisActions.deploy.mutateAsync({ + redisId: serviceId, + }); + + break; + case "mongo": + await mongoActions.deploy.mutateAsync({ + mongoId: serviceId, + }); + + break; + } + success++; + } catch (error) { + failed++; + toast.error( + `Error deploying service ${serviceId}: ${error instanceof Error ? error.message : "Unknown error"}`, + ); + } + } + if (success > 0) { + toast.success( + `${success} service${success !== 1 ? "s" : ""} deployed successfully`, + ); + } + if (failed > 0) { + toast.error( + `${failed} service${failed !== 1 ? "s" : ""} failed to deploy`, + ); + } + + setSelectedServices([]); + setIsDropdownOpen(false); + setIsBulkActionLoading(false); + }; + const filteredServices = useMemo(() => { if (!applications) return []; const filtered = applications.filter( @@ -729,6 +814,24 @@ const Project = ( Start + + + Date: Sat, 23 Aug 2025 16:06:25 -0600 Subject: [PATCH 31/49] feat(ui): implement bulk delete dialog for services in project dashboard --- .../pages/dashboard/project/[projectId].tsx | 115 +++++++++++++++++- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index 65f7d064d..3182f316a 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -290,6 +290,8 @@ const Project = ( const [openCombobox, setOpenCombobox] = useState(false); const [selectedServices, setSelectedServices] = useState([]); const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const [isBulkDeleteDialogOpen, setIsBulkDeleteDialogOpen] = useState(false); + const [deleteVolumes, setDeleteVolumes] = useState(false); const handleSelectAll = () => { if (selectedServices.length === filteredServices.length) { @@ -532,7 +534,7 @@ const Project = ( setIsBulkActionLoading(false); }; - const handleBulkDelete = async () => { + const handleBulkDelete = async (deleteVolumes = false) => { let success = 0; setIsBulkActionLoading(true); for (const serviceId of selectedServices) { @@ -549,7 +551,7 @@ const Project = ( case "compose": await composeActions.delete.mutateAsync({ composeId: serviceId, - deleteVolumes: false, + deleteVolumes, }); break; case "postgres": @@ -879,7 +881,7 @@ const Project = ( disabled={ selectedServicesWithRunningStatus.length > 0 } - onClick={handleBulkDelete} + onClick={() => setIsBulkDeleteDialogOpen(true)} > + + + + From 112b898d989bcc5a6c3faa154a31e51e31fe6b4c Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 24 Aug 2025 02:01:00 +0000 Subject: [PATCH 32/49] [autofix.ci] apply automated fixes --- .../show-preview-settings.tsx | 164 +++++++++--------- 1 file changed, 84 insertions(+), 80 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx index 0aa676057..8e5edf248 100644 --- a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx +++ b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx @@ -211,86 +211,90 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { )} /> - ( - -
- Preview Labels - - - - - - -

- Add a labels that will trigger a preview deployment - for a pull request. If no labels are specified, all - pull requests will trigger a preview deployment. -

-
-
-
-
-
- {field.value?.map((label, index) => ( - - {label} - { - const newLabels = [...(field.value || [])]; - newLabels.splice(index, 1); - field.onChange(newLabels); - }} - /> - - ))} -
-
- - { - if (e.key === "Enter") { - e.preventDefault(); - const input = e.currentTarget; - const label = input.value.trim(); - if (label) { - field.onChange([...(field.value || []), label]); - input.value = ""; - } - } - }} - /> - - -
- -
- )} - /> + ( + +
+ Preview Labels + + + + + + +

+ Add a labels that will trigger a preview + deployment for a pull request. If no labels + are specified, all pull requests will trigger + a preview deployment. +

+
+
+
+
+
+ {field.value?.map((label, index) => ( + + {label} + { + const newLabels = [...(field.value || [])]; + newLabels.splice(index, 1); + field.onChange(newLabels); + }} + /> + + ))} +
+
+ + { + if (e.key === "Enter") { + e.preventDefault(); + const input = e.currentTarget; + const label = input.value.trim(); + if (label) { + field.onChange([ + ...(field.value || []), + label, + ]); + input.value = ""; + } + } + }} + /> + + +
+ +
+ )} + /> Date: Sat, 23 Aug 2025 20:11:18 -0600 Subject: [PATCH 33/49] feat: add support for preview labels in deployment process --- apps/dokploy/pages/api/deploy/github.ts | 22 +++++++++++--------- packages/server/src/db/schema/application.ts | 1 + 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/dokploy/pages/api/deploy/github.ts b/apps/dokploy/pages/api/deploy/github.ts index 7e3df5444..92cf3dc9e 100644 --- a/apps/dokploy/pages/api/deploy/github.ts +++ b/apps/dokploy/pages/api/deploy/github.ts @@ -1,22 +1,22 @@ -import { db } from "@/server/db"; -import { applications, compose, github } from "@/server/db/schema"; -import type { DeploymentJob } from "@/server/queues/queue-types"; -import { myQueue } from "@/server/queues/queueSetup"; -import { deploy } from "@/server/utils/deploy"; import { - IS_CLOUD, checkUserRepositoryPermissions, createPreviewDeployment, createSecurityBlockedComment, findGithubById, findPreviewDeploymentByApplicationId, findPreviewDeploymentsByPullRequestId, + IS_CLOUD, removePreviewDeployment, shouldDeploy, } from "@dokploy/server"; import { Webhooks } from "@octokit/webhooks"; import { and, eq } from "drizzle-orm"; import type { NextApiRequest, NextApiResponse } from "next"; +import { db } from "@/server/db"; +import { applications, compose, github } from "@/server/db/schema"; +import type { DeploymentJob } from "@/server/queues/queue-types"; +import { myQueue } from "@/server/queues/queueSetup"; +import { deploy } from "@/server/utils/deploy"; import { extractCommitMessage, extractHash } from "./[refreshToken]"; export default async function handler( @@ -343,7 +343,9 @@ export default async function handler( if ( action === "opened" || action === "synchronize" || - action === "reopened" + action === "reopened" || + action === "labeled" || + action === "unlabeled" ) { const repository = githubBody?.repository?.name; const deploymentHash = githubBody?.pull_request?.head?.sha; @@ -443,11 +445,11 @@ export default async function handler( for (const app of secureApps) { // check for labels - if (app?.previewLabels.size() > 0) { - let hasLabel: boolean = false; + if (app?.previewLabels && app?.previewLabels?.length > 0) { + let hasLabel = false; const labels = githubBody?.pull_request?.labels; for (const label of labels) { - if (app?.previewLabels.contains(label.name)) { + if (app?.previewLabels?.includes(label.name)) { hasLabel = true; break; } diff --git a/packages/server/src/db/schema/application.ts b/packages/server/src/db/schema/application.ts index 21ee9fbda..198611a77 100644 --- a/packages/server/src/db/schema/application.ts +++ b/packages/server/src/db/schema/application.ts @@ -309,6 +309,7 @@ const createSchema = createInsertSchema(applications, { previewCertificateType: z.enum(["letsencrypt", "none", "custom"]).optional(), previewRequireCollaboratorPermissions: z.boolean().optional(), watchPaths: z.array(z.string()).optional(), + previewLabels: z.array(z.string()).optional(), cleanCache: z.boolean().optional(), }); From 2ef5f967a9f5f95b1c970204adb63a0168b95d69 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 23 Aug 2025 20:14:41 -0600 Subject: [PATCH 34/49] refactor: clean up imports in show-preview-settings component --- .../preview-deployments/show-preview-settings.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx index 0a6637a0a..16c916d93 100644 --- a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx +++ b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-settings.tsx @@ -1,9 +1,9 @@ -import { zodResolver, zodResolver } from "@hookform/resolvers/zod"; -import { HelpCircle, Plus, Settings2, Settings2, X } from "lucide-react"; -import { useEffect, useEffect, useState, useState } from "react"; -import { useForm, useForm } from "react-hook-form"; -import { toast, toast } from "sonner"; -import { z, z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { HelpCircle, Plus, Settings2, X } from "lucide-react"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { toast } from "sonner"; +import { z } from "zod"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { From 40877e437047947899145a8354d8220d57ddaa84 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 24 Aug 2025 02:16:35 +0000 Subject: [PATCH 35/49] [autofix.ci] apply automated fixes --- packages/server/src/setup/traefik-setup.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/server/src/setup/traefik-setup.ts b/packages/server/src/setup/traefik-setup.ts index 5427291ef..17c48d0ff 100644 --- a/packages/server/src/setup/traefik-setup.ts +++ b/packages/server/src/setup/traefik-setup.ts @@ -15,7 +15,6 @@ export const TRAEFIK_HTTP3_PORT = Number.parseInt(process.env.TRAEFIK_HTTP3_PORT!, 10) || 443; export const TRAEFIK_VERSION = process.env.TRAEFIK_VERSION || "3.5.0"; - export interface TraefikOptions { env?: string[]; serverId?: string; From c653dd604f7f6b46bee8480074602fc9258e87c9 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 23 Aug 2025 20:19:14 -0600 Subject: [PATCH 36/49] feat: add previewLabels property to baseApp in drop and traefik test files --- apps/dokploy/__test__/drop/drop.test.ts | 1 + apps/dokploy/__test__/traefik/traefik.test.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/dokploy/__test__/drop/drop.test.ts b/apps/dokploy/__test__/drop/drop.test.ts index 301278dc3..a9bc178a2 100644 --- a/apps/dokploy/__test__/drop/drop.test.ts +++ b/apps/dokploy/__test__/drop/drop.test.ts @@ -27,6 +27,7 @@ if (typeof window === "undefined") { const baseApp: ApplicationNested = { railpackVersion: "0.2.2", applicationId: "", + previewLabels: [], herokuVersion: "", giteaBranch: "", giteaBuildPath: "", diff --git a/apps/dokploy/__test__/traefik/traefik.test.ts b/apps/dokploy/__test__/traefik/traefik.test.ts index 8d9f78aba..ff8a99620 100644 --- a/apps/dokploy/__test__/traefik/traefik.test.ts +++ b/apps/dokploy/__test__/traefik/traefik.test.ts @@ -6,6 +6,7 @@ const baseApp: ApplicationNested = { railpackVersion: "0.2.2", rollbackActive: false, applicationId: "", + previewLabels: [], herokuVersion: "", giteaRepository: "", giteaOwner: "", From 746cf76cf3a32dc2cff2eaffb01185bea277af5a Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 23 Aug 2025 22:59:52 -0600 Subject: [PATCH 37/49] fix: correct application not found error message and improve error handling in removePreviewDeployment function --- .../server/src/services/preview-deployment.ts | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/server/src/services/preview-deployment.ts b/packages/server/src/services/preview-deployment.ts index 1b358946f..44d1604ae 100644 --- a/packages/server/src/services/preview-deployment.ts +++ b/packages/server/src/services/preview-deployment.ts @@ -70,7 +70,7 @@ export const findApplicationByPreview = async (applicationId: string) => { if (!application) { throw new TRPCError({ code: "NOT_FOUND", - message: "Applicationnot found", + message: "Application not found", }); } return application; @@ -78,35 +78,41 @@ export const findApplicationByPreview = async (applicationId: string) => { export const removePreviewDeployment = async (previewDeploymentId: string) => { try { - const application = await findApplicationByPreview(previewDeploymentId); const previewDeployment = await findPreviewDeploymentById(previewDeploymentId); - - const deployment = await db - .delete(previewDeployments) - .where(eq(previewDeployments.previewDeploymentId, previewDeploymentId)) - .returning(); + const application = await findApplicationById( + previewDeployment.applicationId, + ); application.appName = previewDeployment.appName; const cleanupOperations = [ + async () => + await removeService(application?.appName, application?.serverId), async () => await removeDeploymentsByPreviewDeploymentId( previewDeployment, - application.serverId, + application?.serverId, ), async () => - await removeDirectoryCode(application.appName, application.serverId), + await removeDirectoryCode(application?.appName, application?.serverId), async () => - await removeTraefikConfig(application.appName, application.serverId), + await removeTraefikConfig(application?.appName, application?.serverId), async () => - await removeService(application?.appName, application.serverId), + await db + .delete(previewDeployments) + .where( + eq(previewDeployments.previewDeploymentId, previewDeploymentId), + ) + .returning(), ]; for (const operation of cleanupOperations) { try { await operation(); - } catch {} + } catch (error) { + console.error(error); + } } - return deployment[0]; + return previewDeployment; } catch (error) { const message = error instanceof Error From 5e4444610cc9512f544d05f425a9e312dddd42dc Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 24 Aug 2025 06:33:36 +0000 Subject: [PATCH 38/49] [autofix.ci] apply automated fixes --- .../volume-backups/handle-volume-backups.tsx | 8 ++++---- packages/server/src/utils/volume-backups/utils.ts | 10 ++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx b/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx index 09ba71839..feb99175b 100644 --- a/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx +++ b/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx @@ -55,8 +55,7 @@ const formSchema = z cronExpression: z.string().min(1, "Cron expression is required"), volumeName: z.string().min(1, "Volume name is required"), prefix: z.string(), - keepLatestCount: z - .coerce + keepLatestCount: z.coerce .number() .int() .gte(1, "Must be at least 1") @@ -188,7 +187,8 @@ export const HandleVolumeBackups = ({ serviceType: volumeBackup.serviceType, }); setKeepLatestCountInput( - volumeBackup.keepLatestCount !== null && volumeBackup.keepLatestCount !== undefined + volumeBackup.keepLatestCount !== null && + volumeBackup.keepLatestCount !== undefined ? String(volumeBackup.keepLatestCount) : "", ); @@ -203,7 +203,7 @@ export const HandleVolumeBackups = ({ if (!id && !volumeBackupId) return; const preparedKeepLatestCount = - keepLatestCountInput === "" ? null : values.keepLatestCount ?? null; + keepLatestCountInput === "" ? null : (values.keepLatestCount ?? null); await mutateAsync({ ...values, diff --git a/packages/server/src/utils/volume-backups/utils.ts b/packages/server/src/utils/volume-backups/utils.ts index 7ee1ccb4d..5b55c240c 100644 --- a/packages/server/src/utils/volume-backups/utils.ts +++ b/packages/server/src/utils/volume-backups/utils.ts @@ -1,7 +1,13 @@ import { findVolumeBackupById } from "@dokploy/server/services/volume-backups"; import { scheduledJobs, scheduleJob } from "node-schedule"; -import { createDeploymentVolumeBackup, updateDeploymentStatus } from "@dokploy/server/services/deployment"; -import { execAsync, execAsyncRemote } from "@dokploy/server/utils/process/execAsync"; +import { + createDeploymentVolumeBackup, + updateDeploymentStatus, +} from "@dokploy/server/services/deployment"; +import { + execAsync, + execAsyncRemote, +} from "@dokploy/server/utils/process/execAsync"; import { backupVolume } from "./backup"; import { getS3Credentials, normalizeS3Path } from "../backups/utils"; From 59aaa1a47a4dd7505643a8d0270ccc3ac1ae0dfc Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 24 Aug 2025 00:40:17 -0600 Subject: [PATCH 39/49] fix(ui): adjust max width for volume backup dialog based on backup type --- .../application/volume-backups/handle-volume-backups.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx b/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx index feb99175b..f00b91a9d 100644 --- a/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx +++ b/apps/dokploy/components/dashboard/application/volume-backups/handle-volume-backups.tsx @@ -273,9 +273,8 @@ export const HandleVolumeBackups = ({ From cbf6f95891b327657e5c3c7c945c88b541c46930 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 24 Aug 2025 16:19:33 -0600 Subject: [PATCH 40/49] refactor: update database connection handling and remove unused migration and seed files --- apps/dokploy/esbuild.config.ts | 6 + apps/dokploy/migrate.ts | 149 ----------------------- apps/dokploy/server/db/index.ts | 8 +- apps/dokploy/server/db/migration.ts | 21 ---- apps/dokploy/server/db/seed.ts | 29 ----- packages/server/package.json | 31 +++-- packages/server/src/db/drizzle.config.ts | 14 --- packages/server/src/db/index.ts | 21 ---- packages/server/src/db/migration.ts | 21 ---- packages/server/src/db/reset.ts | 23 ---- packages/server/src/db/seed.ts | 35 ------ 11 files changed, 33 insertions(+), 325 deletions(-) delete mode 100644 apps/dokploy/migrate.ts delete mode 100644 apps/dokploy/server/db/migration.ts delete mode 100644 apps/dokploy/server/db/seed.ts delete mode 100644 packages/server/src/db/drizzle.config.ts delete mode 100644 packages/server/src/db/index.ts delete mode 100644 packages/server/src/db/migration.ts delete mode 100644 packages/server/src/db/reset.ts delete mode 100644 packages/server/src/db/seed.ts diff --git a/apps/dokploy/esbuild.config.ts b/apps/dokploy/esbuild.config.ts index c84135e5d..6d96cf058 100644 --- a/apps/dokploy/esbuild.config.ts +++ b/apps/dokploy/esbuild.config.ts @@ -7,6 +7,10 @@ function prepareDefine(config: DotenvParseOutput | undefined) { const define = {}; // @ts-ignore for (const [key, value] of Object.entries(config)) { + // Skip DATABASE_URL to allow runtime environment variable override + if (key === "DATABASE_URL") { + continue; + } // @ts-ignore define[`process.env.${key}`] = JSON.stringify(value); } @@ -14,6 +18,8 @@ function prepareDefine(config: DotenvParseOutput | undefined) { } const define = prepareDefine(result.parsed); + +console.log(define); try { esbuild .build({ diff --git a/apps/dokploy/migrate.ts b/apps/dokploy/migrate.ts deleted file mode 100644 index e1f52c9a3..000000000 --- a/apps/dokploy/migrate.ts +++ /dev/null @@ -1,149 +0,0 @@ -// import { drizzle } from "drizzle-orm/postgres-js"; -// import { nanoid } from "nanoid"; -// import postgres from "postgres"; -// import * as schema from "./server/db/schema"; - -// const connectionString = process.env.DATABASE_URL!; - -// const sql = postgres(connectionString, { max: 1 }); -// const db = drizzle(sql, { -// schema, -// }); - -// await db -// .transaction(async (db) => { -// const admins = await db.query.admins.findMany({ -// with: { -// auth: true, -// users: { -// with: { -// auth: true, -// }, -// }, -// }, -// }); -// for (const admin of admins) { -// const user = await db -// .insert(schema.users_temp) -// .values({ -// id: admin.adminId, -// email: admin.auth.email, -// token: admin.auth.token || "", -// emailVerified: true, -// updatedAt: new Date(), -// role: "admin", -// serverIp: admin.serverIp, -// image: admin.auth.image, -// certificateType: admin.certificateType, -// host: admin.host, -// letsEncryptEmail: admin.letsEncryptEmail, -// sshPrivateKey: admin.sshPrivateKey, -// enableDockerCleanup: admin.enableDockerCleanup, -// enableLogRotation: admin.enableLogRotation, -// enablePaidFeatures: admin.enablePaidFeatures, -// metricsConfig: admin.metricsConfig, -// cleanupCacheApplications: admin.cleanupCacheApplications, -// cleanupCacheOnPreviews: admin.cleanupCacheOnPreviews, -// cleanupCacheOnCompose: admin.cleanupCacheOnCompose, -// stripeCustomerId: admin.stripeCustomerId, -// stripeSubscriptionId: admin.stripeSubscriptionId, -// serversQuantity: admin.serversQuantity, -// }) -// .returning() -// .then((user) => user[0]); - -// await db.insert(schema.account).values({ -// providerId: "credential", -// userId: user?.id || "", -// password: admin.auth.password, -// is2FAEnabled: admin.auth.is2FAEnabled || false, -// createdAt: new Date(admin.auth.createdAt) || new Date(), -// updatedAt: new Date(admin.auth.createdAt) || new Date(), -// }); - -// const organization = await db -// .insert(schema.organization) -// .values({ -// name: "My Organization", -// slug: nanoid(), -// ownerId: user?.id || "", -// createdAt: new Date(admin.createdAt) || new Date(), -// }) -// .returning() -// .then((organization) => organization[0]); - -// for (const member of admin.users) { -// const userTemp = await db -// .insert(schema.users_temp) -// .values({ -// id: member.userId, -// email: member.auth.email, -// token: member.token || "", -// emailVerified: true, -// updatedAt: new Date(admin.createdAt) || new Date(), -// role: "user", -// image: member.auth.image, -// createdAt: admin.createdAt, -// canAccessToAPI: member.canAccessToAPI || false, -// canAccessToDocker: member.canAccessToDocker || false, -// canAccessToGitProviders: member.canAccessToGitProviders || false, -// canAccessToSSHKeys: member.canAccessToSSHKeys || false, -// canAccessToTraefikFiles: member.canAccessToTraefikFiles || false, -// canCreateProjects: member.canCreateProjects || false, -// canCreateServices: member.canCreateServices || false, -// canDeleteProjects: member.canDeleteProjects || false, -// canDeleteServices: member.canDeleteServices || false, -// accessedProjects: member.accessedProjects || [], -// accessedServices: member.accessedServices || [], -// }) -// .returning() -// .then((userTemp) => userTemp[0]); - -// await db.insert(schema.account).values({ -// providerId: "credential", -// userId: member?.userId || "", -// password: member.auth.password, -// is2FAEnabled: member.auth.is2FAEnabled || false, -// createdAt: new Date(member.auth.createdAt) || new Date(), -// updatedAt: new Date(member.auth.createdAt) || new Date(), -// }); - -// await db.insert(schema.member).values({ -// organizationId: organization?.id || "", -// userId: userTemp?.id || "", -// role: "admin", -// createdAt: new Date(member.createdAt) || new Date(), -// }); -// } -// } -// }) -// .then(() => { -// console.log("Migration finished"); -// }) -// .catch((error) => { -// console.error(error); -// }); - -// await db -// .transaction(async (db) => { -// const projects = await db.query.projects.findMany({ -// with: { -// user: { -// with: { -// organizations: true, -// }, -// }, -// }, -// }); -// for (const project of projects) { -// const _user = await db.update(schema.projects).set({ -// organizationId: project.user.organizations[0]?.id || "", -// }); -// } -// }) -// .then(() => { -// console.log("Migration finished"); -// }) -// .catch((error) => { -// console.error(error); -// }); diff --git a/apps/dokploy/server/db/index.ts b/apps/dokploy/server/db/index.ts index 3ac6e3940..55d6d3a46 100644 --- a/apps/dokploy/server/db/index.ts +++ b/apps/dokploy/server/db/index.ts @@ -6,14 +6,18 @@ declare global { var db: PostgresJsDatabase | undefined; } +const dbUrl = + process.env.DATABASE_URL || + "postgres://dokploy:amukds4wi9001583845717ad2@dokploy-postgres:5432/dokploy"; + export let db: PostgresJsDatabase; if (process.env.NODE_ENV === "production") { - db = drizzle(postgres(process.env.DATABASE_URL!), { + db = drizzle(postgres(dbUrl!), { schema, }); } else { if (!global.db) - global.db = drizzle(postgres(process.env.DATABASE_URL!), { + global.db = drizzle(postgres(dbUrl!), { schema, }); diff --git a/apps/dokploy/server/db/migration.ts b/apps/dokploy/server/db/migration.ts deleted file mode 100644 index fa2e1a80f..000000000 --- a/apps/dokploy/server/db/migration.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { drizzle } from "drizzle-orm/postgres-js"; -import { migrate } from "drizzle-orm/postgres-js/migrator"; -import postgres from "postgres"; - -const connectionString = process.env.DATABASE_URL!; - -const sql = postgres(connectionString, { max: 1 }); -const db = drizzle(sql); - -export const migration = async () => - await migrate(db, { migrationsFolder: "drizzle" }) - .then(() => { - console.log("Migration complete"); - sql.end(); - }) - .catch((error) => { - console.log("Migration failed", error); - }) - .finally(() => { - sql.end(); - }); diff --git a/apps/dokploy/server/db/seed.ts b/apps/dokploy/server/db/seed.ts deleted file mode 100644 index 5b3eb6c62..000000000 --- a/apps/dokploy/server/db/seed.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { drizzle } from "drizzle-orm/postgres-js"; -import postgres from "postgres"; - -const connectionString = process.env.DATABASE_URL!; - -const pg = postgres(connectionString, { max: 1 }); -const _db = drizzle(pg); - -async function seed() { - console.log("> Seed:", process.env.DATABASE_PATH, "\n"); - - // const authenticationR = await db - // .insert(users) - // .values([ - // { - // email: "user1@hotmail.com", - // password: password("12345671"), - // }, - // ]) - // .onConflictDoNothing() - // .returning(); - - // console.log("\nSemillas Update:", authenticationR.length); -} - -seed().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/packages/server/package.json b/packages/server/package.json index dbf7d3c65..fc531d540 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,21 +1,32 @@ { "name": "@dokploy/server", "version": "1.0.0", - "main": "./src/index.ts", + "main": "./dist/index.js", "type": "module", "exports": { - ".": "./src/index.ts", + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs.js" + }, "./db": { - "import": "./src/db/index.ts", + "import": "./dist/db/index.js", "require": "./dist/db/index.cjs.js" }, - "./setup/*": { - "import": "./src/setup/*.ts", - "require": "./dist/setup/index.cjs.js" + "./*": { + "import": "./dist/*", + "require": "./dist/*.cjs" }, - "./constants": { - "import": "./src/constants/index.ts", - "require": "./dist/constants.cjs.js" + "./dist": { + "import": "./dist/index.js", + "require": "./dist/index.cjs.js" + }, + "./dist/db": { + "import": "./dist/db/index.js", + "require": "./dist/db/index.cjs.js" + }, + "./dist/db/schema": { + "import": "./dist/db/schema/index.js", + "require": "./dist/db/schema/index.cjs.js" } }, "scripts": { @@ -111,4 +122,4 @@ "node": "^20.16.0", "pnpm": ">=9.12.0" } -} +} \ No newline at end of file diff --git a/packages/server/src/db/drizzle.config.ts b/packages/server/src/db/drizzle.config.ts deleted file mode 100644 index 60a3bb937..000000000 --- a/packages/server/src/db/drizzle.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineConfig } from "drizzle-kit"; - -export default defineConfig({ - schema: "./server/db/schema/index.ts", - dialect: "postgresql", - dbCredentials: { - url: process.env.DATABASE_URL!, - }, - out: "drizzle", - migrations: { - table: "migrations", - schema: "public", - }, -}); diff --git a/packages/server/src/db/index.ts b/packages/server/src/db/index.ts deleted file mode 100644 index 3ac6e3940..000000000 --- a/packages/server/src/db/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { drizzle, type PostgresJsDatabase } from "drizzle-orm/postgres-js"; -import postgres from "postgres"; -import * as schema from "./schema"; - -declare global { - var db: PostgresJsDatabase | undefined; -} - -export let db: PostgresJsDatabase; -if (process.env.NODE_ENV === "production") { - db = drizzle(postgres(process.env.DATABASE_URL!), { - schema, - }); -} else { - if (!global.db) - global.db = drizzle(postgres(process.env.DATABASE_URL!), { - schema, - }); - - db = global.db; -} diff --git a/packages/server/src/db/migration.ts b/packages/server/src/db/migration.ts deleted file mode 100644 index 6fada0833..000000000 --- a/packages/server/src/db/migration.ts +++ /dev/null @@ -1,21 +0,0 @@ -// import { drizzle } from "drizzle-orm/postgres-js"; -// import { migrate } from "drizzle-orm/postgres-js/migrator"; -// import postgres from "postgres"; - -// const connectionString = process.env.DATABASE_URL!; - -// const sql = postgres(connectionString, { max: 1 }); -// const db = drizzle(sql); - -// export const migration = async () => -// await migrate(db, { migrationsFolder: "drizzle" }) -// .then(() => { -// console.log("Migration complete"); -// sql.end(); -// }) -// .catch((error) => { -// console.log("Migration failed", error); -// }) -// .finally(() => { -// sql.end(); -// }); diff --git a/packages/server/src/db/reset.ts b/packages/server/src/db/reset.ts deleted file mode 100644 index c22291478..000000000 --- a/packages/server/src/db/reset.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { sql } from "drizzle-orm"; -// Credits to Louistiti from Drizzle Discord: https://discord.com/channels/1043890932593987624/1130802621750448160/1143083373535973406 -import { drizzle } from "drizzle-orm/postgres-js"; -import postgres from "postgres"; - -const connectionString = process.env.DATABASE_URL!; - -const pg = postgres(connectionString, { max: 1 }); -const db = drizzle(pg); - -const clearDb = async (): Promise => { - try { - const tablesQuery = sql`DROP SCHEMA public CASCADE; CREATE SCHEMA public; DROP schema drizzle CASCADE;`; - const tables = await db.execute(tablesQuery); - console.log(tables); - await pg.end(); - } catch (error) { - console.error("Error cleaning database", error); - } finally { - } -}; - -clearDb(); diff --git a/packages/server/src/db/seed.ts b/packages/server/src/db/seed.ts deleted file mode 100644 index 7e2736b00..000000000 --- a/packages/server/src/db/seed.ts +++ /dev/null @@ -1,35 +0,0 @@ -// import bc from "bcrypt"; -// import { drizzle } from "drizzle-orm/postgres-js"; -// import postgres from "postgres"; -// import { users } from "./schema"; - -// const connectionString = process.env.DATABASE_URL!; - -// const pg = postgres(connectionString, { max: 1 }); -// const db = drizzle(pg); - -// function password(txt: string) { -// return bc.hashSync(txt, 10); -// } - -// async function seed() { -// console.log("> Seed:", process.env.DATABASE_PATH, "\n"); - -// // const authenticationR = await db -// // .insert(users) -// // .values([ -// // { -// // email: "user1@hotmail.com", -// // password: password("12345671"), -// // }, -// // ]) -// // .onConflictDoNothing() -// // .returning(); - -// // console.log("\nSemillas Update:", authenticationR.length); -// } - -// seed().catch((e) => { -// console.error(e); -// process.exit(1); -// }); From 8c420ff4f5b080c26d1c28fd9d5a685876a28555 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 24 Aug 2025 16:20:32 -0600 Subject: [PATCH 41/49] refactor: update package.json to use TypeScript source files instead of compiled JavaScript --- packages/server/package.json | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index fc531d540..3b249a65b 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,32 +1,21 @@ { "name": "@dokploy/server", "version": "1.0.0", - "main": "./dist/index.js", + "main": "./src/index.ts", "type": "module", "exports": { - ".": { - "import": "./dist/index.js", - "require": "./dist/index.cjs.js" - }, + ".": "./src/index.ts", "./db": { - "import": "./dist/db/index.js", + "import": "./src/db/index.ts", "require": "./dist/db/index.cjs.js" }, - "./*": { - "import": "./dist/*", - "require": "./dist/*.cjs" + "./setup/*": { + "import": "./src/setup/*.ts", + "require": "./dist/setup/index.cjs.js" }, - "./dist": { - "import": "./dist/index.js", - "require": "./dist/index.cjs.js" - }, - "./dist/db": { - "import": "./dist/db/index.js", - "require": "./dist/db/index.cjs.js" - }, - "./dist/db/schema": { - "import": "./dist/db/schema/index.js", - "require": "./dist/db/schema/index.cjs.js" + "./constants": { + "import": "./src/constants/index.ts", + "require": "./dist/constants.cjs.js" } }, "scripts": { From 03588bf375544ac1d284ebe39227372555e8af85 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 24 Aug 2025 16:21:01 -0600 Subject: [PATCH 42/49] chore: remove console.log statement from esbuild configuration --- apps/dokploy/esbuild.config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/dokploy/esbuild.config.ts b/apps/dokploy/esbuild.config.ts index 6d96cf058..a1747ac55 100644 --- a/apps/dokploy/esbuild.config.ts +++ b/apps/dokploy/esbuild.config.ts @@ -19,7 +19,6 @@ function prepareDefine(config: DotenvParseOutput | undefined) { const define = prepareDefine(result.parsed); -console.log(define); try { esbuild .build({ From c42054b965e4dcfb27cff60fcbffba4e52075d55 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 24 Aug 2025 16:22:42 -0600 Subject: [PATCH 43/49] feat(migration): implement database migration functionality using drizzle-orm --- apps/dokploy/server/db/migration.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 apps/dokploy/server/db/migration.ts diff --git a/apps/dokploy/server/db/migration.ts b/apps/dokploy/server/db/migration.ts new file mode 100644 index 000000000..fa2e1a80f --- /dev/null +++ b/apps/dokploy/server/db/migration.ts @@ -0,0 +1,21 @@ +import { drizzle } from "drizzle-orm/postgres-js"; +import { migrate } from "drizzle-orm/postgres-js/migrator"; +import postgres from "postgres"; + +const connectionString = process.env.DATABASE_URL!; + +const sql = postgres(connectionString, { max: 1 }); +const db = drizzle(sql); + +export const migration = async () => + await migrate(db, { migrationsFolder: "drizzle" }) + .then(() => { + console.log("Migration complete"); + sql.end(); + }) + .catch((error) => { + console.log("Migration failed", error); + }) + .finally(() => { + sql.end(); + }); From aa434cbdeab8a2506c48ac0ecc811e91425837a3 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 24 Aug 2025 16:25:04 -0600 Subject: [PATCH 44/49] feat(db): add database connection setup using drizzle-orm for PostgreSQL --- packages/server/src/db/index.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 packages/server/src/db/index.ts diff --git a/packages/server/src/db/index.ts b/packages/server/src/db/index.ts new file mode 100644 index 000000000..3ac6e3940 --- /dev/null +++ b/packages/server/src/db/index.ts @@ -0,0 +1,21 @@ +import { drizzle, type PostgresJsDatabase } from "drizzle-orm/postgres-js"; +import postgres from "postgres"; +import * as schema from "./schema"; + +declare global { + var db: PostgresJsDatabase | undefined; +} + +export let db: PostgresJsDatabase; +if (process.env.NODE_ENV === "production") { + db = drizzle(postgres(process.env.DATABASE_URL!), { + schema, + }); +} else { + if (!global.db) + global.db = drizzle(postgres(process.env.DATABASE_URL!), { + schema, + }); + + db = global.db; +} From 17f333ac2a5c789f6426c1d56daa44763ee5c7c2 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 24 Aug 2025 23:44:00 -0600 Subject: [PATCH 45/49] =?UTF-8?q?Revert=20"refactor:=20update=20database?= =?UTF-8?q?=20connection=20handling=20and=20remove=20unused=20migra?= =?UTF-8?q?=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dokploy/esbuild.config.ts | 5 - apps/dokploy/migrate.ts | 149 +++++++++++++++++++++++ apps/dokploy/server/db/index.ts | 8 +- apps/dokploy/server/db/seed.ts | 29 +++++ packages/server/package.json | 2 +- packages/server/src/db/drizzle.config.ts | 14 +++ packages/server/src/db/migration.ts | 21 ++++ packages/server/src/db/reset.ts | 23 ++++ packages/server/src/db/seed.ts | 35 ++++++ 9 files changed, 274 insertions(+), 12 deletions(-) create mode 100644 apps/dokploy/migrate.ts create mode 100644 apps/dokploy/server/db/seed.ts create mode 100644 packages/server/src/db/drizzle.config.ts create mode 100644 packages/server/src/db/migration.ts create mode 100644 packages/server/src/db/reset.ts create mode 100644 packages/server/src/db/seed.ts diff --git a/apps/dokploy/esbuild.config.ts b/apps/dokploy/esbuild.config.ts index a1747ac55..c84135e5d 100644 --- a/apps/dokploy/esbuild.config.ts +++ b/apps/dokploy/esbuild.config.ts @@ -7,10 +7,6 @@ function prepareDefine(config: DotenvParseOutput | undefined) { const define = {}; // @ts-ignore for (const [key, value] of Object.entries(config)) { - // Skip DATABASE_URL to allow runtime environment variable override - if (key === "DATABASE_URL") { - continue; - } // @ts-ignore define[`process.env.${key}`] = JSON.stringify(value); } @@ -18,7 +14,6 @@ function prepareDefine(config: DotenvParseOutput | undefined) { } const define = prepareDefine(result.parsed); - try { esbuild .build({ diff --git a/apps/dokploy/migrate.ts b/apps/dokploy/migrate.ts new file mode 100644 index 000000000..e1f52c9a3 --- /dev/null +++ b/apps/dokploy/migrate.ts @@ -0,0 +1,149 @@ +// import { drizzle } from "drizzle-orm/postgres-js"; +// import { nanoid } from "nanoid"; +// import postgres from "postgres"; +// import * as schema from "./server/db/schema"; + +// const connectionString = process.env.DATABASE_URL!; + +// const sql = postgres(connectionString, { max: 1 }); +// const db = drizzle(sql, { +// schema, +// }); + +// await db +// .transaction(async (db) => { +// const admins = await db.query.admins.findMany({ +// with: { +// auth: true, +// users: { +// with: { +// auth: true, +// }, +// }, +// }, +// }); +// for (const admin of admins) { +// const user = await db +// .insert(schema.users_temp) +// .values({ +// id: admin.adminId, +// email: admin.auth.email, +// token: admin.auth.token || "", +// emailVerified: true, +// updatedAt: new Date(), +// role: "admin", +// serverIp: admin.serverIp, +// image: admin.auth.image, +// certificateType: admin.certificateType, +// host: admin.host, +// letsEncryptEmail: admin.letsEncryptEmail, +// sshPrivateKey: admin.sshPrivateKey, +// enableDockerCleanup: admin.enableDockerCleanup, +// enableLogRotation: admin.enableLogRotation, +// enablePaidFeatures: admin.enablePaidFeatures, +// metricsConfig: admin.metricsConfig, +// cleanupCacheApplications: admin.cleanupCacheApplications, +// cleanupCacheOnPreviews: admin.cleanupCacheOnPreviews, +// cleanupCacheOnCompose: admin.cleanupCacheOnCompose, +// stripeCustomerId: admin.stripeCustomerId, +// stripeSubscriptionId: admin.stripeSubscriptionId, +// serversQuantity: admin.serversQuantity, +// }) +// .returning() +// .then((user) => user[0]); + +// await db.insert(schema.account).values({ +// providerId: "credential", +// userId: user?.id || "", +// password: admin.auth.password, +// is2FAEnabled: admin.auth.is2FAEnabled || false, +// createdAt: new Date(admin.auth.createdAt) || new Date(), +// updatedAt: new Date(admin.auth.createdAt) || new Date(), +// }); + +// const organization = await db +// .insert(schema.organization) +// .values({ +// name: "My Organization", +// slug: nanoid(), +// ownerId: user?.id || "", +// createdAt: new Date(admin.createdAt) || new Date(), +// }) +// .returning() +// .then((organization) => organization[0]); + +// for (const member of admin.users) { +// const userTemp = await db +// .insert(schema.users_temp) +// .values({ +// id: member.userId, +// email: member.auth.email, +// token: member.token || "", +// emailVerified: true, +// updatedAt: new Date(admin.createdAt) || new Date(), +// role: "user", +// image: member.auth.image, +// createdAt: admin.createdAt, +// canAccessToAPI: member.canAccessToAPI || false, +// canAccessToDocker: member.canAccessToDocker || false, +// canAccessToGitProviders: member.canAccessToGitProviders || false, +// canAccessToSSHKeys: member.canAccessToSSHKeys || false, +// canAccessToTraefikFiles: member.canAccessToTraefikFiles || false, +// canCreateProjects: member.canCreateProjects || false, +// canCreateServices: member.canCreateServices || false, +// canDeleteProjects: member.canDeleteProjects || false, +// canDeleteServices: member.canDeleteServices || false, +// accessedProjects: member.accessedProjects || [], +// accessedServices: member.accessedServices || [], +// }) +// .returning() +// .then((userTemp) => userTemp[0]); + +// await db.insert(schema.account).values({ +// providerId: "credential", +// userId: member?.userId || "", +// password: member.auth.password, +// is2FAEnabled: member.auth.is2FAEnabled || false, +// createdAt: new Date(member.auth.createdAt) || new Date(), +// updatedAt: new Date(member.auth.createdAt) || new Date(), +// }); + +// await db.insert(schema.member).values({ +// organizationId: organization?.id || "", +// userId: userTemp?.id || "", +// role: "admin", +// createdAt: new Date(member.createdAt) || new Date(), +// }); +// } +// } +// }) +// .then(() => { +// console.log("Migration finished"); +// }) +// .catch((error) => { +// console.error(error); +// }); + +// await db +// .transaction(async (db) => { +// const projects = await db.query.projects.findMany({ +// with: { +// user: { +// with: { +// organizations: true, +// }, +// }, +// }, +// }); +// for (const project of projects) { +// const _user = await db.update(schema.projects).set({ +// organizationId: project.user.organizations[0]?.id || "", +// }); +// } +// }) +// .then(() => { +// console.log("Migration finished"); +// }) +// .catch((error) => { +// console.error(error); +// }); diff --git a/apps/dokploy/server/db/index.ts b/apps/dokploy/server/db/index.ts index 55d6d3a46..3ac6e3940 100644 --- a/apps/dokploy/server/db/index.ts +++ b/apps/dokploy/server/db/index.ts @@ -6,18 +6,14 @@ declare global { var db: PostgresJsDatabase | undefined; } -const dbUrl = - process.env.DATABASE_URL || - "postgres://dokploy:amukds4wi9001583845717ad2@dokploy-postgres:5432/dokploy"; - export let db: PostgresJsDatabase; if (process.env.NODE_ENV === "production") { - db = drizzle(postgres(dbUrl!), { + db = drizzle(postgres(process.env.DATABASE_URL!), { schema, }); } else { if (!global.db) - global.db = drizzle(postgres(dbUrl!), { + global.db = drizzle(postgres(process.env.DATABASE_URL!), { schema, }); diff --git a/apps/dokploy/server/db/seed.ts b/apps/dokploy/server/db/seed.ts new file mode 100644 index 000000000..5b3eb6c62 --- /dev/null +++ b/apps/dokploy/server/db/seed.ts @@ -0,0 +1,29 @@ +import { drizzle } from "drizzle-orm/postgres-js"; +import postgres from "postgres"; + +const connectionString = process.env.DATABASE_URL!; + +const pg = postgres(connectionString, { max: 1 }); +const _db = drizzle(pg); + +async function seed() { + console.log("> Seed:", process.env.DATABASE_PATH, "\n"); + + // const authenticationR = await db + // .insert(users) + // .values([ + // { + // email: "user1@hotmail.com", + // password: password("12345671"), + // }, + // ]) + // .onConflictDoNothing() + // .returning(); + + // console.log("\nSemillas Update:", authenticationR.length); +} + +seed().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/packages/server/package.json b/packages/server/package.json index 3b249a65b..dbf7d3c65 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -111,4 +111,4 @@ "node": "^20.16.0", "pnpm": ">=9.12.0" } -} \ No newline at end of file +} diff --git a/packages/server/src/db/drizzle.config.ts b/packages/server/src/db/drizzle.config.ts new file mode 100644 index 000000000..60a3bb937 --- /dev/null +++ b/packages/server/src/db/drizzle.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + schema: "./server/db/schema/index.ts", + dialect: "postgresql", + dbCredentials: { + url: process.env.DATABASE_URL!, + }, + out: "drizzle", + migrations: { + table: "migrations", + schema: "public", + }, +}); diff --git a/packages/server/src/db/migration.ts b/packages/server/src/db/migration.ts new file mode 100644 index 000000000..6fada0833 --- /dev/null +++ b/packages/server/src/db/migration.ts @@ -0,0 +1,21 @@ +// import { drizzle } from "drizzle-orm/postgres-js"; +// import { migrate } from "drizzle-orm/postgres-js/migrator"; +// import postgres from "postgres"; + +// const connectionString = process.env.DATABASE_URL!; + +// const sql = postgres(connectionString, { max: 1 }); +// const db = drizzle(sql); + +// export const migration = async () => +// await migrate(db, { migrationsFolder: "drizzle" }) +// .then(() => { +// console.log("Migration complete"); +// sql.end(); +// }) +// .catch((error) => { +// console.log("Migration failed", error); +// }) +// .finally(() => { +// sql.end(); +// }); diff --git a/packages/server/src/db/reset.ts b/packages/server/src/db/reset.ts new file mode 100644 index 000000000..c22291478 --- /dev/null +++ b/packages/server/src/db/reset.ts @@ -0,0 +1,23 @@ +import { sql } from "drizzle-orm"; +// Credits to Louistiti from Drizzle Discord: https://discord.com/channels/1043890932593987624/1130802621750448160/1143083373535973406 +import { drizzle } from "drizzle-orm/postgres-js"; +import postgres from "postgres"; + +const connectionString = process.env.DATABASE_URL!; + +const pg = postgres(connectionString, { max: 1 }); +const db = drizzle(pg); + +const clearDb = async (): Promise => { + try { + const tablesQuery = sql`DROP SCHEMA public CASCADE; CREATE SCHEMA public; DROP schema drizzle CASCADE;`; + const tables = await db.execute(tablesQuery); + console.log(tables); + await pg.end(); + } catch (error) { + console.error("Error cleaning database", error); + } finally { + } +}; + +clearDb(); diff --git a/packages/server/src/db/seed.ts b/packages/server/src/db/seed.ts new file mode 100644 index 000000000..7e2736b00 --- /dev/null +++ b/packages/server/src/db/seed.ts @@ -0,0 +1,35 @@ +// import bc from "bcrypt"; +// import { drizzle } from "drizzle-orm/postgres-js"; +// import postgres from "postgres"; +// import { users } from "./schema"; + +// const connectionString = process.env.DATABASE_URL!; + +// const pg = postgres(connectionString, { max: 1 }); +// const db = drizzle(pg); + +// function password(txt: string) { +// return bc.hashSync(txt, 10); +// } + +// async function seed() { +// console.log("> Seed:", process.env.DATABASE_PATH, "\n"); + +// // const authenticationR = await db +// // .insert(users) +// // .values([ +// // { +// // email: "user1@hotmail.com", +// // password: password("12345671"), +// // }, +// // ]) +// // .onConflictDoNothing() +// // .returning(); + +// // console.log("\nSemillas Update:", authenticationR.length); +// } + +// seed().catch((e) => { +// console.error(e); +// process.exit(1); +// }); From 8a1e36cc3b813a0066b8c73d4411ec80ed149ed6 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:26:05 -0600 Subject: [PATCH 46/49] feat(settings): add user subscription check to dashboard layout --- .../components/layouts/dashboard-layout.tsx | 11 ++++++++++- apps/dokploy/server/api/routers/settings.ts | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/layouts/dashboard-layout.tsx b/apps/dokploy/components/layouts/dashboard-layout.tsx index b4832b4b3..b65e7dbb8 100644 --- a/apps/dokploy/components/layouts/dashboard-layout.tsx +++ b/apps/dokploy/components/layouts/dashboard-layout.tsx @@ -11,11 +11,20 @@ interface Props { export const DashboardLayout = ({ children }: Props) => { const { data: haveRootAccess } = api.user.haveRootAccess.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery(); + const { data: isUserSubscribed } = api.settings.isUserSubscribed.useQuery( + undefined, + { + enabled: isCloud === true, + refetchOnWindowFocus: false, + refetchOnMount: false, + refetchOnReconnect: false, + }, + ); return ( <> {children} - {isCloud === true && ( + {isCloud === true && isUserSubscribed === true && ( )} diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index 7ae0b6e85..e6a15af24 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -45,7 +45,7 @@ import { } from "@dokploy/server"; import { generateOpenApiDocument } from "@dokploy/trpc-openapi"; import { TRPCError } from "@trpc/server"; -import { sql } from "drizzle-orm"; +import { eq, sql } from "drizzle-orm"; import { dump, load } from "js-yaml"; import { scheduledJobs, scheduleJob } from "node-schedule"; import { z } from "zod"; @@ -60,6 +60,8 @@ import { apiServerSchema, apiTraefikConfig, apiUpdateDockerCleanup, + projects, + server, } from "@/server/db/schema"; import { removeJob, schedule } from "@/server/utils/backup"; import packageInfo from "../../../package.json"; @@ -706,6 +708,18 @@ export const settingsRouter = createTRPCRouter({ isCloud: publicProcedure.query(async () => { return IS_CLOUD; }), + isUserSubscribed: publicProcedure.query(async ({ ctx }) => { + const haveServers = await db.query.server.findMany({ + where: eq(server.organizationId, ctx.session?.activeOrganizationId || ""), + }); + const haveProjects = await db.query.projects.findMany({ + where: eq( + projects.organizationId, + ctx.session?.activeOrganizationId || "", + ), + }); + return haveServers.length > 0 || haveProjects.length > 0; + }), health: publicProcedure.query(async () => { if (IS_CLOUD) { try { From 44ae4df1511dd49eb601ffd442ed6f959854e22b Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:27:47 -0600 Subject: [PATCH 47/49] fix(settings): change user subscription query to protected procedure --- apps/dokploy/server/api/routers/settings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index e6a15af24..02678b990 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -708,7 +708,7 @@ export const settingsRouter = createTRPCRouter({ isCloud: publicProcedure.query(async () => { return IS_CLOUD; }), - isUserSubscribed: publicProcedure.query(async ({ ctx }) => { + isUserSubscribed: protectedProcedure.query(async ({ ctx }) => { const haveServers = await db.query.server.findMany({ where: eq(server.organizationId, ctx.session?.activeOrganizationId || ""), }); From d922568510d8ef377cdbfde2b9e93636dd47aeb9 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:42:21 -0600 Subject: [PATCH 48/49] fix(redis): return newRedis object instead of true in redis router --- apps/dokploy/server/api/routers/redis.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/server/api/routers/redis.ts b/apps/dokploy/server/api/routers/redis.ts index a403f8768..ad1ade43d 100644 --- a/apps/dokploy/server/api/routers/redis.ts +++ b/apps/dokploy/server/api/routers/redis.ts @@ -80,7 +80,7 @@ export const redisRouter = createTRPCRouter({ type: "volume", }); - return true; + return newRedis; } catch (error) { throw error; } From d6a0585baeb9be7f8c959d8bff66a64bc009cd90 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 28 Aug 2025 19:03:37 -0600 Subject: [PATCH 49/49] chore(package): update dokploy version to v0.25.0 --- apps/dokploy/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index b919554e8..66d9f7edd 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -1,6 +1,6 @@ { "name": "dokploy", - "version": "v0.24.12", + "version": "v0.25.0", "private": true, "license": "Apache-2.0", "type": "module",