From c04bf3c7e03a09fd840bbbf5cb1c5dd62a0e4d9c Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 9 Feb 2025 18:19:21 -0600 Subject: [PATCH 01/89] feat: add migration --- apps/dokploy/drizzle/0066_broad_marrow.sql | 255 + apps/dokploy/drizzle/meta/0066_snapshot.json | 4686 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + apps/dokploy/lib/auth.ts | 4 + apps/dokploy/package.json | 1 + apps/dokploy/pages/api/auth/[...all].ts | 7 + apps/dokploy/pages/api/stripe/webhook.ts | 368 +- .../pages/dashboard/project/[projectId].tsx | 4 +- apps/dokploy/pages/index.tsx | 74 +- apps/dokploy/server/server.ts | 16 +- packages/server/auth-schema.ts | 62 + packages/server/package.json | 1 + packages/server/src/db/schema/account.ts | 34 + packages/server/src/db/schema/admin.ts | 195 +- packages/server/src/db/schema/auth.ts | 4 +- packages/server/src/db/schema/certificate.ts | 10 +- packages/server/src/db/schema/destination.ts | 11 +- packages/server/src/db/schema/git-provider.ts | 9 +- packages/server/src/db/schema/index.ts | 1 + packages/server/src/db/schema/notification.ts | 9 +- packages/server/src/db/schema/project.ts | 13 +- packages/server/src/db/schema/registry.ts | 13 +- packages/server/src/db/schema/server.ts | 11 +- packages/server/src/db/schema/session.ts | 16 +- packages/server/src/db/schema/ssh-key.ts | 11 +- packages/server/src/db/schema/user.ts | 117 +- packages/server/src/index.ts | 2 + packages/server/src/lib/auth.ts | 14 + packages/server/src/services/admin.ts | 4 +- .../server/src/utils/access-log/handler.ts | 65 +- pnpm-lock.yaml | 206 +- 31 files changed, 5790 insertions(+), 440 deletions(-) create mode 100644 apps/dokploy/drizzle/0066_broad_marrow.sql create mode 100644 apps/dokploy/drizzle/meta/0066_snapshot.json create mode 100644 apps/dokploy/lib/auth.ts create mode 100644 apps/dokploy/pages/api/auth/[...all].ts create mode 100644 packages/server/auth-schema.ts create mode 100644 packages/server/src/db/schema/account.ts create mode 100644 packages/server/src/lib/auth.ts diff --git a/apps/dokploy/drizzle/0066_broad_marrow.sql b/apps/dokploy/drizzle/0066_broad_marrow.sql new file mode 100644 index 000000000..f10854144 --- /dev/null +++ b/apps/dokploy/drizzle/0066_broad_marrow.sql @@ -0,0 +1,255 @@ +CREATE TABLE "account" ( + "id" text PRIMARY KEY NOT NULL, + "account_id" text NOT NULL, + "provider_id" text NOT NULL, + "user_id" text NOT NULL, + "access_token" text, + "refresh_token" text, + "id_token" text, + "access_token_expires_at" timestamp, + "refresh_token_expires_at" timestamp, + "scope" text, + "password" text, + "is2FAEnabled" boolean DEFAULT false NOT NULL, + "created_at" timestamp NOT NULL, + "updated_at" timestamp NOT NULL, + "resetPasswordToken" text, + "resetPasswordExpiresAt" text, + "confirmationToken" text, + "confirmationExpiresAt" text +); + +--> statement-breakpoint +CREATE TABLE "verification" ( + "id" text PRIMARY KEY NOT NULL, + "identifier" text NOT NULL, + "value" text NOT NULL, + "expires_at" timestamp NOT NULL, + "created_at" timestamp, + "updated_at" timestamp +); + +-- Primero eliminar las restricciones NOT NULL y foreign keys +ALTER TABLE "user" ALTER COLUMN "adminId" DROP NOT NULL; +ALTER TABLE "user" ALTER COLUMN "authId" DROP NOT NULL; + +ALTER TABLE "user" DROP CONSTRAINT IF EXISTS "user_adminId_admin_adminId_fk"; +ALTER TABLE "user" DROP CONSTRAINT IF EXISTS "user_authId_auth_id_fk"; +ALTER TABLE "admin" DROP CONSTRAINT IF EXISTS "admin_authId_auth_id_fk"; +ALTER TABLE "project" DROP CONSTRAINT IF EXISTS "project_adminId_admin_adminId_fk"; +ALTER TABLE "destination" DROP CONSTRAINT IF EXISTS "destination_adminId_admin_adminId_fk"; +ALTER TABLE "certificate" DROP CONSTRAINT IF EXISTS "certificate_adminId_admin_adminId_fk"; +ALTER TABLE "session" DROP CONSTRAINT IF EXISTS "session_user_id_auth_id_fk"; +ALTER TABLE "registry" DROP CONSTRAINT IF EXISTS "registry_adminId_admin_adminId_fk"; +ALTER TABLE "notification" DROP CONSTRAINT IF EXISTS "notification_adminId_admin_adminId_fk"; +ALTER TABLE "ssh-key" DROP CONSTRAINT IF EXISTS "ssh-key_adminId_admin_adminId_fk"; +ALTER TABLE "git_provider" DROP CONSTRAINT IF EXISTS "git_provider_adminId_admin_adminId_fk"; +ALTER TABLE "server" DROP CONSTRAINT IF EXISTS "server_adminId_admin_adminId_fk"; + +-- Luego renombrar las columnas +ALTER TABLE "user" RENAME COLUMN "userId" TO "id"; +ALTER TABLE "project" RENAME COLUMN "adminId" TO "userId"; +ALTER TABLE "destination" RENAME COLUMN "adminId" TO "userId"; +ALTER TABLE "certificate" RENAME COLUMN "adminId" TO "userId"; +ALTER TABLE "registry" RENAME COLUMN "adminId" TO "userId"; +ALTER TABLE "notification" RENAME COLUMN "adminId" TO "userId"; +ALTER TABLE "ssh-key" RENAME COLUMN "adminId" TO "userId"; +ALTER TABLE "git_provider" RENAME COLUMN "adminId" TO "userId"; +ALTER TABLE "server" RENAME COLUMN "adminId" TO "userId"; + +-- Primero agregar todas las columnas sin restricciones +ALTER TABLE "user" ADD COLUMN "name" text; +ALTER TABLE "user" ADD COLUMN "email" text; +ALTER TABLE "user" ADD COLUMN "email_verified" boolean; +ALTER TABLE "user" ADD COLUMN "image" text; +ALTER TABLE "user" ADD COLUMN "role" text; +ALTER TABLE "user" ADD COLUMN "banned" boolean; +ALTER TABLE "user" ADD COLUMN "ban_reason" text; +ALTER TABLE "user" ADD COLUMN "ban_expires" timestamp; +ALTER TABLE "user" ADD COLUMN "updated_at" timestamp; +ALTER TABLE "user" ADD COLUMN "serverIp" text; +ALTER TABLE "user" ADD COLUMN "certificateType" "certificateType" DEFAULT 'none'; +ALTER TABLE "user" ADD COLUMN "host" text; +ALTER TABLE "user" ADD COLUMN "letsEncryptEmail" text; +ALTER TABLE "user" ADD COLUMN "sshPrivateKey" text; +ALTER TABLE "user" ADD COLUMN "enableDockerCleanup" boolean DEFAULT false; +ALTER TABLE "user" ADD COLUMN "enableLogRotation" boolean DEFAULT false; +ALTER TABLE "user" ADD COLUMN "enablePaidFeatures" boolean DEFAULT false; +ALTER TABLE "user" ADD COLUMN "metricsConfig" jsonb DEFAULT '{"server":{"type":"Dokploy","refreshRate":60,"port":4500,"token":"","retentionDays":2,"cronJob":"","urlCallback":"","thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}'; +ALTER TABLE "user" ADD COLUMN "cleanupCacheApplications" boolean DEFAULT false; +ALTER TABLE "user" ADD COLUMN "cleanupCacheOnPreviews" boolean DEFAULT false; +ALTER TABLE "user" ADD COLUMN "cleanupCacheOnCompose" boolean DEFAULT false; + +ALTER TABLE "user" ALTER COLUMN "token" SET DEFAULT ''; +ALTER TABLE "user" ALTER COLUMN "expirationDate" SET DEFAULT CURRENT_TIMESTAMP + INTERVAL '1 year'; +ALTER TABLE "user" ALTER COLUMN "createdAt" SET DEFAULT to_char(CURRENT_TIMESTAMP, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'); + +--> statement-breakpoint +-- Luego actualizar los valores nulos +UPDATE "user" SET token = '' WHERE token IS NULL; +UPDATE "user" SET "expirationDate" = CURRENT_TIMESTAMP + INTERVAL '1 year' WHERE "expirationDate" IS NULL; +UPDATE "user" SET "createdAt" = to_char(CURRENT_TIMESTAMP, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') WHERE "createdAt" IS NULL; +UPDATE "user" SET "name" = '' WHERE "name" IS NULL; +UPDATE "user" SET "email" = COALESCE("email", '') WHERE true; +UPDATE "user" SET "email_verified" = COALESCE("email_verified", false) WHERE true; +UPDATE "user" SET "role" = COALESCE("role", 'user') WHERE true; +UPDATE "user" SET "banned" = COALESCE("banned", false) WHERE true; +UPDATE "user" SET "updated_at" = COALESCE("updated_at", CURRENT_TIMESTAMP) WHERE true; +UPDATE "user" SET "certificateType" = COALESCE("certificateType", 'none') WHERE true; +UPDATE "user" SET "enableDockerCleanup" = COALESCE("enableDockerCleanup", false) WHERE true; +UPDATE "user" SET "enableLogRotation" = COALESCE("enableLogRotation", false) WHERE true; +UPDATE "user" SET "enablePaidFeatures" = COALESCE("enablePaidFeatures", false) WHERE true; +UPDATE "user" SET "metricsConfig" = COALESCE("metricsConfig", '{"server":{"type":"Dokploy","refreshRate":60,"port":4500,"token":"","retentionDays":2,"cronJob":"","urlCallback":"","thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}') WHERE true; +UPDATE "user" SET "cleanupCacheApplications" = COALESCE("cleanupCacheApplications", false) WHERE true; +UPDATE "user" SET "cleanupCacheOnPreviews" = COALESCE("cleanupCacheOnPreviews", false) WHERE true; +UPDATE "user" SET "cleanupCacheOnCompose" = COALESCE("cleanupCacheOnCompose", false) WHERE true; +--> statement-breakpoint + +-- Migrar datos de auth a user +INSERT INTO "user" ( + id, + name, + email, + email_verified, + image, + role, + updated_at +) +SELECT + id, + '' as name, + email, + true as email_verified, + image, + CASE + WHEN rol = 'admin' THEN 'admin' + ELSE 'user' + END as role, + CAST("createdAt" AS timestamp) as updated_at +FROM "auth"; + +-- Migrar datos de admin a user +UPDATE "user" u +SET + "serverIp" = a."serverIp", + "certificateType" = a."certificateType", + "host" = a."host", + "letsEncryptEmail" = a."letsEncryptEmail", + "sshPrivateKey" = a."sshPrivateKey", + "enableDockerCleanup" = a."enableDockerCleanup", + "enableLogRotation" = a."enableLogRotation", + "enablePaidFeatures" = a."enablePaidFeatures", + "metricsConfig" = a."metricsConfig", + "cleanupCacheApplications" = a."cleanupCacheApplications", + "cleanupCacheOnPreviews" = a."cleanupCacheOnPreviews", + "cleanupCacheOnCompose" = a."cleanupCacheOnCompose" +FROM "admin" a +WHERE u.id = a."authId"; + +-- Actualizar referencias en las tablas relacionadas +UPDATE "project" p +SET "userId" = a."authId" +FROM "admin" a +WHERE p."userId" = a."adminId"; + +UPDATE "destination" d +SET "userId" = a."authId" +FROM "admin" a +WHERE d."userId" = a."adminId"; + +UPDATE "certificate" c +SET "userId" = a."authId" +FROM "admin" a +WHERE c."userId" = a."adminId"; + +UPDATE "registry" r +SET "userId" = a."authId" +FROM "admin" a +WHERE r."userId" = a."adminId"; + +UPDATE "notification" n +SET "userId" = a."authId" +FROM "admin" a +WHERE n."userId" = a."adminId"; + +UPDATE "ssh-key" s +SET "userId" = a."authId" +FROM "admin" a +WHERE s."userId" = a."adminId"; + +UPDATE "git_provider" g +SET "userId" = a."authId" +FROM "admin" a +WHERE g."userId" = a."adminId"; + +UPDATE "server" s +SET "userId" = a."authId" +FROM "admin" a +WHERE s."userId" = a."adminId"; + +-- Ahora agregar las restricciones NOT NULL después de migrar los datos +ALTER TABLE "user" ALTER COLUMN "name" SET NOT NULL; +ALTER TABLE "user" ALTER COLUMN "email" SET NOT NULL; +ALTER TABLE "user" ALTER COLUMN "email_verified" SET NOT NULL; +ALTER TABLE "user" ALTER COLUMN "updated_at" SET NOT NULL; +ALTER TABLE "user" ALTER COLUMN "certificateType" SET NOT NULL; +ALTER TABLE "user" ALTER COLUMN "enableDockerCleanup" SET NOT NULL; +ALTER TABLE "user" ALTER COLUMN "enableLogRotation" SET NOT NULL; +ALTER TABLE "user" ALTER COLUMN "enablePaidFeatures" SET NOT NULL; +ALTER TABLE "user" ALTER COLUMN "metricsConfig" SET NOT NULL; +ALTER TABLE "user" ALTER COLUMN "cleanupCacheApplications" SET NOT NULL; +ALTER TABLE "user" ALTER COLUMN "cleanupCacheOnPreviews" SET NOT NULL; +ALTER TABLE "user" ALTER COLUMN "cleanupCacheOnCompose" SET NOT NULL; + +-- Modificar session +ALTER TABLE "session" ALTER COLUMN "expires_at" SET DATA TYPE timestamp; +ALTER TABLE "session" ADD COLUMN "token" text; +ALTER TABLE "session" ADD COLUMN "created_at" timestamp; +ALTER TABLE "session" ADD COLUMN "updated_at" timestamp; +ALTER TABLE "session" ADD COLUMN "ip_address" text; +ALTER TABLE "session" ADD COLUMN "user_agent" text; +ALTER TABLE "session" ADD COLUMN "impersonated_by" text; + +-- Agregar nuevas restricciones después de migrar todos los datos +ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; +ALTER TABLE "project" ADD CONSTRAINT "project_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +ALTER TABLE "destination" ADD CONSTRAINT "destination_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +ALTER TABLE "certificate" ADD CONSTRAINT "certificate_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; +ALTER TABLE "registry" ADD CONSTRAINT "registry_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +ALTER TABLE "notification" ADD CONSTRAINT "notification_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +ALTER TABLE "ssh-key" ADD CONSTRAINT "ssh-key_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +ALTER TABLE "git_provider" ADD CONSTRAINT "git_provider_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +ALTER TABLE "server" ADD CONSTRAINT "server_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; + +-- Agregar restricciones únicas +ALTER TABLE "user" ADD CONSTRAINT "user_email_unique" UNIQUE("email"); +ALTER TABLE "session" ADD CONSTRAINT "session_token_unique" UNIQUE("token"); + +-- Eliminar columnas antiguas +ALTER TABLE "user" DROP COLUMN IF EXISTS "adminId"; +ALTER TABLE "user" DROP COLUMN IF EXISTS "authId"; + +-- Eliminar columnas de admin +ALTER TABLE "admin" DROP COLUMN IF EXISTS "adminId"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "serverIp"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "certificateType"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "host"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "letsEncryptEmail"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "sshPrivateKey"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "enableDockerCleanup"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "enableLogRotation"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "authId"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "createdAt"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "stripeCustomerId"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "stripeSubscriptionId"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "serversQuantity"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "enablePaidFeatures"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "metricsConfig"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "cleanupCacheApplications"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "cleanupCacheOnPreviews"; +ALTER TABLE "admin" DROP COLUMN IF EXISTS "cleanupCacheOnCompose"; + +-- Eliminar tablas antiguas +DROP TABLE IF EXISTS "auth" CASCADE; +DROP TABLE IF EXISTS "admin" CASCADE; diff --git a/apps/dokploy/drizzle/meta/0066_snapshot.json b/apps/dokploy/drizzle/meta/0066_snapshot.json new file mode 100644 index 000000000..8572b47b4 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0066_snapshot.json @@ -0,0 +1,4686 @@ +{ + "id": "e7c50cc6-9e18-47c5-b155-dd31fc8bd774", + "prevId": "1240ec96-1751-4de3-b64f-cef9cb716786", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "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 + }, + "role": { + "name": "role", + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.admin": { + "name": "admin", + "schema": "", + "columns": {}, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resetPasswordToken": { + "name": "resetPasswordToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resetPasswordExpiresAt": { + "name": "resetPasswordExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationToken": { + "name": "confirmationToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationExpiresAt": { + "name": "confirmationExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "project_userId_user_id_fk": { + "name": "project_userId_user_id_fk", + "tableFrom": "project", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "destination_userId_user_id_fk": { + "name": "destination_userId_user_id_fk", + "tableFrom": "destination", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "certificate_userId_user_id_fk": { + "name": "certificate_userId_user_id_fk", + "tableFrom": "certificate", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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": { + "name": "session", + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_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 + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_userId_user_id_fk": { + "name": "registry_userId_user_id_fk", + "tableFrom": "registry", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "notification_slackId_slack_slackId_fk": { + "name": "notification_slackId_slack_slackId_fk", + "tableFrom": "notification", + "tableTo": "slack", + "columnsFrom": [ + "slackId" + ], + "columnsTo": [ + "slackId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_telegramId_telegram_telegramId_fk": { + "name": "notification_telegramId_telegram_telegramId_fk", + "tableFrom": "notification", + "tableTo": "telegram", + "columnsFrom": [ + "telegramId" + ], + "columnsTo": [ + "telegramId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_discordId_discord_discordId_fk": { + "name": "notification_discordId_discord_discordId_fk", + "tableFrom": "notification", + "tableTo": "discord", + "columnsFrom": [ + "discordId" + ], + "columnsTo": [ + "discordId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_emailId_email_emailId_fk": { + "name": "notification_emailId_email_emailId_fk", + "tableFrom": "notification", + "tableTo": "email", + "columnsFrom": [ + "emailId" + ], + "columnsTo": [ + "emailId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_gotifyId_gotify_gotifyId_fk": { + "name": "notification_gotifyId_gotify_gotifyId_fk", + "tableFrom": "notification", + "tableTo": "gotify", + "columnsFrom": [ + "gotifyId" + ], + "columnsTo": [ + "gotifyId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_userId_user_id_fk": { + "name": "notification_userId_user_id_fk", + "tableFrom": "notification", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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 + } + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "ssh-key_userId_user_id_fk": { + "name": "ssh-key_userId_user_id_fk", + "tableFrom": "ssh-key", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "git_provider_userId_user_id_fk": { + "name": "git_provider_userId_user_id_fk", + "tableFrom": "git_provider", + "tableTo": "user", + "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.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 + }, + "userId": { + "name": "userId", + "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_userId_user_id_fk": { + "name": "server_userId_user_id_fk", + "tableFrom": "server", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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.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_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 588d36eb7..8d09d2090 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -463,6 +463,13 @@ "when": 1739087857244, "tag": "0065_daily_zaladane", "breakpoints": true + }, + { + "idx": 66, + "version": "7", + "when": 1739142819089, + "tag": "0066_broad_marrow", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/lib/auth.ts b/apps/dokploy/lib/auth.ts new file mode 100644 index 000000000..d0b50c7e3 --- /dev/null +++ b/apps/dokploy/lib/auth.ts @@ -0,0 +1,4 @@ +import { createAuthClient } from "better-auth/react"; +export const authClient = createAuthClient({ + baseURL: "http://localhost:3000", // the base url of your auth server +}); diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 213c90739..e2a7c4a2b 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -35,6 +35,7 @@ "test": "vitest --config __test__/vitest.config.ts" }, "dependencies": { + "better-auth":"1.1.16", "bl": "6.0.11", "rotating-file-stream": "3.2.3", "qrcode": "^1.5.3", diff --git a/apps/dokploy/pages/api/auth/[...all].ts b/apps/dokploy/pages/api/auth/[...all].ts new file mode 100644 index 000000000..48aa03706 --- /dev/null +++ b/apps/dokploy/pages/api/auth/[...all].ts @@ -0,0 +1,7 @@ +import { auth } from "@dokploy/server/index"; +import { toNodeHandler } from "better-auth/node"; + +// Disallow body parsing, we will parse it manually +export const config = { api: { bodyParser: false } }; + +export default toNodeHandler(auth.handler); diff --git a/apps/dokploy/pages/api/stripe/webhook.ts b/apps/dokploy/pages/api/stripe/webhook.ts index d4599f784..7701ebd98 100644 --- a/apps/dokploy/pages/api/stripe/webhook.ts +++ b/apps/dokploy/pages/api/stripe/webhook.ts @@ -18,224 +18,224 @@ export default async function handler( req: NextApiRequest, res: NextApiResponse, ) { - if (!endpointSecret) { - return res.status(400).send("Webhook Error: Missing Stripe Secret Key"); - } - const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { - apiVersion: "2024-09-30.acacia", - maxNetworkRetries: 3, - }); + // if (!endpointSecret) { + // return res.status(400).send("Webhook Error: Missing Stripe Secret Key"); + // } + // const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { + // apiVersion: "2024-09-30.acacia", + // maxNetworkRetries: 3, + // }); - const buf = await buffer(req); - const sig = req.headers["stripe-signature"] as string; + // const buf = await buffer(req); + // const sig = req.headers["stripe-signature"] as string; - let event: Stripe.Event; + // let event: Stripe.Event; - try { - event = stripe.webhooks.constructEvent(buf, sig, endpointSecret); - } catch (err) { - console.error( - "Webhook signature verification failed.", - err instanceof Error ? err.message : err, - ); - return res.status(400).send("Webhook Error: "); - } + // try { + // event = stripe.webhooks.constructEvent(buf, sig, endpointSecret); + // } catch (err) { + // console.error( + // "Webhook signature verification failed.", + // err instanceof Error ? err.message : err, + // ); + // return res.status(400).send("Webhook Error: "); + // } - const webhooksAllowed = [ - "customer.subscription.created", - "customer.subscription.deleted", - "customer.subscription.updated", - "invoice.payment_succeeded", - "invoice.payment_failed", - "customer.deleted", - "checkout.session.completed", - ]; + // const webhooksAllowed = [ + // "customer.subscription.created", + // "customer.subscription.deleted", + // "customer.subscription.updated", + // "invoice.payment_succeeded", + // "invoice.payment_failed", + // "customer.deleted", + // "checkout.session.completed", + // ]; - if (!webhooksAllowed.includes(event.type)) { - return res.status(400).send("Webhook Error: Invalid Event Type"); - } + // if (!webhooksAllowed.includes(event.type)) { + // return res.status(400).send("Webhook Error: Invalid Event Type"); + // } - switch (event.type) { - case "checkout.session.completed": { - const session = event.data.object as Stripe.Checkout.Session; - const adminId = session?.metadata?.adminId as string; + // switch (event.type) { + // case "checkout.session.completed": { + // const session = event.data.object as Stripe.Checkout.Session; + // const adminId = session?.metadata?.adminId as string; - const subscription = await stripe.subscriptions.retrieve( - session.subscription as string, - ); - await db - .update(admins) - .set({ - stripeCustomerId: session.customer as string, - stripeSubscriptionId: session.subscription as string, - serversQuantity: subscription?.items?.data?.[0]?.quantity ?? 0, - }) - .where(eq(admins.adminId, adminId)) - .returning(); + // const subscription = await stripe.subscriptions.retrieve( + // session.subscription as string, + // ); + // await db + // .update(admins) + // .set({ + // stripeCustomerId: session.customer as string, + // stripeSubscriptionId: session.subscription as string, + // serversQuantity: subscription?.items?.data?.[0]?.quantity ?? 0, + // }) + // .where(eq(admins.adminId, adminId)) + // .returning(); - const admin = await findAdminById(adminId); - if (!admin) { - return res.status(400).send("Webhook Error: Admin not found"); - } - const newServersQuantity = admin.serversQuantity; - await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); - break; - } - case "customer.subscription.created": { - const newSubscription = event.data.object as Stripe.Subscription; + // const admin = await findAdminById(adminId); + // if (!admin) { + // return res.status(400).send("Webhook Error: Admin not found"); + // } + // const newServersQuantity = admin.serversQuantity; + // await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); + // break; + // } + // case "customer.subscription.created": { + // const newSubscription = event.data.object as Stripe.Subscription; - await db - .update(admins) - .set({ - stripeSubscriptionId: newSubscription.id, - stripeCustomerId: newSubscription.customer as string, - }) - .where(eq(admins.stripeCustomerId, newSubscription.customer as string)) - .returning(); + // await db + // .update(admins) + // .set({ + // stripeSubscriptionId: newSubscription.id, + // stripeCustomerId: newSubscription.customer as string, + // }) + // .where(eq(admins.stripeCustomerId, newSubscription.customer as string)) + // .returning(); - break; - } + // break; + // } - case "customer.subscription.deleted": { - const newSubscription = event.data.object as Stripe.Subscription; + // case "customer.subscription.deleted": { + // const newSubscription = event.data.object as Stripe.Subscription; - await db - .update(admins) - .set({ - stripeSubscriptionId: null, - serversQuantity: 0, - }) - .where(eq(admins.stripeCustomerId, newSubscription.customer as string)); + // await db + // .update(admins) + // .set({ + // stripeSubscriptionId: null, + // serversQuantity: 0, + // }) + // .where(eq(admins.stripeCustomerId, newSubscription.customer as string)); - const admin = await findAdminByStripeCustomerId( - newSubscription.customer as string, - ); + // const admin = await findAdminByStripeCustomerId( + // newSubscription.customer as string, + // ); - if (!admin) { - return res.status(400).send("Webhook Error: Admin not found"); - } + // if (!admin) { + // return res.status(400).send("Webhook Error: Admin not found"); + // } - await disableServers(admin.adminId); - break; - } - case "customer.subscription.updated": { - const newSubscription = event.data.object as Stripe.Subscription; + // await disableServers(admin.adminId); + // break; + // } + // case "customer.subscription.updated": { + // const newSubscription = event.data.object as Stripe.Subscription; - const admin = await findAdminByStripeCustomerId( - newSubscription.customer as string, - ); + // const admin = await findAdminByStripeCustomerId( + // newSubscription.customer as string, + // ); - if (!admin) { - return res.status(400).send("Webhook Error: Admin not found"); - } + // if (!admin) { + // return res.status(400).send("Webhook Error: Admin not found"); + // } - if (newSubscription.status === "active") { - await db - .update(admins) - .set({ - serversQuantity: newSubscription?.items?.data?.[0]?.quantity ?? 0, - }) - .where( - eq(admins.stripeCustomerId, newSubscription.customer as string), - ); + // if (newSubscription.status === "active") { + // await db + // .update(admins) + // .set({ + // serversQuantity: newSubscription?.items?.data?.[0]?.quantity ?? 0, + // }) + // .where( + // eq(admins.stripeCustomerId, newSubscription.customer as string), + // ); - const newServersQuantity = admin.serversQuantity; - await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); - } else { - await disableServers(admin.adminId); - await db - .update(admins) - .set({ serversQuantity: 0 }) - .where( - eq(admins.stripeCustomerId, newSubscription.customer as string), - ); - } + // const newServersQuantity = admin.serversQuantity; + // await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); + // } else { + // await disableServers(admin.adminId); + // await db + // .update(admins) + // .set({ serversQuantity: 0 }) + // .where( + // eq(admins.stripeCustomerId, newSubscription.customer as string), + // ); + // } - break; - } - case "invoice.payment_succeeded": { - const newInvoice = event.data.object as Stripe.Invoice; + // break; + // } + // case "invoice.payment_succeeded": { + // const newInvoice = event.data.object as Stripe.Invoice; - const suscription = await stripe.subscriptions.retrieve( - newInvoice.subscription as string, - ); + // const suscription = await stripe.subscriptions.retrieve( + // newInvoice.subscription as string, + // ); - if (suscription.status !== "active") { - console.log( - `Skipping invoice.payment_succeeded for subscription ${suscription.id} with status ${suscription.status}`, - ); - break; - } + // if (suscription.status !== "active") { + // console.log( + // `Skipping invoice.payment_succeeded for subscription ${suscription.id} with status ${suscription.status}`, + // ); + // break; + // } - await db - .update(admins) - .set({ - serversQuantity: suscription?.items?.data?.[0]?.quantity ?? 0, - }) - .where(eq(admins.stripeCustomerId, suscription.customer as string)); + // await db + // .update(admins) + // .set({ + // serversQuantity: suscription?.items?.data?.[0]?.quantity ?? 0, + // }) + // .where(eq(admins.stripeCustomerId, suscription.customer as string)); - const admin = await findAdminByStripeCustomerId( - suscription.customer as string, - ); + // const admin = await findAdminByStripeCustomerId( + // suscription.customer as string, + // ); - if (!admin) { - return res.status(400).send("Webhook Error: Admin not found"); - } - const newServersQuantity = admin.serversQuantity; - await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); - break; - } - case "invoice.payment_failed": { - const newInvoice = event.data.object as Stripe.Invoice; + // if (!admin) { + // return res.status(400).send("Webhook Error: Admin not found"); + // } + // const newServersQuantity = admin.serversQuantity; + // await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); + // break; + // } + // case "invoice.payment_failed": { + // const newInvoice = event.data.object as Stripe.Invoice; - const subscription = await stripe.subscriptions.retrieve( - newInvoice.subscription as string, - ); + // const subscription = await stripe.subscriptions.retrieve( + // newInvoice.subscription as string, + // ); - if (subscription.status !== "active") { - const admin = await findAdminByStripeCustomerId( - newInvoice.customer as string, - ); + // if (subscription.status !== "active") { + // const admin = await findAdminByStripeCustomerId( + // newInvoice.customer as string, + // ); - if (!admin) { - return res.status(400).send("Webhook Error: Admin not found"); - } - await db - .update(admins) - .set({ - serversQuantity: 0, - }) - .where(eq(admins.stripeCustomerId, newInvoice.customer as string)); + // if (!admin) { + // return res.status(400).send("Webhook Error: Admin not found"); + // } + // await db + // .update(admins) + // .set({ + // serversQuantity: 0, + // }) + // .where(eq(admins.stripeCustomerId, newInvoice.customer as string)); - await disableServers(admin.adminId); - } + // await disableServers(admin.adminId); + // } - break; - } + // break; + // } - case "customer.deleted": { - const customer = event.data.object as Stripe.Customer; + // case "customer.deleted": { + // const customer = event.data.object as Stripe.Customer; - const admin = await findAdminByStripeCustomerId(customer.id); - if (!admin) { - return res.status(400).send("Webhook Error: Admin not found"); - } + // const admin = await findAdminByStripeCustomerId(customer.id); + // if (!admin) { + // return res.status(400).send("Webhook Error: Admin not found"); + // } - await disableServers(admin.adminId); - await db - .update(admins) - .set({ - stripeCustomerId: null, - stripeSubscriptionId: null, - serversQuantity: 0, - }) - .where(eq(admins.stripeCustomerId, customer.id)); + // await disableServers(admin.adminId); + // await db + // .update(admins) + // .set({ + // stripeCustomerId: null, + // stripeSubscriptionId: null, + // serversQuantity: 0, + // }) + // .where(eq(admins.stripeCustomerId, customer.id)); - break; - } - default: - console.log(`Unhandled event type: ${event.type}`); - } + // break; + // } + // default: + // console.log(`Unhandled event type: ${event.type}`); + // } return res.status(200).json({ received: true }); } diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index 26317ca92..ea23ad3a8 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -70,9 +70,9 @@ import type { } from "next"; import Head from "next/head"; import { useRouter } from "next/router"; -import { useMemo, useState, type ReactElement } from "react"; -import superjson from "superjson"; +import { type ReactElement, useMemo, useState } from "react"; import { toast } from "sonner"; +import superjson from "superjson"; export type Services = { appName: string; diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 2c5ab0bbd..3aafe9bf9 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -201,51 +201,51 @@ Home.getLayout = (page: ReactElement) => { return {page}; }; export async function getServerSideProps(context: GetServerSidePropsContext) { - if (IS_CLOUD) { - try { - const { user } = await validateRequest(context.req, context.res); + // if (IS_CLOUD) { + // try { + // const { user } = await validateRequest(context.req, context.res); - if (user) { - return { - redirect: { - permanent: true, - destination: "/dashboard/projects", - }, - }; - } - } catch (error) {} + // if (user) { + // return { + // redirect: { + // permanent: true, + // destination: "/dashboard/projects", + // }, + // }; + // } + // } catch (error) {} - return { - props: { - IS_CLOUD: IS_CLOUD, - }, - }; - } - const hasAdmin = await isAdminPresent(); + // return { + // props: { + // IS_CLOUD: IS_CLOUD, + // }, + // }; + // } + // const hasAdmin = await isAdminPresent(); - if (!hasAdmin) { - return { - redirect: { - permanent: true, - destination: "/register", - }, - }; - } + // if (!hasAdmin) { + // return { + // redirect: { + // permanent: true, + // destination: "/register", + // }, + // }; + // } - const { user } = await validateRequest(context.req, context.res); + // const { user } = await validateRequest(context.req, context.res); - if (user) { - return { - redirect: { - permanent: true, - destination: "/dashboard/projects", - }, - }; - } + // if (user) { + // return { + // redirect: { + // permanent: true, + // destination: "/dashboard/projects", + // }, + // }; + // } return { props: { - hasAdmin, + // hasAdmin, }, }; } diff --git a/apps/dokploy/server/server.ts b/apps/dokploy/server/server.ts index c8f53f6f9..a277dc0ac 100644 --- a/apps/dokploy/server/server.ts +++ b/apps/dokploy/server/server.ts @@ -34,14 +34,14 @@ void app.prepare().then(async () => { }); // WEBSOCKET - setupDrawerLogsWebSocketServer(server); - setupDeploymentLogsWebSocketServer(server); - setupDockerContainerLogsWebSocketServer(server); - setupDockerContainerTerminalWebSocketServer(server); - setupTerminalWebSocketServer(server); - if (!IS_CLOUD) { - setupDockerStatsMonitoringSocketServer(server); - } + // setupDrawerLogsWebSocketServer(server); + // setupDeploymentLogsWebSocketServer(server); + // setupDockerContainerLogsWebSocketServer(server); + // setupDockerContainerTerminalWebSocketServer(server); + // setupTerminalWebSocketServer(server); + // if (!IS_CLOUD) { + // setupDockerStatsMonitoringSocketServer(server); + // } if (process.env.NODE_ENV === "production" && !IS_CLOUD) { setupDirectories(); diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts new file mode 100644 index 000000000..8f8be24d9 --- /dev/null +++ b/packages/server/auth-schema.ts @@ -0,0 +1,62 @@ +import { + pgTable, + text, + integer, + timestamp, + boolean, +} from "drizzle-orm/pg-core"; + +export const user = pgTable("user", { + id: text("id").primaryKey(), + name: text("name").notNull(), + email: text("email").notNull().unique(), + emailVerified: boolean("email_verified").notNull(), + image: text("image"), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), + role: text("role"), + banned: boolean("banned"), + banReason: text("ban_reason"), + banExpires: timestamp("ban_expires"), +}); + +export const session = pgTable("session", { + id: text("id").primaryKey(), + expiresAt: timestamp("expires_at").notNull(), + token: text("token").notNull().unique(), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), + ipAddress: text("ip_address"), + userAgent: text("user_agent"), + userId: text("user_id") + .notNull() + .references(() => user.id), + impersonatedBy: text("impersonated_by"), +}); + +// export const account = pgTable("account", { +// id: text("id").primaryKey(), +// accountId: text("account_id").notNull(), +// providerId: text("provider_id").notNull(), +// userId: text("user_id") +// .notNull() +// .references(() => user.id), +// accessToken: text("access_token"), +// refreshToken: text("refresh_token"), +// idToken: text("id_token"), +// accessTokenExpiresAt: timestamp("access_token_expires_at"), +// refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), +// scope: text("scope"), +// password: text("password"), +// createdAt: timestamp("created_at").notNull(), +// updatedAt: timestamp("updated_at").notNull(), +// }); + +// export const verification = pgTable("verification", { +// id: text("id").primaryKey(), +// identifier: text("identifier").notNull(), +// value: text("value").notNull(), +// expiresAt: timestamp("expires_at").notNull(), +// createdAt: timestamp("created_at"), +// updatedAt: timestamp("updated_at"), +// }); diff --git a/packages/server/package.json b/packages/server/package.json index cfff36fe8..228344210 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -28,6 +28,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "better-auth":"1.1.16", "rotating-file-stream": "3.2.3", "@faker-js/faker": "^8.4.1", "@lucia-auth/adapter-drizzle": "1.0.7", diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts new file mode 100644 index 000000000..7117f4a44 --- /dev/null +++ b/packages/server/src/db/schema/account.ts @@ -0,0 +1,34 @@ +import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; +import { users } from "./user"; + +export const account = pgTable("account", { + id: text("id").primaryKey(), + accountId: text("account_id").notNull(), + providerId: text("provider_id").notNull(), + userId: text("user_id") + .notNull() + .references(() => users.id), + accessToken: text("access_token"), + refreshToken: text("refresh_token"), + idToken: text("id_token"), + accessTokenExpiresAt: timestamp("access_token_expires_at"), + refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), + scope: text("scope"), + password: text("password"), + is2FAEnabled: boolean("is2FAEnabled").notNull().default(false), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), + resetPasswordToken: text("resetPasswordToken"), + resetPasswordExpiresAt: text("resetPasswordExpiresAt"), + confirmationToken: text("confirmationToken"), + confirmationExpiresAt: text("confirmationExpiresAt"), +}); + +export const verification = pgTable("verification", { + id: text("id").primaryKey(), + identifier: text("identifier").notNull(), + value: text("value").notNull(), + expiresAt: timestamp("expires_at").notNull(), + createdAt: timestamp("created_at"), + updatedAt: timestamp("updated_at"), +}); diff --git a/packages/server/src/db/schema/admin.ts b/packages/server/src/db/schema/admin.ts index 983f99fd6..c842bd7a3 100644 --- a/packages/server/src/db/schema/admin.ts +++ b/packages/server/src/db/schema/admin.ts @@ -18,128 +18,127 @@ import { sshKeys } from "./ssh-key"; import { users } from "./user"; export const admins = pgTable("admin", { - adminId: text("adminId") - .notNull() - .primaryKey() - .$defaultFn(() => nanoid()), - serverIp: text("serverIp"), - certificateType: certificateType("certificateType").notNull().default("none"), - host: text("host"), - letsEncryptEmail: text("letsEncryptEmail"), - sshPrivateKey: text("sshPrivateKey"), - enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false), - enableLogRotation: boolean("enableLogRotation").notNull().default(false), - authId: text("authId") - .notNull() - .references(() => auth.id, { onDelete: "cascade" }), - createdAt: text("createdAt") - .notNull() - .$defaultFn(() => new Date().toISOString()), - stripeCustomerId: text("stripeCustomerId"), - stripeSubscriptionId: text("stripeSubscriptionId"), - serversQuantity: integer("serversQuantity").notNull().default(0), - - // Metrics - enablePaidFeatures: boolean("enablePaidFeatures").notNull().default(false), - metricsConfig: jsonb("metricsConfig") - .$type<{ - server: { - type: "Dokploy" | "Remote"; - refreshRate: number; - port: number; - token: string; - urlCallback: string; - retentionDays: number; - cronJob: string; - thresholds: { - cpu: number; - memory: number; - }; - }; - containers: { - refreshRate: number; - services: { - include: string[]; - exclude: string[]; - }; - }; - }>() - .notNull() - .default({ - server: { - type: "Dokploy", - refreshRate: 60, - port: 4500, - token: "", - retentionDays: 2, - cronJob: "", - urlCallback: "", - thresholds: { - cpu: 0, - memory: 0, - }, - }, - containers: { - refreshRate: 60, - services: { - include: [], - exclude: [], - }, - }, - }), - cleanupCacheApplications: boolean("cleanupCacheApplications") - .notNull() - .default(false), - cleanupCacheOnPreviews: boolean("cleanupCacheOnPreviews") - .notNull() - .default(false), - cleanupCacheOnCompose: boolean("cleanupCacheOnCompose") - .notNull() - .default(false), + // adminId: text("adminId") + // .notNull() + // .primaryKey() + // .$defaultFn(() => nanoid()), + // serverIp: text("serverIp"), + // certificateType: certificateType("certificateType").notNull().default("none"), + // host: text("host"), + // letsEncryptEmail: text("letsEncryptEmail"), + // sshPrivateKey: text("sshPrivateKey"), + // enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false), + // enableLogRotation: boolean("enableLogRotation").notNull().default(false), + // authId: text("authId") + // .notNull() + // .references(() => auth.id, { onDelete: "cascade" }), + // createdAt: text("createdAt") + // .notNull() + // .$defaultFn(() => new Date().toISOString()), + // stripeCustomerId: text("stripeCustomerId"), + // stripeSubscriptionId: text("stripeSubscriptionId"), + // serversQuantity: integer("serversQuantity").notNull().default(0), + // // Metrics + // enablePaidFeatures: boolean("enablePaidFeatures").notNull().default(false), + // metricsConfig: jsonb("metricsConfig") + // .$type<{ + // server: { + // type: "Dokploy" | "Remote"; + // refreshRate: number; + // port: number; + // token: string; + // urlCallback: string; + // retentionDays: number; + // cronJob: string; + // thresholds: { + // cpu: number; + // memory: number; + // }; + // }; + // containers: { + // refreshRate: number; + // services: { + // include: string[]; + // exclude: string[]; + // }; + // }; + // }>() + // .notNull() + // .default({ + // server: { + // type: "Dokploy", + // refreshRate: 60, + // port: 4500, + // token: "", + // retentionDays: 2, + // cronJob: "", + // urlCallback: "", + // thresholds: { + // cpu: 0, + // memory: 0, + // }, + // }, + // containers: { + // refreshRate: 60, + // services: { + // include: [], + // exclude: [], + // }, + // }, + // }), + // cleanupCacheApplications: boolean("cleanupCacheApplications") + // .notNull() + // .default(false), + // cleanupCacheOnPreviews: boolean("cleanupCacheOnPreviews") + // .notNull() + // .default(false), + // cleanupCacheOnCompose: boolean("cleanupCacheOnCompose") + // .notNull() + // .default(false), }); export const adminsRelations = relations(admins, ({ one, many }) => ({ - auth: one(auth, { - fields: [admins.authId], - references: [auth.id], - }), - users: many(users), - registry: many(registry), - sshKeys: many(sshKeys), - certificates: many(certificates), + // auth: one(auth, { + // fields: [admins.authId], + // references: [auth.id], + // }), + // users: many(users), + // registry: many(registry), + // sshKeys: many(sshKeys), + // certificates: many(certificates), })); const createSchema = createInsertSchema(admins, { - adminId: z.string(), - enableDockerCleanup: z.boolean().optional(), - sshPrivateKey: z.string().optional(), - certificateType: z.enum(["letsencrypt", "none"]).default("none"), - serverIp: z.string().optional(), - letsEncryptEmail: z.string().optional(), + // adminId: z.string(), + // enableDockerCleanup: z.boolean().optional(), + // sshPrivateKey: z.string().optional(), + // certificateType: z.enum(["letsencrypt", "none"]).default("none"), + // serverIp: z.string().optional(), + // letsEncryptEmail: z.string().optional(), }); export const apiUpdateAdmin = createSchema.partial(); export const apiSaveSSHKey = createSchema .pick({ - sshPrivateKey: true, + // sshPrivateKey: true, }) .required(); export const apiAssignDomain = createSchema .pick({ - host: true, - certificateType: true, - letsEncryptEmail: true, + // host: true, + // certificateType: true, + // letsEncryptEmail: true, }) .required() .partial({ - letsEncryptEmail: true, + // letsEncryptEmail: true, }); export const apiUpdateDockerCleanup = createSchema .pick({ - enableDockerCleanup: true, + // enableDockerCleanup: true, }) .required() .extend({ diff --git a/packages/server/src/db/schema/auth.ts b/packages/server/src/db/schema/auth.ts index 3e16c68ee..7093a40c3 100644 --- a/packages/server/src/db/schema/auth.ts +++ b/packages/server/src/db/schema/auth.ts @@ -4,7 +4,7 @@ import { boolean, pgEnum, pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; -import { admins } from "./admin"; +// import { admins } from "./admin"; import { users } from "./user"; const randomImages = [ @@ -55,7 +55,7 @@ export const auth = pgTable("auth", { }); export const authRelations = relations(auth, ({ many }) => ({ - admins: many(admins), + // admins: many(admins), users: many(users), })); const createSchema = createInsertSchema(auth, { diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts index 1df61be86..22f4f9cb7 100644 --- a/packages/server/src/db/schema/certificate.ts +++ b/packages/server/src/db/schema/certificate.ts @@ -3,9 +3,9 @@ import { boolean, pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; -import { admins } from "./admin"; import { server } from "./server"; import { generateAppName } from "./utils"; +import { users } from "./user"; export const certificates = pgTable("certificate", { certificateId: text("certificateId") @@ -20,7 +20,7 @@ export const certificates = pgTable("certificate", { .$defaultFn(() => generateAppName("certificate")) .unique(), autoRenew: boolean("autoRenew"), - adminId: text("adminId").references(() => admins.adminId, { + userId: text("userId").references(() => users.id, { onDelete: "cascade", }), serverId: text("serverId").references(() => server.serverId, { @@ -35,9 +35,9 @@ export const certificatesRelations = relations( fields: [certificates.serverId], references: [server.serverId], }), - admin: one(admins, { - fields: [certificates.adminId], - references: [admins.adminId], + user: one(users, { + fields: [certificates.userId], + references: [users.id], }), }), ); diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts index 7d7be6141..c89ed1e37 100644 --- a/packages/server/src/db/schema/destination.ts +++ b/packages/server/src/db/schema/destination.ts @@ -5,6 +5,7 @@ import { nanoid } from "nanoid"; import { z } from "zod"; import { admins } from "./admin"; import { backups } from "./backups"; +import { users } from "./user"; export const destinations = pgTable("destination", { destinationId: text("destinationId") @@ -19,18 +20,18 @@ export const destinations = pgTable("destination", { region: text("region").notNull(), // maybe it can be null endpoint: text("endpoint").notNull(), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users.id, { onDelete: "cascade" }), }); export const destinationsRelations = relations( destinations, ({ many, one }) => ({ backups: many(backups), - admin: one(admins, { - fields: [destinations.adminId], - references: [admins.adminId], + user: one(users, { + fields: [destinations.userId], + references: [users.id], }), }), ); diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index dbbfc183b..00dc928d4 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -7,6 +7,7 @@ import { admins } from "./admin"; import { bitbucket } from "./bitbucket"; import { github } from "./github"; import { gitlab } from "./gitlab"; +import { users } from "./user"; export const gitProviderType = pgEnum("gitProviderType", [ "github", @@ -24,7 +25,7 @@ export const gitProvider = pgTable("git_provider", { createdAt: text("createdAt") .notNull() .$defaultFn(() => new Date().toISOString()), - adminId: text("adminId").references(() => admins.adminId, { + userId: text("userId").references(() => users.id, { onDelete: "cascade", }), }); @@ -42,9 +43,9 @@ export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ fields: [gitProvider.gitProviderId], references: [bitbucket.gitProviderId], }), - admin: one(admins, { - fields: [gitProvider.adminId], - references: [admins.adminId], + user: one(users, { + fields: [gitProvider.userId], + references: [users.id], }), })); diff --git a/packages/server/src/db/schema/index.ts b/packages/server/src/db/schema/index.ts index 9c7a079c5..405fa383b 100644 --- a/packages/server/src/db/schema/index.ts +++ b/packages/server/src/db/schema/index.ts @@ -30,3 +30,4 @@ export * from "./gitlab"; export * from "./server"; export * from "./utils"; export * from "./preview-deployments"; +export * from "./account"; diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 73d22e1cc..4b7a09eac 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -4,6 +4,7 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { admins } from "./admin"; +import { users } from "./user"; export const notificationType = pgEnum("notificationType", [ "slack", @@ -44,7 +45,7 @@ export const notifications = pgTable("notification", { gotifyId: text("gotifyId").references(() => gotify.gotifyId, { onDelete: "cascade", }), - adminId: text("adminId").references(() => admins.adminId, { + userId: text("userId").references(() => users.id, { onDelete: "cascade", }), }); @@ -121,9 +122,9 @@ export const notificationsRelations = relations(notifications, ({ one }) => ({ fields: [notifications.gotifyId], references: [gotify.gotifyId], }), - admin: one(admins, { - fields: [notifications.adminId], - references: [admins.adminId], + user: one(users, { + fields: [notifications.userId], + references: [users.id], }), })); diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index 7ed140d6f..440368383 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -4,7 +4,7 @@ import { pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; -import { admins } from "./admin"; +// import { admins } from "./admin"; import { applications } from "./application"; import { compose } from "./compose"; import { mariadb } from "./mariadb"; @@ -12,6 +12,7 @@ import { mongo } from "./mongo"; import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; +import { users } from "./user"; export const projects = pgTable("project", { projectId: text("projectId") @@ -23,9 +24,9 @@ export const projects = pgTable("project", { createdAt: text("createdAt") .notNull() .$defaultFn(() => new Date().toISOString()), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users.id, { onDelete: "cascade" }), env: text("env").notNull().default(""), }); @@ -37,9 +38,9 @@ export const projectRelations = relations(projects, ({ many, one }) => ({ mongo: many(mongo), redis: many(redis), compose: many(compose), - admin: one(admins, { - fields: [projects.adminId], - references: [admins.adminId], + user: one(users, { + fields: [projects.userId], + references: [users.id], }), })); diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index 20544a587..d1f790686 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -5,6 +5,7 @@ import { nanoid } from "nanoid"; import { z } from "zod"; import { admins } from "./admin"; import { applications } from "./application"; +import { users } from "./user"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * database instance for multiple projects. @@ -27,15 +28,15 @@ export const registry = pgTable("registry", { .notNull() .$defaultFn(() => new Date().toISOString()), registryType: registryType("selfHosted").notNull().default("cloud"), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users.id, { onDelete: "cascade" }), }); export const registryRelations = relations(registry, ({ one, many }) => ({ - admin: one(admins, { - fields: [registry.adminId], - references: [admins.adminId], + user: one(users, { + fields: [registry.userId], + references: [users.id], }), applications: many(applications), })); @@ -45,7 +46,7 @@ const createSchema = createInsertSchema(registry, { username: z.string().min(1), password: z.string().min(1), registryUrl: z.string(), - adminId: z.string().min(1), + userId: z.string().min(1), registryId: z.string().min(1), registryType: z.enum(["cloud"]), imagePrefix: z.string().nullable().optional(), diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index c4ec6a09f..71d6ca080 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -23,6 +23,7 @@ import { postgres } from "./postgres"; import { redis } from "./redis"; import { sshKeys } from "./ssh-key"; import { generateAppName } from "./utils"; +import { users } from "./user"; export const serverStatus = pgEnum("serverStatus", ["active", "inactive"]); @@ -43,9 +44,9 @@ export const server = pgTable("server", { createdAt: text("createdAt") .notNull() .$defaultFn(() => new Date().toISOString()), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users.id, { onDelete: "cascade" }), serverStatus: serverStatus("serverStatus").notNull().default("active"), command: text("command").notNull().default(""), sshKeyId: text("sshKeyId").references(() => sshKeys.sshKeyId, { @@ -100,9 +101,9 @@ export const server = pgTable("server", { }); export const serverRelations = relations(server, ({ one, many }) => ({ - admin: one(admins, { - fields: [server.adminId], - references: [admins.adminId], + user: one(users, { + fields: [server.userId], + references: [users.id], }), deployments: many(deployments), sshKey: one(sshKeys, { diff --git a/packages/server/src/db/schema/session.ts b/packages/server/src/db/schema/session.ts index 1b6d8cc17..396e81949 100644 --- a/packages/server/src/db/schema/session.ts +++ b/packages/server/src/db/schema/session.ts @@ -1,13 +1,17 @@ import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; -import { auth } from "./auth"; +import { users } from "./user"; +// OLD TABLE export const sessionTable = pgTable("session", { id: text("id").primaryKey(), + expiresAt: timestamp("expires_at").notNull(), + token: text("token").notNull().unique(), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), + ipAddress: text("ip_address"), + userAgent: text("user_agent"), userId: text("user_id") .notNull() - .references(() => auth.id, { onDelete: "cascade" }), - expiresAt: timestamp("expires_at", { - withTimezone: true, - mode: "date", - }).notNull(), + .references(() => users.id), + impersonatedBy: text("impersonated_by"), }); diff --git a/packages/server/src/db/schema/ssh-key.ts b/packages/server/src/db/schema/ssh-key.ts index e4842851b..7a4f50613 100644 --- a/packages/server/src/db/schema/ssh-key.ts +++ b/packages/server/src/db/schema/ssh-key.ts @@ -7,6 +7,7 @@ import { admins } from "./admin"; import { applications } from "./application"; import { compose } from "./compose"; import { server } from "./server"; +import { users } from "./user"; export const sshKeys = pgTable("ssh-key", { sshKeyId: text("sshKeyId") @@ -21,7 +22,7 @@ export const sshKeys = pgTable("ssh-key", { .notNull() .$defaultFn(() => new Date().toISOString()), lastUsedAt: text("lastUsedAt"), - adminId: text("adminId").references(() => admins.adminId, { + userId: text("userId").references(() => users.id, { onDelete: "cascade", }), }); @@ -30,9 +31,9 @@ export const sshKeysRelations = relations(sshKeys, ({ many, one }) => ({ applications: many(applications), compose: many(compose), servers: many(server), - admin: one(admins, { - fields: [sshKeys.adminId], - references: [admins.adminId], + user: one(users, { + fields: [sshKeys.userId], + references: [users.id], }), })); @@ -48,7 +49,7 @@ export const apiCreateSshKey = createSchema description: true, privateKey: true, publicKey: true, - adminId: true, + userId: true, }) .merge(sshKeyCreate.pick({ privateKey: true })); diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 735898f9a..473cf1907 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -1,10 +1,11 @@ import { relations, sql } from "drizzle-orm"; -import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; +import { boolean, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { admins } from "./admin"; import { auth } from "./auth"; +import { certificateType } from "./shared"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * database instance for multiple projects. @@ -12,12 +13,13 @@ import { auth } from "./auth"; * @see https://orm.drizzle.team/docs/goodies#multi-project-schema */ +// OLD TABLE export const users = pgTable("user", { - userId: text("userId") + id: text("id") .notNull() .primaryKey() .$defaultFn(() => nanoid()), - + name: text("name").notNull().default(""), token: text("token").notNull(), isRegistered: boolean("isRegistered").notNull().default(false), expirationDate: timestamp("expirationDate", { @@ -48,31 +50,102 @@ export const users = pgTable("user", { .array() .notNull() .default(sql`ARRAY[]::text[]`), - adminId: text("adminId") + // authId: text("authId") + // .notNull() + // .references(() => auth.id, { onDelete: "cascade" }), + // Auth + email: text("email").notNull().unique(), + emailVerified: boolean("email_verified").notNull(), + image: text("image"), + role: text("role"), + banned: boolean("banned"), + banReason: text("ban_reason"), + banExpires: timestamp("ban_expires"), + updatedAt: timestamp("updated_at").notNull(), + // Admin + serverIp: text("serverIp"), + certificateType: certificateType("certificateType").notNull().default("none"), + host: text("host"), + letsEncryptEmail: text("letsEncryptEmail"), + sshPrivateKey: text("sshPrivateKey"), + enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false), + enableLogRotation: boolean("enableLogRotation").notNull().default(false), + // Metrics + enablePaidFeatures: boolean("enablePaidFeatures").notNull().default(false), + metricsConfig: jsonb("metricsConfig") + .$type<{ + server: { + type: "Dokploy" | "Remote"; + refreshRate: number; + port: number; + token: string; + urlCallback: string; + retentionDays: number; + cronJob: string; + thresholds: { + cpu: number; + memory: number; + }; + }; + containers: { + refreshRate: number; + services: { + include: string[]; + exclude: string[]; + }; + }; + }>() .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), - authId: text("authId") + .default({ + server: { + type: "Dokploy", + refreshRate: 60, + port: 4500, + token: "", + retentionDays: 2, + cronJob: "", + urlCallback: "", + thresholds: { + cpu: 0, + memory: 0, + }, + }, + containers: { + refreshRate: 60, + services: { + include: [], + exclude: [], + }, + }, + }), + cleanupCacheApplications: boolean("cleanupCacheApplications") .notNull() - .references(() => auth.id, { onDelete: "cascade" }), + .default(false), + cleanupCacheOnPreviews: boolean("cleanupCacheOnPreviews") + .notNull() + .default(false), + cleanupCacheOnCompose: boolean("cleanupCacheOnCompose") + .notNull() + .default(false), }); export const usersRelations = relations(users, ({ one }) => ({ - auth: one(auth, { - fields: [users.authId], - references: [auth.id], - }), - admin: one(admins, { - fields: [users.adminId], - references: [admins.adminId], - }), + // auth: one(auth, { + // fields: [users.authId], + // references: [auth.id], + // }), + // admin: one(admins, { + // fields: [users.adminId], + // references: [admins.adminId], + // }), })); const createSchema = createInsertSchema(users, { - userId: z.string().min(1), - authId: z.string().min(1), + id: z.string().min(1), + // authId: z.string().min(1), token: z.string().min(1), isRegistered: z.boolean().optional(), - adminId: z.string(), + // adminId: z.string(), accessedProjects: z.array(z.string()).optional(), accessedServices: z.array(z.string()).optional(), canCreateProjects: z.boolean().optional(), @@ -89,7 +162,7 @@ export const apiCreateUserInvitation = createSchema.pick({}).extend({ export const apiRemoveUser = createSchema .pick({ - authId: true, + // authId: true, }) .required(); @@ -101,7 +174,7 @@ export const apiFindOneToken = createSchema export const apiAssignPermissions = createSchema .pick({ - userId: true, + id: true, canCreateProjects: true, canCreateServices: true, canDeleteProjects: true, @@ -118,12 +191,12 @@ export const apiAssignPermissions = createSchema export const apiFindOneUser = createSchema .pick({ - userId: true, + id: true, }) .required(); export const apiFindOneUserByAuth = createSchema .pick({ - authId: true, + // authId: true, }) .required(); diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 71549a388..345849ed9 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -118,3 +118,5 @@ export * from "./monitoring/utils"; export * from "./db/validations/domain"; export * from "./db/validations/index"; export * from "./utils/gpu-setup"; + +export * from "./lib/auth"; diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts new file mode 100644 index 000000000..fada2c434 --- /dev/null +++ b/packages/server/src/lib/auth.ts @@ -0,0 +1,14 @@ +import { betterAuth } from "better-auth"; +import { drizzleAdapter } from "better-auth/adapters/drizzle"; +import { admin } from "better-auth/plugins"; +import { db } from "../db"; + +export const auth = betterAuth({ + database: drizzleAdapter(db, { + provider: "pg", + }), + emailAndPassword: { + enabled: true, + }, + plugins: [admin()], +}); diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index b6d9c7fb4..056b81785 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -94,7 +94,9 @@ export const updateAdminById = async ( }; export const isAdminPresent = async () => { - const admin = await db.query.admins.findFirst(); + const admin = await db.query.users.findFirst({ + where: eq(users.role, "admin"), + }); if (!admin) { return false; } diff --git a/packages/server/src/utils/access-log/handler.ts b/packages/server/src/utils/access-log/handler.ts index b1fd925c6..668855144 100644 --- a/packages/server/src/utils/access-log/handler.ts +++ b/packages/server/src/utils/access-log/handler.ts @@ -23,27 +23,27 @@ class LogRotationManager { } private async initialize(): Promise { - const isActive = await this.getStateFromDB(); - if (isActive) { - await this.activateStream(); - } + // const isActive = await this.getStateFromDB(); + // if (isActive) { + // await this.activateStream(); + // } } - private async getStateFromDB(): Promise { - const setting = await db.query.admins.findFirst({}); - return setting?.enableLogRotation ?? false; - } + // private async getStateFromDB(): Promise { + // const setting = await db.query.admins.findFirst({}); + // return setting?.enableLogRotation ?? false; + // } - private async setStateInDB(active: boolean): Promise { - const admin = await db.query.admins.findFirst({}); + // private async setStateInDB(active: boolean): Promise { + // const admin = await db.query.admins.findFirst({}); - if (!admin) { - return; - } - await updateAdmin(admin?.authId, { - enableLogRotation: active, - }); - } + // if (!admin) { + // return; + // } + // await updateAdmin(admin?.authId, { + // enableLogRotation: active, + // }); + // } private async activateStream(): Promise { const { DYNAMIC_TRAEFIK_PATH } = paths(); @@ -76,26 +76,26 @@ class LogRotationManager { } public async activate(): Promise { - const currentState = await this.getStateFromDB(); - if (currentState) { - return true; - } + // const currentState = await this.getStateFromDB(); + // if (currentState) { + // return true; + // } - await this.setStateInDB(true); - await this.activateStream(); + // await this.setStateInDB(true); + // await this.activateStream(); return true; } public async deactivate(): Promise { console.log("Deactivating log rotation..."); - const currentState = await this.getStateFromDB(); - if (!currentState) { - console.log("Log rotation is already inactive in DB"); - return true; - } + // const currentState = await this.getStateFromDB(); + // if (!currentState) { + // console.log("Log rotation is already inactive in DB"); + // return true; + // } - await this.setStateInDB(false); - await this.deactivateStream(); + // await this.setStateInDB(false); + // await this.deactivateStream(); console.log("Log rotation deactivated successfully"); return true; } @@ -115,8 +115,9 @@ class LogRotationManager { } } public async getStatus(): Promise { - const dbState = await this.getStateFromDB(); - return dbState; + // const dbState = await this.getStateFromDB(); + // return dbState; + return false; } } export const logRotationManager = LogRotationManager.getInstance(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2c6514644..555822409 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -238,6 +238,9 @@ importers: bcrypt: specifier: 5.1.1 version: 5.1.1(encoding@0.1.13) + better-auth: + specifier: 1.1.16 + version: 1.1.16 bl: specifier: 6.0.11 version: 6.0.11 @@ -273,10 +276,10 @@ importers: version: 16.4.5 drizzle-orm: specifier: ^0.39.1 - version: 0.39.1(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7) + version: 0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7) drizzle-zod: specifier: 0.5.1 - version: 0.5.1(drizzle-orm@0.39.1(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7))(zod@3.23.8) + version: 0.5.1(drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7))(zod@3.23.8) fancy-ansi: specifier: ^0.1.3 version: 0.1.3 @@ -505,7 +508,7 @@ importers: version: 16.4.5 drizzle-orm: specifier: ^0.39.1 - version: 0.39.1(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7) + version: 0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7) hono: specifier: ^4.5.8 version: 4.5.8 @@ -567,6 +570,9 @@ importers: bcrypt: specifier: 5.1.1 version: 5.1.1(encoding@0.1.13) + better-auth: + specifier: 1.1.16 + version: 1.1.16 bl: specifier: 6.0.11 version: 6.0.11 @@ -584,10 +590,10 @@ importers: version: 16.4.5 drizzle-orm: specifier: ^0.39.1 - version: 0.39.1(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7) + version: 0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7) drizzle-zod: specifier: 0.5.1 - version: 0.5.1(drizzle-orm@0.39.1(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7))(zod@3.23.8) + version: 0.5.1(drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7))(zod@3.23.8) hi-base32: specifier: ^0.5.1 version: 0.5.1 @@ -748,6 +754,12 @@ packages: '@balena/dockerignore@1.0.2': resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} + '@better-auth/utils@0.2.3': + resolution: {integrity: sha512-Ap1GaSmo6JYhJhxJOpUB0HobkKPTNzfta+bLV89HfpyCAHN7p8ntCrmNFHNAVD0F6v0mywFVEUg1FUhNCc81Rw==} + + '@better-fetch/fetch@1.1.12': + resolution: {integrity: sha512-B3bfloI/2UBQWIATRN6qmlORrvx3Mp0kkNjmXLv0b+DtbtR+pP4/I5kQA/rDUv+OReLywCCldf6co4LdDmh8JA==} + '@biomejs/biome@1.9.4': resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} engines: {node: '>=14.21.3'} @@ -1518,6 +1530,9 @@ packages: '@hapi/bourne@3.0.0': resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==} + '@hexagon/base64@1.1.28': + resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} + '@hono/node-server@1.12.1': resolution: {integrity: sha512-C9l+08O8xtXB7Ppmy8DjBFH1hYji7JKzsU32Yt1poIIbdPp6S7aOI8IldDHD9YFJ55lv2c21ovNrmxatlHfhAg==} engines: {node: '>=18.14.1'} @@ -1697,6 +1712,9 @@ packages: '@leichtgewicht/ip-codec@2.0.5': resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} + '@levischuck/tiny-cbor@0.2.11': + resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==} + '@lezer/common@1.2.1': resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==} @@ -1807,10 +1825,17 @@ packages: cpu: [x64] os: [win32] + '@noble/ciphers@0.6.0': + resolution: {integrity: sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ==} + '@noble/hashes@1.5.0': resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==} engines: {node: ^14.21.3 || >=16} + '@noble/hashes@1.7.1': + resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} + engines: {node: ^14.21.3 || >=16} + '@node-rs/argon2-android-arm-eabi@1.7.0': resolution: {integrity: sha512-udDqkr5P9E+wYX1SZwAVPdyfYvaF4ry9Tm+R9LkfSHbzWH0uhU6zjIwNRp7m+n4gx691rk+lqqDAIP8RLKwbhg==} engines: {node: '>= 10'} @@ -2136,6 +2161,21 @@ packages: '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@peculiar/asn1-android@2.3.15': + resolution: {integrity: sha512-8U2TIj59cRlSXTX2d0mzUKP7whfWGFMzTeC3qPgAbccXFrPNZLaDhpNEdG5U2QZ/tBv/IHlCJ8s+KYXpJeop6w==} + + '@peculiar/asn1-ecc@2.3.15': + resolution: {integrity: sha512-/HtR91dvgog7z/WhCVdxZJ/jitJuIu8iTqiyWVgRE9Ac5imt2sT/E4obqIVGKQw7PIy+X6i8lVBoT6wC73XUgA==} + + '@peculiar/asn1-rsa@2.3.15': + resolution: {integrity: sha512-p6hsanvPhexRtYSOHihLvUUgrJ8y0FtOM97N5UEpC+VifFYyZa0iZ5cXjTkZoDwxJ/TTJ1IJo3HVTB2JJTpXvg==} + + '@peculiar/asn1-schema@2.3.15': + resolution: {integrity: sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==} + + '@peculiar/asn1-x509@2.3.15': + resolution: {integrity: sha512-0dK5xqTqSLaxv1FHXIcd4Q/BZNuopg+u1l23hT9rOmQ1g4dNtw0g/RnEi+TboB0gOwGtrWn269v27cMgchFIIg==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -3147,6 +3187,13 @@ packages: '@selderee/plugin-htmlparser2@0.11.0': resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} + '@simplewebauthn/browser@13.1.0': + resolution: {integrity: sha512-WuHZ/PYvyPJ9nxSzgHtOEjogBhwJfC8xzYkPC+rR/+8chl/ft4ngjiK8kSU5HtRJfczupyOh33b25TjYbvwAcg==} + + '@simplewebauthn/server@13.1.1': + resolution: {integrity: sha512-1hsLpRHfSuMB9ee2aAdh0Htza/X3f4djhYISrggqGe3xopNjOcePiSDkDDoPzDYaaMCrbqGP1H2TYU7bgL9PmA==} + engines: {node: '>=20.0.0'} + '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -3762,6 +3809,10 @@ packages: asn1@0.2.6: resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + asn1js@3.0.5: + resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==} + engines: {node: '>=12.0.0'} + assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} @@ -3804,6 +3855,12 @@ packages: before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + better-auth@1.1.16: + resolution: {integrity: sha512-Xc5pxafKZw4QVU8WYfkV2z4Hd8KCXXbphrgOpe2gA/EfanysLBhE1G/F7cEi5e0bW2pGR+vw6gf0ARHA7VFihg==} + + better-call@0.3.3: + resolution: {integrity: sha512-N4lDVm0NGmFfDJ0XMQ4O83Zm/3dPlvIQdxvwvgSLSkjFX5PM4GUYSVAuxNzXN27QZMHDkrJTWUqxBrm4tPC3eA==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -5120,6 +5177,9 @@ packages: resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} hasBin: true + jose@5.9.6: + resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -5223,6 +5283,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kysely@0.27.5: + resolution: {integrity: sha512-s7hZHcQeSNKpzCkHRm8yA+0JPLjncSWnjb+2TIElwS2JAqYr+Kv3Ess+9KFfJS0C1xcQ1i9NkNHpWwCYpHMWsA==} + engines: {node: '>=14.0.0'} + leac@0.6.0: resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} @@ -5608,6 +5672,10 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanostores@0.11.3: + resolution: {integrity: sha512-TUes3xKIX33re4QzdxwZ6tdbodjmn3tWXCEc1uokiEmo14sI1EaGYNs2k3bU2pyyGNmBqFGAVl6jAGWd06AVIg==} + engines: {node: ^18.0.0 || >=20.0.0} + napi-build-utils@1.0.2: resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} @@ -6058,6 +6126,13 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.3: + resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} + engines: {node: '>=6.0.0'} + qrcode@1.5.4: resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} engines: {node: '>=10.13.0'} @@ -6403,6 +6478,9 @@ packages: resolution: {integrity: sha512-cfmm3tqdnbuYw2FBmRTPBDaohYEbMJ3211T35o6eZdr4d7v69+ZeK1Av84Br7FLj2dlzyeZSbN6qTuXXE6dawQ==} engines: {node: '>=14.0'} + rou3@0.5.1: + resolution: {integrity: sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -6872,6 +6950,9 @@ packages: tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.16.2: resolution: {integrity: sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==} engines: {node: '>=18.0.0'} @@ -7237,6 +7318,9 @@ packages: zod@3.23.8: resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + zod@3.24.1: + resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} + snapshots: '@alloc/quick-lru@5.2.0': {} @@ -7266,6 +7350,12 @@ snapshots: '@balena/dockerignore@1.0.2': {} + '@better-auth/utils@0.2.3': + dependencies: + uncrypto: 0.1.3 + + '@better-fetch/fetch@1.1.12': {} + '@biomejs/biome@1.9.4': optionalDependencies: '@biomejs/cli-darwin-arm64': 1.9.4 @@ -7832,6 +7922,8 @@ snapshots: '@hapi/bourne@3.0.0': {} + '@hexagon/base64@1.1.28': {} + '@hono/node-server@1.12.1': {} '@hono/zod-validator@0.3.0(hono@4.5.8)(zod@3.23.8)': @@ -7981,6 +8073,8 @@ snapshots: '@leichtgewicht/ip-codec@2.0.5': {} + '@levischuck/tiny-cbor@0.2.11': {} + '@lezer/common@1.2.1': {} '@lezer/highlight@1.2.0': @@ -8071,8 +8165,12 @@ snapshots: '@next/swc-win32-x64-msvc@15.0.1': optional: true + '@noble/ciphers@0.6.0': {} + '@noble/hashes@1.5.0': {} + '@noble/hashes@1.7.1': {} + '@node-rs/argon2-android-arm-eabi@1.7.0': optional: true @@ -8401,6 +8499,39 @@ snapshots: '@one-ini/wasm@0.1.1': {} + '@peculiar/asn1-android@2.3.15': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + asn1js: 3.0.5 + tslib: 2.8.1 + + '@peculiar/asn1-ecc@2.3.15': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + '@peculiar/asn1-x509': 2.3.15 + asn1js: 3.0.5 + tslib: 2.8.1 + + '@peculiar/asn1-rsa@2.3.15': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + '@peculiar/asn1-x509': 2.3.15 + asn1js: 3.0.5 + tslib: 2.8.1 + + '@peculiar/asn1-schema@2.3.15': + dependencies: + asn1js: 3.0.5 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509@2.3.15': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + asn1js: 3.0.5 + pvtsutils: 1.3.6 + tslib: 2.8.1 + '@pkgjs/parseargs@0.11.0': optional: true @@ -9394,6 +9525,18 @@ snapshots: domhandler: 5.0.3 selderee: 0.11.0 + '@simplewebauthn/browser@13.1.0': {} + + '@simplewebauthn/server@13.1.1': + dependencies: + '@hexagon/base64': 1.1.28 + '@levischuck/tiny-cbor': 0.2.11 + '@peculiar/asn1-android': 2.3.15 + '@peculiar/asn1-ecc': 2.3.15 + '@peculiar/asn1-rsa': 2.3.15 + '@peculiar/asn1-schema': 2.3.15 + '@peculiar/asn1-x509': 2.3.15 + '@sinclair/typebox@0.27.8': {} '@sindresorhus/is@5.6.0': {} @@ -10304,6 +10447,12 @@ snapshots: dependencies: safer-buffer: 2.1.2 + asn1js@3.0.5: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.3 + tslib: 2.8.1 + assertion-error@1.1.0: {} async-await-queue@2.1.4: {} @@ -10352,6 +10501,28 @@ snapshots: before-after-hook@2.2.3: {} + better-auth@1.1.16: + dependencies: + '@better-auth/utils': 0.2.3 + '@better-fetch/fetch': 1.1.12 + '@noble/ciphers': 0.6.0 + '@noble/hashes': 1.7.1 + '@simplewebauthn/browser': 13.1.0 + '@simplewebauthn/server': 13.1.1 + better-call: 0.3.3 + defu: 6.1.4 + jose: 5.9.6 + kysely: 0.27.5 + nanostores: 0.11.3 + zod: 3.24.1 + + better-call@0.3.3: + dependencies: + '@better-fetch/fetch': 1.1.12 + rou3: 0.5.1 + uncrypto: 0.1.3 + zod: 3.24.1 + binary-extensions@2.3.0: {} bindings@1.5.0: @@ -10957,16 +11128,17 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.39.1(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7): + drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7): optionalDependencies: '@types/react': 18.3.5 + kysely: 0.27.5 postgres: 3.4.4 react: 18.2.0 sqlite3: 5.1.7 - drizzle-zod@0.5.1(drizzle-orm@0.39.1(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7))(zod@3.23.8): + drizzle-zod@0.5.1(drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7))(zod@3.23.8): dependencies: - drizzle-orm: 0.39.1(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7) + drizzle-orm: 0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7) zod: 3.23.8 eastasianwidth@0.2.0: {} @@ -11686,6 +11858,8 @@ snapshots: jiti@1.21.6: {} + jose@5.9.6: {} + joycon@3.1.1: {} js-base64@3.7.7: {} @@ -11843,6 +12017,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + kysely@0.27.5: {} + leac@0.6.0: {} lefthook-darwin-arm64@1.8.4: @@ -12215,6 +12391,8 @@ snapshots: nanoid@3.3.7: {} + nanostores@0.11.3: {} + napi-build-utils@1.0.2: optional: true @@ -12692,6 +12870,12 @@ snapshots: punycode@2.3.1: {} + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.3: {} + qrcode@1.5.4: dependencies: dijkstrajs: 1.0.3 @@ -13054,6 +13238,8 @@ snapshots: rotating-file-stream@3.2.3: {} + rou3@0.5.1: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -13617,6 +13803,8 @@ snapshots: tslib@2.6.3: {} + tslib@2.8.1: {} + tsx@4.16.2: dependencies: esbuild: 0.21.5 @@ -13994,3 +14182,5 @@ snapshots: zod: 3.23.8 zod@3.23.8: {} + + zod@3.24.1: {} From fafc238e701c74f7a524a762865fc2302674fc40 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 9 Feb 2025 18:56:17 -0600 Subject: [PATCH 02/89] refactor: migration --- apps/dokploy/drizzle/0066_broad_marrow.sql | 25 +++++++++- apps/dokploy/package.json | 2 +- apps/dokploy/pages/index.tsx | 47 +++++++++++-------- apps/dokploy/pages/register.tsx | 36 ++++++++------ apps/dokploy/server/api/routers/admin.ts | 2 +- packages/server/auth-schema.ts | 4 +- packages/server/src/db/schema/account.ts | 4 +- packages/server/src/db/schema/auth.ts | 4 +- packages/server/src/db/schema/certificate.ts | 8 ++-- packages/server/src/db/schema/destination.ts | 8 ++-- packages/server/src/db/schema/git-provider.ts | 8 ++-- packages/server/src/db/schema/notification.ts | 8 ++-- packages/server/src/db/schema/project.ts | 8 ++-- packages/server/src/db/schema/registry.ts | 8 ++-- packages/server/src/db/schema/server.ts | 8 ++-- packages/server/src/db/schema/session.ts | 4 +- packages/server/src/db/schema/ssh-key.ts | 8 ++-- packages/server/src/db/schema/user.ts | 6 +-- packages/server/src/lib/auth.ts | 3 +- packages/server/src/services/admin.ts | 2 +- packages/server/src/services/auth.ts | 2 +- packages/server/src/services/user.ts | 34 +++++++------- 22 files changed, 138 insertions(+), 101 deletions(-) diff --git a/apps/dokploy/drizzle/0066_broad_marrow.sql b/apps/dokploy/drizzle/0066_broad_marrow.sql index f10854144..d7e3acf0e 100644 --- a/apps/dokploy/drizzle/0066_broad_marrow.sql +++ b/apps/dokploy/drizzle/0066_broad_marrow.sql @@ -90,7 +90,8 @@ UPDATE "user" SET token = '' WHERE token IS NULL; UPDATE "user" SET "expirationDate" = CURRENT_TIMESTAMP + INTERVAL '1 year' WHERE "expirationDate" IS NULL; UPDATE "user" SET "createdAt" = to_char(CURRENT_TIMESTAMP, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') WHERE "createdAt" IS NULL; UPDATE "user" SET "name" = '' WHERE "name" IS NULL; -UPDATE "user" SET "email" = COALESCE("email", '') WHERE true; +-- Generar emails únicos para registros vacíos +UPDATE "user" SET "email" = CONCAT('user_', id, '@dokploy.local') WHERE "email" = '' OR "email" IS NULL; UPDATE "user" SET "email_verified" = COALESCE("email_verified", false) WHERE true; UPDATE "user" SET "role" = COALESCE("role", 'user') WHERE true; UPDATE "user" SET "banned" = COALESCE("banned", false) WHERE true; @@ -128,6 +129,28 @@ SELECT CAST("createdAt" AS timestamp) as updated_at FROM "auth"; +-- Migrar datos de auth a account +INSERT INTO "account" ( + id, + account_id, + provider_id, + user_id, + password, + "is2FAEnabled", + created_at, + updated_at +) +SELECT + id as id, + id as account_id, + 'credentials' as provider_id, + id as user_id, + password, + "is2FAEnabled", + CAST("createdAt" AS timestamp) as created_at, + CAST("createdAt" AS timestamp) as updated_at +FROM "auth"; + -- Migrar datos de admin a user UPDATE "user" u SET diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index e2a7c4a2b..9e531cf8c 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -35,7 +35,7 @@ "test": "vitest --config __test__/vitest.config.ts" }, "dependencies": { - "better-auth":"1.1.16", + "better-auth": "1.1.16", "bl": "6.0.11", "rotating-file-stream": "3.2.3", "qrcode": "^1.5.3", diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 3aafe9bf9..2691fc5c3 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -13,6 +13,7 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; +import { authClient } from "@/lib/auth"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { IS_CLOUD, isAdminPresent, validateRequest } from "@dokploy/server"; @@ -65,8 +66,8 @@ export default function Home({ IS_CLOUD }: Props) { const router = useRouter(); const form = useForm({ defaultValues: { - email: "", - password: "", + email: "siumauricio@hotmail.com", + password: "Password1234", }, resolver: zodResolver(loginSchema), }); @@ -76,25 +77,31 @@ export default function Home({ IS_CLOUD }: Props) { }, [form, form.reset, form.formState.isSubmitSuccessful]); const onSubmit = async (values: Login) => { - await mutateAsync({ - email: values.email.toLowerCase(), + const { data, error } = await authClient.signIn.email({ + email: values.email, password: values.password, - }) - .then((data) => { - if (data.is2FAEnabled) { - setTemp(data); - } else { - toast.success("Successfully signed in", { - duration: 2000, - }); - router.push("/dashboard/projects"); - } - }) - .catch(() => { - toast.error("Signin failed", { - duration: 2000, - }); - }); + }); + + console.log(data, error); + // await mutateAsync({ + // email: values.email.toLowerCase(), + // password: values.password, + // }) + // .then((data) => { + // if (data.is2FAEnabled) { + // setTemp(data); + // } else { + // toast.success("Successfully signed in", { + // duration: 2000, + // }); + // router.push("/dashboard/projects"); + // } + // }) + // .catch(() => { + // toast.error("Signin failed", { + // duration: 2000, + // }); + // }); }; return ( <> diff --git a/apps/dokploy/pages/register.tsx b/apps/dokploy/pages/register.tsx index e42231a2f..4ff3d4dad 100644 --- a/apps/dokploy/pages/register.tsx +++ b/apps/dokploy/pages/register.tsx @@ -17,6 +17,7 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; +import { authClient } from "@/lib/auth"; import { api } from "@/utils/api"; import { IS_CLOUD, isAdminPresent, validateRequest } from "@dokploy/server"; import { zodResolver } from "@hookform/resolvers/zod"; @@ -79,9 +80,9 @@ const Register = ({ isCloud }: Props) => { const form = useForm({ defaultValues: { - email: "", - password: "", - confirmPassword: "", + email: "user5@yopmail.com", + password: "Password1234", + confirmPassword: "Password1234", }, resolver: zodResolver(registerSchema), }); @@ -91,19 +92,24 @@ const Register = ({ isCloud }: Props) => { }, [form, form.reset, form.formState.isSubmitSuccessful]); const onSubmit = async (values: Register) => { - await mutateAsync({ - email: values.email.toLowerCase(), + const { data, error } = await authClient.signUp.email({ + email: values.email, password: values.password, - }) - .then(() => { - toast.success("User registered successfuly", { - duration: 2000, - }); - if (!isCloud) { - router.push("/"); - } - }) - .catch((e) => e); + name: "Mauricio Siu", + }); + // await mutateAsync({ + // email: values.email.toLowerCase(), + // password: values.password, + // }) + // .then(() => { + // toast.success("User registered successfuly", { + // duration: 2000, + // }); + // if (!isCloud) { + // router.push("/"); + // } + // }) + // .catch((e) => e); }; return (
diff --git a/apps/dokploy/server/api/routers/admin.ts b/apps/dokploy/server/api/routers/admin.ts index 31612fe06..6a4764f56 100644 --- a/apps/dokploy/server/api/routers/admin.ts +++ b/apps/dokploy/server/api/routers/admin.ts @@ -6,7 +6,7 @@ import { apiRemoveUser, apiUpdateAdmin, apiUpdateWebServerMonitoring, - users, + user, } from "@/server/db/schema"; import { IS_CLOUD, diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index 8f8be24d9..8865078b2 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,9 +1,9 @@ import { + boolean, + integer, pgTable, text, - integer, timestamp, - boolean, } from "drizzle-orm/pg-core"; export const user = pgTable("user", { diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 7117f4a44..a332ec920 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -1,5 +1,5 @@ import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; -import { users } from "./user"; +import { user } from "./user"; export const account = pgTable("account", { id: text("id").primaryKey(), @@ -7,7 +7,7 @@ export const account = pgTable("account", { providerId: text("provider_id").notNull(), userId: text("user_id") .notNull() - .references(() => users.id), + .references(() => user.id), accessToken: text("access_token"), refreshToken: text("refresh_token"), idToken: text("id_token"), diff --git a/packages/server/src/db/schema/auth.ts b/packages/server/src/db/schema/auth.ts index 7093a40c3..35f4dc853 100644 --- a/packages/server/src/db/schema/auth.ts +++ b/packages/server/src/db/schema/auth.ts @@ -5,7 +5,7 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; // import { admins } from "./admin"; -import { users } from "./user"; +import { user } from "./user"; const randomImages = [ "/avatars/avatar-1.png", @@ -56,7 +56,7 @@ export const auth = pgTable("auth", { export const authRelations = relations(auth, ({ many }) => ({ // admins: many(admins), - users: many(users), + users: many(user), })); const createSchema = createInsertSchema(auth, { email: z.string().email(), diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts index 22f4f9cb7..3a7ec596d 100644 --- a/packages/server/src/db/schema/certificate.ts +++ b/packages/server/src/db/schema/certificate.ts @@ -4,8 +4,8 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { server } from "./server"; +import { user } from "./user"; import { generateAppName } from "./utils"; -import { users } from "./user"; export const certificates = pgTable("certificate", { certificateId: text("certificateId") @@ -20,7 +20,7 @@ export const certificates = pgTable("certificate", { .$defaultFn(() => generateAppName("certificate")) .unique(), autoRenew: boolean("autoRenew"), - userId: text("userId").references(() => users.id, { + userId: text("userId").references(() => user.id, { onDelete: "cascade", }), serverId: text("serverId").references(() => server.serverId, { @@ -35,9 +35,9 @@ export const certificatesRelations = relations( fields: [certificates.serverId], references: [server.serverId], }), - user: one(users, { + user: one(user, { fields: [certificates.userId], - references: [users.id], + references: [user.id], }), }), ); diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts index c89ed1e37..37faf0fa4 100644 --- a/packages/server/src/db/schema/destination.ts +++ b/packages/server/src/db/schema/destination.ts @@ -5,7 +5,7 @@ import { nanoid } from "nanoid"; import { z } from "zod"; import { admins } from "./admin"; import { backups } from "./backups"; -import { users } from "./user"; +import { user } from "./user"; export const destinations = pgTable("destination", { destinationId: text("destinationId") @@ -22,16 +22,16 @@ export const destinations = pgTable("destination", { endpoint: text("endpoint").notNull(), userId: text("userId") .notNull() - .references(() => users.id, { onDelete: "cascade" }), + .references(() => user.id, { onDelete: "cascade" }), }); export const destinationsRelations = relations( destinations, ({ many, one }) => ({ backups: many(backups), - user: one(users, { + user: one(user, { fields: [destinations.userId], - references: [users.id], + references: [user.id], }), }), ); diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index 00dc928d4..f044b0a09 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -7,7 +7,7 @@ import { admins } from "./admin"; import { bitbucket } from "./bitbucket"; import { github } from "./github"; import { gitlab } from "./gitlab"; -import { users } from "./user"; +import { user } from "./user"; export const gitProviderType = pgEnum("gitProviderType", [ "github", @@ -25,7 +25,7 @@ export const gitProvider = pgTable("git_provider", { createdAt: text("createdAt") .notNull() .$defaultFn(() => new Date().toISOString()), - userId: text("userId").references(() => users.id, { + userId: text("userId").references(() => user.id, { onDelete: "cascade", }), }); @@ -43,9 +43,9 @@ export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ fields: [gitProvider.gitProviderId], references: [bitbucket.gitProviderId], }), - user: one(users, { + user: one(user, { fields: [gitProvider.userId], - references: [users.id], + references: [user.id], }), })); diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 4b7a09eac..5174c17c1 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -4,7 +4,7 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { admins } from "./admin"; -import { users } from "./user"; +import { user } from "./user"; export const notificationType = pgEnum("notificationType", [ "slack", @@ -45,7 +45,7 @@ export const notifications = pgTable("notification", { gotifyId: text("gotifyId").references(() => gotify.gotifyId, { onDelete: "cascade", }), - userId: text("userId").references(() => users.id, { + userId: text("userId").references(() => user.id, { onDelete: "cascade", }), }); @@ -122,9 +122,9 @@ export const notificationsRelations = relations(notifications, ({ one }) => ({ fields: [notifications.gotifyId], references: [gotify.gotifyId], }), - user: one(users, { + user: one(user, { fields: [notifications.userId], - references: [users.id], + references: [user.id], }), })); diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index 440368383..2602a8ec0 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -12,7 +12,7 @@ import { mongo } from "./mongo"; import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; -import { users } from "./user"; +import { user } from "./user"; export const projects = pgTable("project", { projectId: text("projectId") @@ -26,7 +26,7 @@ export const projects = pgTable("project", { .$defaultFn(() => new Date().toISOString()), userId: text("userId") .notNull() - .references(() => users.id, { onDelete: "cascade" }), + .references(() => user.id, { onDelete: "cascade" }), env: text("env").notNull().default(""), }); @@ -38,9 +38,9 @@ export const projectRelations = relations(projects, ({ many, one }) => ({ mongo: many(mongo), redis: many(redis), compose: many(compose), - user: one(users, { + user: one(user, { fields: [projects.userId], - references: [users.id], + references: [user.id], }), })); diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index d1f790686..166168c5f 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -5,7 +5,7 @@ import { nanoid } from "nanoid"; import { z } from "zod"; import { admins } from "./admin"; import { applications } from "./application"; -import { users } from "./user"; +import { user } from "./user"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * database instance for multiple projects. @@ -30,13 +30,13 @@ export const registry = pgTable("registry", { registryType: registryType("selfHosted").notNull().default("cloud"), userId: text("userId") .notNull() - .references(() => users.id, { onDelete: "cascade" }), + .references(() => user.id, { onDelete: "cascade" }), }); export const registryRelations = relations(registry, ({ one, many }) => ({ - user: one(users, { + user: one(user, { fields: [registry.userId], - references: [users.id], + references: [user.id], }), applications: many(applications), })); diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index 71d6ca080..e3a14f953 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -22,8 +22,8 @@ import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; import { sshKeys } from "./ssh-key"; +import { user } from "./user"; import { generateAppName } from "./utils"; -import { users } from "./user"; export const serverStatus = pgEnum("serverStatus", ["active", "inactive"]); @@ -46,7 +46,7 @@ export const server = pgTable("server", { .$defaultFn(() => new Date().toISOString()), userId: text("userId") .notNull() - .references(() => users.id, { onDelete: "cascade" }), + .references(() => user.id, { onDelete: "cascade" }), serverStatus: serverStatus("serverStatus").notNull().default("active"), command: text("command").notNull().default(""), sshKeyId: text("sshKeyId").references(() => sshKeys.sshKeyId, { @@ -101,9 +101,9 @@ export const server = pgTable("server", { }); export const serverRelations = relations(server, ({ one, many }) => ({ - user: one(users, { + user: one(user, { fields: [server.userId], - references: [users.id], + references: [user.id], }), deployments: many(deployments), sshKey: one(sshKeys, { diff --git a/packages/server/src/db/schema/session.ts b/packages/server/src/db/schema/session.ts index 396e81949..e7d579fb1 100644 --- a/packages/server/src/db/schema/session.ts +++ b/packages/server/src/db/schema/session.ts @@ -1,5 +1,5 @@ import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; -import { users } from "./user"; +import { user } from "./user"; // OLD TABLE export const sessionTable = pgTable("session", { @@ -12,6 +12,6 @@ export const sessionTable = pgTable("session", { userAgent: text("user_agent"), userId: text("user_id") .notNull() - .references(() => users.id), + .references(() => user.id), impersonatedBy: text("impersonated_by"), }); diff --git a/packages/server/src/db/schema/ssh-key.ts b/packages/server/src/db/schema/ssh-key.ts index 7a4f50613..6c5ba0a7b 100644 --- a/packages/server/src/db/schema/ssh-key.ts +++ b/packages/server/src/db/schema/ssh-key.ts @@ -7,7 +7,7 @@ import { admins } from "./admin"; import { applications } from "./application"; import { compose } from "./compose"; import { server } from "./server"; -import { users } from "./user"; +import { user } from "./user"; export const sshKeys = pgTable("ssh-key", { sshKeyId: text("sshKeyId") @@ -22,7 +22,7 @@ export const sshKeys = pgTable("ssh-key", { .notNull() .$defaultFn(() => new Date().toISOString()), lastUsedAt: text("lastUsedAt"), - userId: text("userId").references(() => users.id, { + userId: text("userId").references(() => user.id, { onDelete: "cascade", }), }); @@ -31,9 +31,9 @@ export const sshKeysRelations = relations(sshKeys, ({ many, one }) => ({ applications: many(applications), compose: many(compose), servers: many(server), - user: one(users, { + user: one(user, { fields: [sshKeys.userId], - references: [users.id], + references: [user.id], }), })); diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 473cf1907..372b79f87 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -14,7 +14,7 @@ import { certificateType } from "./shared"; */ // OLD TABLE -export const users = pgTable("user", { +export const user = pgTable("user", { id: text("id") .notNull() .primaryKey() @@ -129,7 +129,7 @@ export const users = pgTable("user", { .default(false), }); -export const usersRelations = relations(users, ({ one }) => ({ +export const usersRelations = relations(user, ({ one }) => ({ // auth: one(auth, { // fields: [users.authId], // references: [auth.id], @@ -140,7 +140,7 @@ export const usersRelations = relations(users, ({ one }) => ({ // }), })); -const createSchema = createInsertSchema(users, { +const createSchema = createInsertSchema(user, { id: z.string().min(1), // authId: z.string().min(1), token: z.string().min(1), diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index fada2c434..93eed4ca2 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -2,10 +2,11 @@ import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { admin } from "better-auth/plugins"; import { db } from "../db"; - +import * as schema from "../db/schema"; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", + schema: schema, }), emailAndPassword: { enabled: true, diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index 056b81785..ea0df9b08 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -4,7 +4,7 @@ import { admins, type apiCreateUserInvitation, auth, - users, + user, } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import * as bcrypt from "bcrypt"; diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts index 65a01c412..376f10e90 100644 --- a/packages/server/src/services/auth.ts +++ b/packages/server/src/services/auth.ts @@ -5,7 +5,7 @@ import { type apiCreateAdmin, type apiCreateUser, auth, - users, + user, } from "@dokploy/server/db/schema"; import { getPublicIpWithFallback } from "@dokploy/server/wss/utils"; import { TRPCError } from "@trpc/server"; diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index d8d9862c4..f50e678ad 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -1,15 +1,15 @@ import { db } from "@dokploy/server/db"; -import { users } from "@dokploy/server/db/schema"; +import { user } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; -export type User = typeof users.$inferSelect; +export type User = typeof user.$inferSelect; export const findUserById = async (userId: string) => { - const user = await db.query.users.findFirst({ - where: eq(users.userId, userId), + const userR = await db.query.user.findFirst({ + where: eq(user.userId, userId), }); - if (!user) { + if (!userR) { throw new TRPCError({ code: "NOT_FOUND", message: "User not found", @@ -19,8 +19,8 @@ export const findUserById = async (userId: string) => { }; export const findUserByAuthId = async (authId: string) => { - const user = await db.query.users.findFirst({ - where: eq(users.authId, authId), + const userR = await db.query.user.findFirst({ + where: eq(user.authId, authId), with: { auth: true, }, @@ -35,8 +35,8 @@ export const findUserByAuthId = async (authId: string) => { }; export const findUsers = async (adminId: string) => { - const currentUsers = await db.query.users.findMany({ - where: eq(users.adminId, adminId), + const currentUsers = await db.query.user.findMany({ + where: eq(user.adminId, adminId), with: { auth: { columns: { @@ -49,24 +49,24 @@ export const findUsers = async (adminId: string) => { }; export const addNewProject = async (authId: string, projectId: string) => { - const user = await findUserByAuthId(authId); + const userR = await findUserByAuthId(authId); await db - .update(users) + .update(user) .set({ - accessedProjects: [...user.accessedProjects, projectId], + accessedProjects: [...userR.accessedProjects, projectId], }) - .where(eq(users.authId, authId)); + .where(eq(user.authId, authId)); }; export const addNewService = async (authId: string, serviceId: string) => { - const user = await findUserByAuthId(authId); + const userR = await findUserByAuthId(authId); await db - .update(users) + .update(user) .set({ - accessedServices: [...user.accessedServices, serviceId], + accessedServices: [...userR.accessedServices, serviceId], }) - .where(eq(users.authId, authId)); + .where(eq(user.authId, authId)); }; export const canPerformCreationService = async ( From 8bd72a8a343488e9f51007e7bcddfa80e0563796 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 9 Feb 2025 20:53:06 -0600 Subject: [PATCH 03/89] refactor: add organizations system --- .../dashboard/projects/handle-project.tsx | 37 +++++++- .../components/dashboard/projects/show.tsx | 6 +- .../components/dashboard/search-command.tsx | 7 +- apps/dokploy/components/layouts/side.tsx | 34 +++---- apps/dokploy/components/layouts/user-nav.tsx | 8 +- apps/dokploy/lib/auth.ts | 3 + .../pages/api/providers/github/setup.ts | 2 +- apps/dokploy/pages/dashboard/docker.tsx | 2 +- .../pages/dashboard/project/[projectId].tsx | 4 +- .../services/application/[applicationId].tsx | 4 +- .../services/compose/[composeId].tsx | 4 +- .../services/mariadb/[mariadbId].tsx | 4 +- .../[projectId]/services/mongo/[mongoId].tsx | 4 +- .../[projectId]/services/mysql/[mysqlId].tsx | 4 +- .../services/postgres/[postgresId].tsx | 4 +- .../[projectId]/services/redis/[redisId].tsx | 4 +- .../pages/dashboard/settings/billing.tsx | 2 +- .../pages/dashboard/settings/certificates.tsx | 2 +- .../pages/dashboard/settings/cluster.tsx | 2 +- .../pages/dashboard/settings/destinations.tsx | 2 +- .../dashboard/settings/git-providers.tsx | 2 +- .../pages/dashboard/settings/index.tsx | 2 +- .../dashboard/settings/notifications.tsx | 2 +- .../pages/dashboard/settings/profile.tsx | 6 +- .../pages/dashboard/settings/registry.tsx | 2 +- .../pages/dashboard/settings/server.tsx | 2 +- .../pages/dashboard/settings/servers.tsx | 2 +- .../pages/dashboard/settings/ssh-keys.tsx | 2 +- .../pages/dashboard/settings/users.tsx | 2 +- apps/dokploy/pages/dashboard/swarm.tsx | 2 +- apps/dokploy/pages/dashboard/traefik.tsx | 2 +- apps/dokploy/pages/index.tsx | 94 ++++++++++-------- apps/dokploy/pages/register.tsx | 28 +++++- apps/dokploy/pages/swagger.tsx | 2 +- apps/dokploy/server/api/routers/auth.ts | 3 +- apps/dokploy/server/api/routers/project.ts | 7 +- apps/dokploy/server/api/routers/settings.ts | 2 +- apps/dokploy/server/api/trpc.ts | 18 ++-- packages/server/auth-schema.ts | 95 ++++++++++++------- packages/server/src/auth/auth.ts | 5 +- packages/server/src/db/schema/account.ts | 35 +++++++ packages/server/src/db/schema/session.ts | 3 +- packages/server/src/db/schema/user.ts | 13 ++- packages/server/src/lib/auth.ts | 39 +++++++- packages/server/src/services/admin.ts | 4 +- packages/server/src/services/auth.ts | 7 +- packages/server/src/services/user.ts | 10 +- 47 files changed, 359 insertions(+), 171 deletions(-) diff --git a/apps/dokploy/components/dashboard/projects/handle-project.tsx b/apps/dokploy/components/dashboard/projects/handle-project.tsx index 08e3e0a8d..5b0777716 100644 --- a/apps/dokploy/components/dashboard/projects/handle-project.tsx +++ b/apps/dokploy/components/dashboard/projects/handle-project.tsx @@ -21,6 +21,7 @@ import { import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; +import { authClient } from "@/lib/auth"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { PlusIcon, SquarePen } from "lucide-react"; @@ -97,6 +98,18 @@ export const HandleProject = ({ projectId }: Props) => { ); }); }; + // useEffect(() => { + // const getUsers = async () => { + // const users = await authClient.admin.listUsers({ + // query: { + // limit: 100, + // }, + // }); + // console.log(users); + // }; + + // getUsers(); + // }); return ( @@ -110,10 +123,26 @@ export const HandleProject = ({ projectId }: Props) => { Update ) : ( - + <> + + + )} diff --git a/apps/dokploy/components/dashboard/projects/show.tsx b/apps/dokploy/components/dashboard/projects/show.tsx index 8d058b6cb..98ef14a4b 100644 --- a/apps/dokploy/components/dashboard/projects/show.tsx +++ b/apps/dokploy/components/dashboard/projects/show.tsx @@ -57,7 +57,7 @@ export const ShowProjects = () => { authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); const { mutateAsync } = api.project.remove.useMutation(); @@ -91,7 +91,7 @@ export const ShowProjects = () => { - {(auth?.rol === "admin" || user?.canCreateProjects) && ( + {(auth?.role === "admin" || user?.canCreateProjects) && (
@@ -293,7 +293,7 @@ export const ShowProjects = () => {
e.stopPropagation()} > - {(auth?.rol === "admin" || + {(auth?.role === "admin" || user?.canDeleteProjects) && ( diff --git a/apps/dokploy/components/dashboard/search-command.tsx b/apps/dokploy/components/dashboard/search-command.tsx index 4d3c75f98..f52fd14f8 100644 --- a/apps/dokploy/components/dashboard/search-command.tsx +++ b/apps/dokploy/components/dashboard/search-command.tsx @@ -28,6 +28,7 @@ import { BookIcon, CircuitBoard, GlobeIcon } from "lucide-react"; import { useRouter } from "next/router"; import React from "react"; import { StatusTooltip } from "../shared/status-tooltip"; +import { authClient } from "@/lib/auth"; type Project = Awaited>; @@ -35,8 +36,10 @@ export const SearchCommand = () => { const router = useRouter(); const [open, setOpen] = React.useState(false); const [search, setSearch] = React.useState(""); - - const { data } = api.project.all.useQuery(); + const { data: session } = authClient.getSession(); + const { data } = api.project.all.useQuery(undefined, { + enabled: !!session, + }); const { data: isCloud, isLoading } = api.settings.isCloud.useQuery(); React.useEffect(() => { diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 44a4b0ed0..88740054b 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -155,7 +155,7 @@ const MENU: Menu = { // Only enabled for admins and users with access to Traefik files in non-cloud environments isEnabled: ({ auth, user, isCloud }) => !!( - (auth?.rol === "admin" || user?.canAccessToTraefikFiles) && + (auth?.role === "admin" || user?.canAccessToTraefikFiles) && !isCloud ), }, @@ -166,7 +166,7 @@ const MENU: Menu = { icon: BlocksIcon, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!((auth?.rol === "admin" || user?.canAccessToDocker) && !isCloud), + !!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud), }, { isSingle: true, @@ -175,7 +175,7 @@ const MENU: Menu = { icon: PieChart, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!((auth?.rol === "admin" || user?.canAccessToDocker) && !isCloud), + !!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud), }, { isSingle: true, @@ -184,7 +184,7 @@ const MENU: Menu = { icon: Forward, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!((auth?.rol === "admin" || user?.canAccessToDocker) && !isCloud), + !!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud), }, // Legacy unused menu, adjusted to the new structure @@ -252,7 +252,7 @@ const MENU: Menu = { icon: Activity, // Only enabled for admins in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!(auth?.rol === "admin" && !isCloud), + !!(auth?.role === "admin" && !isCloud), }, { isSingle: true, @@ -266,7 +266,7 @@ const MENU: Menu = { url: "/dashboard/settings/servers", icon: Server, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { isSingle: true, @@ -274,7 +274,7 @@ const MENU: Menu = { icon: Users, url: "/dashboard/settings/users", // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { isSingle: true, @@ -283,7 +283,7 @@ const MENU: Menu = { url: "/dashboard/settings/ssh-keys", // Only enabled for admins and users with access to SSH keys isEnabled: ({ auth, user }) => - !!(auth?.rol === "admin" || user?.canAccessToSSHKeys), + !!(auth?.role === "admin" || user?.canAccessToSSHKeys), }, { isSingle: true, @@ -292,7 +292,7 @@ const MENU: Menu = { icon: GitBranch, // Only enabled for admins and users with access to Git providers isEnabled: ({ auth, user }) => - !!(auth?.rol === "admin" || user?.canAccessToGitProviders), + !!(auth?.role === "admin" || user?.canAccessToGitProviders), }, { isSingle: true, @@ -300,7 +300,7 @@ const MENU: Menu = { url: "/dashboard/settings/registry", icon: Package, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { isSingle: true, @@ -308,7 +308,7 @@ const MENU: Menu = { url: "/dashboard/settings/destinations", icon: Database, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { @@ -317,7 +317,7 @@ const MENU: Menu = { url: "/dashboard/settings/certificates", icon: ShieldCheck, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { isSingle: true, @@ -326,7 +326,7 @@ const MENU: Menu = { icon: Boxes, // Only enabled for admins in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!(auth?.rol === "admin" && !isCloud), + !!(auth?.role === "admin" && !isCloud), }, { isSingle: true, @@ -334,7 +334,7 @@ const MENU: Menu = { url: "/dashboard/settings/notifications", icon: Bell, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.rol === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), }, { isSingle: true, @@ -343,7 +343,7 @@ const MENU: Menu = { icon: CreditCard, // Only enabled for admins in cloud environments isEnabled: ({ auth, user, isCloud }) => - !!(auth?.rol === "admin" && isCloud), + !!(auth?.role === "admin" && isCloud), }, ], @@ -537,7 +537,7 @@ export default function Page({ children }: Props) { authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -783,7 +783,7 @@ export default function Page({ children }: Props) { ))} - {!isCloud && auth?.rol === "admin" && ( + {!isCloud && auth?.role === "admin" && ( diff --git a/apps/dokploy/components/layouts/user-nav.tsx b/apps/dokploy/components/layouts/user-nav.tsx index 67c5cbfdc..d2ad153be 100644 --- a/apps/dokploy/components/layouts/user-nav.tsx +++ b/apps/dokploy/components/layouts/user-nav.tsx @@ -24,6 +24,7 @@ import { useRouter } from "next/router"; import { useEffect, useRef, useState } from "react"; import { ModeToggle } from "../ui/modeToggle"; import { SidebarMenuButton } from "../ui/sidebar"; +import { authClient } from "@/lib/auth"; const AUTO_CHECK_UPDATES_INTERVAL_MINUTES = 7; @@ -40,7 +41,7 @@ export const UserNav = () => { }, ); const { locale, setLocale } = useLocale(); - const { mutateAsync } = api.auth.logout.useMutation(); + // const { mutateAsync } = api.auth.logout.useMutation(); return ( @@ -178,9 +179,12 @@ export const UserNav = () => { { - await mutateAsync().then(() => { + await authClient.signOut().then(() => { router.push("/"); }); + // await mutateAsync().then(() => { + // router.push("/"); + // }); }} > Log out diff --git a/apps/dokploy/lib/auth.ts b/apps/dokploy/lib/auth.ts index d0b50c7e3..d050b3608 100644 --- a/apps/dokploy/lib/auth.ts +++ b/apps/dokploy/lib/auth.ts @@ -1,4 +1,7 @@ import { createAuthClient } from "better-auth/react"; +import { organizationClient } from "better-auth/client/plugins"; + export const authClient = createAuthClient({ baseURL: "http://localhost:3000", // the base url of your auth server + plugins: [organizationClient()], }); diff --git a/apps/dokploy/pages/api/providers/github/setup.ts b/apps/dokploy/pages/api/providers/github/setup.ts index a1ce98d48..38a281b1b 100644 --- a/apps/dokploy/pages/api/providers/github/setup.ts +++ b/apps/dokploy/pages/api/providers/github/setup.ts @@ -42,7 +42,7 @@ export default async function handler( const auth = await findAuthById(value as string); let adminId = ""; - if (auth.rol === "admin") { + if (auth.role === "admin") { const admin = await findAdminByAuthId(auth.id); adminId = admin.adminId; } else { diff --git a/apps/dokploy/pages/dashboard/docker.tsx b/apps/dokploy/pages/dashboard/docker.tsx index 96387c07d..5449b9bdc 100644 --- a/apps/dokploy/pages/dashboard/docker.tsx +++ b/apps/dokploy/pages/dashboard/docker.tsx @@ -53,7 +53,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.rol === "user") { + if (auth.role === "user") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index ea23ad3a8..f8c39a3a3 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -206,7 +206,7 @@ const Project = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); const { data, isLoading, refetch } = api.project.one.useQuery({ projectId }); @@ -335,7 +335,7 @@ const Project = ( {data?.description} - {(auth?.rol === "admin" || user?.canCreateServices) && ( + {(auth?.role === "admin" || user?.canCreateServices) && (
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx index 9d3ffe4fb..e2bf8455b 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx @@ -93,7 +93,7 @@ const Service = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -186,7 +186,7 @@ const Service = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx index c68402142..ddc613e5f 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx @@ -87,7 +87,7 @@ const Service = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -181,7 +181,7 @@ const Service = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx index a2ee90512..813ea7292 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx @@ -68,7 +68,7 @@ const Mariadb = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -154,7 +154,7 @@ const Mariadb = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx index 4f3947c2a..0361b7e29 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx @@ -68,7 +68,7 @@ const Mongo = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -156,7 +156,7 @@ const Mongo = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx index baf7e6f8b..eff9cfe79 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx @@ -67,7 +67,7 @@ const MySql = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -156,7 +156,7 @@ const MySql = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx index e3fd8b444..808c7aee4 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx @@ -66,7 +66,7 @@ const Postgresql = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); const { data: monitoring } = api.admin.getMetricsToken.useQuery(); @@ -154,7 +154,7 @@ const Postgresql = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx index 3421e759c..82180401b 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx @@ -67,7 +67,7 @@ const Redis = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.rol === "user", + enabled: !!auth?.id && auth?.role === "user", }, ); @@ -155,7 +155,7 @@ const Redis = (
- {(auth?.rol === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "admin" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/settings/billing.tsx b/apps/dokploy/pages/dashboard/settings/billing.tsx index 5c58e25a9..dd70c22ae 100644 --- a/apps/dokploy/pages/dashboard/settings/billing.tsx +++ b/apps/dokploy/pages/dashboard/settings/billing.tsx @@ -30,7 +30,7 @@ export async function getServerSideProps( } const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/certificates.tsx b/apps/dokploy/pages/dashboard/settings/certificates.tsx index 732b6622a..d5bbf0332 100644 --- a/apps/dokploy/pages/dashboard/settings/certificates.tsx +++ b/apps/dokploy/pages/dashboard/settings/certificates.tsx @@ -25,7 +25,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/cluster.tsx b/apps/dokploy/pages/dashboard/settings/cluster.tsx index a6605c573..9affb9ee2 100644 --- a/apps/dokploy/pages/dashboard/settings/cluster.tsx +++ b/apps/dokploy/pages/dashboard/settings/cluster.tsx @@ -34,7 +34,7 @@ export async function getServerSideProps( }; } const { user, session } = await validateRequest(ctx.req, ctx.res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/destinations.tsx b/apps/dokploy/pages/dashboard/settings/destinations.tsx index c5c6f2f81..671087fe8 100644 --- a/apps/dokploy/pages/dashboard/settings/destinations.tsx +++ b/apps/dokploy/pages/dashboard/settings/destinations.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx index dc37522ac..6e8bf5874 100644 --- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx +++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx @@ -51,7 +51,7 @@ export async function getServerSideProps( await helpers.settings.isCloud.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.rol === "user") { + if (auth.role === "user") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/settings/index.tsx b/apps/dokploy/pages/dashboard/settings/index.tsx index bf76607b4..9b4c80485 100644 --- a/apps/dokploy/pages/dashboard/settings/index.tsx +++ b/apps/dokploy/pages/dashboard/settings/index.tsx @@ -190,7 +190,7 @@ export async function getServerSideProps( }, }; } - if (user.rol === "user") { + if (user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/notifications.tsx b/apps/dokploy/pages/dashboard/settings/notifications.tsx index 0b75fc67a..054f92e5a 100644 --- a/apps/dokploy/pages/dashboard/settings/notifications.tsx +++ b/apps/dokploy/pages/dashboard/settings/notifications.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index 44e007f11..00f10ec72 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -19,7 +19,7 @@ const Page = () => { authId: data?.id || "", }, { - enabled: !!data?.id && data?.rol === "user", + enabled: !!data?.id && data?.role === "user", }, ); @@ -28,7 +28,7 @@ const Page = () => {
- {(user?.canAccessToAPI || data?.rol === "admin") && } + {(user?.canAccessToAPI || data?.role === "admin") && } {isCloud && }
@@ -62,7 +62,7 @@ export async function getServerSideProps( await helpers.settings.isCloud.prefetch(); await helpers.auth.get.prefetch(); - if (user?.rol === "user") { + if (user?.role === "user") { await helpers.user.byAuthId.prefetch({ authId: user.authId, }); diff --git a/apps/dokploy/pages/dashboard/settings/registry.tsx b/apps/dokploy/pages/dashboard/settings/registry.tsx index 49c9ec20f..441bee395 100644 --- a/apps/dokploy/pages/dashboard/settings/registry.tsx +++ b/apps/dokploy/pages/dashboard/settings/registry.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/server.tsx b/apps/dokploy/pages/dashboard/settings/server.tsx index a229d0bcb..98710d06e 100644 --- a/apps/dokploy/pages/dashboard/settings/server.tsx +++ b/apps/dokploy/pages/dashboard/settings/server.tsx @@ -107,7 +107,7 @@ export async function getServerSideProps( }, }; } - if (user.rol === "user") { + if (user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/servers.tsx b/apps/dokploy/pages/dashboard/settings/servers.tsx index 36fde9834..27f88be24 100644 --- a/apps/dokploy/pages/dashboard/settings/servers.tsx +++ b/apps/dokploy/pages/dashboard/settings/servers.tsx @@ -36,7 +36,7 @@ export async function getServerSideProps( }, }; } - if (user.rol === "user") { + if (user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx index 239edac6a..fcb11666f 100644 --- a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx +++ b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx @@ -51,7 +51,7 @@ export async function getServerSideProps( const auth = await helpers.auth.get.fetch(); await helpers.settings.isCloud.prefetch(); - if (auth.rol === "user") { + if (auth.role === "user") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/settings/users.tsx b/apps/dokploy/pages/dashboard/settings/users.tsx index e70728909..ace439692 100644 --- a/apps/dokploy/pages/dashboard/settings/users.tsx +++ b/apps/dokploy/pages/dashboard/settings/users.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.rol === "user") { + if (!user || user.role === "user") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/swarm.tsx b/apps/dokploy/pages/dashboard/swarm.tsx index 3a8a60b28..524b464af 100644 --- a/apps/dokploy/pages/dashboard/swarm.tsx +++ b/apps/dokploy/pages/dashboard/swarm.tsx @@ -53,7 +53,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.rol === "user") { + if (auth.role === "user") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/traefik.tsx b/apps/dokploy/pages/dashboard/traefik.tsx index 9cd7eefcf..b8ff13f3f 100644 --- a/apps/dokploy/pages/dashboard/traefik.tsx +++ b/apps/dokploy/pages/dashboard/traefik.tsx @@ -53,7 +53,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.rol === "user") { + if (auth.role === "user") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 2691fc5c3..7877e65cc 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -16,8 +16,11 @@ import { Input } from "@/components/ui/input"; import { authClient } from "@/lib/auth"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; -import { IS_CLOUD, isAdminPresent, validateRequest } from "@dokploy/server"; +import { auth, IS_CLOUD, isAdminPresent } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { zodResolver } from "@hookform/resolvers/zod"; +import { getSessionCookie, Session } from "better-auth"; +import { betterFetch } from "better-auth/react"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; @@ -66,7 +69,7 @@ export default function Home({ IS_CLOUD }: Props) { const router = useRouter(); const form = useForm({ defaultValues: { - email: "siumauricio@hotmail.com", + email: "user5@yopmail.com", password: "Password1234", }, resolver: zodResolver(loginSchema), @@ -82,6 +85,17 @@ export default function Home({ IS_CLOUD }: Props) { password: values.password, }); + if (!error) { + // if (data) { + // setTemp(data); + // } else { + toast.success("Successfully signed in", { + duration: 2000, + }); + // router.push("/dashboard/projects"); + // } + } + console.log(data, error); // await mutateAsync({ // email: values.email.toLowerCase(), @@ -208,51 +222,51 @@ Home.getLayout = (page: ReactElement) => { return {page}; }; export async function getServerSideProps(context: GetServerSidePropsContext) { - // if (IS_CLOUD) { - // try { - // const { user } = await validateRequest(context.req, context.res); + if (IS_CLOUD) { + try { + const { user } = await validateRequest(context.req); + if (user) { + return { + redirect: { + permanent: true, + destination: "/dashboard/projects", + }, + }; + } + } catch (error) {} - // if (user) { - // return { - // redirect: { - // permanent: true, - // destination: "/dashboard/projects", - // }, - // }; - // } - // } catch (error) {} + return { + props: { + IS_CLOUD: IS_CLOUD, + }, + }; + } + const hasAdmin = await isAdminPresent(); - // return { - // props: { - // IS_CLOUD: IS_CLOUD, - // }, - // }; - // } - // const hasAdmin = await isAdminPresent(); + if (!hasAdmin) { + return { + redirect: { + permanent: true, + destination: "/register", + }, + }; + } - // if (!hasAdmin) { - // return { - // redirect: { - // permanent: true, - // destination: "/register", - // }, - // }; - // } + const { user } = await validateRequest(context.req); + console.log("Response", user); - // const { user } = await validateRequest(context.req, context.res); - - // if (user) { - // return { - // redirect: { - // permanent: true, - // destination: "/dashboard/projects", - // }, - // }; - // } + if (user) { + return { + redirect: { + permanent: true, + destination: "/dashboard/projects", + }, + }; + } return { props: { - // hasAdmin, + hasAdmin, }, }; } diff --git a/apps/dokploy/pages/register.tsx b/apps/dokploy/pages/register.tsx index 4ff3d4dad..f79024788 100644 --- a/apps/dokploy/pages/register.tsx +++ b/apps/dokploy/pages/register.tsx @@ -32,6 +32,9 @@ import { z } from "zod"; const registerSchema = z .object({ + name: z.string().min(1, { + message: "Name is required", + }), email: z .string() .min(1, { @@ -80,6 +83,7 @@ const Register = ({ isCloud }: Props) => { const form = useForm({ defaultValues: { + name: "Mauricio Siu", email: "user5@yopmail.com", password: "Password1234", confirmPassword: "Password1234", @@ -95,8 +99,17 @@ const Register = ({ isCloud }: Props) => { const { data, error } = await authClient.signUp.email({ email: values.email, password: values.password, - name: "Mauricio Siu", + name: values.name, }); + + // const { data, error } = await authClient.admin.createUser({ + // name: values.name, + // email: values.email, + // password: values.password, + // role: "superAdmin", + // }); + + // consol/e.log(data, error); // await mutateAsync({ // email: values.email.toLowerCase(), // password: values.password, @@ -153,6 +166,19 @@ const Register = ({ isCloud }: Props) => { className="grid gap-4" >
+ ( + + Name + + + + + + )} + /> { - const auth = await findAuthById(ctx.user.authId); + console.log(ctx.user); + const auth = await findAuthById(ctx.user.id); return auth; }), diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index 35b2669bd..c2852ff6b 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -124,9 +124,10 @@ export const projectRouter = createTRPCRouter({ return project; }), all: protectedProcedure.query(async ({ ctx }) => { + // console.log(ctx.user); if (ctx.user.rol === "user") { const { accessedProjects, accessedServices } = await findUserByAuthId( - ctx.user.authId, + ctx.user.id, ); if (accessedProjects.length === 0) { @@ -139,7 +140,7 @@ export const projectRouter = createTRPCRouter({ accessedProjects.map((projectId) => sql`${projectId}`), sql`, `, )})`, - eq(projects.adminId, ctx.user.adminId), + eq(projects.userId, ctx.user.id), ), with: { applications: { @@ -193,7 +194,7 @@ export const projectRouter = createTRPCRouter({ }, }, }, - where: eq(projects.adminId, ctx.user.adminId), + where: eq(projects.userId, ctx.user.id), orderBy: desc(projects.createdAt), }); }), diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index cb0e32d9a..116de6ad8 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -655,7 +655,7 @@ export const settingsRouter = createTRPCRouter({ return true; }), - isCloud: protectedProcedure.query(async () => { + isCloud: publicProcedure.query(async () => { return IS_CLOUD; }), health: publicProcedure.query(async () => { diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index db4f7adfe..9579407b5 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -9,7 +9,8 @@ // import { getServerAuthSession } from "@/server/auth"; import { db } from "@/server/db"; -import { validateBearerToken, validateRequest } from "@dokploy/server"; +import { validateBearerToken } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import type { OpenApiMeta } from "@dokploy/trpc-openapi"; import { TRPCError, initTRPC } from "@trpc/server"; import type { CreateNextContextOptions } from "@trpc/server/adapters/next"; @@ -18,7 +19,7 @@ import { experimental_isMultipartFormDataRequest, experimental_parseMultipartFormData, } from "@trpc/server/adapters/node-http/content-type/form-data"; -import type { Session, User } from "lucia"; +import type { Session, User } from "better-auth"; import superjson from "superjson"; import { ZodError } from "zod"; /** @@ -30,7 +31,7 @@ import { ZodError } from "zod"; */ interface CreateContextOptions { - user: (User & { authId: string; adminId: string }) | null; + user: (User & { authId: string; rol: "admin" | "user" }) | null; session: Session | null; req: CreateNextContextOptions["req"]; res: CreateNextContextOptions["res"]; @@ -65,10 +66,11 @@ const createInnerTRPCContext = (opts: CreateContextOptions) => { export const createTRPCContext = async (opts: CreateNextContextOptions) => { const { req, res } = opts; - let { session, user } = await validateBearerToken(req); + // Get from the request + let { session, user } = await validateRequest(req); if (!session) { - const cookieResult = await validateRequest(req, res); + const cookieResult = await validateRequest(req); session = cookieResult.session; user = cookieResult.user; } @@ -79,12 +81,10 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { session: session, ...((user && { user: { - authId: user.id, + authId: "Null", email: user.email, - rol: user.rol, + rol: user.role, id: user.id, - secret: user.secret, - adminId: user.adminId, }, }) || { user: null, diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index 8865078b2..0bd911414 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,9 +1,9 @@ import { - boolean, - integer, pgTable, text, + integer, timestamp, + boolean, } from "drizzle-orm/pg-core"; export const user = pgTable("user", { @@ -14,10 +14,6 @@ export const user = pgTable("user", { image: text("image"), createdAt: timestamp("created_at").notNull(), updatedAt: timestamp("updated_at").notNull(), - role: text("role"), - banned: boolean("banned"), - banReason: text("ban_reason"), - banExpires: timestamp("ban_expires"), }); export const session = pgTable("session", { @@ -31,32 +27,67 @@ export const session = pgTable("session", { userId: text("user_id") .notNull() .references(() => user.id), - impersonatedBy: text("impersonated_by"), + activeOrganizationId: text("active_organization_id"), }); -// export const account = pgTable("account", { -// id: text("id").primaryKey(), -// accountId: text("account_id").notNull(), -// providerId: text("provider_id").notNull(), -// userId: text("user_id") -// .notNull() -// .references(() => user.id), -// accessToken: text("access_token"), -// refreshToken: text("refresh_token"), -// idToken: text("id_token"), -// accessTokenExpiresAt: timestamp("access_token_expires_at"), -// refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), -// scope: text("scope"), -// password: text("password"), -// createdAt: timestamp("created_at").notNull(), -// updatedAt: timestamp("updated_at").notNull(), -// }); +export const account = pgTable("account", { + id: text("id").primaryKey(), + accountId: text("account_id").notNull(), + providerId: text("provider_id").notNull(), + userId: text("user_id") + .notNull() + .references(() => user.id), + accessToken: text("access_token"), + refreshToken: text("refresh_token"), + idToken: text("id_token"), + accessTokenExpiresAt: timestamp("access_token_expires_at"), + refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), + scope: text("scope"), + password: text("password"), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), +}); -// export const verification = pgTable("verification", { -// id: text("id").primaryKey(), -// identifier: text("identifier").notNull(), -// value: text("value").notNull(), -// expiresAt: timestamp("expires_at").notNull(), -// createdAt: timestamp("created_at"), -// updatedAt: timestamp("updated_at"), -// }); +export const verification = pgTable("verification", { + id: text("id").primaryKey(), + identifier: text("identifier").notNull(), + value: text("value").notNull(), + expiresAt: timestamp("expires_at").notNull(), + createdAt: timestamp("created_at"), + updatedAt: timestamp("updated_at"), +}); + +export const organization = pgTable("organization", { + id: text("id").primaryKey(), + name: text("name").notNull(), + slug: text("slug").unique(), + logo: text("logo"), + createdAt: timestamp("created_at").notNull(), + metadata: text("metadata"), +}); + +export const member = pgTable("member", { + id: text("id").primaryKey(), + organizationId: text("organization_id") + .notNull() + .references(() => organization.id), + userId: text("user_id") + .notNull() + .references(() => user.id), + role: text("role").notNull(), + createdAt: timestamp("created_at").notNull(), +}); + +export const invitation = pgTable("invitation", { + id: text("id").primaryKey(), + organizationId: text("organization_id") + .notNull() + .references(() => organization.id), + email: text("email").notNull(), + role: text("role"), + status: text("status").notNull(), + expiresAt: timestamp("expires_at").notNull(), + inviterId: text("inviter_id") + .notNull() + .references(() => user.id), +}); diff --git a/packages/server/src/auth/auth.ts b/packages/server/src/auth/auth.ts index ab340d0af..423c4333f 100644 --- a/packages/server/src/auth/auth.ts +++ b/packages/server/src/auth/auth.ts @@ -6,9 +6,9 @@ import { TimeSpan } from "lucia"; import { Lucia } from "lucia/dist/core.js"; import type { Session, User } from "lucia/dist/core.js"; import { db } from "../db"; -import { type DatabaseUser, auth, sessionTable } from "../db/schema"; +import { type DatabaseUser, auth, session } from "../db/schema"; -export const adapter = new DrizzlePostgreSQLAdapter(db, sessionTable, auth); +export const adapter = new DrizzlePostgreSQLAdapter(db, session, auth); export const lucia = new Lucia(adapter, { sessionCookie: { @@ -46,6 +46,7 @@ export async function validateRequest( req: IncomingMessage, res: ServerResponse, ): ReturnValidateToken { + console.log(session); const sessionId = lucia.readSessionCookie(req.headers.cookie ?? ""); if (!sessionId) { diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index a332ec920..38c630275 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -32,3 +32,38 @@ export const verification = pgTable("verification", { createdAt: timestamp("created_at"), updatedAt: timestamp("updated_at"), }); + +export const organization = pgTable("organization", { + id: text("id").primaryKey(), + name: text("name").notNull(), + slug: text("slug").unique(), + logo: text("logo"), + createdAt: timestamp("created_at").notNull(), + metadata: text("metadata"), +}); + +export const member = pgTable("member", { + id: text("id").primaryKey(), + organizationId: text("organization_id") + .notNull() + .references(() => organization.id), + userId: text("user_id") + .notNull() + .references(() => user.id), + role: text("role").notNull(), + createdAt: timestamp("created_at").notNull(), +}); + +export const invitation = pgTable("invitation", { + id: text("id").primaryKey(), + organizationId: text("organization_id") + .notNull() + .references(() => organization.id), + email: text("email").notNull(), + role: text("role"), + status: text("status").notNull(), + expiresAt: timestamp("expires_at").notNull(), + inviterId: text("inviter_id") + .notNull() + .references(() => user.id), +}); diff --git a/packages/server/src/db/schema/session.ts b/packages/server/src/db/schema/session.ts index e7d579fb1..66a410b30 100644 --- a/packages/server/src/db/schema/session.ts +++ b/packages/server/src/db/schema/session.ts @@ -2,7 +2,7 @@ import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { user } from "./user"; // OLD TABLE -export const sessionTable = pgTable("session", { +export const session = pgTable("session", { id: text("id").primaryKey(), expiresAt: timestamp("expires_at").notNull(), token: text("token").notNull().unique(), @@ -14,4 +14,5 @@ export const sessionTable = pgTable("session", { .notNull() .references(() => user.id), impersonatedBy: text("impersonated_by"), + activeOrganizationId: text("active_organization_id"), }); diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 372b79f87..bb06f8bc0 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -24,11 +24,16 @@ export const user = pgTable("user", { isRegistered: boolean("isRegistered").notNull().default(false), expirationDate: timestamp("expirationDate", { precision: 3, - mode: "string", - }).notNull(), - createdAt: text("createdAt") + mode: "date", + }) .notNull() - .$defaultFn(() => new Date().toISOString()), + .$defaultFn(() => new Date()), + createdAt: timestamp("createdAt", { + precision: 3, + mode: "date", + }) + .notNull() + .$defaultFn(() => new Date()), canCreateProjects: boolean("canCreateProjects").notNull().default(false), canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false), canCreateServices: boolean("canCreateServices").notNull().default(false), diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 93eed4ca2..082176b2c 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -1,8 +1,10 @@ import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; -import { admin } from "better-auth/plugins"; +import { admin, createAuthMiddleware, organization } from "better-auth/plugins"; import { db } from "../db"; import * as schema from "../db/schema"; +import type { IncomingMessage } from "node:http"; +import { eq } from "drizzle-orm"; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", @@ -11,5 +13,38 @@ export const auth = betterAuth({ emailAndPassword: { enabled: true, }, - plugins: [admin()], + hooks: { + after: createAuthMiddleware(async (ctx) => { + if (ctx.path.startsWith("/sign-up")) { + const newSession = ctx.context.newSession; + await db + .update(schema.user) + .set({ + role: "admin", + }) + .where(eq(schema.user.id, newSession?.user?.id || "")); + } + }), + }, + user: { + additionalFields: {}, + }, + plugins: [organization()], }); + +export const validateRequest = async (request: IncomingMessage) => { + const session = await auth.api.getSession({ + headers: new Headers({ + cookie: request.headers.cookie || "", + }), + }); + + if (!session?.session || !session.user) { + return { + session: null, + user: null, + }; + } + + return session; +}; diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index ea0df9b08..21c8f13e5 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -94,8 +94,8 @@ export const updateAdminById = async ( }; export const isAdminPresent = async () => { - const admin = await db.query.users.findFirst({ - where: eq(users.role, "admin"), + const admin = await db.query.user.findFirst({ + where: eq(user.role, "admin"), }); if (!admin) { return false; diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts index 376f10e90..f391d011d 100644 --- a/packages/server/src/services/auth.ts +++ b/packages/server/src/services/auth.ts @@ -100,10 +100,11 @@ export const findAuthByEmail = async (email: string) => { }; export const findAuthById = async (authId: string) => { - const result = await db.query.auth.findFirst({ - where: eq(auth.id, authId), + const result = await db.query.user.findFirst({ + where: eq(user.id, authId), columns: { - password: false, + createdAt: false, + updatedAt: false, }, }); if (!result) { diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index f50e678ad..afc3ec009 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -20,18 +20,16 @@ export const findUserById = async (userId: string) => { export const findUserByAuthId = async (authId: string) => { const userR = await db.query.user.findFirst({ - where: eq(user.authId, authId), - with: { - auth: true, - }, + where: eq(user.id, authId), + with: {}, }); - if (!user) { + if (!userR) { throw new TRPCError({ code: "NOT_FOUND", message: "User not found", }); } - return user; + return userR; }; export const findUsers = async (adminId: string) => { From afd3d2eea3706f5a98db6ad079f97dfd681f052f Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 9 Feb 2025 20:53:14 -0600 Subject: [PATCH 04/89] refactor: lint --- apps/dokploy/components/dashboard/search-command.tsx | 2 +- apps/dokploy/components/layouts/user-nav.tsx | 2 +- apps/dokploy/lib/auth.ts | 2 +- apps/dokploy/pages/index.tsx | 4 ++-- packages/server/auth-schema.ts | 4 ++-- packages/server/src/lib/auth.ts | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/dokploy/components/dashboard/search-command.tsx b/apps/dokploy/components/dashboard/search-command.tsx index f52fd14f8..952bbe5c8 100644 --- a/apps/dokploy/components/dashboard/search-command.tsx +++ b/apps/dokploy/components/dashboard/search-command.tsx @@ -18,6 +18,7 @@ import { CommandList, CommandSeparator, } from "@/components/ui/command"; +import { authClient } from "@/lib/auth"; import { type Services, extractServices, @@ -28,7 +29,6 @@ import { BookIcon, CircuitBoard, GlobeIcon } from "lucide-react"; import { useRouter } from "next/router"; import React from "react"; import { StatusTooltip } from "../shared/status-tooltip"; -import { authClient } from "@/lib/auth"; type Project = Awaited>; diff --git a/apps/dokploy/components/layouts/user-nav.tsx b/apps/dokploy/components/layouts/user-nav.tsx index d2ad153be..18d459f07 100644 --- a/apps/dokploy/components/layouts/user-nav.tsx +++ b/apps/dokploy/components/layouts/user-nav.tsx @@ -15,6 +15,7 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { authClient } from "@/lib/auth"; import { Languages } from "@/lib/languages"; import { api } from "@/utils/api"; import useLocale from "@/utils/hooks/use-locale"; @@ -24,7 +25,6 @@ import { useRouter } from "next/router"; import { useEffect, useRef, useState } from "react"; import { ModeToggle } from "../ui/modeToggle"; import { SidebarMenuButton } from "../ui/sidebar"; -import { authClient } from "@/lib/auth"; const AUTO_CHECK_UPDATES_INTERVAL_MINUTES = 7; diff --git a/apps/dokploy/lib/auth.ts b/apps/dokploy/lib/auth.ts index d050b3608..a5b193700 100644 --- a/apps/dokploy/lib/auth.ts +++ b/apps/dokploy/lib/auth.ts @@ -1,5 +1,5 @@ -import { createAuthClient } from "better-auth/react"; import { organizationClient } from "better-auth/client/plugins"; +import { createAuthClient } from "better-auth/react"; export const authClient = createAuthClient({ baseURL: "http://localhost:3000", // the base url of your auth server diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 7877e65cc..e5cc0500d 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -16,10 +16,10 @@ import { Input } from "@/components/ui/input"; import { authClient } from "@/lib/auth"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; -import { auth, IS_CLOUD, isAdminPresent } from "@dokploy/server"; +import { IS_CLOUD, auth, isAdminPresent } from "@dokploy/server"; import { validateRequest } from "@dokploy/server/lib/auth"; import { zodResolver } from "@hookform/resolvers/zod"; -import { getSessionCookie, Session } from "better-auth"; +import { Session, getSessionCookie } from "better-auth"; import { betterFetch } from "better-auth/react"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index 0bd911414..10e9965b5 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,9 +1,9 @@ import { + boolean, + integer, pgTable, text, - integer, timestamp, - boolean, } from "drizzle-orm/pg-core"; export const user = pgTable("user", { diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 082176b2c..8a3e1781c 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -1,10 +1,10 @@ +import type { IncomingMessage } from "node:http"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { admin, createAuthMiddleware, organization } from "better-auth/plugins"; +import { eq } from "drizzle-orm"; import { db } from "../db"; import * as schema from "../db/schema"; -import type { IncomingMessage } from "node:http"; -import { eq } from "drizzle-orm"; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", From 1db6ba94f4153b39d0295f18c72bf6ceee6e003d Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 9 Feb 2025 21:36:36 -0600 Subject: [PATCH 05/89] refactor: remove --- apps/dokploy/drizzle/meta/0066_snapshot.json | 4686 ----------------- apps/dokploy/drizzle/meta/_journal.json | 8 +- .../{0066_broad_marrow.sql => old_migration} | 0 3 files changed, 1 insertion(+), 4693 deletions(-) delete mode 100644 apps/dokploy/drizzle/meta/0066_snapshot.json rename apps/dokploy/drizzle/{0066_broad_marrow.sql => old_migration} (100%) diff --git a/apps/dokploy/drizzle/meta/0066_snapshot.json b/apps/dokploy/drizzle/meta/0066_snapshot.json deleted file mode 100644 index 8572b47b4..000000000 --- a/apps/dokploy/drizzle/meta/0066_snapshot.json +++ /dev/null @@ -1,4686 +0,0 @@ -{ - "id": "e7c50cc6-9e18-47c5-b155-dd31fc8bd774", - "prevId": "1240ec96-1751-4de3-b64f-cef9cb716786", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.application": { - "name": "application", - "schema": "", - "columns": { - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "previewEnv": { - "name": "previewEnv", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "previewBuildArgs": { - "name": "previewBuildArgs", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "previewWildcard": { - "name": "previewWildcard", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "previewPort": { - "name": "previewPort", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 3000 - }, - "previewHttps": { - "name": "previewHttps", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "previewPath": { - "name": "previewPath", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'/'" - }, - "certificateType": { - "name": "certificateType", - "type": "certificateType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'none'" - }, - "previewLimit": { - "name": "previewLimit", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 3 - }, - "isPreviewDeploymentsActive": { - "name": "isPreviewDeploymentsActive", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "buildArgs": { - "name": "buildArgs", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "subtitle": { - "name": "subtitle", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "refreshToken": { - "name": "refreshToken", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sourceType": { - "name": "sourceType", - "type": "sourceType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'github'" - }, - "repository": { - "name": "repository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "owner": { - "name": "owner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "branch": { - "name": "branch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "buildPath": { - "name": "buildPath", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'/'" - }, - "autoDeploy": { - "name": "autoDeploy", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "gitlabProjectId": { - "name": "gitlabProjectId", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "gitlabRepository": { - "name": "gitlabRepository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabOwner": { - "name": "gitlabOwner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabBranch": { - "name": "gitlabBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabBuildPath": { - "name": "gitlabBuildPath", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'/'" - }, - "gitlabPathNamespace": { - "name": "gitlabPathNamespace", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketRepository": { - "name": "bitbucketRepository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketOwner": { - "name": "bitbucketOwner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketBranch": { - "name": "bitbucketBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketBuildPath": { - "name": "bitbucketBuildPath", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'/'" - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "registryUrl": { - "name": "registryUrl", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitUrl": { - "name": "customGitUrl", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitBranch": { - "name": "customGitBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitBuildPath": { - "name": "customGitBuildPath", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitSSHKeyId": { - "name": "customGitSSHKeyId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dockerfile": { - "name": "dockerfile", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dockerContextPath": { - "name": "dockerContextPath", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dockerBuildStage": { - "name": "dockerBuildStage", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dropBuildPath": { - "name": "dropBuildPath", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "healthCheckSwarm": { - "name": "healthCheckSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "restartPolicySwarm": { - "name": "restartPolicySwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "placementSwarm": { - "name": "placementSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "updateConfigSwarm": { - "name": "updateConfigSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "rollbackConfigSwarm": { - "name": "rollbackConfigSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "modeSwarm": { - "name": "modeSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "labelsSwarm": { - "name": "labelsSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "networkSwarm": { - "name": "networkSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "replicas": { - "name": "replicas", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "buildType": { - "name": "buildType", - "type": "buildType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'nixpacks'" - }, - "herokuVersion": { - "name": "herokuVersion", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'24'" - }, - "publishDirectory": { - "name": "publishDirectory", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "registryId": { - "name": "registryId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "githubId": { - "name": "githubId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabId": { - "name": "gitlabId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketId": { - "name": "bitbucketId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { - "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", - "tableFrom": "application", - "tableTo": "ssh-key", - "columnsFrom": [ - "customGitSSHKeyId" - ], - "columnsTo": [ - "sshKeyId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "application_registryId_registry_registryId_fk": { - "name": "application_registryId_registry_registryId_fk", - "tableFrom": "application", - "tableTo": "registry", - "columnsFrom": [ - "registryId" - ], - "columnsTo": [ - "registryId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "application_projectId_project_projectId_fk": { - "name": "application_projectId_project_projectId_fk", - "tableFrom": "application", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "application_githubId_github_githubId_fk": { - "name": "application_githubId_github_githubId_fk", - "tableFrom": "application", - "tableTo": "github", - "columnsFrom": [ - "githubId" - ], - "columnsTo": [ - "githubId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "application_gitlabId_gitlab_gitlabId_fk": { - "name": "application_gitlabId_gitlab_gitlabId_fk", - "tableFrom": "application", - "tableTo": "gitlab", - "columnsFrom": [ - "gitlabId" - ], - "columnsTo": [ - "gitlabId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "application_bitbucketId_bitbucket_bitbucketId_fk": { - "name": "application_bitbucketId_bitbucket_bitbucketId_fk", - "tableFrom": "application", - "tableTo": "bitbucket", - "columnsFrom": [ - "bitbucketId" - ], - "columnsTo": [ - "bitbucketId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "application_serverId_server_serverId_fk": { - "name": "application_serverId_server_serverId_fk", - "tableFrom": "application", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "application_appName_unique": { - "name": "application_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.postgres": { - "name": "postgres", - "schema": "", - "columns": { - "postgresId": { - "name": "postgresId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databaseName": { - "name": "databaseName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databaseUser": { - "name": "databaseUser", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databasePassword": { - "name": "databasePassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "externalPort": { - "name": "externalPort", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "postgres_projectId_project_projectId_fk": { - "name": "postgres_projectId_project_projectId_fk", - "tableFrom": "postgres", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "postgres_serverId_server_serverId_fk": { - "name": "postgres_serverId_server_serverId_fk", - "tableFrom": "postgres", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "postgres_appName_unique": { - "name": "postgres_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "isRegistered": { - "name": "isRegistered", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "expirationDate": { - "name": "expirationDate", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "canCreateProjects": { - "name": "canCreateProjects", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canAccessToSSHKeys": { - "name": "canAccessToSSHKeys", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canCreateServices": { - "name": "canCreateServices", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canDeleteProjects": { - "name": "canDeleteProjects", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canDeleteServices": { - "name": "canDeleteServices", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canAccessToDocker": { - "name": "canAccessToDocker", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canAccessToAPI": { - "name": "canAccessToAPI", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canAccessToGitProviders": { - "name": "canAccessToGitProviders", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canAccessToTraefikFiles": { - "name": "canAccessToTraefikFiles", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "accesedProjects": { - "name": "accesedProjects", - "type": "text[]", - "primaryKey": false, - "notNull": true, - "default": "ARRAY[]::text[]" - }, - "accesedServices": { - "name": "accesedServices", - "type": "text[]", - "primaryKey": false, - "notNull": true, - "default": "ARRAY[]::text[]" - }, - "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 - }, - "role": { - "name": "role", - "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'" - }, - "host": { - "name": "host", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "letsEncryptEmail": { - "name": "letsEncryptEmail", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sshPrivateKey": { - "name": "sshPrivateKey", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "enableDockerCleanup": { - "name": "enableDockerCleanup", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "enableLogRotation": { - "name": "enableLogRotation", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "enablePaidFeatures": { - "name": "enablePaidFeatures", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "metricsConfig": { - "name": "metricsConfig", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" - }, - "cleanupCacheApplications": { - "name": "cleanupCacheApplications", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "cleanupCacheOnPreviews": { - "name": "cleanupCacheOnPreviews", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "cleanupCacheOnCompose": { - "name": "cleanupCacheOnCompose", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_email_unique": { - "name": "user_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.admin": { - "name": "admin", - "schema": "", - "columns": {}, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.auth": { - "name": "auth", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "rol": { - "name": "rol", - "type": "Roles", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "image": { - "name": "image", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "secret": { - "name": "secret", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is2FAEnabled": { - "name": "is2FAEnabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "resetPasswordToken": { - "name": "resetPasswordToken", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "resetPasswordExpiresAt": { - "name": "resetPasswordExpiresAt", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "confirmationToken": { - "name": "confirmationToken", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "confirmationExpiresAt": { - "name": "confirmationExpiresAt", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "auth_email_unique": { - "name": "auth_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.project": { - "name": "project", - "schema": "", - "columns": { - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" - } - }, - "indexes": {}, - "foreignKeys": { - "project_userId_user_id_fk": { - "name": "project_userId_user_id_fk", - "tableFrom": "project", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "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 - }, - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "previewDeploymentId": { - "name": "previewDeploymentId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "certificateType": { - "name": "certificateType", - "type": "certificateType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'none'" - } - }, - "indexes": {}, - "foreignKeys": { - "domain_composeId_compose_composeId_fk": { - "name": "domain_composeId_compose_composeId_fk", - "tableFrom": "domain", - "tableTo": "compose", - "columnsFrom": [ - "composeId" - ], - "columnsTo": [ - "composeId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "domain_applicationId_application_applicationId_fk": { - "name": "domain_applicationId_application_applicationId_fk", - "tableFrom": "domain", - "tableTo": "application", - "columnsFrom": [ - "applicationId" - ], - "columnsTo": [ - "applicationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { - "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", - "tableFrom": "domain", - "tableTo": "preview_deployments", - "columnsFrom": [ - "previewDeploymentId" - ], - "columnsTo": [ - "previewDeploymentId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.mariadb": { - "name": "mariadb", - "schema": "", - "columns": { - "mariadbId": { - "name": "mariadbId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "databaseName": { - "name": "databaseName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databaseUser": { - "name": "databaseUser", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databasePassword": { - "name": "databasePassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "rootPassword": { - "name": "rootPassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "externalPort": { - "name": "externalPort", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "mariadb_projectId_project_projectId_fk": { - "name": "mariadb_projectId_project_projectId_fk", - "tableFrom": "mariadb", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mariadb_serverId_server_serverId_fk": { - "name": "mariadb_serverId_server_serverId_fk", - "tableFrom": "mariadb", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "mariadb_appName_unique": { - "name": "mariadb_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.mongo": { - "name": "mongo", - "schema": "", - "columns": { - "mongoId": { - "name": "mongoId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "databaseUser": { - "name": "databaseUser", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databasePassword": { - "name": "databasePassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "externalPort": { - "name": "externalPort", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "replicaSets": { - "name": "replicaSets", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - } - }, - "indexes": {}, - "foreignKeys": { - "mongo_projectId_project_projectId_fk": { - "name": "mongo_projectId_project_projectId_fk", - "tableFrom": "mongo", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mongo_serverId_server_serverId_fk": { - "name": "mongo_serverId_server_serverId_fk", - "tableFrom": "mongo", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "mongo_appName_unique": { - "name": "mongo_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.mysql": { - "name": "mysql", - "schema": "", - "columns": { - "mysqlId": { - "name": "mysqlId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "databaseName": { - "name": "databaseName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databaseUser": { - "name": "databaseUser", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databasePassword": { - "name": "databasePassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "rootPassword": { - "name": "rootPassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "externalPort": { - "name": "externalPort", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "mysql_projectId_project_projectId_fk": { - "name": "mysql_projectId_project_projectId_fk", - "tableFrom": "mysql", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mysql_serverId_server_serverId_fk": { - "name": "mysql_serverId_server_serverId_fk", - "tableFrom": "mysql", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "mysql_appName_unique": { - "name": "mysql_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.backup": { - "name": "backup", - "schema": "", - "columns": { - "backupId": { - "name": "backupId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "schedule": { - "name": "schedule", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "database": { - "name": "database", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "prefix": { - "name": "prefix", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "destinationId": { - "name": "destinationId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databaseType": { - "name": "databaseType", - "type": "databaseType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "postgresId": { - "name": "postgresId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mariadbId": { - "name": "mariadbId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mysqlId": { - "name": "mysqlId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mongoId": { - "name": "mongoId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "backup_destinationId_destination_destinationId_fk": { - "name": "backup_destinationId_destination_destinationId_fk", - "tableFrom": "backup", - "tableTo": "destination", - "columnsFrom": [ - "destinationId" - ], - "columnsTo": [ - "destinationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "backup_postgresId_postgres_postgresId_fk": { - "name": "backup_postgresId_postgres_postgresId_fk", - "tableFrom": "backup", - "tableTo": "postgres", - "columnsFrom": [ - "postgresId" - ], - "columnsTo": [ - "postgresId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "backup_mariadbId_mariadb_mariadbId_fk": { - "name": "backup_mariadbId_mariadb_mariadbId_fk", - "tableFrom": "backup", - "tableTo": "mariadb", - "columnsFrom": [ - "mariadbId" - ], - "columnsTo": [ - "mariadbId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "backup_mysqlId_mysql_mysqlId_fk": { - "name": "backup_mysqlId_mysql_mysqlId_fk", - "tableFrom": "backup", - "tableTo": "mysql", - "columnsFrom": [ - "mysqlId" - ], - "columnsTo": [ - "mysqlId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "backup_mongoId_mongo_mongoId_fk": { - "name": "backup_mongoId_mongo_mongoId_fk", - "tableFrom": "backup", - "tableTo": "mongo", - "columnsFrom": [ - "mongoId" - ], - "columnsTo": [ - "mongoId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.destination": { - "name": "destination", - "schema": "", - "columns": { - "destinationId": { - "name": "destinationId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "provider": { - "name": "provider", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "accessKey": { - "name": "accessKey", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "secretAccessKey": { - "name": "secretAccessKey", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "bucket": { - "name": "bucket", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "region": { - "name": "region", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "endpoint": { - "name": "endpoint", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "destination_userId_user_id_fk": { - "name": "destination_userId_user_id_fk", - "tableFrom": "destination", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "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 - }, - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "composeId": { - "name": "composeId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "isPreviewDeployment": { - "name": "isPreviewDeployment", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "previewDeploymentId": { - "name": "previewDeploymentId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "errorMessage": { - "name": "errorMessage", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "deployment_applicationId_application_applicationId_fk": { - "name": "deployment_applicationId_application_applicationId_fk", - "tableFrom": "deployment", - "tableTo": "application", - "columnsFrom": [ - "applicationId" - ], - "columnsTo": [ - "applicationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "deployment_composeId_compose_composeId_fk": { - "name": "deployment_composeId_compose_composeId_fk", - "tableFrom": "deployment", - "tableTo": "compose", - "columnsFrom": [ - "composeId" - ], - "columnsTo": [ - "composeId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "deployment_serverId_server_serverId_fk": { - "name": "deployment_serverId_server_serverId_fk", - "tableFrom": "deployment", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { - "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", - "tableFrom": "deployment", - "tableTo": "preview_deployments", - "columnsFrom": [ - "previewDeploymentId" - ], - "columnsTo": [ - "previewDeploymentId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.mount": { - "name": "mount", - "schema": "", - "columns": { - "mountId": { - "name": "mountId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "type": { - "name": "type", - "type": "mountType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "hostPath": { - "name": "hostPath", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "volumeName": { - "name": "volumeName", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "filePath": { - "name": "filePath", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "content": { - "name": "content", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "serviceType": { - "name": "serviceType", - "type": "serviceType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'application'" - }, - "mountPath": { - "name": "mountPath", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "postgresId": { - "name": "postgresId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mariadbId": { - "name": "mariadbId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mongoId": { - "name": "mongoId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mysqlId": { - "name": "mysqlId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "redisId": { - "name": "redisId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "composeId": { - "name": "composeId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "mount_applicationId_application_applicationId_fk": { - "name": "mount_applicationId_application_applicationId_fk", - "tableFrom": "mount", - "tableTo": "application", - "columnsFrom": [ - "applicationId" - ], - "columnsTo": [ - "applicationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_postgresId_postgres_postgresId_fk": { - "name": "mount_postgresId_postgres_postgresId_fk", - "tableFrom": "mount", - "tableTo": "postgres", - "columnsFrom": [ - "postgresId" - ], - "columnsTo": [ - "postgresId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_mariadbId_mariadb_mariadbId_fk": { - "name": "mount_mariadbId_mariadb_mariadbId_fk", - "tableFrom": "mount", - "tableTo": "mariadb", - "columnsFrom": [ - "mariadbId" - ], - "columnsTo": [ - "mariadbId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_mongoId_mongo_mongoId_fk": { - "name": "mount_mongoId_mongo_mongoId_fk", - "tableFrom": "mount", - "tableTo": "mongo", - "columnsFrom": [ - "mongoId" - ], - "columnsTo": [ - "mongoId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_mysqlId_mysql_mysqlId_fk": { - "name": "mount_mysqlId_mysql_mysqlId_fk", - "tableFrom": "mount", - "tableTo": "mysql", - "columnsFrom": [ - "mysqlId" - ], - "columnsTo": [ - "mysqlId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_redisId_redis_redisId_fk": { - "name": "mount_redisId_redis_redisId_fk", - "tableFrom": "mount", - "tableTo": "redis", - "columnsFrom": [ - "redisId" - ], - "columnsTo": [ - "redisId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_composeId_compose_composeId_fk": { - "name": "mount_composeId_compose_composeId_fk", - "tableFrom": "mount", - "tableTo": "compose", - "columnsFrom": [ - "composeId" - ], - "columnsTo": [ - "composeId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.certificate": { - "name": "certificate", - "schema": "", - "columns": { - "certificateId": { - "name": "certificateId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "certificateData": { - "name": "certificateData", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "privateKey": { - "name": "privateKey", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "certificatePath": { - "name": "certificatePath", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "autoRenew": { - "name": "autoRenew", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "certificate_userId_user_id_fk": { - "name": "certificate_userId_user_id_fk", - "tableFrom": "certificate", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "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": { - "name": "session", - "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 - } - }, - "indexes": {}, - "foreignKeys": { - "session_user_id_user_id_fk": { - "name": "session_user_id_user_id_fk", - "tableFrom": "session", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "session_token_unique": { - "name": "session_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 - }, - "targetPort": { - "name": "targetPort", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "protocol": { - "name": "protocol", - "type": "protocolType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "port_applicationId_application_applicationId_fk": { - "name": "port_applicationId_application_applicationId_fk", - "tableFrom": "port", - "tableTo": "application", - "columnsFrom": [ - "applicationId" - ], - "columnsTo": [ - "applicationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.redis": { - "name": "redis", - "schema": "", - "columns": { - "redisId": { - "name": "redisId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "externalPort": { - "name": "externalPort", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "redis_projectId_project_projectId_fk": { - "name": "redis_projectId_project_projectId_fk", - "tableFrom": "redis", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "redis_serverId_server_serverId_fk": { - "name": "redis_serverId_server_serverId_fk", - "tableFrom": "redis", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "redis_appName_unique": { - "name": "redis_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.compose": { - "name": "compose", - "schema": "", - "columns": { - "composeId": { - "name": "composeId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "composeFile": { - "name": "composeFile", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" - }, - "refreshToken": { - "name": "refreshToken", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sourceType": { - "name": "sourceType", - "type": "sourceTypeCompose", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'github'" - }, - "composeType": { - "name": "composeType", - "type": "composeType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'docker-compose'" - }, - "repository": { - "name": "repository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "owner": { - "name": "owner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "branch": { - "name": "branch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "autoDeploy": { - "name": "autoDeploy", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "gitlabProjectId": { - "name": "gitlabProjectId", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "gitlabRepository": { - "name": "gitlabRepository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabOwner": { - "name": "gitlabOwner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabBranch": { - "name": "gitlabBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabPathNamespace": { - "name": "gitlabPathNamespace", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketRepository": { - "name": "bitbucketRepository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketOwner": { - "name": "bitbucketOwner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketBranch": { - "name": "bitbucketBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitUrl": { - "name": "customGitUrl", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitBranch": { - "name": "customGitBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitSSHKeyId": { - "name": "customGitSSHKeyId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" - }, - "composePath": { - "name": "composePath", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'./docker-compose.yml'" - }, - "suffix": { - "name": "suffix", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" - }, - "randomize": { - "name": "randomize", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "isolatedDeployment": { - "name": "isolatedDeployment", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "composeStatus": { - "name": "composeStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "githubId": { - "name": "githubId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabId": { - "name": "gitlabId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketId": { - "name": "bitbucketId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { - "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", - "tableFrom": "compose", - "tableTo": "ssh-key", - "columnsFrom": [ - "customGitSSHKeyId" - ], - "columnsTo": [ - "sshKeyId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "compose_projectId_project_projectId_fk": { - "name": "compose_projectId_project_projectId_fk", - "tableFrom": "compose", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "compose_githubId_github_githubId_fk": { - "name": "compose_githubId_github_githubId_fk", - "tableFrom": "compose", - "tableTo": "github", - "columnsFrom": [ - "githubId" - ], - "columnsTo": [ - "githubId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "compose_gitlabId_gitlab_gitlabId_fk": { - "name": "compose_gitlabId_gitlab_gitlabId_fk", - "tableFrom": "compose", - "tableTo": "gitlab", - "columnsFrom": [ - "gitlabId" - ], - "columnsTo": [ - "gitlabId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "compose_bitbucketId_bitbucket_bitbucketId_fk": { - "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", - "tableFrom": "compose", - "tableTo": "bitbucket", - "columnsFrom": [ - "bitbucketId" - ], - "columnsTo": [ - "bitbucketId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "compose_serverId_server_serverId_fk": { - "name": "compose_serverId_server_serverId_fk", - "tableFrom": "compose", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.registry": { - "name": "registry", - "schema": "", - "columns": { - "registryId": { - "name": "registryId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "registryName": { - "name": "registryName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "imagePrefix": { - "name": "imagePrefix", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "registryUrl": { - "name": "registryUrl", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "selfHosted": { - "name": "selfHosted", - "type": "RegistryType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'cloud'" - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "registry_userId_user_id_fk": { - "name": "registry_userId_user_id_fk", - "tableFrom": "registry", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "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 - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "notification_slackId_slack_slackId_fk": { - "name": "notification_slackId_slack_slackId_fk", - "tableFrom": "notification", - "tableTo": "slack", - "columnsFrom": [ - "slackId" - ], - "columnsTo": [ - "slackId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "notification_telegramId_telegram_telegramId_fk": { - "name": "notification_telegramId_telegram_telegramId_fk", - "tableFrom": "notification", - "tableTo": "telegram", - "columnsFrom": [ - "telegramId" - ], - "columnsTo": [ - "telegramId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "notification_discordId_discord_discordId_fk": { - "name": "notification_discordId_discord_discordId_fk", - "tableFrom": "notification", - "tableTo": "discord", - "columnsFrom": [ - "discordId" - ], - "columnsTo": [ - "discordId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "notification_emailId_email_emailId_fk": { - "name": "notification_emailId_email_emailId_fk", - "tableFrom": "notification", - "tableTo": "email", - "columnsFrom": [ - "emailId" - ], - "columnsTo": [ - "emailId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "notification_gotifyId_gotify_gotifyId_fk": { - "name": "notification_gotifyId_gotify_gotifyId_fk", - "tableFrom": "notification", - "tableTo": "gotify", - "columnsFrom": [ - "gotifyId" - ], - "columnsTo": [ - "gotifyId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "notification_userId_user_id_fk": { - "name": "notification_userId_user_id_fk", - "tableFrom": "notification", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "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 - } - }, - "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 - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "ssh-key_userId_user_id_fk": { - "name": "ssh-key_userId_user_id_fk", - "tableFrom": "ssh-key", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "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 - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "git_provider_userId_user_id_fk": { - "name": "git_provider_userId_user_id_fk", - "tableFrom": "git_provider", - "tableTo": "user", - "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.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 - }, - "userId": { - "name": "userId", - "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_userId_user_id_fk": { - "name": "server_userId_user_id_fk", - "tableFrom": "server", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "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.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_id_fk": { - "name": "account_user_id_user_id_fk", - "tableFrom": "account", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "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 - } - }, - "enums": { - "public.buildType": { - "name": "buildType", - "schema": "public", - "values": [ - "dockerfile", - "heroku_buildpacks", - "paketo_buildpacks", - "nixpacks", - "static" - ] - }, - "public.sourceType": { - "name": "sourceType", - "schema": "public", - "values": [ - "docker", - "git", - "github", - "gitlab", - "bitbucket", - "drop" - ] - }, - "public.Roles": { - "name": "Roles", - "schema": "public", - "values": [ - "admin", - "user" - ] - }, - "public.domainType": { - "name": "domainType", - "schema": "public", - "values": [ - "compose", - "application", - "preview" - ] - }, - "public.databaseType": { - "name": "databaseType", - "schema": "public", - "values": [ - "postgres", - "mariadb", - "mysql", - "mongo" - ] - }, - "public.deploymentStatus": { - "name": "deploymentStatus", - "schema": "public", - "values": [ - "running", - "done", - "error" - ] - }, - "public.mountType": { - "name": "mountType", - "schema": "public", - "values": [ - "bind", - "volume", - "file" - ] - }, - "public.serviceType": { - "name": "serviceType", - "schema": "public", - "values": [ - "application", - "postgres", - "mysql", - "mariadb", - "mongo", - "redis", - "compose" - ] - }, - "public.protocolType": { - "name": "protocolType", - "schema": "public", - "values": [ - "tcp", - "udp" - ] - }, - "public.applicationStatus": { - "name": "applicationStatus", - "schema": "public", - "values": [ - "idle", - "running", - "done", - "error" - ] - }, - "public.certificateType": { - "name": "certificateType", - "schema": "public", - "values": [ - "letsencrypt", - "none" - ] - }, - "public.composeType": { - "name": "composeType", - "schema": "public", - "values": [ - "docker-compose", - "stack" - ] - }, - "public.sourceTypeCompose": { - "name": "sourceTypeCompose", - "schema": "public", - "values": [ - "git", - "github", - "gitlab", - "bitbucket", - "raw" - ] - }, - "public.RegistryType": { - "name": "RegistryType", - "schema": "public", - "values": [ - "selfHosted", - "cloud" - ] - }, - "public.notificationType": { - "name": "notificationType", - "schema": "public", - "values": [ - "slack", - "telegram", - "discord", - "email", - "gotify" - ] - }, - "public.gitProviderType": { - "name": "gitProviderType", - "schema": "public", - "values": [ - "github", - "gitlab", - "bitbucket" - ] - }, - "public.serverStatus": { - "name": "serverStatus", - "schema": "public", - "values": [ - "active", - "inactive" - ] - } - }, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 8d09d2090..bd626bf9d 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -463,13 +463,7 @@ "when": 1739087857244, "tag": "0065_daily_zaladane", "breakpoints": true - }, - { - "idx": 66, - "version": "7", - "when": 1739142819089, - "tag": "0066_broad_marrow", - "breakpoints": true } + ] } \ No newline at end of file diff --git a/apps/dokploy/drizzle/0066_broad_marrow.sql b/apps/dokploy/drizzle/old_migration similarity index 100% rename from apps/dokploy/drizzle/0066_broad_marrow.sql rename to apps/dokploy/drizzle/old_migration From b7112b89fdc85a7f2b06ef475aabd1fd0430e8e6 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Mon, 10 Feb 2025 00:39:46 -0600 Subject: [PATCH 06/89] refactor: add migration --- apps/dokploy/drizzle/0066_calm_vengeance.sql | 367 ++ apps/dokploy/drizzle/meta/0066_snapshot.json | 4940 ++++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 8 +- packages/server/auth-schema.ts | 3 + packages/server/package.json | 1 + packages/server/src/db/schema/account.ts | 3 + packages/server/src/db/schema/dbml.ts | 7 + packages/server/src/db/schema/schema.dbml | 872 ++++ packages/server/src/db/schema/user.ts | 26 +- pnpm-lock.yaml | 12 + 10 files changed, 6227 insertions(+), 12 deletions(-) create mode 100644 apps/dokploy/drizzle/0066_calm_vengeance.sql create mode 100644 apps/dokploy/drizzle/meta/0066_snapshot.json create mode 100644 packages/server/src/db/schema/dbml.ts create mode 100644 packages/server/src/db/schema/schema.dbml diff --git a/apps/dokploy/drizzle/0066_calm_vengeance.sql b/apps/dokploy/drizzle/0066_calm_vengeance.sql new file mode 100644 index 000000000..3901740b3 --- /dev/null +++ b/apps/dokploy/drizzle/0066_calm_vengeance.sql @@ -0,0 +1,367 @@ +-- Primero ejecutar todas las modificaciones estructurales +ALTER TABLE "user" RENAME COLUMN "userId" TO "id"; +--> statement-breakpoint +ALTER TABLE "project" RENAME COLUMN "adminId" TO "userId"; +--> statement-breakpoint +ALTER TABLE "destination" RENAME COLUMN "adminId" TO "userId"; +--> statement-breakpoint +ALTER TABLE "certificate" RENAME COLUMN "adminId" TO "userId"; +--> statement-breakpoint +ALTER TABLE "registry" RENAME COLUMN "adminId" TO "userId"; +--> statement-breakpoint +ALTER TABLE "notification" RENAME COLUMN "adminId" TO "userId"; +--> statement-breakpoint +ALTER TABLE "ssh-key" RENAME COLUMN "adminId" TO "userId"; +--> statement-breakpoint +ALTER TABLE "git_provider" RENAME COLUMN "adminId" TO "userId"; +--> statement-breakpoint +ALTER TABLE "server" RENAME COLUMN "adminId" TO "userId"; +--> statement-breakpoint +ALTER TABLE "user" DROP CONSTRAINT "user_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "user" DROP CONSTRAINT "user_authId_auth_id_fk"; +--> statement-breakpoint +ALTER TABLE "admin" DROP CONSTRAINT "admin_authId_auth_id_fk"; +--> statement-breakpoint +ALTER TABLE "project" DROP CONSTRAINT "project_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "destination" DROP CONSTRAINT "destination_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "certificate" DROP CONSTRAINT "certificate_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "session" DROP CONSTRAINT "session_user_id_auth_id_fk"; +--> statement-breakpoint +ALTER TABLE "registry" DROP CONSTRAINT "registry_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "notification" DROP CONSTRAINT "notification_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "ssh-key" DROP CONSTRAINT "ssh-key_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "git_provider" DROP CONSTRAINT "git_provider_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "server" DROP CONSTRAINT "server_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "user" ALTER COLUMN "expirationDate" SET DATA TYPE text; +--> statement-breakpoint +ALTER TABLE "session" ALTER COLUMN "expires_at" SET DATA TYPE timestamp; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "name" text DEFAULT '' NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "email" text NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "email_verified" boolean NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "image" text; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "role" text; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "banned" boolean; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "ban_reason" text; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "ban_expires" timestamp; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "updated_at" timestamp NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "serverIp" text; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "certificateType" "certificateType" DEFAULT 'none' NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "host" text; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "letsEncryptEmail" text; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "sshPrivateKey" text; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "enableDockerCleanup" boolean DEFAULT false NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "enableLogRotation" boolean DEFAULT false NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "enablePaidFeatures" boolean DEFAULT false NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "metricsConfig" jsonb 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 NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "cleanupCacheApplications" boolean DEFAULT false NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "cleanupCacheOnPreviews" boolean DEFAULT false NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "cleanupCacheOnCompose" boolean DEFAULT false NOT NULL; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "stripeCustomerId" text; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "stripeSubscriptionId" text; +--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "serversQuantity" integer DEFAULT 0 NOT NULL; +--> statement-breakpoint +ALTER TABLE "session" ADD COLUMN "token" text NOT NULL; +--> statement-breakpoint +ALTER TABLE "session" ADD COLUMN "created_at" timestamp NOT NULL; +--> statement-breakpoint +ALTER TABLE "session" ADD COLUMN "updated_at" timestamp NOT NULL; +--> statement-breakpoint +ALTER TABLE "session" ADD COLUMN "ip_address" text; +--> statement-breakpoint +ALTER TABLE "session" ADD COLUMN "user_agent" text; +--> statement-breakpoint +ALTER TABLE "session" ADD COLUMN "impersonated_by" text; +--> statement-breakpoint +ALTER TABLE "session" ADD COLUMN "active_organization_id" text; +--> statement-breakpoint +CREATE TABLE "account" ( + "id" text PRIMARY KEY NOT NULL, + "account_id" text NOT NULL, + "provider_id" text NOT NULL, + "user_id" text NOT NULL, + "access_token" text, + "refresh_token" text, + "id_token" text, + "access_token_expires_at" timestamp, + "refresh_token_expires_at" timestamp, + "scope" text, + "password" text, + "is2FAEnabled" boolean DEFAULT false NOT NULL, + "created_at" timestamp NOT NULL, + "updated_at" timestamp NOT NULL, + "resetPasswordToken" text, + "resetPasswordExpiresAt" text, + "confirmationToken" text, + "confirmationExpiresAt" text +); +--> statement-breakpoint +CREATE TABLE "invitation" ( + "id" text PRIMARY KEY NOT NULL, + "organization_id" text NOT NULL, + "email" text NOT NULL, + "role" text, + "status" text NOT NULL, + "expires_at" timestamp NOT NULL, + "inviter_id" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE "member" ( + "id" text PRIMARY KEY NOT NULL, + "organization_id" text NOT NULL, + "user_id" text NOT NULL, + "role" text NOT NULL, + "created_at" timestamp NOT NULL +); +--> statement-breakpoint +CREATE TABLE "organization" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "slug" text, + "logo" text, + "created_at" timestamp NOT NULL, + "metadata" text, + "owner_id" text NOT NULL, + CONSTRAINT "organization_slug_unique" UNIQUE("slug") +); +--> statement-breakpoint +CREATE TABLE "verification" ( + "id" text PRIMARY KEY NOT NULL, + "identifier" text NOT NULL, + "value" text NOT NULL, + "expires_at" timestamp NOT NULL, + "created_at" timestamp, + "updated_at" timestamp +); +--> statement-breakpoint +ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "invitation" ADD CONSTRAINT "invitation_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "invitation" ADD CONSTRAINT "invitation_inviter_id_user_id_fk" FOREIGN KEY ("inviter_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "project" ADD CONSTRAINT "project_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "destination" ADD CONSTRAINT "destination_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "certificate" ADD CONSTRAINT "certificate_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "registry" ADD CONSTRAINT "registry_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "notification" ADD CONSTRAINT "notification_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "ssh-key" ADD CONSTRAINT "ssh-key_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "git_provider" ADD CONSTRAINT "git_provider_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "server" ADD CONSTRAINT "server_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +--> statement-breakpoint +ALTER TABLE "user" DROP COLUMN "adminId"; +--> statement-breakpoint +ALTER TABLE "user" DROP COLUMN "authId"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "adminId"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "serverIp"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "certificateType"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "host"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "letsEncryptEmail"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "sshPrivateKey"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "enableDockerCleanup"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "enableLogRotation"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "authId"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "createdAt"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "stripeCustomerId"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "stripeSubscriptionId"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "serversQuantity"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "enablePaidFeatures"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "metricsConfig"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "cleanupCacheApplications"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "cleanupCacheOnPreviews"; +--> statement-breakpoint +ALTER TABLE "admin" DROP COLUMN "cleanupCacheOnCompose"; +--> statement-breakpoint +ALTER TABLE "user" ADD CONSTRAINT "user_email_unique" UNIQUE("email"); +--> statement-breakpoint + +-- Primero quitar NOT NULL temporalmente +ALTER TABLE "session" ALTER COLUMN "token" DROP NOT NULL; +--> statement-breakpoint + +-- Actualizar tokens existentes +UPDATE "session" SET + token = gen_random_uuid(), + created_at = COALESCE(created_at, NOW() - interval '1 day'), + updated_at = NOW() +WHERE token IS NULL; + +-- Restablecer restricciones +ALTER TABLE "session" ALTER COLUMN "token" SET NOT NULL; +ALTER TABLE "session" ADD CONSTRAINT "session_token_unique" UNIQUE (token); + +-- Luego realizar la migración de datos +-- Migración de datos para Admins +WITH admin_users AS ( + INSERT INTO "user" ( + id, created_at, token, email, email_verified, role, updated_at, + certificate_type, server_ip, host, lets_encrypt_email, ssh_private_key, + enable_docker_cleanup, enable_log_rotation, enable_paid_features, + metrics_config, cleanup_cache_applications, cleanup_cache_on_previews, + cleanup_cache_on_compose, stripe_customer_id, stripe_subscription_id, + servers_quantity + ) + SELECT + gen_random_uuid(), + a.created_at, + a.token, + a.email, + true, + 'admin', + a.created_at, + ad.certificate_type, + ad.server_ip, + ad.host, + ad.lets_encrypt_email, + ad.ssh_private_key, + ad.enable_docker_cleanup, + ad.enable_log_rotation, + ad.enable_paid_features, + ad.metrics_config, + ad.cleanup_cache_applications, + ad.cleanup_cache_on_previews, + ad.cleanup_cache_on_compose, + ad.stripe_customer_id, + ad.stripe_subscription_id, + ad.servers_quantity + FROM auth a + JOIN admins ad ON a.id = ad.auth_id + RETURNING id AS user_id, created_at, email +) +INSERT INTO account (id, account_id, provider_id, user_id, password, created_at, updated_at) +SELECT + gen_random_uuid(), + a.id, + 'credentials', + au.user_id, + a.password, + au.created_at, + au.created_at +FROM auth a +JOIN admin_users au ON a.email = au.email; + +-- Crear organizaciones para admins +WITH admin_orgs AS ( + INSERT INTO organization (id, name, slug, created_at, owner_id) + SELECT + gen_random_uuid(), + 'My Organization', + 'org/' || au.user_id, + au.created_at, + au.user_id + FROM admin_users au + RETURNING id AS org_id, owner_id +) +-- Migrar usuarios regulares y asociar a organizaciones +INSERT INTO "user" ( + id, created_at, token, email, email_verified, role, updated_at, + can_create_projects, can_access_ssh_keys +) +SELECT + gen_random_uuid(), + a.created_at, + a.token, + a.email, + true, + 'user', + a.created_at, + u.can_create_projects, + u.can_access_ssh_keys +FROM auth a +JOIN users u ON a.id = u.auth_id +WHERE a.role = 'user'; + +-- Crear accounts para usuarios +INSERT INTO account (id, account_id, provider_id, user_id, password, created_at, updated_at) +SELECT + gen_random_uuid(), + a.id, + 'credentials', + u.id, + a.password, + a.created_at, + a.created_at +FROM auth a +JOIN "user" u ON a.email = u.email; + +-- Asociar usuarios a organizaciones de sus admins +INSERT INTO member (id, organization_id, user_id, role, created_at) +SELECT + gen_random_uuid(), + ao.org_id, + u.id, + 'user', + u.created_at +FROM "user" u +JOIN users old_u ON u.email = old_u.email +JOIN auth a ON old_u.auth_id = a.id +JOIN admin_orgs ao ON ao.owner_id = a.id; + +-- Eliminar tablas obsoletas +DROP TABLE IF EXISTS admins; +DROP TABLE IF EXISTS users; +DROP TABLE IF EXISTS auth; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0066_snapshot.json b/apps/dokploy/drizzle/meta/0066_snapshot.json new file mode 100644 index 000000000..83cdfe7e3 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0066_snapshot.json @@ -0,0 +1,4940 @@ +{ + "id": "5963096c-1a97-4e26-9f3f-f8613a359596", + "prevId": "1240ec96-1751-4de3-b64f-cef9cb716786", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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 + }, + "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[]" + }, + "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 + }, + "role": { + "name": "role", + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.admin": { + "name": "admin", + "schema": "", + "columns": {}, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resetPasswordToken": { + "name": "resetPasswordToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resetPasswordExpiresAt": { + "name": "resetPasswordExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationToken": { + "name": "confirmationToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationExpiresAt": { + "name": "confirmationExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "project_userId_user_id_fk": { + "name": "project_userId_user_id_fk", + "tableFrom": "project", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "destination_userId_user_id_fk": { + "name": "destination_userId_user_id_fk", + "tableFrom": "destination", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "certificate_userId_user_id_fk": { + "name": "certificate_userId_user_id_fk", + "tableFrom": "certificate", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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": { + "name": "session", + "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_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_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 + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_userId_user_id_fk": { + "name": "registry_userId_user_id_fk", + "tableFrom": "registry", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "notification_slackId_slack_slackId_fk": { + "name": "notification_slackId_slack_slackId_fk", + "tableFrom": "notification", + "tableTo": "slack", + "columnsFrom": [ + "slackId" + ], + "columnsTo": [ + "slackId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_telegramId_telegram_telegramId_fk": { + "name": "notification_telegramId_telegram_telegramId_fk", + "tableFrom": "notification", + "tableTo": "telegram", + "columnsFrom": [ + "telegramId" + ], + "columnsTo": [ + "telegramId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_discordId_discord_discordId_fk": { + "name": "notification_discordId_discord_discordId_fk", + "tableFrom": "notification", + "tableTo": "discord", + "columnsFrom": [ + "discordId" + ], + "columnsTo": [ + "discordId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_emailId_email_emailId_fk": { + "name": "notification_emailId_email_emailId_fk", + "tableFrom": "notification", + "tableTo": "email", + "columnsFrom": [ + "emailId" + ], + "columnsTo": [ + "emailId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_gotifyId_gotify_gotifyId_fk": { + "name": "notification_gotifyId_gotify_gotifyId_fk", + "tableFrom": "notification", + "tableTo": "gotify", + "columnsFrom": [ + "gotifyId" + ], + "columnsTo": [ + "gotifyId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_userId_user_id_fk": { + "name": "notification_userId_user_id_fk", + "tableFrom": "notification", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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 + } + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "ssh-key_userId_user_id_fk": { + "name": "ssh-key_userId_user_id_fk", + "tableFrom": "ssh-key", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "git_provider_userId_user_id_fk": { + "name": "git_provider_userId_user_id_fk", + "tableFrom": "git_provider", + "tableTo": "user", + "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.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 + }, + "userId": { + "name": "userId", + "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_userId_user_id_fk": { + "name": "server_userId_user_id_fk", + "tableFrom": "server", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "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.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_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "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 + } + }, + "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": "no action", + "onUpdate": "no action" + }, + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": [ + "inviter_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "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 + } + }, + "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": "no action", + "onUpdate": "no action" + }, + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "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_id_fk": { + "name": "organization_owner_id_user_id_fk", + "tableFrom": "organization", + "tableTo": "user", + "columnsFrom": [ + "owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index bd626bf9d..8c06b6375 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -463,7 +463,13 @@ "when": 1739087857244, "tag": "0065_daily_zaladane", "breakpoints": true + }, + { + "idx": 66, + "version": "7", + "when": 1739168611366, + "tag": "0066_calm_vengeance", + "breakpoints": true } - ] } \ No newline at end of file diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index 10e9965b5..8b09e3366 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -64,6 +64,9 @@ export const organization = pgTable("organization", { logo: text("logo"), createdAt: timestamp("created_at").notNull(), metadata: text("metadata"), + ownerId: text("owner_id") + .notNull() + .references(() => user.id), }); export const member = pgTable("member", { diff --git a/packages/server/package.json b/packages/server/package.json index 228344210..a8cf97c66 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -28,6 +28,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "drizzle-dbml-generator":"0.10.0", "better-auth":"1.1.16", "rotating-file-stream": "3.2.3", "@faker-js/faker": "^8.4.1", diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 38c630275..ce963a0d3 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -40,6 +40,9 @@ export const organization = pgTable("organization", { logo: text("logo"), createdAt: timestamp("created_at").notNull(), metadata: text("metadata"), + ownerId: text("owner_id") + .notNull() + .references(() => user.id), }); export const member = pgTable("member", { diff --git a/packages/server/src/db/schema/dbml.ts b/packages/server/src/db/schema/dbml.ts new file mode 100644 index 000000000..72a758146 --- /dev/null +++ b/packages/server/src/db/schema/dbml.ts @@ -0,0 +1,7 @@ +import { pgGenerate } from "drizzle-dbml-generator"; // Using Postgres for this example +import * as schema from "./index"; + +const out = "./schema.dbml"; +const relational = true; + +pgGenerate({ schema, out, relational }); diff --git a/packages/server/src/db/schema/schema.dbml b/packages/server/src/db/schema/schema.dbml new file mode 100644 index 000000000..ce2b5abca --- /dev/null +++ b/packages/server/src/db/schema/schema.dbml @@ -0,0 +1,872 @@ +enum applicationStatus { + idle + running + done + error +} + +enum buildType { + dockerfile + heroku_buildpacks + paketo_buildpacks + nixpacks + static +} + +enum certificateType { + letsencrypt + none +} + +enum composeType { + "docker-compose" + stack +} + +enum databaseType { + postgres + mariadb + mysql + mongo +} + +enum deploymentStatus { + running + done + error +} + +enum domainType { + compose + application + preview +} + +enum gitProviderType { + github + gitlab + bitbucket +} + +enum mountType { + bind + volume + file +} + +enum notificationType { + slack + telegram + discord + email + gotify +} + +enum protocolType { + tcp + udp +} + +enum RegistryType { + selfHosted + cloud +} + +enum Roles { + admin + user +} + +enum serverStatus { + active + inactive +} + +enum serviceType { + application + postgres + mysql + mariadb + mongo + redis + compose +} + +enum sourceType { + docker + git + github + gitlab + bitbucket + drop +} + +enum sourceTypeCompose { + git + github + gitlab + bitbucket + raw +} + +table account { + id text [pk, not null] + account_id text [not null] + provider_id text [not null] + user_id text [not null] + access_token text + refresh_token text + id_token text + access_token_expires_at timestamp + refresh_token_expires_at timestamp + scope text + password text + is2FAEnabled boolean [not null, default: false] + created_at timestamp [not null] + updated_at timestamp [not null] + resetPasswordToken text + resetPasswordExpiresAt text + confirmationToken text + confirmationExpiresAt text +} + +table admin { +} + +table application { + applicationId text [pk, not null] + name text [not null] + appName text [not null, unique] + description text + env text + previewEnv text + previewBuildArgs text + previewWildcard text + previewPort integer [default: 3000] + previewHttps boolean [not null, default: false] + previewPath text [default: '/'] + certificateType certificateType [not null, default: 'none'] + previewLimit integer [default: 3] + isPreviewDeploymentsActive boolean [default: false] + buildArgs text + memoryReservation text + memoryLimit text + cpuReservation text + cpuLimit text + title text + enabled boolean + subtitle text + command text + refreshToken text + sourceType sourceType [not null, default: 'github'] + repository text + owner text + branch text + buildPath text [default: '/'] + autoDeploy boolean + gitlabProjectId integer + gitlabRepository text + gitlabOwner text + gitlabBranch text + gitlabBuildPath text [default: '/'] + gitlabPathNamespace text + bitbucketRepository text + bitbucketOwner text + bitbucketBranch text + bitbucketBuildPath text [default: '/'] + username text + password text + dockerImage text + registryUrl text + customGitUrl text + customGitBranch text + customGitBuildPath text + customGitSSHKeyId text + dockerfile text + dockerContextPath text + dockerBuildStage text + dropBuildPath text + healthCheckSwarm json + restartPolicySwarm json + placementSwarm json + updateConfigSwarm json + rollbackConfigSwarm json + modeSwarm json + labelsSwarm json + networkSwarm json + replicas integer [not null, default: 1] + applicationStatus applicationStatus [not null, default: 'idle'] + buildType buildType [not null, default: 'nixpacks'] + herokuVersion text [default: '24'] + publishDirectory text + createdAt text [not null] + registryId text + projectId text [not null] + githubId text + gitlabId text + bitbucketId text + serverId text +} + +table auth { + id text [pk, not null] + email text [not null, unique] + password text [not null] + rol Roles [not null] + image text + secret text + token text + is2FAEnabled boolean [not null, default: false] + createdAt text [not null] + resetPasswordToken text + resetPasswordExpiresAt text + confirmationToken text + confirmationExpiresAt text +} + +table backup { + backupId text [pk, not null] + schedule text [not null] + enabled boolean + database text [not null] + prefix text [not null] + destinationId text [not null] + databaseType databaseType [not null] + postgresId text + mariadbId text + mysqlId text + mongoId text +} + +table bitbucket { + bitbucketId text [pk, not null] + bitbucketUsername text + appPassword text + bitbucketWorkspaceName text + gitProviderId text [not null] +} + +table certificate { + certificateId text [pk, not null] + name text [not null] + certificateData text [not null] + privateKey text [not null] + certificatePath text [not null, unique] + autoRenew boolean + userId text + serverId text +} + +table compose { + composeId text [pk, not null] + name text [not null] + appName text [not null] + description text + env text + composeFile text [not null, default: ''] + refreshToken text + sourceType sourceTypeCompose [not null, default: 'github'] + composeType composeType [not null, default: 'docker-compose'] + repository text + owner text + branch text + autoDeploy boolean + gitlabProjectId integer + gitlabRepository text + gitlabOwner text + gitlabBranch text + gitlabPathNamespace text + bitbucketRepository text + bitbucketOwner text + bitbucketBranch text + customGitUrl text + customGitBranch text + customGitSSHKeyId text + command text [not null, default: ''] + composePath text [not null, default: './docker-compose.yml'] + suffix text [not null, default: ''] + randomize boolean [not null, default: false] + isolatedDeployment boolean [not null, default: false] + composeStatus applicationStatus [not null, default: 'idle'] + projectId text [not null] + createdAt text [not null] + githubId text + gitlabId text + bitbucketId text + serverId text +} + +table deployment { + deploymentId text [pk, not null] + title text [not null] + description text + status deploymentStatus [default: 'running'] + logPath text [not null] + applicationId text + composeId text + serverId text + isPreviewDeployment boolean [default: false] + previewDeploymentId text + createdAt text [not null] + errorMessage text +} + +table destination { + destinationId text [pk, not null] + name text [not null] + provider text + accessKey text [not null] + secretAccessKey text [not null] + bucket text [not null] + region text [not null] + endpoint text [not null] + userId text [not null] +} + +table discord { + discordId text [pk, not null] + webhookUrl text [not null] + decoration boolean +} + +table domain { + domainId text [pk, not null] + host text [not null] + https boolean [not null, default: false] + port integer [default: 3000] + path text [default: '/'] + serviceName text + domainType domainType [default: 'application'] + uniqueConfigKey serial [not null, increment] + createdAt text [not null] + composeId text + applicationId text + previewDeploymentId text + certificateType certificateType [not null, default: 'none'] +} + +table email { + emailId text [pk, not null] + smtpServer text [not null] + smtpPort integer [not null] + username text [not null] + password text [not null] + fromAddress text [not null] + toAddress text[] [not null] +} + +table git_provider { + gitProviderId text [pk, not null] + name text [not null] + providerType gitProviderType [not null, default: 'github'] + createdAt text [not null] + userId text +} + +table github { + githubId text [pk, not null] + githubAppName text + githubAppId integer + githubClientId text + githubClientSecret text + githubInstallationId text + githubPrivateKey text + githubWebhookSecret text + gitProviderId text [not null] +} + +table gitlab { + gitlabId text [pk, not null] + gitlabUrl text [not null, default: 'https://gitlab.com'] + application_id text + redirect_uri text + secret text + access_token text + refresh_token text + group_name text + expires_at integer + gitProviderId text [not null] +} + +table gotify { + gotifyId text [pk, not null] + serverUrl text [not null] + appToken text [not null] + priority integer [not null, default: 5] + decoration boolean +} + +table invitation { + id text [pk, not null] + organization_id text [not null] + email text [not null] + role text + status text [not null] + expires_at timestamp [not null] + inviter_id text [not null] +} + +table mariadb { + mariadbId text [pk, not null] + name text [not null] + appName text [not null, unique] + description text + databaseName text [not null] + databaseUser text [not null] + databasePassword text [not null] + rootPassword text [not null] + dockerImage text [not null] + command text + env text + memoryReservation text + memoryLimit text + cpuReservation text + cpuLimit text + externalPort integer + applicationStatus applicationStatus [not null, default: 'idle'] + createdAt text [not null] + projectId text [not null] + serverId text +} + +table member { + id text [pk, not null] + organization_id text [not null] + user_id text [not null] + role text [not null] + created_at timestamp [not null] +} + +table mongo { + mongoId text [pk, not null] + name text [not null] + appName text [not null, unique] + description text + databaseUser text [not null] + databasePassword text [not null] + dockerImage text [not null] + command text + env text + memoryReservation text + memoryLimit text + cpuReservation text + cpuLimit text + externalPort integer + applicationStatus applicationStatus [not null, default: 'idle'] + createdAt text [not null] + projectId text [not null] + serverId text + replicaSets boolean [default: false] +} + +table mount { + mountId text [pk, not null] + type mountType [not null] + hostPath text + volumeName text + filePath text + content text + serviceType serviceType [not null, default: 'application'] + mountPath text [not null] + applicationId text + postgresId text + mariadbId text + mongoId text + mysqlId text + redisId text + composeId text +} + +table mysql { + mysqlId text [pk, not null] + name text [not null] + appName text [not null, unique] + description text + databaseName text [not null] + databaseUser text [not null] + databasePassword text [not null] + rootPassword text [not null] + dockerImage text [not null] + command text + env text + memoryReservation text + memoryLimit text + cpuReservation text + cpuLimit text + externalPort integer + applicationStatus applicationStatus [not null, default: 'idle'] + createdAt text [not null] + projectId text [not null] + serverId text +} + +table notification { + notificationId text [pk, not null] + name text [not null] + appDeploy boolean [not null, default: false] + appBuildError boolean [not null, default: false] + databaseBackup boolean [not null, default: false] + dokployRestart boolean [not null, default: false] + dockerCleanup boolean [not null, default: false] + serverThreshold boolean [not null, default: false] + notificationType notificationType [not null] + createdAt text [not null] + slackId text + telegramId text + discordId text + emailId text + gotifyId text + userId text +} + +table organization { + id text [pk, not null] + name text [not null] + slug text [unique] + logo text + created_at timestamp [not null] + metadata text + owner_id text [not null] +} + +table port { + portId text [pk, not null] + publishedPort integer [not null] + targetPort integer [not null] + protocol protocolType [not null] + applicationId text [not null] +} + +table postgres { + postgresId text [pk, not null] + name text [not null] + appName text [not null, unique] + databaseName text [not null] + databaseUser text [not null] + databasePassword text [not null] + description text + dockerImage text [not null] + command text + env text + memoryReservation text + externalPort integer + memoryLimit text + cpuReservation text + cpuLimit text + applicationStatus applicationStatus [not null, default: 'idle'] + createdAt text [not null] + projectId text [not null] + serverId text +} + +table preview_deployments { + previewDeploymentId text [pk, not null] + branch text [not null] + pullRequestId text [not null] + pullRequestNumber text [not null] + pullRequestURL text [not null] + pullRequestTitle text [not null] + pullRequestCommentId text [not null] + previewStatus applicationStatus [not null, default: 'idle'] + appName text [not null, unique] + applicationId text [not null] + domainId text + createdAt text [not null] + expiresAt text +} + +table project { + projectId text [pk, not null] + name text [not null] + description text + createdAt text [not null] + userId text [not null] + env text [not null, default: ''] +} + +table redirect { + redirectId text [pk, not null] + regex text [not null] + replacement text [not null] + permanent boolean [not null, default: false] + uniqueConfigKey serial [not null, increment] + createdAt text [not null] + applicationId text [not null] +} + +table redis { + redisId text [pk, not null] + name text [not null] + appName text [not null, unique] + description text + password text [not null] + dockerImage text [not null] + command text + env text + memoryReservation text + memoryLimit text + cpuReservation text + cpuLimit text + externalPort integer + createdAt text [not null] + applicationStatus applicationStatus [not null, default: 'idle'] + projectId text [not null] + serverId text +} + +table registry { + registryId text [pk, not null] + registryName text [not null] + imagePrefix text + username text [not null] + password text [not null] + registryUrl text [not null, default: ''] + createdAt text [not null] + selfHosted RegistryType [not null, default: 'cloud'] + userId text [not null] +} + +table security { + securityId text [pk, not null] + username text [not null] + password text [not null] + createdAt text [not null] + applicationId text [not null] + + indexes { + (username, applicationId) [name: 'security_username_applicationId_unique', unique] + } +} + +table server { + serverId text [pk, not null] + name text [not null] + description text + ipAddress text [not null] + port integer [not null] + username text [not null, default: 'root'] + appName text [not null] + enableDockerCleanup boolean [not null, default: false] + createdAt text [not null] + userId text [not null] + serverStatus serverStatus [not null, default: 'active'] + command text [not null, default: ''] + sshKeyId text + metricsConfig jsonb [not null, default: `{"server":{"type":"Remote","refreshRate":60,"port":4500,"token":"","urlCallback":"","cronJob":"","retentionDays":2,"thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}`] +} + +table session { + id text [pk, not null] + expires_at timestamp [not null] + token text [not null, unique] + created_at timestamp [not null] + updated_at timestamp [not null] + ip_address text + user_agent text + user_id text [not null] + impersonated_by text + active_organization_id text +} + +table slack { + slackId text [pk, not null] + webhookUrl text [not null] + channel text +} + +table "ssh-key" { + sshKeyId text [pk, not null] + privateKey text [not null, default: ''] + publicKey text [not null] + name text [not null] + description text + createdAt text [not null] + lastUsedAt text + userId text +} + +table telegram { + telegramId text [pk, not null] + botToken text [not null] + chatId text [not null] +} + +table user { + id text [pk, not null] + name text [not null, default: ''] + token text [not null] + isRegistered boolean [not null, default: false] + expirationDate text [not null] + createdAt text [not null] + canCreateProjects boolean [not null, default: false] + canAccessToSSHKeys boolean [not null, default: false] + canCreateServices boolean [not null, default: false] + canDeleteProjects boolean [not null, default: false] + canDeleteServices boolean [not null, default: false] + canAccessToDocker boolean [not null, default: false] + canAccessToAPI boolean [not null, default: false] + canAccessToGitProviders boolean [not null, default: false] + canAccessToTraefikFiles boolean [not null, default: false] + accesedProjects text[] [not null, default: `ARRAY[]::text[]`] + accesedServices text[] [not null, default: `ARRAY[]::text[]`] + email text [not null, unique] + email_verified boolean [not null] + image text + role text + banned boolean + ban_reason text + ban_expires timestamp + updated_at timestamp [not null] + serverIp text + certificateType certificateType [not null, default: 'none'] + host text + letsEncryptEmail text + sshPrivateKey text + enableDockerCleanup boolean [not null, default: false] + enableLogRotation boolean [not null, default: false] + enablePaidFeatures boolean [not null, default: false] + metricsConfig jsonb [not null, default: `{"server":{"type":"Dokploy","refreshRate":60,"port":4500,"token":"","retentionDays":2,"cronJob":"","urlCallback":"","thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}`] + cleanupCacheApplications boolean [not null, default: false] + cleanupCacheOnPreviews boolean [not null, default: false] + cleanupCacheOnCompose boolean [not null, default: false] + stripeCustomerId text + stripeSubscriptionId text + serversQuantity integer [not null, default: 0] +} + +table verification { + id text [pk, not null] + identifier text [not null] + value text [not null] + expires_at timestamp [not null] + created_at timestamp + updated_at timestamp +} + +ref: mount.applicationId > application.applicationId + +ref: mount.postgresId > postgres.postgresId + +ref: mount.mariadbId > mariadb.mariadbId + +ref: mount.mongoId > mongo.mongoId + +ref: mount.mysqlId > mysql.mysqlId + +ref: mount.redisId > redis.redisId + +ref: mount.composeId > compose.composeId + +ref: application.projectId > project.projectId + +ref: application.customGitSSHKeyId > "ssh-key".sshKeyId + +ref: application.registryId > registry.registryId + +ref: application.githubId - github.githubId + +ref: application.gitlabId - gitlab.gitlabId + +ref: application.bitbucketId - bitbucket.bitbucketId + +ref: application.serverId > server.serverId + +ref: backup.destinationId > destination.destinationId + +ref: backup.postgresId > postgres.postgresId + +ref: backup.mariadbId > mariadb.mariadbId + +ref: backup.mysqlId > mysql.mysqlId + +ref: backup.mongoId > mongo.mongoId + +ref: git_provider.gitProviderId - bitbucket.gitProviderId + +ref: certificate.serverId > server.serverId + +ref: certificate.userId - user.id + +ref: compose.projectId > project.projectId + +ref: compose.customGitSSHKeyId > "ssh-key".sshKeyId + +ref: compose.githubId - github.githubId + +ref: compose.gitlabId - gitlab.gitlabId + +ref: compose.bitbucketId - bitbucket.bitbucketId + +ref: compose.serverId > server.serverId + +ref: deployment.applicationId > application.applicationId + +ref: deployment.composeId > compose.composeId + +ref: deployment.serverId > server.serverId + +ref: deployment.previewDeploymentId > preview_deployments.previewDeploymentId + +ref: destination.userId - user.id + +ref: domain.applicationId > application.applicationId + +ref: domain.composeId > compose.composeId + +ref: preview_deployments.domainId - domain.domainId + +ref: github.gitProviderId - git_provider.gitProviderId + +ref: gitlab.gitProviderId - git_provider.gitProviderId + +ref: git_provider.userId - user.id + +ref: mariadb.projectId > project.projectId + +ref: mariadb.serverId > server.serverId + +ref: mongo.projectId > project.projectId + +ref: mongo.serverId > server.serverId + +ref: mysql.projectId > project.projectId + +ref: mysql.serverId > server.serverId + +ref: notification.slackId - slack.slackId + +ref: notification.telegramId - telegram.telegramId + +ref: notification.discordId - discord.discordId + +ref: notification.emailId - email.emailId + +ref: notification.gotifyId - gotify.gotifyId + +ref: notification.userId - user.id + +ref: port.applicationId > application.applicationId + +ref: postgres.projectId > project.projectId + +ref: postgres.serverId > server.serverId + +ref: preview_deployments.applicationId > application.applicationId + +ref: project.userId - user.id + +ref: redirect.applicationId > application.applicationId + +ref: redis.projectId > project.projectId + +ref: redis.serverId > server.serverId + +ref: registry.userId - user.id + +ref: security.applicationId > application.applicationId + +ref: server.userId - user.id + +ref: server.sshKeyId > "ssh-key".sshKeyId + +ref: "ssh-key".userId - user.id \ No newline at end of file diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index bb06f8bc0..886cedbb3 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -1,5 +1,12 @@ import { relations, sql } from "drizzle-orm"; -import { boolean, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core"; +import { + boolean, + integer, + jsonb, + pgTable, + text, + timestamp, +} from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; @@ -22,18 +29,12 @@ export const user = pgTable("user", { name: text("name").notNull().default(""), token: text("token").notNull(), isRegistered: boolean("isRegistered").notNull().default(false), - expirationDate: timestamp("expirationDate", { - precision: 3, - mode: "date", - }) + expirationDate: text("expirationDate") .notNull() - .$defaultFn(() => new Date()), - createdAt: timestamp("createdAt", { - precision: 3, - mode: "date", - }) + .$defaultFn(() => new Date().toISOString()), + createdAt: text("createdAt") .notNull() - .$defaultFn(() => new Date()), + .$defaultFn(() => new Date().toISOString()), canCreateProjects: boolean("canCreateProjects").notNull().default(false), canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false), canCreateServices: boolean("canCreateServices").notNull().default(false), @@ -132,6 +133,9 @@ export const user = pgTable("user", { cleanupCacheOnCompose: boolean("cleanupCacheOnCompose") .notNull() .default(false), + stripeCustomerId: text("stripeCustomerId"), + stripeSubscriptionId: text("stripeSubscriptionId"), + serversQuantity: integer("serversQuantity").notNull().default(0), }); export const usersRelations = relations(user, ({ one }) => ({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 555822409..bb49174f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -588,6 +588,9 @@ importers: dotenv: specifier: 16.4.5 version: 16.4.5 + drizzle-dbml-generator: + specifier: 0.10.0 + version: 0.10.0(drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7)) drizzle-orm: specifier: ^0.39.1 version: 0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7) @@ -4446,6 +4449,11 @@ packages: resolution: {integrity: sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==} engines: {node: '>=4'} + drizzle-dbml-generator@0.10.0: + resolution: {integrity: sha512-cMZq9E3U3RlmE0uBeXyc6oWJ0royOkC6HiTlc9LDeMe+W87poZTzKoNYUyAxZrs4Q1RQtob+cGKiefV4ZoI8HA==} + peerDependencies: + drizzle-orm: '>=0.36.0' + drizzle-kit@0.30.4: resolution: {integrity: sha512-B2oJN5UkvwwNHscPWXDG5KqAixu7AUzZ3qbe++KU9SsQ+cZWR4DXEPYcvWplyFAno0dhRJECNEhNxiDmFaPGyQ==} hasBin: true @@ -11119,6 +11127,10 @@ snapshots: drange@1.1.1: {} + drizzle-dbml-generator@0.10.0(drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7)): + dependencies: + drizzle-orm: 0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7) + drizzle-kit@0.30.4: dependencies: '@drizzle-team/brocli': 0.10.2 From 6179cef1ee19a32da0178a81ca9d183266484467 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Mon, 10 Feb 2025 02:13:52 -0600 Subject: [PATCH 07/89] refactor: update name --- apps/dokploy/drizzle/0066_calm_vengeance.sql | 367 ------------------ apps/dokploy/drizzle/0066_soft_kronos.sql | 183 +++++++++ apps/dokploy/drizzle/meta/0066_snapshot.json | 100 ++--- apps/dokploy/drizzle/meta/_journal.json | 4 +- packages/server/auth-schema.ts | 10 +- packages/server/src/db/schema/account.ts | 8 +- packages/server/src/db/schema/certificate.ts | 2 +- packages/server/src/db/schema/destination.ts | 2 +- packages/server/src/db/schema/git-provider.ts | 2 +- packages/server/src/db/schema/notification.ts | 2 +- packages/server/src/db/schema/project.ts | 2 +- packages/server/src/db/schema/registry.ts | 2 +- packages/server/src/db/schema/server.ts | 2 +- packages/server/src/db/schema/session.ts | 5 +- packages/server/src/db/schema/ssh-key.ts | 2 +- packages/server/src/db/schema/user.ts | 2 +- 16 files changed, 249 insertions(+), 446 deletions(-) delete mode 100644 apps/dokploy/drizzle/0066_calm_vengeance.sql create mode 100644 apps/dokploy/drizzle/0066_soft_kronos.sql diff --git a/apps/dokploy/drizzle/0066_calm_vengeance.sql b/apps/dokploy/drizzle/0066_calm_vengeance.sql deleted file mode 100644 index 3901740b3..000000000 --- a/apps/dokploy/drizzle/0066_calm_vengeance.sql +++ /dev/null @@ -1,367 +0,0 @@ --- Primero ejecutar todas las modificaciones estructurales -ALTER TABLE "user" RENAME COLUMN "userId" TO "id"; ---> statement-breakpoint -ALTER TABLE "project" RENAME COLUMN "adminId" TO "userId"; ---> statement-breakpoint -ALTER TABLE "destination" RENAME COLUMN "adminId" TO "userId"; ---> statement-breakpoint -ALTER TABLE "certificate" RENAME COLUMN "adminId" TO "userId"; ---> statement-breakpoint -ALTER TABLE "registry" RENAME COLUMN "adminId" TO "userId"; ---> statement-breakpoint -ALTER TABLE "notification" RENAME COLUMN "adminId" TO "userId"; ---> statement-breakpoint -ALTER TABLE "ssh-key" RENAME COLUMN "adminId" TO "userId"; ---> statement-breakpoint -ALTER TABLE "git_provider" RENAME COLUMN "adminId" TO "userId"; ---> statement-breakpoint -ALTER TABLE "server" RENAME COLUMN "adminId" TO "userId"; ---> statement-breakpoint -ALTER TABLE "user" DROP CONSTRAINT "user_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "user" DROP CONSTRAINT "user_authId_auth_id_fk"; ---> statement-breakpoint -ALTER TABLE "admin" DROP CONSTRAINT "admin_authId_auth_id_fk"; ---> statement-breakpoint -ALTER TABLE "project" DROP CONSTRAINT "project_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "destination" DROP CONSTRAINT "destination_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "certificate" DROP CONSTRAINT "certificate_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "session" DROP CONSTRAINT "session_user_id_auth_id_fk"; ---> statement-breakpoint -ALTER TABLE "registry" DROP CONSTRAINT "registry_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "notification" DROP CONSTRAINT "notification_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "ssh-key" DROP CONSTRAINT "ssh-key_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "git_provider" DROP CONSTRAINT "git_provider_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "server" DROP CONSTRAINT "server_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "user" ALTER COLUMN "expirationDate" SET DATA TYPE text; ---> statement-breakpoint -ALTER TABLE "session" ALTER COLUMN "expires_at" SET DATA TYPE timestamp; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "name" text DEFAULT '' NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "email" text NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "email_verified" boolean NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "image" text; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "role" text; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "banned" boolean; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "ban_reason" text; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "ban_expires" timestamp; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "updated_at" timestamp NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "serverIp" text; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "certificateType" "certificateType" DEFAULT 'none' NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "host" text; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "letsEncryptEmail" text; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "sshPrivateKey" text; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "enableDockerCleanup" boolean DEFAULT false NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "enableLogRotation" boolean DEFAULT false NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "enablePaidFeatures" boolean DEFAULT false NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "metricsConfig" jsonb 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 NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "cleanupCacheApplications" boolean DEFAULT false NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "cleanupCacheOnPreviews" boolean DEFAULT false NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "cleanupCacheOnCompose" boolean DEFAULT false NOT NULL; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "stripeCustomerId" text; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "stripeSubscriptionId" text; ---> statement-breakpoint -ALTER TABLE "user" ADD COLUMN "serversQuantity" integer DEFAULT 0 NOT NULL; ---> statement-breakpoint -ALTER TABLE "session" ADD COLUMN "token" text NOT NULL; ---> statement-breakpoint -ALTER TABLE "session" ADD COLUMN "created_at" timestamp NOT NULL; ---> statement-breakpoint -ALTER TABLE "session" ADD COLUMN "updated_at" timestamp NOT NULL; ---> statement-breakpoint -ALTER TABLE "session" ADD COLUMN "ip_address" text; ---> statement-breakpoint -ALTER TABLE "session" ADD COLUMN "user_agent" text; ---> statement-breakpoint -ALTER TABLE "session" ADD COLUMN "impersonated_by" text; ---> statement-breakpoint -ALTER TABLE "session" ADD COLUMN "active_organization_id" text; ---> statement-breakpoint -CREATE TABLE "account" ( - "id" text PRIMARY KEY NOT NULL, - "account_id" text NOT NULL, - "provider_id" text NOT NULL, - "user_id" text NOT NULL, - "access_token" text, - "refresh_token" text, - "id_token" text, - "access_token_expires_at" timestamp, - "refresh_token_expires_at" timestamp, - "scope" text, - "password" text, - "is2FAEnabled" boolean DEFAULT false NOT NULL, - "created_at" timestamp NOT NULL, - "updated_at" timestamp NOT NULL, - "resetPasswordToken" text, - "resetPasswordExpiresAt" text, - "confirmationToken" text, - "confirmationExpiresAt" text -); ---> statement-breakpoint -CREATE TABLE "invitation" ( - "id" text PRIMARY KEY NOT NULL, - "organization_id" text NOT NULL, - "email" text NOT NULL, - "role" text, - "status" text NOT NULL, - "expires_at" timestamp NOT NULL, - "inviter_id" text NOT NULL -); ---> statement-breakpoint -CREATE TABLE "member" ( - "id" text PRIMARY KEY NOT NULL, - "organization_id" text NOT NULL, - "user_id" text NOT NULL, - "role" text NOT NULL, - "created_at" timestamp NOT NULL -); ---> statement-breakpoint -CREATE TABLE "organization" ( - "id" text PRIMARY KEY NOT NULL, - "name" text NOT NULL, - "slug" text, - "logo" text, - "created_at" timestamp NOT NULL, - "metadata" text, - "owner_id" text NOT NULL, - CONSTRAINT "organization_slug_unique" UNIQUE("slug") -); ---> statement-breakpoint -CREATE TABLE "verification" ( - "id" text PRIMARY KEY NOT NULL, - "identifier" text NOT NULL, - "value" text NOT NULL, - "expires_at" timestamp NOT NULL, - "created_at" timestamp, - "updated_at" timestamp -); ---> statement-breakpoint -ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "invitation" ADD CONSTRAINT "invitation_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "invitation" ADD CONSTRAINT "invitation_inviter_id_user_id_fk" FOREIGN KEY ("inviter_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "project" ADD CONSTRAINT "project_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "destination" ADD CONSTRAINT "destination_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "certificate" ADD CONSTRAINT "certificate_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "registry" ADD CONSTRAINT "registry_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "notification" ADD CONSTRAINT "notification_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "ssh-key" ADD CONSTRAINT "ssh-key_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "git_provider" ADD CONSTRAINT "git_provider_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "server" ADD CONSTRAINT "server_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; ---> statement-breakpoint -ALTER TABLE "user" DROP COLUMN "adminId"; ---> statement-breakpoint -ALTER TABLE "user" DROP COLUMN "authId"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "adminId"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "serverIp"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "certificateType"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "host"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "letsEncryptEmail"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "sshPrivateKey"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "enableDockerCleanup"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "enableLogRotation"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "authId"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "createdAt"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "stripeCustomerId"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "stripeSubscriptionId"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "serversQuantity"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "enablePaidFeatures"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "metricsConfig"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "cleanupCacheApplications"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "cleanupCacheOnPreviews"; ---> statement-breakpoint -ALTER TABLE "admin" DROP COLUMN "cleanupCacheOnCompose"; ---> statement-breakpoint -ALTER TABLE "user" ADD CONSTRAINT "user_email_unique" UNIQUE("email"); ---> statement-breakpoint - --- Primero quitar NOT NULL temporalmente -ALTER TABLE "session" ALTER COLUMN "token" DROP NOT NULL; ---> statement-breakpoint - --- Actualizar tokens existentes -UPDATE "session" SET - token = gen_random_uuid(), - created_at = COALESCE(created_at, NOW() - interval '1 day'), - updated_at = NOW() -WHERE token IS NULL; - --- Restablecer restricciones -ALTER TABLE "session" ALTER COLUMN "token" SET NOT NULL; -ALTER TABLE "session" ADD CONSTRAINT "session_token_unique" UNIQUE (token); - --- Luego realizar la migración de datos --- Migración de datos para Admins -WITH admin_users AS ( - INSERT INTO "user" ( - id, created_at, token, email, email_verified, role, updated_at, - certificate_type, server_ip, host, lets_encrypt_email, ssh_private_key, - enable_docker_cleanup, enable_log_rotation, enable_paid_features, - metrics_config, cleanup_cache_applications, cleanup_cache_on_previews, - cleanup_cache_on_compose, stripe_customer_id, stripe_subscription_id, - servers_quantity - ) - SELECT - gen_random_uuid(), - a.created_at, - a.token, - a.email, - true, - 'admin', - a.created_at, - ad.certificate_type, - ad.server_ip, - ad.host, - ad.lets_encrypt_email, - ad.ssh_private_key, - ad.enable_docker_cleanup, - ad.enable_log_rotation, - ad.enable_paid_features, - ad.metrics_config, - ad.cleanup_cache_applications, - ad.cleanup_cache_on_previews, - ad.cleanup_cache_on_compose, - ad.stripe_customer_id, - ad.stripe_subscription_id, - ad.servers_quantity - FROM auth a - JOIN admins ad ON a.id = ad.auth_id - RETURNING id AS user_id, created_at, email -) -INSERT INTO account (id, account_id, provider_id, user_id, password, created_at, updated_at) -SELECT - gen_random_uuid(), - a.id, - 'credentials', - au.user_id, - a.password, - au.created_at, - au.created_at -FROM auth a -JOIN admin_users au ON a.email = au.email; - --- Crear organizaciones para admins -WITH admin_orgs AS ( - INSERT INTO organization (id, name, slug, created_at, owner_id) - SELECT - gen_random_uuid(), - 'My Organization', - 'org/' || au.user_id, - au.created_at, - au.user_id - FROM admin_users au - RETURNING id AS org_id, owner_id -) --- Migrar usuarios regulares y asociar a organizaciones -INSERT INTO "user" ( - id, created_at, token, email, email_verified, role, updated_at, - can_create_projects, can_access_ssh_keys -) -SELECT - gen_random_uuid(), - a.created_at, - a.token, - a.email, - true, - 'user', - a.created_at, - u.can_create_projects, - u.can_access_ssh_keys -FROM auth a -JOIN users u ON a.id = u.auth_id -WHERE a.role = 'user'; - --- Crear accounts para usuarios -INSERT INTO account (id, account_id, provider_id, user_id, password, created_at, updated_at) -SELECT - gen_random_uuid(), - a.id, - 'credentials', - u.id, - a.password, - a.created_at, - a.created_at -FROM auth a -JOIN "user" u ON a.email = u.email; - --- Asociar usuarios a organizaciones de sus admins -INSERT INTO member (id, organization_id, user_id, role, created_at) -SELECT - gen_random_uuid(), - ao.org_id, - u.id, - 'user', - u.created_at -FROM "user" u -JOIN users old_u ON u.email = old_u.email -JOIN auth a ON old_u.auth_id = a.id -JOIN admin_orgs ao ON ao.owner_id = a.id; - --- Eliminar tablas obsoletas -DROP TABLE IF EXISTS admins; -DROP TABLE IF EXISTS users; -DROP TABLE IF EXISTS auth; \ No newline at end of file diff --git a/apps/dokploy/drizzle/0066_soft_kronos.sql b/apps/dokploy/drizzle/0066_soft_kronos.sql new file mode 100644 index 000000000..e75a6b247 --- /dev/null +++ b/apps/dokploy/drizzle/0066_soft_kronos.sql @@ -0,0 +1,183 @@ +-- Create new tables +CREATE TABLE IF NOT EXISTS "account" ( + "id" text PRIMARY KEY NOT NULL, + "accountId" text NOT NULL, + "providerId" text NOT NULL, + "userId" text NOT NULL REFERENCES "user"("userId"), + "accessToken" text, + "refreshToken" text, + "idToken" text, + "accessTokenExpiresAt" timestamp, + "refreshTokenExpiresAt" timestamp, + "scope" text, + "password" text, + "is2FAEnabled" boolean DEFAULT false NOT NULL, + "createdAt" timestamp NOT NULL, + "updatedAt" timestamp NOT NULL, + "resetPasswordToken" text, + "resetPasswordExpiresAt" text, + "confirmationToken" text, + "confirmationExpiresAt" text +); + +CREATE TABLE IF NOT EXISTS "organization" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "slug" text, + "logo" text, + "createdAt" timestamp NOT NULL, + "metadata" text, + "ownerId" text NOT NULL REFERENCES "user"("userId"), + CONSTRAINT "organization_slug_unique" UNIQUE("slug") +); + +CREATE TABLE IF NOT EXISTS "member" ( + "id" text PRIMARY KEY NOT NULL, + "organizationId" text NOT NULL REFERENCES "organization"("id"), + "userId" text NOT NULL REFERENCES "user"("userId"), + "role" text NOT NULL, + "createdAt" timestamp NOT NULL +); + +CREATE TABLE IF NOT EXISTS "invitation" ( + "id" text PRIMARY KEY NOT NULL, + "organizationId" text NOT NULL, + "email" text NOT NULL, + "role" text, + "status" text NOT NULL, + "expiresAt" timestamp NOT NULL, + "inviterId" text NOT NULL +); + +CREATE TABLE IF NOT EXISTS "verification" ( + "id" text PRIMARY KEY NOT NULL, + "identifier" text NOT NULL, + "value" text NOT NULL, + "expiresAt" timestamp NOT NULL, + "createdAt" timestamp, + "updatedAt" timestamp +); + +-- Alter existing user table to add new columns +ALTER TABLE "user" +ADD COLUMN IF NOT EXISTS "email" text, +ADD COLUMN IF NOT EXISTS "emailVerified" boolean DEFAULT false, +ADD COLUMN IF NOT EXISTS "role" text, +ADD COLUMN IF NOT EXISTS "certificateType" text DEFAULT 'none', +ADD COLUMN IF NOT EXISTS "serverIp" text, +ADD COLUMN IF NOT EXISTS "host" text, +ADD COLUMN IF NOT EXISTS "letsEncryptEmail" text, +ADD COLUMN IF NOT EXISTS "sshPrivateKey" text, +ADD COLUMN IF NOT EXISTS "enableDockerCleanup" boolean DEFAULT false, +ADD COLUMN IF NOT EXISTS "enableLogRotation" boolean DEFAULT false, +ADD COLUMN IF NOT EXISTS "enablePaidFeatures" boolean DEFAULT false, +ADD COLUMN IF NOT EXISTS "metricsConfig" jsonb DEFAULT '{}', +ADD COLUMN IF NOT EXISTS "cleanupCacheApplications" boolean DEFAULT false, +ADD COLUMN IF NOT EXISTS "cleanupCacheOnPreviews" boolean DEFAULT false, +ADD COLUMN IF NOT EXISTS "cleanupCacheOnCompose" boolean DEFAULT false, +ADD COLUMN IF NOT EXISTS "stripeCustomerId" text, +ADD COLUMN IF NOT EXISTS "stripeSubscriptionId" text, +ADD COLUMN IF NOT EXISTS "serversQuantity" integer DEFAULT 0; + +-- Migrate admin users +WITH admin_users AS ( + UPDATE "user" u + SET + "email" = a."email", + "emailVerified" = true, + "role" = 'admin', + "token" = a."token", + "certificateType" = adm."certificateType", + "serverIp" = adm."serverIp", + "host" = adm."host", + "letsEncryptEmail" = adm."letsEncryptEmail", + "sshPrivateKey" = adm."sshPrivateKey", + "enableDockerCleanup" = adm."enableDockerCleanup", + "enableLogRotation" = adm."enableLogRotation", + "enablePaidFeatures" = adm."enablePaidFeatures", + "metricsConfig" = adm."metricsConfig", + "cleanupCacheApplications" = adm."cleanupCacheApplications", + "cleanupCacheOnPreviews" = adm."cleanupCacheOnPreviews", + "cleanupCacheOnCompose" = adm."cleanupCacheOnCompose", + "stripeCustomerId" = adm."stripeCustomerId", + "stripeSubscriptionId" = adm."stripeSubscriptionId", + "serversQuantity" = adm."serversQuantity" + FROM "auth" a + INNER JOIN "admin" adm ON a."id" = adm."adminId" + WHERE a."id" = u."userId" + RETURNING u."userId", a."email" +) +INSERT INTO "account" ("id", "accountId", "providerId", "password", "userId", "createdAt", "updatedAt") +SELECT + gen_random_uuid(), + a."id", + 'credentials', + a."password", + au."userId", + NOW(), + NOW() +FROM "auth" a +INNER JOIN admin_users au ON a."email" = au."email"; + +-- Create organizations for admin users +WITH admin_orgs AS ( + INSERT INTO "organization" ("id", "name", "slug", "createdAt", "ownerId") + SELECT + gen_random_uuid(), + 'My Organization', + concat('org/', u."userId"), + NOW(), + u."userId" + FROM "user" u + WHERE u."role" = 'admin' + RETURNING * +) +-- Migrate regular users +UPDATE "user" u +SET + "email" = a."email", + "emailVerified" = true, + "role" = 'user', + "token" = a."token", + "canCreateProjects" = usr."canCreateProjects", + "canAccessToSSHKeys" = usr."canAccessToSSHKeys" +FROM "auth" a +INNER JOIN "user" usr ON a."id" = usr."userId" +WHERE a."id" = u."userId" +AND NOT EXISTS ( + SELECT 1 FROM "admin" adm WHERE a."id" = adm."adminId" +); + +-- Create accounts for regular users +INSERT INTO "account" ("id", "accountId", "providerId", "password", "userId", "createdAt", "updatedAt") +SELECT + gen_random_uuid(), + a."id", + 'credentials', + a."password", + u."userId", + NOW(), + NOW() +FROM "auth" a +INNER JOIN "user" u ON a."email" = u."email" +WHERE u."role" = 'user'; + +-- Create member relationships +INSERT INTO "member" ("id", "organizationId", "role", "userId", "createdAt") +SELECT + gen_random_uuid(), + o."id", + 'user', + u."userId", + NOW() +FROM "user" usr +INNER JOIN "user" u ON usr."userId" = u."userId" +INNER JOIN "admin" adm ON usr."adminId" = adm."adminId" +INNER JOIN "user" admin_u ON adm."adminId" = admin_u."userId" +INNER JOIN "organization" o ON o."ownerId" = admin_u."userId" +WHERE u."role" = 'user'; + +-- Drop old tables (after all data is migrated) +DROP TABLE IF EXISTS "sessionTable" CASCADE; +DROP TABLE IF EXISTS "admin" CASCADE; +DROP TABLE IF EXISTS "auth" CASCADE; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0066_snapshot.json b/apps/dokploy/drizzle/meta/0066_snapshot.json index 83cdfe7e3..3ffb0dbf0 100644 --- a/apps/dokploy/drizzle/meta/0066_snapshot.json +++ b/apps/dokploy/drizzle/meta/0066_snapshot.json @@ -1,5 +1,5 @@ { - "id": "5963096c-1a97-4e26-9f3f-f8613a359596", + "id": "d76ab830-b647-4e53-b6cc-0cf515968758", "prevId": "1240ec96-1751-4de3-b64f-cef9cb716786", "version": "7", "dialect": "postgresql", @@ -735,8 +735,8 @@ "name": "user", "schema": "", "columns": { - "id": { - "name": "id", + "userId": { + "name": "userId", "type": "text", "primaryKey": true, "notNull": true @@ -1172,15 +1172,15 @@ }, "indexes": {}, "foreignKeys": { - "project_userId_user_id_fk": { - "name": "project_userId_user_id_fk", + "project_userId_user_userId_fk": { + "name": "project_userId_user_userId_fk", "tableFrom": "project", "tableTo": "user", "columnsFrom": [ "userId" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -2042,15 +2042,15 @@ }, "indexes": {}, "foreignKeys": { - "destination_userId_user_id_fk": { - "name": "destination_userId_user_id_fk", + "destination_userId_user_userId_fk": { + "name": "destination_userId_user_userId_fk", "tableFrom": "destination", "tableTo": "user", "columnsFrom": [ "userId" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -2456,15 +2456,15 @@ }, "indexes": {}, "foreignKeys": { - "certificate_userId_user_id_fk": { - "name": "certificate_userId_user_id_fk", + "certificate_userId_user_userId_fk": { + "name": "certificate_userId_user_userId_fk", "tableFrom": "certificate", "tableTo": "user", "columnsFrom": [ "userId" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -2513,12 +2513,6 @@ "primaryKey": false, "notNull": true }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, "created_at": { "name": "created_at", "type": "timestamp", @@ -2564,30 +2558,22 @@ }, "indexes": {}, "foreignKeys": { - "session_user_id_user_id_fk": { - "name": "session_user_id_user_id_fk", + "session_user_id_user_userId_fk": { + "name": "session_user_id_user_userId_fk", "tableFrom": "session", "tableTo": "user", "columnsFrom": [ "user_id" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "no action", "onUpdate": "no action" } }, "compositePrimaryKeys": {}, - "uniqueConstraints": { - "session_token_unique": { - "name": "session_token_unique", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - }, + "uniqueConstraints": {}, "policies": {}, "checkConstraints": {}, "isRLSEnabled": false @@ -3322,15 +3308,15 @@ }, "indexes": {}, "foreignKeys": { - "registry_userId_user_id_fk": { - "name": "registry_userId_user_id_fk", + "registry_userId_user_userId_fk": { + "name": "registry_userId_user_userId_fk", "tableFrom": "registry", "tableTo": "user", "columnsFrom": [ "userId" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -3647,15 +3633,15 @@ "onDelete": "cascade", "onUpdate": "no action" }, - "notification_userId_user_id_fk": { - "name": "notification_userId_user_id_fk", + "notification_userId_user_userId_fk": { + "name": "notification_userId_user_userId_fk", "tableFrom": "notification", "tableTo": "user", "columnsFrom": [ "userId" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -3785,15 +3771,15 @@ }, "indexes": {}, "foreignKeys": { - "ssh-key_userId_user_id_fk": { - "name": "ssh-key_userId_user_id_fk", + "ssh-key_userId_user_userId_fk": { + "name": "ssh-key_userId_user_userId_fk", "tableFrom": "ssh-key", "tableTo": "user", "columnsFrom": [ "userId" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -3844,15 +3830,15 @@ }, "indexes": {}, "foreignKeys": { - "git_provider_userId_user_id_fk": { - "name": "git_provider_userId_user_id_fk", + "git_provider_userId_user_userId_fk": { + "name": "git_provider_userId_user_userId_fk", "tableFrom": "git_provider", "tableTo": "user", "columnsFrom": [ "userId" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -4187,15 +4173,15 @@ }, "indexes": {}, "foreignKeys": { - "server_userId_user_id_fk": { - "name": "server_userId_user_id_fk", + "server_userId_user_userId_fk": { + "name": "server_userId_user_userId_fk", "tableFrom": "server", "tableTo": "user", "columnsFrom": [ "userId" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -4464,15 +4450,15 @@ }, "indexes": {}, "foreignKeys": { - "account_user_id_user_id_fk": { - "name": "account_user_id_user_id_fk", + "account_user_id_user_userId_fk": { + "name": "account_user_id_user_userId_fk", "tableFrom": "account", "tableTo": "user", "columnsFrom": [ "user_id" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "no action", "onUpdate": "no action" @@ -4546,15 +4532,15 @@ "onDelete": "no action", "onUpdate": "no action" }, - "invitation_inviter_id_user_id_fk": { - "name": "invitation_inviter_id_user_id_fk", + "invitation_inviter_id_user_userId_fk": { + "name": "invitation_inviter_id_user_userId_fk", "tableFrom": "invitation", "tableTo": "user", "columnsFrom": [ "inviter_id" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "no action", "onUpdate": "no action" @@ -4616,15 +4602,15 @@ "onDelete": "no action", "onUpdate": "no action" }, - "member_user_id_user_id_fk": { - "name": "member_user_id_user_id_fk", + "member_user_id_user_userId_fk": { + "name": "member_user_id_user_userId_fk", "tableFrom": "member", "tableTo": "user", "columnsFrom": [ "user_id" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "no action", "onUpdate": "no action" @@ -4685,15 +4671,15 @@ }, "indexes": {}, "foreignKeys": { - "organization_owner_id_user_id_fk": { - "name": "organization_owner_id_user_id_fk", + "organization_owner_id_user_userId_fk": { + "name": "organization_owner_id_user_userId_fk", "tableFrom": "organization", "tableTo": "user", "columnsFrom": [ "owner_id" ], "columnsTo": [ - "id" + "userId" ], "onDelete": "no action", "onUpdate": "no action" diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 8c06b6375..d3de75645 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -467,8 +467,8 @@ { "idx": 66, "version": "7", - "when": 1739168611366, - "tag": "0066_calm_vengeance", + "when": 1739173929725, + "tag": "0066_soft_kronos", "breakpoints": true } ] diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index 8b09e3366..3e19bebe0 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -26,7 +26,7 @@ export const session = pgTable("session", { userAgent: text("user_agent"), userId: text("user_id") .notNull() - .references(() => user.id), + .references(() => user.userId), activeOrganizationId: text("active_organization_id"), }); @@ -36,7 +36,7 @@ export const account = pgTable("account", { providerId: text("provider_id").notNull(), userId: text("user_id") .notNull() - .references(() => user.id), + .references(() => user.userId), accessToken: text("access_token"), refreshToken: text("refresh_token"), idToken: text("id_token"), @@ -66,7 +66,7 @@ export const organization = pgTable("organization", { metadata: text("metadata"), ownerId: text("owner_id") .notNull() - .references(() => user.id), + .references(() => user.userId), }); export const member = pgTable("member", { @@ -76,7 +76,7 @@ export const member = pgTable("member", { .references(() => organization.id), userId: text("user_id") .notNull() - .references(() => user.id), + .references(() => user.userId), role: text("role").notNull(), createdAt: timestamp("created_at").notNull(), }); @@ -92,5 +92,5 @@ export const invitation = pgTable("invitation", { expiresAt: timestamp("expires_at").notNull(), inviterId: text("inviter_id") .notNull() - .references(() => user.id), + .references(() => user.userId), }); diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index ce963a0d3..24350c55c 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -7,7 +7,7 @@ export const account = pgTable("account", { providerId: text("provider_id").notNull(), userId: text("user_id") .notNull() - .references(() => user.id), + .references(() => user.userId), accessToken: text("access_token"), refreshToken: text("refresh_token"), idToken: text("id_token"), @@ -42,7 +42,7 @@ export const organization = pgTable("organization", { metadata: text("metadata"), ownerId: text("owner_id") .notNull() - .references(() => user.id), + .references(() => user.userId), }); export const member = pgTable("member", { @@ -52,7 +52,7 @@ export const member = pgTable("member", { .references(() => organization.id), userId: text("user_id") .notNull() - .references(() => user.id), + .references(() => user.userId), role: text("role").notNull(), createdAt: timestamp("created_at").notNull(), }); @@ -68,5 +68,5 @@ export const invitation = pgTable("invitation", { expiresAt: timestamp("expires_at").notNull(), inviterId: text("inviter_id") .notNull() - .references(() => user.id), + .references(() => user.userId), }); diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts index 3a7ec596d..c1a57a5ac 100644 --- a/packages/server/src/db/schema/certificate.ts +++ b/packages/server/src/db/schema/certificate.ts @@ -20,7 +20,7 @@ export const certificates = pgTable("certificate", { .$defaultFn(() => generateAppName("certificate")) .unique(), autoRenew: boolean("autoRenew"), - userId: text("userId").references(() => user.id, { + userId: text("userId").references(() => user.userId, { onDelete: "cascade", }), serverId: text("serverId").references(() => server.serverId, { diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts index 37faf0fa4..1fe48a346 100644 --- a/packages/server/src/db/schema/destination.ts +++ b/packages/server/src/db/schema/destination.ts @@ -22,7 +22,7 @@ export const destinations = pgTable("destination", { endpoint: text("endpoint").notNull(), userId: text("userId") .notNull() - .references(() => user.id, { onDelete: "cascade" }), + .references(() => user.userId, { onDelete: "cascade" }), }); export const destinationsRelations = relations( diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index f044b0a09..3a3bade81 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -25,7 +25,7 @@ export const gitProvider = pgTable("git_provider", { createdAt: text("createdAt") .notNull() .$defaultFn(() => new Date().toISOString()), - userId: text("userId").references(() => user.id, { + userId: text("userId").references(() => user.userId, { onDelete: "cascade", }), }); diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 5174c17c1..1771a92af 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -45,7 +45,7 @@ export const notifications = pgTable("notification", { gotifyId: text("gotifyId").references(() => gotify.gotifyId, { onDelete: "cascade", }), - userId: text("userId").references(() => user.id, { + userId: text("userId").references(() => user.userId, { onDelete: "cascade", }), }); diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index 2602a8ec0..d83936a38 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -26,7 +26,7 @@ export const projects = pgTable("project", { .$defaultFn(() => new Date().toISOString()), userId: text("userId") .notNull() - .references(() => user.id, { onDelete: "cascade" }), + .references(() => user.userId, { onDelete: "cascade" }), env: text("env").notNull().default(""), }); diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index 166168c5f..936f65fc8 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -30,7 +30,7 @@ export const registry = pgTable("registry", { registryType: registryType("selfHosted").notNull().default("cloud"), userId: text("userId") .notNull() - .references(() => user.id, { onDelete: "cascade" }), + .references(() => user.userId, { onDelete: "cascade" }), }); export const registryRelations = relations(registry, ({ one, many }) => ({ diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index e3a14f953..4e238e23b 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -46,7 +46,7 @@ export const server = pgTable("server", { .$defaultFn(() => new Date().toISOString()), userId: text("userId") .notNull() - .references(() => user.id, { onDelete: "cascade" }), + .references(() => user.userId, { onDelete: "cascade" }), serverStatus: serverStatus("serverStatus").notNull().default("active"), command: text("command").notNull().default(""), sshKeyId: text("sshKeyId").references(() => sshKeys.sshKeyId, { diff --git a/packages/server/src/db/schema/session.ts b/packages/server/src/db/schema/session.ts index 66a410b30..d5932764a 100644 --- a/packages/server/src/db/schema/session.ts +++ b/packages/server/src/db/schema/session.ts @@ -1,3 +1,4 @@ +import { sql } from "drizzle-orm"; import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { user } from "./user"; @@ -5,14 +6,14 @@ import { user } from "./user"; export const session = pgTable("session", { id: text("id").primaryKey(), expiresAt: timestamp("expires_at").notNull(), - token: text("token").notNull().unique(), + // token: text("token").notNull().unique().default(sql`gen_random_uuid()`), createdAt: timestamp("created_at").notNull(), updatedAt: timestamp("updated_at").notNull(), ipAddress: text("ip_address"), userAgent: text("user_agent"), userId: text("user_id") .notNull() - .references(() => user.id), + .references(() => user.userId), impersonatedBy: text("impersonated_by"), activeOrganizationId: text("active_organization_id"), }); diff --git a/packages/server/src/db/schema/ssh-key.ts b/packages/server/src/db/schema/ssh-key.ts index 6c5ba0a7b..9bb69fee4 100644 --- a/packages/server/src/db/schema/ssh-key.ts +++ b/packages/server/src/db/schema/ssh-key.ts @@ -22,7 +22,7 @@ export const sshKeys = pgTable("ssh-key", { .notNull() .$defaultFn(() => new Date().toISOString()), lastUsedAt: text("lastUsedAt"), - userId: text("userId").references(() => user.id, { + userId: text("userId").references(() => user.userId, { onDelete: "cascade", }), }); diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 886cedbb3..00e16679b 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -22,7 +22,7 @@ import { certificateType } from "./shared"; // OLD TABLE export const user = pgTable("user", { - id: text("id") + userId: text("userId") .notNull() .primaryKey() .$defaultFn(() => nanoid()), From 60eee55f2d760866ae374dc6d19269e6e920d892 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Wed, 12 Feb 2025 23:41:04 -0600 Subject: [PATCH 08/89] refactor: test migrastion --- apps/dokploy/drizzle/0066_rapid_morbius.sql | 153 ++++++ apps/dokploy/drizzle/0066_soft_kronos.sql | 187 ------- apps/dokploy/drizzle/meta/0066_snapshot.json | 486 +++++++++++++++--- apps/dokploy/drizzle/meta/_journal.json | 4 +- apps/dokploy/migrate.ts | 117 +++++ apps/dokploy/package.json | 1 + packages/server/auth-schema.ts | 4 +- packages/server/src/db/schema/account.ts | 27 +- packages/server/src/db/schema/admin.ts | 195 +++---- packages/server/src/db/schema/auth.ts | 4 +- packages/server/src/db/schema/certificate.ts | 21 +- packages/server/src/db/schema/destination.ts | 16 +- packages/server/src/db/schema/git-provider.ts | 20 +- packages/server/src/db/schema/notification.ts | 20 +- packages/server/src/db/schema/project.ts | 16 +- packages/server/src/db/schema/registry.ts | 16 +- packages/server/src/db/schema/server.ts | 21 +- packages/server/src/db/schema/session.ts | 20 +- packages/server/src/db/schema/ssh-key.ts | 19 +- packages/server/src/db/schema/user.ts | 74 ++- 20 files changed, 978 insertions(+), 443 deletions(-) create mode 100644 apps/dokploy/drizzle/0066_rapid_morbius.sql delete mode 100644 apps/dokploy/drizzle/0066_soft_kronos.sql create mode 100644 apps/dokploy/migrate.ts diff --git a/apps/dokploy/drizzle/0066_rapid_morbius.sql b/apps/dokploy/drizzle/0066_rapid_morbius.sql new file mode 100644 index 000000000..9deea8818 --- /dev/null +++ b/apps/dokploy/drizzle/0066_rapid_morbius.sql @@ -0,0 +1,153 @@ +CREATE TABLE "user_temp" ( + "id" text PRIMARY KEY NOT NULL, + "name" text DEFAULT '' NOT NULL, + "token" text NOT NULL, + "isRegistered" boolean DEFAULT false NOT NULL, + "expirationDate" text NOT NULL, + "createdAt" text NOT NULL, + "canCreateProjects" boolean DEFAULT false NOT NULL, + "canAccessToSSHKeys" boolean DEFAULT false NOT NULL, + "canCreateServices" boolean DEFAULT false NOT NULL, + "canDeleteProjects" boolean DEFAULT false NOT NULL, + "canDeleteServices" boolean DEFAULT false NOT NULL, + "canAccessToDocker" boolean DEFAULT false NOT NULL, + "canAccessToAPI" boolean DEFAULT false NOT NULL, + "canAccessToGitProviders" boolean DEFAULT false NOT NULL, + "canAccessToTraefikFiles" boolean DEFAULT false NOT NULL, + "accesedProjects" text[] DEFAULT ARRAY[]::text[] NOT NULL, + "accesedServices" text[] DEFAULT ARRAY[]::text[] NOT NULL, + "email" text NOT NULL, + "email_verified" boolean NOT NULL, + "image" text, + "role" text, + "banned" boolean, + "ban_reason" text, + "ban_expires" timestamp, + "updated_at" timestamp NOT NULL, + "serverIp" text, + "certificateType" "certificateType" DEFAULT 'none' NOT NULL, + "host" text, + "letsEncryptEmail" text, + "sshPrivateKey" text, + "enableDockerCleanup" boolean DEFAULT false NOT NULL, + "enableLogRotation" boolean DEFAULT false NOT NULL, + "enablePaidFeatures" boolean DEFAULT false NOT NULL, + "metricsConfig" jsonb 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 NOT NULL, + "cleanupCacheApplications" boolean DEFAULT false NOT NULL, + "cleanupCacheOnPreviews" boolean DEFAULT false NOT NULL, + "cleanupCacheOnCompose" boolean DEFAULT false NOT NULL, + "stripeCustomerId" text, + "stripeSubscriptionId" text, + "serversQuantity" integer DEFAULT 0 NOT NULL, + CONSTRAINT "user_temp_email_unique" UNIQUE("email") +); +--> statement-breakpoint +CREATE TABLE "session_temp" ( + "id" text PRIMARY KEY NOT NULL, + "expires_at" timestamp NOT NULL, + "token" text NOT NULL, + "created_at" timestamp NOT NULL, + "updated_at" timestamp NOT NULL, + "ip_address" text, + "user_agent" text, + "user_id" text NOT NULL, + "impersonated_by" text, + "active_organization_id" text, + CONSTRAINT "session_temp_token_unique" UNIQUE("token") +); +--> statement-breakpoint +CREATE TABLE "account" ( + "id" text PRIMARY KEY NOT NULL, + "account_id" text NOT NULL, + "provider_id" text NOT NULL, + "user_id" text NOT NULL, + "access_token" text, + "refresh_token" text, + "id_token" text, + "access_token_expires_at" timestamp, + "refresh_token_expires_at" timestamp, + "scope" text, + "password" text, + "is2FAEnabled" boolean DEFAULT false NOT NULL, + "created_at" timestamp NOT NULL, + "updated_at" timestamp NOT NULL, + "resetPasswordToken" text, + "resetPasswordExpiresAt" text, + "confirmationToken" text, + "confirmationExpiresAt" text +); +--> statement-breakpoint +CREATE TABLE "invitation" ( + "id" text PRIMARY KEY NOT NULL, + "organization_id" text NOT NULL, + "email" text NOT NULL, + "role" text, + "status" text NOT NULL, + "expires_at" timestamp NOT NULL, + "inviter_id" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE "member" ( + "id" text PRIMARY KEY NOT NULL, + "organization_id" text NOT NULL, + "user_id" text NOT NULL, + "role" text NOT NULL, + "created_at" timestamp NOT NULL +); +--> statement-breakpoint +CREATE TABLE "organization" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "slug" text, + "logo" text, + "created_at" timestamp NOT NULL, + "metadata" text, + "owner_id" text NOT NULL, + CONSTRAINT "organization_slug_unique" UNIQUE("slug") +); +--> statement-breakpoint +CREATE TABLE "verification" ( + "id" text PRIMARY KEY NOT NULL, + "identifier" text NOT NULL, + "value" text NOT NULL, + "expires_at" timestamp NOT NULL, + "created_at" timestamp, + "updated_at" timestamp +); +--> statement-breakpoint +ALTER TABLE "project" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "destination" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "certificate" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "registry" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "notification" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "git_provider" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "server" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "project" DROP CONSTRAINT "project_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "destination" DROP CONSTRAINT "destination_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "certificate" DROP CONSTRAINT "certificate_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "registry" DROP CONSTRAINT "registry_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "notification" DROP CONSTRAINT "notification_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "git_provider" DROP CONSTRAINT "git_provider_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "server" DROP CONSTRAINT "server_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "ssh-key" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "session_temp" ADD CONSTRAINT "session_temp_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "invitation" ADD CONSTRAINT "invitation_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "invitation" ADD CONSTRAINT "invitation_inviter_id_user_temp_id_fk" FOREIGN KEY ("inviter_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_temp_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "project" ADD CONSTRAINT "project_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "destination" ADD CONSTRAINT "destination_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "certificate" ADD CONSTRAINT "certificate_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "registry" ADD CONSTRAINT "registry_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "notification" ADD CONSTRAINT "notification_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "git_provider" ADD CONSTRAINT "git_provider_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "server" ADD CONSTRAINT "server_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/apps/dokploy/drizzle/0066_soft_kronos.sql b/apps/dokploy/drizzle/0066_soft_kronos.sql deleted file mode 100644 index cc627fa8e..000000000 --- a/apps/dokploy/drizzle/0066_soft_kronos.sql +++ /dev/null @@ -1,187 +0,0 @@ --- Create new tables -CREATE TABLE IF NOT EXISTS "account" ( - "id" text PRIMARY KEY NOT NULL, - "accountId" text NOT NULL, - "providerId" text NOT NULL, - "userId" text NOT NULL REFERENCES "user"("userId"), - "accessToken" text, - "refreshToken" text, - "idToken" text, - "accessTokenExpiresAt" timestamp, - "refreshTokenExpiresAt" timestamp, - "scope" text, - "password" text, - "is2FAEnabled" boolean DEFAULT false NOT NULL, - "createdAt" timestamp NOT NULL, - "updatedAt" timestamp NOT NULL, - "resetPasswordToken" text, - "resetPasswordExpiresAt" text, - "confirmationToken" text, - "confirmationExpiresAt" text -); - -CREATE TABLE IF NOT EXISTS "organization" ( - "id" text PRIMARY KEY NOT NULL,mn cj. - "name" text NOT NULL, - "slug" text, - "logo" text, - "createdAt" timestamp NOT NULL, - "metadata" text, - "ownerId" text NOT NULL REFERENCES "user"("userId"), - CONSTRAINT "organization_slug_unique" UNIQUE("slug") -); - -CREATE TABLE IF NOT EXISTS "member" ( - "id" text PRIMARY KEY NOT NULL, - "organizationId" text NOT NULL REFERENCES "organization"("id"), - "userId" text NOT NULL REFERENCES "user"("userId"), - "role" text NOT NULL, - "createdAt" timestamp NOT NULL -); - -CREATE TABLE IF NOT EXISTS "invitation" ( - "id" text PRIMARY KEY NOT NULL, - "organizationId" text NOT NULL, - "email" text NOT NULL, - "role" text, - "status" text NOT NULL, - "expiresAt" timestamp NOT NULL, - "inviterId" text NOT NULL -); - -CREATE TABLE IF NOT EXISTS "verification" ( - "id" text PRIMARY KEY NOT NULL, - "identifier" text NOT NULL, - "value" text NOT NULL, - "expiresAt" timestamp NOT NULL, - "createdAt" timestamp, - "updatedAt" timestamp -); - --- Alter existing user table to add new columns -ALTER TABLE "user" -ADD COLUMN IF NOT EXISTS "email" text, -ADD COLUMN IF NOT EXISTS "emailVerified" boolean DEFAULT false, -ADD COLUMN IF NOT EXISTS "role" text, -ADD COLUMN IF NOT EXISTS "certificateType" text DEFAULT 'none', -ADD COLUMN IF NOT EXISTS "serverIp" text, -ADD COLUMN IF NOT EXISTS "host" text, -ADD COLUMN IF NOT EXISTS "letsEncryptEmail" text, -ADD COLUMN IF NOT EXISTS "sshPrivateKey" text, -ADD COLUMN IF NOT EXISTS "enableDockerCleanup" boolean DEFAULT false, -ADD COLUMN IF NOT EXISTS "enableLogRotation" boolean DEFAULT false, -ADD COLUMN IF NOT EXISTS "enablePaidFeatures" boolean DEFAULT false, -ADD COLUMN IF NOT EXISTS "metricsConfig" jsonb DEFAULT '{}', -ADD COLUMN IF NOT EXISTS "cleanupCacheApplications" boolean DEFAULT false, -ADD COLUMN IF NOT EXISTS "cleanupCacheOnPreviews" boolean DEFAULT false, -ADD COLUMN IF NOT EXISTS "cleanupCacheOnCompose" boolean DEFAULT false, -ADD COLUMN IF NOT EXISTS "stripeCustomerId" text, -ADD COLUMN IF NOT EXISTS "stripeSubscriptionId" text, -ADD COLUMN IF NOT EXISTS "serversQuantity" integer DEFAULT 0; - --- Migrate email from auth table to user table -UPDATE "user" u -SET "email" = a."email" -FROM "auth" a -WHERE a."id" = u."userId"; - --- Migrate admin users -WITH admin_users AS ( - UPDATE "user" u - SET - "emailVerified" = true, - "role" = 'admin', - "token" = a."token", - "certificateType" = adm."certificateType", - "serverIp" = adm."serverIp", - "host" = adm."host", - "letsEncryptEmail" = adm."letsEncryptEmail", - "sshPrivateKey" = adm."sshPrivateKey", - "enableDockerCleanup" = adm."enableDockerCleanup", - "enableLogRotation" = adm."enableLogRotation", - "enablePaidFeatures" = adm."enablePaidFeatures", - "metricsConfig" = adm."metricsConfig", - "cleanupCacheApplications" = adm."cleanupCacheApplications", - "cleanupCacheOnPreviews" = adm."cleanupCacheOnPreviews", - "cleanupCacheOnCompose" = adm."cleanupCacheOnCompose", - "stripeCustomerId" = adm."stripeCustomerId", - "stripeSubscriptionId" = adm."stripeSubscriptionId", - "serversQuantity" = adm."serversQuantity" - FROM "auth" a - INNER JOIN "admin" adm ON a."id" = adm."adminId" - WHERE a."id" = u."userId" - RETURNING u."userId", u."email" -) -INSERT INTO "account" ("id", "accountId", "providerId", "password", "userId", "createdAt", "updatedAt") -SELECT - gen_random_uuid(), - a."id", - 'credentials', - a."password", - au."userId", - NOW(), - NOW() -FROM "auth" a -INNER JOIN admin_users au ON a."email" = au."email"; - --- Create organizations for admin users -WITH admin_orgs AS ( - INSERT INTO "organization" ("id", "name", "slug", "createdAt", "ownerId") - SELECT - gen_random_uuid(), - 'My Organization', - concat('org/', u."userId"), - NOW(), - u."userId" - FROM "user" u - WHERE u."role" = 'admin' - RETURNING * -) --- Migrate regular users -UPDATE "user" u -SET - "emailVerified" = true, - "role" = 'user', - "token" = a."token", - "canCreateProjects" = usr."canCreateProjects", - "canAccessToSSHKeys" = usr."canAccessToSSHKeys" -FROM "auth" a -INNER JOIN "user" usr ON a."id" = usr."userId" -WHERE a."id" = u."userId" -AND NOT EXISTS ( - SELECT 1 FROM "admin" adm WHERE a."id" = adm."adminId" -); - --- Create accounts for regular users -INSERT INTO "account" ("id", "accountId", "providerId", "password", "userId", "createdAt", "updatedAt") -SELECT - gen_random_uuid(), - a."id", - 'credentials', - a."password", - u."userId", - NOW(), - NOW() -FROM "auth" a -INNER JOIN "user" u ON a."email" = u."email" -WHERE u."role" = 'user'; - --- Create member relationships -INSERT INTO "member" ("id", "organizationId", "role", "userId", "createdAt") -SELECT - gen_random_uuid(), - o."id", - 'user', - u."userId", - NOW() -FROM "user" usr -INNER JOIN "user" u ON usr."userId" = u."userId" -INNER JOIN "admin" adm ON usr."adminId" = adm."adminId" -INNER JOIN "user" admin_u ON adm."adminId" = admin_u."userId" -INNER JOIN "organization" o ON o."ownerId" = admin_u."userId" -WHERE u."role" = 'user'; - --- Drop old tables (after all data is migrated) -DROP TABLE IF EXISTS "sessionTable" CASCADE; -DROP TABLE IF EXISTS "admin" CASCADE; -DROP TABLE IF EXISTS "auth" CASCADE; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0066_snapshot.json b/apps/dokploy/drizzle/meta/0066_snapshot.json index 3ffb0dbf0..1bf9811a3 100644 --- a/apps/dokploy/drizzle/meta/0066_snapshot.json +++ b/apps/dokploy/drizzle/meta/0066_snapshot.json @@ -1,5 +1,5 @@ { - "id": "d76ab830-b647-4e53-b6cc-0cf515968758", + "id": "de382c48-6f10-4578-a307-884fecb4baa3", "prevId": "1240ec96-1751-4de3-b64f-cef9cb716786", "version": "7", "dialect": "postgresql", @@ -741,6 +741,166 @@ "primaryKey": true, "notNull": true }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_adminId_admin_adminId_fk": { + "name": "user_adminId_admin_adminId_fk", + "tableFrom": "user", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_authId_auth_id_fk": { + "name": "user_authId_auth_id_fk", + "tableFrom": "user", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_temp": { + "name": "user_temp", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, "name": { "name": "name", "type": "text", @@ -1003,8 +1163,8 @@ "foreignKeys": {}, "compositePrimaryKeys": {}, "uniqueConstraints": { - "user_email_unique": { - "name": "user_email_unique", + "user_temp_email_unique": { + "name": "user_temp_email_unique", "nullsNotDistinct": false, "columns": [ "email" @@ -1018,9 +1178,142 @@ "public.admin": { "name": "admin", "schema": "", - "columns": {}, + "columns": { + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripeCustomerId": { + "name": "stripeCustomerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripeSubscriptionId": { + "name": "stripeSubscriptionId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serversQuantity": { + "name": "serversQuantity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, "indexes": {}, - "foreignKeys": {}, + "foreignKeys": { + "admin_authId_auth_id_fk": { + "name": "admin_authId_auth_id_fk", + "tableFrom": "admin", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, "compositePrimaryKeys": {}, "uniqueConstraints": {}, "policies": {}, @@ -1172,15 +1465,15 @@ }, "indexes": {}, "foreignKeys": { - "project_userId_user_userId_fk": { - "name": "project_userId_user_userId_fk", + "project_userId_user_temp_id_fk": { + "name": "project_userId_user_temp_id_fk", "tableFrom": "project", - "tableTo": "user", + "tableTo": "user_temp", "columnsFrom": [ "userId" ], "columnsTo": [ - "userId" + "id" ], "onDelete": "cascade", "onUpdate": "no action" @@ -2042,15 +2335,15 @@ }, "indexes": {}, "foreignKeys": { - "destination_userId_user_userId_fk": { - "name": "destination_userId_user_userId_fk", + "destination_userId_user_temp_id_fk": { + "name": "destination_userId_user_temp_id_fk", "tableFrom": "destination", - "tableTo": "user", + "tableTo": "user_temp", "columnsFrom": [ "userId" ], "columnsTo": [ - "userId" + "id" ], "onDelete": "cascade", "onUpdate": "no action" @@ -2445,7 +2738,7 @@ "name": "userId", "type": "text", "primaryKey": false, - "notNull": false + "notNull": true }, "serverId": { "name": "serverId", @@ -2456,15 +2749,15 @@ }, "indexes": {}, "foreignKeys": { - "certificate_userId_user_userId_fk": { - "name": "certificate_userId_user_userId_fk", + "certificate_userId_user_temp_id_fk": { + "name": "certificate_userId_user_temp_id_fk", "tableFrom": "certificate", - "tableTo": "user", + "tableTo": "user_temp", "columnsFrom": [ "userId" ], "columnsTo": [ - "userId" + "id" ], "onDelete": "cascade", "onUpdate": "no action" @@ -2497,8 +2790,8 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "public.session": { - "name": "session", + "public.session_temp": { + "name": "session_temp", "schema": "", "columns": { "id": { @@ -2513,6 +2806,12 @@ "primaryKey": false, "notNull": true }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, "created_at": { "name": "created_at", "type": "timestamp", @@ -2558,21 +2857,74 @@ }, "indexes": {}, "foreignKeys": { - "session_user_id_user_userId_fk": { - "name": "session_user_id_user_userId_fk", - "tableFrom": "session", - "tableTo": "user", + "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": [ - "userId" + "id" ], "onDelete": "no action", "onUpdate": "no action" } }, "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_temp_token_unique": { + "name": "session_temp_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_auth_id_fk": { + "name": "session_user_id_auth_id_fk", + "tableFrom": "session", + "tableTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, "uniqueConstraints": {}, "policies": {}, "checkConstraints": {}, @@ -3308,15 +3660,15 @@ }, "indexes": {}, "foreignKeys": { - "registry_userId_user_userId_fk": { - "name": "registry_userId_user_userId_fk", + "registry_userId_user_temp_id_fk": { + "name": "registry_userId_user_temp_id_fk", "tableFrom": "registry", - "tableTo": "user", + "tableTo": "user_temp", "columnsFrom": [ "userId" ], "columnsTo": [ - "userId" + "id" ], "onDelete": "cascade", "onUpdate": "no action" @@ -3563,7 +3915,7 @@ "name": "userId", "type": "text", "primaryKey": false, - "notNull": false + "notNull": true } }, "indexes": {}, @@ -3633,15 +3985,15 @@ "onDelete": "cascade", "onUpdate": "no action" }, - "notification_userId_user_userId_fk": { - "name": "notification_userId_user_userId_fk", + "notification_userId_user_temp_id_fk": { + "name": "notification_userId_user_temp_id_fk", "tableFrom": "notification", - "tableTo": "user", + "tableTo": "user_temp", "columnsFrom": [ "userId" ], "columnsTo": [ - "userId" + "id" ], "onDelete": "cascade", "onUpdate": "no action" @@ -3762,24 +4114,24 @@ "primaryKey": false, "notNull": false }, - "userId": { - "name": "userId", + "adminId": { + "name": "adminId", "type": "text", "primaryKey": false, - "notNull": false + "notNull": true } }, "indexes": {}, "foreignKeys": { - "ssh-key_userId_user_userId_fk": { - "name": "ssh-key_userId_user_userId_fk", + "ssh-key_adminId_admin_adminId_fk": { + "name": "ssh-key_adminId_admin_adminId_fk", "tableFrom": "ssh-key", - "tableTo": "user", + "tableTo": "admin", "columnsFrom": [ - "userId" + "adminId" ], "columnsTo": [ - "userId" + "adminId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -3825,20 +4177,20 @@ "name": "userId", "type": "text", "primaryKey": false, - "notNull": false + "notNull": true } }, "indexes": {}, "foreignKeys": { - "git_provider_userId_user_userId_fk": { - "name": "git_provider_userId_user_userId_fk", + "git_provider_userId_user_temp_id_fk": { + "name": "git_provider_userId_user_temp_id_fk", "tableFrom": "git_provider", - "tableTo": "user", + "tableTo": "user_temp", "columnsFrom": [ "userId" ], "columnsTo": [ - "userId" + "id" ], "onDelete": "cascade", "onUpdate": "no action" @@ -4173,15 +4525,15 @@ }, "indexes": {}, "foreignKeys": { - "server_userId_user_userId_fk": { - "name": "server_userId_user_userId_fk", + "server_userId_user_temp_id_fk": { + "name": "server_userId_user_temp_id_fk", "tableFrom": "server", - "tableTo": "user", + "tableTo": "user_temp", "columnsFrom": [ "userId" ], "columnsTo": [ - "userId" + "id" ], "onDelete": "cascade", "onUpdate": "no action" @@ -4450,15 +4802,15 @@ }, "indexes": {}, "foreignKeys": { - "account_user_id_user_userId_fk": { - "name": "account_user_id_user_userId_fk", + "account_user_id_user_temp_id_fk": { + "name": "account_user_id_user_temp_id_fk", "tableFrom": "account", - "tableTo": "user", + "tableTo": "user_temp", "columnsFrom": [ "user_id" ], "columnsTo": [ - "userId" + "id" ], "onDelete": "no action", "onUpdate": "no action" @@ -4532,15 +4884,15 @@ "onDelete": "no action", "onUpdate": "no action" }, - "invitation_inviter_id_user_userId_fk": { - "name": "invitation_inviter_id_user_userId_fk", + "invitation_inviter_id_user_temp_id_fk": { + "name": "invitation_inviter_id_user_temp_id_fk", "tableFrom": "invitation", - "tableTo": "user", + "tableTo": "user_temp", "columnsFrom": [ "inviter_id" ], "columnsTo": [ - "userId" + "id" ], "onDelete": "no action", "onUpdate": "no action" @@ -4602,15 +4954,15 @@ "onDelete": "no action", "onUpdate": "no action" }, - "member_user_id_user_userId_fk": { - "name": "member_user_id_user_userId_fk", + "member_user_id_user_temp_id_fk": { + "name": "member_user_id_user_temp_id_fk", "tableFrom": "member", - "tableTo": "user", + "tableTo": "user_temp", "columnsFrom": [ "user_id" ], "columnsTo": [ - "userId" + "id" ], "onDelete": "no action", "onUpdate": "no action" @@ -4671,15 +5023,15 @@ }, "indexes": {}, "foreignKeys": { - "organization_owner_id_user_userId_fk": { - "name": "organization_owner_id_user_userId_fk", + "organization_owner_id_user_temp_id_fk": { + "name": "organization_owner_id_user_temp_id_fk", "tableFrom": "organization", - "tableTo": "user", + "tableTo": "user_temp", "columnsFrom": [ "owner_id" ], "columnsTo": [ - "userId" + "id" ], "onDelete": "no action", "onUpdate": "no action" diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index d3de75645..188a97009 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -467,8 +467,8 @@ { "idx": 66, "version": "7", - "when": 1739173929725, - "tag": "0066_soft_kronos", + "when": 1739425241338, + "tag": "0066_rapid_morbius", "breakpoints": true } ] diff --git a/apps/dokploy/migrate.ts b/apps/dokploy/migrate.ts new file mode 100644 index 000000000..72bbf2ab0 --- /dev/null +++ b/apps/dokploy/migrate.ts @@ -0,0 +1,117 @@ +import { drizzle } from "drizzle-orm/postgres-js"; +import { migrate } from "drizzle-orm/postgres-js/migrator"; +import postgres from "postgres"; +import * as schema from "./server/db/schema"; +import { nanoid } from "nanoid"; + +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: "credentials", + 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.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); + }); diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 9e531cf8c..f68978c36 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -16,6 +16,7 @@ "studio": "drizzle-kit studio --config ./server/db/drizzle.config.ts", "migration:generate": "drizzle-kit generate --config ./server/db/drizzle.config.ts", "migration:run": "tsx -r dotenv/config migration.ts", + "manual-migration:run": "tsx -r dotenv/config migrate.ts", "migration:up": "drizzle-kit up --config ./server/db/drizzle.config.ts", "migration:drop": "drizzle-kit drop --config ./server/db/drizzle.config.ts", "db:push": "drizzle-kit push --config ./server/db/drizzle.config.ts", diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index 3e19bebe0..bfb03d2e4 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -26,7 +26,7 @@ export const session = pgTable("session", { userAgent: text("user_agent"), userId: text("user_id") .notNull() - .references(() => user.userId), + .references(() => user.id), activeOrganizationId: text("active_organization_id"), }); @@ -36,7 +36,7 @@ export const account = pgTable("account", { providerId: text("provider_id").notNull(), userId: text("user_id") .notNull() - .references(() => user.userId), + .references(() => user.id), accessToken: text("access_token"), refreshToken: text("refresh_token"), idToken: text("id_token"), diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 24350c55c..349428fd8 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -1,13 +1,18 @@ import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; -import { user } from "./user"; +import { users_temp } from "./user"; +import { nanoid } from "nanoid"; export const account = pgTable("account", { - id: text("id").primaryKey(), - accountId: text("account_id").notNull(), + id: text("id") + .primaryKey() + .$defaultFn(() => nanoid()), + accountId: text("account_id") + .notNull() + .$defaultFn(() => nanoid()), providerId: text("provider_id").notNull(), userId: text("user_id") .notNull() - .references(() => user.userId), + .references(() => users_temp.id), accessToken: text("access_token"), refreshToken: text("refresh_token"), idToken: text("id_token"), @@ -34,7 +39,9 @@ export const verification = pgTable("verification", { }); export const organization = pgTable("organization", { - id: text("id").primaryKey(), + id: text("id") + .primaryKey() + .$defaultFn(() => nanoid()), name: text("name").notNull(), slug: text("slug").unique(), logo: text("logo"), @@ -42,17 +49,19 @@ export const organization = pgTable("organization", { metadata: text("metadata"), ownerId: text("owner_id") .notNull() - .references(() => user.userId), + .references(() => users_temp.id), }); export const member = pgTable("member", { - id: text("id").primaryKey(), + id: text("id") + .primaryKey() + .$defaultFn(() => nanoid()), organizationId: text("organization_id") .notNull() .references(() => organization.id), userId: text("user_id") .notNull() - .references(() => user.userId), + .references(() => users_temp.id), role: text("role").notNull(), createdAt: timestamp("created_at").notNull(), }); @@ -68,5 +77,5 @@ export const invitation = pgTable("invitation", { expiresAt: timestamp("expires_at").notNull(), inviterId: text("inviter_id") .notNull() - .references(() => user.userId), + .references(() => users_temp.id), }); diff --git a/packages/server/src/db/schema/admin.ts b/packages/server/src/db/schema/admin.ts index c842bd7a3..983f99fd6 100644 --- a/packages/server/src/db/schema/admin.ts +++ b/packages/server/src/db/schema/admin.ts @@ -18,127 +18,128 @@ import { sshKeys } from "./ssh-key"; import { users } from "./user"; export const admins = pgTable("admin", { - // adminId: text("adminId") - // .notNull() - // .primaryKey() - // .$defaultFn(() => nanoid()), - // serverIp: text("serverIp"), - // certificateType: certificateType("certificateType").notNull().default("none"), - // host: text("host"), - // letsEncryptEmail: text("letsEncryptEmail"), - // sshPrivateKey: text("sshPrivateKey"), - // enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false), - // enableLogRotation: boolean("enableLogRotation").notNull().default(false), - // authId: text("authId") - // .notNull() - // .references(() => auth.id, { onDelete: "cascade" }), - // createdAt: text("createdAt") - // .notNull() - // .$defaultFn(() => new Date().toISOString()), - // stripeCustomerId: text("stripeCustomerId"), - // stripeSubscriptionId: text("stripeSubscriptionId"), - // serversQuantity: integer("serversQuantity").notNull().default(0), - // // Metrics - // enablePaidFeatures: boolean("enablePaidFeatures").notNull().default(false), - // metricsConfig: jsonb("metricsConfig") - // .$type<{ - // server: { - // type: "Dokploy" | "Remote"; - // refreshRate: number; - // port: number; - // token: string; - // urlCallback: string; - // retentionDays: number; - // cronJob: string; - // thresholds: { - // cpu: number; - // memory: number; - // }; - // }; - // containers: { - // refreshRate: number; - // services: { - // include: string[]; - // exclude: string[]; - // }; - // }; - // }>() - // .notNull() - // .default({ - // server: { - // type: "Dokploy", - // refreshRate: 60, - // port: 4500, - // token: "", - // retentionDays: 2, - // cronJob: "", - // urlCallback: "", - // thresholds: { - // cpu: 0, - // memory: 0, - // }, - // }, - // containers: { - // refreshRate: 60, - // services: { - // include: [], - // exclude: [], - // }, - // }, - // }), - // cleanupCacheApplications: boolean("cleanupCacheApplications") - // .notNull() - // .default(false), - // cleanupCacheOnPreviews: boolean("cleanupCacheOnPreviews") - // .notNull() - // .default(false), - // cleanupCacheOnCompose: boolean("cleanupCacheOnCompose") - // .notNull() - // .default(false), + adminId: text("adminId") + .notNull() + .primaryKey() + .$defaultFn(() => nanoid()), + serverIp: text("serverIp"), + certificateType: certificateType("certificateType").notNull().default("none"), + host: text("host"), + letsEncryptEmail: text("letsEncryptEmail"), + sshPrivateKey: text("sshPrivateKey"), + enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false), + enableLogRotation: boolean("enableLogRotation").notNull().default(false), + authId: text("authId") + .notNull() + .references(() => auth.id, { onDelete: "cascade" }), + createdAt: text("createdAt") + .notNull() + .$defaultFn(() => new Date().toISOString()), + stripeCustomerId: text("stripeCustomerId"), + stripeSubscriptionId: text("stripeSubscriptionId"), + serversQuantity: integer("serversQuantity").notNull().default(0), + + // Metrics + enablePaidFeatures: boolean("enablePaidFeatures").notNull().default(false), + metricsConfig: jsonb("metricsConfig") + .$type<{ + server: { + type: "Dokploy" | "Remote"; + refreshRate: number; + port: number; + token: string; + urlCallback: string; + retentionDays: number; + cronJob: string; + thresholds: { + cpu: number; + memory: number; + }; + }; + containers: { + refreshRate: number; + services: { + include: string[]; + exclude: string[]; + }; + }; + }>() + .notNull() + .default({ + server: { + type: "Dokploy", + refreshRate: 60, + port: 4500, + token: "", + retentionDays: 2, + cronJob: "", + urlCallback: "", + thresholds: { + cpu: 0, + memory: 0, + }, + }, + containers: { + refreshRate: 60, + services: { + include: [], + exclude: [], + }, + }, + }), + cleanupCacheApplications: boolean("cleanupCacheApplications") + .notNull() + .default(false), + cleanupCacheOnPreviews: boolean("cleanupCacheOnPreviews") + .notNull() + .default(false), + cleanupCacheOnCompose: boolean("cleanupCacheOnCompose") + .notNull() + .default(false), }); export const adminsRelations = relations(admins, ({ one, many }) => ({ - // auth: one(auth, { - // fields: [admins.authId], - // references: [auth.id], - // }), - // users: many(users), - // registry: many(registry), - // sshKeys: many(sshKeys), - // certificates: many(certificates), + auth: one(auth, { + fields: [admins.authId], + references: [auth.id], + }), + users: many(users), + registry: many(registry), + sshKeys: many(sshKeys), + certificates: many(certificates), })); const createSchema = createInsertSchema(admins, { - // adminId: z.string(), - // enableDockerCleanup: z.boolean().optional(), - // sshPrivateKey: z.string().optional(), - // certificateType: z.enum(["letsencrypt", "none"]).default("none"), - // serverIp: z.string().optional(), - // letsEncryptEmail: z.string().optional(), + adminId: z.string(), + enableDockerCleanup: z.boolean().optional(), + sshPrivateKey: z.string().optional(), + certificateType: z.enum(["letsencrypt", "none"]).default("none"), + serverIp: z.string().optional(), + letsEncryptEmail: z.string().optional(), }); export const apiUpdateAdmin = createSchema.partial(); export const apiSaveSSHKey = createSchema .pick({ - // sshPrivateKey: true, + sshPrivateKey: true, }) .required(); export const apiAssignDomain = createSchema .pick({ - // host: true, - // certificateType: true, - // letsEncryptEmail: true, + host: true, + certificateType: true, + letsEncryptEmail: true, }) .required() .partial({ - // letsEncryptEmail: true, + letsEncryptEmail: true, }); export const apiUpdateDockerCleanup = createSchema .pick({ - // enableDockerCleanup: true, + enableDockerCleanup: true, }) .required() .extend({ diff --git a/packages/server/src/db/schema/auth.ts b/packages/server/src/db/schema/auth.ts index 35f4dc853..7093a40c3 100644 --- a/packages/server/src/db/schema/auth.ts +++ b/packages/server/src/db/schema/auth.ts @@ -5,7 +5,7 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; // import { admins } from "./admin"; -import { user } from "./user"; +import { users } from "./user"; const randomImages = [ "/avatars/avatar-1.png", @@ -56,7 +56,7 @@ export const auth = pgTable("auth", { export const authRelations = relations(auth, ({ many }) => ({ // admins: many(admins), - users: many(user), + users: many(users), })); const createSchema = createInsertSchema(auth, { email: z.string().email(), diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts index c1a57a5ac..c72d189c2 100644 --- a/packages/server/src/db/schema/certificate.ts +++ b/packages/server/src/db/schema/certificate.ts @@ -4,8 +4,10 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { server } from "./server"; -import { user } from "./user"; +// import { user } from "./user"; import { generateAppName } from "./utils"; +import { admins } from "./admin"; +import { users_temp } from "./user"; export const certificates = pgTable("certificate", { certificateId: text("certificateId") @@ -20,9 +22,12 @@ export const certificates = pgTable("certificate", { .$defaultFn(() => generateAppName("certificate")) .unique(), autoRenew: boolean("autoRenew"), - userId: text("userId").references(() => user.userId, { - onDelete: "cascade", - }), + // userId: text("userId").references(() => user.userId, { + // onDelete: "cascade", + // }), + userId: text("userId") + .notNull() + .references(() => users_temp.id, { onDelete: "cascade" }), serverId: text("serverId").references(() => server.serverId, { onDelete: "cascade", }), @@ -35,10 +40,10 @@ export const certificatesRelations = relations( fields: [certificates.serverId], references: [server.serverId], }), - user: one(user, { - fields: [certificates.userId], - references: [user.id], - }), + // user: one(user, { + // fields: [certificates.userId], + // references: [user.id], + // }), }), ); diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts index 1fe48a346..6b9ea5d93 100644 --- a/packages/server/src/db/schema/destination.ts +++ b/packages/server/src/db/schema/destination.ts @@ -5,7 +5,8 @@ import { nanoid } from "nanoid"; import { z } from "zod"; import { admins } from "./admin"; import { backups } from "./backups"; -import { user } from "./user"; +import { users_temp } from "./user"; +// import { user } from "./user"; export const destinations = pgTable("destination", { destinationId: text("destinationId") @@ -20,19 +21,22 @@ export const destinations = pgTable("destination", { region: text("region").notNull(), // maybe it can be null endpoint: text("endpoint").notNull(), + // userId: text("userId") + // .notNull() + // .references(() => user.userId, { onDelete: "cascade" }), userId: text("userId") .notNull() - .references(() => user.userId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), }); export const destinationsRelations = relations( destinations, ({ many, one }) => ({ backups: many(backups), - user: one(user, { - fields: [destinations.userId], - references: [user.id], - }), + // user: one(user, { + // fields: [destinations.userId], + // references: [user.id], + // }), }), ); diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index 3a3bade81..4d154ee33 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -7,7 +7,8 @@ import { admins } from "./admin"; import { bitbucket } from "./bitbucket"; import { github } from "./github"; import { gitlab } from "./gitlab"; -import { user } from "./user"; +import { users_temp } from "./user"; +// import { user } from "./user"; export const gitProviderType = pgEnum("gitProviderType", [ "github", @@ -25,9 +26,12 @@ export const gitProvider = pgTable("git_provider", { createdAt: text("createdAt") .notNull() .$defaultFn(() => new Date().toISOString()), - userId: text("userId").references(() => user.userId, { - onDelete: "cascade", - }), + // userId: text("userId").references(() => user.userId, { + // onDelete: "cascade", + // }), + userId: text("userId") + .notNull() + .references(() => users_temp.id, { onDelete: "cascade" }), }); export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ @@ -43,10 +47,10 @@ export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ fields: [gitProvider.gitProviderId], references: [bitbucket.gitProviderId], }), - user: one(user, { - fields: [gitProvider.userId], - references: [user.id], - }), + // user: one(user, { + // fields: [gitProvider.userId], + // references: [user.id], + // }), })); const createSchema = createInsertSchema(gitProvider); diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 1771a92af..3ab253396 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -4,7 +4,8 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { admins } from "./admin"; -import { user } from "./user"; +import { users_temp } from "./user"; +// import { user } from "./user"; export const notificationType = pgEnum("notificationType", [ "slack", @@ -45,9 +46,12 @@ export const notifications = pgTable("notification", { gotifyId: text("gotifyId").references(() => gotify.gotifyId, { onDelete: "cascade", }), - userId: text("userId").references(() => user.userId, { - onDelete: "cascade", - }), + // userId: text("userId").references(() => user.userId, { + // onDelete: "cascade", + // }), + userId: text("userId") + .notNull() + .references(() => users_temp.id, { onDelete: "cascade" }), }); export const slack = pgTable("slack", { @@ -122,10 +126,10 @@ export const notificationsRelations = relations(notifications, ({ one }) => ({ fields: [notifications.gotifyId], references: [gotify.gotifyId], }), - user: one(user, { - fields: [notifications.userId], - references: [user.id], - }), + // user: one(user, { + // fields: [notifications.userId], + // references: [user.id], + // }), })); export const notificationsSchema = createInsertSchema(notifications); diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index d83936a38..efde3c34b 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -12,7 +12,8 @@ import { mongo } from "./mongo"; import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; -import { user } from "./user"; +import { users, users_temp } from "./user"; +import { admins } from "./admin"; export const projects = pgTable("project", { projectId: text("projectId") @@ -24,9 +25,12 @@ export const projects = pgTable("project", { createdAt: text("createdAt") .notNull() .$defaultFn(() => new Date().toISOString()), + // userId: text("userId") + // .notNull() + // .references(() => user.userId, { onDelete: "cascade" }), userId: text("userId") .notNull() - .references(() => user.userId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), env: text("env").notNull().default(""), }); @@ -38,10 +42,10 @@ export const projectRelations = relations(projects, ({ many, one }) => ({ mongo: many(mongo), redis: many(redis), compose: many(compose), - user: one(user, { - fields: [projects.userId], - references: [user.id], - }), + // user: one(user, { + // fields: [projects.userId], + // references: [user.id], + // }), })); const createSchema = createInsertSchema(projects, { diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index 936f65fc8..62c2b2d7d 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -5,7 +5,8 @@ import { nanoid } from "nanoid"; import { z } from "zod"; import { admins } from "./admin"; import { applications } from "./application"; -import { user } from "./user"; +import { users_temp } from "./user"; +// import { user } from "./user"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * database instance for multiple projects. @@ -28,16 +29,19 @@ export const registry = pgTable("registry", { .notNull() .$defaultFn(() => new Date().toISOString()), registryType: registryType("selfHosted").notNull().default("cloud"), + // userId: text("userId") + // .notNull() + // .references(() => user.userId, { onDelete: "cascade" }), userId: text("userId") .notNull() - .references(() => user.userId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), }); export const registryRelations = relations(registry, ({ one, many }) => ({ - user: one(user, { - fields: [registry.userId], - references: [user.id], - }), + // user: one(user, { + // fields: [registry.userId], + // references: [user.id], + // }), applications: many(applications), })); diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index 4e238e23b..b6b77dbcd 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -22,8 +22,9 @@ import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; import { sshKeys } from "./ssh-key"; -import { user } from "./user"; +// import { user } from "./user"; import { generateAppName } from "./utils"; +import { users_temp } from "./user"; export const serverStatus = pgEnum("serverStatus", ["active", "inactive"]); @@ -41,12 +42,14 @@ export const server = pgTable("server", { .notNull() .$defaultFn(() => generateAppName("server")), enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false), - createdAt: text("createdAt") - .notNull() - .$defaultFn(() => new Date().toISOString()), + createdAt: text("createdAt").notNull(), + // .$defaultFn(() => new Date().toISOString()), + // userId: text("userId") + // .notNull() + // .references(() => user.userId, { onDelete: "cascade" }), userId: text("userId") .notNull() - .references(() => user.userId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), serverStatus: serverStatus("serverStatus").notNull().default("active"), command: text("command").notNull().default(""), sshKeyId: text("sshKeyId").references(() => sshKeys.sshKeyId, { @@ -101,10 +104,10 @@ export const server = pgTable("server", { }); export const serverRelations = relations(server, ({ one, many }) => ({ - user: one(user, { - fields: [server.userId], - references: [user.id], - }), + // user: one(user, { + // fields: [server.userId], + // references: [user.id], + // }), deployments: many(deployments), sshKey: one(sshKeys, { fields: [server.sshKeyId], diff --git a/packages/server/src/db/schema/session.ts b/packages/server/src/db/schema/session.ts index d5932764a..03a70c41a 100644 --- a/packages/server/src/db/schema/session.ts +++ b/packages/server/src/db/schema/session.ts @@ -1,19 +1,31 @@ import { sql } from "drizzle-orm"; import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; -import { user } from "./user"; +import { users_temp } from "./user"; +import { auth } from "./auth"; // OLD TABLE -export const session = pgTable("session", { +export const session = pgTable("session_temp", { id: text("id").primaryKey(), expiresAt: timestamp("expires_at").notNull(), - // token: text("token").notNull().unique().default(sql`gen_random_uuid()`), + token: text("token").notNull().unique(), createdAt: timestamp("created_at").notNull(), updatedAt: timestamp("updated_at").notNull(), ipAddress: text("ip_address"), userAgent: text("user_agent"), userId: text("user_id") .notNull() - .references(() => user.userId), + .references(() => users_temp.id), impersonatedBy: text("impersonated_by"), activeOrganizationId: text("active_organization_id"), }); + +export const sessionTable = pgTable("session", { + id: text("id").primaryKey(), + userId: text("user_id") + .notNull() + .references(() => auth.id, { onDelete: "cascade" }), + expiresAt: timestamp("expires_at", { + withTimezone: true, + mode: "date", + }).notNull(), +}); diff --git a/packages/server/src/db/schema/ssh-key.ts b/packages/server/src/db/schema/ssh-key.ts index 9bb69fee4..cca9259bc 100644 --- a/packages/server/src/db/schema/ssh-key.ts +++ b/packages/server/src/db/schema/ssh-key.ts @@ -7,7 +7,7 @@ import { admins } from "./admin"; import { applications } from "./application"; import { compose } from "./compose"; import { server } from "./server"; -import { user } from "./user"; +// import { user } from "./user"; export const sshKeys = pgTable("ssh-key", { sshKeyId: text("sshKeyId") @@ -22,19 +22,22 @@ export const sshKeys = pgTable("ssh-key", { .notNull() .$defaultFn(() => new Date().toISOString()), lastUsedAt: text("lastUsedAt"), - userId: text("userId").references(() => user.userId, { - onDelete: "cascade", - }), + // userId: text("userId").references(() => user.userId, { + // onDelete: "cascade", + // }), + adminId: text("adminId") + .notNull() + .references(() => admins.adminId, { onDelete: "cascade" }), }); export const sshKeysRelations = relations(sshKeys, ({ many, one }) => ({ applications: many(applications), compose: many(compose), servers: many(server), - user: one(user, { - fields: [sshKeys.userId], - references: [user.id], - }), + // user: one(user, { + // fields: [sshKeys.userId], + // references: [user.id], + // }), })); const createSchema = createInsertSchema( diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 00e16679b..5f2a14e91 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -21,11 +21,57 @@ import { certificateType } from "./shared"; */ // OLD TABLE -export const user = pgTable("user", { + +export const users = pgTable("user", { userId: text("userId") .notNull() .primaryKey() .$defaultFn(() => nanoid()), + + token: text("token").notNull(), + isRegistered: boolean("isRegistered").notNull().default(false), + expirationDate: timestamp("expirationDate", { + precision: 3, + mode: "string", + }).notNull(), + createdAt: text("createdAt") + .notNull() + .$defaultFn(() => new Date().toISOString()), + canCreateProjects: boolean("canCreateProjects").notNull().default(false), + canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false), + canCreateServices: boolean("canCreateServices").notNull().default(false), + canDeleteProjects: boolean("canDeleteProjects").notNull().default(false), + canDeleteServices: boolean("canDeleteServices").notNull().default(false), + canAccessToDocker: boolean("canAccessToDocker").notNull().default(false), + canAccessToAPI: boolean("canAccessToAPI").notNull().default(false), + canAccessToGitProviders: boolean("canAccessToGitProviders") + .notNull() + .default(false), + canAccessToTraefikFiles: boolean("canAccessToTraefikFiles") + .notNull() + .default(false), + accessedProjects: text("accesedProjects") + .array() + .notNull() + .default(sql`ARRAY[]::text[]`), + accessedServices: text("accesedServices") + .array() + .notNull() + .default(sql`ARRAY[]::text[]`), + adminId: text("adminId") + .notNull() + .references(() => admins.adminId, { onDelete: "cascade" }), + authId: text("authId") + .notNull() + .references(() => auth.id, { onDelete: "cascade" }), +}); + +// TEMP +export const users_temp = pgTable("user_temp", { + id: text("id") + .notNull() + .primaryKey() + .$defaultFn(() => nanoid()), name: text("name").notNull().default(""), token: text("token").notNull(), isRegistered: boolean("isRegistered").notNull().default(false), @@ -138,19 +184,19 @@ export const user = pgTable("user", { serversQuantity: integer("serversQuantity").notNull().default(0), }); -export const usersRelations = relations(user, ({ one }) => ({ - // auth: one(auth, { - // fields: [users.authId], - // references: [auth.id], - // }), - // admin: one(admins, { - // fields: [users.adminId], - // references: [admins.adminId], - // }), +export const usersRelations = relations(users, ({ one }) => ({ + auth: one(auth, { + fields: [users.authId], + references: [auth.id], + }), + admin: one(admins, { + fields: [users.adminId], + references: [admins.adminId], + }), })); -const createSchema = createInsertSchema(user, { - id: z.string().min(1), +const createSchema = createInsertSchema(users, { + userId: z.string().min(1), // authId: z.string().min(1), token: z.string().min(1), isRegistered: z.boolean().optional(), @@ -183,7 +229,7 @@ export const apiFindOneToken = createSchema export const apiAssignPermissions = createSchema .pick({ - id: true, + userId: true, canCreateProjects: true, canCreateServices: true, canDeleteProjects: true, @@ -200,7 +246,7 @@ export const apiAssignPermissions = createSchema export const apiFindOneUser = createSchema .pick({ - id: true, + userId: true, }) .required(); From 23f1ce17de1f18e65aa9bd8610822968b14c7c34 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 13 Feb 2025 00:38:22 -0600 Subject: [PATCH 09/89] refactor: add migration --- ...d_morbius.sql => 0066_smiling_warlock.sql} | 0 apps/dokploy/drizzle/0066_yielding_echo.sql | 128 + apps/dokploy/drizzle/0067_migrate-data.sql | 170 + apps/dokploy/drizzle/meta/0066_snapshot.json | 100 +- apps/dokploy/drizzle/meta/0067_snapshot.json | 5278 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 11 +- packages/server/src/db/schema/certificate.ts | 12 +- packages/server/src/db/schema/destination.ts | 4 +- packages/server/src/db/schema/git-provider.ts | 12 +- packages/server/src/db/schema/notification.ts | 12 +- packages/server/src/db/schema/project.ts | 4 +- packages/server/src/db/schema/registry.ts | 4 +- packages/server/src/db/schema/server.ts | 4 +- 13 files changed, 5661 insertions(+), 78 deletions(-) rename apps/dokploy/drizzle/{0066_rapid_morbius.sql => 0066_smiling_warlock.sql} (100%) create mode 100644 apps/dokploy/drizzle/0066_yielding_echo.sql create mode 100644 apps/dokploy/drizzle/0067_migrate-data.sql create mode 100644 apps/dokploy/drizzle/meta/0067_snapshot.json diff --git a/apps/dokploy/drizzle/0066_rapid_morbius.sql b/apps/dokploy/drizzle/0066_smiling_warlock.sql similarity index 100% rename from apps/dokploy/drizzle/0066_rapid_morbius.sql rename to apps/dokploy/drizzle/0066_smiling_warlock.sql diff --git a/apps/dokploy/drizzle/0066_yielding_echo.sql b/apps/dokploy/drizzle/0066_yielding_echo.sql new file mode 100644 index 000000000..20f9d07b9 --- /dev/null +++ b/apps/dokploy/drizzle/0066_yielding_echo.sql @@ -0,0 +1,128 @@ +CREATE TABLE "user_temp" ( + "id" text PRIMARY KEY NOT NULL, + "name" text DEFAULT '' NOT NULL, + "token" text NOT NULL, + "isRegistered" boolean DEFAULT false NOT NULL, + "expirationDate" text NOT NULL, + "createdAt" text NOT NULL, + "canCreateProjects" boolean DEFAULT false NOT NULL, + "canAccessToSSHKeys" boolean DEFAULT false NOT NULL, + "canCreateServices" boolean DEFAULT false NOT NULL, + "canDeleteProjects" boolean DEFAULT false NOT NULL, + "canDeleteServices" boolean DEFAULT false NOT NULL, + "canAccessToDocker" boolean DEFAULT false NOT NULL, + "canAccessToAPI" boolean DEFAULT false NOT NULL, + "canAccessToGitProviders" boolean DEFAULT false NOT NULL, + "canAccessToTraefikFiles" boolean DEFAULT false NOT NULL, + "accesedProjects" text[] DEFAULT ARRAY[]::text[] NOT NULL, + "accesedServices" text[] DEFAULT ARRAY[]::text[] NOT NULL, + "email" text NOT NULL, + "email_verified" boolean NOT NULL, + "image" text, + "role" text, + "banned" boolean, + "ban_reason" text, + "ban_expires" timestamp, + "updated_at" timestamp NOT NULL, + "serverIp" text, + "certificateType" "certificateType" DEFAULT 'none' NOT NULL, + "host" text, + "letsEncryptEmail" text, + "sshPrivateKey" text, + "enableDockerCleanup" boolean DEFAULT false NOT NULL, + "enableLogRotation" boolean DEFAULT false NOT NULL, + "enablePaidFeatures" boolean DEFAULT false NOT NULL, + "metricsConfig" jsonb 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 NOT NULL, + "cleanupCacheApplications" boolean DEFAULT false NOT NULL, + "cleanupCacheOnPreviews" boolean DEFAULT false NOT NULL, + "cleanupCacheOnCompose" boolean DEFAULT false NOT NULL, + "stripeCustomerId" text, + "stripeSubscriptionId" text, + "serversQuantity" integer DEFAULT 0 NOT NULL, + CONSTRAINT "user_temp_email_unique" UNIQUE("email") +); +--> statement-breakpoint +CREATE TABLE "session_temp" ( + "id" text PRIMARY KEY NOT NULL, + "expires_at" timestamp NOT NULL, + "token" text NOT NULL, + "created_at" timestamp NOT NULL, + "updated_at" timestamp NOT NULL, + "ip_address" text, + "user_agent" text, + "user_id" text NOT NULL, + "impersonated_by" text, + "active_organization_id" text, + CONSTRAINT "session_temp_token_unique" UNIQUE("token") +); +--> statement-breakpoint +CREATE TABLE "account" ( + "id" text PRIMARY KEY NOT NULL, + "account_id" text NOT NULL, + "provider_id" text NOT NULL, + "user_id" text NOT NULL, + "access_token" text, + "refresh_token" text, + "id_token" text, + "access_token_expires_at" timestamp, + "refresh_token_expires_at" timestamp, + "scope" text, + "password" text, + "is2FAEnabled" boolean DEFAULT false NOT NULL, + "created_at" timestamp NOT NULL, + "updated_at" timestamp NOT NULL, + "resetPasswordToken" text, + "resetPasswordExpiresAt" text, + "confirmationToken" text, + "confirmationExpiresAt" text +); +--> statement-breakpoint +CREATE TABLE "invitation" ( + "id" text PRIMARY KEY NOT NULL, + "organization_id" text NOT NULL, + "email" text NOT NULL, + "role" text, + "status" text NOT NULL, + "expires_at" timestamp NOT NULL, + "inviter_id" text NOT NULL +); +--> statement-breakpoint +CREATE TABLE "member" ( + "id" text PRIMARY KEY NOT NULL, + "organization_id" text NOT NULL, + "user_id" text NOT NULL, + "role" text NOT NULL, + "created_at" timestamp NOT NULL +); +--> statement-breakpoint +CREATE TABLE "organization" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "slug" text, + "logo" text, + "created_at" timestamp NOT NULL, + "metadata" text, + "owner_id" text NOT NULL, + CONSTRAINT "organization_slug_unique" UNIQUE("slug") +); +--> statement-breakpoint +CREATE TABLE "verification" ( + "id" text PRIMARY KEY NOT NULL, + "identifier" text NOT NULL, + "value" text NOT NULL, + "expires_at" timestamp NOT NULL, + "created_at" timestamp, + "updated_at" timestamp +); +--> statement-breakpoint +ALTER TABLE "certificate" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "notification" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "ssh-key" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "git_provider" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "session_temp" ADD CONSTRAINT "session_temp_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "invitation" ADD CONSTRAINT "invitation_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "invitation" ADD CONSTRAINT "invitation_inviter_id_user_temp_id_fk" FOREIGN KEY ("inviter_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_temp_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action; \ No newline at end of file diff --git a/apps/dokploy/drizzle/0067_migrate-data.sql b/apps/dokploy/drizzle/0067_migrate-data.sql new file mode 100644 index 000000000..62604d32c --- /dev/null +++ b/apps/dokploy/drizzle/0067_migrate-data.sql @@ -0,0 +1,170 @@ +-- Custom SQL migration file, put your code below! -- + +WITH inserted_users AS ( + -- Insertar usuarios desde admins + INSERT INTO user_temp ( + id, + email, + token, + "email_verified", + "updated_at", + role, + "serverIp", + image, + "certificateType", + host, + "letsEncryptEmail", + "sshPrivateKey", + "enableDockerCleanup", + "enableLogRotation", + "enablePaidFeatures", + "metricsConfig", + "cleanupCacheApplications", + "cleanupCacheOnPreviews", + "cleanupCacheOnCompose", + "stripeCustomerId", + "stripeSubscriptionId", + "serversQuantity", + "expirationDate", + "createdAt" + ) + SELECT + a."adminId", + auth.email, + COALESCE(auth.token, ''), + true, + CURRENT_TIMESTAMP, + 'admin', + a."serverIp", + auth.image, + a."certificateType", + a.host, + a."letsEncryptEmail", + a."sshPrivateKey", + a."enableDockerCleanup", + a."enableLogRotation", + a."enablePaidFeatures", + a."metricsConfig", + a."cleanupCacheApplications", + a."cleanupCacheOnPreviews", + a."cleanupCacheOnCompose", + a."stripeCustomerId", + a."stripeSubscriptionId", + a."serversQuantity", + NOW() + INTERVAL '1 year', + NOW() + FROM admin a + JOIN auth ON auth.id = a."authId" + RETURNING * +), +inserted_accounts AS ( + -- Insertar cuentas para los admins + INSERT INTO account ( + id, + "account_id", + "provider_id", + "user_id", + password, + "is2FAEnabled", + "created_at", + "updated_at" + ) + SELECT + gen_random_uuid(), + gen_random_uuid(), + 'credentials', + a."adminId", + auth.password, + COALESCE(auth."is2FAEnabled", false), + NOW(), + NOW() + FROM admin a + JOIN auth ON auth.id = a."authId" + RETURNING * +), +inserted_orgs AS ( + -- Crear organizaciones para cada admin + INSERT INTO organization ( + id, + name, + slug, + "owner_id", + "created_at" + ) + SELECT + gen_random_uuid(), + 'My Organization', + -- Generamos un slug único usando una función de hash + encode(sha256((a."adminId" || CURRENT_TIMESTAMP)::bytea), 'hex'), + a."adminId", + NOW() + FROM admin a + RETURNING * +), +inserted_members AS ( + -- Insertar usuarios miembros + INSERT INTO user_temp ( + id, + email, + token, + "email_verified", + "updated_at", + role, + image, + "createdAt", + "canAccessToAPI", + "canAccessToDocker", + "canAccessToGitProviders", + "canAccessToSSHKeys", + "canAccessToTraefikFiles", + "canCreateProjects", + "canCreateServices", + "canDeleteProjects", + "canDeleteServices", + "accesedProjects", + "accesedServices", + "expirationDate" + ) + SELECT + u."userId", + auth.email, + COALESCE(u.token, ''), + true, + CURRENT_TIMESTAMP, + 'user', + auth.image, + NOW(), + COALESCE(u."canAccessToAPI", false), + COALESCE(u."canAccessToDocker", false), + COALESCE(u."canAccessToGitProviders", false), + COALESCE(u."canAccessToSSHKeys", false), + COALESCE(u."canAccessToTraefikFiles", false), + COALESCE(u."canCreateProjects", false), + COALESCE(u."canCreateServices", false), + COALESCE(u."canDeleteProjects", false), + COALESCE(u."canDeleteServices", false), + COALESCE(u."accesedProjects", '{}'), + COALESCE(u."accesedServices", '{}'), + NOW() + INTERVAL '1 year' + FROM "user" u + JOIN admin a ON u."adminId" = a."adminId" + JOIN auth ON auth.id = u."authId" + RETURNING * +) +-- Insertar miembros en las organizaciones +INSERT INTO member ( + id, + "organization_id", + "user_id", + role, + "created_at" +) +SELECT + gen_random_uuid(), + o.id, + u."userId", + 'admin', + NOW() +FROM "user" u +JOIN admin a ON u."adminId" = a."adminId" +JOIN inserted_orgs o ON o."owner_id" = a."adminId"; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0066_snapshot.json b/apps/dokploy/drizzle/meta/0066_snapshot.json index 1bf9811a3..c51e03851 100644 --- a/apps/dokploy/drizzle/meta/0066_snapshot.json +++ b/apps/dokploy/drizzle/meta/0066_snapshot.json @@ -1,5 +1,5 @@ { - "id": "de382c48-6f10-4578-a307-884fecb4baa3", + "id": "67140673-fcd1-4c33-8dd1-bb7a34bdae23", "prevId": "1240ec96-1751-4de3-b64f-cef9cb716786", "version": "7", "dialect": "postgresql", @@ -1449,8 +1449,8 @@ "primaryKey": false, "notNull": true }, - "userId": { - "name": "userId", + "adminId": { + "name": "adminId", "type": "text", "primaryKey": false, "notNull": true @@ -1465,15 +1465,15 @@ }, "indexes": {}, "foreignKeys": { - "project_userId_user_temp_id_fk": { - "name": "project_userId_user_temp_id_fk", + "project_adminId_admin_adminId_fk": { + "name": "project_adminId_admin_adminId_fk", "tableFrom": "project", - "tableTo": "user_temp", + "tableTo": "admin", "columnsFrom": [ - "userId" + "adminId" ], "columnsTo": [ - "id" + "adminId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -2326,8 +2326,8 @@ "primaryKey": false, "notNull": true }, - "userId": { - "name": "userId", + "adminId": { + "name": "adminId", "type": "text", "primaryKey": false, "notNull": true @@ -2335,15 +2335,15 @@ }, "indexes": {}, "foreignKeys": { - "destination_userId_user_temp_id_fk": { - "name": "destination_userId_user_temp_id_fk", + "destination_adminId_admin_adminId_fk": { + "name": "destination_adminId_admin_adminId_fk", "tableFrom": "destination", - "tableTo": "user_temp", + "tableTo": "admin", "columnsFrom": [ - "userId" + "adminId" ], "columnsTo": [ - "id" + "adminId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -2734,8 +2734,8 @@ "primaryKey": false, "notNull": false }, - "userId": { - "name": "userId", + "adminId": { + "name": "adminId", "type": "text", "primaryKey": false, "notNull": true @@ -2749,15 +2749,15 @@ }, "indexes": {}, "foreignKeys": { - "certificate_userId_user_temp_id_fk": { - "name": "certificate_userId_user_temp_id_fk", + "certificate_adminId_admin_adminId_fk": { + "name": "certificate_adminId_admin_adminId_fk", "tableFrom": "certificate", - "tableTo": "user_temp", + "tableTo": "admin", "columnsFrom": [ - "userId" + "adminId" ], "columnsTo": [ - "id" + "adminId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -3651,8 +3651,8 @@ "notNull": true, "default": "'cloud'" }, - "userId": { - "name": "userId", + "adminId": { + "name": "adminId", "type": "text", "primaryKey": false, "notNull": true @@ -3660,15 +3660,15 @@ }, "indexes": {}, "foreignKeys": { - "registry_userId_user_temp_id_fk": { - "name": "registry_userId_user_temp_id_fk", + "registry_adminId_admin_adminId_fk": { + "name": "registry_adminId_admin_adminId_fk", "tableFrom": "registry", - "tableTo": "user_temp", + "tableTo": "admin", "columnsFrom": [ - "userId" + "adminId" ], "columnsTo": [ - "id" + "adminId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -3911,8 +3911,8 @@ "primaryKey": false, "notNull": false }, - "userId": { - "name": "userId", + "adminId": { + "name": "adminId", "type": "text", "primaryKey": false, "notNull": true @@ -3985,15 +3985,15 @@ "onDelete": "cascade", "onUpdate": "no action" }, - "notification_userId_user_temp_id_fk": { - "name": "notification_userId_user_temp_id_fk", + "notification_adminId_admin_adminId_fk": { + "name": "notification_adminId_admin_adminId_fk", "tableFrom": "notification", - "tableTo": "user_temp", + "tableTo": "admin", "columnsFrom": [ - "userId" + "adminId" ], "columnsTo": [ - "id" + "adminId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -4173,8 +4173,8 @@ "primaryKey": false, "notNull": true }, - "userId": { - "name": "userId", + "adminId": { + "name": "adminId", "type": "text", "primaryKey": false, "notNull": true @@ -4182,15 +4182,15 @@ }, "indexes": {}, "foreignKeys": { - "git_provider_userId_user_temp_id_fk": { - "name": "git_provider_userId_user_temp_id_fk", + "git_provider_adminId_admin_adminId_fk": { + "name": "git_provider_adminId_admin_adminId_fk", "tableFrom": "git_provider", - "tableTo": "user_temp", + "tableTo": "admin", "columnsFrom": [ - "userId" + "adminId" ], "columnsTo": [ - "id" + "adminId" ], "onDelete": "cascade", "onUpdate": "no action" @@ -4488,8 +4488,8 @@ "primaryKey": false, "notNull": true }, - "userId": { - "name": "userId", + "adminId": { + "name": "adminId", "type": "text", "primaryKey": false, "notNull": true @@ -4525,15 +4525,15 @@ }, "indexes": {}, "foreignKeys": { - "server_userId_user_temp_id_fk": { - "name": "server_userId_user_temp_id_fk", + "server_adminId_admin_adminId_fk": { + "name": "server_adminId_admin_adminId_fk", "tableFrom": "server", - "tableTo": "user_temp", + "tableTo": "admin", "columnsFrom": [ - "userId" + "adminId" ], "columnsTo": [ - "id" + "adminId" ], "onDelete": "cascade", "onUpdate": "no action" diff --git a/apps/dokploy/drizzle/meta/0067_snapshot.json b/apps/dokploy/drizzle/meta/0067_snapshot.json new file mode 100644 index 000000000..33fc48703 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0067_snapshot.json @@ -0,0 +1,5278 @@ +{ + "id": "54ba08a1-8861-438a-a89d-f01d09a690c2", + "prevId": "67140673-fcd1-4c33-8dd1-bb7a34bdae23", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "tableTo": "ssh-key", + "columnsTo": [ + "sshKeyId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "columnsFrom": [ + "registryId" + ], + "tableTo": "registry", + "columnsTo": [ + "registryId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "columnsFrom": [ + "githubId" + ], + "tableTo": "github", + "columnsTo": [ + "githubId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "columnsFrom": [ + "gitlabId" + ], + "tableTo": "gitlab", + "columnsTo": [ + "gitlabId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "columnsFrom": [ + "bitbucketId" + ], + "tableTo": "bitbucket", + "columnsTo": [ + "bitbucketId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "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", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_adminId_admin_adminId_fk": { + "name": "user_adminId_admin_adminId_fk", + "tableFrom": "user", + "columnsFrom": [ + "adminId" + ], + "tableTo": "admin", + "columnsTo": [ + "adminId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "user_authId_auth_id_fk": { + "name": "user_authId_auth_id_fk", + "tableFrom": "user", + "columnsFrom": [ + "authId" + ], + "tableTo": "auth", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "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": "''" + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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 + }, + "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[]" + }, + "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 + }, + "role": { + "name": "role", + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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", + "columns": [ + "email" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.admin": { + "name": "admin", + "schema": "", + "columns": { + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripeCustomerId": { + "name": "stripeCustomerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripeSubscriptionId": { + "name": "stripeSubscriptionId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serversQuantity": { + "name": "serversQuantity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "admin_authId_auth_id_fk": { + "name": "admin_authId_auth_id_fk", + "tableFrom": "admin", + "columnsFrom": [ + "authId" + ], + "tableTo": "auth", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resetPasswordToken": { + "name": "resetPasswordToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resetPasswordExpiresAt": { + "name": "resetPasswordExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationToken": { + "name": "confirmationToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationExpiresAt": { + "name": "confirmationExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "columns": [ + "email" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "project_adminId_admin_adminId_fk": { + "name": "project_adminId_admin_adminId_fk", + "tableFrom": "project", + "columnsFrom": [ + "adminId" + ], + "tableTo": "admin", + "columnsTo": [ + "adminId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.domain": { + "name": "domain", + "schema": "", + "columns": { + "domainId": { + "name": "domainId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "https": { + "name": "https", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domainType": { + "name": "domainType", + "type": "domainType", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'application'" + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "columnsFrom": [ + "composeId" + ], + "tableTo": "compose", + "columnsTo": [ + "composeId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "columnsFrom": [ + "previewDeploymentId" + ], + "tableTo": "preview_deployments", + "columnsTo": [ + "previewDeploymentId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "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", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "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", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "columnsFrom": [ + "destinationId" + ], + "tableTo": "destination", + "columnsTo": [ + "destinationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "columnsFrom": [ + "postgresId" + ], + "tableTo": "postgres", + "columnsTo": [ + "postgresId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "columnsFrom": [ + "mariadbId" + ], + "tableTo": "mariadb", + "columnsTo": [ + "mariadbId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "columnsFrom": [ + "mysqlId" + ], + "tableTo": "mysql", + "columnsTo": [ + "mysqlId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "columnsFrom": [ + "mongoId" + ], + "tableTo": "mongo", + "columnsTo": [ + "mongoId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "destination_adminId_admin_adminId_fk": { + "name": "destination_adminId_admin_adminId_fk", + "tableFrom": "destination", + "columnsFrom": [ + "adminId" + ], + "tableTo": "admin", + "columnsTo": [ + "adminId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment": { + "name": "deployment", + "schema": "", + "columns": { + "deploymentId": { + "name": "deploymentId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "deploymentStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'running'" + }, + "logPath": { + "name": "logPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "columnsFrom": [ + "composeId" + ], + "tableTo": "compose", + "columnsTo": [ + "composeId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "columnsFrom": [ + "previewDeploymentId" + ], + "tableTo": "preview_deployments", + "columnsTo": [ + "previewDeploymentId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "postgresId" + ], + "tableTo": "postgres", + "columnsTo": [ + "postgresId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "mariadbId" + ], + "tableTo": "mariadb", + "columnsTo": [ + "mariadbId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "mongoId" + ], + "tableTo": "mongo", + "columnsTo": [ + "mongoId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "mysqlId" + ], + "tableTo": "mysql", + "columnsTo": [ + "mysqlId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "redisId" + ], + "tableTo": "redis", + "columnsTo": [ + "redisId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "composeId" + ], + "tableTo": "compose", + "columnsTo": [ + "composeId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "certificate_adminId_admin_adminId_fk": { + "name": "certificate_adminId_admin_adminId_fk", + "tableFrom": "certificate", + "columnsFrom": [ + "adminId" + ], + "tableTo": "admin", + "columnsTo": [ + "adminId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "certificate_serverId_server_serverId_fk": { + "name": "certificate_serverId_server_serverId_fk", + "tableFrom": "certificate", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "certificate_certificatePath_unique": { + "name": "certificate_certificatePath_unique", + "columns": [ + "certificatePath" + ], + "nullsNotDistinct": false + } + }, + "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", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_temp_token_unique": { + "name": "session_temp_token_unique", + "columns": [ + "token" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_auth_id_fk": { + "name": "session_user_id_auth_id_fk", + "tableFrom": "session", + "columnsFrom": [ + "user_id" + ], + "tableTo": "auth", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redirect": { + "name": "redirect", + "schema": "", + "columns": { + "redirectId": { + "name": "redirectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "regex": { + "name": "regex", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replacement": { + "name": "replacement", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permanent": { + "name": "permanent", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "redirect_applicationId_application_applicationId_fk": { + "name": "redirect_applicationId_application_applicationId_fk", + "tableFrom": "redirect", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "security_username_applicationId_unique": { + "name": "security_username_applicationId_unique", + "columns": [ + "username", + "applicationId" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.port": { + "name": "port", + "schema": "", + "columns": { + "portId": { + "name": "portId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publishedPort": { + "name": "publishedPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "tableTo": "ssh-key", + "columnsTo": [ + "sshKeyId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "githubId" + ], + "tableTo": "github", + "columnsTo": [ + "githubId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "gitlabId" + ], + "tableTo": "gitlab", + "columnsTo": [ + "gitlabId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "bitbucketId" + ], + "tableTo": "bitbucket", + "columnsTo": [ + "bitbucketId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_adminId_admin_adminId_fk": { + "name": "registry_adminId_admin_adminId_fk", + "tableFrom": "registry", + "columnsFrom": [ + "adminId" + ], + "tableTo": "admin", + "columnsTo": [ + "adminId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.discord": { + "name": "discord", + "schema": "", + "columns": { + "discordId": { + "name": "discordId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "decoration": { + "name": "decoration", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.email": { + "name": "email", + "schema": "", + "columns": { + "emailId": { + "name": "emailId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "smtpServer": { + "name": "smtpServer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "smtpPort": { + "name": "smtpPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fromAddress": { + "name": "fromAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "toAddress": { + "name": "toAddress", + "type": "text[]", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gotify": { + "name": "gotify", + "schema": "", + "columns": { + "gotifyId": { + "name": "gotifyId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverUrl": { + "name": "serverUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appToken": { + "name": "appToken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 5 + }, + "decoration": { + "name": "decoration", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notification": { + "name": "notification", + "schema": "", + "columns": { + "notificationId": { + "name": "notificationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appDeploy": { + "name": "appDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "appBuildError": { + "name": "appBuildError", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "databaseBackup": { + "name": "databaseBackup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dokployRestart": { + "name": "dokployRestart", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dockerCleanup": { + "name": "dockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "serverThreshold": { + "name": "serverThreshold", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "notificationType": { + "name": "notificationType", + "type": "notificationType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slackId": { + "name": "slackId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discordId": { + "name": "discordId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "emailId": { + "name": "emailId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gotifyId": { + "name": "gotifyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "notification_slackId_slack_slackId_fk": { + "name": "notification_slackId_slack_slackId_fk", + "tableFrom": "notification", + "columnsFrom": [ + "slackId" + ], + "tableTo": "slack", + "columnsTo": [ + "slackId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "notification_telegramId_telegram_telegramId_fk": { + "name": "notification_telegramId_telegram_telegramId_fk", + "tableFrom": "notification", + "columnsFrom": [ + "telegramId" + ], + "tableTo": "telegram", + "columnsTo": [ + "telegramId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "notification_discordId_discord_discordId_fk": { + "name": "notification_discordId_discord_discordId_fk", + "tableFrom": "notification", + "columnsFrom": [ + "discordId" + ], + "tableTo": "discord", + "columnsTo": [ + "discordId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "notification_emailId_email_emailId_fk": { + "name": "notification_emailId_email_emailId_fk", + "tableFrom": "notification", + "columnsFrom": [ + "emailId" + ], + "tableTo": "email", + "columnsTo": [ + "emailId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "notification_gotifyId_gotify_gotifyId_fk": { + "name": "notification_gotifyId_gotify_gotifyId_fk", + "tableFrom": "notification", + "columnsFrom": [ + "gotifyId" + ], + "tableTo": "gotify", + "columnsTo": [ + "gotifyId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "notification_adminId_admin_adminId_fk": { + "name": "notification_adminId_admin_adminId_fk", + "tableFrom": "notification", + "columnsFrom": [ + "adminId" + ], + "tableTo": "admin", + "columnsTo": [ + "adminId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack": { + "name": "slack", + "schema": "", + "columns": { + "slackId": { + "name": "slackId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.telegram": { + "name": "telegram", + "schema": "", + "columns": { + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "botToken": { + "name": "botToken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chatId": { + "name": "chatId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ssh-key": { + "name": "ssh-key", + "schema": "", + "columns": { + "sshKeyId": { + "name": "sshKeyId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "publicKey": { + "name": "publicKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lastUsedAt": { + "name": "lastUsedAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "ssh-key_adminId_admin_adminId_fk": { + "name": "ssh-key_adminId_admin_adminId_fk", + "tableFrom": "ssh-key", + "columnsFrom": [ + "adminId" + ], + "tableTo": "admin", + "columnsTo": [ + "adminId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.git_provider": { + "name": "git_provider", + "schema": "", + "columns": { + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerType": { + "name": "providerType", + "type": "gitProviderType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "git_provider_adminId_admin_adminId_fk": { + "name": "git_provider_adminId_admin_adminId_fk", + "tableFrom": "git_provider", + "columnsFrom": [ + "adminId" + ], + "tableTo": "admin", + "columnsTo": [ + "adminId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "gitProviderId" + ], + "tableTo": "git_provider", + "columnsTo": [ + "gitProviderId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "gitProviderId" + ], + "tableTo": "git_provider", + "columnsTo": [ + "gitProviderId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "gitProviderId" + ], + "tableTo": "git_provider", + "columnsTo": [ + "gitProviderId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.server": { + "name": "server", + "schema": "", + "columns": { + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'root'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverStatus": { + "name": "serverStatus", + "type": "serverStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "sshKeyId": { + "name": "sshKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Remote\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"urlCallback\":\"\",\"cronJob\":\"\",\"retentionDays\":2,\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + } + }, + "indexes": {}, + "foreignKeys": { + "server_adminId_admin_adminId_fk": { + "name": "server_adminId_admin_adminId_fk", + "tableFrom": "server", + "columnsFrom": [ + "adminId" + ], + "tableTo": "admin", + "columnsTo": [ + "adminId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "server_sshKeyId_ssh-key_sshKeyId_fk": { + "name": "server_sshKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "server", + "columnsFrom": [ + "sshKeyId" + ], + "tableTo": "ssh-key", + "columnsTo": [ + "sshKeyId" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "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", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "preview_deployments_domainId_domain_domainId_fk": { + "name": "preview_deployments_domainId_domain_domainId_fk", + "tableFrom": "preview_deployments", + "columnsFrom": [ + "domainId" + ], + "tableTo": "domain", + "columnsTo": [ + "domainId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "preview_deployments_appName_unique": { + "name": "preview_deployments_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "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", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "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 + } + }, + "indexes": {}, + "foreignKeys": { + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "invitation_inviter_id_user_temp_id_fk": { + "name": "invitation_inviter_id_user_temp_id_fk", + "tableFrom": "invitation", + "columnsFrom": [ + "inviter_id" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "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 + } + }, + "indexes": {}, + "foreignKeys": { + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "member_user_id_user_temp_id_fk": { + "name": "member_user_id_user_temp_id_fk", + "tableFrom": "member", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "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", + "columnsFrom": [ + "owner_id" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "columns": [ + "slug" + ], + "nullsNotDistinct": false + } + }, + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "views": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "_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 188a97009..c01cd500c 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -467,8 +467,15 @@ { "idx": 66, "version": "7", - "when": 1739425241338, - "tag": "0066_rapid_morbius", + "when": 1739426913392, + "tag": "0066_yielding_echo", + "breakpoints": true + }, + { + "idx": 67, + "version": "7", + "when": 1739427057545, + "tag": "0067_migrate-data", "breakpoints": true } ] diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts index c72d189c2..bbdb1915d 100644 --- a/packages/server/src/db/schema/certificate.ts +++ b/packages/server/src/db/schema/certificate.ts @@ -25,9 +25,9 @@ export const certificates = pgTable("certificate", { // userId: text("userId").references(() => user.userId, { // onDelete: "cascade", // }), - userId: text("userId") + adminId: text("adminId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => admins.adminId, { onDelete: "cascade" }), serverId: text("serverId").references(() => server.serverId, { onDelete: "cascade", }), @@ -40,10 +40,10 @@ export const certificatesRelations = relations( fields: [certificates.serverId], references: [server.serverId], }), - // user: one(user, { - // fields: [certificates.userId], - // references: [user.id], - // }), + admin: one(admins, { + fields: [certificates.adminId], + references: [admins.adminId], + }), }), ); diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts index 6b9ea5d93..cbbb4c2d5 100644 --- a/packages/server/src/db/schema/destination.ts +++ b/packages/server/src/db/schema/destination.ts @@ -24,9 +24,9 @@ export const destinations = pgTable("destination", { // userId: text("userId") // .notNull() // .references(() => user.userId, { onDelete: "cascade" }), - userId: text("userId") + adminId: text("adminId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => admins.adminId, { onDelete: "cascade" }), }); export const destinationsRelations = relations( diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index 4d154ee33..d6720ce06 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -29,9 +29,9 @@ export const gitProvider = pgTable("git_provider", { // userId: text("userId").references(() => user.userId, { // onDelete: "cascade", // }), - userId: text("userId") + adminId: text("adminId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => admins.adminId, { onDelete: "cascade" }), }); export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ @@ -47,10 +47,10 @@ export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ fields: [gitProvider.gitProviderId], references: [bitbucket.gitProviderId], }), - // user: one(user, { - // fields: [gitProvider.userId], - // references: [user.id], - // }), + admin: one(admins, { + fields: [gitProvider.adminId], + references: [admins.adminId], + }), })); const createSchema = createInsertSchema(gitProvider); diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 3ab253396..0270bd567 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -49,9 +49,9 @@ export const notifications = pgTable("notification", { // userId: text("userId").references(() => user.userId, { // onDelete: "cascade", // }), - userId: text("userId") + adminId: text("adminId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => admins.adminId, { onDelete: "cascade" }), }); export const slack = pgTable("slack", { @@ -126,10 +126,10 @@ export const notificationsRelations = relations(notifications, ({ one }) => ({ fields: [notifications.gotifyId], references: [gotify.gotifyId], }), - // user: one(user, { - // fields: [notifications.userId], - // references: [user.id], - // }), + admin: one(admins, { + fields: [notifications.adminId], + references: [admins.adminId], + }), })); export const notificationsSchema = createInsertSchema(notifications); diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index efde3c34b..e352e47fb 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -28,9 +28,9 @@ export const projects = pgTable("project", { // userId: text("userId") // .notNull() // .references(() => user.userId, { onDelete: "cascade" }), - userId: text("userId") + adminId: text("adminId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => admins.adminId, { onDelete: "cascade" }), env: text("env").notNull().default(""), }); diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index 62c2b2d7d..9efd6536f 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -32,9 +32,9 @@ export const registry = pgTable("registry", { // userId: text("userId") // .notNull() // .references(() => user.userId, { onDelete: "cascade" }), - userId: text("userId") + adminId: text("adminId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => admins.adminId, { onDelete: "cascade" }), }); export const registryRelations = relations(registry, ({ one, many }) => ({ diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index b6b77dbcd..ee1083bd6 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -47,9 +47,9 @@ export const server = pgTable("server", { // userId: text("userId") // .notNull() // .references(() => user.userId, { onDelete: "cascade" }), - userId: text("userId") + adminId: text("adminId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => admins.adminId, { onDelete: "cascade" }), serverStatus: serverStatus("serverStatus").notNull().default("active"), command: text("command").notNull().default(""), sshKeyId: text("sshKeyId").references(() => sshKeys.sshKeyId, { From 7c624080704134999fb5325ae1739339337b4be6 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 13 Feb 2025 00:38:39 -0600 Subject: [PATCH 10/89] refactor: delete --- apps/dokploy/drizzle/0066_smiling_warlock.sql | 153 ------------------ apps/dokploy/migrate.ts | 2 +- packages/server/src/db/schema/account.ts | 2 +- packages/server/src/db/schema/certificate.ts | 4 +- packages/server/src/db/schema/project.ts | 2 +- packages/server/src/db/schema/server.ts | 2 +- packages/server/src/db/schema/session.ts | 2 +- 7 files changed, 7 insertions(+), 160 deletions(-) delete mode 100644 apps/dokploy/drizzle/0066_smiling_warlock.sql diff --git a/apps/dokploy/drizzle/0066_smiling_warlock.sql b/apps/dokploy/drizzle/0066_smiling_warlock.sql deleted file mode 100644 index 9deea8818..000000000 --- a/apps/dokploy/drizzle/0066_smiling_warlock.sql +++ /dev/null @@ -1,153 +0,0 @@ -CREATE TABLE "user_temp" ( - "id" text PRIMARY KEY NOT NULL, - "name" text DEFAULT '' NOT NULL, - "token" text NOT NULL, - "isRegistered" boolean DEFAULT false NOT NULL, - "expirationDate" text NOT NULL, - "createdAt" text NOT NULL, - "canCreateProjects" boolean DEFAULT false NOT NULL, - "canAccessToSSHKeys" boolean DEFAULT false NOT NULL, - "canCreateServices" boolean DEFAULT false NOT NULL, - "canDeleteProjects" boolean DEFAULT false NOT NULL, - "canDeleteServices" boolean DEFAULT false NOT NULL, - "canAccessToDocker" boolean DEFAULT false NOT NULL, - "canAccessToAPI" boolean DEFAULT false NOT NULL, - "canAccessToGitProviders" boolean DEFAULT false NOT NULL, - "canAccessToTraefikFiles" boolean DEFAULT false NOT NULL, - "accesedProjects" text[] DEFAULT ARRAY[]::text[] NOT NULL, - "accesedServices" text[] DEFAULT ARRAY[]::text[] NOT NULL, - "email" text NOT NULL, - "email_verified" boolean NOT NULL, - "image" text, - "role" text, - "banned" boolean, - "ban_reason" text, - "ban_expires" timestamp, - "updated_at" timestamp NOT NULL, - "serverIp" text, - "certificateType" "certificateType" DEFAULT 'none' NOT NULL, - "host" text, - "letsEncryptEmail" text, - "sshPrivateKey" text, - "enableDockerCleanup" boolean DEFAULT false NOT NULL, - "enableLogRotation" boolean DEFAULT false NOT NULL, - "enablePaidFeatures" boolean DEFAULT false NOT NULL, - "metricsConfig" jsonb 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 NOT NULL, - "cleanupCacheApplications" boolean DEFAULT false NOT NULL, - "cleanupCacheOnPreviews" boolean DEFAULT false NOT NULL, - "cleanupCacheOnCompose" boolean DEFAULT false NOT NULL, - "stripeCustomerId" text, - "stripeSubscriptionId" text, - "serversQuantity" integer DEFAULT 0 NOT NULL, - CONSTRAINT "user_temp_email_unique" UNIQUE("email") -); ---> statement-breakpoint -CREATE TABLE "session_temp" ( - "id" text PRIMARY KEY NOT NULL, - "expires_at" timestamp NOT NULL, - "token" text NOT NULL, - "created_at" timestamp NOT NULL, - "updated_at" timestamp NOT NULL, - "ip_address" text, - "user_agent" text, - "user_id" text NOT NULL, - "impersonated_by" text, - "active_organization_id" text, - CONSTRAINT "session_temp_token_unique" UNIQUE("token") -); ---> statement-breakpoint -CREATE TABLE "account" ( - "id" text PRIMARY KEY NOT NULL, - "account_id" text NOT NULL, - "provider_id" text NOT NULL, - "user_id" text NOT NULL, - "access_token" text, - "refresh_token" text, - "id_token" text, - "access_token_expires_at" timestamp, - "refresh_token_expires_at" timestamp, - "scope" text, - "password" text, - "is2FAEnabled" boolean DEFAULT false NOT NULL, - "created_at" timestamp NOT NULL, - "updated_at" timestamp NOT NULL, - "resetPasswordToken" text, - "resetPasswordExpiresAt" text, - "confirmationToken" text, - "confirmationExpiresAt" text -); ---> statement-breakpoint -CREATE TABLE "invitation" ( - "id" text PRIMARY KEY NOT NULL, - "organization_id" text NOT NULL, - "email" text NOT NULL, - "role" text, - "status" text NOT NULL, - "expires_at" timestamp NOT NULL, - "inviter_id" text NOT NULL -); ---> statement-breakpoint -CREATE TABLE "member" ( - "id" text PRIMARY KEY NOT NULL, - "organization_id" text NOT NULL, - "user_id" text NOT NULL, - "role" text NOT NULL, - "created_at" timestamp NOT NULL -); ---> statement-breakpoint -CREATE TABLE "organization" ( - "id" text PRIMARY KEY NOT NULL, - "name" text NOT NULL, - "slug" text, - "logo" text, - "created_at" timestamp NOT NULL, - "metadata" text, - "owner_id" text NOT NULL, - CONSTRAINT "organization_slug_unique" UNIQUE("slug") -); ---> statement-breakpoint -CREATE TABLE "verification" ( - "id" text PRIMARY KEY NOT NULL, - "identifier" text NOT NULL, - "value" text NOT NULL, - "expires_at" timestamp NOT NULL, - "created_at" timestamp, - "updated_at" timestamp -); ---> statement-breakpoint -ALTER TABLE "project" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint -ALTER TABLE "destination" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint -ALTER TABLE "certificate" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint -ALTER TABLE "registry" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint -ALTER TABLE "notification" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint -ALTER TABLE "git_provider" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint -ALTER TABLE "server" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint -ALTER TABLE "project" DROP CONSTRAINT "project_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "destination" DROP CONSTRAINT "destination_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "certificate" DROP CONSTRAINT "certificate_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "registry" DROP CONSTRAINT "registry_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "notification" DROP CONSTRAINT "notification_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "git_provider" DROP CONSTRAINT "git_provider_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "server" DROP CONSTRAINT "server_adminId_admin_adminId_fk"; ---> statement-breakpoint -ALTER TABLE "ssh-key" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint -ALTER TABLE "session_temp" ADD CONSTRAINT "session_temp_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "invitation" ADD CONSTRAINT "invitation_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "invitation" ADD CONSTRAINT "invitation_inviter_id_user_temp_id_fk" FOREIGN KEY ("inviter_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_temp_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "project" ADD CONSTRAINT "project_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "destination" ADD CONSTRAINT "destination_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "certificate" ADD CONSTRAINT "certificate_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "registry" ADD CONSTRAINT "registry_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "notification" ADD CONSTRAINT "notification_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "git_provider" ADD CONSTRAINT "git_provider_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "server" ADD CONSTRAINT "server_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/apps/dokploy/migrate.ts b/apps/dokploy/migrate.ts index 72bbf2ab0..bcbac2336 100644 --- a/apps/dokploy/migrate.ts +++ b/apps/dokploy/migrate.ts @@ -1,8 +1,8 @@ import { drizzle } from "drizzle-orm/postgres-js"; import { migrate } from "drizzle-orm/postgres-js/migrator"; +import { nanoid } from "nanoid"; import postgres from "postgres"; import * as schema from "./server/db/schema"; -import { nanoid } from "nanoid"; const connectionString = process.env.DATABASE_URL!; diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 349428fd8..3e81fbf69 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -1,6 +1,6 @@ import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; -import { users_temp } from "./user"; import { nanoid } from "nanoid"; +import { users_temp } from "./user"; export const account = pgTable("account", { id: text("id") diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts index bbdb1915d..02b00f65e 100644 --- a/packages/server/src/db/schema/certificate.ts +++ b/packages/server/src/db/schema/certificate.ts @@ -3,11 +3,11 @@ import { boolean, pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; +import { admins } from "./admin"; import { server } from "./server"; +import { users_temp } from "./user"; // import { user } from "./user"; import { generateAppName } from "./utils"; -import { admins } from "./admin"; -import { users_temp } from "./user"; export const certificates = pgTable("certificate", { certificateId: text("certificateId") diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index e352e47fb..48effa81c 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -4,6 +4,7 @@ import { pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; +import { admins } from "./admin"; // import { admins } from "./admin"; import { applications } from "./application"; import { compose } from "./compose"; @@ -13,7 +14,6 @@ import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; import { users, users_temp } from "./user"; -import { admins } from "./admin"; export const projects = pgTable("project", { projectId: text("projectId") diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index ee1083bd6..c0b44ef97 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -22,9 +22,9 @@ import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; import { sshKeys } from "./ssh-key"; +import { users_temp } from "./user"; // import { user } from "./user"; import { generateAppName } from "./utils"; -import { users_temp } from "./user"; export const serverStatus = pgEnum("serverStatus", ["active", "inactive"]); diff --git a/packages/server/src/db/schema/session.ts b/packages/server/src/db/schema/session.ts index 03a70c41a..4e9d28835 100644 --- a/packages/server/src/db/schema/session.ts +++ b/packages/server/src/db/schema/session.ts @@ -1,7 +1,7 @@ import { sql } from "drizzle-orm"; import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; -import { users_temp } from "./user"; import { auth } from "./auth"; +import { users_temp } from "./user"; // OLD TABLE export const session = pgTable("session_temp", { From 0d525398a83fff995dd1c4eda8ad4541d24ec11f Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 13 Feb 2025 00:45:29 -0600 Subject: [PATCH 11/89] feat: migrate rest schemas --- .../drizzle/0068_sour_professor_monster.sql | 32 + apps/dokploy/drizzle/meta/0068_snapshot.json | 5278 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + packages/server/src/db/schema/certificate.ts | 10 +- packages/server/src/db/schema/destination.ts | 4 +- packages/server/src/db/schema/git-provider.ts | 4 +- packages/server/src/db/schema/notification.ts | 10 +- packages/server/src/db/schema/project.ts | 4 +- packages/server/src/db/schema/registry.ts | 4 +- packages/server/src/db/schema/server.ts | 4 +- packages/server/src/db/schema/ssh-key.ts | 13 +- packages/server/src/db/schema/user.ts | 8 +- 12 files changed, 5348 insertions(+), 30 deletions(-) create mode 100644 apps/dokploy/drizzle/0068_sour_professor_monster.sql create mode 100644 apps/dokploy/drizzle/meta/0068_snapshot.json diff --git a/apps/dokploy/drizzle/0068_sour_professor_monster.sql b/apps/dokploy/drizzle/0068_sour_professor_monster.sql new file mode 100644 index 000000000..f69152b5d --- /dev/null +++ b/apps/dokploy/drizzle/0068_sour_professor_monster.sql @@ -0,0 +1,32 @@ +ALTER TABLE "project" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "destination" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "certificate" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "registry" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "notification" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "ssh-key" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "git_provider" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "server" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint +ALTER TABLE "project" DROP CONSTRAINT "project_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "destination" DROP CONSTRAINT "destination_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "certificate" DROP CONSTRAINT "certificate_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "registry" DROP CONSTRAINT "registry_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "notification" DROP CONSTRAINT "notification_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "ssh-key" DROP CONSTRAINT "ssh-key_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "git_provider" DROP CONSTRAINT "git_provider_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "server" DROP CONSTRAINT "server_adminId_admin_adminId_fk"; +--> statement-breakpoint +ALTER TABLE "project" ADD CONSTRAINT "project_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "destination" ADD CONSTRAINT "destination_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "certificate" ADD CONSTRAINT "certificate_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "registry" ADD CONSTRAINT "registry_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "notification" ADD CONSTRAINT "notification_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "ssh-key" ADD CONSTRAINT "ssh-key_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "git_provider" ADD CONSTRAINT "git_provider_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "server" ADD CONSTRAINT "server_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0068_snapshot.json b/apps/dokploy/drizzle/meta/0068_snapshot.json new file mode 100644 index 000000000..c9f50b5ee --- /dev/null +++ b/apps/dokploy/drizzle/meta/0068_snapshot.json @@ -0,0 +1,5278 @@ +{ + "id": "c2e134de-9865-4892-a24d-048aa5be22e8", + "prevId": "54ba08a1-8861-438a-a89d-f01d09a690c2", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_adminId_admin_adminId_fk": { + "name": "user_adminId_admin_adminId_fk", + "tableFrom": "user", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_authId_auth_id_fk": { + "name": "user_authId_auth_id_fk", + "tableFrom": "user", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.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": "''" + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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 + }, + "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[]" + }, + "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 + }, + "role": { + "name": "role", + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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.admin": { + "name": "admin", + "schema": "", + "columns": { + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripeCustomerId": { + "name": "stripeCustomerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripeSubscriptionId": { + "name": "stripeSubscriptionId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serversQuantity": { + "name": "serversQuantity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "admin_authId_auth_id_fk": { + "name": "admin_authId_auth_id_fk", + "tableFrom": "admin", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resetPasswordToken": { + "name": "resetPasswordToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resetPasswordExpiresAt": { + "name": "resetPasswordExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationToken": { + "name": "confirmationToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationExpiresAt": { + "name": "confirmationExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "project_userId_user_temp_id_fk": { + "name": "project_userId_user_temp_id_fk", + "tableFrom": "project", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "destination_userId_user_temp_id_fk": { + "name": "destination_userId_user_temp_id_fk", + "tableFrom": "destination", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "certificate_userId_user_temp_id_fk": { + "name": "certificate_userId_user_temp_id_fk", + "tableFrom": "certificate", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_temp_token_unique": { + "name": "session_temp_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_auth_id_fk": { + "name": "session_user_id_auth_id_fk", + "tableFrom": "session", + "tableTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redirect": { + "name": "redirect", + "schema": "", + "columns": { + "redirectId": { + "name": "redirectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "regex": { + "name": "regex", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replacement": { + "name": "replacement", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permanent": { + "name": "permanent", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "redirect_applicationId_application_applicationId_fk": { + "name": "redirect_applicationId_application_applicationId_fk", + "tableFrom": "redirect", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.security": { + "name": "security", + "schema": "", + "columns": { + "securityId": { + "name": "securityId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "security_applicationId_application_applicationId_fk": { + "name": "security_applicationId_application_applicationId_fk", + "tableFrom": "security", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "security_username_applicationId_unique": { + "name": "security_username_applicationId_unique", + "nullsNotDistinct": false, + "columns": [ + "username", + "applicationId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.port": { + "name": "port", + "schema": "", + "columns": { + "portId": { + "name": "portId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publishedPort": { + "name": "publishedPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_userId_user_temp_id_fk": { + "name": "registry_userId_user_temp_id_fk", + "tableFrom": "registry", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "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_userId_user_temp_id_fk": { + "name": "notification_userId_user_temp_id_fk", + "tableFrom": "notification", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + } + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "ssh-key_userId_user_temp_id_fk": { + "name": "ssh-key_userId_user_temp_id_fk", + "tableFrom": "ssh-key", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "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.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 + }, + "userId": { + "name": "userId", + "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_userId_user_temp_id_fk": { + "name": "server_userId_user_temp_id_fk", + "tableFrom": "server", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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.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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index c01cd500c..e0bdf1c64 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -477,6 +477,13 @@ "when": 1739427057545, "tag": "0067_migrate-data", "breakpoints": true + }, + { + "idx": 68, + "version": "7", + "when": 1739428942964, + "tag": "0068_sour_professor_monster", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts index 02b00f65e..d31e5929f 100644 --- a/packages/server/src/db/schema/certificate.ts +++ b/packages/server/src/db/schema/certificate.ts @@ -25,9 +25,9 @@ export const certificates = pgTable("certificate", { // userId: text("userId").references(() => user.userId, { // onDelete: "cascade", // }), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), serverId: text("serverId").references(() => server.serverId, { onDelete: "cascade", }), @@ -40,9 +40,9 @@ export const certificatesRelations = relations( fields: [certificates.serverId], references: [server.serverId], }), - admin: one(admins, { - fields: [certificates.adminId], - references: [admins.adminId], + user: one(users_temp, { + fields: [certificates.userId], + references: [users_temp.id], }), }), ); diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts index cbbb4c2d5..6b9ea5d93 100644 --- a/packages/server/src/db/schema/destination.ts +++ b/packages/server/src/db/schema/destination.ts @@ -24,9 +24,9 @@ export const destinations = pgTable("destination", { // userId: text("userId") // .notNull() // .references(() => user.userId, { onDelete: "cascade" }), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), }); export const destinationsRelations = relations( diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index d6720ce06..a3410af53 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -29,9 +29,9 @@ export const gitProvider = pgTable("git_provider", { // userId: text("userId").references(() => user.userId, { // onDelete: "cascade", // }), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), }); export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 0270bd567..462b67109 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -49,9 +49,9 @@ export const notifications = pgTable("notification", { // userId: text("userId").references(() => user.userId, { // onDelete: "cascade", // }), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), }); export const slack = pgTable("slack", { @@ -126,9 +126,9 @@ export const notificationsRelations = relations(notifications, ({ one }) => ({ fields: [notifications.gotifyId], references: [gotify.gotifyId], }), - admin: one(admins, { - fields: [notifications.adminId], - references: [admins.adminId], + user: one(users_temp, { + fields: [notifications.userId], + references: [users_temp.id], }), })); diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index 48effa81c..60f7842b1 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -28,9 +28,9 @@ export const projects = pgTable("project", { // userId: text("userId") // .notNull() // .references(() => user.userId, { onDelete: "cascade" }), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), env: text("env").notNull().default(""), }); diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index 9efd6536f..62c2b2d7d 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -32,9 +32,9 @@ export const registry = pgTable("registry", { // userId: text("userId") // .notNull() // .references(() => user.userId, { onDelete: "cascade" }), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), }); export const registryRelations = relations(registry, ({ one, many }) => ({ diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index c0b44ef97..26023e96c 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -47,9 +47,9 @@ export const server = pgTable("server", { // userId: text("userId") // .notNull() // .references(() => user.userId, { onDelete: "cascade" }), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), serverStatus: serverStatus("serverStatus").notNull().default("active"), command: text("command").notNull().default(""), sshKeyId: text("sshKeyId").references(() => sshKeys.sshKeyId, { diff --git a/packages/server/src/db/schema/ssh-key.ts b/packages/server/src/db/schema/ssh-key.ts index cca9259bc..4daa438ce 100644 --- a/packages/server/src/db/schema/ssh-key.ts +++ b/packages/server/src/db/schema/ssh-key.ts @@ -7,6 +7,7 @@ import { admins } from "./admin"; import { applications } from "./application"; import { compose } from "./compose"; import { server } from "./server"; +import { users_temp } from "./user"; // import { user } from "./user"; export const sshKeys = pgTable("ssh-key", { @@ -25,19 +26,19 @@ export const sshKeys = pgTable("ssh-key", { // userId: text("userId").references(() => user.userId, { // onDelete: "cascade", // }), - adminId: text("adminId") + userId: text("userId") .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), + .references(() => users_temp.id, { onDelete: "cascade" }), }); export const sshKeysRelations = relations(sshKeys, ({ many, one }) => ({ applications: many(applications), compose: many(compose), servers: many(server), - // user: one(user, { - // fields: [sshKeys.userId], - // references: [user.id], - // }), + user: one(users_temp, { + fields: [sshKeys.userId], + references: [users_temp.id], + }), })); const createSchema = createInsertSchema( diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 5f2a14e91..932a0a09c 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -189,10 +189,10 @@ export const usersRelations = relations(users, ({ one }) => ({ fields: [users.authId], references: [auth.id], }), - admin: one(admins, { - fields: [users.adminId], - references: [admins.adminId], - }), + // admin: one(admins, { + // fields: [users.adminId], + // references: [admins.adminId], + // }), })); const createSchema = createInsertSchema(users, { From d1f72a2e20fdc2304a380c684ea7f77e52daa95a Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 13 Feb 2025 00:57:22 -0600 Subject: [PATCH 12/89] refactor: update migration --- apps/dokploy/drizzle/0067_migrate-data.sql | 26 ++++++++++++++++++++++ apps/dokploy/migrate.ts | 9 ++++++++ 2 files changed, 35 insertions(+) diff --git a/apps/dokploy/drizzle/0067_migrate-data.sql b/apps/dokploy/drizzle/0067_migrate-data.sql index 62604d32c..b5cefd7b7 100644 --- a/apps/dokploy/drizzle/0067_migrate-data.sql +++ b/apps/dokploy/drizzle/0067_migrate-data.sql @@ -150,6 +150,32 @@ inserted_members AS ( JOIN admin a ON u."adminId" = a."adminId" JOIN auth ON auth.id = u."authId" RETURNING * +), +inserted_member_accounts AS ( + -- Insertar cuentas para los usuarios miembros + INSERT INTO account ( + id, + "account_id", + "provider_id", + "user_id", + password, + "is2FAEnabled", + "created_at", + "updated_at" + ) + SELECT + gen_random_uuid(), + gen_random_uuid(), + 'credentials', + u."userId", + auth.password, + COALESCE(auth."is2FAEnabled", false), + NOW(), + NOW() + FROM "user" u + JOIN admin a ON u."adminId" = a."adminId" + JOIN auth ON auth.id = u."authId" + RETURNING * ) -- Insertar miembros en las organizaciones INSERT INTO member ( diff --git a/apps/dokploy/migrate.ts b/apps/dokploy/migrate.ts index bcbac2336..8a8e0dcbe 100644 --- a/apps/dokploy/migrate.ts +++ b/apps/dokploy/migrate.ts @@ -100,6 +100,15 @@ await db .returning() .then((userTemp) => userTemp[0]); + await db.insert(schema.account).values({ + providerId: "credentials", + 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 || "", From 140a871275a7d61ed74e34d1c6f81c69a89c7fc6 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 13 Feb 2025 01:21:49 -0600 Subject: [PATCH 13/89] refactor: update --- packages/server/src/db/schema/git-provider.ts | 6 +++--- packages/server/src/services/admin.ts | 2 +- packages/server/src/services/auth.ts | 2 +- packages/server/src/services/user.ts | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index a3410af53..be2c50001 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -47,9 +47,9 @@ export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ fields: [gitProvider.gitProviderId], references: [bitbucket.gitProviderId], }), - admin: one(admins, { - fields: [gitProvider.adminId], - references: [admins.adminId], + user: one(users_temp, { + fields: [gitProvider.userId], + references: [users_temp.id], }), })); diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index 21c8f13e5..5155231b0 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -4,7 +4,7 @@ import { admins, type apiCreateUserInvitation, auth, - user, + users_temp, } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import * as bcrypt from "bcrypt"; diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts index f391d011d..787ceedb8 100644 --- a/packages/server/src/services/auth.ts +++ b/packages/server/src/services/auth.ts @@ -5,7 +5,7 @@ import { type apiCreateAdmin, type apiCreateUser, auth, - user, + users_temp, } from "@dokploy/server/db/schema"; import { getPublicIpWithFallback } from "@dokploy/server/wss/utils"; import { TRPCError } from "@trpc/server"; diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index afc3ec009..5a9898cde 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -1,9 +1,9 @@ import { db } from "@dokploy/server/db"; -import { user } from "@dokploy/server/db/schema"; +import type { users_temp } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; -export type User = typeof user.$inferSelect; +export type User = typeof users_temp.$inferSelect; export const findUserById = async (userId: string) => { const userR = await db.query.user.findFirst({ From 74ee024cf90e6ba66e2d6ef31443d8763adf1718 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 13 Feb 2025 01:24:25 -0600 Subject: [PATCH 14/89] refactor: update temps --- apps/dokploy/pages/index.tsx | 4 ++++ packages/server/src/lib/auth.ts | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index e5cc0500d..210160843 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -94,6 +94,10 @@ export default function Home({ IS_CLOUD }: Props) { }); // router.push("/dashboard/projects"); // } + } else { + toast.error("Error to sign up", { + description: error.message, + }); } console.log(data, error); diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 8a3e1781c..2706bceac 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -18,15 +18,16 @@ export const auth = betterAuth({ if (ctx.path.startsWith("/sign-up")) { const newSession = ctx.context.newSession; await db - .update(schema.user) + .update(schema.users_temp) .set({ role: "admin", }) - .where(eq(schema.user.id, newSession?.user?.id || "")); + .where(eq(schema.users_temp.id, newSession?.user?.id || "")); } }), }, user: { + modelName: "users_temp", additionalFields: {}, }, plugins: [organization()], From 7c0d223e1794a2721c6368cca06c284087fdc241 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 13 Feb 2025 01:42:58 -0600 Subject: [PATCH 15/89] refactor: add fields --- apps/dokploy/drizzle/0069_known_aqueduct.sql | 1 + .../drizzle/0070_overrated_the_stranger.sql | 1 + apps/dokploy/drizzle/meta/0069_snapshot.json | 5285 ++++++++++++++++ apps/dokploy/drizzle/meta/0070_snapshot.json | 5286 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 14 + packages/server/package.json | 2 + packages/server/src/auth/auth.ts | 1 + packages/server/src/db/schema/user.ts | 5 +- packages/server/src/lib/auth.ts | 7 + packages/server/src/lib/crypto.ts | 94 + packages/server/src/lib/scrypt/index.ts | 1 + pnpm-lock.yaml | 31 + 12 files changed, 10726 insertions(+), 2 deletions(-) create mode 100644 apps/dokploy/drizzle/0069_known_aqueduct.sql create mode 100644 apps/dokploy/drizzle/0070_overrated_the_stranger.sql create mode 100644 apps/dokploy/drizzle/meta/0069_snapshot.json create mode 100644 apps/dokploy/drizzle/meta/0070_snapshot.json create mode 100644 packages/server/src/lib/crypto.ts create mode 100644 packages/server/src/lib/scrypt/index.ts diff --git a/apps/dokploy/drizzle/0069_known_aqueduct.sql b/apps/dokploy/drizzle/0069_known_aqueduct.sql new file mode 100644 index 000000000..d6f4dea76 --- /dev/null +++ b/apps/dokploy/drizzle/0069_known_aqueduct.sql @@ -0,0 +1 @@ +ALTER TABLE "user_temp" ADD COLUMN "created_at" timestamp DEFAULT now(); \ No newline at end of file diff --git a/apps/dokploy/drizzle/0070_overrated_the_stranger.sql b/apps/dokploy/drizzle/0070_overrated_the_stranger.sql new file mode 100644 index 000000000..dab91327b --- /dev/null +++ b/apps/dokploy/drizzle/0070_overrated_the_stranger.sql @@ -0,0 +1 @@ +ALTER TABLE "user_temp" ALTER COLUMN "token" SET DEFAULT ''; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0069_snapshot.json b/apps/dokploy/drizzle/meta/0069_snapshot.json new file mode 100644 index 000000000..084216167 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0069_snapshot.json @@ -0,0 +1,5285 @@ +{ + "id": "82a6a31d-7611-410d-8a32-31a36ab369c5", + "prevId": "c2e134de-9865-4892-a24d-048aa5be22e8", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_adminId_admin_adminId_fk": { + "name": "user_adminId_admin_adminId_fk", + "tableFrom": "user", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_authId_auth_id_fk": { + "name": "user_authId_auth_id_fk", + "tableFrom": "user", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.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": "''" + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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()" + }, + "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[]" + }, + "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 + }, + "role": { + "name": "role", + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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.admin": { + "name": "admin", + "schema": "", + "columns": { + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripeCustomerId": { + "name": "stripeCustomerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripeSubscriptionId": { + "name": "stripeSubscriptionId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serversQuantity": { + "name": "serversQuantity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "admin_authId_auth_id_fk": { + "name": "admin_authId_auth_id_fk", + "tableFrom": "admin", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resetPasswordToken": { + "name": "resetPasswordToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resetPasswordExpiresAt": { + "name": "resetPasswordExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationToken": { + "name": "confirmationToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationExpiresAt": { + "name": "confirmationExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "project_userId_user_temp_id_fk": { + "name": "project_userId_user_temp_id_fk", + "tableFrom": "project", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "destination_userId_user_temp_id_fk": { + "name": "destination_userId_user_temp_id_fk", + "tableFrom": "destination", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "certificate_userId_user_temp_id_fk": { + "name": "certificate_userId_user_temp_id_fk", + "tableFrom": "certificate", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_temp_token_unique": { + "name": "session_temp_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_auth_id_fk": { + "name": "session_user_id_auth_id_fk", + "tableFrom": "session", + "tableTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redirect": { + "name": "redirect", + "schema": "", + "columns": { + "redirectId": { + "name": "redirectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "regex": { + "name": "regex", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replacement": { + "name": "replacement", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permanent": { + "name": "permanent", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "redirect_applicationId_application_applicationId_fk": { + "name": "redirect_applicationId_application_applicationId_fk", + "tableFrom": "redirect", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.security": { + "name": "security", + "schema": "", + "columns": { + "securityId": { + "name": "securityId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "security_applicationId_application_applicationId_fk": { + "name": "security_applicationId_application_applicationId_fk", + "tableFrom": "security", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "security_username_applicationId_unique": { + "name": "security_username_applicationId_unique", + "nullsNotDistinct": false, + "columns": [ + "username", + "applicationId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.port": { + "name": "port", + "schema": "", + "columns": { + "portId": { + "name": "portId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publishedPort": { + "name": "publishedPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_userId_user_temp_id_fk": { + "name": "registry_userId_user_temp_id_fk", + "tableFrom": "registry", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "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_userId_user_temp_id_fk": { + "name": "notification_userId_user_temp_id_fk", + "tableFrom": "notification", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + } + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "ssh-key_userId_user_temp_id_fk": { + "name": "ssh-key_userId_user_temp_id_fk", + "tableFrom": "ssh-key", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "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.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 + }, + "userId": { + "name": "userId", + "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_userId_user_temp_id_fk": { + "name": "server_userId_user_temp_id_fk", + "tableFrom": "server", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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.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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0070_snapshot.json b/apps/dokploy/drizzle/meta/0070_snapshot.json new file mode 100644 index 000000000..b0a1eea7c --- /dev/null +++ b/apps/dokploy/drizzle/meta/0070_snapshot.json @@ -0,0 +1,5286 @@ +{ + "id": "c01cab17-e046-4691-b5ab-43f6a92879d4", + "prevId": "82a6a31d-7611-410d-8a32-31a36ab369c5", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_adminId_admin_adminId_fk": { + "name": "user_adminId_admin_adminId_fk", + "tableFrom": "user", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_authId_auth_id_fk": { + "name": "user_authId_auth_id_fk", + "tableFrom": "user", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.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": "''" + }, + "token": { + "name": "token", + "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()" + }, + "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[]" + }, + "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 + }, + "role": { + "name": "role", + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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.admin": { + "name": "admin", + "schema": "", + "columns": { + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripeCustomerId": { + "name": "stripeCustomerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripeSubscriptionId": { + "name": "stripeSubscriptionId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serversQuantity": { + "name": "serversQuantity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "admin_authId_auth_id_fk": { + "name": "admin_authId_auth_id_fk", + "tableFrom": "admin", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resetPasswordToken": { + "name": "resetPasswordToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resetPasswordExpiresAt": { + "name": "resetPasswordExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationToken": { + "name": "confirmationToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationExpiresAt": { + "name": "confirmationExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "project_userId_user_temp_id_fk": { + "name": "project_userId_user_temp_id_fk", + "tableFrom": "project", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "destination_userId_user_temp_id_fk": { + "name": "destination_userId_user_temp_id_fk", + "tableFrom": "destination", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "certificate_userId_user_temp_id_fk": { + "name": "certificate_userId_user_temp_id_fk", + "tableFrom": "certificate", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_temp_token_unique": { + "name": "session_temp_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_auth_id_fk": { + "name": "session_user_id_auth_id_fk", + "tableFrom": "session", + "tableTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redirect": { + "name": "redirect", + "schema": "", + "columns": { + "redirectId": { + "name": "redirectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "regex": { + "name": "regex", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replacement": { + "name": "replacement", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permanent": { + "name": "permanent", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "redirect_applicationId_application_applicationId_fk": { + "name": "redirect_applicationId_application_applicationId_fk", + "tableFrom": "redirect", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.security": { + "name": "security", + "schema": "", + "columns": { + "securityId": { + "name": "securityId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "security_applicationId_application_applicationId_fk": { + "name": "security_applicationId_application_applicationId_fk", + "tableFrom": "security", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "security_username_applicationId_unique": { + "name": "security_username_applicationId_unique", + "nullsNotDistinct": false, + "columns": [ + "username", + "applicationId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.port": { + "name": "port", + "schema": "", + "columns": { + "portId": { + "name": "portId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publishedPort": { + "name": "publishedPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_userId_user_temp_id_fk": { + "name": "registry_userId_user_temp_id_fk", + "tableFrom": "registry", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "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_userId_user_temp_id_fk": { + "name": "notification_userId_user_temp_id_fk", + "tableFrom": "notification", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + } + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "ssh-key_userId_user_temp_id_fk": { + "name": "ssh-key_userId_user_temp_id_fk", + "tableFrom": "ssh-key", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "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.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 + }, + "userId": { + "name": "userId", + "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_userId_user_temp_id_fk": { + "name": "server_userId_user_temp_id_fk", + "tableFrom": "server", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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.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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index e0bdf1c64..d10d6816e 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -484,6 +484,20 @@ "when": 1739428942964, "tag": "0068_sour_professor_monster", "breakpoints": true + }, + { + "idx": 69, + "version": "7", + "when": 1739432476590, + "tag": "0069_known_aqueduct", + "breakpoints": true + }, + { + "idx": 70, + "version": "7", + "when": 1739432513877, + "tag": "0070_overrated_the_stranger", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/server/package.json b/packages/server/package.json index a8cf97c66..d8f72a868 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -28,6 +28,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@oslojs/encoding":"1.1.0", + "@oslojs/crypto":"1.0.1", "drizzle-dbml-generator":"0.10.0", "better-auth":"1.1.16", "rotating-file-stream": "3.2.3", diff --git a/packages/server/src/auth/auth.ts b/packages/server/src/auth/auth.ts index 423c4333f..7dc26c95f 100644 --- a/packages/server/src/auth/auth.ts +++ b/packages/server/src/auth/auth.ts @@ -16,6 +16,7 @@ export const lucia = new Lucia(adapter, { secure: false, }, }, + sessionExpiresIn: new TimeSpan(1, "d"), getUserAttributes: (attributes) => { return { diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 932a0a09c..d754687cd 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -73,14 +73,15 @@ export const users_temp = pgTable("user_temp", { .primaryKey() .$defaultFn(() => nanoid()), name: text("name").notNull().default(""), - token: text("token").notNull(), + token: text("token").notNull().default(""), isRegistered: boolean("isRegistered").notNull().default(false), expirationDate: text("expirationDate") .notNull() .$defaultFn(() => new Date().toISOString()), - createdAt: text("createdAt") + createdAt2: text("createdAt") .notNull() .$defaultFn(() => new Date().toISOString()), + createdAt: timestamp("created_at").defaultNow(), canCreateProjects: boolean("canCreateProjects").notNull().default(false), canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false), canCreateServices: boolean("canCreateServices").notNull().default(false), diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 2706bceac..9555e9b6c 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -5,6 +5,9 @@ import { admin, createAuthMiddleware, organization } from "better-auth/plugins"; import { eq } from "drizzle-orm"; import { db } from "../db"; import * as schema from "../db/schema"; +import { Scrypt } from "lucia"; +const scrypt = new Scrypt(); + export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", @@ -12,6 +15,10 @@ export const auth = betterAuth({ }), emailAndPassword: { enabled: true, + password: { + hash: scrypt.hash, + verify: scrypt.verify, + }, }, hooks: { after: createAuthMiddleware(async (ctx) => { diff --git a/packages/server/src/lib/crypto.ts b/packages/server/src/lib/crypto.ts new file mode 100644 index 000000000..27d86dbd5 --- /dev/null +++ b/packages/server/src/lib/crypto.ts @@ -0,0 +1,94 @@ +// import { +// decodeHex, +// encodeBase32LowerCaseNoPadding, +// encodeHexLowerCase, +// } from "@oslojs/encoding"; +// import { generateRandomString } from "@oslojs/crypto/random"; +// import { constantTimeEqual } from "@oslojs/crypto/subtle"; +// import { scrypt } from "./scrypt/index"; + +// import type { RandomReader } from "@oslojs/crypto/random"; + +// async function generateScryptKey( +// data: string, +// salt: string, +// blockSize = 16, +// ): Promise { +// const encodedData = new TextEncoder().encode(data); +// const encodedSalt = new TextEncoder().encode(salt); +// const keyUint8Array = await scrypt(encodedData, encodedSalt, { +// N: 16384, +// r: blockSize, +// p: 1, +// dkLen: 64, +// }); +// return new Uint8Array(keyUint8Array); +// } + +// const random: RandomReader = { +// read(bytes: Uint8Array): void { +// crypto.getRandomValues(bytes); +// }, +// }; + +// export function generateId(length: number): string { +// const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; +// return generateRandomString(random, alphabet, length); +// } + +// export function generateIdFromEntropySize(size: number): string { +// const buffer = crypto.getRandomValues(new Uint8Array(size)); +// return encodeBase32LowerCaseNoPadding(buffer); +// } + +// export class Scrypt implements PasswordHashingAlgorithm { +// async hash(password: string): Promise { +// const salt = encodeHexLowerCase(crypto.getRandomValues(new Uint8Array(16))); +// const key = await generateScryptKey(password.normalize("NFKC"), salt); +// return `${salt}:${encodeHexLowerCase(key)}`; +// } +// async verify(hash: string, password: string): Promise { +// const parts = hash.split(":"); +// if (parts.length !== 2) return false; + +// const [salt, key] = parts; +// const targetKey = await generateScryptKey(password.normalize("NFKC"), salt); +// return constantTimeEqual(targetKey, decodeHex(key)); +// } +// } + +// export class LegacyScrypt implements PasswordHashingAlgorithm { +// async hash(password: string): Promise { +// const salt = encodeHexLowerCase(crypto.getRandomValues(new Uint8Array(16))); +// const key = await generateScryptKey(password.normalize("NFKC"), salt); +// return `s2:${salt}:${encodeHexLowerCase(key)}`; +// } +// async verify(hash: string, password: string): Promise { +// const parts = hash.split(":"); +// if (parts.length === 2) { +// const [salt, key] = parts; +// const targetKey = await generateScryptKey( +// password.normalize("NFKC"), +// salt, +// 8, +// ); +// const result = constantTimeEqual(targetKey, decodeHex(key)); +// return result; +// } +// if (parts.length !== 3) return false; +// const [version, salt, key] = parts; +// if (version === "s2") { +// const targetKey = await generateScryptKey( +// password.normalize("NFKC"), +// salt, +// ); +// return constantTimeEqual(targetKey, decodeHex(key)); +// } +// return false; +// } +// } + +// export interface PasswordHashingAlgorithm { +// hash(password: string): Promise; +// verify(hash: string, password: string): Promise; +// } diff --git a/packages/server/src/lib/scrypt/index.ts b/packages/server/src/lib/scrypt/index.ts new file mode 100644 index 000000000..8337712ea --- /dev/null +++ b/packages/server/src/lib/scrypt/index.ts @@ -0,0 +1 @@ +// diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bb49174f4..09f7885b4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -558,6 +558,12 @@ importers: '@octokit/auth-app': specifier: ^6.0.4 version: 6.1.1 + '@oslojs/crypto': + specifier: 1.0.1 + version: 1.0.1 + '@oslojs/encoding': + specifier: 1.1.0 + version: 1.1.0 '@react-email/components': specifier: ^0.0.21 version: 0.0.21(@types/react@18.3.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -2164,6 +2170,18 @@ packages: '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@oslojs/asn1@1.0.0': + resolution: {integrity: sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==} + + '@oslojs/binary@1.0.0': + resolution: {integrity: sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==} + + '@oslojs/crypto@1.0.1': + resolution: {integrity: sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==} + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + '@peculiar/asn1-android@2.3.15': resolution: {integrity: sha512-8U2TIj59cRlSXTX2d0mzUKP7whfWGFMzTeC3qPgAbccXFrPNZLaDhpNEdG5U2QZ/tBv/IHlCJ8s+KYXpJeop6w==} @@ -8507,6 +8525,19 @@ snapshots: '@one-ini/wasm@0.1.1': {} + '@oslojs/asn1@1.0.0': + dependencies: + '@oslojs/binary': 1.0.0 + + '@oslojs/binary@1.0.0': {} + + '@oslojs/crypto@1.0.1': + dependencies: + '@oslojs/asn1': 1.0.0 + '@oslojs/binary': 1.0.0 + + '@oslojs/encoding@1.1.0': {} + '@peculiar/asn1-android@2.3.15': dependencies: '@peculiar/asn1-schema': 2.3.15 From bc901bcb255e655f6e8481672c09d170a322b333 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 13 Feb 2025 02:36:08 -0600 Subject: [PATCH 16/89] refactor: update --- apps/dokploy/drizzle/0067_migrate-data.sql | 4 ++-- apps/dokploy/migrate.ts | 4 ++-- apps/dokploy/pages/index.tsx | 4 ++-- packages/server/src/auth/auth.ts | 2 +- packages/server/src/lib/auth.ts | 16 ++++++++++------ 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/apps/dokploy/drizzle/0067_migrate-data.sql b/apps/dokploy/drizzle/0067_migrate-data.sql index b5cefd7b7..2057bd965 100644 --- a/apps/dokploy/drizzle/0067_migrate-data.sql +++ b/apps/dokploy/drizzle/0067_migrate-data.sql @@ -72,7 +72,7 @@ inserted_accounts AS ( SELECT gen_random_uuid(), gen_random_uuid(), - 'credentials', + 'credential', a."adminId", auth.password, COALESCE(auth."is2FAEnabled", false), @@ -166,7 +166,7 @@ inserted_member_accounts AS ( SELECT gen_random_uuid(), gen_random_uuid(), - 'credentials', + 'credential', u."userId", auth.password, COALESCE(auth."is2FAEnabled", false), diff --git a/apps/dokploy/migrate.ts b/apps/dokploy/migrate.ts index 8a8e0dcbe..d56006f18 100644 --- a/apps/dokploy/migrate.ts +++ b/apps/dokploy/migrate.ts @@ -54,7 +54,7 @@ await db .then((user) => user[0]); await db.insert(schema.account).values({ - providerId: "credentials", + providerId: "credential", userId: user?.id || "", password: admin.auth.password, is2FAEnabled: admin.auth.is2FAEnabled || false, @@ -101,7 +101,7 @@ await db .then((userTemp) => userTemp[0]); await db.insert(schema.account).values({ - providerId: "credentials", + providerId: "credential", userId: member?.userId || "", password: member.auth.password, is2FAEnabled: member.auth.is2FAEnabled || false, diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 210160843..4c53f4797 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -69,8 +69,8 @@ export default function Home({ IS_CLOUD }: Props) { const router = useRouter(); const form = useForm({ defaultValues: { - email: "user5@yopmail.com", - password: "Password1234", + email: "", + password: "", }, resolver: zodResolver(loginSchema), }); diff --git a/packages/server/src/auth/auth.ts b/packages/server/src/auth/auth.ts index 7dc26c95f..09372fa5b 100644 --- a/packages/server/src/auth/auth.ts +++ b/packages/server/src/auth/auth.ts @@ -16,7 +16,7 @@ export const lucia = new Lucia(adapter, { secure: false, }, }, - + sessionExpiresIn: new TimeSpan(1, "d"), getUserAttributes: (attributes) => { return { diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 9555e9b6c..2844d1d17 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -1,23 +1,28 @@ import type { IncomingMessage } from "node:http"; +import * as bcrypt from "bcrypt"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; -import { admin, createAuthMiddleware, organization } from "better-auth/plugins"; +import { createAuthMiddleware, organization } from "better-auth/plugins"; import { eq } from "drizzle-orm"; import { db } from "../db"; import * as schema from "../db/schema"; -import { Scrypt } from "lucia"; -const scrypt = new Scrypt(); export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", schema: schema, }), + emailAndPassword: { enabled: true, + password: { - hash: scrypt.hash, - verify: scrypt.verify, + async hash(password) { + return bcrypt.hashSync(password, 10); + }, + async verify({ hash, password }) { + return bcrypt.compareSync(password, hash); + }, }, }, hooks: { @@ -35,7 +40,6 @@ export const auth = betterAuth({ }, user: { modelName: "users_temp", - additionalFields: {}, }, plugins: [organization()], }); From 5c24281f720578df8ab26c4113c6057ee61835a8 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 13 Feb 2025 02:45:33 -0600 Subject: [PATCH 17/89] refactor: return correct information --- apps/dokploy/server/api/routers/auth.ts | 1 - packages/server/src/lib/auth.ts | 7 +++++++ packages/server/src/services/auth.ts | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index b6b915f69..c1c2e0a75 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -169,7 +169,6 @@ export const authRouter = createTRPCRouter({ }), get: protectedProcedure.query(async ({ ctx }) => { - console.log(ctx.user); const auth = await findAuthById(ctx.user.id); return auth; }), diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 2844d1d17..878313ae5 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -40,6 +40,11 @@ export const auth = betterAuth({ }, user: { modelName: "users_temp", + additionalFields: { + role: { + type: "string", + }, + }, }, plugins: [organization()], }); @@ -51,6 +56,8 @@ export const validateRequest = async (request: IncomingMessage) => { }), }); + console.log(session); + if (!session?.session || !session.user) { return { session: null, diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts index 787ceedb8..8781f4f19 100644 --- a/packages/server/src/services/auth.ts +++ b/packages/server/src/services/auth.ts @@ -100,8 +100,8 @@ export const findAuthByEmail = async (email: string) => { }; export const findAuthById = async (authId: string) => { - const result = await db.query.user.findFirst({ - where: eq(user.id, authId), + const result = await db.query.users_temp.findFirst({ + where: eq(users_temp.id, authId), columns: { createdAt: false, updatedAt: false, From ca217affe66d860381100417b286615189e90d38 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Fri, 14 Feb 2025 02:18:53 -0600 Subject: [PATCH 18/89] feat: update references --- .../dashboard/projects/handle-project.tsx | 24 +---- apps/dokploy/pages/index.tsx | 18 ++-- apps/dokploy/server/api/routers/admin.ts | 100 +++++++++--------- .../dokploy/server/api/routers/application.ts | 44 ++++---- apps/dokploy/server/api/routers/auth.ts | 1 - apps/dokploy/server/api/routers/bitbucket.ts | 16 +-- .../dokploy/server/api/routers/certificate.ts | 8 +- apps/dokploy/server/api/routers/compose.ts | 32 +++--- apps/dokploy/server/api/routers/deployment.ts | 6 +- .../dokploy/server/api/routers/destination.ts | 14 +-- apps/dokploy/server/api/routers/domain.ts | 24 ++--- .../server/api/routers/git-provider.ts | 4 +- apps/dokploy/server/api/routers/github.ts | 14 +-- apps/dokploy/server/api/routers/gitlab.ts | 16 +-- apps/dokploy/server/api/routers/mariadb.ts | 22 ++-- apps/dokploy/server/api/routers/mongo.ts | 24 ++--- apps/dokploy/server/api/routers/mysql.ts | 24 ++--- .../server/api/routers/notification.ts | 54 +++++----- apps/dokploy/server/api/routers/postgres.ts | 24 ++--- .../server/api/routers/preview-deployment.ts | 6 +- apps/dokploy/server/api/routers/project.ts | 8 +- apps/dokploy/server/api/routers/redirects.ts | 8 +- apps/dokploy/server/api/routers/redis.ts | 22 ++-- apps/dokploy/server/api/routers/registry.ts | 12 +-- apps/dokploy/server/api/routers/security.ts | 8 +- apps/dokploy/server/api/routers/server.ts | 41 ++++--- apps/dokploy/server/api/routers/settings.ts | 1 - apps/dokploy/server/api/routers/ssh-key.ts | 11 +- apps/dokploy/server/api/routers/stripe.ts | 31 +++--- apps/dokploy/server/api/trpc.ts | 4 +- packages/server/src/db/schema/account.ts | 33 ++++++ packages/server/src/db/schema/bitbucket.ts | 2 +- packages/server/src/db/schema/notification.ts | 11 +- packages/server/src/db/schema/user.ts | 10 +- packages/server/src/lib/auth.ts | 18 +++- packages/server/src/services/admin.ts | 44 ++++---- packages/server/src/services/bitbucket.ts | 8 +- packages/server/src/services/github.ts | 4 +- packages/server/src/services/notification.ts | 30 +++--- packages/server/src/services/registry.ts | 8 +- packages/server/src/services/server.ts | 8 +- 41 files changed, 416 insertions(+), 381 deletions(-) diff --git a/apps/dokploy/components/dashboard/projects/handle-project.tsx b/apps/dokploy/components/dashboard/projects/handle-project.tsx index 5b0777716..fb2cbf67a 100644 --- a/apps/dokploy/components/dashboard/projects/handle-project.tsx +++ b/apps/dokploy/components/dashboard/projects/handle-project.tsx @@ -123,26 +123,10 @@ export const HandleProject = ({ projectId }: Props) => { Update ) : ( - <> - - - + )} diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 4c53f4797..0fecc209c 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -60,17 +60,18 @@ interface Props { IS_CLOUD: boolean; } export default function Home({ IS_CLOUD }: Props) { + const [isLoading, setIsLoading] = useState(false); + const [isError, setIsError] = useState(false); + const [error, setError] = useState(null); const [temp, setTemp] = useState({ is2FAEnabled: false, authId: "", }); - const { mutateAsync, isLoading, error, isError } = - api.auth.login.useMutation(); const router = useRouter(); const form = useForm({ defaultValues: { - email: "", - password: "", + email: "siumauricio@hotmail.com", + password: "Password123", }, resolver: zodResolver(loginSchema), }); @@ -80,6 +81,7 @@ export default function Home({ IS_CLOUD }: Props) { }, [form, form.reset, form.formState.isSubmitSuccessful]); const onSubmit = async (values: Login) => { + setIsLoading(true); const { data, error } = await authClient.signIn.email({ email: values.email, password: values.password, @@ -92,15 +94,17 @@ export default function Home({ IS_CLOUD }: Props) { toast.success("Successfully signed in", { duration: 2000, }); - // router.push("/dashboard/projects"); + router.push("/dashboard/projects"); // } } else { + setIsError(true); + setError(error.message ?? "Error to signup"); toast.error("Error to sign up", { description: error.message, }); } - console.log(data, error); + setIsLoading(false); // await mutateAsync({ // email: values.email.toLowerCase(), // password: values.password, @@ -136,7 +140,7 @@ export default function Home({ IS_CLOUD }: Props) {
{isError && ( - {error?.message} + {error} )} diff --git a/apps/dokploy/server/api/routers/admin.ts b/apps/dokploy/server/api/routers/admin.ts index 6a4764f56..0b232f6da 100644 --- a/apps/dokploy/server/api/routers/admin.ts +++ b/apps/dokploy/server/api/routers/admin.ts @@ -6,18 +6,15 @@ import { apiRemoveUser, apiUpdateAdmin, apiUpdateWebServerMonitoring, - user, } from "@/server/db/schema"; import { IS_CLOUD, createInvitation, - findAdminById, findUserByAuthId, findUserById, getUserByToken, - removeUserByAuthId, + removeUserById, setupWebMonitoring, - updateAdmin, updateAdminById, } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; @@ -32,7 +29,7 @@ import { export const adminRouter = createTRPCRouter({ one: adminProcedure.query(async ({ ctx }) => { - const { sshPrivateKey, ...rest } = await findAdminById(ctx.user.adminId); + const { sshPrivateKey, ...rest } = await findUserById(ctx.user.id); return { haveSSH: !!sshPrivateKey, ...rest, @@ -47,15 +44,15 @@ export const adminRouter = createTRPCRouter({ message: "You are not allowed to update this admin", }); } - const { authId } = await findAdminById(ctx.user.adminId); + const { id } = await findUserById(ctx.user.id); // @ts-ignore - return updateAdmin(authId, input); + return updateAdmin(id, input); }), createUserInvitation: adminProcedure .input(apiCreateUserInvitation) .mutation(async ({ input, ctx }) => { try { - await createInvitation(input, ctx.user.adminId); + await createInvitation(input, ctx.user.id); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -69,15 +66,16 @@ export const adminRouter = createTRPCRouter({ .input(apiRemoveUser) .mutation(async ({ input, ctx }) => { try { - const user = await findUserByAuthId(input.authId); + const user = await findUserById(input.id); - if (user.adminId !== ctx.user.adminId) { + if (user.id !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to delete this user", }); } - return await removeUserByAuthId(input.authId); + + return await removeUserById(input.id); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -95,20 +93,20 @@ export const adminRouter = createTRPCRouter({ .input(apiAssignPermissions) .mutation(async ({ input, ctx }) => { try { - const user = await findUserById(input.userId); + const user = await findUserById(input.id); - if (user.adminId !== ctx.user.adminId) { + if (user.id !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to assign permissions", }); } - await db - .update(users) - .set({ - ...input, - }) - .where(eq(users.userId, input.userId)); + // await db + // .update(users) + // .set({ + // ...input, + // }) + // .where(eq(users.userId, input.userId)); } catch (error) { throw error; } @@ -124,50 +122,50 @@ export const adminRouter = createTRPCRouter({ message: "Feature disabled on cloud", }); } - const admin = await findAdminById(ctx.user.adminId); - if (admin.adminId !== ctx.user.adminId) { + const user = await findUserById(ctx.user.ownerId); + if (user.id !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to setup this server", }); } - await updateAdminById(admin.adminId, { - metricsConfig: { - server: { - type: "Dokploy", - refreshRate: input.metricsConfig.server.refreshRate, - port: input.metricsConfig.server.port, - token: input.metricsConfig.server.token, - cronJob: input.metricsConfig.server.cronJob, - urlCallback: input.metricsConfig.server.urlCallback, - retentionDays: input.metricsConfig.server.retentionDays, - thresholds: { - cpu: input.metricsConfig.server.thresholds.cpu, - memory: input.metricsConfig.server.thresholds.memory, - }, - }, - containers: { - refreshRate: input.metricsConfig.containers.refreshRate, - services: { - include: input.metricsConfig.containers.services.include || [], - exclude: input.metricsConfig.containers.services.exclude || [], - }, - }, - }, - }); - const currentServer = await setupWebMonitoring(admin.adminId); - return currentServer; + // await updateAdminById(admin.adminId, { + // metricsConfig: { + // server: { + // type: "Dokploy", + // refreshRate: input.metricsConfig.server.refreshRate, + // port: input.metricsConfig.server.port, + // token: input.metricsConfig.server.token, + // cronJob: input.metricsConfig.server.cronJob, + // urlCallback: input.metricsConfig.server.urlCallback, + // retentionDays: input.metricsConfig.server.retentionDays, + // thresholds: { + // cpu: input.metricsConfig.server.thresholds.cpu, + // memory: input.metricsConfig.server.thresholds.memory, + // }, + // }, + // containers: { + // refreshRate: input.metricsConfig.containers.refreshRate, + // services: { + // include: input.metricsConfig.containers.services.include || [], + // exclude: input.metricsConfig.containers.services.exclude || [], + // }, + // }, + // }, + // }); + // const currentServer = await setupWebMonitoring(admin.adminId); + // return currentServer; } catch (error) { throw error; } }), getMetricsToken: protectedProcedure.query(async ({ ctx }) => { - const admin = await findAdminById(ctx.user.adminId); + const user = await findUserById(ctx.user.ownerId); return { - serverIp: admin.serverIp, - enabledFeatures: admin.enablePaidFeatures, - metricsConfig: admin?.metricsConfig, + serverIp: user.serverIp, + enabledFeatures: user.enablePaidFeatures, + metricsConfig: user?.metricsConfig, }; }), diff --git a/apps/dokploy/server/api/routers/application.ts b/apps/dokploy/server/api/routers/application.ts index 13b7c80df..d07caa435 100644 --- a/apps/dokploy/server/api/routers/application.ts +++ b/apps/dokploy/server/api/routers/application.ts @@ -72,7 +72,7 @@ export const applicationRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.adminId !== ctx.user.adminId) { + if (project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -106,7 +106,7 @@ export const applicationRouter = createTRPCRouter({ ); } const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -119,7 +119,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiReloadApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this application", @@ -153,7 +153,7 @@ export const applicationRouter = createTRPCRouter({ } const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this application", @@ -194,7 +194,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const service = await findApplicationById(input.applicationId); - if (service.project.adminId !== ctx.user.adminId) { + if (service.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this application", @@ -214,7 +214,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const service = await findApplicationById(input.applicationId); - if (service.project.adminId !== ctx.user.adminId) { + if (service.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this application", @@ -235,7 +235,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to redeploy this application", @@ -268,7 +268,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariables) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", @@ -284,7 +284,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveBuildType) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this build type", @@ -305,7 +305,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveGithubProvider) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this github provider", @@ -327,7 +327,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveGitlabProvider) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this gitlab provider", @@ -351,7 +351,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveBitbucketProvider) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this bitbucket provider", @@ -373,7 +373,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveDockerProvider) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this docker provider", @@ -394,7 +394,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveGitProvider) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this git provider", @@ -415,7 +415,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to mark this application as running", @@ -427,7 +427,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiUpdateApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this application", @@ -451,7 +451,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to refresh this application", @@ -466,7 +466,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this application", @@ -500,7 +500,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to clean this application", @@ -513,7 +513,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .query(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to read this application", @@ -548,7 +548,7 @@ export const applicationRouter = createTRPCRouter({ const app = await findApplicationById(input.applicationId as string); - if (app.project.adminId !== ctx.user.adminId) { + if (app.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this application", @@ -590,7 +590,7 @@ export const applicationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this application", diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index c1c2e0a75..cc88f2c34 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -21,7 +21,6 @@ import { lucia, luciaToken, removeAdminByAuthId, - removeUserByAuthId, sendDiscordNotification, sendEmailNotification, updateAuthById, diff --git a/apps/dokploy/server/api/routers/bitbucket.ts b/apps/dokploy/server/api/routers/bitbucket.ts index c66716d30..75513a805 100644 --- a/apps/dokploy/server/api/routers/bitbucket.ts +++ b/apps/dokploy/server/api/routers/bitbucket.ts @@ -23,7 +23,7 @@ export const bitbucketRouter = createTRPCRouter({ .input(apiCreateBitbucket) .mutation(async ({ input, ctx }) => { try { - return await createBitbucket(input, ctx.user.adminId); + return await createBitbucket(input, ctx.user.ownerId); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -38,7 +38,7 @@ export const bitbucketRouter = createTRPCRouter({ const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( IS_CLOUD && - bitbucketProvider.gitProvider.adminId !== ctx.user.adminId + bitbucketProvider.gitProvider.userId !== ctx.user.ownerId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -61,7 +61,7 @@ export const bitbucketRouter = createTRPCRouter({ if (IS_CLOUD) { // TODO: mAyBe a rEfaCtoR 🤫 result = result.filter( - (provider) => provider.gitProvider.adminId === ctx.user.adminId, + (provider) => provider.gitProvider.userId === ctx.user.ownerId, ); } return result; @@ -73,7 +73,7 @@ export const bitbucketRouter = createTRPCRouter({ const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( IS_CLOUD && - bitbucketProvider.gitProvider.adminId !== ctx.user.adminId + bitbucketProvider.gitProvider.userId !== ctx.user.ownerId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -91,7 +91,7 @@ export const bitbucketRouter = createTRPCRouter({ ); if ( IS_CLOUD && - bitbucketProvider.gitProvider.adminId !== ctx.user.adminId + bitbucketProvider.gitProvider.userId !== ctx.user.ownerId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -108,7 +108,7 @@ export const bitbucketRouter = createTRPCRouter({ const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( IS_CLOUD && - bitbucketProvider.gitProvider.adminId !== ctx.user.adminId + bitbucketProvider.gitProvider.userId !== ctx.user.ownerId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -132,7 +132,7 @@ export const bitbucketRouter = createTRPCRouter({ const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( IS_CLOUD && - bitbucketProvider.gitProvider.adminId !== ctx.user.adminId + bitbucketProvider.gitProvider.userId !== ctx.user.ownerId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -142,7 +142,7 @@ export const bitbucketRouter = createTRPCRouter({ } return await updateBitbucket(input.bitbucketId, { ...input, - adminId: ctx.user.adminId, + userId: ctx.user.ownerId, }); }), }); diff --git a/apps/dokploy/server/api/routers/certificate.ts b/apps/dokploy/server/api/routers/certificate.ts index 0f8d6fd94..b1c6f5c2d 100644 --- a/apps/dokploy/server/api/routers/certificate.ts +++ b/apps/dokploy/server/api/routers/certificate.ts @@ -25,14 +25,14 @@ export const certificateRouter = createTRPCRouter({ message: "Please set a server to create a certificate", }); } - return await createCertificate(input, ctx.user.adminId); + return await createCertificate(input, ctx.user.ownerId); }), one: adminProcedure .input(apiFindCertificate) .query(async ({ input, ctx }) => { const certificates = await findCertificateById(input.certificateId); - if (IS_CLOUD && certificates.adminId !== ctx.user.adminId) { + if (IS_CLOUD && certificates.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this certificate", @@ -44,7 +44,7 @@ export const certificateRouter = createTRPCRouter({ .input(apiFindCertificate) .mutation(async ({ input, ctx }) => { const certificates = await findCertificateById(input.certificateId); - if (IS_CLOUD && certificates.adminId !== ctx.user.adminId) { + if (IS_CLOUD && certificates.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to delete this certificate", @@ -56,7 +56,7 @@ export const certificateRouter = createTRPCRouter({ all: adminProcedure.query(async ({ ctx }) => { return await db.query.certificates.findMany({ // TODO: Remove this line when the cloud version is ready - ...(IS_CLOUD && { where: eq(certificates.adminId, ctx.user.adminId) }), + ...(IS_CLOUD && { where: eq(certificates.userId, ctx.user.ownerId) }), }); }), }); diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index 463d0398c..5d5c11731 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -71,7 +71,7 @@ export const composeRouter = createTRPCRouter({ }); } const project = await findProjectById(input.projectId); - if (project.adminId !== ctx.user.adminId) { + if (project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -97,7 +97,7 @@ export const composeRouter = createTRPCRouter({ } const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -110,7 +110,7 @@ export const composeRouter = createTRPCRouter({ .input(apiUpdateCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this compose", @@ -126,7 +126,7 @@ export const composeRouter = createTRPCRouter({ } const composeResult = await findComposeById(input.composeId); - if (composeResult.project.adminId !== ctx.user.adminId) { + if (composeResult.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this compose", @@ -157,7 +157,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to clean this compose", @@ -170,7 +170,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFetchServices) .query(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to load this compose", @@ -184,7 +184,7 @@ export const composeRouter = createTRPCRouter({ try { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to fetch this compose", @@ -209,7 +209,7 @@ export const composeRouter = createTRPCRouter({ .input(apiRandomizeCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to randomize this compose", @@ -221,7 +221,7 @@ export const composeRouter = createTRPCRouter({ .input(apiRandomizeCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to randomize this compose", @@ -236,7 +236,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .query(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to get this compose", @@ -254,7 +254,7 @@ export const composeRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this compose", @@ -287,7 +287,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to redeploy this compose", @@ -319,7 +319,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this compose", @@ -333,7 +333,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this compose", @@ -348,7 +348,7 @@ export const composeRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to get this compose", @@ -361,7 +361,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to refresh this compose", diff --git a/apps/dokploy/server/api/routers/deployment.ts b/apps/dokploy/server/api/routers/deployment.ts index bf981c6d9..b9daaf0e7 100644 --- a/apps/dokploy/server/api/routers/deployment.ts +++ b/apps/dokploy/server/api/routers/deployment.ts @@ -19,7 +19,7 @@ export const deploymentRouter = createTRPCRouter({ .input(apiFindAllByApplication) .query(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -32,7 +32,7 @@ export const deploymentRouter = createTRPCRouter({ .input(apiFindAllByCompose) .query(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -44,7 +44,7 @@ export const deploymentRouter = createTRPCRouter({ .input(apiFindAllByServer) .query(async ({ input, ctx }) => { const server = await findServerById(input.serverId); - if (server.adminId !== ctx.user.adminId) { + if (server.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this server", diff --git a/apps/dokploy/server/api/routers/destination.ts b/apps/dokploy/server/api/routers/destination.ts index d13928be8..49edadf5e 100644 --- a/apps/dokploy/server/api/routers/destination.ts +++ b/apps/dokploy/server/api/routers/destination.ts @@ -28,7 +28,7 @@ export const destinationRouter = createTRPCRouter({ .input(apiCreateDestination) .mutation(async ({ input, ctx }) => { try { - return await createDestintation(input, ctx.user.adminId); + return await createDestintation(input, ctx.user.ownerId); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -84,7 +84,7 @@ export const destinationRouter = createTRPCRouter({ .input(apiFindOneDestination) .query(async ({ input, ctx }) => { const destination = await findDestinationById(input.destinationId); - if (destination.adminId !== ctx.user.adminId) { + if (destination.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this destination", @@ -94,7 +94,7 @@ export const destinationRouter = createTRPCRouter({ }), all: protectedProcedure.query(async ({ ctx }) => { return await db.query.destinations.findMany({ - where: eq(destinations.adminId, ctx.user.adminId), + where: eq(destinations.userId, ctx.user.ownerId), }); }), remove: adminProcedure @@ -103,7 +103,7 @@ export const destinationRouter = createTRPCRouter({ try { const destination = await findDestinationById(input.destinationId); - if (destination.adminId !== ctx.user.adminId) { + if (destination.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to delete this destination", @@ -111,7 +111,7 @@ export const destinationRouter = createTRPCRouter({ } return await removeDestinationById( input.destinationId, - ctx.user.adminId, + ctx.user.ownerId, ); } catch (error) { throw error; @@ -122,7 +122,7 @@ export const destinationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const destination = await findDestinationById(input.destinationId); - if (destination.adminId !== ctx.user.adminId) { + if (destination.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to update this destination", @@ -130,7 +130,7 @@ export const destinationRouter = createTRPCRouter({ } return await updateDestinationById(input.destinationId, { ...input, - adminId: ctx.user.adminId, + userId: ctx.user.ownerId, }); } catch (error) { throw error; diff --git a/apps/dokploy/server/api/routers/domain.ts b/apps/dokploy/server/api/routers/domain.ts index f122cf86f..526a156bb 100644 --- a/apps/dokploy/server/api/routers/domain.ts +++ b/apps/dokploy/server/api/routers/domain.ts @@ -30,7 +30,7 @@ export const domainRouter = createTRPCRouter({ try { if (input.domainType === "compose" && input.composeId) { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -38,7 +38,7 @@ export const domainRouter = createTRPCRouter({ } } else if (input.domainType === "application" && input.applicationId) { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -58,7 +58,7 @@ export const domainRouter = createTRPCRouter({ .input(apiFindOneApplication) .query(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -70,7 +70,7 @@ export const domainRouter = createTRPCRouter({ .input(apiFindCompose) .query(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -83,7 +83,7 @@ export const domainRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { return generateTraefikMeDomain( input.appName, - ctx.user.adminId, + ctx.user.ownerId, input.serverId, ); }), @@ -95,7 +95,7 @@ export const domainRouter = createTRPCRouter({ if (currentDomain.applicationId) { const newApp = await findApplicationById(currentDomain.applicationId); - if (newApp.project.adminId !== ctx.user.adminId) { + if (newApp.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -103,7 +103,7 @@ export const domainRouter = createTRPCRouter({ } } else if (currentDomain.composeId) { const newCompose = await findComposeById(currentDomain.composeId); - if (newCompose.project.adminId !== ctx.user.adminId) { + if (newCompose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -114,7 +114,7 @@ export const domainRouter = createTRPCRouter({ currentDomain.previewDeploymentId, ); if ( - newPreviewDeployment.application.project.adminId !== ctx.user.adminId + newPreviewDeployment.application.project.userId !== ctx.user.ownerId ) { throw new TRPCError({ code: "UNAUTHORIZED", @@ -143,7 +143,7 @@ export const domainRouter = createTRPCRouter({ const domain = await findDomainById(input.domainId); if (domain.applicationId) { const application = await findApplicationById(domain.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -151,7 +151,7 @@ export const domainRouter = createTRPCRouter({ } } else if (domain.composeId) { const compose = await findComposeById(domain.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -166,7 +166,7 @@ export const domainRouter = createTRPCRouter({ const domain = await findDomainById(input.domainId); if (domain.applicationId) { const application = await findApplicationById(domain.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -174,7 +174,7 @@ export const domainRouter = createTRPCRouter({ } } else if (domain.composeId) { const compose = await findComposeById(domain.composeId); - if (compose.project.adminId !== ctx.user.adminId) { + if (compose.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", diff --git a/apps/dokploy/server/api/routers/git-provider.ts b/apps/dokploy/server/api/routers/git-provider.ts index abd933923..83e71dd81 100644 --- a/apps/dokploy/server/api/routers/git-provider.ts +++ b/apps/dokploy/server/api/routers/git-provider.ts @@ -18,7 +18,7 @@ export const gitProviderRouter = createTRPCRouter({ github: true, }, orderBy: desc(gitProvider.createdAt), - ...(IS_CLOUD && { where: eq(gitProvider.adminId, ctx.user.adminId) }), + ...(IS_CLOUD && { where: eq(gitProvider.userId, ctx.user.ownerId) }), //TODO: Remove this line when the cloud version is ready }); }), @@ -28,7 +28,7 @@ export const gitProviderRouter = createTRPCRouter({ try { const gitProvider = await findGitProviderById(input.gitProviderId); - if (IS_CLOUD && gitProvider.adminId !== ctx.user.adminId) { + if (IS_CLOUD && gitProvider.userId !== ctx.user.ownerId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", diff --git a/apps/dokploy/server/api/routers/github.ts b/apps/dokploy/server/api/routers/github.ts index 562225778..62c21805d 100644 --- a/apps/dokploy/server/api/routers/github.ts +++ b/apps/dokploy/server/api/routers/github.ts @@ -20,7 +20,7 @@ export const githubRouter = createTRPCRouter({ .input(apiFindOneGithub) .query(async ({ input, ctx }) => { const githubProvider = await findGithubById(input.githubId); - if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) { + if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -33,7 +33,7 @@ export const githubRouter = createTRPCRouter({ .input(apiFindOneGithub) .query(async ({ input, ctx }) => { const githubProvider = await findGithubById(input.githubId); - if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) { + if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -46,7 +46,7 @@ export const githubRouter = createTRPCRouter({ .input(apiFindGithubBranches) .query(async ({ input, ctx }) => { const githubProvider = await findGithubById(input.githubId || ""); - if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) { + if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -65,7 +65,7 @@ export const githubRouter = createTRPCRouter({ if (IS_CLOUD) { // TODO: mAyBe a rEfaCtoR 🤫 result = result.filter( - (provider) => provider.gitProvider.adminId === ctx.user.adminId, + (provider) => provider.gitProvider.userId === ctx.user.ownerId, ); } @@ -90,7 +90,7 @@ export const githubRouter = createTRPCRouter({ const githubProvider = await findGithubById(input.githubId); if ( IS_CLOUD && - githubProvider.gitProvider.adminId !== ctx.user.adminId + githubProvider.gitProvider.userId !== ctx.user.ownerId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -111,7 +111,7 @@ export const githubRouter = createTRPCRouter({ .input(apiUpdateGithub) .mutation(async ({ input, ctx }) => { const githubProvider = await findGithubById(input.githubId); - if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) { + if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -120,7 +120,7 @@ export const githubRouter = createTRPCRouter({ } await updateGitProvider(input.gitProviderId, { name: input.name, - adminId: ctx.user.adminId, + userId: ctx.user.ownerId, }); }), }); diff --git a/apps/dokploy/server/api/routers/gitlab.ts b/apps/dokploy/server/api/routers/gitlab.ts index 6d35f4a28..d3ba5a44a 100644 --- a/apps/dokploy/server/api/routers/gitlab.ts +++ b/apps/dokploy/server/api/routers/gitlab.ts @@ -26,7 +26,7 @@ export const gitlabRouter = createTRPCRouter({ .input(apiCreateGitlab) .mutation(async ({ input, ctx }) => { try { - return await createGitlab(input, ctx.user.adminId); + return await createGitlab(input, ctx.user.ownerId); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -39,7 +39,7 @@ export const gitlabRouter = createTRPCRouter({ .input(apiFindOneGitlab) .query(async ({ input, ctx }) => { const gitlabProvider = await findGitlabById(input.gitlabId); - if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) { + if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -58,7 +58,7 @@ export const gitlabRouter = createTRPCRouter({ if (IS_CLOUD) { // TODO: mAyBe a rEfaCtoR 🤫 result = result.filter( - (provider) => provider.gitProvider.adminId === ctx.user.adminId, + (provider) => provider.gitProvider.userId === ctx.user.ownerId, ); } const filtered = result @@ -78,7 +78,7 @@ export const gitlabRouter = createTRPCRouter({ .input(apiFindOneGitlab) .query(async ({ input, ctx }) => { const gitlabProvider = await findGitlabById(input.gitlabId); - if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) { + if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -92,7 +92,7 @@ export const gitlabRouter = createTRPCRouter({ .input(apiFindGitlabBranches) .query(async ({ input, ctx }) => { const gitlabProvider = await findGitlabById(input.gitlabId || ""); - if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) { + if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -108,7 +108,7 @@ export const gitlabRouter = createTRPCRouter({ const gitlabProvider = await findGitlabById(input.gitlabId || ""); if ( IS_CLOUD && - gitlabProvider.gitProvider.adminId !== ctx.user.adminId + gitlabProvider.gitProvider.userId !== ctx.user.ownerId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -130,7 +130,7 @@ export const gitlabRouter = createTRPCRouter({ .input(apiUpdateGitlab) .mutation(async ({ input, ctx }) => { const gitlabProvider = await findGitlabById(input.gitlabId); - if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) { + if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -140,7 +140,7 @@ export const gitlabRouter = createTRPCRouter({ if (input.name) { await updateGitProvider(input.gitProviderId, { name: input.name, - adminId: ctx.user.adminId, + userId: ctx.user.ownerId, }); await updateGitlab(input.gitlabId, { diff --git a/apps/dokploy/server/api/routers/mariadb.ts b/apps/dokploy/server/api/routers/mariadb.ts index 6e85d274b..283455fae 100644 --- a/apps/dokploy/server/api/routers/mariadb.ts +++ b/apps/dokploy/server/api/routers/mariadb.ts @@ -49,7 +49,7 @@ export const mariadbRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.adminId !== ctx.user.adminId) { + if (project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -83,7 +83,7 @@ export const mariadbRouter = createTRPCRouter({ await checkServiceAccess(ctx.user.authId, input.mariadbId, "access"); } const mariadb = await findMariadbById(input.mariadbId); - if (mariadb.project.adminId !== ctx.user.adminId) { + if (mariadb.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this Mariadb", @@ -96,7 +96,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiFindOneMariaDB) .mutation(async ({ input, ctx }) => { const service = await findMariadbById(input.mariadbId); - if (service.project.adminId !== ctx.user.adminId) { + if (service.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this Mariadb", @@ -133,7 +133,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiSaveExternalPortMariaDB) .mutation(async ({ input, ctx }) => { const mongo = await findMariadbById(input.mariadbId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this external port", @@ -149,7 +149,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiDeployMariaDB) .mutation(async ({ input, ctx }) => { const mariadb = await findMariadbById(input.mariadbId); - if (mariadb.project.adminId !== ctx.user.adminId) { + if (mariadb.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Mariadb", @@ -170,7 +170,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiDeployMariaDB) .subscription(async ({ input, ctx }) => { const mariadb = await findMariadbById(input.mariadbId); - if (mariadb.project.adminId !== ctx.user.adminId) { + if (mariadb.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Mariadb", @@ -187,7 +187,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiChangeMariaDBStatus) .mutation(async ({ input, ctx }) => { const mongo = await findMariadbById(input.mariadbId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to change this Mariadb status", @@ -206,7 +206,7 @@ export const mariadbRouter = createTRPCRouter({ } const mongo = await findMariadbById(input.mariadbId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this Mariadb", @@ -232,7 +232,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariablesMariaDB) .mutation(async ({ input, ctx }) => { const mariadb = await findMariadbById(input.mariadbId); - if (mariadb.project.adminId !== ctx.user.adminId) { + if (mariadb.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", @@ -255,7 +255,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiResetMariadb) .mutation(async ({ input, ctx }) => { const mariadb = await findMariadbById(input.mariadbId); - if (mariadb.project.adminId !== ctx.user.adminId) { + if (mariadb.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this Mariadb", @@ -285,7 +285,7 @@ export const mariadbRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const { mariadbId, ...rest } = input; const mariadb = await findMariadbById(mariadbId); - if (mariadb.project.adminId !== ctx.user.adminId) { + if (mariadb.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this Mariadb", diff --git a/apps/dokploy/server/api/routers/mongo.ts b/apps/dokploy/server/api/routers/mongo.ts index 2bca3ec5a..94a012724 100644 --- a/apps/dokploy/server/api/routers/mongo.ts +++ b/apps/dokploy/server/api/routers/mongo.ts @@ -48,7 +48,7 @@ export const mongoRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.adminId !== ctx.user.adminId) { + if (project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -87,7 +87,7 @@ export const mongoRouter = createTRPCRouter({ } const mongo = await findMongoById(input.mongoId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this mongo", @@ -101,7 +101,7 @@ export const mongoRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const service = await findMongoById(input.mongoId); - if (service.project.adminId !== ctx.user.adminId) { + if (service.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this mongo", @@ -124,7 +124,7 @@ export const mongoRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this mongo", @@ -146,7 +146,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiSaveExternalPortMongo) .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this external port", @@ -162,7 +162,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiDeployMongo) .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this mongo", @@ -182,7 +182,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiDeployMongo) .subscription(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this mongo", @@ -199,7 +199,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiChangeMongoStatus) .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to change this mongo status", @@ -214,7 +214,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiResetMongo) .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this mongo", @@ -248,7 +248,7 @@ export const mongoRouter = createTRPCRouter({ const mongo = await findMongoById(input.mongoId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this mongo", @@ -274,7 +274,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariablesMongo) .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", @@ -298,7 +298,7 @@ export const mongoRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const { mongoId, ...rest } = input; const mongo = await findMongoById(mongoId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this mongo", diff --git a/apps/dokploy/server/api/routers/mysql.ts b/apps/dokploy/server/api/routers/mysql.ts index 7ebf4623a..efea72076 100644 --- a/apps/dokploy/server/api/routers/mysql.ts +++ b/apps/dokploy/server/api/routers/mysql.ts @@ -50,7 +50,7 @@ export const mysqlRouter = createTRPCRouter({ } 1; const project = await findProjectById(input.projectId); - if (project.adminId !== ctx.user.adminId) { + if (project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -89,7 +89,7 @@ export const mysqlRouter = createTRPCRouter({ await checkServiceAccess(ctx.user.authId, input.mysqlId, "access"); } const mysql = await findMySqlById(input.mysqlId); - if (mysql.project.adminId !== ctx.user.adminId) { + if (mysql.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this MySQL", @@ -102,7 +102,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiFindOneMySql) .mutation(async ({ input, ctx }) => { const service = await findMySqlById(input.mysqlId); - if (service.project.adminId !== ctx.user.adminId) { + if (service.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this MySQL", @@ -124,7 +124,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiFindOneMySql) .mutation(async ({ input, ctx }) => { const mongo = await findMySqlById(input.mysqlId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this MySQL", @@ -145,7 +145,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiSaveExternalPortMySql) .mutation(async ({ input, ctx }) => { const mongo = await findMySqlById(input.mysqlId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this external port", @@ -161,7 +161,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiDeployMySql) .mutation(async ({ input, ctx }) => { const mysql = await findMySqlById(input.mysqlId); - if (mysql.project.adminId !== ctx.user.adminId) { + if (mysql.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this MySQL", @@ -181,7 +181,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiDeployMySql) .subscription(async ({ input, ctx }) => { const mysql = await findMySqlById(input.mysqlId); - if (mysql.project.adminId !== ctx.user.adminId) { + if (mysql.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this MySQL", @@ -198,7 +198,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiChangeMySqlStatus) .mutation(async ({ input, ctx }) => { const mongo = await findMySqlById(input.mysqlId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to change this MySQL status", @@ -213,7 +213,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiResetMysql) .mutation(async ({ input, ctx }) => { const mysql = await findMySqlById(input.mysqlId); - if (mysql.project.adminId !== ctx.user.adminId) { + if (mysql.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this MySQL", @@ -244,7 +244,7 @@ export const mysqlRouter = createTRPCRouter({ await checkServiceAccess(ctx.user.authId, input.mysqlId, "delete"); } const mongo = await findMySqlById(input.mysqlId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this MySQL", @@ -270,7 +270,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariablesMySql) .mutation(async ({ input, ctx }) => { const mysql = await findMySqlById(input.mysqlId); - if (mysql.project.adminId !== ctx.user.adminId) { + if (mysql.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", @@ -294,7 +294,7 @@ export const mysqlRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const { mysqlId, ...rest } = input; const mysql = await findMySqlById(mysqlId); - if (mysql.project.adminId !== ctx.user.adminId) { + if (mysql.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this MySQL", diff --git a/apps/dokploy/server/api/routers/notification.ts b/apps/dokploy/server/api/routers/notification.ts index ea3469731..6c2b469d9 100644 --- a/apps/dokploy/server/api/routers/notification.ts +++ b/apps/dokploy/server/api/routers/notification.ts @@ -6,7 +6,6 @@ import { } from "@/server/api/trpc"; import { db } from "@/server/db"; import { - admins, apiCreateDiscord, apiCreateEmail, apiCreateGotify, @@ -25,6 +24,7 @@ import { apiUpdateTelegram, notifications, server, + users_temp, } from "@/server/db/schema"; import { IS_CLOUD, @@ -57,7 +57,7 @@ export const notificationRouter = createTRPCRouter({ .input(apiCreateSlack) .mutation(async ({ input, ctx }) => { try { - return await createSlackNotification(input, ctx.user.adminId); + return await createSlackNotification(input, ctx.user.ownerId); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -71,7 +71,7 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { + if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -80,7 +80,7 @@ export const notificationRouter = createTRPCRouter({ } return await updateSlackNotification({ ...input, - adminId: ctx.user.adminId, + userId: ctx.user.ownerId, }); } catch (error) { throw error; @@ -107,7 +107,7 @@ export const notificationRouter = createTRPCRouter({ .input(apiCreateTelegram) .mutation(async ({ input, ctx }) => { try { - return await createTelegramNotification(input, ctx.user.adminId); + return await createTelegramNotification(input, ctx.user.ownerId); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -122,7 +122,7 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { + if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -131,7 +131,7 @@ export const notificationRouter = createTRPCRouter({ } return await updateTelegramNotification({ ...input, - adminId: ctx.user.adminId, + userId: ctx.user.ownerId, }); } catch (error) { throw new TRPCError({ @@ -159,7 +159,7 @@ export const notificationRouter = createTRPCRouter({ .input(apiCreateDiscord) .mutation(async ({ input, ctx }) => { try { - return await createDiscordNotification(input, ctx.user.adminId); + return await createDiscordNotification(input, ctx.user.ownerId); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -174,7 +174,7 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { + if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -183,7 +183,7 @@ export const notificationRouter = createTRPCRouter({ } return await updateDiscordNotification({ ...input, - adminId: ctx.user.adminId, + userId: ctx.user.ownerId, }); } catch (error) { throw new TRPCError({ @@ -220,7 +220,7 @@ export const notificationRouter = createTRPCRouter({ .input(apiCreateEmail) .mutation(async ({ input, ctx }) => { try { - return await createEmailNotification(input, ctx.user.adminId); + return await createEmailNotification(input, ctx.user.ownerId); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -234,7 +234,7 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { + if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -243,7 +243,7 @@ export const notificationRouter = createTRPCRouter({ } return await updateEmailNotification({ ...input, - adminId: ctx.user.adminId, + userId: ctx.user.ownerId, }); } catch (error) { throw new TRPCError({ @@ -276,7 +276,7 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { + if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -295,7 +295,7 @@ export const notificationRouter = createTRPCRouter({ .input(apiFindOneNotification) .query(async ({ input, ctx }) => { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { + if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -314,7 +314,7 @@ export const notificationRouter = createTRPCRouter({ gotify: true, }, orderBy: desc(notifications.createdAt), - ...(IS_CLOUD && { where: eq(notifications.adminId, ctx.user.adminId) }), + ...(IS_CLOUD && { where: eq(notifications.userId, ctx.user.ownerId) }), // TODO: Remove this line when the cloud version is ready }); }), @@ -332,24 +332,24 @@ export const notificationRouter = createTRPCRouter({ ) .mutation(async ({ input }) => { try { - let adminId = ""; + let userId = ""; let ServerName = ""; if (input.ServerType === "Dokploy") { const result = await db .select() - .from(admins) + .from(users_temp) .where( - sql`${admins.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`, + sql`${users_temp.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`, ); - if (!result?.[0]?.adminId) { + if (!result?.[0]?.id) { throw new TRPCError({ code: "BAD_REQUEST", message: "Token not found", }); } - adminId = result?.[0]?.adminId; + userId = result?.[0]?.id; ServerName = "Dokploy"; } else { const result = await db @@ -359,18 +359,18 @@ export const notificationRouter = createTRPCRouter({ sql`${server.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`, ); - if (!result?.[0]?.adminId) { + if (!result?.[0]?.userId) { throw new TRPCError({ code: "BAD_REQUEST", message: "Token not found", }); } - adminId = result?.[0]?.adminId; + userId = result?.[0]?.userId; ServerName = "Remote"; } - await sendServerThresholdNotifications(adminId, { + await sendServerThresholdNotifications(userId, { ...input, ServerName, }); @@ -386,7 +386,7 @@ export const notificationRouter = createTRPCRouter({ .input(apiCreateGotify) .mutation(async ({ input, ctx }) => { try { - return await createGotifyNotification(input, ctx.user.adminId); + return await createGotifyNotification(input, ctx.user.ownerId); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -400,7 +400,7 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.adminId !== ctx.user.adminId) { + if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this notification", @@ -408,7 +408,7 @@ export const notificationRouter = createTRPCRouter({ } return await updateGotifyNotification({ ...input, - adminId: ctx.user.adminId, + userId: ctx.user.ownerId, }); } catch (error) { throw error; diff --git a/apps/dokploy/server/api/routers/postgres.ts b/apps/dokploy/server/api/routers/postgres.ts index 92603a613..a7d0de399 100644 --- a/apps/dokploy/server/api/routers/postgres.ts +++ b/apps/dokploy/server/api/routers/postgres.ts @@ -56,7 +56,7 @@ export const postgresRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.adminId !== ctx.user.adminId) { + if (project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -95,7 +95,7 @@ export const postgresRouter = createTRPCRouter({ } const postgres = await findPostgresById(input.postgresId); - if (postgres.project.adminId !== ctx.user.adminId) { + if (postgres.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this Postgres", @@ -109,7 +109,7 @@ export const postgresRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const service = await findPostgresById(input.postgresId); - if (service.project.adminId !== ctx.user.adminId) { + if (service.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this Postgres", @@ -131,7 +131,7 @@ export const postgresRouter = createTRPCRouter({ .input(apiFindOnePostgres) .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.adminId !== ctx.user.adminId) { + if (postgres.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this Postgres", @@ -153,7 +153,7 @@ export const postgresRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.adminId !== ctx.user.adminId) { + if (postgres.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this external port", @@ -169,7 +169,7 @@ export const postgresRouter = createTRPCRouter({ .input(apiDeployPostgres) .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.adminId !== ctx.user.adminId) { + if (postgres.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Postgres", @@ -190,7 +190,7 @@ export const postgresRouter = createTRPCRouter({ .input(apiDeployPostgres) .subscription(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.adminId !== ctx.user.adminId) { + if (postgres.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Postgres", @@ -207,7 +207,7 @@ export const postgresRouter = createTRPCRouter({ .input(apiChangePostgresStatus) .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.adminId !== ctx.user.adminId) { + if (postgres.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to change this Postgres status", @@ -226,7 +226,7 @@ export const postgresRouter = createTRPCRouter({ } const postgres = await findPostgresById(input.postgresId); - if (postgres.project.adminId !== ctx.user.adminId) { + if (postgres.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this Postgres", @@ -249,7 +249,7 @@ export const postgresRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariablesPostgres) .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.adminId !== ctx.user.adminId) { + if (postgres.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", @@ -272,7 +272,7 @@ export const postgresRouter = createTRPCRouter({ .input(apiResetPostgres) .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.adminId !== ctx.user.adminId) { + if (postgres.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this Postgres", @@ -302,7 +302,7 @@ export const postgresRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const { postgresId, ...rest } = input; const postgres = await findPostgresById(postgresId); - if (postgres.project.adminId !== ctx.user.adminId) { + if (postgres.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this Postgres", diff --git a/apps/dokploy/server/api/routers/preview-deployment.ts b/apps/dokploy/server/api/routers/preview-deployment.ts index 74b8461ae..482bb3505 100644 --- a/apps/dokploy/server/api/routers/preview-deployment.ts +++ b/apps/dokploy/server/api/routers/preview-deployment.ts @@ -14,7 +14,7 @@ export const previewDeploymentRouter = createTRPCRouter({ .input(apiFindAllByApplication) .query(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -28,7 +28,7 @@ export const previewDeploymentRouter = createTRPCRouter({ const previewDeployment = await findPreviewDeploymentById( input.previewDeploymentId, ); - if (previewDeployment.application.project.adminId !== ctx.user.adminId) { + if (previewDeployment.application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this preview deployment", @@ -43,7 +43,7 @@ export const previewDeploymentRouter = createTRPCRouter({ const previewDeployment = await findPreviewDeploymentById( input.previewDeploymentId, ); - if (previewDeployment.application.project.adminId !== ctx.user.adminId) { + if (previewDeployment.application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this preview deployment", diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index c2852ff6b..1d2d20360 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -75,7 +75,7 @@ export const projectRouter = createTRPCRouter({ const project = await db.query.projects.findFirst({ where: and( eq(projects.projectId, input.projectId), - eq(projects.adminId, ctx.user.adminId), + eq(projects.userId, ctx.user.ownerId), ), with: { compose: { @@ -115,7 +115,7 @@ export const projectRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.adminId !== ctx.user.adminId) { + if (project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -207,7 +207,7 @@ export const projectRouter = createTRPCRouter({ await checkProjectAccess(ctx.user.authId, "delete"); } const currentProject = await findProjectById(input.projectId); - if (currentProject.adminId !== ctx.user.adminId) { + if (currentProject.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this project", @@ -225,7 +225,7 @@ export const projectRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const currentProject = await findProjectById(input.projectId); - if (currentProject.adminId !== ctx.user.adminId) { + if (currentProject.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this project", diff --git a/apps/dokploy/server/api/routers/redirects.ts b/apps/dokploy/server/api/routers/redirects.ts index bcd7962a6..1a8ba4cfa 100644 --- a/apps/dokploy/server/api/routers/redirects.ts +++ b/apps/dokploy/server/api/routers/redirects.ts @@ -18,7 +18,7 @@ export const redirectsRouter = createTRPCRouter({ .input(apiCreateRedirect) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -31,7 +31,7 @@ export const redirectsRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const redirect = await findRedirectById(input.redirectId); const application = await findApplicationById(redirect.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -44,7 +44,7 @@ export const redirectsRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const redirect = await findRedirectById(input.redirectId); const application = await findApplicationById(redirect.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -57,7 +57,7 @@ export const redirectsRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const redirect = await findRedirectById(input.redirectId); const application = await findApplicationById(redirect.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", diff --git a/apps/dokploy/server/api/routers/redis.ts b/apps/dokploy/server/api/routers/redis.ts index 967fb51a2..af1d4234a 100644 --- a/apps/dokploy/server/api/routers/redis.ts +++ b/apps/dokploy/server/api/routers/redis.ts @@ -48,7 +48,7 @@ export const redisRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.adminId !== ctx.user.adminId) { + if (project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -80,7 +80,7 @@ export const redisRouter = createTRPCRouter({ } const redis = await findRedisById(input.redisId); - if (redis.project.adminId !== ctx.user.adminId) { + if (redis.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this Redis", @@ -93,7 +93,7 @@ export const redisRouter = createTRPCRouter({ .input(apiFindOneRedis) .mutation(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.adminId !== ctx.user.adminId) { + if (redis.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this Redis", @@ -115,7 +115,7 @@ export const redisRouter = createTRPCRouter({ .input(apiResetRedis) .mutation(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.adminId !== ctx.user.adminId) { + if (redis.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this Redis", @@ -145,7 +145,7 @@ export const redisRouter = createTRPCRouter({ .input(apiFindOneRedis) .mutation(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.adminId !== ctx.user.adminId) { + if (redis.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this Redis", @@ -166,7 +166,7 @@ export const redisRouter = createTRPCRouter({ .input(apiSaveExternalPortRedis) .mutation(async ({ input, ctx }) => { const mongo = await findRedisById(input.redisId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this external port", @@ -182,7 +182,7 @@ export const redisRouter = createTRPCRouter({ .input(apiDeployRedis) .mutation(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.adminId !== ctx.user.adminId) { + if (redis.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Redis", @@ -202,7 +202,7 @@ export const redisRouter = createTRPCRouter({ .input(apiDeployRedis) .subscription(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.adminId !== ctx.user.adminId) { + if (redis.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Redis", @@ -218,7 +218,7 @@ export const redisRouter = createTRPCRouter({ .input(apiChangeRedisStatus) .mutation(async ({ input, ctx }) => { const mongo = await findRedisById(input.redisId); - if (mongo.project.adminId !== ctx.user.adminId) { + if (mongo.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to change this Redis status", @@ -238,7 +238,7 @@ export const redisRouter = createTRPCRouter({ const redis = await findRedisById(input.redisId); - if (redis.project.adminId !== ctx.user.adminId) { + if (redis.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this Redis", @@ -261,7 +261,7 @@ export const redisRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariablesRedis) .mutation(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.adminId !== ctx.user.adminId) { + if (redis.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", diff --git a/apps/dokploy/server/api/routers/registry.ts b/apps/dokploy/server/api/routers/registry.ts index f66ed4aea..76df5cd65 100644 --- a/apps/dokploy/server/api/routers/registry.ts +++ b/apps/dokploy/server/api/routers/registry.ts @@ -10,7 +10,7 @@ import { createRegistry, execAsync, execAsyncRemote, - findAllRegistryByAdminId, + findAllRegistryByUserId, findRegistryById, removeRegistry, updateRegistry, @@ -22,13 +22,13 @@ export const registryRouter = createTRPCRouter({ create: adminProcedure .input(apiCreateRegistry) .mutation(async ({ ctx, input }) => { - return await createRegistry(input, ctx.user.adminId); + return await createRegistry(input, ctx.user.ownerId); }), remove: adminProcedure .input(apiRemoveRegistry) .mutation(async ({ ctx, input }) => { const registry = await findRegistryById(input.registryId); - if (registry.adminId !== ctx.user.adminId) { + if (registry.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to delete this registry", @@ -41,7 +41,7 @@ export const registryRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const { registryId, ...rest } = input; const registry = await findRegistryById(registryId); - if (registry.adminId !== ctx.user.adminId) { + if (registry.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to update this registry", @@ -61,13 +61,13 @@ export const registryRouter = createTRPCRouter({ return true; }), all: protectedProcedure.query(async ({ ctx }) => { - return await findAllRegistryByAdminId(ctx.user.adminId); + return await findAllRegistryByUserId(ctx.user.ownerId); }), one: adminProcedure .input(apiFindOneRegistry) .query(async ({ input, ctx }) => { const registry = await findRegistryById(input.registryId); - if (registry.adminId !== ctx.user.adminId) { + if (registry.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this registry", diff --git a/apps/dokploy/server/api/routers/security.ts b/apps/dokploy/server/api/routers/security.ts index 5318a2939..ca4892d26 100644 --- a/apps/dokploy/server/api/routers/security.ts +++ b/apps/dokploy/server/api/routers/security.ts @@ -18,7 +18,7 @@ export const securityRouter = createTRPCRouter({ .input(apiCreateSecurity) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -31,7 +31,7 @@ export const securityRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const security = await findSecurityById(input.securityId); const application = await findApplicationById(security.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -44,7 +44,7 @@ export const securityRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const security = await findSecurityById(input.securityId); const application = await findApplicationById(security.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -57,7 +57,7 @@ export const securityRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const security = await findSecurityById(input.securityId); const application = await findApplicationById(security.applicationId); - if (application.project.adminId !== ctx.user.adminId) { + if (application.project.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts index 0094b6756..8e63d7e66 100644 --- a/apps/dokploy/server/api/routers/server.ts +++ b/apps/dokploy/server/api/routers/server.ts @@ -21,9 +21,9 @@ import { createServer, defaultCommand, deleteServer, - findAdminById, findServerById, - findServersByAdminId, + findServersByUserId, + findUserById, getPublicIpWithFallback, haveActiveServices, removeDeploymentsByServerId, @@ -42,15 +42,15 @@ export const serverRouter = createTRPCRouter({ .input(apiCreateServer) .mutation(async ({ ctx, input }) => { try { - const admin = await findAdminById(ctx.user.adminId); - const servers = await findServersByAdminId(admin.adminId); - if (IS_CLOUD && servers.length >= admin.serversQuantity) { + const user = await findUserById(ctx.user.ownerId); + const servers = await findServersByUserId(user.id); + if (IS_CLOUD && servers.length >= user.serversQuantity) { throw new TRPCError({ code: "BAD_REQUEST", message: "You cannot create more servers", }); } - const project = await createServer(input, ctx.user.adminId); + const project = await createServer(input, ctx.user.ownerId); return project; } catch (error) { throw new TRPCError({ @@ -65,7 +65,7 @@ export const serverRouter = createTRPCRouter({ .input(apiFindOneServer) .query(async ({ input, ctx }) => { const server = await findServerById(input.serverId); - if (server.adminId !== ctx.user.adminId) { + if (server.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this server", @@ -93,7 +93,7 @@ export const serverRouter = createTRPCRouter({ .leftJoin(mongo, eq(mongo.serverId, server.serverId)) .leftJoin(mysql, eq(mysql.serverId, server.serverId)) .leftJoin(postgres, eq(postgres.serverId, server.serverId)) - .where(eq(server.adminId, ctx.user.adminId)) + .where(eq(server.userId, ctx.user.ownerId)) .orderBy(desc(server.createdAt)) .groupBy(server.serverId); @@ -105,10 +105,10 @@ export const serverRouter = createTRPCRouter({ where: IS_CLOUD ? and( isNotNull(server.sshKeyId), - eq(server.adminId, ctx.user.adminId), + eq(server.userId, ctx.user.ownerId), eq(server.serverStatus, "active"), ) - : and(isNotNull(server.sshKeyId), eq(server.adminId, ctx.user.adminId)), + : and(isNotNull(server.sshKeyId), eq(server.userId, ctx.user.ownerId)), }); return result; }), @@ -117,7 +117,7 @@ export const serverRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.adminId !== ctx.user.adminId) { + if (server.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to setup this server", @@ -142,7 +142,7 @@ export const serverRouter = createTRPCRouter({ .subscription(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.adminId !== ctx.user.adminId) { + if (server.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to setup this server", @@ -162,7 +162,7 @@ export const serverRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.adminId !== ctx.user.adminId) { + if (server.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to validate this server", @@ -204,7 +204,7 @@ export const serverRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.adminId !== ctx.user.adminId) { + if (server.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to validate this server", @@ -254,7 +254,7 @@ export const serverRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.adminId !== ctx.user.adminId) { + if (server.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to setup this server", @@ -296,7 +296,7 @@ export const serverRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.adminId !== ctx.user.adminId) { + if (server.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this server", @@ -315,12 +315,9 @@ export const serverRouter = createTRPCRouter({ await deleteServer(input.serverId); if (IS_CLOUD) { - const admin = await findAdminById(ctx.user.adminId); + const admin = await findUserById(ctx.user.ownerId); - await updateServersBasedOnQuantity( - admin.adminId, - admin.serversQuantity, - ); + await updateServersBasedOnQuantity(admin.id, admin.serversQuantity); } return currentServer; @@ -333,7 +330,7 @@ export const serverRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.adminId !== ctx.user.adminId) { + if (server.userId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this server", diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index 116de6ad8..6dda93835 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -47,7 +47,6 @@ import { startServiceRemote, stopService, stopServiceRemote, - updateAdmin, updateLetsEncryptEmail, updateServerById, updateServerTraefik, diff --git a/apps/dokploy/server/api/routers/ssh-key.ts b/apps/dokploy/server/api/routers/ssh-key.ts index fe2f24f91..4beb0bae8 100644 --- a/apps/dokploy/server/api/routers/ssh-key.ts +++ b/apps/dokploy/server/api/routers/ssh-key.ts @@ -24,9 +24,10 @@ export const sshRouter = createTRPCRouter({ .input(apiCreateSshKey) .mutation(async ({ input, ctx }) => { try { + console.log(ctx.user.ownerId); await createSshKey({ ...input, - adminId: ctx.user.adminId, + userId: ctx.user.ownerId, }); } catch (error) { throw new TRPCError({ @@ -41,7 +42,7 @@ export const sshRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const sshKey = await findSSHKeyById(input.sshKeyId); - if (IS_CLOUD && sshKey.adminId !== ctx.user.adminId) { + if (IS_CLOUD && sshKey.userId !== ctx.user.ownerId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -59,7 +60,7 @@ export const sshRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const sshKey = await findSSHKeyById(input.sshKeyId); - if (IS_CLOUD && sshKey.adminId !== ctx.user.adminId) { + if (IS_CLOUD && sshKey.userId !== ctx.user.ownerId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -70,7 +71,7 @@ export const sshRouter = createTRPCRouter({ }), all: protectedProcedure.query(async ({ ctx }) => { return await db.query.sshKeys.findMany({ - ...(IS_CLOUD && { where: eq(sshKeys.adminId, ctx.user.adminId) }), + ...(IS_CLOUD && { where: eq(sshKeys.userId, ctx.user.ownerId) }), orderBy: desc(sshKeys.createdAt), }); // TODO: Remove this line when the cloud version is ready @@ -85,7 +86,7 @@ export const sshRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const sshKey = await findSSHKeyById(input.sshKeyId); - if (IS_CLOUD && sshKey.adminId !== ctx.user.adminId) { + if (IS_CLOUD && sshKey.userId !== ctx.user.ownerId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", diff --git a/apps/dokploy/server/api/routers/stripe.ts b/apps/dokploy/server/api/routers/stripe.ts index 7a8a537c1..91fa44fd6 100644 --- a/apps/dokploy/server/api/routers/stripe.ts +++ b/apps/dokploy/server/api/routers/stripe.ts @@ -1,9 +1,9 @@ import { WEBSITE_URL, getStripeItems } from "@/server/utils/stripe"; import { IS_CLOUD, - findAdminById, - findServersByAdminId, - updateAdmin, + findServersByUserId, + findUserById, + updateUser, } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; import Stripe from "stripe"; @@ -12,8 +12,8 @@ import { adminProcedure, createTRPCRouter } from "../trpc"; export const stripeRouter = createTRPCRouter({ getProducts: adminProcedure.query(async ({ ctx }) => { - const admin = await findAdminById(ctx.user.adminId); - const stripeCustomerId = admin.stripeCustomerId; + const user = await findUserById(ctx.user.ownerId); + const stripeCustomerId = user.stripeCustomerId; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: "2024-09-30.acacia", @@ -56,15 +56,15 @@ export const stripeRouter = createTRPCRouter({ }); const items = getStripeItems(input.serverQuantity, input.isAnnual); - const admin = await findAdminById(ctx.user.adminId); + const user = await findUserById(ctx.user.ownerId); - let stripeCustomerId = admin.stripeCustomerId; + let stripeCustomerId = user.stripeCustomerId; if (stripeCustomerId) { const customer = await stripe.customers.retrieve(stripeCustomerId); if (customer.deleted) { - await updateAdmin(admin.authId, { + await updateUser(user.id, { stripeCustomerId: null, }); stripeCustomerId = null; @@ -78,7 +78,7 @@ export const stripeRouter = createTRPCRouter({ customer: stripeCustomerId, }), metadata: { - adminId: admin.adminId, + ownerId: user.id, }, allow_promotion_codes: true, success_url: `${WEBSITE_URL}/dashboard/settings/servers?success=true`, @@ -89,15 +89,15 @@ export const stripeRouter = createTRPCRouter({ }), createCustomerPortalSession: adminProcedure.mutation( async ({ ctx, input }) => { - const admin = await findAdminById(ctx.user.adminId); + const user = await findUserById(ctx.user.ownerId); - if (!admin.stripeCustomerId) { + if (!user.stripeCustomerId) { throw new TRPCError({ code: "BAD_REQUEST", message: "Stripe Customer ID not found", }); } - const stripeCustomerId = admin.stripeCustomerId; + const stripeCustomerId = user.stripeCustomerId; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: "2024-09-30.acacia", @@ -119,13 +119,14 @@ export const stripeRouter = createTRPCRouter({ ), canCreateMoreServers: adminProcedure.query(async ({ ctx }) => { - const admin = await findAdminById(ctx.user.adminId); - const servers = await findServersByAdminId(admin.adminId); + const user = await findUserById(ctx.user.ownerId); + console.log(user); + // const servers = await findServersByUserId(user.id); if (!IS_CLOUD) { return true; } - return servers.length < admin.serversQuantity; + return servers.length < user.serversQuantity; }), }); diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index 9579407b5..9f373ad3f 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -31,7 +31,7 @@ import { ZodError } from "zod"; */ interface CreateContextOptions { - user: (User & { authId: string; rol: "admin" | "user" }) | null; + user: (User & { rol: "admin" | "user"; ownerId: string }) | null; session: Session | null; req: CreateNextContextOptions["req"]; res: CreateNextContextOptions["res"]; @@ -81,10 +81,10 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { session: session, ...((user && { user: { - authId: "Null", email: user.email, rol: user.role, id: user.id, + ownerId: user.ownerId, }, }) || { user: null, diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 3e81fbf69..e7a263fa0 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -1,6 +1,7 @@ import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { nanoid } from "nanoid"; import { users_temp } from "./user"; +import { relations } from "drizzle-orm"; export const account = pgTable("account", { id: text("id") @@ -29,6 +30,13 @@ export const account = pgTable("account", { confirmationExpiresAt: text("confirmationExpiresAt"), }); +export const accountRelations = relations(account, ({ one }) => ({ + user: one(users_temp, { + fields: [account.userId], + references: [users_temp.id], + }), +})); + export const verification = pgTable("verification", { id: text("id").primaryKey(), identifier: text("identifier").notNull(), @@ -52,6 +60,13 @@ export const organization = pgTable("organization", { .references(() => users_temp.id), }); +export const organizationRelations = relations(organization, ({ one }) => ({ + owner: one(users_temp, { + fields: [organization.ownerId], + references: [users_temp.id], + }), +})); + export const member = pgTable("member", { id: text("id") .primaryKey() @@ -66,6 +81,17 @@ export const member = pgTable("member", { createdAt: timestamp("created_at").notNull(), }); +export const memberRelations = relations(member, ({ one }) => ({ + organization: one(organization, { + fields: [member.organizationId], + references: [organization.id], + }), + user: one(users_temp, { + fields: [member.userId], + references: [users_temp.id], + }), +})); + export const invitation = pgTable("invitation", { id: text("id").primaryKey(), organizationId: text("organization_id") @@ -79,3 +105,10 @@ export const invitation = pgTable("invitation", { .notNull() .references(() => users_temp.id), }); + +export const invitationRelations = relations(invitation, ({ one }) => ({ + organization: one(organization, { + fields: [invitation.organizationId], + references: [organization.id], + }), +})); diff --git a/packages/server/src/db/schema/bitbucket.ts b/packages/server/src/db/schema/bitbucket.ts index 393cb1e7d..b8ecb6682 100644 --- a/packages/server/src/db/schema/bitbucket.ts +++ b/packages/server/src/db/schema/bitbucket.ts @@ -61,5 +61,5 @@ export const apiUpdateBitbucket = createSchema.extend({ name: z.string().min(1), bitbucketUsername: z.string().optional(), bitbucketWorkspaceName: z.string().optional(), - adminId: z.string().optional(), + userId: z.string().optional(), }); diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 462b67109..78596b0d7 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -3,7 +3,6 @@ import { boolean, integer, pgEnum, pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; -import { admins } from "./admin"; import { users_temp } from "./user"; // import { user } from "./user"; @@ -153,7 +152,7 @@ export const apiCreateSlack = notificationsSchema export const apiUpdateSlack = apiCreateSlack.partial().extend({ notificationId: z.string().min(1), slackId: z.string(), - adminId: z.string().optional(), + userId: z.string().optional(), }); export const apiTestSlackConnection = apiCreateSlack.pick({ @@ -180,7 +179,7 @@ export const apiCreateTelegram = notificationsSchema export const apiUpdateTelegram = apiCreateTelegram.partial().extend({ notificationId: z.string().min(1), telegramId: z.string().min(1), - adminId: z.string().optional(), + userId: z.string().optional(), }); export const apiTestTelegramConnection = apiCreateTelegram.pick({ @@ -207,7 +206,7 @@ export const apiCreateDiscord = notificationsSchema export const apiUpdateDiscord = apiCreateDiscord.partial().extend({ notificationId: z.string().min(1), discordId: z.string().min(1), - adminId: z.string().optional(), + userId: z.string().optional(), }); export const apiTestDiscordConnection = apiCreateDiscord @@ -241,7 +240,7 @@ export const apiCreateEmail = notificationsSchema export const apiUpdateEmail = apiCreateEmail.partial().extend({ notificationId: z.string().min(1), emailId: z.string().min(1), - adminId: z.string().optional(), + userId: z.string().optional(), }); export const apiTestEmailConnection = apiCreateEmail.pick({ @@ -273,7 +272,7 @@ export const apiCreateGotify = notificationsSchema export const apiUpdateGotify = apiCreateGotify.partial().extend({ notificationId: z.string().min(1), gotifyId: z.string().min(1), - adminId: z.string().optional(), + userId: z.string().optional(), }); export const apiTestGotifyConnection = apiCreateGotify diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index d754687cd..0a3535137 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -196,8 +196,8 @@ export const usersRelations = relations(users, ({ one }) => ({ // }), })); -const createSchema = createInsertSchema(users, { - userId: z.string().min(1), +const createSchema = createInsertSchema(users_temp, { + id: z.string().min(1), // authId: z.string().min(1), token: z.string().min(1), isRegistered: z.boolean().optional(), @@ -218,7 +218,7 @@ export const apiCreateUserInvitation = createSchema.pick({}).extend({ export const apiRemoveUser = createSchema .pick({ - // authId: true, + id: true, }) .required(); @@ -230,7 +230,7 @@ export const apiFindOneToken = createSchema export const apiAssignPermissions = createSchema .pick({ - userId: true, + id: true, canCreateProjects: true, canCreateServices: true, canDeleteProjects: true, @@ -247,7 +247,7 @@ export const apiAssignPermissions = createSchema export const apiFindOneUser = createSchema .pick({ - userId: true, + id: true, }) .required(); diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 878313ae5..48e11f215 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -44,6 +44,9 @@ export const auth = betterAuth({ role: { type: "string", }, + ownerId: { + type: "string", + }, }, }, plugins: [organization()], @@ -56,7 +59,20 @@ export const validateRequest = async (request: IncomingMessage) => { }), }); - console.log(session); + if (session?.user.role === "user") { + const owner = await db.query.member.findFirst({ + where: eq(schema.member.userId, session.user.id), + with: { + organization: true, + }, + }); + + if (owner) { + session.user.ownerId = owner.organization.ownerId; + } + } else { + session.user.ownerId = session?.user.id; + } if (!session?.session || !session.user) { return { diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index 5155231b0..c4b7650ba 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -11,7 +11,7 @@ import * as bcrypt from "bcrypt"; import { eq } from "drizzle-orm"; import { IS_CLOUD } from "../constants"; -export type Admin = typeof admins.$inferSelect; +export type Admin = typeof users_temp.$inferSelect; export const createInvitation = async ( input: typeof apiCreateUserInvitation._type, adminId: string, @@ -48,33 +48,30 @@ export const createInvitation = async ( }); }; -export const findAdminById = async (adminId: string) => { - const admin = await db.query.admins.findFirst({ - where: eq(admins.adminId, adminId), +export const findUserById = async (userId: string) => { + const user = await db.query.users_temp.findFirst({ + where: eq(users_temp.id, userId), }); - if (!admin) { + if (!user) { throw new TRPCError({ code: "NOT_FOUND", - message: "Admin not found", + message: "User not found", }); } - return admin; + return user; }; -export const updateAdmin = async ( - authId: string, - adminData: Partial, -) => { - const admin = await db - .update(admins) +export const updateUser = async (userId: string, userData: Partial) => { + const user = await db + .update(users_temp) .set({ - ...adminData, + ...userData, }) - .where(eq(admins.authId, authId)) + .where(eq(users_temp.id, userId)) .returning() .then((res) => res[0]); - return admin; + return user; }; export const updateAdminById = async ( @@ -93,6 +90,13 @@ export const updateAdminById = async ( return admin; }; +export const findAdminById = async (userId: string) => { + const admin = await db.query.admins.findFirst({ + where: eq(admins.userId, userId), + }); + return admin; +}; + export const isAdminPresent = async () => { const admin = await db.query.user.findFirst({ where: eq(user.role, "admin"), @@ -154,10 +158,10 @@ export const getUserByToken = async (token: string) => { }; }; -export const removeUserByAuthId = async (authId: string) => { +export const removeUserById = async (userId: string) => { await db - .delete(auth) - .where(eq(auth.id, authId)) + .delete(users_temp) + .where(eq(users_temp.id, userId)) .returning() .then((res) => res[0]); }; @@ -170,7 +174,7 @@ export const removeAdminByAuthId = async (authId: string) => { const users = admin.users; for (const user of users) { - await removeUserByAuthId(user.authId); + await removeUserById(user.id); } // Then delete the auth record which will cascade delete the admin return await db diff --git a/packages/server/src/services/bitbucket.ts b/packages/server/src/services/bitbucket.ts index 218071567..4ce4a7b03 100644 --- a/packages/server/src/services/bitbucket.ts +++ b/packages/server/src/services/bitbucket.ts @@ -12,14 +12,14 @@ export type Bitbucket = typeof bitbucket.$inferSelect; export const createBitbucket = async ( input: typeof apiCreateBitbucket._type, - adminId: string, + userId: string, ) => { return await db.transaction(async (tx) => { const newGitProvider = await tx .insert(gitProvider) .values({ providerType: "bitbucket", - adminId: adminId, + userId: userId, name: input.name, }) .returning() @@ -74,12 +74,12 @@ export const updateBitbucket = async ( .where(eq(bitbucket.bitbucketId, bitbucketId)) .returning(); - if (input.name || input.adminId) { + if (input.name || input.userId) { await tx .update(gitProvider) .set({ name: input.name, - adminId: input.adminId, + userId: input.userId, }) .where(eq(gitProvider.gitProviderId, input.gitProviderId)) .returning(); diff --git a/packages/server/src/services/github.ts b/packages/server/src/services/github.ts index a5d9d8638..b23edf207 100644 --- a/packages/server/src/services/github.ts +++ b/packages/server/src/services/github.ts @@ -12,14 +12,14 @@ import { updatePreviewDeployment } from "./preview-deployment"; export type Github = typeof github.$inferSelect; export const createGithub = async ( input: typeof apiCreateGithub._type, - adminId: string, + userId: string, ) => { return await db.transaction(async (tx) => { const newGitProvider = await tx .insert(gitProvider) .values({ providerType: "github", - adminId: adminId, + userId: userId, name: input.name, }) .returning() diff --git a/packages/server/src/services/notification.ts b/packages/server/src/services/notification.ts index 8b17da367..03f6bd09d 100644 --- a/packages/server/src/services/notification.ts +++ b/packages/server/src/services/notification.ts @@ -24,7 +24,7 @@ export type Notification = typeof notifications.$inferSelect; export const createSlackNotification = async ( input: typeof apiCreateSlack._type, - adminId: string, + userId: string, ) => { await db.transaction(async (tx) => { const newSlack = await tx @@ -54,7 +54,7 @@ export const createSlackNotification = async ( dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, notificationType: "slack", - adminId: adminId, + userId: userId, serverThreshold: input.serverThreshold, }) .returning() @@ -84,7 +84,7 @@ export const updateSlackNotification = async ( databaseBackup: input.databaseBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, - adminId: input.adminId, + userId: input.userId, serverThreshold: input.serverThreshold, }) .where(eq(notifications.notificationId, input.notificationId)) @@ -114,7 +114,7 @@ export const updateSlackNotification = async ( export const createTelegramNotification = async ( input: typeof apiCreateTelegram._type, - adminId: string, + userId: string, ) => { await db.transaction(async (tx) => { const newTelegram = await tx @@ -144,7 +144,7 @@ export const createTelegramNotification = async ( dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, notificationType: "telegram", - adminId: adminId, + userId: userId, serverThreshold: input.serverThreshold, }) .returning() @@ -174,7 +174,7 @@ export const updateTelegramNotification = async ( databaseBackup: input.databaseBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, - adminId: input.adminId, + userId: input.userId, serverThreshold: input.serverThreshold, }) .where(eq(notifications.notificationId, input.notificationId)) @@ -204,7 +204,7 @@ export const updateTelegramNotification = async ( export const createDiscordNotification = async ( input: typeof apiCreateDiscord._type, - adminId: string, + userId: string, ) => { await db.transaction(async (tx) => { const newDiscord = await tx @@ -234,7 +234,7 @@ export const createDiscordNotification = async ( dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, notificationType: "discord", - adminId: adminId, + userId: userId, serverThreshold: input.serverThreshold, }) .returning() @@ -264,7 +264,7 @@ export const updateDiscordNotification = async ( databaseBackup: input.databaseBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, - adminId: input.adminId, + userId: input.userId, serverThreshold: input.serverThreshold, }) .where(eq(notifications.notificationId, input.notificationId)) @@ -294,7 +294,7 @@ export const updateDiscordNotification = async ( export const createEmailNotification = async ( input: typeof apiCreateEmail._type, - adminId: string, + userId: string, ) => { await db.transaction(async (tx) => { const newEmail = await tx @@ -328,7 +328,7 @@ export const createEmailNotification = async ( dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, notificationType: "email", - adminId: adminId, + userId: userId, serverThreshold: input.serverThreshold, }) .returning() @@ -358,7 +358,7 @@ export const updateEmailNotification = async ( databaseBackup: input.databaseBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, - adminId: input.adminId, + userId: input.userId, serverThreshold: input.serverThreshold, }) .where(eq(notifications.notificationId, input.notificationId)) @@ -392,7 +392,7 @@ export const updateEmailNotification = async ( export const createGotifyNotification = async ( input: typeof apiCreateGotify._type, - adminId: string, + userId: string, ) => { await db.transaction(async (tx) => { const newGotify = await tx @@ -424,7 +424,7 @@ export const createGotifyNotification = async ( dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, notificationType: "gotify", - adminId: adminId, + userId: userId, }) .returning() .then((value) => value[0]); @@ -453,7 +453,7 @@ export const updateGotifyNotification = async ( databaseBackup: input.databaseBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, - adminId: input.adminId, + userId: input.userId, }) .where(eq(notifications.notificationId, input.notificationId)) .returning() diff --git a/packages/server/src/services/registry.ts b/packages/server/src/services/registry.ts index 2bcf3a4a4..b92eabdb0 100644 --- a/packages/server/src/services/registry.ts +++ b/packages/server/src/services/registry.ts @@ -12,14 +12,14 @@ export type Registry = typeof registry.$inferSelect; export const createRegistry = async ( input: typeof apiCreateRegistry._type, - adminId: string, + userId: string, ) => { return await db.transaction(async (tx) => { const newRegistry = await tx .insert(registry) .values({ ...input, - adminId: adminId, + userId: userId, }) .returning() .then((value) => value[0]); @@ -135,9 +135,9 @@ export const findRegistryById = async (registryId: string) => { return registryResponse; }; -export const findAllRegistryByAdminId = async (adminId: string) => { +export const findAllRegistryByUserId = async (userId: string) => { const registryResponse = await db.query.registry.findMany({ - where: eq(registry.adminId, adminId), + where: eq(registry.userId, userId), }); return registryResponse; }; diff --git a/packages/server/src/services/server.ts b/packages/server/src/services/server.ts index 081b19fad..6aaa8becc 100644 --- a/packages/server/src/services/server.ts +++ b/packages/server/src/services/server.ts @@ -7,13 +7,13 @@ export type Server = typeof server.$inferSelect; export const createServer = async ( input: typeof apiCreateServer._type, - adminId: string, + userId: string, ) => { const newServer = await db .insert(server) .values({ ...input, - adminId: adminId, + userId: userId, }) .returning() .then((value) => value[0]); @@ -45,9 +45,9 @@ export const findServerById = async (serverId: string) => { return currentServer; }; -export const findServersByAdminId = async (adminId: string) => { +export const findServersByUserId = async (userId: string) => { const servers = await db.query.server.findMany({ - where: eq(server.adminId, adminId), + where: eq(server.userId, userId), orderBy: desc(server.createdAt), }); From b6c29ccf0543d9713dd8a2f543da0e45a0c30799 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Fri, 14 Feb 2025 02:40:11 -0600 Subject: [PATCH 19/89] refactor: update --- apps/dokploy/server/api/routers/admin.ts | 57 ++++++------ .../dokploy/server/api/routers/application.ts | 16 +--- apps/dokploy/server/api/routers/auth.ts | 21 +++-- apps/dokploy/server/api/routers/compose.ts | 15 +-- apps/dokploy/server/api/routers/mariadb.ts | 8 +- apps/dokploy/server/api/routers/mongo.ts | 8 +- apps/dokploy/server/api/routers/mysql.ts | 8 +- apps/dokploy/server/api/routers/postgres.ts | 8 +- apps/dokploy/server/api/routers/project.ts | 18 ++-- apps/dokploy/server/api/routers/redis.ts | 8 +- apps/dokploy/server/api/routers/stripe.ts | 3 +- packages/server/src/db/schema/account.ts | 2 +- packages/server/src/db/schema/user.ts | 13 ++- packages/server/src/services/admin.ts | 3 + packages/server/src/services/auth.ts | 7 +- packages/server/src/services/server.ts | 1 + packages/server/src/services/user.ts | 91 +++++++++---------- packages/server/src/setup/monitoring-setup.ts | 14 +-- 18 files changed, 154 insertions(+), 147 deletions(-) diff --git a/apps/dokploy/server/api/routers/admin.ts b/apps/dokploy/server/api/routers/admin.ts index 0b232f6da..e8467283a 100644 --- a/apps/dokploy/server/api/routers/admin.ts +++ b/apps/dokploy/server/api/routers/admin.ts @@ -16,6 +16,7 @@ import { removeUserById, setupWebMonitoring, updateAdminById, + updateUser, } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; @@ -101,6 +102,9 @@ export const adminRouter = createTRPCRouter({ message: "You are not allowed to assign permissions", }); } + await updateUser(user.id, { + ...input, + }); // await db // .update(users) // .set({ @@ -130,32 +134,33 @@ export const adminRouter = createTRPCRouter({ }); } - // await updateAdminById(admin.adminId, { - // metricsConfig: { - // server: { - // type: "Dokploy", - // refreshRate: input.metricsConfig.server.refreshRate, - // port: input.metricsConfig.server.port, - // token: input.metricsConfig.server.token, - // cronJob: input.metricsConfig.server.cronJob, - // urlCallback: input.metricsConfig.server.urlCallback, - // retentionDays: input.metricsConfig.server.retentionDays, - // thresholds: { - // cpu: input.metricsConfig.server.thresholds.cpu, - // memory: input.metricsConfig.server.thresholds.memory, - // }, - // }, - // containers: { - // refreshRate: input.metricsConfig.containers.refreshRate, - // services: { - // include: input.metricsConfig.containers.services.include || [], - // exclude: input.metricsConfig.containers.services.exclude || [], - // }, - // }, - // }, - // }); - // const currentServer = await setupWebMonitoring(admin.adminId); - // return currentServer; + await updateUser(user.id, { + metricsConfig: { + server: { + type: "Dokploy", + refreshRate: input.metricsConfig.server.refreshRate, + port: input.metricsConfig.server.port, + token: input.metricsConfig.server.token, + cronJob: input.metricsConfig.server.cronJob, + urlCallback: input.metricsConfig.server.urlCallback, + retentionDays: input.metricsConfig.server.retentionDays, + thresholds: { + cpu: input.metricsConfig.server.thresholds.cpu, + memory: input.metricsConfig.server.thresholds.memory, + }, + }, + containers: { + refreshRate: input.metricsConfig.containers.refreshRate, + services: { + include: input.metricsConfig.containers.services.include || [], + exclude: input.metricsConfig.containers.services.exclude || [], + }, + }, + }, + }); + + const currentServer = await setupWebMonitoring(user.id); + return currentServer; } catch (error) { throw error; } diff --git a/apps/dokploy/server/api/routers/application.ts b/apps/dokploy/server/api/routers/application.ts index d07caa435..0f7c1eb67 100644 --- a/apps/dokploy/server/api/routers/application.ts +++ b/apps/dokploy/server/api/routers/application.ts @@ -61,7 +61,7 @@ export const applicationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + await checkServiceAccess(ctx.user.id, input.projectId, "create"); } if (IS_CLOUD && !input.serverId) { @@ -81,7 +81,7 @@ export const applicationRouter = createTRPCRouter({ const newApplication = await createApplication(input); if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, newApplication.applicationId); + await addNewService(ctx.user.id, newApplication.applicationId); } return newApplication; } catch (error: unknown) { @@ -99,11 +99,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .query(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess( - ctx.user.authId, - input.applicationId, - "access", - ); + await checkServiceAccess(ctx.user.id, input.applicationId, "access"); } const application = await findApplicationById(input.applicationId); if (application.project.userId !== ctx.user.ownerId) { @@ -145,11 +141,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess( - ctx.user.authId, - input.applicationId, - "delete", - ); + await checkServiceAccess(ctx.user.id, input.applicationId, "delete"); } const application = await findApplicationById(input.applicationId); diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index cc88f2c34..7f1382b49 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -16,6 +16,7 @@ import { createUser, findAuthByEmail, findAuthById, + findUserById, generate2FASecret, getUserByToken, lucia, @@ -24,6 +25,7 @@ import { sendDiscordNotification, sendEmailNotification, updateAuthById, + updateUser, validateRequest, verify2FA, } from "@dokploy/server"; @@ -252,19 +254,18 @@ export const authRouter = createTRPCRouter({ }), generateToken: protectedProcedure.mutation(async ({ ctx, input }) => { - const auth = await findAuthById(ctx.user.authId); + const auth = await findUserById(ctx.user.id); + console.log(auth); if (auth.token) { await luciaToken.invalidateSession(auth.token); } - const session = await luciaToken.createSession(auth?.id || "", { - expiresIn: 60 * 60 * 24 * 30, - }); - - await updateAuthById(auth.id, { - token: session.id, - }); - + // const session = await luciaToken.createSession(auth?.id || "", { + // expiresIn: 60 * 60 * 24 * 30, + // }); + // await updateUser(auth.id, { + // token: session.id, + // }); return auth; }), verifyToken: protectedProcedure.mutation(async () => { @@ -276,7 +277,7 @@ export const authRouter = createTRPCRouter({ }), generate2FASecret: protectedProcedure.query(async ({ ctx }) => { - return await generate2FASecret(ctx.user.authId); + return await generate2FASecret(ctx.user.id); }), verify2FASetup: protectedProcedure .input(apiVerify2FA) diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index 5d5c11731..b3fbae93a 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -44,6 +44,7 @@ import { findDomainsByComposeId, findProjectById, findServerById, + findUserById, loadServices, randomizeComposeFile, randomizeIsolatedDeploymentComposeFile, @@ -61,7 +62,7 @@ export const composeRouter = createTRPCRouter({ .mutation(async ({ ctx, input }) => { try { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + await checkServiceAccess(ctx.user.id, input.projectId, "create"); } if (IS_CLOUD && !input.serverId) { @@ -80,7 +81,7 @@ export const composeRouter = createTRPCRouter({ const newService = await createCompose(input); if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, newService.composeId); + await addNewService(ctx.user.id, newService.composeId); } return newService; @@ -93,7 +94,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .query(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.composeId, "access"); + await checkServiceAccess(ctx.user.id, input.composeId, "access"); } const compose = await findComposeById(input.composeId); @@ -122,7 +123,7 @@ export const composeRouter = createTRPCRouter({ .input(apiDeleteCompose) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.composeId, "delete"); + await checkServiceAccess(ctx.user.id, input.composeId, "delete"); } const composeResult = await findComposeById(input.composeId); @@ -376,7 +377,7 @@ export const composeRouter = createTRPCRouter({ .input(apiCreateComposeByTemplate) .mutation(async ({ ctx, input }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + await checkServiceAccess(ctx.user.id, input.projectId, "create"); } if (IS_CLOUD && !input.serverId) { @@ -390,7 +391,7 @@ export const composeRouter = createTRPCRouter({ const generate = await loadTemplateModule(input.id as TemplatesKeys); - const admin = await findAdminById(ctx.user.adminId); + const admin = await findUserById(ctx.user.ownerId); let serverIp = admin.serverIp || "127.0.0.1"; const project = await findProjectById(input.projectId); @@ -419,7 +420,7 @@ export const composeRouter = createTRPCRouter({ }); if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, compose.composeId); + await addNewService(ctx.user.id, compose.composeId); } if (mounts && mounts?.length > 0) { diff --git a/apps/dokploy/server/api/routers/mariadb.ts b/apps/dokploy/server/api/routers/mariadb.ts index 283455fae..9305395d3 100644 --- a/apps/dokploy/server/api/routers/mariadb.ts +++ b/apps/dokploy/server/api/routers/mariadb.ts @@ -38,7 +38,7 @@ export const mariadbRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + await checkServiceAccess(ctx.user.id, input.projectId, "create"); } if (IS_CLOUD && !input.serverId) { @@ -57,7 +57,7 @@ export const mariadbRouter = createTRPCRouter({ } const newMariadb = await createMariadb(input); if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, newMariadb.mariadbId); + await addNewService(ctx.user.id, newMariadb.mariadbId); } await createMount({ @@ -80,7 +80,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiFindOneMariaDB) .query(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.mariadbId, "access"); + await checkServiceAccess(ctx.user.id, input.mariadbId, "access"); } const mariadb = await findMariadbById(input.mariadbId); if (mariadb.project.userId !== ctx.user.ownerId) { @@ -202,7 +202,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiFindOneMariaDB) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.mariadbId, "delete"); + await checkServiceAccess(ctx.user.id, input.mariadbId, "delete"); } const mongo = await findMariadbById(input.mariadbId); diff --git a/apps/dokploy/server/api/routers/mongo.ts b/apps/dokploy/server/api/routers/mongo.ts index 94a012724..aed7b4c52 100644 --- a/apps/dokploy/server/api/routers/mongo.ts +++ b/apps/dokploy/server/api/routers/mongo.ts @@ -37,7 +37,7 @@ export const mongoRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + await checkServiceAccess(ctx.user.id, input.projectId, "create"); } if (IS_CLOUD && !input.serverId) { @@ -56,7 +56,7 @@ export const mongoRouter = createTRPCRouter({ } const newMongo = await createMongo(input); if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, newMongo.mongoId); + await addNewService(ctx.user.id, newMongo.mongoId); } await createMount({ @@ -83,7 +83,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiFindOneMongo) .query(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.mongoId, "access"); + await checkServiceAccess(ctx.user.id, input.mongoId, "access"); } const mongo = await findMongoById(input.mongoId); @@ -243,7 +243,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiFindOneMongo) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.mongoId, "delete"); + await checkServiceAccess(ctx.user.id, input.mongoId, "delete"); } const mongo = await findMongoById(input.mongoId); diff --git a/apps/dokploy/server/api/routers/mysql.ts b/apps/dokploy/server/api/routers/mysql.ts index efea72076..e66c30941 100644 --- a/apps/dokploy/server/api/routers/mysql.ts +++ b/apps/dokploy/server/api/routers/mysql.ts @@ -39,7 +39,7 @@ export const mysqlRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + await checkServiceAccess(ctx.user.id, input.projectId, "create"); } if (IS_CLOUD && !input.serverId) { @@ -59,7 +59,7 @@ export const mysqlRouter = createTRPCRouter({ const newMysql = await createMysql(input); if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, newMysql.mysqlId); + await addNewService(ctx.user.id, newMysql.mysqlId); } await createMount({ @@ -86,7 +86,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiFindOneMySql) .query(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.mysqlId, "access"); + await checkServiceAccess(ctx.user.id, input.mysqlId, "access"); } const mysql = await findMySqlById(input.mysqlId); if (mysql.project.userId !== ctx.user.ownerId) { @@ -241,7 +241,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiFindOneMySql) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.mysqlId, "delete"); + await checkServiceAccess(ctx.user.id, input.mysqlId, "delete"); } const mongo = await findMySqlById(input.mysqlId); if (mongo.project.userId !== ctx.user.ownerId) { diff --git a/apps/dokploy/server/api/routers/postgres.ts b/apps/dokploy/server/api/routers/postgres.ts index a7d0de399..0aab4dc65 100644 --- a/apps/dokploy/server/api/routers/postgres.ts +++ b/apps/dokploy/server/api/routers/postgres.ts @@ -45,7 +45,7 @@ export const postgresRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + await checkServiceAccess(ctx.user.id, input.projectId, "create"); } if (IS_CLOUD && !input.serverId) { @@ -64,7 +64,7 @@ export const postgresRouter = createTRPCRouter({ } const newPostgres = await createPostgres(input); if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, newPostgres.postgresId); + await addNewService(ctx.user.id, newPostgres.postgresId); } await createMount({ @@ -91,7 +91,7 @@ export const postgresRouter = createTRPCRouter({ .input(apiFindOnePostgres) .query(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.postgresId, "access"); + await checkServiceAccess(ctx.user.id, input.postgresId, "access"); } const postgres = await findPostgresById(input.postgresId); @@ -222,7 +222,7 @@ export const postgresRouter = createTRPCRouter({ .input(apiFindOnePostgres) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.postgresId, "delete"); + await checkServiceAccess(ctx.user.id, input.postgresId, "delete"); } const postgres = await findPostgresById(input.postgresId); diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index 1d2d20360..d4a30580a 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -25,9 +25,9 @@ import { checkProjectAccess, createProject, deleteProject, - findAdminById, findProjectById, findUserByAuthId, + findUserById, updateProjectById, } from "@dokploy/server"; @@ -37,10 +37,10 @@ export const projectRouter = createTRPCRouter({ .mutation(async ({ ctx, input }) => { try { if (ctx.user.rol === "user") { - await checkProjectAccess(ctx.user.authId, "create"); + await checkProjectAccess(ctx.user.id, "create"); } - const admin = await findAdminById(ctx.user.adminId); + const admin = await findUserById(ctx.user.ownerId); if (admin.serversQuantity === 0 && IS_CLOUD) { throw new TRPCError({ @@ -49,9 +49,9 @@ export const projectRouter = createTRPCRouter({ }); } - const project = await createProject(input, ctx.user.adminId); + const project = await createProject(input, ctx.user.ownerId); if (ctx.user.rol === "user") { - await addNewProject(ctx.user.authId, project.projectId); + await addNewProject(ctx.user.id, project.projectId); } return project; @@ -68,9 +68,9 @@ export const projectRouter = createTRPCRouter({ .input(apiFindOneProject) .query(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - const { accessedServices } = await findUserByAuthId(ctx.user.authId); + const { accessedServices } = await findUserByAuthId(ctx.user.id); - await checkProjectAccess(ctx.user.authId, "access", input.projectId); + await checkProjectAccess(ctx.user.id, "access", input.projectId); const project = await db.query.projects.findFirst({ where: and( @@ -126,7 +126,7 @@ export const projectRouter = createTRPCRouter({ all: protectedProcedure.query(async ({ ctx }) => { // console.log(ctx.user); if (ctx.user.rol === "user") { - const { accessedProjects, accessedServices } = await findUserByAuthId( + const { accessedProjects, accessedServices } = await findUserById( ctx.user.id, ); @@ -204,7 +204,7 @@ export const projectRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "user") { - await checkProjectAccess(ctx.user.authId, "delete"); + await checkProjectAccess(ctx.user.id, "delete"); } const currentProject = await findProjectById(input.projectId); if (currentProject.userId !== ctx.user.ownerId) { diff --git a/apps/dokploy/server/api/routers/redis.ts b/apps/dokploy/server/api/routers/redis.ts index af1d4234a..46586e5e2 100644 --- a/apps/dokploy/server/api/routers/redis.ts +++ b/apps/dokploy/server/api/routers/redis.ts @@ -37,7 +37,7 @@ export const redisRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.projectId, "create"); + await checkServiceAccess(ctx.user.id, input.projectId, "create"); } if (IS_CLOUD && !input.serverId) { @@ -56,7 +56,7 @@ export const redisRouter = createTRPCRouter({ } const newRedis = await createRedis(input); if (ctx.user.rol === "user") { - await addNewService(ctx.user.authId, newRedis.redisId); + await addNewService(ctx.user.id, newRedis.redisId); } await createMount({ @@ -76,7 +76,7 @@ export const redisRouter = createTRPCRouter({ .input(apiFindOneRedis) .query(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.redisId, "access"); + await checkServiceAccess(ctx.user.id, input.redisId, "access"); } const redis = await findRedisById(input.redisId); @@ -233,7 +233,7 @@ export const redisRouter = createTRPCRouter({ .input(apiFindOneRedis) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "user") { - await checkServiceAccess(ctx.user.authId, input.redisId, "delete"); + await checkServiceAccess(ctx.user.id, input.redisId, "delete"); } const redis = await findRedisById(input.redisId); diff --git a/apps/dokploy/server/api/routers/stripe.ts b/apps/dokploy/server/api/routers/stripe.ts index 91fa44fd6..540820f25 100644 --- a/apps/dokploy/server/api/routers/stripe.ts +++ b/apps/dokploy/server/api/routers/stripe.ts @@ -120,8 +120,7 @@ export const stripeRouter = createTRPCRouter({ canCreateMoreServers: adminProcedure.query(async ({ ctx }) => { const user = await findUserById(ctx.user.ownerId); - console.log(user); - // const servers = await findServersByUserId(user.id); + const servers = await findServersByUserId(user.id); if (!IS_CLOUD) { return true; diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index e7a263fa0..432753fde 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -1,7 +1,7 @@ +import { relations } from "drizzle-orm"; import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { nanoid } from "nanoid"; import { users_temp } from "./user"; -import { relations } from "drizzle-orm"; export const account = pgTable("account", { id: text("id") diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 0a3535137..bf47967c3 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -13,6 +13,7 @@ import { z } from "zod"; import { admins } from "./admin"; import { auth } from "./auth"; import { certificateType } from "./shared"; +import { account } from "./account"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * database instance for multiple projects. @@ -185,10 +186,14 @@ export const users_temp = pgTable("user_temp", { serversQuantity: integer("serversQuantity").notNull().default(0), }); -export const usersRelations = relations(users, ({ one }) => ({ - auth: one(auth, { - fields: [users.authId], - references: [auth.id], +export const usersRelations = relations(users_temp, ({ one }) => ({ + // auth: one(auth, { + // fields: [users.authId], + // references: [auth.id], + // }), + account: one(account, { + fields: [users_temp.id], + references: [account.userId], }), // admin: one(admins, { // fields: [users.adminId], diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index c4b7650ba..ea87e4560 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -51,6 +51,9 @@ export const createInvitation = async ( export const findUserById = async (userId: string) => { const user = await db.query.users_temp.findFirst({ where: eq(users_temp.id, userId), + // with: { + // account: true, + // }, }); if (!user) { throw new TRPCError({ diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts index 8781f4f19..74cd04197 100644 --- a/packages/server/src/services/auth.ts +++ b/packages/server/src/services/auth.ts @@ -15,6 +15,7 @@ import encode from "hi-base32"; import { TOTP } from "otpauth"; import QRCode from "qrcode"; import { IS_CLOUD } from "../constants"; +import { findUserById } from "./admin"; export type Auth = typeof auth.$inferSelect; @@ -131,14 +132,14 @@ export const updateAuthById = async ( return result[0]; }; -export const generate2FASecret = async (authId: string) => { - const auth = await findAuthById(authId); +export const generate2FASecret = async (userId: string) => { + const user = await findUserById(userId); const base32_secret = generateBase32Secret(); const totp = new TOTP({ issuer: "Dokploy", - label: `${auth?.email}`, + label: `${user?.email}`, algorithm: "SHA1", digits: 6, secret: base32_secret, diff --git a/packages/server/src/services/server.ts b/packages/server/src/services/server.ts index 6aaa8becc..7702c90d6 100644 --- a/packages/server/src/services/server.ts +++ b/packages/server/src/services/server.ts @@ -14,6 +14,7 @@ export const createServer = async ( .values({ ...input, userId: userId, + createdAt: new Date().toISOString(), }) .returning() .then((value) => value[0]); diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index 5a9898cde..c32ceef2c 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -2,21 +2,22 @@ import { db } from "@dokploy/server/db"; import type { users_temp } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; +import { findUserById } from "./admin"; export type User = typeof users_temp.$inferSelect; -export const findUserById = async (userId: string) => { - const userR = await db.query.user.findFirst({ - where: eq(user.userId, userId), - }); - if (!userR) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "User not found", - }); - } - return user; -}; +// export const findUserById = async (userId: string) => { +// // const userR = await db.query.user.findFirst({ +// // where: eq(user.userId, userId), +// // }); +// // if (!userR) { +// // throw new TRPCError({ +// // code: "NOT_FOUND", +// // message: "User not found", +// // }); +// // } +// // return user; +// }; export const findUserByAuthId = async (authId: string) => { const userR = await db.query.user.findFirst({ @@ -46,33 +47,32 @@ export const findUsers = async (adminId: string) => { return currentUsers; }; -export const addNewProject = async (authId: string, projectId: string) => { - const userR = await findUserByAuthId(authId); +export const addNewProject = async (userId: string, projectId: string) => { + const userR = await findUserById(userId); - await db - .update(user) - .set({ - accessedProjects: [...userR.accessedProjects, projectId], - }) - .where(eq(user.authId, authId)); + // await db + // .update(user) + // .set({ + // accessedProjects: [...userR.accessedProjects, projectId], + // }) + // .where(eq(user.authId, authId)); }; -export const addNewService = async (authId: string, serviceId: string) => { - const userR = await findUserByAuthId(authId); - await db - .update(user) - .set({ - accessedServices: [...userR.accessedServices, serviceId], - }) - .where(eq(user.authId, authId)); +export const addNewService = async (userId: string, serviceId: string) => { + const userR = await findUserById(userId); + // await db + // .update(user) + // .set({ + // accessedServices: [...userR.accessedServices, serviceId], + // }) + // .where(eq(user.userId, userId)); }; export const canPerformCreationService = async ( userId: string, projectId: string, ) => { - const { accessedProjects, canCreateServices } = - await findUserByAuthId(userId); + const { accessedProjects, canCreateServices } = await findUserById(userId); const haveAccessToProject = accessedProjects.includes(projectId); if (canCreateServices && haveAccessToProject) { @@ -86,7 +86,7 @@ export const canPerformAccessService = async ( userId: string, serviceId: string, ) => { - const { accessedServices } = await findUserByAuthId(userId); + const { accessedServices } = await findUserById(userId); const haveAccessToService = accessedServices.includes(serviceId); if (haveAccessToService) { @@ -97,11 +97,10 @@ export const canPerformAccessService = async ( }; export const canPeformDeleteService = async ( - authId: string, + userId: string, serviceId: string, ) => { - const { accessedServices, canDeleteServices } = - await findUserByAuthId(authId); + const { accessedServices, canDeleteServices } = await findUserById(userId); const haveAccessToService = accessedServices.includes(serviceId); if (canDeleteServices && haveAccessToService) { @@ -111,8 +110,8 @@ export const canPeformDeleteService = async ( return false; }; -export const canPerformCreationProject = async (authId: string) => { - const { canCreateProjects } = await findUserByAuthId(authId); +export const canPerformCreationProject = async (userId: string) => { + const { canCreateProjects } = await findUserById(userId); if (canCreateProjects) { return true; @@ -121,8 +120,8 @@ export const canPerformCreationProject = async (authId: string) => { return false; }; -export const canPerformDeleteProject = async (authId: string) => { - const { canDeleteProjects } = await findUserByAuthId(authId); +export const canPerformDeleteProject = async (userId: string) => { + const { canDeleteProjects } = await findUserById(userId); if (canDeleteProjects) { return true; @@ -132,10 +131,10 @@ export const canPerformDeleteProject = async (authId: string) => { }; export const canPerformAccessProject = async ( - authId: string, + userId: string, projectId: string, ) => { - const { accessedProjects } = await findUserByAuthId(authId); + const { accessedProjects } = await findUserById(userId); const haveAccessToProject = accessedProjects.includes(projectId); @@ -145,26 +144,26 @@ export const canPerformAccessProject = async ( return false; }; -export const canAccessToTraefikFiles = async (authId: string) => { - const { canAccessToTraefikFiles } = await findUserByAuthId(authId); +export const canAccessToTraefikFiles = async (userId: string) => { + const { canAccessToTraefikFiles } = await findUserById(userId); return canAccessToTraefikFiles; }; export const checkServiceAccess = async ( - authId: string, + userId: string, serviceId: string, action = "access" as "access" | "create" | "delete", ) => { let hasPermission = false; switch (action) { case "create": - hasPermission = await canPerformCreationService(authId, serviceId); + hasPermission = await canPerformCreationService(userId, serviceId); break; case "access": - hasPermission = await canPerformAccessService(authId, serviceId); + hasPermission = await canPerformAccessService(userId, serviceId); break; case "delete": - hasPermission = await canPeformDeleteService(authId, serviceId); + hasPermission = await canPeformDeleteService(userId, serviceId); break; default: hasPermission = false; diff --git a/packages/server/src/setup/monitoring-setup.ts b/packages/server/src/setup/monitoring-setup.ts index f72b22447..ea6c768ba 100644 --- a/packages/server/src/setup/monitoring-setup.ts +++ b/packages/server/src/setup/monitoring-setup.ts @@ -1,7 +1,7 @@ import { findServerById } from "@dokploy/server/services/server"; import type { ContainerCreateOptions } from "dockerode"; import { IS_CLOUD } from "../constants"; -import { findAdminById } from "../services/admin"; +import { findAdminById, findUserById } from "../services/admin"; import { getDokployImageTag } from "../services/settings"; import { pullImage, pullRemoteImage } from "../utils/docker/utils"; import { execAsync, execAsyncRemote } from "../utils/process/execAsync"; @@ -80,8 +80,8 @@ export const setupMonitoring = async (serverId: string) => { } }; -export const setupWebMonitoring = async (adminId: string) => { - const admin = await findAdminById(adminId); +export const setupWebMonitoring = async (userId: string) => { + const user = await findUserById(userId); const containerName = "dokploy-monitoring"; let imageName = "dokploy/monitoring:latest"; @@ -96,7 +96,7 @@ export const setupWebMonitoring = async (adminId: string) => { const settings: ContainerCreateOptions = { name: containerName, - Env: [`METRICS_CONFIG=${JSON.stringify(admin?.metricsConfig)}`], + Env: [`METRICS_CONFIG=${JSON.stringify(user?.metricsConfig)}`], Image: imageName, HostConfig: { // Memory: 100 * 1024 * 1024, // 100MB en bytes @@ -104,9 +104,9 @@ export const setupWebMonitoring = async (adminId: string) => { // CapAdd: ["NET_ADMIN", "SYS_ADMIN"], // Privileged: true, PortBindings: { - [`${admin.metricsConfig.server.port}/tcp`]: [ + [`${user?.metricsConfig?.server?.port}/tcp`]: [ { - HostPort: admin.metricsConfig.server.port.toString(), + HostPort: user?.metricsConfig?.server?.port.toString(), }, ], }, @@ -120,7 +120,7 @@ export const setupWebMonitoring = async (adminId: string) => { // NetworkMode: "host", }, ExposedPorts: { - [`${admin.metricsConfig.server.port}/tcp`]: {}, + [`${user?.metricsConfig?.server?.port}/tcp`]: {}, }, }; const docker = await getRemoteDocker(); From 55abac3f2f0a3011b5c624ff7293f20389df63a3 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Fri, 14 Feb 2025 02:52:37 -0600 Subject: [PATCH 20/89] refactor: migrate endpoints --- apps/dokploy/pages/api/stripe/webhook.ts | 396 +++++++++--------- packages/server/src/db/schema/user.ts | 2 +- packages/server/src/services/application.ts | 22 +- packages/server/src/services/certificate.ts | 4 +- packages/server/src/services/compose.ts | 18 +- packages/server/src/services/destination.ts | 10 +- packages/server/src/services/domain.ts | 6 +- packages/server/src/services/gitlab.ts | 4 +- .../server/src/services/preview-deployment.ts | 8 +- packages/server/src/services/project.ts | 4 +- packages/server/src/utils/backups/mariadb.ts | 4 +- packages/server/src/utils/backups/mongo.ts | 4 +- packages/server/src/utils/backups/mysql.ts | 4 +- packages/server/src/utils/backups/postgres.ts | 4 +- .../src/utils/notifications/build-error.ts | 6 +- .../src/utils/notifications/build-success.ts | 6 +- .../utils/notifications/database-backup.ts | 6 +- .../src/utils/notifications/docker-cleanup.ts | 4 +- .../utils/notifications/server-threshold.ts | 4 +- 19 files changed, 260 insertions(+), 256 deletions(-) diff --git a/apps/dokploy/pages/api/stripe/webhook.ts b/apps/dokploy/pages/api/stripe/webhook.ts index 7701ebd98..e8416c5d0 100644 --- a/apps/dokploy/pages/api/stripe/webhook.ts +++ b/apps/dokploy/pages/api/stripe/webhook.ts @@ -1,7 +1,7 @@ import { buffer } from "node:stream/consumers"; import { db } from "@/server/db"; -import { admins, server } from "@/server/db/schema"; -import { findAdminById } from "@dokploy/server"; +import { admins, server, users_temp } from "@/server/db/schema"; +import { findAdminById, findUserById } from "@dokploy/server"; import { asc, eq } from "drizzle-orm"; import type { NextApiRequest, NextApiResponse } from "next"; import Stripe from "stripe"; @@ -18,242 +18,246 @@ export default async function handler( req: NextApiRequest, res: NextApiResponse, ) { - // if (!endpointSecret) { - // return res.status(400).send("Webhook Error: Missing Stripe Secret Key"); - // } - // const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { - // apiVersion: "2024-09-30.acacia", - // maxNetworkRetries: 3, - // }); + if (!endpointSecret) { + return res.status(400).send("Webhook Error: Missing Stripe Secret Key"); + } + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { + apiVersion: "2024-09-30.acacia", + maxNetworkRetries: 3, + }); - // const buf = await buffer(req); - // const sig = req.headers["stripe-signature"] as string; + const buf = await buffer(req); + const sig = req.headers["stripe-signature"] as string; - // let event: Stripe.Event; + let event: Stripe.Event; - // try { - // event = stripe.webhooks.constructEvent(buf, sig, endpointSecret); - // } catch (err) { - // console.error( - // "Webhook signature verification failed.", - // err instanceof Error ? err.message : err, - // ); - // return res.status(400).send("Webhook Error: "); - // } + try { + event = stripe.webhooks.constructEvent(buf, sig, endpointSecret); + } catch (err) { + console.error( + "Webhook signature verification failed.", + err instanceof Error ? err.message : err, + ); + return res.status(400).send("Webhook Error: "); + } - // const webhooksAllowed = [ - // "customer.subscription.created", - // "customer.subscription.deleted", - // "customer.subscription.updated", - // "invoice.payment_succeeded", - // "invoice.payment_failed", - // "customer.deleted", - // "checkout.session.completed", - // ]; + const webhooksAllowed = [ + "customer.subscription.created", + "customer.subscription.deleted", + "customer.subscription.updated", + "invoice.payment_succeeded", + "invoice.payment_failed", + "customer.deleted", + "checkout.session.completed", + ]; - // if (!webhooksAllowed.includes(event.type)) { - // return res.status(400).send("Webhook Error: Invalid Event Type"); - // } + if (!webhooksAllowed.includes(event.type)) { + return res.status(400).send("Webhook Error: Invalid Event Type"); + } - // switch (event.type) { - // case "checkout.session.completed": { - // const session = event.data.object as Stripe.Checkout.Session; - // const adminId = session?.metadata?.adminId as string; + switch (event.type) { + case "checkout.session.completed": { + const session = event.data.object as Stripe.Checkout.Session; + const adminId = session?.metadata?.adminId as string; - // const subscription = await stripe.subscriptions.retrieve( - // session.subscription as string, - // ); - // await db - // .update(admins) - // .set({ - // stripeCustomerId: session.customer as string, - // stripeSubscriptionId: session.subscription as string, - // serversQuantity: subscription?.items?.data?.[0]?.quantity ?? 0, - // }) - // .where(eq(admins.adminId, adminId)) - // .returning(); + const subscription = await stripe.subscriptions.retrieve( + session.subscription as string, + ); + await db + .update(users_temp) + .set({ + stripeCustomerId: session.customer as string, + stripeSubscriptionId: session.subscription as string, + serversQuantity: subscription?.items?.data?.[0]?.quantity ?? 0, + }) + .where(eq(users_temp.id, adminId)) + .returning(); - // const admin = await findAdminById(adminId); - // if (!admin) { - // return res.status(400).send("Webhook Error: Admin not found"); - // } - // const newServersQuantity = admin.serversQuantity; - // await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); - // break; - // } - // case "customer.subscription.created": { - // const newSubscription = event.data.object as Stripe.Subscription; + const admin = await findUserById(adminId); + if (!admin) { + return res.status(400).send("Webhook Error: Admin not found"); + } + const newServersQuantity = admin.serversQuantity; + await updateServersBasedOnQuantity(admin.id, newServersQuantity); + break; + } + case "customer.subscription.created": { + const newSubscription = event.data.object as Stripe.Subscription; - // await db - // .update(admins) - // .set({ - // stripeSubscriptionId: newSubscription.id, - // stripeCustomerId: newSubscription.customer as string, - // }) - // .where(eq(admins.stripeCustomerId, newSubscription.customer as string)) - // .returning(); + await db + .update(users_temp) + .set({ + stripeSubscriptionId: newSubscription.id, + stripeCustomerId: newSubscription.customer as string, + }) + .where( + eq(users_temp.stripeCustomerId, newSubscription.customer as string), + ) + .returning(); - // break; - // } + break; + } - // case "customer.subscription.deleted": { - // const newSubscription = event.data.object as Stripe.Subscription; + case "customer.subscription.deleted": { + const newSubscription = event.data.object as Stripe.Subscription; - // await db - // .update(admins) - // .set({ - // stripeSubscriptionId: null, - // serversQuantity: 0, - // }) - // .where(eq(admins.stripeCustomerId, newSubscription.customer as string)); + await db + .update(users_temp) + .set({ + stripeSubscriptionId: null, + serversQuantity: 0, + }) + .where( + eq(users_temp.stripeCustomerId, newSubscription.customer as string), + ); - // const admin = await findAdminByStripeCustomerId( - // newSubscription.customer as string, - // ); + const admin = await findUserByStripeCustomerId( + newSubscription.customer as string, + ); - // if (!admin) { - // return res.status(400).send("Webhook Error: Admin not found"); - // } + if (!admin) { + return res.status(400).send("Webhook Error: Admin not found"); + } - // await disableServers(admin.adminId); - // break; - // } - // case "customer.subscription.updated": { - // const newSubscription = event.data.object as Stripe.Subscription; + await disableServers(admin.id); + break; + } + case "customer.subscription.updated": { + const newSubscription = event.data.object as Stripe.Subscription; - // const admin = await findAdminByStripeCustomerId( - // newSubscription.customer as string, - // ); + const admin = await findUserByStripeCustomerId( + newSubscription.customer as string, + ); - // if (!admin) { - // return res.status(400).send("Webhook Error: Admin not found"); - // } + if (!admin) { + return res.status(400).send("Webhook Error: Admin not found"); + } - // if (newSubscription.status === "active") { - // await db - // .update(admins) - // .set({ - // serversQuantity: newSubscription?.items?.data?.[0]?.quantity ?? 0, - // }) - // .where( - // eq(admins.stripeCustomerId, newSubscription.customer as string), - // ); + if (newSubscription.status === "active") { + await db + .update(users_temp) + .set({ + serversQuantity: newSubscription?.items?.data?.[0]?.quantity ?? 0, + }) + .where( + eq(users_temp.stripeCustomerId, newSubscription.customer as string), + ); - // const newServersQuantity = admin.serversQuantity; - // await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); - // } else { - // await disableServers(admin.adminId); - // await db - // .update(admins) - // .set({ serversQuantity: 0 }) - // .where( - // eq(admins.stripeCustomerId, newSubscription.customer as string), - // ); - // } + const newServersQuantity = admin.serversQuantity; + await updateServersBasedOnQuantity(admin.id, newServersQuantity); + } else { + await disableServers(admin.id); + await db + .update(users_temp) + .set({ serversQuantity: 0 }) + .where( + eq(users_temp.stripeCustomerId, newSubscription.customer as string), + ); + } - // break; - // } - // case "invoice.payment_succeeded": { - // const newInvoice = event.data.object as Stripe.Invoice; + break; + } + case "invoice.payment_succeeded": { + const newInvoice = event.data.object as Stripe.Invoice; - // const suscription = await stripe.subscriptions.retrieve( - // newInvoice.subscription as string, - // ); + const suscription = await stripe.subscriptions.retrieve( + newInvoice.subscription as string, + ); - // if (suscription.status !== "active") { - // console.log( - // `Skipping invoice.payment_succeeded for subscription ${suscription.id} with status ${suscription.status}`, - // ); - // break; - // } + if (suscription.status !== "active") { + console.log( + `Skipping invoice.payment_succeeded for subscription ${suscription.id} with status ${suscription.status}`, + ); + break; + } - // await db - // .update(admins) - // .set({ - // serversQuantity: suscription?.items?.data?.[0]?.quantity ?? 0, - // }) - // .where(eq(admins.stripeCustomerId, suscription.customer as string)); + await db + .update(admins) + .set({ + serversQuantity: suscription?.items?.data?.[0]?.quantity ?? 0, + }) + .where(eq(admins.stripeCustomerId, suscription.customer as string)); - // const admin = await findAdminByStripeCustomerId( - // suscription.customer as string, - // ); + const admin = await findUserByStripeCustomerId( + suscription.customer as string, + ); - // if (!admin) { - // return res.status(400).send("Webhook Error: Admin not found"); - // } - // const newServersQuantity = admin.serversQuantity; - // await updateServersBasedOnQuantity(admin.adminId, newServersQuantity); - // break; - // } - // case "invoice.payment_failed": { - // const newInvoice = event.data.object as Stripe.Invoice; + if (!admin) { + return res.status(400).send("Webhook Error: Admin not found"); + } + const newServersQuantity = admin.serversQuantity; + await updateServersBasedOnQuantity(admin.id, newServersQuantity); + break; + } + case "invoice.payment_failed": { + const newInvoice = event.data.object as Stripe.Invoice; - // const subscription = await stripe.subscriptions.retrieve( - // newInvoice.subscription as string, - // ); + const subscription = await stripe.subscriptions.retrieve( + newInvoice.subscription as string, + ); - // if (subscription.status !== "active") { - // const admin = await findAdminByStripeCustomerId( - // newInvoice.customer as string, - // ); + if (subscription.status !== "active") { + const admin = await findUserByStripeCustomerId( + newInvoice.customer as string, + ); - // if (!admin) { - // return res.status(400).send("Webhook Error: Admin not found"); - // } - // await db - // .update(admins) - // .set({ - // serversQuantity: 0, - // }) - // .where(eq(admins.stripeCustomerId, newInvoice.customer as string)); + if (!admin) { + return res.status(400).send("Webhook Error: Admin not found"); + } + await db + .update(admins) + .set({ + serversQuantity: 0, + }) + .where(eq(admins.stripeCustomerId, newInvoice.customer as string)); - // await disableServers(admin.adminId); - // } + await disableServers(admin.id); + } - // break; - // } + break; + } - // case "customer.deleted": { - // const customer = event.data.object as Stripe.Customer; + case "customer.deleted": { + const customer = event.data.object as Stripe.Customer; - // const admin = await findAdminByStripeCustomerId(customer.id); - // if (!admin) { - // return res.status(400).send("Webhook Error: Admin not found"); - // } + const admin = await findUserByStripeCustomerId(customer.id); + if (!admin) { + return res.status(400).send("Webhook Error: Admin not found"); + } - // await disableServers(admin.adminId); - // await db - // .update(admins) - // .set({ - // stripeCustomerId: null, - // stripeSubscriptionId: null, - // serversQuantity: 0, - // }) - // .where(eq(admins.stripeCustomerId, customer.id)); + await disableServers(admin.id); + await db + .update(users_temp) + .set({ + stripeCustomerId: null, + stripeSubscriptionId: null, + serversQuantity: 0, + }) + .where(eq(users_temp.stripeCustomerId, customer.id)); - // break; - // } - // default: - // console.log(`Unhandled event type: ${event.type}`); - // } + break; + } + default: + console.log(`Unhandled event type: ${event.type}`); + } return res.status(200).json({ received: true }); } -const disableServers = async (adminId: string) => { +const disableServers = async (userId: string) => { await db .update(server) .set({ serverStatus: "inactive", }) - .where(eq(server.adminId, adminId)); + .where(eq(server.userId, userId)); }; -const findAdminByStripeCustomerId = async (stripeCustomerId: string) => { - const admin = db.query.admins.findFirst({ - where: eq(admins.stripeCustomerId, stripeCustomerId), +const findUserByStripeCustomerId = async (stripeCustomerId: string) => { + const user = db.query.users_temp.findFirst({ + where: eq(users_temp.stripeCustomerId, stripeCustomerId), }); - return admin; + return user; }; const activateServer = async (serverId: string) => { @@ -270,19 +274,19 @@ const deactivateServer = async (serverId: string) => { .where(eq(server.serverId, serverId)); }; -export const findServersByAdminIdSorted = async (adminId: string) => { +export const findServersByUserIdSorted = async (userId: string) => { const servers = await db.query.server.findMany({ - where: eq(server.adminId, adminId), + where: eq(server.userId, userId), orderBy: asc(server.createdAt), }); return servers; }; export const updateServersBasedOnQuantity = async ( - adminId: string, + userId: string, newServersQuantity: number, ) => { - const servers = await findServersByAdminIdSorted(adminId); + const servers = await findServersByUserIdSorted(userId); if (servers.length > newServersQuantity) { for (const [index, server] of servers.entries()) { diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index bf47967c3..fba21e234 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -10,10 +10,10 @@ import { import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; +import { account } from "./account"; import { admins } from "./admin"; import { auth } from "./auth"; import { certificateType } from "./shared"; -import { account } from "./account"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * database instance for multiple projects. diff --git a/packages/server/src/services/application.ts b/packages/server/src/services/application.ts index c102e8ed7..b60665304 100644 --- a/packages/server/src/services/application.ts +++ b/packages/server/src/services/application.ts @@ -40,7 +40,7 @@ import { createTraefikConfig } from "@dokploy/server/utils/traefik/application"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { encodeBase64 } from "../utils/docker/utils"; -import { findAdminById, getDokployUrl } from "./admin"; +import { findAdminById, findUserById, getDokployUrl } from "./admin"; import { createDeployment, createDeploymentPreview, @@ -185,7 +185,7 @@ export const deployApplication = async ({ }); try { - const admin = await findAdminById(application.project.adminId); + const admin = await findUserById(application.project.userId); if (admin.cleanupCacheApplications) { await cleanupFullDocker(application?.serverId); @@ -220,7 +220,7 @@ export const deployApplication = async ({ applicationName: application.name, applicationType: "application", buildLink, - adminId: application.project.adminId, + userId: application.project.userId, domains: application.domains, }); } catch (error) { @@ -233,7 +233,7 @@ export const deployApplication = async ({ // @ts-ignore errorMessage: error?.message || "Error building", buildLink, - adminId: application.project.adminId, + userId: application.project.userId, }); throw error; @@ -260,7 +260,7 @@ export const rebuildApplication = async ({ }); try { - const admin = await findAdminById(application.project.adminId); + const admin = await findUserById(application.project.userId); if (admin.cleanupCacheApplications) { await cleanupFullDocker(application?.serverId); @@ -309,7 +309,7 @@ export const deployRemoteApplication = async ({ try { if (application.serverId) { - const admin = await findAdminById(application.project.adminId); + const admin = await findUserById(application.project.userId); if (admin.cleanupCacheApplications) { await cleanupFullDocker(application?.serverId); @@ -352,7 +352,7 @@ export const deployRemoteApplication = async ({ applicationName: application.name, applicationType: "application", buildLink, - adminId: application.project.adminId, + userId: application.project.userId, domains: application.domains, }); } catch (error) { @@ -376,7 +376,7 @@ export const deployRemoteApplication = async ({ // @ts-ignore errorMessage: error?.message || "Error building", buildLink, - adminId: application.project.adminId, + userId: application.project.userId, }); throw error; @@ -454,7 +454,7 @@ export const deployPreviewApplication = async ({ application.env = `${application.previewEnv}\nDOKPLOY_DEPLOY_URL=${previewDeployment?.domain}`; application.buildArgs = application.previewBuildArgs; - const admin = await findAdminById(application.project.adminId); + const admin = await findUserById(application.project.userId); if (admin.cleanupCacheOnPreviews) { await cleanupFullDocker(application?.serverId); @@ -568,7 +568,7 @@ export const deployRemotePreviewApplication = async ({ application.buildArgs = application.previewBuildArgs; if (application.serverId) { - const admin = await findAdminById(application.project.adminId); + const admin = await findUserById(application.project.userId); if (admin.cleanupCacheOnPreviews) { await cleanupFullDocker(application?.serverId); @@ -637,7 +637,7 @@ export const rebuildRemoteApplication = async ({ try { if (application.serverId) { - const admin = await findAdminById(application.project.adminId); + const admin = await findUserById(application.project.userId); if (admin.cleanupCacheApplications) { await cleanupFullDocker(application?.serverId); diff --git a/packages/server/src/services/certificate.ts b/packages/server/src/services/certificate.ts index 231778621..dd83e61df 100644 --- a/packages/server/src/services/certificate.ts +++ b/packages/server/src/services/certificate.ts @@ -33,13 +33,13 @@ export const findCertificateById = async (certificateId: string) => { export const createCertificate = async ( certificateData: z.infer, - adminId: string, + userId: string, ) => { const certificate = await db .insert(certificates) .values({ ...certificateData, - adminId: adminId, + userId: userId, }) .returning(); diff --git a/packages/server/src/services/compose.ts b/packages/server/src/services/compose.ts index 39bf423fa..a4126a0d0 100644 --- a/packages/server/src/services/compose.ts +++ b/packages/server/src/services/compose.ts @@ -44,7 +44,7 @@ import { import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { encodeBase64 } from "../utils/docker/utils"; -import { findAdminById, getDokployUrl } from "./admin"; +import { findAdminById, findUserById, getDokployUrl } from "./admin"; import { createDeploymentCompose, updateDeploymentStatus } from "./deployment"; import { validUniqueServerAppName } from "./project"; import { cleanupFullDocker } from "./settings"; @@ -217,7 +217,7 @@ export const deployCompose = async ({ }); try { - const admin = await findAdminById(compose.project.adminId); + const admin = await findUserById(compose.project.userId); if (admin.cleanupCacheOnCompose) { await cleanupFullDocker(compose?.serverId); } @@ -247,7 +247,7 @@ export const deployCompose = async ({ applicationName: compose.name, applicationType: "compose", buildLink, - adminId: compose.project.adminId, + userId: compose.project.userId, domains: compose.domains, }); } catch (error) { @@ -262,7 +262,7 @@ export const deployCompose = async ({ // @ts-ignore errorMessage: error?.message || "Error building", buildLink, - adminId: compose.project.adminId, + userId: compose.project.userId, }); throw error; } @@ -286,7 +286,7 @@ export const rebuildCompose = async ({ }); try { - const admin = await findAdminById(compose.project.adminId); + const admin = await findUserById(compose.project.userId); if (admin.cleanupCacheOnCompose) { await cleanupFullDocker(compose?.serverId); } @@ -332,7 +332,7 @@ export const deployRemoteCompose = async ({ }); try { if (compose.serverId) { - const admin = await findAdminById(compose.project.adminId); + const admin = await findUserById(compose.project.userId); if (admin.cleanupCacheOnCompose) { await cleanupFullDocker(compose?.serverId); } @@ -381,7 +381,7 @@ export const deployRemoteCompose = async ({ applicationName: compose.name, applicationType: "compose", buildLink, - adminId: compose.project.adminId, + userId: compose.project.userId, domains: compose.domains, }); } catch (error) { @@ -406,7 +406,7 @@ export const deployRemoteCompose = async ({ // @ts-ignore errorMessage: error?.message || "Error building", buildLink, - adminId: compose.project.adminId, + userId: compose.project.userId, }); throw error; } @@ -430,7 +430,7 @@ export const rebuildRemoteCompose = async ({ }); try { - const admin = await findAdminById(compose.project.adminId); + const admin = await findUserById(compose.project.userId); if (admin.cleanupCacheOnCompose) { await cleanupFullDocker(compose?.serverId); } diff --git a/packages/server/src/services/destination.ts b/packages/server/src/services/destination.ts index 892c93541..add0a3dff 100644 --- a/packages/server/src/services/destination.ts +++ b/packages/server/src/services/destination.ts @@ -10,13 +10,13 @@ export type Destination = typeof destinations.$inferSelect; export const createDestintation = async ( input: typeof apiCreateDestination._type, - adminId: string, + userId: string, ) => { const newDestination = await db .insert(destinations) .values({ ...input, - adminId: adminId, + userId: userId, }) .returning() .then((value) => value[0]); @@ -46,14 +46,14 @@ export const findDestinationById = async (destinationId: string) => { export const removeDestinationById = async ( destinationId: string, - adminId: string, + userId: string, ) => { const result = await db .delete(destinations) .where( and( eq(destinations.destinationId, destinationId), - eq(destinations.adminId, adminId), + eq(destinations.userId, userId), ), ) .returning(); @@ -73,7 +73,7 @@ export const updateDestinationById = async ( .where( and( eq(destinations.destinationId, destinationId), - eq(destinations.adminId, destinationData.adminId || ""), + eq(destinations.userId, destinationData.userId || ""), ), ) .returning(); diff --git a/packages/server/src/services/domain.ts b/packages/server/src/services/domain.ts index b99c4869d..99dcde559 100644 --- a/packages/server/src/services/domain.ts +++ b/packages/server/src/services/domain.ts @@ -4,7 +4,7 @@ import { manageDomain } from "@dokploy/server/utils/traefik/domain"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { type apiCreateDomain, domains } from "../db/schema"; -import { findAdmin, findAdminById } from "./admin"; +import { findAdmin, findAdminById, findUserById } from "./admin"; import { findApplicationById } from "./application"; import { findServerById } from "./server"; @@ -40,7 +40,7 @@ export const createDomain = async (input: typeof apiCreateDomain._type) => { export const generateTraefikMeDomain = async ( appName: string, - adminId: string, + userId: string, serverId?: string, ) => { if (serverId) { @@ -57,7 +57,7 @@ export const generateTraefikMeDomain = async ( projectName: appName, }); } - const admin = await findAdminById(adminId); + const admin = await findUserById(userId); return generateRandomDomain({ serverIp: admin?.serverIp || "", projectName: appName, diff --git a/packages/server/src/services/gitlab.ts b/packages/server/src/services/gitlab.ts index 8e1362c94..c581c96ce 100644 --- a/packages/server/src/services/gitlab.ts +++ b/packages/server/src/services/gitlab.ts @@ -13,14 +13,14 @@ export type Gitlab = typeof gitlab.$inferSelect; export const createGitlab = async ( input: typeof apiCreateGitlab._type, - adminId: string, + userId: string, ) => { return await db.transaction(async (tx) => { const newGitProvider = await tx .insert(gitProvider) .values({ providerType: "gitlab", - adminId: adminId, + userId: userId, name: input.name, }) .returning() diff --git a/packages/server/src/services/preview-deployment.ts b/packages/server/src/services/preview-deployment.ts index ab38c17ca..69279b027 100644 --- a/packages/server/src/services/preview-deployment.ts +++ b/packages/server/src/services/preview-deployment.ts @@ -13,7 +13,7 @@ import { removeDirectoryCode } from "../utils/filesystem/directory"; import { authGithub } from "../utils/providers/github"; import { removeTraefikConfig } from "../utils/traefik/application"; import { manageDomain } from "../utils/traefik/domain"; -import { findAdminById } from "./admin"; +import { findAdminById, findUserById } from "./admin"; import { findApplicationById } from "./application"; import { removeDeployments, @@ -158,7 +158,7 @@ export const createPreviewDeployment = async ( application.previewWildcard || "*.traefik.me", appName, application.server?.ipAddress || "", - application.project.adminId, + application.project.userId, ); const octokit = authGithub(application?.github as Github); @@ -250,7 +250,7 @@ const generateWildcardDomain = async ( baseDomain: string, appName: string, serverIp: string, - adminId: string, + userId: string, ): Promise => { if (!baseDomain.startsWith("*.")) { throw new Error('The base domain must start with "*."'); @@ -268,7 +268,7 @@ const generateWildcardDomain = async ( } if (!ip) { - const admin = await findAdminById(adminId); + const admin = await findUserById(userId); ip = admin?.serverIp || ""; } diff --git a/packages/server/src/services/project.ts b/packages/server/src/services/project.ts index adaa07ea0..8b80738fd 100644 --- a/packages/server/src/services/project.ts +++ b/packages/server/src/services/project.ts @@ -16,13 +16,13 @@ export type Project = typeof projects.$inferSelect; export const createProject = async ( input: typeof apiCreateProject._type, - adminId: string, + userId: string, ) => { const newProject = await db .insert(projects) .values({ ...input, - adminId: adminId, + userId: userId, }) .returning() .then((value) => value[0]); diff --git a/packages/server/src/utils/backups/mariadb.ts b/packages/server/src/utils/backups/mariadb.ts index 79cba9c57..7ffa16e11 100644 --- a/packages/server/src/utils/backups/mariadb.ts +++ b/packages/server/src/utils/backups/mariadb.ts @@ -49,7 +49,7 @@ export const runMariadbBackup = async ( projectName: project.name, databaseType: "mariadb", type: "success", - adminId: project.adminId, + userId: project.userId, }); } catch (error) { console.log(error); @@ -60,7 +60,7 @@ export const runMariadbBackup = async ( type: "error", // @ts-ignore errorMessage: error?.message || "Error message not provided", - adminId: project.adminId, + userId: project.userId, }); throw error; } diff --git a/packages/server/src/utils/backups/mongo.ts b/packages/server/src/utils/backups/mongo.ts index ddd1b8896..d6860a010 100644 --- a/packages/server/src/utils/backups/mongo.ts +++ b/packages/server/src/utils/backups/mongo.ts @@ -46,7 +46,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => { projectName: project.name, databaseType: "mongodb", type: "success", - adminId: project.adminId, + userId: project.userId, }); } catch (error) { console.log(error); @@ -57,7 +57,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => { type: "error", // @ts-ignore errorMessage: error?.message || "Error message not provided", - adminId: project.adminId, + userId: project.userId, }); throw error; } diff --git a/packages/server/src/utils/backups/mysql.ts b/packages/server/src/utils/backups/mysql.ts index b505204c2..a73179417 100644 --- a/packages/server/src/utils/backups/mysql.ts +++ b/packages/server/src/utils/backups/mysql.ts @@ -46,7 +46,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => { projectName: project.name, databaseType: "mysql", type: "success", - adminId: project.adminId, + userId: project.userId, }); } catch (error) { console.log(error); @@ -57,7 +57,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => { type: "error", // @ts-ignore errorMessage: error?.message || "Error message not provided", - adminId: project.adminId, + userId: project.userId, }); throw error; } diff --git a/packages/server/src/utils/backups/postgres.ts b/packages/server/src/utils/backups/postgres.ts index e9609fc89..33c37b862 100644 --- a/packages/server/src/utils/backups/postgres.ts +++ b/packages/server/src/utils/backups/postgres.ts @@ -49,7 +49,7 @@ export const runPostgresBackup = async ( projectName: project.name, databaseType: "postgres", type: "success", - adminId: project.adminId, + userId: project.userId, }); } catch (error) { await sendDatabaseBackupNotifications({ @@ -59,7 +59,7 @@ export const runPostgresBackup = async ( type: "error", // @ts-ignore errorMessage: error?.message || "Error message not provided", - adminId: project.adminId, + userId: project.userId, }); throw error; diff --git a/packages/server/src/utils/notifications/build-error.ts b/packages/server/src/utils/notifications/build-error.ts index 95936652c..4ed227e1e 100644 --- a/packages/server/src/utils/notifications/build-error.ts +++ b/packages/server/src/utils/notifications/build-error.ts @@ -18,7 +18,7 @@ interface Props { applicationType: string; errorMessage: string; buildLink: string; - adminId: string; + userId: string; } export const sendBuildErrorNotifications = async ({ @@ -27,14 +27,14 @@ export const sendBuildErrorNotifications = async ({ applicationType, errorMessage, buildLink, - adminId, + userId, }: Props) => { const date = new Date(); const unixDate = ~~(Number(date) / 1000); const notificationList = await db.query.notifications.findMany({ where: and( eq(notifications.appBuildError, true), - eq(notifications.adminId, adminId), + eq(notifications.userId, userId), ), with: { email: true, diff --git a/packages/server/src/utils/notifications/build-success.ts b/packages/server/src/utils/notifications/build-success.ts index 960f7a6a4..dfa4824f6 100644 --- a/packages/server/src/utils/notifications/build-success.ts +++ b/packages/server/src/utils/notifications/build-success.ts @@ -18,7 +18,7 @@ interface Props { applicationName: string; applicationType: string; buildLink: string; - adminId: string; + userId: string; domains: Domain[]; } @@ -27,7 +27,7 @@ export const sendBuildSuccessNotifications = async ({ applicationName, applicationType, buildLink, - adminId, + userId, domains, }: Props) => { const date = new Date(); @@ -35,7 +35,7 @@ export const sendBuildSuccessNotifications = async ({ const notificationList = await db.query.notifications.findMany({ where: and( eq(notifications.appDeploy, true), - eq(notifications.adminId, adminId), + eq(notifications.userId, userId), ), with: { email: true, diff --git a/packages/server/src/utils/notifications/database-backup.ts b/packages/server/src/utils/notifications/database-backup.ts index 0b1d61f7e..3ce36aa9f 100644 --- a/packages/server/src/utils/notifications/database-backup.ts +++ b/packages/server/src/utils/notifications/database-backup.ts @@ -19,13 +19,13 @@ export const sendDatabaseBackupNotifications = async ({ databaseType, type, errorMessage, - adminId, + userId, }: { projectName: string; applicationName: string; databaseType: "postgres" | "mysql" | "mongodb" | "mariadb"; type: "error" | "success"; - adminId: string; + userId: string; errorMessage?: string; }) => { const date = new Date(); @@ -33,7 +33,7 @@ export const sendDatabaseBackupNotifications = async ({ const notificationList = await db.query.notifications.findMany({ where: and( eq(notifications.databaseBackup, true), - eq(notifications.adminId, adminId), + eq(notifications.userId, userId), ), with: { email: true, diff --git a/packages/server/src/utils/notifications/docker-cleanup.ts b/packages/server/src/utils/notifications/docker-cleanup.ts index b60e3b0ac..0acf1b6c4 100644 --- a/packages/server/src/utils/notifications/docker-cleanup.ts +++ b/packages/server/src/utils/notifications/docker-cleanup.ts @@ -13,7 +13,7 @@ import { } from "./utils"; export const sendDockerCleanupNotifications = async ( - adminId: string, + userId: string, message = "Docker cleanup for dokploy", ) => { const date = new Date(); @@ -21,7 +21,7 @@ export const sendDockerCleanupNotifications = async ( const notificationList = await db.query.notifications.findMany({ where: and( eq(notifications.dockerCleanup, true), - eq(notifications.adminId, adminId), + eq(notifications.userId, userId), ), with: { email: true, diff --git a/packages/server/src/utils/notifications/server-threshold.ts b/packages/server/src/utils/notifications/server-threshold.ts index 32ff9b55c..c606f0ef3 100644 --- a/packages/server/src/utils/notifications/server-threshold.ts +++ b/packages/server/src/utils/notifications/server-threshold.ts @@ -18,7 +18,7 @@ interface ServerThresholdPayload { } export const sendServerThresholdNotifications = async ( - adminId: string, + userId: string, payload: ServerThresholdPayload, ) => { const date = new Date(payload.Timestamp); @@ -27,7 +27,7 @@ export const sendServerThresholdNotifications = async ( const notificationList = await db.query.notifications.findMany({ where: and( eq(notifications.serverThreshold, true), - eq(notifications.adminId, adminId), + eq(notifications.userId, userId), ), with: { email: true, From 6ec60b6bab2a7f0bc0c31ea230fcc0bd9c299db0 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 13:14:48 -0600 Subject: [PATCH 21/89] refactor: update validation --- packages/server/src/lib/auth.ts | 132 ++++++------ packages/server/src/services/admin.ts | 292 +++++++++++++------------- 2 files changed, 213 insertions(+), 211 deletions(-) diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 48e11f215..226ab0a8c 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -8,78 +8,80 @@ import { db } from "../db"; import * as schema from "../db/schema"; export const auth = betterAuth({ - database: drizzleAdapter(db, { - provider: "pg", - schema: schema, - }), + database: drizzleAdapter(db, { + provider: "pg", + schema: schema, + }), - emailAndPassword: { - enabled: true, + emailAndPassword: { + enabled: true, - password: { - async hash(password) { - return bcrypt.hashSync(password, 10); - }, - async verify({ hash, password }) { - return bcrypt.compareSync(password, hash); - }, - }, - }, - hooks: { - after: createAuthMiddleware(async (ctx) => { - if (ctx.path.startsWith("/sign-up")) { - const newSession = ctx.context.newSession; - await db - .update(schema.users_temp) - .set({ - role: "admin", - }) - .where(eq(schema.users_temp.id, newSession?.user?.id || "")); - } - }), - }, - user: { - modelName: "users_temp", - additionalFields: { - role: { - type: "string", - }, - ownerId: { - type: "string", - }, - }, - }, - plugins: [organization()], + password: { + async hash(password) { + return bcrypt.hashSync(password, 10); + }, + async verify({ hash, password }) { + return bcrypt.compareSync(password, hash); + }, + }, + }, + hooks: { + after: createAuthMiddleware(async (ctx) => { + if (ctx.path.startsWith("/sign-up")) { + const newSession = ctx.context.newSession; + await db + .update(schema.users_temp) + .set({ + role: "admin", + }) + .where(eq(schema.users_temp.id, newSession?.user?.id || "")); + } + }), + }, + user: { + modelName: "users_temp", + additionalFields: { + role: { + type: "string", + }, + ownerId: { + type: "string", + }, + }, + }, + plugins: [organization()], }); export const validateRequest = async (request: IncomingMessage) => { - const session = await auth.api.getSession({ - headers: new Headers({ - cookie: request.headers.cookie || "", - }), - }); + const session = await auth.api.getSession({ + headers: new Headers({ + cookie: request.headers.cookie || "", + }), + }); - if (session?.user.role === "user") { - const owner = await db.query.member.findFirst({ - where: eq(schema.member.userId, session.user.id), - with: { - organization: true, - }, - }); + if (!session?.session || !session.user) { + return { + session: null, + user: null, + }; + } - if (owner) { - session.user.ownerId = owner.organization.ownerId; - } - } else { - session.user.ownerId = session?.user.id; - } + if (session?.user) { + if (session?.user.role === "user") { + const owner = await db.query.member.findFirst({ + where: eq(schema.member.userId, session.user.id), + with: { + organization: true, + }, + }); - if (!session?.session || !session.user) { - return { - session: null, - user: null, - }; - } + if (owner) { + session.user.ownerId = owner.organization.ownerId; + } + } else { + session.user.ownerId = session?.user?.id || ""; + } + } - return session; + return session; }; diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index ea87e4560..e8a60498f 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -1,10 +1,10 @@ import { randomBytes } from "node:crypto"; import { db } from "@dokploy/server/db"; import { - admins, - type apiCreateUserInvitation, - auth, - users_temp, + admins, + type apiCreateUserInvitation, + auth, + users_temp, } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import * as bcrypt from "bcrypt"; @@ -13,188 +13,188 @@ import { IS_CLOUD } from "../constants"; export type Admin = typeof users_temp.$inferSelect; export const createInvitation = async ( - input: typeof apiCreateUserInvitation._type, - adminId: string, + input: typeof apiCreateUserInvitation._type, + adminId: string ) => { - await db.transaction(async (tx) => { - const result = await tx - .insert(auth) - .values({ - email: input.email.toLowerCase(), - rol: "user", - password: bcrypt.hashSync("01231203012312", 10), - }) - .returning() - .then((res) => res[0]); + await db.transaction(async (tx) => { + const result = await tx + .insert(auth) + .values({ + email: input.email.toLowerCase(), + rol: "user", + password: bcrypt.hashSync("01231203012312", 10), + }) + .returning() + .then((res) => res[0]); - if (!result) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error creating the user", - }); - } - const expiresIn24Hours = new Date(); - expiresIn24Hours.setDate(expiresIn24Hours.getDate() + 1); - const token = randomBytes(32).toString("hex"); - await tx - .insert(users) - .values({ - adminId: adminId, - authId: result.id, - token, - expirationDate: expiresIn24Hours.toISOString(), - }) - .returning(); - }); + if (!result) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Error creating the user", + }); + } + const expiresIn24Hours = new Date(); + expiresIn24Hours.setDate(expiresIn24Hours.getDate() + 1); + const token = randomBytes(32).toString("hex"); + await tx + .insert(users) + .values({ + adminId: adminId, + authId: result.id, + token, + expirationDate: expiresIn24Hours.toISOString(), + }) + .returning(); + }); }; export const findUserById = async (userId: string) => { - const user = await db.query.users_temp.findFirst({ - where: eq(users_temp.id, userId), - // with: { - // account: true, - // }, - }); - if (!user) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "User not found", - }); - } - return user; + const user = await db.query.users_temp.findFirst({ + where: eq(users_temp.id, userId), + // with: { + // account: true, + // }, + }); + if (!user) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "User not found", + }); + } + return user; }; export const updateUser = async (userId: string, userData: Partial) => { - const user = await db - .update(users_temp) - .set({ - ...userData, - }) - .where(eq(users_temp.id, userId)) - .returning() - .then((res) => res[0]); + const user = await db + .update(users_temp) + .set({ + ...userData, + }) + .where(eq(users_temp.id, userId)) + .returning() + .then((res) => res[0]); - return user; + return user; }; export const updateAdminById = async ( - adminId: string, - adminData: Partial, + adminId: string, + adminData: Partial ) => { - const admin = await db - .update(admins) - .set({ - ...adminData, - }) - .where(eq(admins.adminId, adminId)) - .returning() - .then((res) => res[0]); + const admin = await db + .update(admins) + .set({ + ...adminData, + }) + .where(eq(admins.adminId, adminId)) + .returning() + .then((res) => res[0]); - return admin; + return admin; }; export const findAdminById = async (userId: string) => { - const admin = await db.query.admins.findFirst({ - where: eq(admins.userId, userId), - }); - return admin; + const admin = await db.query.admins.findFirst({ + where: eq(admins.userId, userId), + }); + return admin; }; export const isAdminPresent = async () => { - const admin = await db.query.user.findFirst({ - where: eq(user.role, "admin"), - }); - if (!admin) { - return false; - } - return true; + const admin = await db.query.users_temp.findFirst({ + where: eq(users_temp.role, "admin"), + }); + if (!admin) { + return false; + } + return true; }; export const findAdminByAuthId = async (authId: string) => { - const admin = await db.query.admins.findFirst({ - where: eq(admins.authId, authId), - with: { - users: true, - }, - }); - if (!admin) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Admin not found", - }); - } - return admin; + const admin = await db.query.admins.findFirst({ + where: eq(admins.authId, authId), + with: { + users: true, + }, + }); + if (!admin) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Admin not found", + }); + } + return admin; }; export const findAdmin = async () => { - const admin = await db.query.admins.findFirst({}); - if (!admin) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Admin not found", - }); - } - return admin; + const admin = await db.query.admins.findFirst({}); + if (!admin) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Admin not found", + }); + } + return admin; }; export const getUserByToken = async (token: string) => { - const user = await db.query.users.findFirst({ - where: eq(users.token, token), - with: { - auth: { - columns: { - password: false, - }, - }, - }, - }); + const user = await db.query.users.findFirst({ + where: eq(users.token, token), + with: { + auth: { + columns: { + password: false, + }, + }, + }, + }); - if (!user) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Invitation not found", - }); - } - return { - ...user, - isExpired: user.isRegistered, - }; + if (!user) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Invitation not found", + }); + } + return { + ...user, + isExpired: user.isRegistered, + }; }; export const removeUserById = async (userId: string) => { - await db - .delete(users_temp) - .where(eq(users_temp.id, userId)) - .returning() - .then((res) => res[0]); + await db + .delete(users_temp) + .where(eq(users_temp.id, userId)) + .returning() + .then((res) => res[0]); }; export const removeAdminByAuthId = async (authId: string) => { - const admin = await findAdminByAuthId(authId); - if (!admin) return null; + const admin = await findAdminByAuthId(authId); + if (!admin) return null; - // First delete all associated users - const users = admin.users; + // First delete all associated users + const users = admin.users; - for (const user of users) { - await removeUserById(user.id); - } - // Then delete the auth record which will cascade delete the admin - return await db - .delete(auth) - .where(eq(auth.id, authId)) - .returning() - .then((res) => res[0]); + for (const user of users) { + await removeUserById(user.id); + } + // Then delete the auth record which will cascade delete the admin + return await db + .delete(auth) + .where(eq(auth.id, authId)) + .returning() + .then((res) => res[0]); }; export const getDokployUrl = async () => { - if (IS_CLOUD) { - return "https://app.dokploy.com"; - } - const admin = await findAdmin(); + if (IS_CLOUD) { + return "https://app.dokploy.com"; + } + const admin = await findAdmin(); - if (admin.host) { - return `https://${admin.host}`; - } - return `http://${admin.serverIp}:${process.env.PORT}`; + if (admin.host) { + return `https://${admin.host}`; + } + return `http://${admin.serverIp}:${process.env.PORT}`; }; From 1bbb4c9b6429f45889f84c798fa8fb58be91aa08 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 18:13:20 -0600 Subject: [PATCH 22/89] refactor: update migration --- apps/dokploy/drizzle/0066_yielding_echo.sql | 1 - apps/dokploy/drizzle/0067_migrate-data.sql | 27 +- apps/dokploy/drizzle/0069_broad_ken_ellis.sql | 2 + apps/dokploy/drizzle/0069_known_aqueduct.sql | 1 - .../drizzle/0070_overrated_the_stranger.sql | 1 - apps/dokploy/drizzle/meta/0066_snapshot.json | 6 - apps/dokploy/drizzle/meta/0067_snapshot.json | 6 - apps/dokploy/drizzle/meta/0068_snapshot.json | 6 - apps/dokploy/drizzle/meta/0069_snapshot.json | 11 +- apps/dokploy/drizzle/meta/0070_snapshot.json | 5286 ----------------- apps/dokploy/drizzle/meta/_journal.json | 11 +- apps/dokploy/drizzle/old_migration | 278 - packages/server/src/db/schema/user.ts | 1 - 13 files changed, 28 insertions(+), 5609 deletions(-) create mode 100644 apps/dokploy/drizzle/0069_broad_ken_ellis.sql delete mode 100644 apps/dokploy/drizzle/0069_known_aqueduct.sql delete mode 100644 apps/dokploy/drizzle/0070_overrated_the_stranger.sql delete mode 100644 apps/dokploy/drizzle/meta/0070_snapshot.json delete mode 100644 apps/dokploy/drizzle/old_migration diff --git a/apps/dokploy/drizzle/0066_yielding_echo.sql b/apps/dokploy/drizzle/0066_yielding_echo.sql index 20f9d07b9..c66e2318b 100644 --- a/apps/dokploy/drizzle/0066_yielding_echo.sql +++ b/apps/dokploy/drizzle/0066_yielding_echo.sql @@ -19,7 +19,6 @@ CREATE TABLE "user_temp" ( "email" text NOT NULL, "email_verified" boolean NOT NULL, "image" text, - "role" text, "banned" boolean, "ban_reason" text, "ban_expires" timestamp, diff --git a/apps/dokploy/drizzle/0067_migrate-data.sql b/apps/dokploy/drizzle/0067_migrate-data.sql index 2057bd965..074de9fa6 100644 --- a/apps/dokploy/drizzle/0067_migrate-data.sql +++ b/apps/dokploy/drizzle/0067_migrate-data.sql @@ -8,7 +8,6 @@ WITH inserted_users AS ( token, "email_verified", "updated_at", - role, "serverIp", image, "certificateType", @@ -34,7 +33,6 @@ WITH inserted_users AS ( COALESCE(auth.token, ''), true, CURRENT_TIMESTAMP, - 'admin', a."serverIp", auth.image, a."certificateType", @@ -109,7 +107,6 @@ inserted_members AS ( token, "email_verified", "updated_at", - role, image, "createdAt", "canAccessToAPI", @@ -131,7 +128,6 @@ inserted_members AS ( COALESCE(u.token, ''), true, CURRENT_TIMESTAMP, - 'user', auth.image, NOW(), COALESCE(u."canAccessToAPI", false), @@ -176,8 +172,27 @@ inserted_member_accounts AS ( JOIN admin a ON u."adminId" = a."adminId" JOIN auth ON auth.id = u."authId" RETURNING * +), +inserted_admin_members AS ( + -- Insertar miembros en las organizaciones (admins como owners) + INSERT INTO member ( + id, + "organization_id", + "user_id", + role, + "created_at" + ) + SELECT + gen_random_uuid(), + o.id, + a."adminId", + 'owner', + NOW() + FROM admin a + JOIN inserted_orgs o ON o."owner_id" = a."adminId" + RETURNING * ) --- Insertar miembros en las organizaciones +-- Insertar miembros regulares en las organizaciones INSERT INTO member ( id, "organization_id", @@ -189,7 +204,7 @@ SELECT gen_random_uuid(), o.id, u."userId", - 'admin', + 'member', NOW() FROM "user" u JOIN admin a ON u."adminId" = a."adminId" diff --git a/apps/dokploy/drizzle/0069_broad_ken_ellis.sql b/apps/dokploy/drizzle/0069_broad_ken_ellis.sql new file mode 100644 index 000000000..3e2c918bd --- /dev/null +++ b/apps/dokploy/drizzle/0069_broad_ken_ellis.sql @@ -0,0 +1,2 @@ +ALTER TABLE "user_temp" ALTER COLUMN "token" SET DEFAULT '';--> statement-breakpoint +ALTER TABLE "user_temp" ADD COLUMN "created_at" timestamp DEFAULT now(); \ No newline at end of file diff --git a/apps/dokploy/drizzle/0069_known_aqueduct.sql b/apps/dokploy/drizzle/0069_known_aqueduct.sql deleted file mode 100644 index d6f4dea76..000000000 --- a/apps/dokploy/drizzle/0069_known_aqueduct.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "user_temp" ADD COLUMN "created_at" timestamp DEFAULT now(); \ No newline at end of file diff --git a/apps/dokploy/drizzle/0070_overrated_the_stranger.sql b/apps/dokploy/drizzle/0070_overrated_the_stranger.sql deleted file mode 100644 index dab91327b..000000000 --- a/apps/dokploy/drizzle/0070_overrated_the_stranger.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "user_temp" ALTER COLUMN "token" SET DEFAULT ''; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0066_snapshot.json b/apps/dokploy/drizzle/meta/0066_snapshot.json index c51e03851..bcb7807a7 100644 --- a/apps/dokploy/drizzle/meta/0066_snapshot.json +++ b/apps/dokploy/drizzle/meta/0066_snapshot.json @@ -1028,12 +1028,6 @@ "primaryKey": false, "notNull": false }, - "role": { - "name": "role", - "type": "text", - "primaryKey": false, - "notNull": false - }, "banned": { "name": "banned", "type": "boolean", diff --git a/apps/dokploy/drizzle/meta/0067_snapshot.json b/apps/dokploy/drizzle/meta/0067_snapshot.json index 33fc48703..69d4a4ee8 100644 --- a/apps/dokploy/drizzle/meta/0067_snapshot.json +++ b/apps/dokploy/drizzle/meta/0067_snapshot.json @@ -1028,12 +1028,6 @@ "primaryKey": false, "notNull": false }, - "role": { - "name": "role", - "type": "text", - "primaryKey": false, - "notNull": false - }, "banned": { "name": "banned", "type": "boolean", diff --git a/apps/dokploy/drizzle/meta/0068_snapshot.json b/apps/dokploy/drizzle/meta/0068_snapshot.json index c9f50b5ee..02e33084f 100644 --- a/apps/dokploy/drizzle/meta/0068_snapshot.json +++ b/apps/dokploy/drizzle/meta/0068_snapshot.json @@ -1028,12 +1028,6 @@ "primaryKey": false, "notNull": false }, - "role": { - "name": "role", - "type": "text", - "primaryKey": false, - "notNull": false - }, "banned": { "name": "banned", "type": "boolean", diff --git a/apps/dokploy/drizzle/meta/0069_snapshot.json b/apps/dokploy/drizzle/meta/0069_snapshot.json index 084216167..41b53582e 100644 --- a/apps/dokploy/drizzle/meta/0069_snapshot.json +++ b/apps/dokploy/drizzle/meta/0069_snapshot.json @@ -1,5 +1,5 @@ { - "id": "82a6a31d-7611-410d-8a32-31a36ab369c5", + "id": "e0842a94-530d-4a3c-a6b1-16cf37618b8b", "prevId": "c2e134de-9865-4892-a24d-048aa5be22e8", "version": "7", "dialect": "postgresql", @@ -912,7 +912,8 @@ "name": "token", "type": "text", "primaryKey": false, - "notNull": true + "notNull": true, + "default": "''" }, "isRegistered": { "name": "isRegistered", @@ -1035,12 +1036,6 @@ "primaryKey": false, "notNull": false }, - "role": { - "name": "role", - "type": "text", - "primaryKey": false, - "notNull": false - }, "banned": { "name": "banned", "type": "boolean", diff --git a/apps/dokploy/drizzle/meta/0070_snapshot.json b/apps/dokploy/drizzle/meta/0070_snapshot.json deleted file mode 100644 index b0a1eea7c..000000000 --- a/apps/dokploy/drizzle/meta/0070_snapshot.json +++ /dev/null @@ -1,5286 +0,0 @@ -{ - "id": "c01cab17-e046-4691-b5ab-43f6a92879d4", - "prevId": "82a6a31d-7611-410d-8a32-31a36ab369c5", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.application": { - "name": "application", - "schema": "", - "columns": { - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "previewEnv": { - "name": "previewEnv", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "previewBuildArgs": { - "name": "previewBuildArgs", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "previewWildcard": { - "name": "previewWildcard", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "previewPort": { - "name": "previewPort", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 3000 - }, - "previewHttps": { - "name": "previewHttps", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "previewPath": { - "name": "previewPath", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'/'" - }, - "certificateType": { - "name": "certificateType", - "type": "certificateType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'none'" - }, - "previewLimit": { - "name": "previewLimit", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 3 - }, - "isPreviewDeploymentsActive": { - "name": "isPreviewDeploymentsActive", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "buildArgs": { - "name": "buildArgs", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "subtitle": { - "name": "subtitle", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "refreshToken": { - "name": "refreshToken", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sourceType": { - "name": "sourceType", - "type": "sourceType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'github'" - }, - "repository": { - "name": "repository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "owner": { - "name": "owner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "branch": { - "name": "branch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "buildPath": { - "name": "buildPath", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'/'" - }, - "autoDeploy": { - "name": "autoDeploy", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "gitlabProjectId": { - "name": "gitlabProjectId", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "gitlabRepository": { - "name": "gitlabRepository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabOwner": { - "name": "gitlabOwner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabBranch": { - "name": "gitlabBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabBuildPath": { - "name": "gitlabBuildPath", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'/'" - }, - "gitlabPathNamespace": { - "name": "gitlabPathNamespace", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketRepository": { - "name": "bitbucketRepository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketOwner": { - "name": "bitbucketOwner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketBranch": { - "name": "bitbucketBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketBuildPath": { - "name": "bitbucketBuildPath", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'/'" - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "registryUrl": { - "name": "registryUrl", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitUrl": { - "name": "customGitUrl", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitBranch": { - "name": "customGitBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitBuildPath": { - "name": "customGitBuildPath", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitSSHKeyId": { - "name": "customGitSSHKeyId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dockerfile": { - "name": "dockerfile", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dockerContextPath": { - "name": "dockerContextPath", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dockerBuildStage": { - "name": "dockerBuildStage", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dropBuildPath": { - "name": "dropBuildPath", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "healthCheckSwarm": { - "name": "healthCheckSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "restartPolicySwarm": { - "name": "restartPolicySwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "placementSwarm": { - "name": "placementSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "updateConfigSwarm": { - "name": "updateConfigSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "rollbackConfigSwarm": { - "name": "rollbackConfigSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "modeSwarm": { - "name": "modeSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "labelsSwarm": { - "name": "labelsSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "networkSwarm": { - "name": "networkSwarm", - "type": "json", - "primaryKey": false, - "notNull": false - }, - "replicas": { - "name": "replicas", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 1 - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "buildType": { - "name": "buildType", - "type": "buildType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'nixpacks'" - }, - "herokuVersion": { - "name": "herokuVersion", - "type": "text", - "primaryKey": false, - "notNull": false, - "default": "'24'" - }, - "publishDirectory": { - "name": "publishDirectory", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "registryId": { - "name": "registryId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "githubId": { - "name": "githubId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabId": { - "name": "gitlabId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketId": { - "name": "bitbucketId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { - "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", - "tableFrom": "application", - "tableTo": "ssh-key", - "columnsFrom": [ - "customGitSSHKeyId" - ], - "columnsTo": [ - "sshKeyId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "application_registryId_registry_registryId_fk": { - "name": "application_registryId_registry_registryId_fk", - "tableFrom": "application", - "tableTo": "registry", - "columnsFrom": [ - "registryId" - ], - "columnsTo": [ - "registryId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "application_projectId_project_projectId_fk": { - "name": "application_projectId_project_projectId_fk", - "tableFrom": "application", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "application_githubId_github_githubId_fk": { - "name": "application_githubId_github_githubId_fk", - "tableFrom": "application", - "tableTo": "github", - "columnsFrom": [ - "githubId" - ], - "columnsTo": [ - "githubId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "application_gitlabId_gitlab_gitlabId_fk": { - "name": "application_gitlabId_gitlab_gitlabId_fk", - "tableFrom": "application", - "tableTo": "gitlab", - "columnsFrom": [ - "gitlabId" - ], - "columnsTo": [ - "gitlabId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "application_bitbucketId_bitbucket_bitbucketId_fk": { - "name": "application_bitbucketId_bitbucket_bitbucketId_fk", - "tableFrom": "application", - "tableTo": "bitbucket", - "columnsFrom": [ - "bitbucketId" - ], - "columnsTo": [ - "bitbucketId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "application_serverId_server_serverId_fk": { - "name": "application_serverId_server_serverId_fk", - "tableFrom": "application", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "application_appName_unique": { - "name": "application_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.postgres": { - "name": "postgres", - "schema": "", - "columns": { - "postgresId": { - "name": "postgresId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databaseName": { - "name": "databaseName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databaseUser": { - "name": "databaseUser", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databasePassword": { - "name": "databasePassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "externalPort": { - "name": "externalPort", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "postgres_projectId_project_projectId_fk": { - "name": "postgres_projectId_project_projectId_fk", - "tableFrom": "postgres", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "postgres_serverId_server_serverId_fk": { - "name": "postgres_serverId_server_serverId_fk", - "tableFrom": "postgres", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "postgres_appName_unique": { - "name": "postgres_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "userId": { - "name": "userId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "isRegistered": { - "name": "isRegistered", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "expirationDate": { - "name": "expirationDate", - "type": "timestamp(3)", - "primaryKey": false, - "notNull": true - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "canCreateProjects": { - "name": "canCreateProjects", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canAccessToSSHKeys": { - "name": "canAccessToSSHKeys", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canCreateServices": { - "name": "canCreateServices", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canDeleteProjects": { - "name": "canDeleteProjects", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canDeleteServices": { - "name": "canDeleteServices", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canAccessToDocker": { - "name": "canAccessToDocker", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canAccessToAPI": { - "name": "canAccessToAPI", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canAccessToGitProviders": { - "name": "canAccessToGitProviders", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "canAccessToTraefikFiles": { - "name": "canAccessToTraefikFiles", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "accesedProjects": { - "name": "accesedProjects", - "type": "text[]", - "primaryKey": false, - "notNull": true, - "default": "ARRAY[]::text[]" - }, - "accesedServices": { - "name": "accesedServices", - "type": "text[]", - "primaryKey": false, - "notNull": true, - "default": "ARRAY[]::text[]" - }, - "adminId": { - "name": "adminId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "authId": { - "name": "authId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_adminId_admin_adminId_fk": { - "name": "user_adminId_admin_adminId_fk", - "tableFrom": "user", - "tableTo": "admin", - "columnsFrom": [ - "adminId" - ], - "columnsTo": [ - "adminId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "user_authId_auth_id_fk": { - "name": "user_authId_auth_id_fk", - "tableFrom": "user", - "tableTo": "auth", - "columnsFrom": [ - "authId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.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": "''" - }, - "token": { - "name": "token", - "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()" - }, - "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[]" - }, - "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 - }, - "role": { - "name": "role", - "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'" - }, - "host": { - "name": "host", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "letsEncryptEmail": { - "name": "letsEncryptEmail", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sshPrivateKey": { - "name": "sshPrivateKey", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "enableDockerCleanup": { - "name": "enableDockerCleanup", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "enableLogRotation": { - "name": "enableLogRotation", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "enablePaidFeatures": { - "name": "enablePaidFeatures", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "metricsConfig": { - "name": "metricsConfig", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" - }, - "cleanupCacheApplications": { - "name": "cleanupCacheApplications", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "cleanupCacheOnPreviews": { - "name": "cleanupCacheOnPreviews", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "cleanupCacheOnCompose": { - "name": "cleanupCacheOnCompose", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "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.admin": { - "name": "admin", - "schema": "", - "columns": { - "adminId": { - "name": "adminId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "serverIp": { - "name": "serverIp", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "certificateType": { - "name": "certificateType", - "type": "certificateType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'none'" - }, - "host": { - "name": "host", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "letsEncryptEmail": { - "name": "letsEncryptEmail", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sshPrivateKey": { - "name": "sshPrivateKey", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "enableDockerCleanup": { - "name": "enableDockerCleanup", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "enableLogRotation": { - "name": "enableLogRotation", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "authId": { - "name": "authId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "stripeCustomerId": { - "name": "stripeCustomerId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "stripeSubscriptionId": { - "name": "stripeSubscriptionId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "serversQuantity": { - "name": "serversQuantity", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "enablePaidFeatures": { - "name": "enablePaidFeatures", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "metricsConfig": { - "name": "metricsConfig", - "type": "jsonb", - "primaryKey": false, - "notNull": true, - "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" - }, - "cleanupCacheApplications": { - "name": "cleanupCacheApplications", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "cleanupCacheOnPreviews": { - "name": "cleanupCacheOnPreviews", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "cleanupCacheOnCompose": { - "name": "cleanupCacheOnCompose", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - } - }, - "indexes": {}, - "foreignKeys": { - "admin_authId_auth_id_fk": { - "name": "admin_authId_auth_id_fk", - "tableFrom": "admin", - "tableTo": "auth", - "columnsFrom": [ - "authId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.auth": { - "name": "auth", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "rol": { - "name": "rol", - "type": "Roles", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "image": { - "name": "image", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "secret": { - "name": "secret", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "is2FAEnabled": { - "name": "is2FAEnabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "resetPasswordToken": { - "name": "resetPasswordToken", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "resetPasswordExpiresAt": { - "name": "resetPasswordExpiresAt", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "confirmationToken": { - "name": "confirmationToken", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "confirmationExpiresAt": { - "name": "confirmationExpiresAt", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "auth_email_unique": { - "name": "auth_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.project": { - "name": "project", - "schema": "", - "columns": { - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" - } - }, - "indexes": {}, - "foreignKeys": { - "project_userId_user_temp_id_fk": { - "name": "project_userId_user_temp_id_fk", - "tableFrom": "project", - "tableTo": "user_temp", - "columnsFrom": [ - "userId" - ], - "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 - }, - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "previewDeploymentId": { - "name": "previewDeploymentId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "certificateType": { - "name": "certificateType", - "type": "certificateType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'none'" - } - }, - "indexes": {}, - "foreignKeys": { - "domain_composeId_compose_composeId_fk": { - "name": "domain_composeId_compose_composeId_fk", - "tableFrom": "domain", - "tableTo": "compose", - "columnsFrom": [ - "composeId" - ], - "columnsTo": [ - "composeId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "domain_applicationId_application_applicationId_fk": { - "name": "domain_applicationId_application_applicationId_fk", - "tableFrom": "domain", - "tableTo": "application", - "columnsFrom": [ - "applicationId" - ], - "columnsTo": [ - "applicationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { - "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", - "tableFrom": "domain", - "tableTo": "preview_deployments", - "columnsFrom": [ - "previewDeploymentId" - ], - "columnsTo": [ - "previewDeploymentId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.mariadb": { - "name": "mariadb", - "schema": "", - "columns": { - "mariadbId": { - "name": "mariadbId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "databaseName": { - "name": "databaseName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databaseUser": { - "name": "databaseUser", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databasePassword": { - "name": "databasePassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "rootPassword": { - "name": "rootPassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "externalPort": { - "name": "externalPort", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "mariadb_projectId_project_projectId_fk": { - "name": "mariadb_projectId_project_projectId_fk", - "tableFrom": "mariadb", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mariadb_serverId_server_serverId_fk": { - "name": "mariadb_serverId_server_serverId_fk", - "tableFrom": "mariadb", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "mariadb_appName_unique": { - "name": "mariadb_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.mongo": { - "name": "mongo", - "schema": "", - "columns": { - "mongoId": { - "name": "mongoId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "databaseUser": { - "name": "databaseUser", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databasePassword": { - "name": "databasePassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "externalPort": { - "name": "externalPort", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "replicaSets": { - "name": "replicaSets", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - } - }, - "indexes": {}, - "foreignKeys": { - "mongo_projectId_project_projectId_fk": { - "name": "mongo_projectId_project_projectId_fk", - "tableFrom": "mongo", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mongo_serverId_server_serverId_fk": { - "name": "mongo_serverId_server_serverId_fk", - "tableFrom": "mongo", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "mongo_appName_unique": { - "name": "mongo_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.mysql": { - "name": "mysql", - "schema": "", - "columns": { - "mysqlId": { - "name": "mysqlId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "databaseName": { - "name": "databaseName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databaseUser": { - "name": "databaseUser", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databasePassword": { - "name": "databasePassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "rootPassword": { - "name": "rootPassword", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "externalPort": { - "name": "externalPort", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "mysql_projectId_project_projectId_fk": { - "name": "mysql_projectId_project_projectId_fk", - "tableFrom": "mysql", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mysql_serverId_server_serverId_fk": { - "name": "mysql_serverId_server_serverId_fk", - "tableFrom": "mysql", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "mysql_appName_unique": { - "name": "mysql_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.backup": { - "name": "backup", - "schema": "", - "columns": { - "backupId": { - "name": "backupId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "schedule": { - "name": "schedule", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "database": { - "name": "database", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "prefix": { - "name": "prefix", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "destinationId": { - "name": "destinationId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "databaseType": { - "name": "databaseType", - "type": "databaseType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "postgresId": { - "name": "postgresId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mariadbId": { - "name": "mariadbId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mysqlId": { - "name": "mysqlId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mongoId": { - "name": "mongoId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "backup_destinationId_destination_destinationId_fk": { - "name": "backup_destinationId_destination_destinationId_fk", - "tableFrom": "backup", - "tableTo": "destination", - "columnsFrom": [ - "destinationId" - ], - "columnsTo": [ - "destinationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "backup_postgresId_postgres_postgresId_fk": { - "name": "backup_postgresId_postgres_postgresId_fk", - "tableFrom": "backup", - "tableTo": "postgres", - "columnsFrom": [ - "postgresId" - ], - "columnsTo": [ - "postgresId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "backup_mariadbId_mariadb_mariadbId_fk": { - "name": "backup_mariadbId_mariadb_mariadbId_fk", - "tableFrom": "backup", - "tableTo": "mariadb", - "columnsFrom": [ - "mariadbId" - ], - "columnsTo": [ - "mariadbId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "backup_mysqlId_mysql_mysqlId_fk": { - "name": "backup_mysqlId_mysql_mysqlId_fk", - "tableFrom": "backup", - "tableTo": "mysql", - "columnsFrom": [ - "mysqlId" - ], - "columnsTo": [ - "mysqlId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "backup_mongoId_mongo_mongoId_fk": { - "name": "backup_mongoId_mongo_mongoId_fk", - "tableFrom": "backup", - "tableTo": "mongo", - "columnsFrom": [ - "mongoId" - ], - "columnsTo": [ - "mongoId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.destination": { - "name": "destination", - "schema": "", - "columns": { - "destinationId": { - "name": "destinationId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "provider": { - "name": "provider", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "accessKey": { - "name": "accessKey", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "secretAccessKey": { - "name": "secretAccessKey", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "bucket": { - "name": "bucket", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "region": { - "name": "region", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "endpoint": { - "name": "endpoint", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "destination_userId_user_temp_id_fk": { - "name": "destination_userId_user_temp_id_fk", - "tableFrom": "destination", - "tableTo": "user_temp", - "columnsFrom": [ - "userId" - ], - "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 - }, - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "composeId": { - "name": "composeId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "isPreviewDeployment": { - "name": "isPreviewDeployment", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "previewDeploymentId": { - "name": "previewDeploymentId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "errorMessage": { - "name": "errorMessage", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "deployment_applicationId_application_applicationId_fk": { - "name": "deployment_applicationId_application_applicationId_fk", - "tableFrom": "deployment", - "tableTo": "application", - "columnsFrom": [ - "applicationId" - ], - "columnsTo": [ - "applicationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "deployment_composeId_compose_composeId_fk": { - "name": "deployment_composeId_compose_composeId_fk", - "tableFrom": "deployment", - "tableTo": "compose", - "columnsFrom": [ - "composeId" - ], - "columnsTo": [ - "composeId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "deployment_serverId_server_serverId_fk": { - "name": "deployment_serverId_server_serverId_fk", - "tableFrom": "deployment", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { - "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", - "tableFrom": "deployment", - "tableTo": "preview_deployments", - "columnsFrom": [ - "previewDeploymentId" - ], - "columnsTo": [ - "previewDeploymentId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.mount": { - "name": "mount", - "schema": "", - "columns": { - "mountId": { - "name": "mountId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "type": { - "name": "type", - "type": "mountType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "hostPath": { - "name": "hostPath", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "volumeName": { - "name": "volumeName", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "filePath": { - "name": "filePath", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "content": { - "name": "content", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "serviceType": { - "name": "serviceType", - "type": "serviceType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'application'" - }, - "mountPath": { - "name": "mountPath", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "postgresId": { - "name": "postgresId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mariadbId": { - "name": "mariadbId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mongoId": { - "name": "mongoId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "mysqlId": { - "name": "mysqlId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "redisId": { - "name": "redisId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "composeId": { - "name": "composeId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "mount_applicationId_application_applicationId_fk": { - "name": "mount_applicationId_application_applicationId_fk", - "tableFrom": "mount", - "tableTo": "application", - "columnsFrom": [ - "applicationId" - ], - "columnsTo": [ - "applicationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_postgresId_postgres_postgresId_fk": { - "name": "mount_postgresId_postgres_postgresId_fk", - "tableFrom": "mount", - "tableTo": "postgres", - "columnsFrom": [ - "postgresId" - ], - "columnsTo": [ - "postgresId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_mariadbId_mariadb_mariadbId_fk": { - "name": "mount_mariadbId_mariadb_mariadbId_fk", - "tableFrom": "mount", - "tableTo": "mariadb", - "columnsFrom": [ - "mariadbId" - ], - "columnsTo": [ - "mariadbId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_mongoId_mongo_mongoId_fk": { - "name": "mount_mongoId_mongo_mongoId_fk", - "tableFrom": "mount", - "tableTo": "mongo", - "columnsFrom": [ - "mongoId" - ], - "columnsTo": [ - "mongoId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_mysqlId_mysql_mysqlId_fk": { - "name": "mount_mysqlId_mysql_mysqlId_fk", - "tableFrom": "mount", - "tableTo": "mysql", - "columnsFrom": [ - "mysqlId" - ], - "columnsTo": [ - "mysqlId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_redisId_redis_redisId_fk": { - "name": "mount_redisId_redis_redisId_fk", - "tableFrom": "mount", - "tableTo": "redis", - "columnsFrom": [ - "redisId" - ], - "columnsTo": [ - "redisId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "mount_composeId_compose_composeId_fk": { - "name": "mount_composeId_compose_composeId_fk", - "tableFrom": "mount", - "tableTo": "compose", - "columnsFrom": [ - "composeId" - ], - "columnsTo": [ - "composeId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.certificate": { - "name": "certificate", - "schema": "", - "columns": { - "certificateId": { - "name": "certificateId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "certificateData": { - "name": "certificateData", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "privateKey": { - "name": "privateKey", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "certificatePath": { - "name": "certificatePath", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "autoRenew": { - "name": "autoRenew", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "certificate_userId_user_temp_id_fk": { - "name": "certificate_userId_user_temp_id_fk", - "tableFrom": "certificate", - "tableTo": "user_temp", - "columnsFrom": [ - "userId" - ], - "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": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "session_temp_token_unique": { - "name": "session_temp_token_unique", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.session": { - "name": "session", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "session_user_id_auth_id_fk": { - "name": "session_user_id_auth_id_fk", - "tableFrom": "session", - "tableTo": "auth", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.redirect": { - "name": "redirect", - "schema": "", - "columns": { - "redirectId": { - "name": "redirectId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "regex": { - "name": "regex", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "replacement": { - "name": "replacement", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "permanent": { - "name": "permanent", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "uniqueConfigKey": { - "name": "uniqueConfigKey", - "type": "serial", - "primaryKey": false, - "notNull": true - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "redirect_applicationId_application_applicationId_fk": { - "name": "redirect_applicationId_application_applicationId_fk", - "tableFrom": "redirect", - "tableTo": "application", - "columnsFrom": [ - "applicationId" - ], - "columnsTo": [ - "applicationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.security": { - "name": "security", - "schema": "", - "columns": { - "securityId": { - "name": "securityId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "security_applicationId_application_applicationId_fk": { - "name": "security_applicationId_application_applicationId_fk", - "tableFrom": "security", - "tableTo": "application", - "columnsFrom": [ - "applicationId" - ], - "columnsTo": [ - "applicationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "security_username_applicationId_unique": { - "name": "security_username_applicationId_unique", - "nullsNotDistinct": false, - "columns": [ - "username", - "applicationId" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.port": { - "name": "port", - "schema": "", - "columns": { - "portId": { - "name": "portId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "publishedPort": { - "name": "publishedPort", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "targetPort": { - "name": "targetPort", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "protocol": { - "name": "protocol", - "type": "protocolType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true - }, - "applicationId": { - "name": "applicationId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "port_applicationId_application_applicationId_fk": { - "name": "port_applicationId_application_applicationId_fk", - "tableFrom": "port", - "tableTo": "application", - "columnsFrom": [ - "applicationId" - ], - "columnsTo": [ - "applicationId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.redis": { - "name": "redis", - "schema": "", - "columns": { - "redisId": { - "name": "redisId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dockerImage": { - "name": "dockerImage", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryReservation": { - "name": "memoryReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "memoryLimit": { - "name": "memoryLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuReservation": { - "name": "cpuReservation", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "cpuLimit": { - "name": "cpuLimit", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "externalPort": { - "name": "externalPort", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "applicationStatus": { - "name": "applicationStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "redis_projectId_project_projectId_fk": { - "name": "redis_projectId_project_projectId_fk", - "tableFrom": "redis", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "redis_serverId_server_serverId_fk": { - "name": "redis_serverId_server_serverId_fk", - "tableFrom": "redis", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "redis_appName_unique": { - "name": "redis_appName_unique", - "nullsNotDistinct": false, - "columns": [ - "appName" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.compose": { - "name": "compose", - "schema": "", - "columns": { - "composeId": { - "name": "composeId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "appName": { - "name": "appName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "env": { - "name": "env", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "composeFile": { - "name": "composeFile", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" - }, - "refreshToken": { - "name": "refreshToken", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sourceType": { - "name": "sourceType", - "type": "sourceTypeCompose", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'github'" - }, - "composeType": { - "name": "composeType", - "type": "composeType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'docker-compose'" - }, - "repository": { - "name": "repository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "owner": { - "name": "owner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "branch": { - "name": "branch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "autoDeploy": { - "name": "autoDeploy", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "gitlabProjectId": { - "name": "gitlabProjectId", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "gitlabRepository": { - "name": "gitlabRepository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabOwner": { - "name": "gitlabOwner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabBranch": { - "name": "gitlabBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabPathNamespace": { - "name": "gitlabPathNamespace", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketRepository": { - "name": "bitbucketRepository", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketOwner": { - "name": "bitbucketOwner", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketBranch": { - "name": "bitbucketBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitUrl": { - "name": "customGitUrl", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitBranch": { - "name": "customGitBranch", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "customGitSSHKeyId": { - "name": "customGitSSHKeyId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "command": { - "name": "command", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" - }, - "composePath": { - "name": "composePath", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'./docker-compose.yml'" - }, - "suffix": { - "name": "suffix", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" - }, - "randomize": { - "name": "randomize", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "isolatedDeployment": { - "name": "isolatedDeployment", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "composeStatus": { - "name": "composeStatus", - "type": "applicationStatus", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'idle'" - }, - "projectId": { - "name": "projectId", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "githubId": { - "name": "githubId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "gitlabId": { - "name": "gitlabId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "bitbucketId": { - "name": "bitbucketId", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "serverId": { - "name": "serverId", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { - "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", - "tableFrom": "compose", - "tableTo": "ssh-key", - "columnsFrom": [ - "customGitSSHKeyId" - ], - "columnsTo": [ - "sshKeyId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "compose_projectId_project_projectId_fk": { - "name": "compose_projectId_project_projectId_fk", - "tableFrom": "compose", - "tableTo": "project", - "columnsFrom": [ - "projectId" - ], - "columnsTo": [ - "projectId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "compose_githubId_github_githubId_fk": { - "name": "compose_githubId_github_githubId_fk", - "tableFrom": "compose", - "tableTo": "github", - "columnsFrom": [ - "githubId" - ], - "columnsTo": [ - "githubId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "compose_gitlabId_gitlab_gitlabId_fk": { - "name": "compose_gitlabId_gitlab_gitlabId_fk", - "tableFrom": "compose", - "tableTo": "gitlab", - "columnsFrom": [ - "gitlabId" - ], - "columnsTo": [ - "gitlabId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "compose_bitbucketId_bitbucket_bitbucketId_fk": { - "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", - "tableFrom": "compose", - "tableTo": "bitbucket", - "columnsFrom": [ - "bitbucketId" - ], - "columnsTo": [ - "bitbucketId" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "compose_serverId_server_serverId_fk": { - "name": "compose_serverId_server_serverId_fk", - "tableFrom": "compose", - "tableTo": "server", - "columnsFrom": [ - "serverId" - ], - "columnsTo": [ - "serverId" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.registry": { - "name": "registry", - "schema": "", - "columns": { - "registryId": { - "name": "registryId", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "registryName": { - "name": "registryName", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "imagePrefix": { - "name": "imagePrefix", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "registryUrl": { - "name": "registryUrl", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" - }, - "createdAt": { - "name": "createdAt", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "selfHosted": { - "name": "selfHosted", - "type": "RegistryType", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'cloud'" - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "registry_userId_user_temp_id_fk": { - "name": "registry_userId_user_temp_id_fk", - "tableFrom": "registry", - "tableTo": "user_temp", - "columnsFrom": [ - "userId" - ], - "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 - }, - "userId": { - "name": "userId", - "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_userId_user_temp_id_fk": { - "name": "notification_userId_user_temp_id_fk", - "tableFrom": "notification", - "tableTo": "user_temp", - "columnsFrom": [ - "userId" - ], - "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 - } - }, - "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 - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "ssh-key_userId_user_temp_id_fk": { - "name": "ssh-key_userId_user_temp_id_fk", - "tableFrom": "ssh-key", - "tableTo": "user_temp", - "columnsFrom": [ - "userId" - ], - "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 - }, - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "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.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 - }, - "userId": { - "name": "userId", - "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_userId_user_temp_id_fk": { - "name": "server_userId_user_temp_id_fk", - "tableFrom": "server", - "tableTo": "user_temp", - "columnsFrom": [ - "userId" - ], - "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.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": "no action", - "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 - } - }, - "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": "no action", - "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": "no action", - "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 - } - }, - "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": "no action", - "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": "no action", - "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": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "organization_slug_unique": { - "name": "organization_slug_unique", - "nullsNotDistinct": false, - "columns": [ - "slug" - ] - } - }, - "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 - } - }, - "enums": { - "public.buildType": { - "name": "buildType", - "schema": "public", - "values": [ - "dockerfile", - "heroku_buildpacks", - "paketo_buildpacks", - "nixpacks", - "static" - ] - }, - "public.sourceType": { - "name": "sourceType", - "schema": "public", - "values": [ - "docker", - "git", - "github", - "gitlab", - "bitbucket", - "drop" - ] - }, - "public.Roles": { - "name": "Roles", - "schema": "public", - "values": [ - "admin", - "user" - ] - }, - "public.domainType": { - "name": "domainType", - "schema": "public", - "values": [ - "compose", - "application", - "preview" - ] - }, - "public.databaseType": { - "name": "databaseType", - "schema": "public", - "values": [ - "postgres", - "mariadb", - "mysql", - "mongo" - ] - }, - "public.deploymentStatus": { - "name": "deploymentStatus", - "schema": "public", - "values": [ - "running", - "done", - "error" - ] - }, - "public.mountType": { - "name": "mountType", - "schema": "public", - "values": [ - "bind", - "volume", - "file" - ] - }, - "public.serviceType": { - "name": "serviceType", - "schema": "public", - "values": [ - "application", - "postgres", - "mysql", - "mariadb", - "mongo", - "redis", - "compose" - ] - }, - "public.protocolType": { - "name": "protocolType", - "schema": "public", - "values": [ - "tcp", - "udp" - ] - }, - "public.applicationStatus": { - "name": "applicationStatus", - "schema": "public", - "values": [ - "idle", - "running", - "done", - "error" - ] - }, - "public.certificateType": { - "name": "certificateType", - "schema": "public", - "values": [ - "letsencrypt", - "none" - ] - }, - "public.composeType": { - "name": "composeType", - "schema": "public", - "values": [ - "docker-compose", - "stack" - ] - }, - "public.sourceTypeCompose": { - "name": "sourceTypeCompose", - "schema": "public", - "values": [ - "git", - "github", - "gitlab", - "bitbucket", - "raw" - ] - }, - "public.RegistryType": { - "name": "RegistryType", - "schema": "public", - "values": [ - "selfHosted", - "cloud" - ] - }, - "public.notificationType": { - "name": "notificationType", - "schema": "public", - "values": [ - "slack", - "telegram", - "discord", - "email", - "gotify" - ] - }, - "public.gitProviderType": { - "name": "gitProviderType", - "schema": "public", - "values": [ - "github", - "gitlab", - "bitbucket" - ] - }, - "public.serverStatus": { - "name": "serverStatus", - "schema": "public", - "values": [ - "active", - "inactive" - ] - } - }, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index d10d6816e..39934064c 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -488,15 +488,8 @@ { "idx": 69, "version": "7", - "when": 1739432476590, - "tag": "0069_known_aqueduct", - "breakpoints": true - }, - { - "idx": 70, - "version": "7", - "when": 1739432513877, - "tag": "0070_overrated_the_stranger", + "when": 1739664410814, + "tag": "0069_broad_ken_ellis", "breakpoints": true } ] diff --git a/apps/dokploy/drizzle/old_migration b/apps/dokploy/drizzle/old_migration deleted file mode 100644 index d7e3acf0e..000000000 --- a/apps/dokploy/drizzle/old_migration +++ /dev/null @@ -1,278 +0,0 @@ -CREATE TABLE "account" ( - "id" text PRIMARY KEY NOT NULL, - "account_id" text NOT NULL, - "provider_id" text NOT NULL, - "user_id" text NOT NULL, - "access_token" text, - "refresh_token" text, - "id_token" text, - "access_token_expires_at" timestamp, - "refresh_token_expires_at" timestamp, - "scope" text, - "password" text, - "is2FAEnabled" boolean DEFAULT false NOT NULL, - "created_at" timestamp NOT NULL, - "updated_at" timestamp NOT NULL, - "resetPasswordToken" text, - "resetPasswordExpiresAt" text, - "confirmationToken" text, - "confirmationExpiresAt" text -); - ---> statement-breakpoint -CREATE TABLE "verification" ( - "id" text PRIMARY KEY NOT NULL, - "identifier" text NOT NULL, - "value" text NOT NULL, - "expires_at" timestamp NOT NULL, - "created_at" timestamp, - "updated_at" timestamp -); - --- Primero eliminar las restricciones NOT NULL y foreign keys -ALTER TABLE "user" ALTER COLUMN "adminId" DROP NOT NULL; -ALTER TABLE "user" ALTER COLUMN "authId" DROP NOT NULL; - -ALTER TABLE "user" DROP CONSTRAINT IF EXISTS "user_adminId_admin_adminId_fk"; -ALTER TABLE "user" DROP CONSTRAINT IF EXISTS "user_authId_auth_id_fk"; -ALTER TABLE "admin" DROP CONSTRAINT IF EXISTS "admin_authId_auth_id_fk"; -ALTER TABLE "project" DROP CONSTRAINT IF EXISTS "project_adminId_admin_adminId_fk"; -ALTER TABLE "destination" DROP CONSTRAINT IF EXISTS "destination_adminId_admin_adminId_fk"; -ALTER TABLE "certificate" DROP CONSTRAINT IF EXISTS "certificate_adminId_admin_adminId_fk"; -ALTER TABLE "session" DROP CONSTRAINT IF EXISTS "session_user_id_auth_id_fk"; -ALTER TABLE "registry" DROP CONSTRAINT IF EXISTS "registry_adminId_admin_adminId_fk"; -ALTER TABLE "notification" DROP CONSTRAINT IF EXISTS "notification_adminId_admin_adminId_fk"; -ALTER TABLE "ssh-key" DROP CONSTRAINT IF EXISTS "ssh-key_adminId_admin_adminId_fk"; -ALTER TABLE "git_provider" DROP CONSTRAINT IF EXISTS "git_provider_adminId_admin_adminId_fk"; -ALTER TABLE "server" DROP CONSTRAINT IF EXISTS "server_adminId_admin_adminId_fk"; - --- Luego renombrar las columnas -ALTER TABLE "user" RENAME COLUMN "userId" TO "id"; -ALTER TABLE "project" RENAME COLUMN "adminId" TO "userId"; -ALTER TABLE "destination" RENAME COLUMN "adminId" TO "userId"; -ALTER TABLE "certificate" RENAME COLUMN "adminId" TO "userId"; -ALTER TABLE "registry" RENAME COLUMN "adminId" TO "userId"; -ALTER TABLE "notification" RENAME COLUMN "adminId" TO "userId"; -ALTER TABLE "ssh-key" RENAME COLUMN "adminId" TO "userId"; -ALTER TABLE "git_provider" RENAME COLUMN "adminId" TO "userId"; -ALTER TABLE "server" RENAME COLUMN "adminId" TO "userId"; - --- Primero agregar todas las columnas sin restricciones -ALTER TABLE "user" ADD COLUMN "name" text; -ALTER TABLE "user" ADD COLUMN "email" text; -ALTER TABLE "user" ADD COLUMN "email_verified" boolean; -ALTER TABLE "user" ADD COLUMN "image" text; -ALTER TABLE "user" ADD COLUMN "role" text; -ALTER TABLE "user" ADD COLUMN "banned" boolean; -ALTER TABLE "user" ADD COLUMN "ban_reason" text; -ALTER TABLE "user" ADD COLUMN "ban_expires" timestamp; -ALTER TABLE "user" ADD COLUMN "updated_at" timestamp; -ALTER TABLE "user" ADD COLUMN "serverIp" text; -ALTER TABLE "user" ADD COLUMN "certificateType" "certificateType" DEFAULT 'none'; -ALTER TABLE "user" ADD COLUMN "host" text; -ALTER TABLE "user" ADD COLUMN "letsEncryptEmail" text; -ALTER TABLE "user" ADD COLUMN "sshPrivateKey" text; -ALTER TABLE "user" ADD COLUMN "enableDockerCleanup" boolean DEFAULT false; -ALTER TABLE "user" ADD COLUMN "enableLogRotation" boolean DEFAULT false; -ALTER TABLE "user" ADD COLUMN "enablePaidFeatures" boolean DEFAULT false; -ALTER TABLE "user" ADD COLUMN "metricsConfig" jsonb DEFAULT '{"server":{"type":"Dokploy","refreshRate":60,"port":4500,"token":"","retentionDays":2,"cronJob":"","urlCallback":"","thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}'; -ALTER TABLE "user" ADD COLUMN "cleanupCacheApplications" boolean DEFAULT false; -ALTER TABLE "user" ADD COLUMN "cleanupCacheOnPreviews" boolean DEFAULT false; -ALTER TABLE "user" ADD COLUMN "cleanupCacheOnCompose" boolean DEFAULT false; - -ALTER TABLE "user" ALTER COLUMN "token" SET DEFAULT ''; -ALTER TABLE "user" ALTER COLUMN "expirationDate" SET DEFAULT CURRENT_TIMESTAMP + INTERVAL '1 year'; -ALTER TABLE "user" ALTER COLUMN "createdAt" SET DEFAULT to_char(CURRENT_TIMESTAMP, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'); - ---> statement-breakpoint --- Luego actualizar los valores nulos -UPDATE "user" SET token = '' WHERE token IS NULL; -UPDATE "user" SET "expirationDate" = CURRENT_TIMESTAMP + INTERVAL '1 year' WHERE "expirationDate" IS NULL; -UPDATE "user" SET "createdAt" = to_char(CURRENT_TIMESTAMP, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') WHERE "createdAt" IS NULL; -UPDATE "user" SET "name" = '' WHERE "name" IS NULL; --- Generar emails únicos para registros vacíos -UPDATE "user" SET "email" = CONCAT('user_', id, '@dokploy.local') WHERE "email" = '' OR "email" IS NULL; -UPDATE "user" SET "email_verified" = COALESCE("email_verified", false) WHERE true; -UPDATE "user" SET "role" = COALESCE("role", 'user') WHERE true; -UPDATE "user" SET "banned" = COALESCE("banned", false) WHERE true; -UPDATE "user" SET "updated_at" = COALESCE("updated_at", CURRENT_TIMESTAMP) WHERE true; -UPDATE "user" SET "certificateType" = COALESCE("certificateType", 'none') WHERE true; -UPDATE "user" SET "enableDockerCleanup" = COALESCE("enableDockerCleanup", false) WHERE true; -UPDATE "user" SET "enableLogRotation" = COALESCE("enableLogRotation", false) WHERE true; -UPDATE "user" SET "enablePaidFeatures" = COALESCE("enablePaidFeatures", false) WHERE true; -UPDATE "user" SET "metricsConfig" = COALESCE("metricsConfig", '{"server":{"type":"Dokploy","refreshRate":60,"port":4500,"token":"","retentionDays":2,"cronJob":"","urlCallback":"","thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}') WHERE true; -UPDATE "user" SET "cleanupCacheApplications" = COALESCE("cleanupCacheApplications", false) WHERE true; -UPDATE "user" SET "cleanupCacheOnPreviews" = COALESCE("cleanupCacheOnPreviews", false) WHERE true; -UPDATE "user" SET "cleanupCacheOnCompose" = COALESCE("cleanupCacheOnCompose", false) WHERE true; ---> statement-breakpoint - --- Migrar datos de auth a user -INSERT INTO "user" ( - id, - name, - email, - email_verified, - image, - role, - updated_at -) -SELECT - id, - '' as name, - email, - true as email_verified, - image, - CASE - WHEN rol = 'admin' THEN 'admin' - ELSE 'user' - END as role, - CAST("createdAt" AS timestamp) as updated_at -FROM "auth"; - --- Migrar datos de auth a account -INSERT INTO "account" ( - id, - account_id, - provider_id, - user_id, - password, - "is2FAEnabled", - created_at, - updated_at -) -SELECT - id as id, - id as account_id, - 'credentials' as provider_id, - id as user_id, - password, - "is2FAEnabled", - CAST("createdAt" AS timestamp) as created_at, - CAST("createdAt" AS timestamp) as updated_at -FROM "auth"; - --- Migrar datos de admin a user -UPDATE "user" u -SET - "serverIp" = a."serverIp", - "certificateType" = a."certificateType", - "host" = a."host", - "letsEncryptEmail" = a."letsEncryptEmail", - "sshPrivateKey" = a."sshPrivateKey", - "enableDockerCleanup" = a."enableDockerCleanup", - "enableLogRotation" = a."enableLogRotation", - "enablePaidFeatures" = a."enablePaidFeatures", - "metricsConfig" = a."metricsConfig", - "cleanupCacheApplications" = a."cleanupCacheApplications", - "cleanupCacheOnPreviews" = a."cleanupCacheOnPreviews", - "cleanupCacheOnCompose" = a."cleanupCacheOnCompose" -FROM "admin" a -WHERE u.id = a."authId"; - --- Actualizar referencias en las tablas relacionadas -UPDATE "project" p -SET "userId" = a."authId" -FROM "admin" a -WHERE p."userId" = a."adminId"; - -UPDATE "destination" d -SET "userId" = a."authId" -FROM "admin" a -WHERE d."userId" = a."adminId"; - -UPDATE "certificate" c -SET "userId" = a."authId" -FROM "admin" a -WHERE c."userId" = a."adminId"; - -UPDATE "registry" r -SET "userId" = a."authId" -FROM "admin" a -WHERE r."userId" = a."adminId"; - -UPDATE "notification" n -SET "userId" = a."authId" -FROM "admin" a -WHERE n."userId" = a."adminId"; - -UPDATE "ssh-key" s -SET "userId" = a."authId" -FROM "admin" a -WHERE s."userId" = a."adminId"; - -UPDATE "git_provider" g -SET "userId" = a."authId" -FROM "admin" a -WHERE g."userId" = a."adminId"; - -UPDATE "server" s -SET "userId" = a."authId" -FROM "admin" a -WHERE s."userId" = a."adminId"; - --- Ahora agregar las restricciones NOT NULL después de migrar los datos -ALTER TABLE "user" ALTER COLUMN "name" SET NOT NULL; -ALTER TABLE "user" ALTER COLUMN "email" SET NOT NULL; -ALTER TABLE "user" ALTER COLUMN "email_verified" SET NOT NULL; -ALTER TABLE "user" ALTER COLUMN "updated_at" SET NOT NULL; -ALTER TABLE "user" ALTER COLUMN "certificateType" SET NOT NULL; -ALTER TABLE "user" ALTER COLUMN "enableDockerCleanup" SET NOT NULL; -ALTER TABLE "user" ALTER COLUMN "enableLogRotation" SET NOT NULL; -ALTER TABLE "user" ALTER COLUMN "enablePaidFeatures" SET NOT NULL; -ALTER TABLE "user" ALTER COLUMN "metricsConfig" SET NOT NULL; -ALTER TABLE "user" ALTER COLUMN "cleanupCacheApplications" SET NOT NULL; -ALTER TABLE "user" ALTER COLUMN "cleanupCacheOnPreviews" SET NOT NULL; -ALTER TABLE "user" ALTER COLUMN "cleanupCacheOnCompose" SET NOT NULL; - --- Modificar session -ALTER TABLE "session" ALTER COLUMN "expires_at" SET DATA TYPE timestamp; -ALTER TABLE "session" ADD COLUMN "token" text; -ALTER TABLE "session" ADD COLUMN "created_at" timestamp; -ALTER TABLE "session" ADD COLUMN "updated_at" timestamp; -ALTER TABLE "session" ADD COLUMN "ip_address" text; -ALTER TABLE "session" ADD COLUMN "user_agent" text; -ALTER TABLE "session" ADD COLUMN "impersonated_by" text; - --- Agregar nuevas restricciones después de migrar todos los datos -ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; -ALTER TABLE "project" ADD CONSTRAINT "project_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; -ALTER TABLE "destination" ADD CONSTRAINT "destination_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; -ALTER TABLE "certificate" ADD CONSTRAINT "certificate_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; -ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; -ALTER TABLE "registry" ADD CONSTRAINT "registry_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; -ALTER TABLE "notification" ADD CONSTRAINT "notification_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; -ALTER TABLE "ssh-key" ADD CONSTRAINT "ssh-key_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; -ALTER TABLE "git_provider" ADD CONSTRAINT "git_provider_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; -ALTER TABLE "server" ADD CONSTRAINT "server_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; - --- Agregar restricciones únicas -ALTER TABLE "user" ADD CONSTRAINT "user_email_unique" UNIQUE("email"); -ALTER TABLE "session" ADD CONSTRAINT "session_token_unique" UNIQUE("token"); - --- Eliminar columnas antiguas -ALTER TABLE "user" DROP COLUMN IF EXISTS "adminId"; -ALTER TABLE "user" DROP COLUMN IF EXISTS "authId"; - --- Eliminar columnas de admin -ALTER TABLE "admin" DROP COLUMN IF EXISTS "adminId"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "serverIp"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "certificateType"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "host"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "letsEncryptEmail"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "sshPrivateKey"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "enableDockerCleanup"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "enableLogRotation"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "authId"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "createdAt"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "stripeCustomerId"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "stripeSubscriptionId"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "serversQuantity"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "enablePaidFeatures"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "metricsConfig"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "cleanupCacheApplications"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "cleanupCacheOnPreviews"; -ALTER TABLE "admin" DROP COLUMN IF EXISTS "cleanupCacheOnCompose"; - --- Eliminar tablas antiguas -DROP TABLE IF EXISTS "auth" CASCADE; -DROP TABLE IF EXISTS "admin" CASCADE; diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index fba21e234..f22967d59 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -111,7 +111,6 @@ export const users_temp = pgTable("user_temp", { email: text("email").notNull().unique(), emailVerified: boolean("email_verified").notNull(), image: text("image"), - role: text("role"), banned: boolean("banned"), banReason: text("ban_reason"), banExpires: timestamp("ban_expires"), From d233f2c764fc213d8c411391a4ac60f59116791a Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 19:12:44 -0600 Subject: [PATCH 23/89] feat: adjust roles --- .../components/dashboard/projects/show.tsx | 6 +- apps/dokploy/pages/index.tsx | 1 - apps/dokploy/server/api/routers/auth.ts | 13 +- apps/dokploy/server/api/trpc.ts | 5 +- packages/server/src/db/schema/account.ts | 4 +- packages/server/src/db/schema/user.ts | 5 +- packages/server/src/lib/auth.ts | 167 ++++++---- packages/server/src/services/admin.ts | 299 +++++++++--------- 8 files changed, 273 insertions(+), 227 deletions(-) diff --git a/apps/dokploy/components/dashboard/projects/show.tsx b/apps/dokploy/components/dashboard/projects/show.tsx index 98ef14a4b..206137f56 100644 --- a/apps/dokploy/components/dashboard/projects/show.tsx +++ b/apps/dokploy/components/dashboard/projects/show.tsx @@ -57,7 +57,7 @@ export const ShowProjects = () => { authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.role === "user", + enabled: !!auth?.id && auth?.role === "member", }, ); const { mutateAsync } = api.project.remove.useMutation(); @@ -91,7 +91,7 @@ export const ShowProjects = () => { - {(auth?.role === "admin" || user?.canCreateProjects) && ( + {(auth?.role === "owner" || user?.canCreateProjects) && (
@@ -293,7 +293,7 @@ export const ShowProjects = () => {
e.stopPropagation()} > - {(auth?.role === "admin" || + {(auth?.role === "owner" || user?.canDeleteProjects) && ( diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 0fecc209c..b85b1c7e1 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -261,7 +261,6 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { } const { user } = await validateRequest(context.req); - console.log("Response", user); if (user) { return { diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index 7f1382b49..ccb6b5ad7 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -7,6 +7,7 @@ import { apiVerify2FA, apiVerifyLogin2FA, auth, + member, } from "@/server/db/schema"; import { WEBSITE_URL } from "@/server/utils/stripe"; import { @@ -32,7 +33,7 @@ import { import { TRPCError } from "@trpc/server"; import * as bcrypt from "bcrypt"; import { isBefore } from "date-fns"; -import { eq } from "drizzle-orm"; +import { and, eq } from "drizzle-orm"; import { nanoid } from "nanoid"; import { z } from "zod"; import { db } from "../../db"; @@ -170,8 +171,14 @@ export const authRouter = createTRPCRouter({ }), get: protectedProcedure.query(async ({ ctx }) => { - const auth = await findAuthById(ctx.user.id); - return auth; + const memberResult = await db.query.member.findFirst({ + where: and( + eq(member.userId, ctx.user.id), + eq(member.organizationId, ctx.session?.activeOrganizationId || ""), + ), + }); + + return memberResult; }), logout: protectedProcedure.mutation(async ({ ctx }) => { diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index 9f373ad3f..c88158b85 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -32,7 +32,7 @@ import { ZodError } from "zod"; interface CreateContextOptions { user: (User & { rol: "admin" | "user"; ownerId: string }) | null; - session: Session | null; + session: (Session & { activeOrganizationId: string }) | null; req: CreateNextContextOptions["req"]; res: CreateNextContextOptions["res"]; } @@ -75,12 +75,15 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { user = cookieResult.user; } + console.log("session", { session, user }); + return createInnerTRPCContext({ req, res, session: session, ...((user && { user: { + ...user, email: user.email, rol: user.role, id: user.id, diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 432753fde..0b5ef2707 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -77,7 +77,7 @@ export const member = pgTable("member", { userId: text("user_id") .notNull() .references(() => users_temp.id), - role: text("role").notNull(), + role: text("role").notNull().$type<"owner" | "member" | "admin">(), createdAt: timestamp("created_at").notNull(), }); @@ -98,7 +98,7 @@ export const invitation = pgTable("invitation", { .notNull() .references(() => organization.id), email: text("email").notNull(), - role: text("role"), + role: text("role").$type<"owner" | "member" | "admin">(), status: text("status").notNull(), expiresAt: timestamp("expires_at").notNull(), inviterId: text("inviter_id") diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index f22967d59..c05b734a7 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -10,7 +10,7 @@ import { import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; -import { account } from "./account"; +import { account, organization } from "./account"; import { admins } from "./admin"; import { auth } from "./auth"; import { certificateType } from "./shared"; @@ -185,7 +185,7 @@ export const users_temp = pgTable("user_temp", { serversQuantity: integer("serversQuantity").notNull().default(0), }); -export const usersRelations = relations(users_temp, ({ one }) => ({ +export const usersRelations = relations(users_temp, ({ one, many }) => ({ // auth: one(auth, { // fields: [users.authId], // references: [auth.id], @@ -194,6 +194,7 @@ export const usersRelations = relations(users_temp, ({ one }) => ({ fields: [users_temp.id], references: [account.userId], }), + organizations: many(organization), // admin: one(admins, { // fields: [users.adminId], // references: [admins.adminId], diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 226ab0a8c..ce636c134 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -3,85 +3,116 @@ import * as bcrypt from "bcrypt"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { createAuthMiddleware, organization } from "better-auth/plugins"; -import { eq } from "drizzle-orm"; +import { desc, eq } from "drizzle-orm"; import { db } from "../db"; import * as schema from "../db/schema"; export const auth = betterAuth({ - database: drizzleAdapter(db, { - provider: "pg", - schema: schema, - }), + database: drizzleAdapter(db, { + provider: "pg", + schema: schema, + }), - emailAndPassword: { - enabled: true, + emailAndPassword: { + enabled: true, - password: { - async hash(password) { - return bcrypt.hashSync(password, 10); - }, - async verify({ hash, password }) { - return bcrypt.compareSync(password, hash); - }, - }, - }, - hooks: { - after: createAuthMiddleware(async (ctx) => { - if (ctx.path.startsWith("/sign-up")) { - const newSession = ctx.context.newSession; - await db - .update(schema.users_temp) - .set({ - role: "admin", - }) - .where(eq(schema.users_temp.id, newSession?.user?.id || "")); - } - }), - }, - user: { - modelName: "users_temp", - additionalFields: { - role: { - type: "string", - }, - ownerId: { - type: "string", - }, - }, - }, - plugins: [organization()], + password: { + async hash(password) { + return bcrypt.hashSync(password, 10); + }, + async verify({ hash, password }) { + return bcrypt.compareSync(password, hash); + }, + }, + }, + hooks: { + after: createAuthMiddleware(async (ctx) => { + if (ctx.path.startsWith("/sign-up")) { + const newSession = ctx.context.newSession; + const organization = await db + .insert(schema.organization) + .values({ + name: "My Organization", + ownerId: newSession?.user?.id || "", + createdAt: new Date(), + }) + .returning() + .then((res) => res[0]); + + await db.insert(schema.member).values({ + userId: newSession?.user?.id || "", + organizationId: organization?.id || "", + role: "owner", + createdAt: new Date(), + }); + } + }), + }, + databaseHooks: { + session: { + create: { + before: async (session) => { + const member = await db.query.member.findFirst({ + where: eq(schema.member.userId, session.userId), + orderBy: desc(schema.member.createdAt), + with: { + organization: true, + }, + }); + + return { + data: { + ...session, + activeOrganizationId: member?.organization.id, + }, + }; + }, + }, + }, + }, + user: { + modelName: "users_temp", + additionalFields: { + role: { + type: "string", + }, + ownerId: { + type: "string", + }, + }, + }, + plugins: [organization()], }); export const validateRequest = async (request: IncomingMessage) => { - const session = await auth.api.getSession({ - headers: new Headers({ - cookie: request.headers.cookie || "", - }), - }); + const session = await auth.api.getSession({ + headers: new Headers({ + cookie: request.headers.cookie || "", + }), + }); - if (!session?.session || !session.user) { - return { - session: null, - user: null, - }; - } + if (!session?.session || !session.user) { + return { + session: null, + user: null, + }; + } - if (session?.user) { - if (session?.user.role === "user") { - const owner = await db.query.member.findFirst({ - where: eq(schema.member.userId, session.user.id), - with: { - organization: true, - }, - }); + if (session?.user) { + const member = await db.query.member.findFirst({ + where: eq(schema.member.userId, session.user.id), + with: { + organization: true, + }, + }); - if (owner) { - session.user.ownerId = owner.organization.ownerId; - } - } else { - session.user.ownerId = session?.user?.id || ""; - } - } + session.user.role = member?.role || "member"; + if (member) { + session.user.ownerId = member.organization.ownerId; + } else { + session.user.ownerId = session.user.id; + } + } - return session; + return session; }; diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index e8a60498f..78a0375a8 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -1,10 +1,13 @@ import { randomBytes } from "node:crypto"; import { db } from "@dokploy/server/db"; import { - admins, - type apiCreateUserInvitation, - auth, - users_temp, + account, + admins, + type apiCreateUserInvitation, + auth, + member, + organization, + users_temp, } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import * as bcrypt from "bcrypt"; @@ -13,188 +16,190 @@ import { IS_CLOUD } from "../constants"; export type Admin = typeof users_temp.$inferSelect; export const createInvitation = async ( - input: typeof apiCreateUserInvitation._type, - adminId: string + input: typeof apiCreateUserInvitation._type, + adminId: string, ) => { - await db.transaction(async (tx) => { - const result = await tx - .insert(auth) - .values({ - email: input.email.toLowerCase(), - rol: "user", - password: bcrypt.hashSync("01231203012312", 10), - }) - .returning() - .then((res) => res[0]); + await db.transaction(async (tx) => { + const result = await tx + .insert(auth) + .values({ + email: input.email.toLowerCase(), + rol: "user", + password: bcrypt.hashSync("01231203012312", 10), + }) + .returning() + .then((res) => res[0]); - if (!result) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error creating the user", - }); - } - const expiresIn24Hours = new Date(); - expiresIn24Hours.setDate(expiresIn24Hours.getDate() + 1); - const token = randomBytes(32).toString("hex"); - await tx - .insert(users) - .values({ - adminId: adminId, - authId: result.id, - token, - expirationDate: expiresIn24Hours.toISOString(), - }) - .returning(); - }); + if (!result) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Error creating the user", + }); + } + const expiresIn24Hours = new Date(); + expiresIn24Hours.setDate(expiresIn24Hours.getDate() + 1); + const token = randomBytes(32).toString("hex"); + // await tx + // .insert(users) + // .values({ + // adminId: adminId, + // authId: result.id, + // token, + // expirationDate: expiresIn24Hours.toISOString(), + // }) + // .returning(); + }); }; export const findUserById = async (userId: string) => { - const user = await db.query.users_temp.findFirst({ - where: eq(users_temp.id, userId), - // with: { - // account: true, - // }, - }); - if (!user) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "User not found", - }); - } - return user; + const user = await db.query.users_temp.findFirst({ + where: eq(users_temp.id, userId), + // with: { + // account: true, + // }, + }); + if (!user) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "User not found", + }); + } + return user; }; export const updateUser = async (userId: string, userData: Partial) => { - const user = await db - .update(users_temp) - .set({ - ...userData, - }) - .where(eq(users_temp.id, userId)) - .returning() - .then((res) => res[0]); + const user = await db + .update(users_temp) + .set({ + ...userData, + }) + .where(eq(users_temp.id, userId)) + .returning() + .then((res) => res[0]); - return user; + return user; }; export const updateAdminById = async ( - adminId: string, - adminData: Partial + adminId: string, + adminData: Partial, ) => { - const admin = await db - .update(admins) - .set({ - ...adminData, - }) - .where(eq(admins.adminId, adminId)) - .returning() - .then((res) => res[0]); - - return admin; + // const admin = await db + // .update(admins) + // .set({ + // ...adminData, + // }) + // .where(eq(admins.adminId, adminId)) + // .returning() + // .then((res) => res[0]); + // return admin; }; export const findAdminById = async (userId: string) => { - const admin = await db.query.admins.findFirst({ - where: eq(admins.userId, userId), - }); - return admin; + const admin = await db.query.admins.findFirst({ + // where: eq(admins.userId, userId), + }); + return admin; }; export const isAdminPresent = async () => { - const admin = await db.query.users_temp.findFirst({ - where: eq(users_temp.role, "admin"), - }); - if (!admin) { - return false; - } - return true; + const admin = await db.query.member.findFirst({ + where: eq(member.role, "owner"), + }); + + console.log("admin", admin); + + if (!admin) { + return false; + } + return true; }; export const findAdminByAuthId = async (authId: string) => { - const admin = await db.query.admins.findFirst({ - where: eq(admins.authId, authId), - with: { - users: true, - }, - }); - if (!admin) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Admin not found", - }); - } - return admin; + const admin = await db.query.admins.findFirst({ + where: eq(admins.authId, authId), + with: { + users: true, + }, + }); + if (!admin) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Admin not found", + }); + } + return admin; }; export const findAdmin = async () => { - const admin = await db.query.admins.findFirst({}); - if (!admin) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Admin not found", - }); - } - return admin; + const admin = await db.query.admins.findFirst({}); + if (!admin) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Admin not found", + }); + } + return admin; }; export const getUserByToken = async (token: string) => { - const user = await db.query.users.findFirst({ - where: eq(users.token, token), - with: { - auth: { - columns: { - password: false, - }, - }, - }, - }); + const user = await db.query.users.findFirst({ + where: eq(users.token, token), + with: { + auth: { + columns: { + password: false, + }, + }, + }, + }); - if (!user) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Invitation not found", - }); - } - return { - ...user, - isExpired: user.isRegistered, - }; + if (!user) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Invitation not found", + }); + } + return { + ...user, + isExpired: user.isRegistered, + }; }; export const removeUserById = async (userId: string) => { - await db - .delete(users_temp) - .where(eq(users_temp.id, userId)) - .returning() - .then((res) => res[0]); + await db + .delete(users_temp) + .where(eq(users_temp.id, userId)) + .returning() + .then((res) => res[0]); }; export const removeAdminByAuthId = async (authId: string) => { - const admin = await findAdminByAuthId(authId); - if (!admin) return null; + const admin = await findAdminByAuthId(authId); + if (!admin) return null; - // First delete all associated users - const users = admin.users; + // First delete all associated users + const users = admin.users; - for (const user of users) { - await removeUserById(user.id); - } - // Then delete the auth record which will cascade delete the admin - return await db - .delete(auth) - .where(eq(auth.id, authId)) - .returning() - .then((res) => res[0]); + for (const user of users) { + await removeUserById(user.id); + } + // Then delete the auth record which will cascade delete the admin + return await db + .delete(auth) + .where(eq(auth.id, authId)) + .returning() + .then((res) => res[0]); }; export const getDokployUrl = async () => { - if (IS_CLOUD) { - return "https://app.dokploy.com"; - } - const admin = await findAdmin(); + if (IS_CLOUD) { + return "https://app.dokploy.com"; + } + const admin = await findAdmin(); - if (admin.host) { - return `https://${admin.host}`; - } - return `http://${admin.serverIp}:${process.env.PORT}`; + if (admin.host) { + return `https://${admin.host}`; + } + return `http://${admin.serverIp}:${process.env.PORT}`; }; From 1c5cc5a0dbd539533917a8b9c14d50f887fba7aa Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 19:23:08 -0600 Subject: [PATCH 24/89] refactor: update roles --- .../settings/billing/show-welcome-dokploy.tsx | 6 +-- apps/dokploy/components/layouts/side.tsx | 36 +++++++-------- apps/dokploy/components/layouts/user-nav.tsx | 14 +++--- .../pages/api/providers/github/setup.ts | 2 +- apps/dokploy/pages/dashboard/docker.tsx | 2 +- .../pages/dashboard/project/[projectId].tsx | 4 +- .../services/application/[applicationId].tsx | 4 +- .../services/compose/[composeId].tsx | 4 +- .../services/mariadb/[mariadbId].tsx | 4 +- .../[projectId]/services/mongo/[mongoId].tsx | 4 +- .../[projectId]/services/mysql/[mysqlId].tsx | 4 +- .../services/postgres/[postgresId].tsx | 4 +- .../[projectId]/services/redis/[redisId].tsx | 4 +- .../pages/dashboard/settings/billing.tsx | 2 +- .../pages/dashboard/settings/certificates.tsx | 2 +- .../pages/dashboard/settings/cluster.tsx | 2 +- .../pages/dashboard/settings/destinations.tsx | 2 +- .../dashboard/settings/git-providers.tsx | 2 +- .../pages/dashboard/settings/index.tsx | 2 +- .../dashboard/settings/notifications.tsx | 2 +- .../pages/dashboard/settings/profile.tsx | 6 +-- .../pages/dashboard/settings/registry.tsx | 2 +- .../pages/dashboard/settings/server.tsx | 2 +- .../pages/dashboard/settings/servers.tsx | 2 +- .../pages/dashboard/settings/ssh-keys.tsx | 2 +- .../pages/dashboard/settings/users.tsx | 2 +- apps/dokploy/pages/dashboard/swarm.tsx | 2 +- apps/dokploy/pages/dashboard/traefik.tsx | 2 +- apps/dokploy/pages/swagger.tsx | 2 +- apps/dokploy/server/api/routers/admin.ts | 2 +- .../dokploy/server/api/routers/application.ts | 8 ++-- apps/dokploy/server/api/routers/auth.ts | 5 ++- apps/dokploy/server/api/routers/compose.ts | 12 ++--- apps/dokploy/server/api/routers/mariadb.ts | 8 ++-- apps/dokploy/server/api/routers/mongo.ts | 8 ++-- apps/dokploy/server/api/routers/mysql.ts | 8 ++-- apps/dokploy/server/api/routers/postgres.ts | 8 ++-- apps/dokploy/server/api/routers/project.ts | 10 ++--- apps/dokploy/server/api/routers/redis.ts | 8 ++-- apps/dokploy/server/api/routers/settings.ts | 6 +-- apps/dokploy/server/api/trpc.ts | 44 ++++++++++--------- packages/server/src/auth/auth.ts | 4 +- packages/server/src/auth/token.ts | 8 ++-- packages/server/src/lib/auth.ts | 2 + packages/server/src/utils/providers/gitlab.ts | 4 +- 45 files changed, 141 insertions(+), 132 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/billing/show-welcome-dokploy.tsx b/apps/dokploy/components/dashboard/settings/billing/show-welcome-dokploy.tsx index ca6a4daee..9464a565e 100644 --- a/apps/dokploy/components/dashboard/settings/billing/show-welcome-dokploy.tsx +++ b/apps/dokploy/components/dashboard/settings/billing/show-welcome-dokploy.tsx @@ -15,7 +15,7 @@ export const ShowWelcomeDokploy = () => { const { data: isCloud, isLoading } = api.settings.isCloud.useQuery(); - if (!isCloud || data?.rol !== "admin") { + if (!isCloud || data?.role !== "admin") { return null; } @@ -24,14 +24,14 @@ export const ShowWelcomeDokploy = () => { !isLoading && isCloud && !localStorage.getItem("hasSeenCloudWelcomeModal") && - data?.rol === "admin" + data?.role === "owner" ) { setOpen(true); } }, [isCloud, isLoading]); const handleClose = (isOpen: boolean) => { - if (data?.rol === "admin") { + if (data?.role === "owner") { setOpen(isOpen); if (!isOpen) { localStorage.setItem("hasSeenCloudWelcomeModal", "true"); // Establece el flag al cerrar el modal diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 88740054b..99938a5de 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -155,7 +155,7 @@ const MENU: Menu = { // Only enabled for admins and users with access to Traefik files in non-cloud environments isEnabled: ({ auth, user, isCloud }) => !!( - (auth?.role === "admin" || user?.canAccessToTraefikFiles) && + (auth?.role === "owner" || user?.canAccessToTraefikFiles) && !isCloud ), }, @@ -166,7 +166,7 @@ const MENU: Menu = { icon: BlocksIcon, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud), + !!((auth?.role === "owner" || user?.canAccessToDocker) && !isCloud), }, { isSingle: true, @@ -175,7 +175,7 @@ const MENU: Menu = { icon: PieChart, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud), + !!((auth?.role === "owner" || user?.canAccessToDocker) && !isCloud), }, { isSingle: true, @@ -184,7 +184,7 @@ const MENU: Menu = { icon: Forward, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!((auth?.role === "admin" || user?.canAccessToDocker) && !isCloud), + !!((auth?.role === "owner" || user?.canAccessToDocker) && !isCloud), }, // Legacy unused menu, adjusted to the new structure @@ -252,7 +252,7 @@ const MENU: Menu = { icon: Activity, // Only enabled for admins in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!(auth?.role === "admin" && !isCloud), + !!(auth?.role === "owner" && !isCloud), }, { isSingle: true, @@ -266,7 +266,7 @@ const MENU: Menu = { url: "/dashboard/settings/servers", icon: Server, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), }, { isSingle: true, @@ -274,7 +274,7 @@ const MENU: Menu = { icon: Users, url: "/dashboard/settings/users", // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), }, { isSingle: true, @@ -283,7 +283,7 @@ const MENU: Menu = { url: "/dashboard/settings/ssh-keys", // Only enabled for admins and users with access to SSH keys isEnabled: ({ auth, user }) => - !!(auth?.role === "admin" || user?.canAccessToSSHKeys), + !!(auth?.role === "owner" || user?.canAccessToSSHKeys), }, { isSingle: true, @@ -292,7 +292,7 @@ const MENU: Menu = { icon: GitBranch, // Only enabled for admins and users with access to Git providers isEnabled: ({ auth, user }) => - !!(auth?.role === "admin" || user?.canAccessToGitProviders), + !!(auth?.role === "owner" || user?.canAccessToGitProviders), }, { isSingle: true, @@ -300,7 +300,7 @@ const MENU: Menu = { url: "/dashboard/settings/registry", icon: Package, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), }, { isSingle: true, @@ -308,7 +308,7 @@ const MENU: Menu = { url: "/dashboard/settings/destinations", icon: Database, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), }, { @@ -317,7 +317,7 @@ const MENU: Menu = { url: "/dashboard/settings/certificates", icon: ShieldCheck, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), }, { isSingle: true, @@ -326,7 +326,7 @@ const MENU: Menu = { icon: Boxes, // Only enabled for admins in non-cloud environments isEnabled: ({ auth, user, isCloud }) => - !!(auth?.role === "admin" && !isCloud), + !!(auth?.role === "owner" && !isCloud), }, { isSingle: true, @@ -334,7 +334,7 @@ const MENU: Menu = { url: "/dashboard/settings/notifications", icon: Bell, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "admin"), + isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), }, { isSingle: true, @@ -343,7 +343,7 @@ const MENU: Menu = { icon: CreditCard, // Only enabled for admins in cloud environments isEnabled: ({ auth, user, isCloud }) => - !!(auth?.role === "admin" && isCloud), + !!(auth?.role === "owner" && isCloud), }, ], @@ -537,7 +537,7 @@ export default function Page({ children }: Props) { authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.role === "user", + enabled: !!auth?.id && auth?.role === "member", }, ); @@ -557,7 +557,7 @@ export default function Page({ children }: Props) { // const showProjectsButton = // currentPath === "/dashboard/projects" && - // (auth?.rol === "admin" || user?.canCreateProjects); + // (auth?.rol === "owner" || user?.canCreateProjects); return ( ))} - {!isCloud && auth?.role === "admin" && ( + {!isCloud && auth?.role === "owner" && ( diff --git a/apps/dokploy/components/layouts/user-nav.tsx b/apps/dokploy/components/layouts/user-nav.tsx index 18d459f07..421ea5f2b 100644 --- a/apps/dokploy/components/layouts/user-nav.tsx +++ b/apps/dokploy/components/layouts/user-nav.tsx @@ -37,7 +37,7 @@ export const UserNav = () => { authId: data?.id || "", }, { - enabled: !!data?.id && data?.rol === "user", + enabled: !!data?.id && data?.role === "member", }, ); const { locale, setLocale } = useLocale(); @@ -96,7 +96,7 @@ export const UserNav = () => { > Monitoring - {(data?.rol === "admin" || user?.canAccessToTraefikFiles) && ( + {(data?.role === "owner" || user?.canAccessToTraefikFiles) && ( { @@ -106,7 +106,7 @@ export const UserNav = () => { Traefik )} - {(data?.rol === "admin" || user?.canAccessToDocker) && ( + {(data?.role === "owner" || user?.canAccessToDocker) && ( { @@ -119,7 +119,7 @@ export const UserNav = () => { )} - {data?.rol === "admin" && ( + {data?.role === "owner" && ( { @@ -140,7 +140,7 @@ export const UserNav = () => { > Profile - {data?.rol === "admin" && ( + {data?.role === "owner" && ( { @@ -151,7 +151,7 @@ export const UserNav = () => { )} - {data?.rol === "admin" && ( + {data?.role === "owner" && ( { @@ -164,7 +164,7 @@ export const UserNav = () => { )} - {isCloud && data?.rol === "admin" && ( + {isCloud && data?.role === "owner" && ( { diff --git a/apps/dokploy/pages/api/providers/github/setup.ts b/apps/dokploy/pages/api/providers/github/setup.ts index 38a281b1b..bd123c687 100644 --- a/apps/dokploy/pages/api/providers/github/setup.ts +++ b/apps/dokploy/pages/api/providers/github/setup.ts @@ -42,7 +42,7 @@ export default async function handler( const auth = await findAuthById(value as string); let adminId = ""; - if (auth.role === "admin") { + if (auth.role === "owner") { const admin = await findAdminByAuthId(auth.id); adminId = admin.adminId; } else { diff --git a/apps/dokploy/pages/dashboard/docker.tsx b/apps/dokploy/pages/dashboard/docker.tsx index 5449b9bdc..051e4f0a9 100644 --- a/apps/dokploy/pages/dashboard/docker.tsx +++ b/apps/dokploy/pages/dashboard/docker.tsx @@ -53,7 +53,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.role === "user") { + if (auth.role === "member") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index f8c39a3a3..87fa3df4f 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -206,7 +206,7 @@ const Project = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.role === "user", + enabled: !!auth?.id && auth?.role === "member", }, ); const { data, isLoading, refetch } = api.project.one.useQuery({ projectId }); @@ -335,7 +335,7 @@ const Project = ( {data?.description} - {(auth?.role === "admin" || user?.canCreateServices) && ( + {(auth?.role === "owner" || user?.canCreateServices) && (
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx index e2bf8455b..441720b94 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx @@ -93,7 +93,7 @@ const Service = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.role === "user", + enabled: !!auth?.id && auth?.role === "member", }, ); @@ -186,7 +186,7 @@ const Service = (
- {(auth?.role === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx index ddc613e5f..41a346b4b 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx @@ -87,7 +87,7 @@ const Service = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.role === "user", + enabled: !!auth?.id && auth?.role === "member", }, ); @@ -181,7 +181,7 @@ const Service = (
- {(auth?.role === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx index 813ea7292..7138be021 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx @@ -68,7 +68,7 @@ const Mariadb = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.role === "user", + enabled: !!auth?.id && auth?.role === "member", }, ); const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -154,7 +154,7 @@ const Mariadb = (
- {(auth?.role === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx index 0361b7e29..c0ddd96d5 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx @@ -68,7 +68,7 @@ const Mongo = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.role === "user", + enabled: !!auth?.id && auth?.role === "member", }, ); @@ -156,7 +156,7 @@ const Mongo = (
- {(auth?.role === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx index eff9cfe79..d170bb76e 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx @@ -67,7 +67,7 @@ const MySql = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.role === "user", + enabled: !!auth?.id && auth?.role === "member", }, ); @@ -156,7 +156,7 @@ const MySql = (
- {(auth?.role === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx index 808c7aee4..67c6a4a5e 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx @@ -66,7 +66,7 @@ const Postgresql = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.role === "user", + enabled: !!auth?.id && auth?.role === "member", }, ); const { data: monitoring } = api.admin.getMetricsToken.useQuery(); @@ -154,7 +154,7 @@ const Postgresql = (
- {(auth?.role === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx index 82180401b..bb9ebc4ae 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx @@ -67,7 +67,7 @@ const Redis = ( authId: auth?.id || "", }, { - enabled: !!auth?.id && auth?.role === "user", + enabled: !!auth?.id && auth?.role === "member", }, ); @@ -155,7 +155,7 @@ const Redis = (
- {(auth?.role === "admin" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || user?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/settings/billing.tsx b/apps/dokploy/pages/dashboard/settings/billing.tsx index dd70c22ae..b1a7cb21d 100644 --- a/apps/dokploy/pages/dashboard/settings/billing.tsx +++ b/apps/dokploy/pages/dashboard/settings/billing.tsx @@ -30,7 +30,7 @@ export async function getServerSideProps( } const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.role === "user") { + if (!user || user.role === "member") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/certificates.tsx b/apps/dokploy/pages/dashboard/settings/certificates.tsx index d5bbf0332..14d020c41 100644 --- a/apps/dokploy/pages/dashboard/settings/certificates.tsx +++ b/apps/dokploy/pages/dashboard/settings/certificates.tsx @@ -25,7 +25,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.role === "user") { + if (!user || user.role === "member") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/cluster.tsx b/apps/dokploy/pages/dashboard/settings/cluster.tsx index 9affb9ee2..dd12723c4 100644 --- a/apps/dokploy/pages/dashboard/settings/cluster.tsx +++ b/apps/dokploy/pages/dashboard/settings/cluster.tsx @@ -34,7 +34,7 @@ export async function getServerSideProps( }; } const { user, session } = await validateRequest(ctx.req, ctx.res); - if (!user || user.role === "user") { + if (!user || user.role === "member") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/destinations.tsx b/apps/dokploy/pages/dashboard/settings/destinations.tsx index 671087fe8..5d34ec5f4 100644 --- a/apps/dokploy/pages/dashboard/settings/destinations.tsx +++ b/apps/dokploy/pages/dashboard/settings/destinations.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.role === "user") { + if (!user || user.role === "member") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx index 6e8bf5874..c9135fee6 100644 --- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx +++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx @@ -51,7 +51,7 @@ export async function getServerSideProps( await helpers.settings.isCloud.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.role === "user") { + if (auth.role === "member") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/settings/index.tsx b/apps/dokploy/pages/dashboard/settings/index.tsx index 9b4c80485..577c2b7c7 100644 --- a/apps/dokploy/pages/dashboard/settings/index.tsx +++ b/apps/dokploy/pages/dashboard/settings/index.tsx @@ -190,7 +190,7 @@ export async function getServerSideProps( }, }; } - if (user.role === "user") { + if (user.role === "member") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/notifications.tsx b/apps/dokploy/pages/dashboard/settings/notifications.tsx index 054f92e5a..840eb9d4a 100644 --- a/apps/dokploy/pages/dashboard/settings/notifications.tsx +++ b/apps/dokploy/pages/dashboard/settings/notifications.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.role === "user") { + if (!user || user.role === "member") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index 00f10ec72..1d6d9896d 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -19,7 +19,7 @@ const Page = () => { authId: data?.id || "", }, { - enabled: !!data?.id && data?.role === "user", + enabled: !!data?.id && data?.role === "member", }, ); @@ -28,7 +28,7 @@ const Page = () => {
- {(user?.canAccessToAPI || data?.role === "admin") && } + {(user?.canAccessToAPI || data?.role === "owner") && } {isCloud && }
@@ -62,7 +62,7 @@ export async function getServerSideProps( await helpers.settings.isCloud.prefetch(); await helpers.auth.get.prefetch(); - if (user?.role === "user") { + if (user?.role === "member") { await helpers.user.byAuthId.prefetch({ authId: user.authId, }); diff --git a/apps/dokploy/pages/dashboard/settings/registry.tsx b/apps/dokploy/pages/dashboard/settings/registry.tsx index 441bee395..61f62614a 100644 --- a/apps/dokploy/pages/dashboard/settings/registry.tsx +++ b/apps/dokploy/pages/dashboard/settings/registry.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.role === "user") { + if (!user || user.role === "member") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/server.tsx b/apps/dokploy/pages/dashboard/settings/server.tsx index 98710d06e..498e97ce1 100644 --- a/apps/dokploy/pages/dashboard/settings/server.tsx +++ b/apps/dokploy/pages/dashboard/settings/server.tsx @@ -107,7 +107,7 @@ export async function getServerSideProps( }, }; } - if (user.role === "user") { + if (user.role === "member") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/servers.tsx b/apps/dokploy/pages/dashboard/settings/servers.tsx index 27f88be24..6f83fb669 100644 --- a/apps/dokploy/pages/dashboard/settings/servers.tsx +++ b/apps/dokploy/pages/dashboard/settings/servers.tsx @@ -36,7 +36,7 @@ export async function getServerSideProps( }, }; } - if (user.role === "user") { + if (user.role === "member") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx index fcb11666f..d7876641f 100644 --- a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx +++ b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx @@ -51,7 +51,7 @@ export async function getServerSideProps( const auth = await helpers.auth.get.fetch(); await helpers.settings.isCloud.prefetch(); - if (auth.role === "user") { + if (auth.role === "member") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/settings/users.tsx b/apps/dokploy/pages/dashboard/settings/users.tsx index ace439692..8f97e2b6c 100644 --- a/apps/dokploy/pages/dashboard/settings/users.tsx +++ b/apps/dokploy/pages/dashboard/settings/users.tsx @@ -26,7 +26,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req, res); - if (!user || user.role === "user") { + if (!user || user.role === "member") { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/swarm.tsx b/apps/dokploy/pages/dashboard/swarm.tsx index 524b464af..f57728209 100644 --- a/apps/dokploy/pages/dashboard/swarm.tsx +++ b/apps/dokploy/pages/dashboard/swarm.tsx @@ -53,7 +53,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.role === "user") { + if (auth.role === "member") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/dashboard/traefik.tsx b/apps/dokploy/pages/dashboard/traefik.tsx index b8ff13f3f..1f710c9eb 100644 --- a/apps/dokploy/pages/dashboard/traefik.tsx +++ b/apps/dokploy/pages/dashboard/traefik.tsx @@ -53,7 +53,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); const auth = await helpers.auth.get.fetch(); - if (auth.role === "user") { + if (auth.role === "member") { const user = await helpers.user.byAuthId.fetch({ authId: auth.id, }); diff --git a/apps/dokploy/pages/swagger.tsx b/apps/dokploy/pages/swagger.tsx index 2113e4c85..765194f1c 100644 --- a/apps/dokploy/pages/swagger.tsx +++ b/apps/dokploy/pages/swagger.tsx @@ -58,7 +58,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { }, transformer: superjson, }); - if (user.role === "user") { + if (user.role === "member") { const result = await helpers.user.byAuthId.fetch({ authId: user.id, }); diff --git a/apps/dokploy/server/api/routers/admin.ts b/apps/dokploy/server/api/routers/admin.ts index e8467283a..55df35afe 100644 --- a/apps/dokploy/server/api/routers/admin.ts +++ b/apps/dokploy/server/api/routers/admin.ts @@ -39,7 +39,7 @@ export const adminRouter = createTRPCRouter({ update: adminProcedure .input(apiUpdateAdmin) .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to update this admin", diff --git a/apps/dokploy/server/api/routers/application.ts b/apps/dokploy/server/api/routers/application.ts index 0f7c1eb67..618fd9ce8 100644 --- a/apps/dokploy/server/api/routers/application.ts +++ b/apps/dokploy/server/api/routers/application.ts @@ -60,7 +60,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiCreateApplication) .mutation(async ({ input, ctx }) => { try { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.projectId, "create"); } @@ -80,7 +80,7 @@ export const applicationRouter = createTRPCRouter({ } const newApplication = await createApplication(input); - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await addNewService(ctx.user.id, newApplication.applicationId); } return newApplication; @@ -98,7 +98,7 @@ export const applicationRouter = createTRPCRouter({ one: protectedProcedure .input(apiFindOneApplication) .query(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.applicationId, "access"); } const application = await findApplicationById(input.applicationId); @@ -140,7 +140,7 @@ export const applicationRouter = createTRPCRouter({ delete: protectedProcedure .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.applicationId, "delete"); } const application = await findApplicationById(input.applicationId); diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index ccb6b5ad7..cc149b3c0 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -176,6 +176,9 @@ export const authRouter = createTRPCRouter({ eq(member.userId, ctx.user.id), eq(member.organizationId, ctx.session?.activeOrganizationId || ""), ), + with: { + user: true, + }, }); return memberResult; @@ -251,7 +254,7 @@ export const authRouter = createTRPCRouter({ await lucia.invalidateSession(session.id); res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); - if (ctx.user.rol === "admin") { + if (ctx.user.rol === "owner") { await removeAdminByAuthId(ctx.user.authId); } else { await removeUserByAuthId(ctx.user.authId); diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index b3fbae93a..69586eb42 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -61,7 +61,7 @@ export const composeRouter = createTRPCRouter({ .input(apiCreateCompose) .mutation(async ({ ctx, input }) => { try { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.projectId, "create"); } @@ -80,7 +80,7 @@ export const composeRouter = createTRPCRouter({ } const newService = await createCompose(input); - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await addNewService(ctx.user.id, newService.composeId); } @@ -93,7 +93,7 @@ export const composeRouter = createTRPCRouter({ one: protectedProcedure .input(apiFindCompose) .query(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.composeId, "access"); } @@ -122,7 +122,7 @@ export const composeRouter = createTRPCRouter({ delete: protectedProcedure .input(apiDeleteCompose) .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.composeId, "delete"); } const composeResult = await findComposeById(input.composeId); @@ -376,7 +376,7 @@ export const composeRouter = createTRPCRouter({ deployTemplate: protectedProcedure .input(apiCreateComposeByTemplate) .mutation(async ({ ctx, input }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.projectId, "create"); } @@ -419,7 +419,7 @@ export const composeRouter = createTRPCRouter({ isolatedDeployment: true, }); - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await addNewService(ctx.user.id, compose.composeId); } diff --git a/apps/dokploy/server/api/routers/mariadb.ts b/apps/dokploy/server/api/routers/mariadb.ts index 9305395d3..e50b9b129 100644 --- a/apps/dokploy/server/api/routers/mariadb.ts +++ b/apps/dokploy/server/api/routers/mariadb.ts @@ -37,7 +37,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiCreateMariaDB) .mutation(async ({ input, ctx }) => { try { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.projectId, "create"); } @@ -56,7 +56,7 @@ export const mariadbRouter = createTRPCRouter({ }); } const newMariadb = await createMariadb(input); - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await addNewService(ctx.user.id, newMariadb.mariadbId); } @@ -79,7 +79,7 @@ export const mariadbRouter = createTRPCRouter({ one: protectedProcedure .input(apiFindOneMariaDB) .query(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.mariadbId, "access"); } const mariadb = await findMariadbById(input.mariadbId); @@ -201,7 +201,7 @@ export const mariadbRouter = createTRPCRouter({ remove: protectedProcedure .input(apiFindOneMariaDB) .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.mariadbId, "delete"); } diff --git a/apps/dokploy/server/api/routers/mongo.ts b/apps/dokploy/server/api/routers/mongo.ts index aed7b4c52..ddb3d3ccd 100644 --- a/apps/dokploy/server/api/routers/mongo.ts +++ b/apps/dokploy/server/api/routers/mongo.ts @@ -36,7 +36,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiCreateMongo) .mutation(async ({ input, ctx }) => { try { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.projectId, "create"); } @@ -55,7 +55,7 @@ export const mongoRouter = createTRPCRouter({ }); } const newMongo = await createMongo(input); - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await addNewService(ctx.user.id, newMongo.mongoId); } @@ -82,7 +82,7 @@ export const mongoRouter = createTRPCRouter({ one: protectedProcedure .input(apiFindOneMongo) .query(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.mongoId, "access"); } @@ -242,7 +242,7 @@ export const mongoRouter = createTRPCRouter({ remove: protectedProcedure .input(apiFindOneMongo) .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.mongoId, "delete"); } diff --git a/apps/dokploy/server/api/routers/mysql.ts b/apps/dokploy/server/api/routers/mysql.ts index e66c30941..c81fc8429 100644 --- a/apps/dokploy/server/api/routers/mysql.ts +++ b/apps/dokploy/server/api/routers/mysql.ts @@ -38,7 +38,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiCreateMySql) .mutation(async ({ input, ctx }) => { try { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.projectId, "create"); } @@ -58,7 +58,7 @@ export const mysqlRouter = createTRPCRouter({ } const newMysql = await createMysql(input); - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await addNewService(ctx.user.id, newMysql.mysqlId); } @@ -85,7 +85,7 @@ export const mysqlRouter = createTRPCRouter({ one: protectedProcedure .input(apiFindOneMySql) .query(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.mysqlId, "access"); } const mysql = await findMySqlById(input.mysqlId); @@ -240,7 +240,7 @@ export const mysqlRouter = createTRPCRouter({ remove: protectedProcedure .input(apiFindOneMySql) .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.mysqlId, "delete"); } const mongo = await findMySqlById(input.mysqlId); diff --git a/apps/dokploy/server/api/routers/postgres.ts b/apps/dokploy/server/api/routers/postgres.ts index 0aab4dc65..8a4e8ba25 100644 --- a/apps/dokploy/server/api/routers/postgres.ts +++ b/apps/dokploy/server/api/routers/postgres.ts @@ -44,7 +44,7 @@ export const postgresRouter = createTRPCRouter({ .input(apiCreatePostgres) .mutation(async ({ input, ctx }) => { try { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.projectId, "create"); } @@ -63,7 +63,7 @@ export const postgresRouter = createTRPCRouter({ }); } const newPostgres = await createPostgres(input); - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await addNewService(ctx.user.id, newPostgres.postgresId); } @@ -90,7 +90,7 @@ export const postgresRouter = createTRPCRouter({ one: protectedProcedure .input(apiFindOnePostgres) .query(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.postgresId, "access"); } @@ -221,7 +221,7 @@ export const postgresRouter = createTRPCRouter({ remove: protectedProcedure .input(apiFindOnePostgres) .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.postgresId, "delete"); } const postgres = await findPostgresById(input.postgresId); diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index d4a30580a..bce12565f 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -36,7 +36,7 @@ export const projectRouter = createTRPCRouter({ .input(apiCreateProject) .mutation(async ({ ctx, input }) => { try { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkProjectAccess(ctx.user.id, "create"); } @@ -50,7 +50,7 @@ export const projectRouter = createTRPCRouter({ } const project = await createProject(input, ctx.user.ownerId); - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await addNewProject(ctx.user.id, project.projectId); } @@ -67,7 +67,7 @@ export const projectRouter = createTRPCRouter({ one: protectedProcedure .input(apiFindOneProject) .query(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { const { accessedServices } = await findUserByAuthId(ctx.user.id); await checkProjectAccess(ctx.user.id, "access", input.projectId); @@ -125,7 +125,7 @@ export const projectRouter = createTRPCRouter({ }), all: protectedProcedure.query(async ({ ctx }) => { // console.log(ctx.user); - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { const { accessedProjects, accessedServices } = await findUserById( ctx.user.id, ); @@ -203,7 +203,7 @@ export const projectRouter = createTRPCRouter({ .input(apiRemoveProject) .mutation(async ({ input, ctx }) => { try { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkProjectAccess(ctx.user.id, "delete"); } const currentProject = await findProjectById(input.projectId); diff --git a/apps/dokploy/server/api/routers/redis.ts b/apps/dokploy/server/api/routers/redis.ts index 46586e5e2..acded3723 100644 --- a/apps/dokploy/server/api/routers/redis.ts +++ b/apps/dokploy/server/api/routers/redis.ts @@ -36,7 +36,7 @@ export const redisRouter = createTRPCRouter({ .input(apiCreateRedis) .mutation(async ({ input, ctx }) => { try { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.projectId, "create"); } @@ -55,7 +55,7 @@ export const redisRouter = createTRPCRouter({ }); } const newRedis = await createRedis(input); - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await addNewService(ctx.user.id, newRedis.redisId); } @@ -75,7 +75,7 @@ export const redisRouter = createTRPCRouter({ one: protectedProcedure .input(apiFindOneRedis) .query(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.redisId, "access"); } @@ -232,7 +232,7 @@ export const redisRouter = createTRPCRouter({ remove: protectedProcedure .input(apiFindOneRedis) .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { await checkServiceAccess(ctx.user.id, input.redisId, "delete"); } diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index 6dda93835..cd1f8bd3b 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -382,7 +382,7 @@ export const settingsRouter = createTRPCRouter({ .input(apiServerSchema) .query(async ({ ctx, input }) => { try { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { const canAccess = await canAccessToTraefikFiles(ctx.user.authId); if (!canAccess) { @@ -400,7 +400,7 @@ export const settingsRouter = createTRPCRouter({ updateTraefikFile: protectedProcedure .input(apiModifyTraefikConfig) .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { const canAccess = await canAccessToTraefikFiles(ctx.user.authId); if (!canAccess) { @@ -418,7 +418,7 @@ export const settingsRouter = createTRPCRouter({ readTraefikFile: protectedProcedure .input(apiReadTraefikConfig) .query(async ({ input, ctx }) => { - if (ctx.user.rol === "user") { + if (ctx.user.rol === "member") { const canAccess = await canAccessToTraefikFiles(ctx.user.authId); if (!canAccess) { diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index c88158b85..4e777883a 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -32,7 +32,7 @@ import { ZodError } from "zod"; interface CreateContextOptions { user: (User & { rol: "admin" | "user"; ownerId: string }) | null; - session: (Session & { activeOrganizationId: string }) | null; + session: (Session & { activeOrganizationId?: string }) | null; req: CreateNextContextOptions["req"]; res: CreateNextContextOptions["res"]; } @@ -67,31 +67,35 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { const { req, res } = opts; // Get from the request - let { session, user } = await validateRequest(req); + const { session, user } = await validateRequest(req); - if (!session) { - const cookieResult = await validateRequest(req); - session = cookieResult.session; - user = cookieResult.user; - } + // if (!session) { + // const cookieResult = await validateRequest(req); + // session = cookieResult.session; + // user = cookieResult.user; + // } - console.log("session", { session, user }); + console.log("session", session); + console.log("user", user); return createInnerTRPCContext({ req, res, - session: session, - ...((user && { - user: { - ...user, - email: user.email, - rol: user.role, - id: user.id, - ownerId: user.ownerId, - }, - }) || { - user: null, - }), + session: session + ? { + ...session, + activeOrganizationId: session.activeOrganizationId ?? undefined, + } + : null, + user: user + ? { + ...user, + email: user.email, + rol: user.role as "admin" | "user", + id: user.id, + ownerId: user.ownerId, + } + : null, }); }; diff --git a/packages/server/src/auth/auth.ts b/packages/server/src/auth/auth.ts index 09372fa5b..ab18955f2 100644 --- a/packages/server/src/auth/auth.ts +++ b/packages/server/src/auth/auth.ts @@ -71,10 +71,10 @@ export async function validateRequest( } if (result.user) { try { - if (result.user?.rol === "admin") { + if (result.user?.rol === "owner") { const admin = await findAdminByAuthId(result.user.id); result.user.adminId = admin.adminId; - } else if (result.user?.rol === "user") { + } else if (result.user?.rol === "member") { const userResult = await findUserByAuthId(result.user.id); result.user.adminId = userResult.adminId; } diff --git a/packages/server/src/auth/token.ts b/packages/server/src/auth/token.ts index f29d4dbdd..9dcf99736 100644 --- a/packages/server/src/auth/token.ts +++ b/packages/server/src/auth/token.ts @@ -35,10 +35,10 @@ export const validateBearerToken = async ( const result = await luciaToken.validateSession(sessionId); if (result.user) { - if (result.user?.rol === "admin") { + if (result.user?.rol === "owner") { const admin = await findAdminByAuthId(result.user.id); result.user.adminId = admin.adminId; - } else if (result.user?.rol === "user") { + } else if (result.user?.rol === "member") { const userResult = await findUserByAuthId(result.user.id); result.user.adminId = userResult.adminId; } @@ -73,10 +73,10 @@ export const validateBearerTokenAPI = async ( const result = await luciaToken.validateSession(sessionId); if (result.user) { - if (result.user?.rol === "admin") { + if (result.user?.rol === "owner") { const admin = await findAdminByAuthId(result.user.id); result.user.adminId = admin.adminId; - } else if (result.user?.rol === "user") { + } else if (result.user?.rol === "member") { const userResult = await findUserByAuthId(result.user.id); result.user.adminId = userResult.adminId; } diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index ce636c134..522a921e8 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -75,9 +75,11 @@ export const auth = betterAuth({ additionalFields: { role: { type: "string", + required: true, }, ownerId: { type: "string", + required: true, }, }, }, diff --git a/packages/server/src/utils/providers/gitlab.ts b/packages/server/src/utils/providers/gitlab.ts index 096f9e284..a2c4b8ccb 100644 --- a/packages/server/src/utils/providers/gitlab.ts +++ b/packages/server/src/utils/providers/gitlab.ts @@ -268,7 +268,7 @@ export const getGitlabRepositories = async (gitlabId?: string) => { if (groupName) { return full_path.toLowerCase().includes(groupName) && kind === "group"; } - return kind === "user"; + return kind === "member"; }); const mappedRepositories = filteredRepos.map((repo: any) => { return { @@ -442,7 +442,7 @@ export const testGitlabConnection = async ( if (groupName) { return full_path.toLowerCase().includes(groupName) && kind === "group"; } - return kind === "user"; + return kind === "member"; }); return filteredRepos.length; From 8b71f963cc9fd5d111f4144c27674d15d53e6bd6 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 19:35:22 -0600 Subject: [PATCH 25/89] refactor: update logic --- .../dashboard/settings/profile/generate-token.tsx | 2 +- .../dashboard/settings/profile/profile-form.tsx | 12 ++++++------ apps/dokploy/components/layouts/user-nav.tsx | 9 ++++++--- apps/dokploy/pages/dashboard/settings/profile.tsx | 4 ++-- apps/dokploy/server/api/trpc.ts | 8 ++++---- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx b/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx index 66486c330..ad7840b20 100644 --- a/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx @@ -51,7 +51,7 @@ export const GenerateToken = () => {
diff --git a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx index 9ae140c67..4da97d18b 100644 --- a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx @@ -73,9 +73,9 @@ export const ProfileForm = () => { const form = useForm({ defaultValues: { - email: data?.email || "", + email: data?.user?.email || "", password: "", - image: data?.image || "", + image: data?.user?.image || "", currentPassword: "", }, resolver: zodResolver(profileSchema), @@ -84,14 +84,14 @@ export const ProfileForm = () => { useEffect(() => { if (data) { form.reset({ - email: data?.email || "", + email: data?.user?.email || "", password: "", - image: data?.image || "", + image: data?.user?.image || "", currentPassword: "", }); - if (data.email) { - generateSHA256Hash(data.email).then((hash) => { + if (data.user.email) { + generateSHA256Hash(data.user.email).then((hash) => { setGravatarHash(hash); }); } diff --git a/apps/dokploy/components/layouts/user-nav.tsx b/apps/dokploy/components/layouts/user-nav.tsx index 421ea5f2b..d4de2019c 100644 --- a/apps/dokploy/components/layouts/user-nav.tsx +++ b/apps/dokploy/components/layouts/user-nav.tsx @@ -51,12 +51,15 @@ export const UserNav = () => { className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground" > - + CN
Account - {data?.email} + {data?.user?.email}
@@ -71,7 +74,7 @@ export const UserNav = () => { My Account - {data?.email} + {data?.user?.email} diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index 1d6d9896d..656c30996 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -19,7 +19,7 @@ const Page = () => { authId: data?.id || "", }, { - enabled: !!data?.id && data?.role === "member", + enabled: !!data?.id && data?.role === "user", }, ); @@ -62,7 +62,7 @@ export async function getServerSideProps( await helpers.settings.isCloud.prefetch(); await helpers.auth.get.prefetch(); - if (user?.role === "member") { + if (user?.role === "user") { await helpers.user.byAuthId.prefetch({ authId: user.authId, }); diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index 4e777883a..98b5ab8e4 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -31,7 +31,7 @@ import { ZodError } from "zod"; */ interface CreateContextOptions { - user: (User & { rol: "admin" | "user"; ownerId: string }) | null; + user: (User & { rol: "member" | "admin" | "owner"; ownerId: string }) | null; session: (Session & { activeOrganizationId?: string }) | null; req: CreateNextContextOptions["req"]; res: CreateNextContextOptions["res"]; @@ -91,7 +91,7 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { ? { ...user, email: user.email, - rol: user.role as "admin" | "user", + rol: user.role as "owner" | "member" | "admin", id: user.id, ownerId: user.ownerId, } @@ -188,7 +188,7 @@ export const uploadProcedure = async (opts: any) => { }; export const cliProcedure = t.procedure.use(({ ctx, next }) => { - if (!ctx.session || !ctx.user || ctx.user.rol !== "admin") { + if (!ctx.session || !ctx.user || ctx.user.rol !== "owner") { throw new TRPCError({ code: "UNAUTHORIZED" }); } return next({ @@ -202,7 +202,7 @@ export const cliProcedure = t.procedure.use(({ ctx, next }) => { }); export const adminProcedure = t.procedure.use(({ ctx, next }) => { - if (!ctx.session || !ctx.user || ctx.user.rol !== "admin") { + if (!ctx.session || !ctx.user || ctx.user.rol !== "owner") { throw new TRPCError({ code: "UNAUTHORIZED" }); } return next({ From 87b12ff6e91cc8df584cecac97e0b8d6a620ca97 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 20:06:33 -0600 Subject: [PATCH 26/89] refactor: update --- .../drizzle/0070_dusty_wind_dancer.sql | 2 + .../drizzle/0071_migrate-data-projects.sql | 27 + apps/dokploy/drizzle/meta/0070_snapshot.json | 5299 +++++++++++++++++ apps/dokploy/drizzle/meta/0071_snapshot.json | 5299 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 14 + apps/dokploy/migrate.ts | 24 + packages/server/auth-schema.ts | 149 +- packages/server/src/db/schema/project.ts | 8 + packages/server/src/db/schema/user.ts | 2 + 9 files changed, 10740 insertions(+), 84 deletions(-) create mode 100644 apps/dokploy/drizzle/0070_dusty_wind_dancer.sql create mode 100644 apps/dokploy/drizzle/0071_migrate-data-projects.sql create mode 100644 apps/dokploy/drizzle/meta/0070_snapshot.json create mode 100644 apps/dokploy/drizzle/meta/0071_snapshot.json diff --git a/apps/dokploy/drizzle/0070_dusty_wind_dancer.sql b/apps/dokploy/drizzle/0070_dusty_wind_dancer.sql new file mode 100644 index 000000000..c8308b4a8 --- /dev/null +++ b/apps/dokploy/drizzle/0070_dusty_wind_dancer.sql @@ -0,0 +1,2 @@ +ALTER TABLE "project" ADD COLUMN "organizationId" text;--> statement-breakpoint +ALTER TABLE "project" ADD CONSTRAINT "project_organizationId_organization_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/apps/dokploy/drizzle/0071_migrate-data-projects.sql b/apps/dokploy/drizzle/0071_migrate-data-projects.sql new file mode 100644 index 000000000..038dd0f62 --- /dev/null +++ b/apps/dokploy/drizzle/0071_migrate-data-projects.sql @@ -0,0 +1,27 @@ +-- Custom SQL migration file, put your code below! -- +-- Primero, actualizamos los proyectos con la organización del usuario +UPDATE "project" p +SET "organizationId" = ( + SELECT m."organization_id" + FROM "member" m + WHERE m."user_id" = p."userId" + AND m."role" = 'owner' + LIMIT 1 +) +WHERE p."organizationId" IS NULL; + +-- Verificamos que todos los proyectos tengan una organización +DO $$ +BEGIN + IF EXISTS ( + SELECT 1 + FROM "project" + WHERE "organizationId" IS NULL + ) THEN + RAISE EXCEPTION 'Hay proyectos sin organización asignada'; + END IF; +END $$; + +-- Hacemos organization_id NOT NULL después de la migración +ALTER TABLE "project" + ALTER COLUMN "organizationId" SET NOT NULL; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0070_snapshot.json b/apps/dokploy/drizzle/meta/0070_snapshot.json new file mode 100644 index 000000000..e4c51a577 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0070_snapshot.json @@ -0,0 +1,5299 @@ +{ + "id": "cd06dbbf-61cb-4aba-b096-49a1850ff32b", + "prevId": "e0842a94-530d-4a3c-a6b1-16cf37618b8b", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_adminId_admin_adminId_fk": { + "name": "user_adminId_admin_adminId_fk", + "tableFrom": "user", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_authId_auth_id_fk": { + "name": "user_authId_auth_id_fk", + "tableFrom": "user", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.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": "''" + }, + "token": { + "name": "token", + "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()" + }, + "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[]" + }, + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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.admin": { + "name": "admin", + "schema": "", + "columns": { + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripeCustomerId": { + "name": "stripeCustomerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripeSubscriptionId": { + "name": "stripeSubscriptionId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serversQuantity": { + "name": "serversQuantity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "admin_authId_auth_id_fk": { + "name": "admin_authId_auth_id_fk", + "tableFrom": "admin", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resetPasswordToken": { + "name": "resetPasswordToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resetPasswordExpiresAt": { + "name": "resetPasswordExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationToken": { + "name": "confirmationToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationExpiresAt": { + "name": "confirmationExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "project_userId_user_temp_id_fk": { + "name": "project_userId_user_temp_id_fk", + "tableFrom": "project", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "destination_userId_user_temp_id_fk": { + "name": "destination_userId_user_temp_id_fk", + "tableFrom": "destination", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "certificate_userId_user_temp_id_fk": { + "name": "certificate_userId_user_temp_id_fk", + "tableFrom": "certificate", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_temp_token_unique": { + "name": "session_temp_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_auth_id_fk": { + "name": "session_user_id_auth_id_fk", + "tableFrom": "session", + "tableTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redirect": { + "name": "redirect", + "schema": "", + "columns": { + "redirectId": { + "name": "redirectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "regex": { + "name": "regex", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replacement": { + "name": "replacement", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permanent": { + "name": "permanent", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "redirect_applicationId_application_applicationId_fk": { + "name": "redirect_applicationId_application_applicationId_fk", + "tableFrom": "redirect", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.security": { + "name": "security", + "schema": "", + "columns": { + "securityId": { + "name": "securityId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "security_applicationId_application_applicationId_fk": { + "name": "security_applicationId_application_applicationId_fk", + "tableFrom": "security", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "security_username_applicationId_unique": { + "name": "security_username_applicationId_unique", + "nullsNotDistinct": false, + "columns": [ + "username", + "applicationId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.port": { + "name": "port", + "schema": "", + "columns": { + "portId": { + "name": "portId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publishedPort": { + "name": "publishedPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_userId_user_temp_id_fk": { + "name": "registry_userId_user_temp_id_fk", + "tableFrom": "registry", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "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_userId_user_temp_id_fk": { + "name": "notification_userId_user_temp_id_fk", + "tableFrom": "notification", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + } + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "ssh-key_userId_user_temp_id_fk": { + "name": "ssh-key_userId_user_temp_id_fk", + "tableFrom": "ssh-key", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "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.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 + }, + "userId": { + "name": "userId", + "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_userId_user_temp_id_fk": { + "name": "server_userId_user_temp_id_fk", + "tableFrom": "server", + "tableTo": "user_temp", + "columnsFrom": [ + "userId" + ], + "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.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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0071_snapshot.json b/apps/dokploy/drizzle/meta/0071_snapshot.json new file mode 100644 index 000000000..782aa6451 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0071_snapshot.json @@ -0,0 +1,5299 @@ +{ + "id": "30a4b462-2f38-42ae-8291-f6a2ce6d0bb4", + "prevId": "cd06dbbf-61cb-4aba-b096-49a1850ff32b", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "tableTo": "ssh-key", + "columnsTo": [ + "sshKeyId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "columnsFrom": [ + "registryId" + ], + "tableTo": "registry", + "columnsTo": [ + "registryId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "columnsFrom": [ + "githubId" + ], + "tableTo": "github", + "columnsTo": [ + "githubId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "columnsFrom": [ + "gitlabId" + ], + "tableTo": "gitlab", + "columnsTo": [ + "gitlabId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "columnsFrom": [ + "bitbucketId" + ], + "tableTo": "bitbucket", + "columnsTo": [ + "bitbucketId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "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", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_adminId_admin_adminId_fk": { + "name": "user_adminId_admin_adminId_fk", + "tableFrom": "user", + "columnsFrom": [ + "adminId" + ], + "tableTo": "admin", + "columnsTo": [ + "adminId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "user_authId_auth_id_fk": { + "name": "user_authId_auth_id_fk", + "tableFrom": "user", + "columnsFrom": [ + "authId" + ], + "tableTo": "auth", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "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": "''" + }, + "token": { + "name": "token", + "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()" + }, + "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[]" + }, + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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", + "columns": [ + "email" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.admin": { + "name": "admin", + "schema": "", + "columns": { + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripeCustomerId": { + "name": "stripeCustomerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripeSubscriptionId": { + "name": "stripeSubscriptionId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serversQuantity": { + "name": "serversQuantity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "admin_authId_auth_id_fk": { + "name": "admin_authId_auth_id_fk", + "tableFrom": "admin", + "columnsFrom": [ + "authId" + ], + "tableTo": "auth", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resetPasswordToken": { + "name": "resetPasswordToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resetPasswordExpiresAt": { + "name": "resetPasswordExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationToken": { + "name": "confirmationToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationExpiresAt": { + "name": "confirmationExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "columns": [ + "email" + ], + "nullsNotDistinct": false + } + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": {}, + "foreignKeys": { + "project_userId_user_temp_id_fk": { + "name": "project_userId_user_temp_id_fk", + "tableFrom": "project", + "columnsFrom": [ + "userId" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "project_organizationId_organization_id_fk": { + "name": "project_organizationId_organization_id_fk", + "tableFrom": "project", + "columnsFrom": [ + "organizationId" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.domain": { + "name": "domain", + "schema": "", + "columns": { + "domainId": { + "name": "domainId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "https": { + "name": "https", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domainType": { + "name": "domainType", + "type": "domainType", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'application'" + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "columnsFrom": [ + "composeId" + ], + "tableTo": "compose", + "columnsTo": [ + "composeId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "columnsFrom": [ + "previewDeploymentId" + ], + "tableTo": "preview_deployments", + "columnsTo": [ + "previewDeploymentId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "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", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "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", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "columnsFrom": [ + "destinationId" + ], + "tableTo": "destination", + "columnsTo": [ + "destinationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "columnsFrom": [ + "postgresId" + ], + "tableTo": "postgres", + "columnsTo": [ + "postgresId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "columnsFrom": [ + "mariadbId" + ], + "tableTo": "mariadb", + "columnsTo": [ + "mariadbId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "columnsFrom": [ + "mysqlId" + ], + "tableTo": "mysql", + "columnsTo": [ + "mysqlId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "columnsFrom": [ + "mongoId" + ], + "tableTo": "mongo", + "columnsTo": [ + "mongoId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "destination_userId_user_temp_id_fk": { + "name": "destination_userId_user_temp_id_fk", + "tableFrom": "destination", + "columnsFrom": [ + "userId" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment": { + "name": "deployment", + "schema": "", + "columns": { + "deploymentId": { + "name": "deploymentId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "deploymentStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'running'" + }, + "logPath": { + "name": "logPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "columnsFrom": [ + "composeId" + ], + "tableTo": "compose", + "columnsTo": [ + "composeId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "columnsFrom": [ + "previewDeploymentId" + ], + "tableTo": "preview_deployments", + "columnsTo": [ + "previewDeploymentId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "postgresId" + ], + "tableTo": "postgres", + "columnsTo": [ + "postgresId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "mariadbId" + ], + "tableTo": "mariadb", + "columnsTo": [ + "mariadbId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "mongoId" + ], + "tableTo": "mongo", + "columnsTo": [ + "mongoId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "mysqlId" + ], + "tableTo": "mysql", + "columnsTo": [ + "mysqlId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "redisId" + ], + "tableTo": "redis", + "columnsTo": [ + "redisId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "columnsFrom": [ + "composeId" + ], + "tableTo": "compose", + "columnsTo": [ + "composeId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "certificate_userId_user_temp_id_fk": { + "name": "certificate_userId_user_temp_id_fk", + "tableFrom": "certificate", + "columnsFrom": [ + "userId" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "certificate_serverId_server_serverId_fk": { + "name": "certificate_serverId_server_serverId_fk", + "tableFrom": "certificate", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "certificate_certificatePath_unique": { + "name": "certificate_certificatePath_unique", + "columns": [ + "certificatePath" + ], + "nullsNotDistinct": false + } + }, + "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", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_temp_token_unique": { + "name": "session_temp_token_unique", + "columns": [ + "token" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_auth_id_fk": { + "name": "session_user_id_auth_id_fk", + "tableFrom": "session", + "columnsFrom": [ + "user_id" + ], + "tableTo": "auth", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redirect": { + "name": "redirect", + "schema": "", + "columns": { + "redirectId": { + "name": "redirectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "regex": { + "name": "regex", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replacement": { + "name": "replacement", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permanent": { + "name": "permanent", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "redirect_applicationId_application_applicationId_fk": { + "name": "redirect_applicationId_application_applicationId_fk", + "tableFrom": "redirect", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "security_username_applicationId_unique": { + "name": "security_username_applicationId_unique", + "columns": [ + "username", + "applicationId" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.port": { + "name": "port", + "schema": "", + "columns": { + "portId": { + "name": "portId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publishedPort": { + "name": "publishedPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "tableTo": "ssh-key", + "columnsTo": [ + "sshKeyId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "projectId" + ], + "tableTo": "project", + "columnsTo": [ + "projectId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "githubId" + ], + "tableTo": "github", + "columnsTo": [ + "githubId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "gitlabId" + ], + "tableTo": "gitlab", + "columnsTo": [ + "gitlabId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "bitbucketId" + ], + "tableTo": "bitbucket", + "columnsTo": [ + "bitbucketId" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "columnsFrom": [ + "serverId" + ], + "tableTo": "server", + "columnsTo": [ + "serverId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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'" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "registry_userId_user_temp_id_fk": { + "name": "registry_userId_user_temp_id_fk", + "tableFrom": "registry", + "columnsFrom": [ + "userId" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "notification_slackId_slack_slackId_fk": { + "name": "notification_slackId_slack_slackId_fk", + "tableFrom": "notification", + "columnsFrom": [ + "slackId" + ], + "tableTo": "slack", + "columnsTo": [ + "slackId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "notification_telegramId_telegram_telegramId_fk": { + "name": "notification_telegramId_telegram_telegramId_fk", + "tableFrom": "notification", + "columnsFrom": [ + "telegramId" + ], + "tableTo": "telegram", + "columnsTo": [ + "telegramId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "notification_discordId_discord_discordId_fk": { + "name": "notification_discordId_discord_discordId_fk", + "tableFrom": "notification", + "columnsFrom": [ + "discordId" + ], + "tableTo": "discord", + "columnsTo": [ + "discordId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "notification_emailId_email_emailId_fk": { + "name": "notification_emailId_email_emailId_fk", + "tableFrom": "notification", + "columnsFrom": [ + "emailId" + ], + "tableTo": "email", + "columnsTo": [ + "emailId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "notification_gotifyId_gotify_gotifyId_fk": { + "name": "notification_gotifyId_gotify_gotifyId_fk", + "tableFrom": "notification", + "columnsFrom": [ + "gotifyId" + ], + "tableTo": "gotify", + "columnsTo": [ + "gotifyId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "notification_userId_user_temp_id_fk": { + "name": "notification_userId_user_temp_id_fk", + "tableFrom": "notification", + "columnsFrom": [ + "userId" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack": { + "name": "slack", + "schema": "", + "columns": { + "slackId": { + "name": "slackId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.telegram": { + "name": "telegram", + "schema": "", + "columns": { + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "botToken": { + "name": "botToken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chatId": { + "name": "chatId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ssh-key": { + "name": "ssh-key", + "schema": "", + "columns": { + "sshKeyId": { + "name": "sshKeyId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "publicKey": { + "name": "publicKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "lastUsedAt": { + "name": "lastUsedAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "ssh-key_userId_user_temp_id_fk": { + "name": "ssh-key_userId_user_temp_id_fk", + "tableFrom": "ssh-key", + "columnsFrom": [ + "userId" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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 + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "git_provider_userId_user_temp_id_fk": { + "name": "git_provider_userId_user_temp_id_fk", + "tableFrom": "git_provider", + "columnsFrom": [ + "userId" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "gitProviderId" + ], + "tableTo": "git_provider", + "columnsTo": [ + "gitProviderId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "gitProviderId" + ], + "tableTo": "git_provider", + "columnsTo": [ + "gitProviderId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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", + "columnsFrom": [ + "gitProviderId" + ], + "tableTo": "git_provider", + "columnsTo": [ + "gitProviderId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "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 + }, + "userId": { + "name": "userId", + "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_userId_user_temp_id_fk": { + "name": "server_userId_user_temp_id_fk", + "tableFrom": "server", + "columnsFrom": [ + "userId" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "server_sshKeyId_ssh-key_sshKeyId_fk": { + "name": "server_sshKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "server", + "columnsFrom": [ + "sshKeyId" + ], + "tableTo": "ssh-key", + "columnsTo": [ + "sshKeyId" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "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", + "columnsFrom": [ + "applicationId" + ], + "tableTo": "application", + "columnsTo": [ + "applicationId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "preview_deployments_domainId_domain_domainId_fk": { + "name": "preview_deployments_domainId_domain_domainId_fk", + "tableFrom": "preview_deployments", + "columnsFrom": [ + "domainId" + ], + "tableTo": "domain", + "columnsTo": [ + "domainId" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "preview_deployments_appName_unique": { + "name": "preview_deployments_appName_unique", + "columns": [ + "appName" + ], + "nullsNotDistinct": false + } + }, + "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", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "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 + } + }, + "indexes": {}, + "foreignKeys": { + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "invitation_inviter_id_user_temp_id_fk": { + "name": "invitation_inviter_id_user_temp_id_fk", + "tableFrom": "invitation", + "columnsFrom": [ + "inviter_id" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "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 + } + }, + "indexes": {}, + "foreignKeys": { + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "member_user_id_user_temp_id_fk": { + "name": "member_user_id_user_temp_id_fk", + "tableFrom": "member", + "columnsFrom": [ + "user_id" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "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", + "columnsFrom": [ + "owner_id" + ], + "tableTo": "user_temp", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "columns": [ + "slug" + ], + "nullsNotDistinct": false + } + }, + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "views": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "_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 39934064c..c11391251 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -491,6 +491,20 @@ "when": 1739664410814, "tag": "0069_broad_ken_ellis", "breakpoints": true + }, + { + "idx": 70, + "version": "7", + "when": 1739671371444, + "tag": "0070_dusty_wind_dancer", + "breakpoints": true + }, + { + "idx": 71, + "version": "7", + "when": 1739671387634, + "tag": "0071_migrate-data-projects", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/migrate.ts b/apps/dokploy/migrate.ts index d56006f18..38f48784c 100644 --- a/apps/dokploy/migrate.ts +++ b/apps/dokploy/migrate.ts @@ -124,3 +124,27 @@ await db .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/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index bfb03d2e4..20b0a2b61 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,96 +1,77 @@ -import { - boolean, - integer, - pgTable, - text, - timestamp, -} from "drizzle-orm/pg-core"; - -export const user = pgTable("user", { - id: text("id").primaryKey(), - name: text("name").notNull(), - email: text("email").notNull().unique(), - emailVerified: boolean("email_verified").notNull(), - image: text("image"), - createdAt: timestamp("created_at").notNull(), - updatedAt: timestamp("updated_at").notNull(), -}); +import { pgTable, text, integer, timestamp, boolean } from "drizzle-orm/pg-core"; + +export const users_temp = pgTable("users_temp", { + id: text("id").primaryKey(), + name: text('name').notNull(), + email: text('email').notNull().unique(), + emailVerified: boolean('email_verified').notNull(), + image: text('image'), + createdAt: timestamp('created_at').notNull(), + updatedAt: timestamp('updated_at').notNull(), + role: text('role').notNull(), + ownerId: text('owner_id').notNull() + }); export const session = pgTable("session", { - id: text("id").primaryKey(), - expiresAt: timestamp("expires_at").notNull(), - token: text("token").notNull().unique(), - createdAt: timestamp("created_at").notNull(), - updatedAt: timestamp("updated_at").notNull(), - ipAddress: text("ip_address"), - userAgent: text("user_agent"), - userId: text("user_id") - .notNull() - .references(() => user.id), - activeOrganizationId: text("active_organization_id"), -}); + id: text("id").primaryKey(), + expiresAt: timestamp('expires_at').notNull(), + token: text('token').notNull().unique(), + createdAt: timestamp('created_at').notNull(), + updatedAt: timestamp('updated_at').notNull(), + ipAddress: text('ip_address'), + userAgent: text('user_agent'), + userId: text('user_id').notNull().references(()=> users_temp.id, { onDelete: 'cascade' }), + activeOrganizationId: text('active_organization_id') + }); export const account = pgTable("account", { - id: text("id").primaryKey(), - accountId: text("account_id").notNull(), - providerId: text("provider_id").notNull(), - userId: text("user_id") - .notNull() - .references(() => user.id), - accessToken: text("access_token"), - refreshToken: text("refresh_token"), - idToken: text("id_token"), - accessTokenExpiresAt: timestamp("access_token_expires_at"), - refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), - scope: text("scope"), - password: text("password"), - createdAt: timestamp("created_at").notNull(), - updatedAt: timestamp("updated_at").notNull(), -}); + id: text("id").primaryKey(), + accountId: text('account_id').notNull(), + providerId: text('provider_id').notNull(), + userId: text('user_id').notNull().references(()=> users_temp.id, { onDelete: 'cascade' }), + accessToken: text('access_token'), + refreshToken: text('refresh_token'), + idToken: text('id_token'), + accessTokenExpiresAt: timestamp('access_token_expires_at'), + refreshTokenExpiresAt: timestamp('refresh_token_expires_at'), + scope: text('scope'), + password: text('password'), + createdAt: timestamp('created_at').notNull(), + updatedAt: timestamp('updated_at').notNull() + }); export const verification = pgTable("verification", { - id: text("id").primaryKey(), - identifier: text("identifier").notNull(), - value: text("value").notNull(), - expiresAt: timestamp("expires_at").notNull(), - createdAt: timestamp("created_at"), - updatedAt: timestamp("updated_at"), -}); + id: text("id").primaryKey(), + identifier: text('identifier').notNull(), + value: text('value').notNull(), + expiresAt: timestamp('expires_at').notNull(), + createdAt: timestamp('created_at'), + updatedAt: timestamp('updated_at') + }); export const organization = pgTable("organization", { - id: text("id").primaryKey(), - name: text("name").notNull(), - slug: text("slug").unique(), - logo: text("logo"), - createdAt: timestamp("created_at").notNull(), - metadata: text("metadata"), - ownerId: text("owner_id") - .notNull() - .references(() => user.userId), -}); + id: text("id").primaryKey(), + name: text('name').notNull(), + slug: text('slug').unique(), + logo: text('logo'), + createdAt: timestamp('created_at').notNull(), + metadata: text('metadata') + }); export const member = pgTable("member", { - id: text("id").primaryKey(), - organizationId: text("organization_id") - .notNull() - .references(() => organization.id), - userId: text("user_id") - .notNull() - .references(() => user.userId), - role: text("role").notNull(), - createdAt: timestamp("created_at").notNull(), -}); + id: text("id").primaryKey(), + organizationId: text('organization_id').notNull().references(()=> organization.id, { onDelete: 'cascade' }), + userId: text('user_id').notNull().references(()=> user.id, { onDelete: 'cascade' }), + role: text('role').notNull(), + createdAt: timestamp('created_at').notNull() + }); export const invitation = pgTable("invitation", { - id: text("id").primaryKey(), - organizationId: text("organization_id") - .notNull() - .references(() => organization.id), - email: text("email").notNull(), - role: text("role"), - status: text("status").notNull(), - expiresAt: timestamp("expires_at").notNull(), - inviterId: text("inviter_id") - .notNull() - .references(() => user.userId), -}); + id: text("id").primaryKey(), + organizationId: text('organization_id').notNull().references(()=> organization.id, { onDelete: 'cascade' }), + email: text('email').notNull(), + role: text('role'), + status: text('status').notNull(), + expiresAt: timestamp('expires_at').notNull(), + inviterId: text('inviter_id').notNull().references(()=> user.id, { onDelete: 'cascade' }) + }); diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index 60f7842b1..ee8859327 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -14,6 +14,7 @@ import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; import { users, users_temp } from "./user"; +import { organization } from "./account"; export const projects = pgTable("project", { projectId: text("projectId") @@ -31,6 +32,9 @@ export const projects = pgTable("project", { userId: text("userId") .notNull() .references(() => users_temp.id, { onDelete: "cascade" }), + organizationId: text("organizationId") + // .notNull() + .references(() => organization.id, { onDelete: "cascade" }), env: text("env").notNull().default(""), }); @@ -42,6 +46,10 @@ export const projectRelations = relations(projects, ({ many, one }) => ({ mongo: many(mongo), redis: many(redis), compose: many(compose), + user: one(users_temp, { + fields: [projects.userId], + references: [users_temp.id], + }), // user: one(user, { // fields: [projects.userId], // references: [user.id], diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index c05b734a7..359cfbd45 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -14,6 +14,7 @@ import { account, organization } from "./account"; import { admins } from "./admin"; import { auth } from "./auth"; import { certificateType } from "./shared"; +import { projects } from "./project"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * database instance for multiple projects. @@ -199,6 +200,7 @@ export const usersRelations = relations(users_temp, ({ one, many }) => ({ // fields: [users.adminId], // references: [admins.adminId], // }), + projects: many(projects), })); const createSchema = createInsertSchema(users_temp, { From 53ce5e57faf313bc754007fdc52fd5b20251080d Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 20:25:58 -0600 Subject: [PATCH 27/89] refactor: update organization --- .../drizzle/0070_dusty_wind_dancer.sql | 2 - .../drizzle/0070_nervous_vivisector.sql | 16 + .../drizzle/0071_migrate-data-projects.sql | 135 +- apps/dokploy/drizzle/0072_lazy_pixie.sql | 32 + apps/dokploy/drizzle/meta/0070_snapshot.json | 135 +- apps/dokploy/drizzle/meta/0071_snapshot.json | 137 +- apps/dokploy/drizzle/meta/0072_snapshot.json | 5280 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 13 +- packages/server/src/db/schema/certificate.ts | 14 +- packages/server/src/db/schema/destination.ts | 12 +- packages/server/src/db/schema/git-provider.ts | 14 +- packages/server/src/db/schema/notification.ts | 14 +- packages/server/src/db/schema/project.ts | 19 +- packages/server/src/db/schema/registry.ts | 10 +- packages/server/src/db/schema/server.ts | 9 +- packages/server/src/db/schema/ssh-key.ts | 16 +- 16 files changed, 5776 insertions(+), 82 deletions(-) delete mode 100644 apps/dokploy/drizzle/0070_dusty_wind_dancer.sql create mode 100644 apps/dokploy/drizzle/0070_nervous_vivisector.sql create mode 100644 apps/dokploy/drizzle/0072_lazy_pixie.sql create mode 100644 apps/dokploy/drizzle/meta/0072_snapshot.json diff --git a/apps/dokploy/drizzle/0070_dusty_wind_dancer.sql b/apps/dokploy/drizzle/0070_dusty_wind_dancer.sql deleted file mode 100644 index c8308b4a8..000000000 --- a/apps/dokploy/drizzle/0070_dusty_wind_dancer.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE "project" ADD COLUMN "organizationId" text;--> statement-breakpoint -ALTER TABLE "project" ADD CONSTRAINT "project_organizationId_organization_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/apps/dokploy/drizzle/0070_nervous_vivisector.sql b/apps/dokploy/drizzle/0070_nervous_vivisector.sql new file mode 100644 index 000000000..238a17693 --- /dev/null +++ b/apps/dokploy/drizzle/0070_nervous_vivisector.sql @@ -0,0 +1,16 @@ +ALTER TABLE "project" ADD COLUMN "organizationId" text;--> statement-breakpoint +ALTER TABLE "destination" ADD COLUMN "organizationId" text;--> statement-breakpoint +ALTER TABLE "certificate" ADD COLUMN "organizationId" text;--> statement-breakpoint +ALTER TABLE "registry" ADD COLUMN "organizationId" text;--> statement-breakpoint +ALTER TABLE "notification" ADD COLUMN "organizationId" text;--> statement-breakpoint +ALTER TABLE "ssh-key" ADD COLUMN "organizationId" text;--> statement-breakpoint +ALTER TABLE "git_provider" ADD COLUMN "organizationId" text;--> statement-breakpoint +ALTER TABLE "server" ADD COLUMN "organizationId" text;--> statement-breakpoint +ALTER TABLE "project" ADD CONSTRAINT "project_organizationId_organization_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "destination" ADD CONSTRAINT "destination_organizationId_organization_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "certificate" ADD CONSTRAINT "certificate_organizationId_organization_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "registry" ADD CONSTRAINT "registry_organizationId_organization_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "notification" ADD CONSTRAINT "notification_organizationId_organization_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "ssh-key" ADD CONSTRAINT "ssh-key_organizationId_organization_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "git_provider" ADD CONSTRAINT "git_provider_organizationId_organization_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "server" ADD CONSTRAINT "server_organizationId_organization_id_fk" FOREIGN KEY ("organizationId") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/apps/dokploy/drizzle/0071_migrate-data-projects.sql b/apps/dokploy/drizzle/0071_migrate-data-projects.sql index 038dd0f62..27ca0bea0 100644 --- a/apps/dokploy/drizzle/0071_migrate-data-projects.sql +++ b/apps/dokploy/drizzle/0071_migrate-data-projects.sql @@ -1,5 +1,6 @@ --- Custom SQL migration file, put your code below! -- --- Primero, actualizamos los proyectos con la organización del usuario +-- Custom SQL migration file + +-- Actualizar projects UPDATE "project" p SET "organizationId" = ( SELECT m."organization_id" @@ -10,18 +11,132 @@ SET "organizationId" = ( ) WHERE p."organizationId" IS NULL; --- Verificamos que todos los proyectos tengan una organización +-- Actualizar servers +UPDATE "server" s +SET "organizationId" = ( + SELECT m."organization_id" + FROM "member" m + WHERE m."user_id" = s."userId" + AND m."role" = 'owner' + LIMIT 1 +) +WHERE s."organizationId" IS NULL; + +-- Actualizar ssh-keys +UPDATE "ssh-key" k +SET "organizationId" = ( + SELECT m."organization_id" + FROM "member" m + WHERE m."user_id" = k."userId" + AND m."role" = 'owner' + LIMIT 1 +) +WHERE k."organizationId" IS NULL; + +-- Actualizar destinations +UPDATE "destination" d +SET "organizationId" = ( + SELECT m."organization_id" + FROM "member" m + WHERE m."user_id" = d."userId" + AND m."role" = 'owner' + LIMIT 1 +) +WHERE d."organizationId" IS NULL; + +-- Actualizar registry +UPDATE "registry" r +SET "organizationId" = ( + SELECT m."organization_id" + FROM "member" m + WHERE m."user_id" = r."userId" + AND m."role" = 'owner' + LIMIT 1 +) +WHERE r."organizationId" IS NULL; + +-- Actualizar notifications +UPDATE "notification" n +SET "organizationId" = ( + SELECT m."organization_id" + FROM "member" m + WHERE m."user_id" = n."userId" + AND m."role" = 'owner' + LIMIT 1 +) +WHERE n."organizationId" IS NULL; + +-- Actualizar certificates +UPDATE "certificate" c +SET "organizationId" = ( + SELECT m."organization_id" + FROM "member" m + WHERE m."user_id" = c."userId" + AND m."role" = 'owner' + LIMIT 1 +) +WHERE c."organizationId" IS NULL; + +-- Actualizar git_provider +UPDATE "git_provider" g +SET "organizationId" = ( + SELECT m."organization_id" + FROM "member" m + WHERE m."user_id" = g."userId" + AND m."role" = 'owner' + LIMIT 1 +) +WHERE g."organizationId" IS NULL; + +-- Verificar que todos los recursos tengan una organización DO $$ BEGIN IF EXISTS ( - SELECT 1 - FROM "project" - WHERE "organizationId" IS NULL + SELECT 1 FROM "project" WHERE "organizationId" IS NULL + UNION ALL + SELECT 1 FROM "server" WHERE "organizationId" IS NULL + UNION ALL + SELECT 1 FROM "ssh-key" WHERE "organizationId" IS NULL + UNION ALL + SELECT 1 FROM "destination" WHERE "organizationId" IS NULL + UNION ALL + SELECT 1 FROM "registry" WHERE "organizationId" IS NULL + UNION ALL + SELECT 1 FROM "notification" WHERE "organizationId" IS NULL + UNION ALL + SELECT 1 FROM "certificate" WHERE "organizationId" IS NULL + UNION ALL + SELECT 1 FROM "git_provider" WHERE "organizationId" IS NULL ) THEN - RAISE EXCEPTION 'Hay proyectos sin organización asignada'; + RAISE EXCEPTION 'Hay recursos sin organización asignada'; END IF; END $$; --- Hacemos organization_id NOT NULL después de la migración -ALTER TABLE "project" - ALTER COLUMN "organizationId" SET NOT NULL; \ No newline at end of file +-- Hacer organization_id NOT NULL en todas las tablas +ALTER TABLE "project" ALTER COLUMN "organizationId" SET NOT NULL; +ALTER TABLE "server" ALTER COLUMN "organizationId" SET NOT NULL; +ALTER TABLE "ssh-key" ALTER COLUMN "organizationId" SET NOT NULL; +ALTER TABLE "destination" ALTER COLUMN "organizationId" SET NOT NULL; +ALTER TABLE "registry" ALTER COLUMN "organizationId" SET NOT NULL; +ALTER TABLE "notification" ALTER COLUMN "organizationId" SET NOT NULL; +ALTER TABLE "certificate" ALTER COLUMN "organizationId" SET NOT NULL; +ALTER TABLE "git_provider" ALTER COLUMN "organizationId" SET NOT NULL; + +-- Crear índices para mejorar el rendimiento de búsquedas por organización +CREATE INDEX IF NOT EXISTS "idx_project_organization" ON "project" ("organizationId"); +CREATE INDEX IF NOT EXISTS "idx_server_organization" ON "server" ("organizationId"); +CREATE INDEX IF NOT EXISTS "idx_sshkey_organization" ON "ssh-key" ("organizationId"); +CREATE INDEX IF NOT EXISTS "idx_destination_organization" ON "destination" ("organizationId"); +CREATE INDEX IF NOT EXISTS "idx_registry_organization" ON "registry" ("organizationId"); +CREATE INDEX IF NOT EXISTS "idx_notification_organization" ON "notification" ("organizationId"); +CREATE INDEX IF NOT EXISTS "idx_certificate_organization" ON "certificate" ("organizationId"); +CREATE INDEX IF NOT EXISTS "idx_git_provider_organization" ON "git_provider" ("organizationId"); + + + + + + + + + diff --git a/apps/dokploy/drizzle/0072_lazy_pixie.sql b/apps/dokploy/drizzle/0072_lazy_pixie.sql new file mode 100644 index 000000000..f86f444d4 --- /dev/null +++ b/apps/dokploy/drizzle/0072_lazy_pixie.sql @@ -0,0 +1,32 @@ +ALTER TABLE "project" DROP CONSTRAINT "project_userId_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "destination" DROP CONSTRAINT "destination_userId_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "certificate" DROP CONSTRAINT "certificate_userId_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "registry" DROP CONSTRAINT "registry_userId_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "notification" DROP CONSTRAINT "notification_userId_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "ssh-key" DROP CONSTRAINT "ssh-key_userId_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "git_provider" DROP CONSTRAINT "git_provider_userId_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "server" DROP CONSTRAINT "server_userId_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "project" ALTER COLUMN "organizationId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "destination" ALTER COLUMN "organizationId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "certificate" ALTER COLUMN "organizationId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "registry" ALTER COLUMN "organizationId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "notification" ALTER COLUMN "organizationId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "ssh-key" ALTER COLUMN "organizationId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "git_provider" ALTER COLUMN "organizationId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "server" ALTER COLUMN "organizationId" SET NOT NULL;--> statement-breakpoint +ALTER TABLE "project" DROP COLUMN "userId";--> statement-breakpoint +ALTER TABLE "destination" DROP COLUMN "userId";--> statement-breakpoint +ALTER TABLE "certificate" DROP COLUMN "userId";--> statement-breakpoint +ALTER TABLE "registry" DROP COLUMN "userId";--> statement-breakpoint +ALTER TABLE "notification" DROP COLUMN "userId";--> statement-breakpoint +ALTER TABLE "ssh-key" DROP COLUMN "userId";--> statement-breakpoint +ALTER TABLE "git_provider" DROP COLUMN "userId";--> statement-breakpoint +ALTER TABLE "server" DROP COLUMN "userId"; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0070_snapshot.json b/apps/dokploy/drizzle/meta/0070_snapshot.json index e4c51a577..681bded7e 100644 --- a/apps/dokploy/drizzle/meta/0070_snapshot.json +++ b/apps/dokploy/drizzle/meta/0070_snapshot.json @@ -1,5 +1,5 @@ { - "id": "cd06dbbf-61cb-4aba-b096-49a1850ff32b", + "id": "8e8626de-fb34-4c11-b9d0-b7a958993fb7", "prevId": "e0842a94-530d-4a3c-a6b1-16cf37618b8b", "version": "7", "dialect": "postgresql", @@ -2352,6 +2352,12 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false } }, "indexes": {}, @@ -2368,6 +2374,19 @@ ], "onDelete": "cascade", "onUpdate": "no action" + }, + "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": {}, @@ -2761,6 +2780,12 @@ "primaryKey": false, "notNull": true }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, "serverId": { "name": "serverId", "type": "text", @@ -2783,6 +2808,19 @@ "onDelete": "cascade", "onUpdate": "no action" }, + "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", @@ -3677,6 +3715,12 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false } }, "indexes": {}, @@ -3693,6 +3737,19 @@ ], "onDelete": "cascade", "onUpdate": "no action" + }, + "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": {}, @@ -3937,6 +3994,12 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false } }, "indexes": {}, @@ -4018,6 +4081,19 @@ ], "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": {}, @@ -4140,6 +4216,12 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false } }, "indexes": {}, @@ -4156,6 +4238,19 @@ ], "onDelete": "cascade", "onUpdate": "no action" + }, + "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": {}, @@ -4199,6 +4294,12 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false } }, "indexes": {}, @@ -4215,6 +4316,19 @@ ], "onDelete": "cascade", "onUpdate": "no action" + }, + "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" } }, "compositePrimaryKeys": {}, @@ -4515,6 +4629,12 @@ "primaryKey": false, "notNull": true }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, "serverStatus": { "name": "serverStatus", "type": "serverStatus", @@ -4559,6 +4679,19 @@ "onDelete": "cascade", "onUpdate": "no action" }, + "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", diff --git a/apps/dokploy/drizzle/meta/0071_snapshot.json b/apps/dokploy/drizzle/meta/0071_snapshot.json index 782aa6451..4214343a0 100644 --- a/apps/dokploy/drizzle/meta/0071_snapshot.json +++ b/apps/dokploy/drizzle/meta/0071_snapshot.json @@ -1,6 +1,6 @@ { - "id": "30a4b462-2f38-42ae-8291-f6a2ce6d0bb4", - "prevId": "cd06dbbf-61cb-4aba-b096-49a1850ff32b", + "id": "11cb27c0-0f5a-4ec9-98be-5b6f7c5e7799", + "prevId": "8e8626de-fb34-4c11-b9d0-b7a958993fb7", "version": "7", "dialect": "postgresql", "tables": { @@ -2352,6 +2352,12 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false } }, "indexes": {}, @@ -2368,6 +2374,19 @@ ], "onUpdate": "no action", "onDelete": "cascade" + }, + "destination_organizationId_organization_id_fk": { + "name": "destination_organizationId_organization_id_fk", + "tableFrom": "destination", + "columnsFrom": [ + "organizationId" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" } }, "compositePrimaryKeys": {}, @@ -2761,6 +2780,12 @@ "primaryKey": false, "notNull": true }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, "serverId": { "name": "serverId", "type": "text", @@ -2783,6 +2808,19 @@ "onUpdate": "no action", "onDelete": "cascade" }, + "certificate_organizationId_organization_id_fk": { + "name": "certificate_organizationId_organization_id_fk", + "tableFrom": "certificate", + "columnsFrom": [ + "organizationId" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, "certificate_serverId_server_serverId_fk": { "name": "certificate_serverId_server_serverId_fk", "tableFrom": "certificate", @@ -3677,6 +3715,12 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false } }, "indexes": {}, @@ -3693,6 +3737,19 @@ ], "onUpdate": "no action", "onDelete": "cascade" + }, + "registry_organizationId_organization_id_fk": { + "name": "registry_organizationId_organization_id_fk", + "tableFrom": "registry", + "columnsFrom": [ + "organizationId" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" } }, "compositePrimaryKeys": {}, @@ -3937,6 +3994,12 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false } }, "indexes": {}, @@ -4018,6 +4081,19 @@ ], "onUpdate": "no action", "onDelete": "cascade" + }, + "notification_organizationId_organization_id_fk": { + "name": "notification_organizationId_organization_id_fk", + "tableFrom": "notification", + "columnsFrom": [ + "organizationId" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" } }, "compositePrimaryKeys": {}, @@ -4140,6 +4216,12 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false } }, "indexes": {}, @@ -4156,6 +4238,19 @@ ], "onUpdate": "no action", "onDelete": "cascade" + }, + "ssh-key_organizationId_organization_id_fk": { + "name": "ssh-key_organizationId_organization_id_fk", + "tableFrom": "ssh-key", + "columnsFrom": [ + "organizationId" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" } }, "compositePrimaryKeys": {}, @@ -4199,6 +4294,12 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false } }, "indexes": {}, @@ -4215,6 +4316,19 @@ ], "onUpdate": "no action", "onDelete": "cascade" + }, + "git_provider_organizationId_organization_id_fk": { + "name": "git_provider_organizationId_organization_id_fk", + "tableFrom": "git_provider", + "columnsFrom": [ + "organizationId" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" } }, "compositePrimaryKeys": {}, @@ -4515,6 +4629,12 @@ "primaryKey": false, "notNull": true }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, "serverStatus": { "name": "serverStatus", "type": "serverStatus", @@ -4559,6 +4679,19 @@ "onUpdate": "no action", "onDelete": "cascade" }, + "server_organizationId_organization_id_fk": { + "name": "server_organizationId_organization_id_fk", + "tableFrom": "server", + "columnsFrom": [ + "organizationId" + ], + "tableTo": "organization", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, "server_sshKeyId_ssh-key_sshKeyId_fk": { "name": "server_sshKeyId_ssh-key_sshKeyId_fk", "tableFrom": "server", diff --git a/apps/dokploy/drizzle/meta/0072_snapshot.json b/apps/dokploy/drizzle/meta/0072_snapshot.json new file mode 100644 index 000000000..2f38d98d9 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0072_snapshot.json @@ -0,0 +1,5280 @@ +{ + "id": "4eb71c0e-5bdb-427b-b198-39b1059dcd16", + "prevId": "11cb27c0-0f5a-4ec9-98be-5b6f7c5e7799", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_adminId_admin_adminId_fk": { + "name": "user_adminId_admin_adminId_fk", + "tableFrom": "user", + "tableTo": "admin", + "columnsFrom": [ + "adminId" + ], + "columnsTo": [ + "adminId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_authId_auth_id_fk": { + "name": "user_authId_auth_id_fk", + "tableFrom": "user", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.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": "''" + }, + "token": { + "name": "token", + "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()" + }, + "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[]" + }, + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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.admin": { + "name": "admin", + "schema": "", + "columns": { + "adminId": { + "name": "adminId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverIp": { + "name": "serverIp", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "authId": { + "name": "authId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripeCustomerId": { + "name": "stripeCustomerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripeSubscriptionId": { + "name": "stripeSubscriptionId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serversQuantity": { + "name": "serversQuantity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "admin_authId_auth_id_fk": { + "name": "admin_authId_auth_id_fk", + "tableFrom": "admin", + "tableTo": "auth", + "columnsFrom": [ + "authId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auth": { + "name": "auth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rol": { + "name": "rol", + "type": "Roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is2FAEnabled": { + "name": "is2FAEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resetPasswordToken": { + "name": "resetPasswordToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resetPasswordExpiresAt": { + "name": "resetPasswordExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationToken": { + "name": "confirmationToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confirmationExpiresAt": { + "name": "confirmationExpiresAt", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "auth_email_unique": { + "name": "auth_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_temp_token_unique": { + "name": "session_temp_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_auth_id_fk": { + "name": "session_user_id_auth_id_fk", + "tableFrom": "session", + "tableTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redirect": { + "name": "redirect", + "schema": "", + "columns": { + "redirectId": { + "name": "redirectId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "regex": { + "name": "regex", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replacement": { + "name": "replacement", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permanent": { + "name": "permanent", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "redirect_applicationId_application_applicationId_fk": { + "name": "redirect_applicationId_application_applicationId_fk", + "tableFrom": "redirect", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.security": { + "name": "security", + "schema": "", + "columns": { + "securityId": { + "name": "securityId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "security_applicationId_application_applicationId_fk": { + "name": "security_applicationId_application_applicationId_fk", + "tableFrom": "security", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "security_username_applicationId_unique": { + "name": "security_username_applicationId_unique", + "nullsNotDistinct": false, + "columns": [ + "username", + "applicationId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.port": { + "name": "port", + "schema": "", + "columns": { + "portId": { + "name": "portId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publishedPort": { + "name": "publishedPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "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 + } + }, + "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 + } + }, + "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" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bitbucket": { + "name": "bitbucket", + "schema": "", + "columns": { + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "bitbucketUsername": { + "name": "bitbucketUsername", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "appPassword": { + "name": "appPassword", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketWorkspaceName": { + "name": "bitbucketWorkspaceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bitbucket_gitProviderId_git_provider_gitProviderId_fk": { + "name": "bitbucket_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "bitbucket", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.github": { + "name": "github", + "schema": "", + "columns": { + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "githubAppName": { + "name": "githubAppName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubAppId": { + "name": "githubAppId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "githubClientId": { + "name": "githubClientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubClientSecret": { + "name": "githubClientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubInstallationId": { + "name": "githubInstallationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubPrivateKey": { + "name": "githubPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubWebhookSecret": { + "name": "githubWebhookSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "github_gitProviderId_git_provider_gitProviderId_fk": { + "name": "github_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "github", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gitlab": { + "name": "gitlab", + "schema": "", + "columns": { + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "gitlabUrl": { + "name": "gitlabUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'https://gitlab.com'" + }, + "application_id": { + "name": "application_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_name": { + "name": "group_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "gitlab_gitProviderId_git_provider_gitProviderId_fk": { + "name": "gitlab_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "gitlab", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.server": { + "name": "server", + "schema": "", + "columns": { + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'root'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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.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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.Roles": { + "name": "Roles", + "schema": "public", + "values": [ + "admin", + "user" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index c11391251..aae9728d3 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -495,16 +495,23 @@ { "idx": 70, "version": "7", - "when": 1739671371444, - "tag": "0070_dusty_wind_dancer", + "when": 1739671869809, + "tag": "0070_nervous_vivisector", "breakpoints": true }, { "idx": 71, "version": "7", - "when": 1739671387634, + "when": 1739671878698, "tag": "0071_migrate-data-projects", "breakpoints": true + }, + { + "idx": 72, + "version": "7", + "when": 1739672367223, + "tag": "0072_lazy_pixie", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts index d31e5929f..c78ee9986 100644 --- a/packages/server/src/db/schema/certificate.ts +++ b/packages/server/src/db/schema/certificate.ts @@ -8,6 +8,7 @@ import { server } from "./server"; import { users_temp } from "./user"; // import { user } from "./user"; import { generateAppName } from "./utils"; +import { organization } from "./account"; export const certificates = pgTable("certificate", { certificateId: text("certificateId") @@ -22,12 +23,9 @@ export const certificates = pgTable("certificate", { .$defaultFn(() => generateAppName("certificate")) .unique(), autoRenew: boolean("autoRenew"), - // userId: text("userId").references(() => user.userId, { - // onDelete: "cascade", - // }), - userId: text("userId") + organizationId: text("organizationId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => organization.id, { onDelete: "cascade" }), serverId: text("serverId").references(() => server.serverId, { onDelete: "cascade", }), @@ -40,9 +38,9 @@ export const certificatesRelations = relations( fields: [certificates.serverId], references: [server.serverId], }), - user: one(users_temp, { - fields: [certificates.userId], - references: [users_temp.id], + organization: one(organization, { + fields: [certificates.organizationId], + references: [organization.id], }), }), ); diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts index 6b9ea5d93..b438d20bb 100644 --- a/packages/server/src/db/schema/destination.ts +++ b/packages/server/src/db/schema/destination.ts @@ -6,6 +6,7 @@ import { z } from "zod"; import { admins } from "./admin"; import { backups } from "./backups"; import { users_temp } from "./user"; +import { organization } from "./account"; // import { user } from "./user"; export const destinations = pgTable("destination", { @@ -21,18 +22,19 @@ export const destinations = pgTable("destination", { region: text("region").notNull(), // maybe it can be null endpoint: text("endpoint").notNull(), - // userId: text("userId") - // .notNull() - // .references(() => user.userId, { onDelete: "cascade" }), - userId: text("userId") + organizationId: text("organizationId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => organization.id, { onDelete: "cascade" }), }); export const destinationsRelations = relations( destinations, ({ many, one }) => ({ backups: many(backups), + organization: one(organization, { + fields: [destinations.organizationId], + references: [organization.id], + }), // user: one(user, { // fields: [destinations.userId], // references: [user.id], diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index be2c50001..40c4558af 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -8,6 +8,7 @@ import { bitbucket } from "./bitbucket"; import { github } from "./github"; import { gitlab } from "./gitlab"; import { users_temp } from "./user"; +import { organization } from "./account"; // import { user } from "./user"; export const gitProviderType = pgEnum("gitProviderType", [ @@ -26,12 +27,9 @@ export const gitProvider = pgTable("git_provider", { createdAt: text("createdAt") .notNull() .$defaultFn(() => new Date().toISOString()), - // userId: text("userId").references(() => user.userId, { - // onDelete: "cascade", - // }), - userId: text("userId") + organizationId: text("organizationId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => organization.id, { onDelete: "cascade" }), }); export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ @@ -47,9 +45,9 @@ export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ fields: [gitProvider.gitProviderId], references: [bitbucket.gitProviderId], }), - user: one(users_temp, { - fields: [gitProvider.userId], - references: [users_temp.id], + organization: one(organization, { + fields: [gitProvider.organizationId], + references: [organization.id], }), })); diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 78596b0d7..5d2bb243d 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -4,6 +4,7 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { users_temp } from "./user"; +import { organization } from "./account"; // import { user } from "./user"; export const notificationType = pgEnum("notificationType", [ @@ -45,12 +46,9 @@ export const notifications = pgTable("notification", { gotifyId: text("gotifyId").references(() => gotify.gotifyId, { onDelete: "cascade", }), - // userId: text("userId").references(() => user.userId, { - // onDelete: "cascade", - // }), - userId: text("userId") + organizationId: text("organizationId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => organization.id, { onDelete: "cascade" }), }); export const slack = pgTable("slack", { @@ -125,9 +123,9 @@ export const notificationsRelations = relations(notifications, ({ one }) => ({ fields: [notifications.gotifyId], references: [gotify.gotifyId], }), - user: one(users_temp, { - fields: [notifications.userId], - references: [users_temp.id], + organization: one(organization, { + fields: [notifications.organizationId], + references: [organization.id], }), })); diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index ee8859327..193fce47c 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -26,14 +26,9 @@ export const projects = pgTable("project", { createdAt: text("createdAt") .notNull() .$defaultFn(() => new Date().toISOString()), - // userId: text("userId") - // .notNull() - // .references(() => user.userId, { onDelete: "cascade" }), - userId: text("userId") - .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + organizationId: text("organizationId") - // .notNull() + .notNull() .references(() => organization.id, { onDelete: "cascade" }), env: text("env").notNull().default(""), }); @@ -46,14 +41,10 @@ export const projectRelations = relations(projects, ({ many, one }) => ({ mongo: many(mongo), redis: many(redis), compose: many(compose), - user: one(users_temp, { - fields: [projects.userId], - references: [users_temp.id], + organization: one(organization, { + fields: [projects.organizationId], + references: [organization.id], }), - // user: one(user, { - // fields: [projects.userId], - // references: [user.id], - // }), })); const createSchema = createInsertSchema(projects, { diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index 62c2b2d7d..932b198f2 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -6,6 +6,7 @@ import { z } from "zod"; import { admins } from "./admin"; import { applications } from "./application"; import { users_temp } from "./user"; +import { organization } from "./account"; // import { user } from "./user"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same @@ -29,12 +30,9 @@ export const registry = pgTable("registry", { .notNull() .$defaultFn(() => new Date().toISOString()), registryType: registryType("selfHosted").notNull().default("cloud"), - // userId: text("userId") - // .notNull() - // .references(() => user.userId, { onDelete: "cascade" }), - userId: text("userId") + organizationId: text("organizationId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => organization.id, { onDelete: "cascade" }), }); export const registryRelations = relations(registry, ({ one, many }) => ({ @@ -50,7 +48,7 @@ const createSchema = createInsertSchema(registry, { username: z.string().min(1), password: z.string().min(1), registryUrl: z.string(), - userId: z.string().min(1), + organizationId: z.string().min(1), registryId: z.string().min(1), registryType: z.enum(["cloud"]), imagePrefix: z.string().nullable().optional(), diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index 26023e96c..971c69164 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -25,6 +25,7 @@ import { sshKeys } from "./ssh-key"; import { users_temp } from "./user"; // import { user } from "./user"; import { generateAppName } from "./utils"; +import { organization } from "./account"; export const serverStatus = pgEnum("serverStatus", ["active", "inactive"]); @@ -43,13 +44,9 @@ export const server = pgTable("server", { .$defaultFn(() => generateAppName("server")), enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false), createdAt: text("createdAt").notNull(), - // .$defaultFn(() => new Date().toISOString()), - // userId: text("userId") - // .notNull() - // .references(() => user.userId, { onDelete: "cascade" }), - userId: text("userId") + organizationId: text("organizationId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => organization.id, { onDelete: "cascade" }), serverStatus: serverStatus("serverStatus").notNull().default("active"), command: text("command").notNull().default(""), sshKeyId: text("sshKeyId").references(() => sshKeys.sshKeyId, { diff --git a/packages/server/src/db/schema/ssh-key.ts b/packages/server/src/db/schema/ssh-key.ts index 4daa438ce..0b0124953 100644 --- a/packages/server/src/db/schema/ssh-key.ts +++ b/packages/server/src/db/schema/ssh-key.ts @@ -8,6 +8,7 @@ import { applications } from "./application"; import { compose } from "./compose"; import { server } from "./server"; import { users_temp } from "./user"; +import { organization } from "./account"; // import { user } from "./user"; export const sshKeys = pgTable("ssh-key", { @@ -23,21 +24,18 @@ export const sshKeys = pgTable("ssh-key", { .notNull() .$defaultFn(() => new Date().toISOString()), lastUsedAt: text("lastUsedAt"), - // userId: text("userId").references(() => user.userId, { - // onDelete: "cascade", - // }), - userId: text("userId") + organizationId: text("organizationId") .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), + .references(() => organization.id, { onDelete: "cascade" }), }); export const sshKeysRelations = relations(sshKeys, ({ many, one }) => ({ applications: many(applications), compose: many(compose), servers: many(server), - user: one(users_temp, { - fields: [sshKeys.userId], - references: [users_temp.id], + organization: one(organization, { + fields: [sshKeys.organizationId], + references: [organization.id], }), })); @@ -53,7 +51,7 @@ export const apiCreateSshKey = createSchema description: true, privateKey: true, publicKey: true, - userId: true, + organizationId: true, }) .merge(sshKeyCreate.pick({ privateKey: true })); From 6d0e195a4d3af51d9a0b280ae4a20a0493cdb35e Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 20:26:05 -0600 Subject: [PATCH 28/89] refactor: update --- packages/server/auth-schema.ts | 146 ++++++++++-------- packages/server/src/db/schema/certificate.ts | 2 +- packages/server/src/db/schema/destination.ts | 2 +- packages/server/src/db/schema/git-provider.ts | 2 +- packages/server/src/db/schema/notification.ts | 2 +- packages/server/src/db/schema/project.ts | 2 +- packages/server/src/db/schema/registry.ts | 2 +- packages/server/src/db/schema/server.ts | 2 +- packages/server/src/db/schema/ssh-key.ts | 2 +- packages/server/src/db/schema/user.ts | 2 +- 10 files changed, 91 insertions(+), 73 deletions(-) diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index 20b0a2b61..38839afbf 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,77 +1,95 @@ -import { pgTable, text, integer, timestamp, boolean } from "drizzle-orm/pg-core"; - +import { + boolean, + integer, + pgTable, + text, + timestamp, +} from "drizzle-orm/pg-core"; + export const users_temp = pgTable("users_temp", { - id: text("id").primaryKey(), - name: text('name').notNull(), - email: text('email').notNull().unique(), - emailVerified: boolean('email_verified').notNull(), - image: text('image'), - createdAt: timestamp('created_at').notNull(), - updatedAt: timestamp('updated_at').notNull(), - role: text('role').notNull(), - ownerId: text('owner_id').notNull() - }); + id: text("id").primaryKey(), + name: text("name").notNull(), + email: text("email").notNull().unique(), + emailVerified: boolean("email_verified").notNull(), + image: text("image"), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), + role: text("role").notNull(), + ownerId: text("owner_id").notNull(), +}); export const session = pgTable("session", { - id: text("id").primaryKey(), - expiresAt: timestamp('expires_at').notNull(), - token: text('token').notNull().unique(), - createdAt: timestamp('created_at').notNull(), - updatedAt: timestamp('updated_at').notNull(), - ipAddress: text('ip_address'), - userAgent: text('user_agent'), - userId: text('user_id').notNull().references(()=> users_temp.id, { onDelete: 'cascade' }), - activeOrganizationId: text('active_organization_id') - }); + id: text("id").primaryKey(), + expiresAt: timestamp("expires_at").notNull(), + token: text("token").notNull().unique(), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), + ipAddress: text("ip_address"), + userAgent: text("user_agent"), + userId: text("user_id") + .notNull() + .references(() => users_temp.id, { onDelete: "cascade" }), + activeOrganizationId: text("active_organization_id"), +}); export const account = pgTable("account", { - id: text("id").primaryKey(), - accountId: text('account_id').notNull(), - providerId: text('provider_id').notNull(), - userId: text('user_id').notNull().references(()=> users_temp.id, { onDelete: 'cascade' }), - accessToken: text('access_token'), - refreshToken: text('refresh_token'), - idToken: text('id_token'), - accessTokenExpiresAt: timestamp('access_token_expires_at'), - refreshTokenExpiresAt: timestamp('refresh_token_expires_at'), - scope: text('scope'), - password: text('password'), - createdAt: timestamp('created_at').notNull(), - updatedAt: timestamp('updated_at').notNull() - }); + id: text("id").primaryKey(), + accountId: text("account_id").notNull(), + providerId: text("provider_id").notNull(), + userId: text("user_id") + .notNull() + .references(() => users_temp.id, { onDelete: "cascade" }), + accessToken: text("access_token"), + refreshToken: text("refresh_token"), + idToken: text("id_token"), + accessTokenExpiresAt: timestamp("access_token_expires_at"), + refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), + scope: text("scope"), + password: text("password"), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), +}); export const verification = pgTable("verification", { - id: text("id").primaryKey(), - identifier: text('identifier').notNull(), - value: text('value').notNull(), - expiresAt: timestamp('expires_at').notNull(), - createdAt: timestamp('created_at'), - updatedAt: timestamp('updated_at') - }); + id: text("id").primaryKey(), + identifier: text("identifier").notNull(), + value: text("value").notNull(), + expiresAt: timestamp("expires_at").notNull(), + createdAt: timestamp("created_at"), + updatedAt: timestamp("updated_at"), +}); export const organization = pgTable("organization", { - id: text("id").primaryKey(), - name: text('name').notNull(), - slug: text('slug').unique(), - logo: text('logo'), - createdAt: timestamp('created_at').notNull(), - metadata: text('metadata') - }); + id: text("id").primaryKey(), + name: text("name").notNull(), + slug: text("slug").unique(), + logo: text("logo"), + createdAt: timestamp("created_at").notNull(), + metadata: text("metadata"), +}); export const member = pgTable("member", { - id: text("id").primaryKey(), - organizationId: text('organization_id').notNull().references(()=> organization.id, { onDelete: 'cascade' }), - userId: text('user_id').notNull().references(()=> user.id, { onDelete: 'cascade' }), - role: text('role').notNull(), - createdAt: timestamp('created_at').notNull() - }); + id: text("id").primaryKey(), + organizationId: text("organization_id") + .notNull() + .references(() => organization.id, { onDelete: "cascade" }), + userId: text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + role: text("role").notNull(), + createdAt: timestamp("created_at").notNull(), +}); export const invitation = pgTable("invitation", { - id: text("id").primaryKey(), - organizationId: text('organization_id').notNull().references(()=> organization.id, { onDelete: 'cascade' }), - email: text('email').notNull(), - role: text('role'), - status: text('status').notNull(), - expiresAt: timestamp('expires_at').notNull(), - inviterId: text('inviter_id').notNull().references(()=> user.id, { onDelete: 'cascade' }) - }); + id: text("id").primaryKey(), + organizationId: text("organization_id") + .notNull() + .references(() => organization.id, { onDelete: "cascade" }), + email: text("email").notNull(), + role: text("role"), + status: text("status").notNull(), + expiresAt: timestamp("expires_at").notNull(), + inviterId: text("inviter_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), +}); diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts index c78ee9986..dd121b504 100644 --- a/packages/server/src/db/schema/certificate.ts +++ b/packages/server/src/db/schema/certificate.ts @@ -3,12 +3,12 @@ import { boolean, pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; +import { organization } from "./account"; import { admins } from "./admin"; import { server } from "./server"; import { users_temp } from "./user"; // import { user } from "./user"; import { generateAppName } from "./utils"; -import { organization } from "./account"; export const certificates = pgTable("certificate", { certificateId: text("certificateId") diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts index b438d20bb..4d8dbc13d 100644 --- a/packages/server/src/db/schema/destination.ts +++ b/packages/server/src/db/schema/destination.ts @@ -3,10 +3,10 @@ import { pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; +import { organization } from "./account"; import { admins } from "./admin"; import { backups } from "./backups"; import { users_temp } from "./user"; -import { organization } from "./account"; // import { user } from "./user"; export const destinations = pgTable("destination", { diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index 40c4558af..e42557141 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -3,12 +3,12 @@ import { pgEnum, pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; +import { organization } from "./account"; import { admins } from "./admin"; import { bitbucket } from "./bitbucket"; import { github } from "./github"; import { gitlab } from "./gitlab"; import { users_temp } from "./user"; -import { organization } from "./account"; // import { user } from "./user"; export const gitProviderType = pgEnum("gitProviderType", [ diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 5d2bb243d..6e29ddf67 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -3,8 +3,8 @@ import { boolean, integer, pgEnum, pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; -import { users_temp } from "./user"; import { organization } from "./account"; +import { users_temp } from "./user"; // import { user } from "./user"; export const notificationType = pgEnum("notificationType", [ diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index 193fce47c..cf4ea8a86 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -4,6 +4,7 @@ import { pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; +import { organization } from "./account"; import { admins } from "./admin"; // import { admins } from "./admin"; import { applications } from "./application"; @@ -14,7 +15,6 @@ import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; import { users, users_temp } from "./user"; -import { organization } from "./account"; export const projects = pgTable("project", { projectId: text("projectId") diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index 932b198f2..aa362a050 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -3,10 +3,10 @@ import { pgEnum, pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; +import { organization } from "./account"; import { admins } from "./admin"; import { applications } from "./application"; import { users_temp } from "./user"; -import { organization } from "./account"; // import { user } from "./user"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index 971c69164..f1dcd1001 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -11,6 +11,7 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; +import { organization } from "./account"; import { admins } from "./admin"; import { applications } from "./application"; import { certificates } from "./certificate"; @@ -25,7 +26,6 @@ import { sshKeys } from "./ssh-key"; import { users_temp } from "./user"; // import { user } from "./user"; import { generateAppName } from "./utils"; -import { organization } from "./account"; export const serverStatus = pgEnum("serverStatus", ["active", "inactive"]); diff --git a/packages/server/src/db/schema/ssh-key.ts b/packages/server/src/db/schema/ssh-key.ts index 0b0124953..b705be36e 100644 --- a/packages/server/src/db/schema/ssh-key.ts +++ b/packages/server/src/db/schema/ssh-key.ts @@ -3,12 +3,12 @@ import { pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { sshKeyCreate, sshKeyType } from "../validations"; +import { organization } from "./account"; import { admins } from "./admin"; import { applications } from "./application"; import { compose } from "./compose"; import { server } from "./server"; import { users_temp } from "./user"; -import { organization } from "./account"; // import { user } from "./user"; export const sshKeys = pgTable("ssh-key", { diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 359cfbd45..e2755b8f9 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -13,8 +13,8 @@ import { z } from "zod"; import { account, organization } from "./account"; import { admins } from "./admin"; import { auth } from "./auth"; -import { certificateType } from "./shared"; import { projects } from "./project"; +import { certificateType } from "./shared"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * database instance for multiple projects. From e3e35ce7926a2e7fcb3148be97921b7cedc2376e Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 20:43:23 -0600 Subject: [PATCH 29/89] refactor: update to use organization resources --- .../dokploy/server/api/routers/application.ts | 80 ++++++++++++++----- apps/dokploy/server/api/routers/bitbucket.ts | 19 +++-- .../dokploy/server/api/routers/certificate.ts | 17 +++- apps/dokploy/server/api/routers/deployment.ts | 8 +- .../dokploy/server/api/routers/destination.ts | 10 +-- apps/dokploy/server/api/routers/domain.ts | 41 +++++++--- .../server/api/routers/git-provider.ts | 12 +-- apps/dokploy/server/api/routers/github.ts | 30 +++++-- apps/dokploy/server/api/routers/gitlab.ts | 30 +++++-- apps/dokploy/server/api/routers/mariadb.ts | 22 ++--- apps/dokploy/server/api/routers/mongo.ts | 24 +++--- apps/dokploy/server/api/routers/mysql.ts | 24 +++--- .../server/api/routers/notification.ts | 24 ++++-- apps/dokploy/server/api/routers/postgres.ts | 44 +++++++--- .../server/api/routers/preview-deployment.ts | 14 +++- apps/dokploy/server/api/routers/project.ts | 16 ++-- apps/dokploy/server/api/routers/redirects.ts | 16 +++- apps/dokploy/server/api/routers/redis.ts | 22 ++--- apps/dokploy/server/api/routers/registry.ts | 6 +- apps/dokploy/server/api/routers/security.ts | 16 +++- apps/dokploy/server/api/routers/server.ts | 25 +++--- apps/dokploy/server/api/routers/ssh-key.ts | 21 +++-- apps/dokploy/server/api/trpc.ts | 4 +- packages/server/src/lib/auth.ts | 1 + 24 files changed, 348 insertions(+), 178 deletions(-) diff --git a/apps/dokploy/server/api/routers/application.ts b/apps/dokploy/server/api/routers/application.ts index 618fd9ce8..490da340a 100644 --- a/apps/dokploy/server/api/routers/application.ts +++ b/apps/dokploy/server/api/routers/application.ts @@ -72,7 +72,7 @@ export const applicationRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.userId !== ctx.user.ownerId) { + if (project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -102,7 +102,9 @@ export const applicationRouter = createTRPCRouter({ await checkServiceAccess(ctx.user.id, input.applicationId, "access"); } const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -115,7 +117,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiReloadApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this application", @@ -145,7 +149,9 @@ export const applicationRouter = createTRPCRouter({ } const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this application", @@ -186,7 +192,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const service = await findApplicationById(input.applicationId); - if (service.project.userId !== ctx.user.ownerId) { + if (service.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this application", @@ -206,7 +212,7 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const service = await findApplicationById(input.applicationId); - if (service.project.userId !== ctx.user.ownerId) { + if (service.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this application", @@ -227,7 +233,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to redeploy this application", @@ -260,7 +268,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariables) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", @@ -276,7 +286,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveBuildType) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this build type", @@ -297,7 +309,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveGithubProvider) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this github provider", @@ -319,7 +333,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveGitlabProvider) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this gitlab provider", @@ -343,7 +359,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveBitbucketProvider) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this bitbucket provider", @@ -365,7 +383,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveDockerProvider) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this docker provider", @@ -386,7 +406,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiSaveGitProvider) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this git provider", @@ -407,7 +429,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to mark this application as running", @@ -419,7 +443,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiUpdateApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this application", @@ -443,7 +469,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to refresh this application", @@ -458,7 +486,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this application", @@ -492,7 +522,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to clean this application", @@ -505,7 +537,9 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .query(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to read this application", @@ -540,7 +574,7 @@ export const applicationRouter = createTRPCRouter({ const app = await findApplicationById(input.applicationId as string); - if (app.project.userId !== ctx.user.ownerId) { + if (app.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this application", @@ -582,7 +616,9 @@ export const applicationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this application", diff --git a/apps/dokploy/server/api/routers/bitbucket.ts b/apps/dokploy/server/api/routers/bitbucket.ts index 75513a805..987555e5f 100644 --- a/apps/dokploy/server/api/routers/bitbucket.ts +++ b/apps/dokploy/server/api/routers/bitbucket.ts @@ -38,7 +38,8 @@ export const bitbucketRouter = createTRPCRouter({ const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( IS_CLOUD && - bitbucketProvider.gitProvider.userId !== ctx.user.ownerId + bitbucketProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -61,7 +62,9 @@ export const bitbucketRouter = createTRPCRouter({ if (IS_CLOUD) { // TODO: mAyBe a rEfaCtoR 🤫 result = result.filter( - (provider) => provider.gitProvider.userId === ctx.user.ownerId, + (provider) => + provider.gitProvider.organizationId === + ctx.session.activeOrganizationId, ); } return result; @@ -73,7 +76,8 @@ export const bitbucketRouter = createTRPCRouter({ const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( IS_CLOUD && - bitbucketProvider.gitProvider.userId !== ctx.user.ownerId + bitbucketProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -91,7 +95,8 @@ export const bitbucketRouter = createTRPCRouter({ ); if ( IS_CLOUD && - bitbucketProvider.gitProvider.userId !== ctx.user.ownerId + bitbucketProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -108,7 +113,8 @@ export const bitbucketRouter = createTRPCRouter({ const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( IS_CLOUD && - bitbucketProvider.gitProvider.userId !== ctx.user.ownerId + bitbucketProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -132,7 +138,8 @@ export const bitbucketRouter = createTRPCRouter({ const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( IS_CLOUD && - bitbucketProvider.gitProvider.userId !== ctx.user.ownerId + bitbucketProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ diff --git a/apps/dokploy/server/api/routers/certificate.ts b/apps/dokploy/server/api/routers/certificate.ts index b1c6f5c2d..87e6c6c8d 100644 --- a/apps/dokploy/server/api/routers/certificate.ts +++ b/apps/dokploy/server/api/routers/certificate.ts @@ -32,7 +32,10 @@ export const certificateRouter = createTRPCRouter({ .input(apiFindCertificate) .query(async ({ input, ctx }) => { const certificates = await findCertificateById(input.certificateId); - if (IS_CLOUD && certificates.userId !== ctx.user.ownerId) { + if ( + IS_CLOUD && + certificates.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this certificate", @@ -44,7 +47,10 @@ export const certificateRouter = createTRPCRouter({ .input(apiFindCertificate) .mutation(async ({ input, ctx }) => { const certificates = await findCertificateById(input.certificateId); - if (IS_CLOUD && certificates.userId !== ctx.user.ownerId) { + if ( + IS_CLOUD && + certificates.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to delete this certificate", @@ -56,7 +62,12 @@ export const certificateRouter = createTRPCRouter({ all: adminProcedure.query(async ({ ctx }) => { return await db.query.certificates.findMany({ // TODO: Remove this line when the cloud version is ready - ...(IS_CLOUD && { where: eq(certificates.userId, ctx.user.ownerId) }), + ...(IS_CLOUD && { + where: eq( + certificates.organizationId, + ctx.session.activeOrganizationId, + ), + }), }); }), }); diff --git a/apps/dokploy/server/api/routers/deployment.ts b/apps/dokploy/server/api/routers/deployment.ts index b9daaf0e7..8d95c1218 100644 --- a/apps/dokploy/server/api/routers/deployment.ts +++ b/apps/dokploy/server/api/routers/deployment.ts @@ -19,7 +19,9 @@ export const deploymentRouter = createTRPCRouter({ .input(apiFindAllByApplication) .query(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -32,7 +34,7 @@ export const deploymentRouter = createTRPCRouter({ .input(apiFindAllByCompose) .query(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -44,7 +46,7 @@ export const deploymentRouter = createTRPCRouter({ .input(apiFindAllByServer) .query(async ({ input, ctx }) => { const server = await findServerById(input.serverId); - if (server.userId !== ctx.user.ownerId) { + if (server.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this server", diff --git a/apps/dokploy/server/api/routers/destination.ts b/apps/dokploy/server/api/routers/destination.ts index 49edadf5e..770cb699f 100644 --- a/apps/dokploy/server/api/routers/destination.ts +++ b/apps/dokploy/server/api/routers/destination.ts @@ -84,7 +84,7 @@ export const destinationRouter = createTRPCRouter({ .input(apiFindOneDestination) .query(async ({ input, ctx }) => { const destination = await findDestinationById(input.destinationId); - if (destination.userId !== ctx.user.ownerId) { + if (destination.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this destination", @@ -94,7 +94,7 @@ export const destinationRouter = createTRPCRouter({ }), all: protectedProcedure.query(async ({ ctx }) => { return await db.query.destinations.findMany({ - where: eq(destinations.userId, ctx.user.ownerId), + where: eq(destinations.organizationId, ctx.session.activeOrganizationId), }); }), remove: adminProcedure @@ -103,7 +103,7 @@ export const destinationRouter = createTRPCRouter({ try { const destination = await findDestinationById(input.destinationId); - if (destination.userId !== ctx.user.ownerId) { + if (destination.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to delete this destination", @@ -122,7 +122,7 @@ export const destinationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const destination = await findDestinationById(input.destinationId); - if (destination.userId !== ctx.user.ownerId) { + if (destination.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to update this destination", @@ -130,7 +130,7 @@ export const destinationRouter = createTRPCRouter({ } return await updateDestinationById(input.destinationId, { ...input, - userId: ctx.user.ownerId, + organizationId: ctx.session.activeOrganizationId, }); } catch (error) { throw error; diff --git a/apps/dokploy/server/api/routers/domain.ts b/apps/dokploy/server/api/routers/domain.ts index 526a156bb..aac2a016f 100644 --- a/apps/dokploy/server/api/routers/domain.ts +++ b/apps/dokploy/server/api/routers/domain.ts @@ -30,7 +30,9 @@ export const domainRouter = createTRPCRouter({ try { if (input.domainType === "compose" && input.composeId) { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if ( + compose.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -38,7 +40,10 @@ export const domainRouter = createTRPCRouter({ } } else if (input.domainType === "application" && input.applicationId) { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== + ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -58,7 +63,9 @@ export const domainRouter = createTRPCRouter({ .input(apiFindOneApplication) .query(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -70,7 +77,7 @@ export const domainRouter = createTRPCRouter({ .input(apiFindCompose) .query(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -95,7 +102,9 @@ export const domainRouter = createTRPCRouter({ if (currentDomain.applicationId) { const newApp = await findApplicationById(currentDomain.applicationId); - if (newApp.project.userId !== ctx.user.ownerId) { + if ( + newApp.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -103,7 +112,9 @@ export const domainRouter = createTRPCRouter({ } } else if (currentDomain.composeId) { const newCompose = await findComposeById(currentDomain.composeId); - if (newCompose.project.userId !== ctx.user.ownerId) { + if ( + newCompose.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -114,7 +125,8 @@ export const domainRouter = createTRPCRouter({ currentDomain.previewDeploymentId, ); if ( - newPreviewDeployment.application.project.userId !== ctx.user.ownerId + newPreviewDeployment.application.project.organizationId !== + ctx.session.activeOrganizationId ) { throw new TRPCError({ code: "UNAUTHORIZED", @@ -143,7 +155,9 @@ export const domainRouter = createTRPCRouter({ const domain = await findDomainById(input.domainId); if (domain.applicationId) { const application = await findApplicationById(domain.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -151,7 +165,7 @@ export const domainRouter = createTRPCRouter({ } } else if (domain.composeId) { const compose = await findComposeById(domain.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -166,7 +180,10 @@ export const domainRouter = createTRPCRouter({ const domain = await findDomainById(input.domainId); if (domain.applicationId) { const application = await findApplicationById(domain.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== + ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -174,7 +191,9 @@ export const domainRouter = createTRPCRouter({ } } else if (domain.composeId) { const compose = await findComposeById(domain.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if ( + compose.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", diff --git a/apps/dokploy/server/api/routers/git-provider.ts b/apps/dokploy/server/api/routers/git-provider.ts index 83e71dd81..39194ed31 100644 --- a/apps/dokploy/server/api/routers/git-provider.ts +++ b/apps/dokploy/server/api/routers/git-provider.ts @@ -1,11 +1,7 @@ import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; import { db } from "@/server/db"; import { apiRemoveGitProvider, gitProvider } from "@/server/db/schema"; -import { - IS_CLOUD, - findGitProviderById, - removeGitProvider, -} from "@dokploy/server"; +import { findGitProviderById, removeGitProvider } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; import { desc, eq } from "drizzle-orm"; @@ -18,8 +14,7 @@ export const gitProviderRouter = createTRPCRouter({ github: true, }, orderBy: desc(gitProvider.createdAt), - ...(IS_CLOUD && { where: eq(gitProvider.userId, ctx.user.ownerId) }), - //TODO: Remove this line when the cloud version is ready + where: eq(gitProvider.organizationId, ctx.session.activeOrganizationId), }); }), remove: protectedProcedure @@ -28,8 +23,7 @@ export const gitProviderRouter = createTRPCRouter({ try { const gitProvider = await findGitProviderById(input.gitProviderId); - if (IS_CLOUD && gitProvider.userId !== ctx.user.ownerId) { - // TODO: Remove isCloud in the next versions of dokploy + if (gitProvider.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to delete this Git provider", diff --git a/apps/dokploy/server/api/routers/github.ts b/apps/dokploy/server/api/routers/github.ts index 62c21805d..2b3f15029 100644 --- a/apps/dokploy/server/api/routers/github.ts +++ b/apps/dokploy/server/api/routers/github.ts @@ -20,7 +20,10 @@ export const githubRouter = createTRPCRouter({ .input(apiFindOneGithub) .query(async ({ input, ctx }) => { const githubProvider = await findGithubById(input.githubId); - if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) { + if ( + githubProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId + ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -33,7 +36,10 @@ export const githubRouter = createTRPCRouter({ .input(apiFindOneGithub) .query(async ({ input, ctx }) => { const githubProvider = await findGithubById(input.githubId); - if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) { + if ( + githubProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId + ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -46,7 +52,10 @@ export const githubRouter = createTRPCRouter({ .input(apiFindGithubBranches) .query(async ({ input, ctx }) => { const githubProvider = await findGithubById(input.githubId || ""); - if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) { + if ( + githubProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId + ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -65,7 +74,9 @@ export const githubRouter = createTRPCRouter({ if (IS_CLOUD) { // TODO: mAyBe a rEfaCtoR 🤫 result = result.filter( - (provider) => provider.gitProvider.userId === ctx.user.ownerId, + (provider) => + provider.gitProvider.organizationId === + ctx.session.activeOrganizationId, ); } @@ -90,7 +101,8 @@ export const githubRouter = createTRPCRouter({ const githubProvider = await findGithubById(input.githubId); if ( IS_CLOUD && - githubProvider.gitProvider.userId !== ctx.user.ownerId + githubProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -111,7 +123,11 @@ export const githubRouter = createTRPCRouter({ .input(apiUpdateGithub) .mutation(async ({ input, ctx }) => { const githubProvider = await findGithubById(input.githubId); - if (IS_CLOUD && githubProvider.gitProvider.userId !== ctx.user.ownerId) { + if ( + IS_CLOUD && + githubProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId + ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -120,7 +136,7 @@ export const githubRouter = createTRPCRouter({ } await updateGitProvider(input.gitProviderId, { name: input.name, - userId: ctx.user.ownerId, + organizationId: ctx.session.activeOrganizationId, }); }), }); diff --git a/apps/dokploy/server/api/routers/gitlab.ts b/apps/dokploy/server/api/routers/gitlab.ts index d3ba5a44a..338b8c64d 100644 --- a/apps/dokploy/server/api/routers/gitlab.ts +++ b/apps/dokploy/server/api/routers/gitlab.ts @@ -39,7 +39,10 @@ export const gitlabRouter = createTRPCRouter({ .input(apiFindOneGitlab) .query(async ({ input, ctx }) => { const gitlabProvider = await findGitlabById(input.gitlabId); - if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) { + if ( + gitlabProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId + ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -58,7 +61,9 @@ export const gitlabRouter = createTRPCRouter({ if (IS_CLOUD) { // TODO: mAyBe a rEfaCtoR 🤫 result = result.filter( - (provider) => provider.gitProvider.userId === ctx.user.ownerId, + (provider) => + provider.gitProvider.organizationId === + ctx.session.activeOrganizationId, ); } const filtered = result @@ -78,7 +83,10 @@ export const gitlabRouter = createTRPCRouter({ .input(apiFindOneGitlab) .query(async ({ input, ctx }) => { const gitlabProvider = await findGitlabById(input.gitlabId); - if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) { + if ( + gitlabProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId + ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -92,7 +100,10 @@ export const gitlabRouter = createTRPCRouter({ .input(apiFindGitlabBranches) .query(async ({ input, ctx }) => { const gitlabProvider = await findGitlabById(input.gitlabId || ""); - if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) { + if ( + gitlabProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId + ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -107,8 +118,8 @@ export const gitlabRouter = createTRPCRouter({ try { const gitlabProvider = await findGitlabById(input.gitlabId || ""); if ( - IS_CLOUD && - gitlabProvider.gitProvider.userId !== ctx.user.ownerId + gitlabProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ @@ -130,7 +141,10 @@ export const gitlabRouter = createTRPCRouter({ .input(apiUpdateGitlab) .mutation(async ({ input, ctx }) => { const gitlabProvider = await findGitlabById(input.gitlabId); - if (IS_CLOUD && gitlabProvider.gitProvider.userId !== ctx.user.ownerId) { + if ( + gitlabProvider.gitProvider.organizationId !== + ctx.session.activeOrganizationId + ) { //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", @@ -140,7 +154,7 @@ export const gitlabRouter = createTRPCRouter({ if (input.name) { await updateGitProvider(input.gitProviderId, { name: input.name, - userId: ctx.user.ownerId, + organizationId: ctx.session.activeOrganizationId, }); await updateGitlab(input.gitlabId, { diff --git a/apps/dokploy/server/api/routers/mariadb.ts b/apps/dokploy/server/api/routers/mariadb.ts index e50b9b129..4276560c6 100644 --- a/apps/dokploy/server/api/routers/mariadb.ts +++ b/apps/dokploy/server/api/routers/mariadb.ts @@ -49,7 +49,7 @@ export const mariadbRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.userId !== ctx.user.ownerId) { + if (project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -83,7 +83,7 @@ export const mariadbRouter = createTRPCRouter({ await checkServiceAccess(ctx.user.id, input.mariadbId, "access"); } const mariadb = await findMariadbById(input.mariadbId); - if (mariadb.project.userId !== ctx.user.ownerId) { + if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this Mariadb", @@ -96,7 +96,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiFindOneMariaDB) .mutation(async ({ input, ctx }) => { const service = await findMariadbById(input.mariadbId); - if (service.project.userId !== ctx.user.ownerId) { + if (service.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this Mariadb", @@ -133,7 +133,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiSaveExternalPortMariaDB) .mutation(async ({ input, ctx }) => { const mongo = await findMariadbById(input.mariadbId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this external port", @@ -149,7 +149,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiDeployMariaDB) .mutation(async ({ input, ctx }) => { const mariadb = await findMariadbById(input.mariadbId); - if (mariadb.project.userId !== ctx.user.ownerId) { + if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Mariadb", @@ -170,7 +170,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiDeployMariaDB) .subscription(async ({ input, ctx }) => { const mariadb = await findMariadbById(input.mariadbId); - if (mariadb.project.userId !== ctx.user.ownerId) { + if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Mariadb", @@ -187,7 +187,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiChangeMariaDBStatus) .mutation(async ({ input, ctx }) => { const mongo = await findMariadbById(input.mariadbId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to change this Mariadb status", @@ -206,7 +206,7 @@ export const mariadbRouter = createTRPCRouter({ } const mongo = await findMariadbById(input.mariadbId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this Mariadb", @@ -232,7 +232,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariablesMariaDB) .mutation(async ({ input, ctx }) => { const mariadb = await findMariadbById(input.mariadbId); - if (mariadb.project.userId !== ctx.user.ownerId) { + if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", @@ -255,7 +255,7 @@ export const mariadbRouter = createTRPCRouter({ .input(apiResetMariadb) .mutation(async ({ input, ctx }) => { const mariadb = await findMariadbById(input.mariadbId); - if (mariadb.project.userId !== ctx.user.ownerId) { + if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this Mariadb", @@ -285,7 +285,7 @@ export const mariadbRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const { mariadbId, ...rest } = input; const mariadb = await findMariadbById(mariadbId); - if (mariadb.project.userId !== ctx.user.ownerId) { + if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this Mariadb", diff --git a/apps/dokploy/server/api/routers/mongo.ts b/apps/dokploy/server/api/routers/mongo.ts index ddb3d3ccd..d1d12bd0b 100644 --- a/apps/dokploy/server/api/routers/mongo.ts +++ b/apps/dokploy/server/api/routers/mongo.ts @@ -48,7 +48,7 @@ export const mongoRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.userId !== ctx.user.ownerId) { + if (project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -87,7 +87,7 @@ export const mongoRouter = createTRPCRouter({ } const mongo = await findMongoById(input.mongoId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this mongo", @@ -101,7 +101,7 @@ export const mongoRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const service = await findMongoById(input.mongoId); - if (service.project.userId !== ctx.user.ownerId) { + if (service.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this mongo", @@ -124,7 +124,7 @@ export const mongoRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this mongo", @@ -146,7 +146,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiSaveExternalPortMongo) .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this external port", @@ -162,7 +162,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiDeployMongo) .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this mongo", @@ -182,7 +182,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiDeployMongo) .subscription(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this mongo", @@ -199,7 +199,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiChangeMongoStatus) .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to change this mongo status", @@ -214,7 +214,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiResetMongo) .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this mongo", @@ -248,7 +248,7 @@ export const mongoRouter = createTRPCRouter({ const mongo = await findMongoById(input.mongoId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this mongo", @@ -274,7 +274,7 @@ export const mongoRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariablesMongo) .mutation(async ({ input, ctx }) => { const mongo = await findMongoById(input.mongoId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", @@ -298,7 +298,7 @@ export const mongoRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const { mongoId, ...rest } = input; const mongo = await findMongoById(mongoId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this mongo", diff --git a/apps/dokploy/server/api/routers/mysql.ts b/apps/dokploy/server/api/routers/mysql.ts index c81fc8429..dc107bdba 100644 --- a/apps/dokploy/server/api/routers/mysql.ts +++ b/apps/dokploy/server/api/routers/mysql.ts @@ -50,7 +50,7 @@ export const mysqlRouter = createTRPCRouter({ } 1; const project = await findProjectById(input.projectId); - if (project.userId !== ctx.user.ownerId) { + if (project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -89,7 +89,7 @@ export const mysqlRouter = createTRPCRouter({ await checkServiceAccess(ctx.user.id, input.mysqlId, "access"); } const mysql = await findMySqlById(input.mysqlId); - if (mysql.project.userId !== ctx.user.ownerId) { + if (mysql.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this MySQL", @@ -102,7 +102,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiFindOneMySql) .mutation(async ({ input, ctx }) => { const service = await findMySqlById(input.mysqlId); - if (service.project.userId !== ctx.user.ownerId) { + if (service.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this MySQL", @@ -124,7 +124,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiFindOneMySql) .mutation(async ({ input, ctx }) => { const mongo = await findMySqlById(input.mysqlId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this MySQL", @@ -145,7 +145,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiSaveExternalPortMySql) .mutation(async ({ input, ctx }) => { const mongo = await findMySqlById(input.mysqlId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this external port", @@ -161,7 +161,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiDeployMySql) .mutation(async ({ input, ctx }) => { const mysql = await findMySqlById(input.mysqlId); - if (mysql.project.userId !== ctx.user.ownerId) { + if (mysql.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this MySQL", @@ -181,7 +181,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiDeployMySql) .subscription(async ({ input, ctx }) => { const mysql = await findMySqlById(input.mysqlId); - if (mysql.project.userId !== ctx.user.ownerId) { + if (mysql.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this MySQL", @@ -198,7 +198,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiChangeMySqlStatus) .mutation(async ({ input, ctx }) => { const mongo = await findMySqlById(input.mysqlId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to change this MySQL status", @@ -213,7 +213,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiResetMysql) .mutation(async ({ input, ctx }) => { const mysql = await findMySqlById(input.mysqlId); - if (mysql.project.userId !== ctx.user.ownerId) { + if (mysql.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this MySQL", @@ -244,7 +244,7 @@ export const mysqlRouter = createTRPCRouter({ await checkServiceAccess(ctx.user.id, input.mysqlId, "delete"); } const mongo = await findMySqlById(input.mysqlId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this MySQL", @@ -270,7 +270,7 @@ export const mysqlRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariablesMySql) .mutation(async ({ input, ctx }) => { const mysql = await findMySqlById(input.mysqlId); - if (mysql.project.userId !== ctx.user.ownerId) { + if (mysql.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", @@ -294,7 +294,7 @@ export const mysqlRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const { mysqlId, ...rest } = input; const mysql = await findMySqlById(mysqlId); - if (mysql.project.userId !== ctx.user.ownerId) { + if (mysql.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this MySQL", diff --git a/apps/dokploy/server/api/routers/notification.ts b/apps/dokploy/server/api/routers/notification.ts index 6c2b469d9..451700065 100644 --- a/apps/dokploy/server/api/routers/notification.ts +++ b/apps/dokploy/server/api/routers/notification.ts @@ -71,7 +71,7 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { + if (notification.organizationId !== ctx.session.activeOrganizationId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -122,7 +122,7 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { + if (notification.organizationId !== ctx.session.activeOrganizationId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -174,7 +174,7 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { + if (notification.organizationId !== ctx.session.activeOrganizationId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -234,7 +234,7 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { + if (notification.organizationId !== ctx.session.activeOrganizationId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -276,7 +276,7 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { + if (notification.organizationId !== ctx.session.activeOrganizationId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -295,7 +295,7 @@ export const notificationRouter = createTRPCRouter({ .input(apiFindOneNotification) .query(async ({ input, ctx }) => { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { + if (notification.organizationId !== ctx.session.activeOrganizationId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -314,7 +314,12 @@ export const notificationRouter = createTRPCRouter({ gotify: true, }, orderBy: desc(notifications.createdAt), - ...(IS_CLOUD && { where: eq(notifications.userId, ctx.user.ownerId) }), + ...(IS_CLOUD && { + where: eq( + notifications.organizationId, + ctx.session.activeOrganizationId, + ), + }), // TODO: Remove this line when the cloud version is ready }); }), @@ -400,7 +405,10 @@ export const notificationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const notification = await findNotificationById(input.notificationId); - if (IS_CLOUD && notification.userId !== ctx.user.ownerId) { + if ( + IS_CLOUD && + notification.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this notification", diff --git a/apps/dokploy/server/api/routers/postgres.ts b/apps/dokploy/server/api/routers/postgres.ts index 8a4e8ba25..b74bc0f68 100644 --- a/apps/dokploy/server/api/routers/postgres.ts +++ b/apps/dokploy/server/api/routers/postgres.ts @@ -56,7 +56,7 @@ export const postgresRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.userId !== ctx.user.ownerId) { + if (project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -95,7 +95,9 @@ export const postgresRouter = createTRPCRouter({ } const postgres = await findPostgresById(input.postgresId); - if (postgres.project.userId !== ctx.user.ownerId) { + if ( + postgres.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this Postgres", @@ -109,7 +111,7 @@ export const postgresRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const service = await findPostgresById(input.postgresId); - if (service.project.userId !== ctx.user.ownerId) { + if (service.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this Postgres", @@ -131,7 +133,9 @@ export const postgresRouter = createTRPCRouter({ .input(apiFindOnePostgres) .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.userId !== ctx.user.ownerId) { + if ( + postgres.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this Postgres", @@ -153,7 +157,9 @@ export const postgresRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.userId !== ctx.user.ownerId) { + if ( + postgres.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this external port", @@ -169,7 +175,9 @@ export const postgresRouter = createTRPCRouter({ .input(apiDeployPostgres) .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.userId !== ctx.user.ownerId) { + if ( + postgres.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Postgres", @@ -190,7 +198,9 @@ export const postgresRouter = createTRPCRouter({ .input(apiDeployPostgres) .subscription(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.userId !== ctx.user.ownerId) { + if ( + postgres.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Postgres", @@ -207,7 +217,9 @@ export const postgresRouter = createTRPCRouter({ .input(apiChangePostgresStatus) .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.userId !== ctx.user.ownerId) { + if ( + postgres.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to change this Postgres status", @@ -226,7 +238,9 @@ export const postgresRouter = createTRPCRouter({ } const postgres = await findPostgresById(input.postgresId); - if (postgres.project.userId !== ctx.user.ownerId) { + if ( + postgres.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this Postgres", @@ -249,7 +263,9 @@ export const postgresRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariablesPostgres) .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.userId !== ctx.user.ownerId) { + if ( + postgres.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", @@ -272,7 +288,9 @@ export const postgresRouter = createTRPCRouter({ .input(apiResetPostgres) .mutation(async ({ input, ctx }) => { const postgres = await findPostgresById(input.postgresId); - if (postgres.project.userId !== ctx.user.ownerId) { + if ( + postgres.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this Postgres", @@ -302,7 +320,9 @@ export const postgresRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const { postgresId, ...rest } = input; const postgres = await findPostgresById(postgresId); - if (postgres.project.userId !== ctx.user.ownerId) { + if ( + postgres.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this Postgres", diff --git a/apps/dokploy/server/api/routers/preview-deployment.ts b/apps/dokploy/server/api/routers/preview-deployment.ts index 482bb3505..f833e9f95 100644 --- a/apps/dokploy/server/api/routers/preview-deployment.ts +++ b/apps/dokploy/server/api/routers/preview-deployment.ts @@ -14,7 +14,9 @@ export const previewDeploymentRouter = createTRPCRouter({ .input(apiFindAllByApplication) .query(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -28,7 +30,10 @@ export const previewDeploymentRouter = createTRPCRouter({ const previewDeployment = await findPreviewDeploymentById( input.previewDeploymentId, ); - if (previewDeployment.application.project.userId !== ctx.user.ownerId) { + if ( + previewDeployment.application.project.organizationId !== + ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this preview deployment", @@ -43,7 +48,10 @@ export const previewDeploymentRouter = createTRPCRouter({ const previewDeployment = await findPreviewDeploymentById( input.previewDeploymentId, ); - if (previewDeployment.application.project.userId !== ctx.user.ownerId) { + if ( + previewDeployment.application.project.organizationId !== + ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this preview deployment", diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index bce12565f..88bb21d76 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -75,7 +75,7 @@ export const projectRouter = createTRPCRouter({ const project = await db.query.projects.findFirst({ where: and( eq(projects.projectId, input.projectId), - eq(projects.userId, ctx.user.ownerId), + eq(projects.organizationId, ctx.session.activeOrganizationId), ), with: { compose: { @@ -115,7 +115,7 @@ export const projectRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.userId !== ctx.user.ownerId) { + if (project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -140,7 +140,7 @@ export const projectRouter = createTRPCRouter({ accessedProjects.map((projectId) => sql`${projectId}`), sql`, `, )})`, - eq(projects.userId, ctx.user.id), + eq(projects.organizationId, ctx.session.activeOrganizationId), ), with: { applications: { @@ -194,7 +194,7 @@ export const projectRouter = createTRPCRouter({ }, }, }, - where: eq(projects.userId, ctx.user.id), + where: eq(projects.organizationId, ctx.session.activeOrganizationId), orderBy: desc(projects.createdAt), }); }), @@ -207,7 +207,9 @@ export const projectRouter = createTRPCRouter({ await checkProjectAccess(ctx.user.id, "delete"); } const currentProject = await findProjectById(input.projectId); - if (currentProject.userId !== ctx.user.ownerId) { + if ( + currentProject.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this project", @@ -225,7 +227,9 @@ export const projectRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const currentProject = await findProjectById(input.projectId); - if (currentProject.userId !== ctx.user.ownerId) { + if ( + currentProject.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this project", diff --git a/apps/dokploy/server/api/routers/redirects.ts b/apps/dokploy/server/api/routers/redirects.ts index 1a8ba4cfa..2d520cc42 100644 --- a/apps/dokploy/server/api/routers/redirects.ts +++ b/apps/dokploy/server/api/routers/redirects.ts @@ -18,7 +18,9 @@ export const redirectsRouter = createTRPCRouter({ .input(apiCreateRedirect) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -31,7 +33,9 @@ export const redirectsRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const redirect = await findRedirectById(input.redirectId); const application = await findApplicationById(redirect.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -44,7 +48,9 @@ export const redirectsRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const redirect = await findRedirectById(input.redirectId); const application = await findApplicationById(redirect.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -57,7 +63,9 @@ export const redirectsRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const redirect = await findRedirectById(input.redirectId); const application = await findApplicationById(redirect.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", diff --git a/apps/dokploy/server/api/routers/redis.ts b/apps/dokploy/server/api/routers/redis.ts index acded3723..db76ee6ce 100644 --- a/apps/dokploy/server/api/routers/redis.ts +++ b/apps/dokploy/server/api/routers/redis.ts @@ -48,7 +48,7 @@ export const redisRouter = createTRPCRouter({ } const project = await findProjectById(input.projectId); - if (project.userId !== ctx.user.ownerId) { + if (project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -80,7 +80,7 @@ export const redisRouter = createTRPCRouter({ } const redis = await findRedisById(input.redisId); - if (redis.project.userId !== ctx.user.ownerId) { + if (redis.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this Redis", @@ -93,7 +93,7 @@ export const redisRouter = createTRPCRouter({ .input(apiFindOneRedis) .mutation(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.userId !== ctx.user.ownerId) { + if (redis.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to start this Redis", @@ -115,7 +115,7 @@ export const redisRouter = createTRPCRouter({ .input(apiResetRedis) .mutation(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.userId !== ctx.user.ownerId) { + if (redis.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to reload this Redis", @@ -145,7 +145,7 @@ export const redisRouter = createTRPCRouter({ .input(apiFindOneRedis) .mutation(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.userId !== ctx.user.ownerId) { + if (redis.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this Redis", @@ -166,7 +166,7 @@ export const redisRouter = createTRPCRouter({ .input(apiSaveExternalPortRedis) .mutation(async ({ input, ctx }) => { const mongo = await findRedisById(input.redisId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this external port", @@ -182,7 +182,7 @@ export const redisRouter = createTRPCRouter({ .input(apiDeployRedis) .mutation(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.userId !== ctx.user.ownerId) { + if (redis.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Redis", @@ -202,7 +202,7 @@ export const redisRouter = createTRPCRouter({ .input(apiDeployRedis) .subscription(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.userId !== ctx.user.ownerId) { + if (redis.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this Redis", @@ -218,7 +218,7 @@ export const redisRouter = createTRPCRouter({ .input(apiChangeRedisStatus) .mutation(async ({ input, ctx }) => { const mongo = await findRedisById(input.redisId); - if (mongo.project.userId !== ctx.user.ownerId) { + if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to change this Redis status", @@ -238,7 +238,7 @@ export const redisRouter = createTRPCRouter({ const redis = await findRedisById(input.redisId); - if (redis.project.userId !== ctx.user.ownerId) { + if (redis.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this Redis", @@ -261,7 +261,7 @@ export const redisRouter = createTRPCRouter({ .input(apiSaveEnvironmentVariablesRedis) .mutation(async ({ input, ctx }) => { const redis = await findRedisById(input.redisId); - if (redis.project.userId !== ctx.user.ownerId) { + if (redis.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to save this environment", diff --git a/apps/dokploy/server/api/routers/registry.ts b/apps/dokploy/server/api/routers/registry.ts index 76df5cd65..b57171795 100644 --- a/apps/dokploy/server/api/routers/registry.ts +++ b/apps/dokploy/server/api/routers/registry.ts @@ -28,7 +28,7 @@ export const registryRouter = createTRPCRouter({ .input(apiRemoveRegistry) .mutation(async ({ ctx, input }) => { const registry = await findRegistryById(input.registryId); - if (registry.userId !== ctx.user.ownerId) { + if (registry.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to delete this registry", @@ -41,7 +41,7 @@ export const registryRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const { registryId, ...rest } = input; const registry = await findRegistryById(registryId); - if (registry.userId !== ctx.user.ownerId) { + if (registry.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to update this registry", @@ -67,7 +67,7 @@ export const registryRouter = createTRPCRouter({ .input(apiFindOneRegistry) .query(async ({ input, ctx }) => { const registry = await findRegistryById(input.registryId); - if (registry.userId !== ctx.user.ownerId) { + if (registry.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this registry", diff --git a/apps/dokploy/server/api/routers/security.ts b/apps/dokploy/server/api/routers/security.ts index ca4892d26..b8e70bbb0 100644 --- a/apps/dokploy/server/api/routers/security.ts +++ b/apps/dokploy/server/api/routers/security.ts @@ -18,7 +18,9 @@ export const securityRouter = createTRPCRouter({ .input(apiCreateSecurity) .mutation(async ({ input, ctx }) => { const application = await findApplicationById(input.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -31,7 +33,9 @@ export const securityRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const security = await findSecurityById(input.securityId); const application = await findApplicationById(security.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -44,7 +48,9 @@ export const securityRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const security = await findSecurityById(input.securityId); const application = await findApplicationById(security.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", @@ -57,7 +63,9 @@ export const securityRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const security = await findSecurityById(input.securityId); const application = await findApplicationById(security.applicationId); - if (application.project.userId !== ctx.user.ownerId) { + if ( + application.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this application", diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts index 8e63d7e66..3662345d4 100644 --- a/apps/dokploy/server/api/routers/server.ts +++ b/apps/dokploy/server/api/routers/server.ts @@ -65,7 +65,7 @@ export const serverRouter = createTRPCRouter({ .input(apiFindOneServer) .query(async ({ input, ctx }) => { const server = await findServerById(input.serverId); - if (server.userId !== ctx.user.ownerId) { + if (server.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this server", @@ -93,7 +93,7 @@ export const serverRouter = createTRPCRouter({ .leftJoin(mongo, eq(mongo.serverId, server.serverId)) .leftJoin(mysql, eq(mysql.serverId, server.serverId)) .leftJoin(postgres, eq(postgres.serverId, server.serverId)) - .where(eq(server.userId, ctx.user.ownerId)) + .where(eq(server.organizationId, ctx.session.activeOrganizationId)) .orderBy(desc(server.createdAt)) .groupBy(server.serverId); @@ -105,10 +105,13 @@ export const serverRouter = createTRPCRouter({ where: IS_CLOUD ? and( isNotNull(server.sshKeyId), - eq(server.userId, ctx.user.ownerId), + eq(server.organizationId, ctx.session.activeOrganizationId), eq(server.serverStatus, "active"), ) - : and(isNotNull(server.sshKeyId), eq(server.userId, ctx.user.ownerId)), + : and( + isNotNull(server.sshKeyId), + eq(server.organizationId, ctx.session.activeOrganizationId), + ), }); return result; }), @@ -117,7 +120,7 @@ export const serverRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.userId !== ctx.user.ownerId) { + if (server.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to setup this server", @@ -142,7 +145,7 @@ export const serverRouter = createTRPCRouter({ .subscription(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.userId !== ctx.user.ownerId) { + if (server.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to setup this server", @@ -162,7 +165,7 @@ export const serverRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.userId !== ctx.user.ownerId) { + if (server.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to validate this server", @@ -204,7 +207,7 @@ export const serverRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.userId !== ctx.user.ownerId) { + if (server.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to validate this server", @@ -254,7 +257,7 @@ export const serverRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.userId !== ctx.user.ownerId) { + if (server.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to setup this server", @@ -296,7 +299,7 @@ export const serverRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.userId !== ctx.user.ownerId) { + if (server.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this server", @@ -330,7 +333,7 @@ export const serverRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const server = await findServerById(input.serverId); - if (server.userId !== ctx.user.ownerId) { + if (server.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this server", diff --git a/apps/dokploy/server/api/routers/ssh-key.ts b/apps/dokploy/server/api/routers/ssh-key.ts index 4beb0bae8..725c67fe2 100644 --- a/apps/dokploy/server/api/routers/ssh-key.ts +++ b/apps/dokploy/server/api/routers/ssh-key.ts @@ -27,7 +27,7 @@ export const sshRouter = createTRPCRouter({ console.log(ctx.user.ownerId); await createSshKey({ ...input, - userId: ctx.user.ownerId, + organizationId: ctx.session.activeOrganizationId, }); } catch (error) { throw new TRPCError({ @@ -42,7 +42,10 @@ export const sshRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const sshKey = await findSSHKeyById(input.sshKeyId); - if (IS_CLOUD && sshKey.userId !== ctx.user.ownerId) { + if ( + IS_CLOUD && + sshKey.organizationId !== ctx.session.activeOrganizationId + ) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -60,7 +63,10 @@ export const sshRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const sshKey = await findSSHKeyById(input.sshKeyId); - if (IS_CLOUD && sshKey.userId !== ctx.user.ownerId) { + if ( + IS_CLOUD && + sshKey.organizationId !== ctx.session.activeOrganizationId + ) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -71,7 +77,9 @@ export const sshRouter = createTRPCRouter({ }), all: protectedProcedure.query(async ({ ctx }) => { return await db.query.sshKeys.findMany({ - ...(IS_CLOUD && { where: eq(sshKeys.userId, ctx.user.ownerId) }), + ...(IS_CLOUD && { + where: eq(sshKeys.organizationId, ctx.session.activeOrganizationId), + }), orderBy: desc(sshKeys.createdAt), }); // TODO: Remove this line when the cloud version is ready @@ -86,7 +94,10 @@ export const sshRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const sshKey = await findSSHKeyById(input.sshKeyId); - if (IS_CLOUD && sshKey.userId !== ctx.user.ownerId) { + if ( + IS_CLOUD && + sshKey.organizationId !== ctx.session.activeOrganizationId + ) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index 98b5ab8e4..7f8f0f756 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -32,7 +32,7 @@ import { ZodError } from "zod"; interface CreateContextOptions { user: (User & { rol: "member" | "admin" | "owner"; ownerId: string }) | null; - session: (Session & { activeOrganizationId?: string }) | null; + session: (Session & { activeOrganizationId: string }) | null; req: CreateNextContextOptions["req"]; res: CreateNextContextOptions["res"]; } @@ -84,7 +84,7 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { session: session ? { ...session, - activeOrganizationId: session.activeOrganizationId ?? undefined, + activeOrganizationId: session.activeOrganizationId || "", } : null, user: user diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 522a921e8..3b29e0240 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -83,6 +83,7 @@ export const auth = betterAuth({ }, }, }, + plugins: [organization()], }); From 78c72b6337e8b10d65566c3baebf5b1fabd63256 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 20:49:10 -0600 Subject: [PATCH 30/89] refactor: update --- apps/dokploy/server/api/routers/certificate.ts | 2 +- apps/dokploy/server/api/routers/registry.ts | 10 +++++++--- packages/server/src/services/certificate.ts | 4 ++-- packages/server/src/services/registry.ts | 10 ++++++---- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/dokploy/server/api/routers/certificate.ts b/apps/dokploy/server/api/routers/certificate.ts index 87e6c6c8d..cdca1e97c 100644 --- a/apps/dokploy/server/api/routers/certificate.ts +++ b/apps/dokploy/server/api/routers/certificate.ts @@ -25,7 +25,7 @@ export const certificateRouter = createTRPCRouter({ message: "Please set a server to create a certificate", }); } - return await createCertificate(input, ctx.user.ownerId); + return await createCertificate(input, ctx.session.activeOrganizationId); }), one: adminProcedure diff --git a/apps/dokploy/server/api/routers/registry.ts b/apps/dokploy/server/api/routers/registry.ts index b57171795..1ac37716b 100644 --- a/apps/dokploy/server/api/routers/registry.ts +++ b/apps/dokploy/server/api/routers/registry.ts @@ -4,25 +4,26 @@ import { apiRemoveRegistry, apiTestRegistry, apiUpdateRegistry, + registry, } from "@/server/db/schema"; import { IS_CLOUD, createRegistry, execAsync, execAsyncRemote, - findAllRegistryByUserId, findRegistryById, removeRegistry, updateRegistry, } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; +import { eq } from "drizzle-orm"; export const registryRouter = createTRPCRouter({ create: adminProcedure .input(apiCreateRegistry) .mutation(async ({ ctx, input }) => { - return await createRegistry(input, ctx.user.ownerId); + return await createRegistry(input, ctx.session.activeOrganizationId); }), remove: adminProcedure .input(apiRemoveRegistry) @@ -61,7 +62,10 @@ export const registryRouter = createTRPCRouter({ return true; }), all: protectedProcedure.query(async ({ ctx }) => { - return await findAllRegistryByUserId(ctx.user.ownerId); + const registryResponse = await db.query.registry.findMany({ + where: eq(registry.organizationId, ctx.session.activeOrganizationId), + }); + return registryResponse; }), one: adminProcedure .input(apiFindOneRegistry) diff --git a/packages/server/src/services/certificate.ts b/packages/server/src/services/certificate.ts index dd83e61df..f59f1c2aa 100644 --- a/packages/server/src/services/certificate.ts +++ b/packages/server/src/services/certificate.ts @@ -33,13 +33,13 @@ export const findCertificateById = async (certificateId: string) => { export const createCertificate = async ( certificateData: z.infer, - userId: string, + organizationId: string, ) => { const certificate = await db .insert(certificates) .values({ ...certificateData, - userId: userId, + organizationId: organizationId, }) .returning(); diff --git a/packages/server/src/services/registry.ts b/packages/server/src/services/registry.ts index b92eabdb0..853f4cf7b 100644 --- a/packages/server/src/services/registry.ts +++ b/packages/server/src/services/registry.ts @@ -12,14 +12,14 @@ export type Registry = typeof registry.$inferSelect; export const createRegistry = async ( input: typeof apiCreateRegistry._type, - userId: string, + organizationId: string, ) => { return await db.transaction(async (tx) => { const newRegistry = await tx .insert(registry) .values({ ...input, - userId: userId, + organizationId: organizationId, }) .returning() .then((value) => value[0]); @@ -135,9 +135,11 @@ export const findRegistryById = async (registryId: string) => { return registryResponse; }; -export const findAllRegistryByUserId = async (userId: string) => { +export const findAllRegistryByOrganizationId = async ( + organizationId: string, +) => { const registryResponse = await db.query.registry.findMany({ - where: eq(registry.userId, userId), + where: eq(registry.organizationId, organizationId), }); return registryResponse; }; From 515d65d9934b454d9b679c43bef79dbea3da100a Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 23:01:36 -0600 Subject: [PATCH 31/89] refactor: adjust queries --- .../organization/handle-organization.tsx | 119 ++++++++++ .../settings/certificates/add-certificate.tsx | 1 + .../settings/ssh-keys/handle-ssh-keys.tsx | 1 + .../dashboard/settings/users/show-users.tsx | 89 +++---- .../dashboard/settings/web-domain.tsx | 12 +- apps/dokploy/components/layouts/side.tsx | 222 ++++++++++++++++-- apps/dokploy/server/api/root.ts | 3 +- .../dokploy/server/api/routers/certificate.ts | 18 +- .../server/api/routers/organization.ts | 86 +++++++ apps/dokploy/server/api/routers/registry.ts | 2 +- apps/dokploy/server/api/routers/ssh-key.ts | 1 - apps/dokploy/server/api/routers/user.ts | 11 +- packages/server/src/db/schema/account.ts | 17 +- packages/server/src/db/schema/bitbucket.ts | 2 +- packages/server/src/db/schema/notification.ts | 8 +- packages/server/src/db/schema/server.ts | 4 + packages/server/src/services/bitbucket.ts | 8 +- packages/server/src/services/destination.ts | 10 +- packages/server/src/services/github.ts | 4 +- packages/server/src/services/gitlab.ts | 4 +- packages/server/src/services/notification.ts | 30 +-- packages/server/src/services/project.ts | 4 +- packages/server/src/services/server.ts | 20 +- 23 files changed, 538 insertions(+), 138 deletions(-) create mode 100644 apps/dokploy/components/dashboard/organization/handle-organization.tsx create mode 100644 apps/dokploy/server/api/routers/organization.ts diff --git a/apps/dokploy/components/dashboard/organization/handle-organization.tsx b/apps/dokploy/components/dashboard/organization/handle-organization.tsx new file mode 100644 index 000000000..00bf42b9f --- /dev/null +++ b/apps/dokploy/components/dashboard/organization/handle-organization.tsx @@ -0,0 +1,119 @@ +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { PenBoxIcon, Plus, SquarePen } from "lucide-react"; +import { useEffect, useState } from "react"; +import { api } from "@/utils/api"; +import { toast } from "sonner"; + +interface Props { + organizationId?: string; + children?: React.ReactNode; +} +export function AddOrganization({ organizationId, children }: Props) { + const utils = api.useUtils(); + const { data: organization } = api.organization.one.useQuery( + { + organizationId: organizationId ?? "", + }, + { + enabled: !!organizationId, + }, + ); + const { mutateAsync, isLoading } = organizationId + ? api.organization.update.useMutation() + : api.organization.create.useMutation(); + const [open, setOpen] = useState(false); + const [name, setName] = useState(""); + + useEffect(() => { + if (organization) { + setName(organization.name); + } + }, [organization]); + const handleSubmit = async () => { + await mutateAsync({ name, organizationId: organizationId ?? "" }) + .then(() => { + setOpen(false); + toast.success( + `Organization ${organizationId ? "updated" : "created"} successfully`, + ); + utils.organization.all.invalidate(); + }) + .catch((error) => { + console.error(error); + toast.error( + `Failed to ${organizationId ? "update" : "create"} organization`, + ); + }); + }; + return ( + + + {organizationId ? ( + e.preventDefault()} + > + + + ) : ( + { + setOpen(true); + }} + onSelect={(e) => e.preventDefault()} + > +
+ +
+
+ Add organization +
+
+ )} +
+ + + + {organizationId ? "Update organization" : "Add organization"} + + + {organizationId + ? "Update the organization name" + : "Create a new organization to manage your projects."} + + +
+
+ + setName(e.target.value)} + className="col-span-3" + /> +
+
+ + + +
+
+ ); +} diff --git a/apps/dokploy/components/dashboard/settings/certificates/add-certificate.tsx b/apps/dokploy/components/dashboard/settings/certificates/add-certificate.tsx index c6546f2d1..58cad7910 100644 --- a/apps/dokploy/components/dashboard/settings/certificates/add-certificate.tsx +++ b/apps/dokploy/components/dashboard/settings/certificates/add-certificate.tsx @@ -86,6 +86,7 @@ export const AddCertificate = () => { privateKey: data.privateKey, autoRenew: data.autoRenew, serverId: data.serverId, + organizationId: "", }) .then(async () => { toast.success("Certificate Created"); diff --git a/apps/dokploy/components/dashboard/settings/ssh-keys/handle-ssh-keys.tsx b/apps/dokploy/components/dashboard/settings/ssh-keys/handle-ssh-keys.tsx index fc48134a2..1a8fe9187 100644 --- a/apps/dokploy/components/dashboard/settings/ssh-keys/handle-ssh-keys.tsx +++ b/apps/dokploy/components/dashboard/settings/ssh-keys/handle-ssh-keys.tsx @@ -78,6 +78,7 @@ export const HandleSSHKeys = ({ sshKeyId }: Props) => { const onSubmit = async (data: SSHKey) => { await mutateAsync({ ...data, + organizationId: "", sshKeyId: sshKeyId || "", }) .then(async () => { diff --git a/apps/dokploy/components/dashboard/settings/users/show-users.tsx b/apps/dokploy/components/dashboard/settings/users/show-users.tsx index 9dfbfc931..8aa2a37b4 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-users.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-users.tsx @@ -76,10 +76,11 @@ export const ShowUsers = () => { Email - Status + Role 2FA + {/* Status */} - Expiration + Created At Actions @@ -89,30 +90,32 @@ export const ShowUsers = () => { return ( - {user.auth.email} + {user.user.email} - {user.isRegistered - ? "Registered" - : "Not Registered"} + {user.role} - {user.auth.is2FAEnabled + {user.user.is2FAEnabled ? "2FA Enabled" : "2FA Not Enabled"} + {/* + + {format(new Date(user.createdAt), "PPpp")} + + */} - {format( - new Date(user.expirationDate), - "PPpp", - )} + {format(new Date(user.createdAt), "PPpp")} @@ -131,7 +134,7 @@ export const ShowUsers = () => { Actions - {!user.isRegistered && ( + {/* {!user.isRegistered && ( { @@ -145,42 +148,44 @@ export const ShowUsers = () => { > Copy Invitation - )} + )} */} - {user.isRegistered && ( + {/* {user.isRegistered && ( - )} + )} */} - { - await mutateAsync({ - authId: user.authId, - }) - .then(() => { - toast.success( - "User deleted successfully", - ); - refetch(); + {user.role !== "owner" && ( + { + await mutateAsync({ + userId: user.userId, }) - .catch(() => { - toast.error( - "Error deleting destination", - ); - }); - }} - > - e.preventDefault()} + .then(() => { + toast.success( + "User deleted successfully", + ); + refetch(); + }) + .catch(() => { + toast.error( + "Error deleting destination", + ); + }); + }} > - Delete User - - + e.preventDefault()} + > + Delete User + + + )} diff --git a/apps/dokploy/components/dashboard/settings/web-domain.tsx b/apps/dokploy/components/dashboard/settings/web-domain.tsx index 401981473..0b002e9d4 100644 --- a/apps/dokploy/components/dashboard/settings/web-domain.tsx +++ b/apps/dokploy/components/dashboard/settings/web-domain.tsx @@ -52,7 +52,7 @@ type AddServerDomain = z.infer; export const WebDomain = () => { const { t } = useTranslation("settings"); - const { data: user, refetch } = api.admin.one.useQuery(); + const { data, refetch } = api.auth.get.useQuery(); const { mutateAsync, isLoading } = api.settings.assignDomainServer.useMutation(); @@ -65,14 +65,14 @@ export const WebDomain = () => { resolver: zodResolver(addServerDomain), }); useEffect(() => { - if (user) { + if (data) { form.reset({ - domain: user?.host || "", - certificateType: user?.certificateType, - letsEncryptEmail: user?.letsEncryptEmail || "", + domain: data?.user?.host || "", + certificateType: data?.user?.certificateType, + letsEncryptEmail: data?.user?.letsEncryptEmail || "", }); } - }, [form, form.reset, user]); + }, [form, form.reset, data]); const onSubmit = async (data: AddServerDomain) => { await mutateAsync({ diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 99938a5de..8e8a74dc3 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -1,6 +1,7 @@ "use client"; import { Activity, + AudioWaveform, BarChartHorizontalBigIcon, Bell, BlocksIcon, @@ -8,6 +9,7 @@ import { Boxes, ChevronRight, CircleHelp, + Command, CreditCard, Database, Folder, @@ -16,11 +18,13 @@ import { GitBranch, HeartIcon, KeyRound, + Loader2, type LucideIcon, Package, PieChart, Server, ShieldCheck, + Trash2, User, Users, } from "lucide-react"; @@ -480,37 +484,207 @@ interface Props { function LogoWrapper() { return ; } +import { ChevronsUpDown, Plus } from "lucide-react"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { AddOrganization } from "../dashboard/organization/handle-organization"; +import { authClient } from "@/lib/auth"; +import { DialogAction } from "../shared/dialog-action"; +import { Button } from "../ui/button"; +import { toast } from "sonner"; +const data = { + user: { + name: "shadcn", + email: "m@example.com", + avatar: "/avatars/shadcn.jpg", + }, + teams: [ + { + name: "Acme Inc", + logo: GalleryVerticalEnd, + plan: "Enterprise", + }, + { + name: "Acme Corp.", + logo: AudioWaveform, + plan: "Startup", + }, + { + name: "Evil Corp.", + logo: Command, + plan: "Free", + }, + ], +}; + +const teams = data.teams; function SidebarLogo() { const { state } = useSidebar(); const { data: dokployVersion } = api.settings.getDokployVersion.useQuery(); + const { + data: organizations, + refetch, + isLoading, + } = api.organization.all.useQuery(); + const { mutateAsync: deleteOrganization, isLoading: isRemoving } = + api.organization.delete.useMutation(); + const { isMobile } = useSidebar(); + const { data: activeOrganization } = authClient.useActiveOrganization(); + + const [activeTeam, setActiveTeam] = useState< + typeof activeOrganization | null + >(null); + + useEffect(() => { + if (activeOrganization) { + setActiveTeam(activeOrganization); + } + }, [activeOrganization]); return ( - -
+ {isLoading ? ( +
+ Loading... + +
+ ) : ( + + + + + + {/*
*/} +
+ +
+
+ + {activeTeam?.name} + +
+ + + + + + Organizations + + {organizations?.map((org, index) => ( +
+ { + await authClient.organization.setActive({ + organizationId: org.id, + }); + + window.location.reload(); + }} + className="w-full gap-2 p-2" + > +
+ +
+ {org.name} + {/* ⌘{index + 1} */} +
+ {/* */} +
+ + { + await deleteOrganization({ + organizationId: org.id, + }) + .then(() => { + refetch(); + toast.success("Port deleted successfully"); + }) + .catch(() => { + toast.error("Error deleting port"); + }); + }} + > + + +
+
+ ))} + + +
+ + + + )} + + {/* - -
+ > + +
-
-

Dokploy

-

- {dokployVersion} -

-
- +
+

Dokploy

+

+ {dokployVersion} +

+
+ */} + ); } @@ -577,12 +751,12 @@ export default function Page({ children }: Props) { > - - - + > */} + + {/* */} diff --git a/apps/dokploy/server/api/root.ts b/apps/dokploy/server/api/root.ts index 68f5e4e0c..7860b248f 100644 --- a/apps/dokploy/server/api/root.ts +++ b/apps/dokploy/server/api/root.ts @@ -33,7 +33,7 @@ import { sshRouter } from "./routers/ssh-key"; import { stripeRouter } from "./routers/stripe"; import { swarmRouter } from "./routers/swarm"; import { userRouter } from "./routers/user"; - +import { organizationRouter } from "./routers/organization"; /** * This is the primary router for your server. * @@ -75,6 +75,7 @@ export const appRouter = createTRPCRouter({ server: serverRouter, stripe: stripeRouter, swarm: swarmRouter, + organization: organizationRouter, }); // export type definition of API diff --git a/apps/dokploy/server/api/routers/certificate.ts b/apps/dokploy/server/api/routers/certificate.ts index cdca1e97c..3dc944ac8 100644 --- a/apps/dokploy/server/api/routers/certificate.ts +++ b/apps/dokploy/server/api/routers/certificate.ts @@ -32,10 +32,7 @@ export const certificateRouter = createTRPCRouter({ .input(apiFindCertificate) .query(async ({ input, ctx }) => { const certificates = await findCertificateById(input.certificateId); - if ( - IS_CLOUD && - certificates.organizationId !== ctx.session.activeOrganizationId - ) { + if (certificates.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this certificate", @@ -47,10 +44,7 @@ export const certificateRouter = createTRPCRouter({ .input(apiFindCertificate) .mutation(async ({ input, ctx }) => { const certificates = await findCertificateById(input.certificateId); - if ( - IS_CLOUD && - certificates.organizationId !== ctx.session.activeOrganizationId - ) { + if (certificates.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to delete this certificate", @@ -61,13 +55,7 @@ export const certificateRouter = createTRPCRouter({ }), all: adminProcedure.query(async ({ ctx }) => { return await db.query.certificates.findMany({ - // TODO: Remove this line when the cloud version is ready - ...(IS_CLOUD && { - where: eq( - certificates.organizationId, - ctx.session.activeOrganizationId, - ), - }), + where: eq(certificates.organizationId, ctx.session.activeOrganizationId), }); }), }); diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts new file mode 100644 index 000000000..dd933c9d4 --- /dev/null +++ b/apps/dokploy/server/api/routers/organization.ts @@ -0,0 +1,86 @@ +import { adminProcedure, createTRPCRouter } from "../trpc"; +import { z } from "zod"; +import { db } from "@/server/db"; +import { member, organization } from "@/server/db/schema"; +import { nanoid } from "nanoid"; +import { desc, eq } from "drizzle-orm"; +import { TRPCError } from "@trpc/server"; +export const organizationRouter = createTRPCRouter({ + create: adminProcedure + .input( + z.object({ + name: z.string(), + }), + ) + .mutation(async ({ ctx, input }) => { + const result = await db + .insert(organization) + .values({ + ...input, + slug: nanoid(), + createdAt: new Date(), + ownerId: ctx.user.ownerId, + }) + .returning() + .then((res) => res[0]); + + if (!result) { + throw new TRPCError({ + code: "INTERNAL_SERVER_ERROR", + message: "Failed to create organization", + }); + } + + const memberResult = await db.insert(member).values({ + organizationId: result.id, + role: "owner", + createdAt: new Date(), + userId: ctx.user.id, + }); + return result; + }), + all: adminProcedure.query(async ({ ctx }) => { + return await db.query.organization.findMany({ + where: eq(organization.ownerId, ctx.user.ownerId), + orderBy: [desc(organization.createdAt)], + }); + }), + one: adminProcedure + .input( + z.object({ + organizationId: z.string(), + }), + ) + .query(async ({ ctx, input }) => { + return await db.query.organization.findFirst({ + where: eq(organization.id, input.organizationId), + }); + }), + update: adminProcedure + .input( + z.object({ + organizationId: z.string(), + name: z.string(), + }), + ) + .mutation(async ({ ctx, input }) => { + const result = await db + .update(organization) + .set({ name: input.name }) + .where(eq(organization.id, input.organizationId)) + .returning(); + return result[0]; + }), + delete: adminProcedure + .input( + z.object({ + organizationId: z.string(), + }), + ) + .mutation(async ({ ctx, input }) => { + const result = await db + .delete(organization) + .where(eq(organization.id, input.organizationId)); + return result; + }), +}); diff --git a/apps/dokploy/server/api/routers/registry.ts b/apps/dokploy/server/api/routers/registry.ts index 1ac37716b..6ad7e2a94 100644 --- a/apps/dokploy/server/api/routers/registry.ts +++ b/apps/dokploy/server/api/routers/registry.ts @@ -16,8 +16,8 @@ import { updateRegistry, } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; -import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; import { eq } from "drizzle-orm"; +import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; export const registryRouter = createTRPCRouter({ create: adminProcedure diff --git a/apps/dokploy/server/api/routers/ssh-key.ts b/apps/dokploy/server/api/routers/ssh-key.ts index 725c67fe2..90f7cd6e4 100644 --- a/apps/dokploy/server/api/routers/ssh-key.ts +++ b/apps/dokploy/server/api/routers/ssh-key.ts @@ -24,7 +24,6 @@ export const sshRouter = createTRPCRouter({ .input(apiCreateSshKey) .mutation(async ({ input, ctx }) => { try { - console.log(ctx.user.ownerId); await createSshKey({ ...input, organizationId: ctx.session.activeOrganizationId, diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 91db98261..129b0731d 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -2,10 +2,17 @@ import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema"; import { findUserByAuthId, findUserById, findUsers } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; - +import { eq } from "drizzle-orm"; +import { member } from "@dokploy/server/db/schema"; +import { db } from "@dokploy/server/db"; export const userRouter = createTRPCRouter({ all: adminProcedure.query(async ({ ctx }) => { - return await findUsers(ctx.user.adminId); + return await db.query.member.findMany({ + where: eq(member.organizationId, ctx.session.activeOrganizationId), + with: { + user: true, + }, + }); }), byAuthId: protectedProcedure .input(apiFindOneUserByAuth) diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 0b5ef2707..da765e8f2 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -2,6 +2,8 @@ import { relations } from "drizzle-orm"; import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { nanoid } from "nanoid"; import { users_temp } from "./user"; +import { server } from "./server"; +import { projects } from "./project"; export const account = pgTable("account", { id: text("id") @@ -60,12 +62,17 @@ export const organization = pgTable("organization", { .references(() => users_temp.id), }); -export const organizationRelations = relations(organization, ({ one }) => ({ - owner: one(users_temp, { - fields: [organization.ownerId], - references: [users_temp.id], +export const organizationRelations = relations( + organization, + ({ one, many }) => ({ + owner: one(users_temp, { + fields: [organization.ownerId], + references: [users_temp.id], + }), + servers: many(server), + projects: many(projects), }), -})); +); export const member = pgTable("member", { id: text("id") diff --git a/packages/server/src/db/schema/bitbucket.ts b/packages/server/src/db/schema/bitbucket.ts index b8ecb6682..0311202d7 100644 --- a/packages/server/src/db/schema/bitbucket.ts +++ b/packages/server/src/db/schema/bitbucket.ts @@ -61,5 +61,5 @@ export const apiUpdateBitbucket = createSchema.extend({ name: z.string().min(1), bitbucketUsername: z.string().optional(), bitbucketWorkspaceName: z.string().optional(), - userId: z.string().optional(), + organizationId: z.string().optional(), }); diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 6e29ddf67..4e2917ca9 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -150,7 +150,7 @@ export const apiCreateSlack = notificationsSchema export const apiUpdateSlack = apiCreateSlack.partial().extend({ notificationId: z.string().min(1), slackId: z.string(), - userId: z.string().optional(), + organizationId: z.string().optional(), }); export const apiTestSlackConnection = apiCreateSlack.pick({ @@ -177,7 +177,7 @@ export const apiCreateTelegram = notificationsSchema export const apiUpdateTelegram = apiCreateTelegram.partial().extend({ notificationId: z.string().min(1), telegramId: z.string().min(1), - userId: z.string().optional(), + organizationId: z.string().optional(), }); export const apiTestTelegramConnection = apiCreateTelegram.pick({ @@ -204,7 +204,7 @@ export const apiCreateDiscord = notificationsSchema export const apiUpdateDiscord = apiCreateDiscord.partial().extend({ notificationId: z.string().min(1), discordId: z.string().min(1), - userId: z.string().optional(), + organizationId: z.string().optional(), }); export const apiTestDiscordConnection = apiCreateDiscord @@ -238,7 +238,7 @@ export const apiCreateEmail = notificationsSchema export const apiUpdateEmail = apiCreateEmail.partial().extend({ notificationId: z.string().min(1), emailId: z.string().min(1), - userId: z.string().optional(), + organizationId: z.string().optional(), }); export const apiTestEmailConnection = apiCreateEmail.pick({ diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index f1dcd1001..c94fd693e 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -118,6 +118,10 @@ export const serverRelations = relations(server, ({ one, many }) => ({ mysql: many(mysql), postgres: many(postgres), certificates: many(certificates), + organization: one(organization, { + fields: [server.organizationId], + references: [organization.id], + }), })); const createSchema = createInsertSchema(server, { diff --git a/packages/server/src/services/bitbucket.ts b/packages/server/src/services/bitbucket.ts index 4ce4a7b03..7b5be7d65 100644 --- a/packages/server/src/services/bitbucket.ts +++ b/packages/server/src/services/bitbucket.ts @@ -12,14 +12,14 @@ export type Bitbucket = typeof bitbucket.$inferSelect; export const createBitbucket = async ( input: typeof apiCreateBitbucket._type, - userId: string, + organizationId: string, ) => { return await db.transaction(async (tx) => { const newGitProvider = await tx .insert(gitProvider) .values({ providerType: "bitbucket", - userId: userId, + organizationId: organizationId, name: input.name, }) .returning() @@ -74,12 +74,12 @@ export const updateBitbucket = async ( .where(eq(bitbucket.bitbucketId, bitbucketId)) .returning(); - if (input.name || input.userId) { + if (input.name || input.organizationId) { await tx .update(gitProvider) .set({ name: input.name, - userId: input.userId, + organizationId: input.organizationId, }) .where(eq(gitProvider.gitProviderId, input.gitProviderId)) .returning(); diff --git a/packages/server/src/services/destination.ts b/packages/server/src/services/destination.ts index add0a3dff..e66f8695a 100644 --- a/packages/server/src/services/destination.ts +++ b/packages/server/src/services/destination.ts @@ -10,13 +10,13 @@ export type Destination = typeof destinations.$inferSelect; export const createDestintation = async ( input: typeof apiCreateDestination._type, - userId: string, + organizationId: string, ) => { const newDestination = await db .insert(destinations) .values({ ...input, - userId: userId, + organizationId: organizationId, }) .returning() .then((value) => value[0]); @@ -46,14 +46,14 @@ export const findDestinationById = async (destinationId: string) => { export const removeDestinationById = async ( destinationId: string, - userId: string, + organizationId: string, ) => { const result = await db .delete(destinations) .where( and( eq(destinations.destinationId, destinationId), - eq(destinations.userId, userId), + eq(destinations.organizationId, organizationId), ), ) .returning(); @@ -73,7 +73,7 @@ export const updateDestinationById = async ( .where( and( eq(destinations.destinationId, destinationId), - eq(destinations.userId, destinationData.userId || ""), + eq(destinations.organizationId, destinationData.organizationId || ""), ), ) .returning(); diff --git a/packages/server/src/services/github.ts b/packages/server/src/services/github.ts index b23edf207..deb5f3fa2 100644 --- a/packages/server/src/services/github.ts +++ b/packages/server/src/services/github.ts @@ -12,14 +12,14 @@ import { updatePreviewDeployment } from "./preview-deployment"; export type Github = typeof github.$inferSelect; export const createGithub = async ( input: typeof apiCreateGithub._type, - userId: string, + organizationId: string, ) => { return await db.transaction(async (tx) => { const newGitProvider = await tx .insert(gitProvider) .values({ providerType: "github", - userId: userId, + organizationId: organizationId, name: input.name, }) .returning() diff --git a/packages/server/src/services/gitlab.ts b/packages/server/src/services/gitlab.ts index c581c96ce..0822aaaba 100644 --- a/packages/server/src/services/gitlab.ts +++ b/packages/server/src/services/gitlab.ts @@ -13,14 +13,14 @@ export type Gitlab = typeof gitlab.$inferSelect; export const createGitlab = async ( input: typeof apiCreateGitlab._type, - userId: string, + organizationId: string, ) => { return await db.transaction(async (tx) => { const newGitProvider = await tx .insert(gitProvider) .values({ providerType: "gitlab", - userId: userId, + organizationId: organizationId, name: input.name, }) .returning() diff --git a/packages/server/src/services/notification.ts b/packages/server/src/services/notification.ts index 03f6bd09d..fa355a565 100644 --- a/packages/server/src/services/notification.ts +++ b/packages/server/src/services/notification.ts @@ -24,7 +24,7 @@ export type Notification = typeof notifications.$inferSelect; export const createSlackNotification = async ( input: typeof apiCreateSlack._type, - userId: string, + organizationId: string, ) => { await db.transaction(async (tx) => { const newSlack = await tx @@ -54,7 +54,7 @@ export const createSlackNotification = async ( dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, notificationType: "slack", - userId: userId, + organizationId: organizationId, serverThreshold: input.serverThreshold, }) .returning() @@ -84,7 +84,7 @@ export const updateSlackNotification = async ( databaseBackup: input.databaseBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, - userId: input.userId, + organizationId: input.organizationId, serverThreshold: input.serverThreshold, }) .where(eq(notifications.notificationId, input.notificationId)) @@ -114,7 +114,7 @@ export const updateSlackNotification = async ( export const createTelegramNotification = async ( input: typeof apiCreateTelegram._type, - userId: string, + organizationId: string, ) => { await db.transaction(async (tx) => { const newTelegram = await tx @@ -144,7 +144,7 @@ export const createTelegramNotification = async ( dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, notificationType: "telegram", - userId: userId, + organizationId: organizationId, serverThreshold: input.serverThreshold, }) .returning() @@ -174,7 +174,7 @@ export const updateTelegramNotification = async ( databaseBackup: input.databaseBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, - userId: input.userId, + organizationId: input.organizationId, serverThreshold: input.serverThreshold, }) .where(eq(notifications.notificationId, input.notificationId)) @@ -204,7 +204,7 @@ export const updateTelegramNotification = async ( export const createDiscordNotification = async ( input: typeof apiCreateDiscord._type, - userId: string, + organizationId: string, ) => { await db.transaction(async (tx) => { const newDiscord = await tx @@ -234,7 +234,7 @@ export const createDiscordNotification = async ( dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, notificationType: "discord", - userId: userId, + organizationId: organizationId, serverThreshold: input.serverThreshold, }) .returning() @@ -264,7 +264,7 @@ export const updateDiscordNotification = async ( databaseBackup: input.databaseBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, - userId: input.userId, + organizationId: input.organizationId, serverThreshold: input.serverThreshold, }) .where(eq(notifications.notificationId, input.notificationId)) @@ -294,7 +294,7 @@ export const updateDiscordNotification = async ( export const createEmailNotification = async ( input: typeof apiCreateEmail._type, - userId: string, + organizationId: string, ) => { await db.transaction(async (tx) => { const newEmail = await tx @@ -328,7 +328,7 @@ export const createEmailNotification = async ( dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, notificationType: "email", - userId: userId, + organizationId: organizationId, serverThreshold: input.serverThreshold, }) .returning() @@ -358,7 +358,7 @@ export const updateEmailNotification = async ( databaseBackup: input.databaseBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, - userId: input.userId, + organizationId: input.organizationId, serverThreshold: input.serverThreshold, }) .where(eq(notifications.notificationId, input.notificationId)) @@ -392,7 +392,7 @@ export const updateEmailNotification = async ( export const createGotifyNotification = async ( input: typeof apiCreateGotify._type, - userId: string, + organizationId: string, ) => { await db.transaction(async (tx) => { const newGotify = await tx @@ -424,7 +424,7 @@ export const createGotifyNotification = async ( dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, notificationType: "gotify", - userId: userId, + organizationId: organizationId, }) .returning() .then((value) => value[0]); @@ -453,7 +453,7 @@ export const updateGotifyNotification = async ( databaseBackup: input.databaseBackup, dokployRestart: input.dokployRestart, dockerCleanup: input.dockerCleanup, - userId: input.userId, + organizationId: input.organizationId, }) .where(eq(notifications.notificationId, input.notificationId)) .returning() diff --git a/packages/server/src/services/project.ts b/packages/server/src/services/project.ts index 8b80738fd..b740834b5 100644 --- a/packages/server/src/services/project.ts +++ b/packages/server/src/services/project.ts @@ -16,13 +16,13 @@ export type Project = typeof projects.$inferSelect; export const createProject = async ( input: typeof apiCreateProject._type, - userId: string, + organizationId: string, ) => { const newProject = await db .insert(projects) .values({ ...input, - userId: userId, + organizationId: organizationId, }) .returning() .then((value) => value[0]); diff --git a/packages/server/src/services/server.ts b/packages/server/src/services/server.ts index 7702c90d6..afe851ef5 100644 --- a/packages/server/src/services/server.ts +++ b/packages/server/src/services/server.ts @@ -1,5 +1,9 @@ import { db } from "@dokploy/server/db"; -import { type apiCreateServer, server } from "@dokploy/server/db/schema"; +import { + type apiCreateServer, + organization, + server, +} from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { desc, eq } from "drizzle-orm"; @@ -7,13 +11,13 @@ export type Server = typeof server.$inferSelect; export const createServer = async ( input: typeof apiCreateServer._type, - userId: string, + organizationId: string, ) => { const newServer = await db .insert(server) .values({ ...input, - userId: userId, + organizationId: organizationId, createdAt: new Date().toISOString(), }) .returning() @@ -47,11 +51,15 @@ export const findServerById = async (serverId: string) => { }; export const findServersByUserId = async (userId: string) => { - const servers = await db.query.server.findMany({ - where: eq(server.userId, userId), - orderBy: desc(server.createdAt), + const orgs = await db.query.organization.findMany({ + where: eq(organization.ownerId, userId), + with: { + servers: true, + }, }); + const servers = orgs.flatMap((org) => org.servers); + return servers; }; From ed62b4e1a3cc575b70d5b842d33d7740f0e9bb2a Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 23:01:44 -0600 Subject: [PATCH 32/89] refactor: lint --- .../dashboard/organization/handle-organization.tsx | 2 +- apps/dokploy/components/layouts/side.tsx | 4 ++-- apps/dokploy/server/api/root.ts | 2 +- apps/dokploy/server/api/routers/organization.ts | 8 ++++---- apps/dokploy/server/api/routers/user.ts | 8 ++++---- packages/server/src/db/schema/account.ts | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/dokploy/components/dashboard/organization/handle-organization.tsx b/apps/dokploy/components/dashboard/organization/handle-organization.tsx index 00bf42b9f..24bb5c0eb 100644 --- a/apps/dokploy/components/dashboard/organization/handle-organization.tsx +++ b/apps/dokploy/components/dashboard/organization/handle-organization.tsx @@ -11,9 +11,9 @@ import { import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { api } from "@/utils/api"; import { PenBoxIcon, Plus, SquarePen } from "lucide-react"; import { useEffect, useState } from "react"; -import { api } from "@/utils/api"; import { toast } from "sonner"; interface Props { diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 8e8a74dc3..cc27dc389 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -495,11 +495,11 @@ import { DropdownMenuShortcut, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { AddOrganization } from "../dashboard/organization/handle-organization"; import { authClient } from "@/lib/auth"; +import { toast } from "sonner"; +import { AddOrganization } from "../dashboard/organization/handle-organization"; import { DialogAction } from "../shared/dialog-action"; import { Button } from "../ui/button"; -import { toast } from "sonner"; const data = { user: { name: "shadcn", diff --git a/apps/dokploy/server/api/root.ts b/apps/dokploy/server/api/root.ts index 7860b248f..5f5d0bcc8 100644 --- a/apps/dokploy/server/api/root.ts +++ b/apps/dokploy/server/api/root.ts @@ -19,6 +19,7 @@ import { mongoRouter } from "./routers/mongo"; import { mountRouter } from "./routers/mount"; import { mysqlRouter } from "./routers/mysql"; import { notificationRouter } from "./routers/notification"; +import { organizationRouter } from "./routers/organization"; import { portRouter } from "./routers/port"; import { postgresRouter } from "./routers/postgres"; import { previewDeploymentRouter } from "./routers/preview-deployment"; @@ -33,7 +34,6 @@ import { sshRouter } from "./routers/ssh-key"; import { stripeRouter } from "./routers/stripe"; import { swarmRouter } from "./routers/swarm"; import { userRouter } from "./routers/user"; -import { organizationRouter } from "./routers/organization"; /** * This is the primary router for your server. * diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts index dd933c9d4..db0c64385 100644 --- a/apps/dokploy/server/api/routers/organization.ts +++ b/apps/dokploy/server/api/routers/organization.ts @@ -1,10 +1,10 @@ -import { adminProcedure, createTRPCRouter } from "../trpc"; -import { z } from "zod"; import { db } from "@/server/db"; import { member, organization } from "@/server/db/schema"; -import { nanoid } from "nanoid"; -import { desc, eq } from "drizzle-orm"; import { TRPCError } from "@trpc/server"; +import { desc, eq } from "drizzle-orm"; +import { nanoid } from "nanoid"; +import { z } from "zod"; +import { adminProcedure, createTRPCRouter } from "../trpc"; export const organizationRouter = createTRPCRouter({ create: adminProcedure .input( diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 129b0731d..ccf9e5bc1 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -1,10 +1,10 @@ import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema"; import { findUserByAuthId, findUserById, findUsers } from "@dokploy/server"; -import { TRPCError } from "@trpc/server"; -import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; -import { eq } from "drizzle-orm"; -import { member } from "@dokploy/server/db/schema"; import { db } from "@dokploy/server/db"; +import { member } from "@dokploy/server/db/schema"; +import { TRPCError } from "@trpc/server"; +import { eq } from "drizzle-orm"; +import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; export const userRouter = createTRPCRouter({ all: adminProcedure.query(async ({ ctx }) => { return await db.query.member.findMany({ diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index da765e8f2..3bb7dcfca 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -1,9 +1,9 @@ import { relations } from "drizzle-orm"; import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { nanoid } from "nanoid"; -import { users_temp } from "./user"; -import { server } from "./server"; import { projects } from "./project"; +import { server } from "./server"; +import { users_temp } from "./user"; export const account = pgTable("account", { id: text("id") From 4a1a14aeb49a022a7823ab36899317131269266b Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 15 Feb 2025 23:24:45 -0600 Subject: [PATCH 33/89] refactor: update --- apps/dokploy/pages/dashboard/docker.tsx | 18 ++++----- apps/dokploy/pages/dashboard/monitoring.tsx | 4 +- .../pages/dashboard/project/[projectId].tsx | 4 +- .../services/application/[applicationId].tsx | 5 ++- .../services/compose/[composeId].tsx | 4 +- .../services/mariadb/[mariadbId].tsx | 4 +- .../[projectId]/services/mongo/[mongoId].tsx | 4 +- .../[projectId]/services/mysql/[mysqlId].tsx | 4 +- .../services/postgres/[postgresId].tsx | 4 +- .../[projectId]/services/redis/[redisId].tsx | 4 +- apps/dokploy/pages/dashboard/projects.tsx | 8 ++-- apps/dokploy/pages/dashboard/requests.tsx | 5 ++- .../pages/dashboard/settings/billing.tsx | 9 +++-- apps/dokploy/pages/dashboard/swarm.tsx | 18 ++++----- apps/dokploy/pages/dashboard/traefik.tsx | 18 ++++----- apps/dokploy/server/api/routers/compose.ts | 37 +++++++++++-------- .../server/api/routers/notification.ts | 33 ++++++++--------- apps/dokploy/server/api/routers/project.ts | 5 ++- apps/dokploy/server/api/routers/ssh-key.ts | 22 ++--------- apps/dokploy/server/api/routers/user.ts | 23 +++++++----- packages/server/src/db/schema/notification.ts | 2 +- .../utils/notifications/server-threshold.ts | 4 +- 22 files changed, 119 insertions(+), 120 deletions(-) diff --git a/apps/dokploy/pages/dashboard/docker.tsx b/apps/dokploy/pages/dashboard/docker.tsx index 051e4f0a9..202935aa6 100644 --- a/apps/dokploy/pages/dashboard/docker.tsx +++ b/apps/dokploy/pages/dashboard/docker.tsx @@ -1,7 +1,8 @@ import { ShowContainers } from "@/components/dashboard/docker/show/show-containers"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { appRouter } from "@/server/api/root"; -import { IS_CLOUD, validateRequest } from "@dokploy/server"; +import { IS_CLOUD } from "@dokploy/server/constants"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; import React, { type ReactElement } from "react"; @@ -27,7 +28,7 @@ export async function getServerSideProps( }, }; } - const { user, session } = await validateRequest(ctx.req, ctx.res); + const { user, session } = await validateRequest(ctx.req); if (!user) { return { redirect: { @@ -44,21 +45,20 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); try { await helpers.project.all.prefetch(); - const auth = await helpers.auth.get.fetch(); - if (auth.role === "member") { - const user = await helpers.user.byAuthId.fetch({ - authId: auth.id, + if (user.role === "member") { + const userR = await helpers.user.get.fetch({ + userId: user.id, }); - if (!user.canAccessToDocker) { + if (!userR.canAccessToDocker) { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/monitoring.tsx b/apps/dokploy/pages/dashboard/monitoring.tsx index a9f712f30..a30706fc8 100644 --- a/apps/dokploy/pages/dashboard/monitoring.tsx +++ b/apps/dokploy/pages/dashboard/monitoring.tsx @@ -8,7 +8,7 @@ import { Switch } from "@/components/ui/switch"; import { useLocalStorage } from "@/hooks/useLocalStorage"; import { api } from "@/utils/api"; import { IS_CLOUD } from "@dokploy/server/constants"; -import { validateRequest } from "@dokploy/server/index"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { Loader2 } from "lucide-react"; import type { GetServerSidePropsContext } from "next"; import type React from "react"; @@ -104,7 +104,7 @@ export async function getServerSideProps( }, }; } - const { user } = await validateRequest(ctx.req, ctx.res); + const { user } = await validateRequest(ctx.req); if (!user) { return { redirect: { diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index 87fa3df4f..b5d6b18f8 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -49,7 +49,7 @@ import { cn } from "@/lib/utils"; import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; import type { findProjectById } from "@dokploy/server"; -import { validateRequest } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import { Ban, @@ -658,7 +658,7 @@ export async function getServerSideProps( const { params } = ctx; const { req, res } = ctx; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user) { return { redirect: { diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx index 441720b94..a394f320f 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx @@ -39,7 +39,8 @@ import { import { cn } from "@/lib/utils"; import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; -import { validateRequest } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; +// import { validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import copy from "copy-to-clipboard"; import { GlobeIcon, HelpCircle, ServerOff, Trash2 } from "lucide-react"; @@ -370,7 +371,7 @@ export async function getServerSideProps( const { query, params, req, res } = ctx; const activeTab = query.tab; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user) { return { redirect: { diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx index 41a346b4b..8bd3e8638 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx @@ -33,7 +33,7 @@ import { import { cn } from "@/lib/utils"; import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; -import { validateRequest } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import copy from "copy-to-clipboard"; import { CircuitBoard, ServerOff } from "lucide-react"; @@ -366,7 +366,7 @@ export async function getServerSideProps( const { query, params, req, res } = ctx; const activeTab = query.tab; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user) { return { redirect: { diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx index 7138be021..9adbad15c 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx @@ -35,7 +35,7 @@ import { import { cn } from "@/lib/utils"; import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; -import { validateRequest } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import { HelpCircle, ServerOff, Trash2 } from "lucide-react"; import type { @@ -316,7 +316,7 @@ export async function getServerSideProps( const { query, params, req, res } = ctx; const activeTab = query.tab; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user) { return { redirect: { diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx index c0ddd96d5..a5ba6b5de 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx @@ -35,7 +35,7 @@ import { import { cn } from "@/lib/utils"; import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; -import { validateRequest } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import { HelpCircle, ServerOff, Trash2 } from "lucide-react"; import type { @@ -318,7 +318,7 @@ export async function getServerSideProps( const { query, params, req, res } = ctx; const activeTab = query.tab; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user) { return { redirect: { diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx index d170bb76e..3e17c4fac 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx @@ -35,7 +35,7 @@ import { import { cn } from "@/lib/utils"; import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; -import { validateRequest } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import { HelpCircle, ServerOff, Trash2 } from "lucide-react"; import type { @@ -323,7 +323,7 @@ export async function getServerSideProps( const { query, params, req, res } = ctx; const activeTab = query.tab; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user) { return { redirect: { diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx index 67c6a4a5e..0b1d2aee6 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx @@ -35,7 +35,7 @@ import { import { cn } from "@/lib/utils"; import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; -import { validateRequest } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import { HelpCircle, ServerOff, Trash2 } from "lucide-react"; import type { @@ -319,7 +319,7 @@ export async function getServerSideProps( ) { const { query, params, req, res } = ctx; const activeTab = query.tab; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user) { return { redirect: { diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx index bb9ebc4ae..853e6688b 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx @@ -34,7 +34,7 @@ import { import { cn } from "@/lib/utils"; import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; -import { validateRequest } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import { HelpCircle, ServerOff } from "lucide-react"; import type { @@ -311,7 +311,7 @@ export async function getServerSideProps( const { query, params, req, res } = ctx; const activeTab = query.tab; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user) { return { redirect: { diff --git a/apps/dokploy/pages/dashboard/projects.tsx b/apps/dokploy/pages/dashboard/projects.tsx index af4d0f1ec..abeee6695 100644 --- a/apps/dokploy/pages/dashboard/projects.tsx +++ b/apps/dokploy/pages/dashboard/projects.tsx @@ -2,7 +2,7 @@ import { ShowProjects } from "@/components/dashboard/projects/show"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; -import { validateRequest } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; import dynamic from "next/dynamic"; @@ -38,7 +38,7 @@ export async function getServerSideProps( ctx: GetServerSidePropsContext<{ serviceId: string }>, ) { const { req, res } = ctx; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); const helpers = createServerSideHelpers({ router: appRouter, @@ -46,8 +46,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/requests.tsx b/apps/dokploy/pages/dashboard/requests.tsx index d1a927e34..580b936a2 100644 --- a/apps/dokploy/pages/dashboard/requests.tsx +++ b/apps/dokploy/pages/dashboard/requests.tsx @@ -1,6 +1,7 @@ import { ShowRequests } from "@/components/dashboard/requests/show-requests"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { IS_CLOUD, validateRequest } from "@dokploy/server"; +import { IS_CLOUD } from "@dokploy/server/constants"; +import { validateRequest } from "@dokploy/server/lib/auth"; import type { GetServerSidePropsContext } from "next"; import type { ReactElement } from "react"; import * as React from "react"; @@ -22,7 +23,7 @@ export async function getServerSideProps( }, }; } - const { user } = await validateRequest(ctx.req, ctx.res); + const { user } = await validateRequest(ctx.req); if (!user) { return { redirect: { diff --git a/apps/dokploy/pages/dashboard/settings/billing.tsx b/apps/dokploy/pages/dashboard/settings/billing.tsx index b1a7cb21d..3acce0b01 100644 --- a/apps/dokploy/pages/dashboard/settings/billing.tsx +++ b/apps/dokploy/pages/dashboard/settings/billing.tsx @@ -2,7 +2,8 @@ import { ShowBilling } from "@/components/dashboard/settings/billing/show-billin import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { appRouter } from "@/server/api/root"; -import { IS_CLOUD, validateRequest } from "@dokploy/server"; +import { IS_CLOUD } from "@dokploy/server/constants"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; import React, { type ReactElement } from "react"; @@ -29,7 +30,7 @@ export async function getServerSideProps( }; } const { req, res } = ctx; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user || user.role === "member") { return { redirect: { @@ -45,8 +46,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/swarm.tsx b/apps/dokploy/pages/dashboard/swarm.tsx index f57728209..8278ed181 100644 --- a/apps/dokploy/pages/dashboard/swarm.tsx +++ b/apps/dokploy/pages/dashboard/swarm.tsx @@ -1,7 +1,8 @@ import SwarmMonitorCard from "@/components/dashboard/swarm/monitoring-card"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { appRouter } from "@/server/api/root"; -import { IS_CLOUD, validateRequest } from "@dokploy/server"; +import { IS_CLOUD } from "@dokploy/server/constants"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; import type { ReactElement } from "react"; @@ -27,7 +28,7 @@ export async function getServerSideProps( }, }; } - const { user, session } = await validateRequest(ctx.req, ctx.res); + const { user, session } = await validateRequest(ctx.req); if (!user) { return { redirect: { @@ -44,21 +45,20 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); try { await helpers.project.all.prefetch(); - const auth = await helpers.auth.get.fetch(); - if (auth.role === "member") { - const user = await helpers.user.byAuthId.fetch({ - authId: auth.id, + if (user.role === "member") { + const userR = await helpers.user.get.fetch({ + userId: user.id, }); - if (!user.canAccessToDocker) { + if (!userR.canAccessToDocker) { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/traefik.tsx b/apps/dokploy/pages/dashboard/traefik.tsx index 1f710c9eb..6939eabdf 100644 --- a/apps/dokploy/pages/dashboard/traefik.tsx +++ b/apps/dokploy/pages/dashboard/traefik.tsx @@ -1,7 +1,8 @@ import { ShowTraefikSystem } from "@/components/dashboard/file-system/show-traefik-system"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { appRouter } from "@/server/api/root"; -import { IS_CLOUD, validateRequest } from "@dokploy/server"; +import { IS_CLOUD } from "@dokploy/server/constants"; +import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; import React, { type ReactElement } from "react"; @@ -27,7 +28,7 @@ export async function getServerSideProps( }, }; } - const { user, session } = await validateRequest(ctx.req, ctx.res); + const { user, session } = await validateRequest(ctx.req); if (!user) { return { redirect: { @@ -44,21 +45,20 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); try { await helpers.project.all.prefetch(); - const auth = await helpers.auth.get.fetch(); - if (auth.role === "member") { - const user = await helpers.user.byAuthId.fetch({ - authId: auth.id, + if (user.role === "member") { + const userR = await helpers.user.get.fetch({ + userId: user.id, }); - if (!user.canAccessToTraefikFiles) { + if (!userR.canAccessToTraefikFiles) { return { redirect: { permanent: true, diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index 69586eb42..a74c2bfbb 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -72,7 +72,7 @@ export const composeRouter = createTRPCRouter({ }); } const project = await findProjectById(input.projectId); - if (project.userId !== ctx.user.ownerId) { + if (project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this project", @@ -98,7 +98,7 @@ export const composeRouter = createTRPCRouter({ } const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this compose", @@ -111,7 +111,7 @@ export const composeRouter = createTRPCRouter({ .input(apiUpdateCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this compose", @@ -127,7 +127,10 @@ export const composeRouter = createTRPCRouter({ } const composeResult = await findComposeById(input.composeId); - if (composeResult.project.userId !== ctx.user.ownerId) { + if ( + composeResult.project.organizationId !== + ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this compose", @@ -158,7 +161,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to clean this compose", @@ -171,7 +174,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFetchServices) .query(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to load this compose", @@ -185,7 +188,9 @@ export const composeRouter = createTRPCRouter({ try { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if ( + compose.project.organizationId !== ctx.session.activeOrganizationId + ) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to fetch this compose", @@ -210,7 +215,7 @@ export const composeRouter = createTRPCRouter({ .input(apiRandomizeCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to randomize this compose", @@ -222,7 +227,7 @@ export const composeRouter = createTRPCRouter({ .input(apiRandomizeCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to randomize this compose", @@ -237,7 +242,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .query(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to get this compose", @@ -255,7 +260,7 @@ export const composeRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to deploy this compose", @@ -288,7 +293,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to redeploy this compose", @@ -320,7 +325,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this compose", @@ -334,7 +339,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to stop this compose", @@ -349,7 +354,7 @@ export const composeRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to get this compose", @@ -362,7 +367,7 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .mutation(async ({ input, ctx }) => { const compose = await findComposeById(input.composeId); - if (compose.project.userId !== ctx.user.ownerId) { + if (compose.project.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to refresh this compose", diff --git a/apps/dokploy/server/api/routers/notification.ts b/apps/dokploy/server/api/routers/notification.ts index 451700065..bba6c7db9 100644 --- a/apps/dokploy/server/api/routers/notification.ts +++ b/apps/dokploy/server/api/routers/notification.ts @@ -57,7 +57,10 @@ export const notificationRouter = createTRPCRouter({ .input(apiCreateSlack) .mutation(async ({ input, ctx }) => { try { - return await createSlackNotification(input, ctx.user.ownerId); + return await createSlackNotification( + input, + ctx.session.activeOrganizationId, + ); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -80,7 +83,7 @@ export const notificationRouter = createTRPCRouter({ } return await updateSlackNotification({ ...input, - userId: ctx.user.ownerId, + organizationId: ctx.session.activeOrganizationId, }); } catch (error) { throw error; @@ -131,7 +134,7 @@ export const notificationRouter = createTRPCRouter({ } return await updateTelegramNotification({ ...input, - userId: ctx.user.ownerId, + organizationId: ctx.session.activeOrganizationId, }); } catch (error) { throw new TRPCError({ @@ -183,7 +186,7 @@ export const notificationRouter = createTRPCRouter({ } return await updateDiscordNotification({ ...input, - userId: ctx.user.ownerId, + organizationId: ctx.session.activeOrganizationId, }); } catch (error) { throw new TRPCError({ @@ -243,7 +246,7 @@ export const notificationRouter = createTRPCRouter({ } return await updateEmailNotification({ ...input, - userId: ctx.user.ownerId, + organizationId: ctx.session.activeOrganizationId, }); } catch (error) { throw new TRPCError({ @@ -314,13 +317,7 @@ export const notificationRouter = createTRPCRouter({ gotify: true, }, orderBy: desc(notifications.createdAt), - ...(IS_CLOUD && { - where: eq( - notifications.organizationId, - ctx.session.activeOrganizationId, - ), - }), - // TODO: Remove this line when the cloud version is ready + where: eq(notifications.organizationId, ctx.session.activeOrganizationId), }); }), receiveNotification: publicProcedure @@ -337,7 +334,7 @@ export const notificationRouter = createTRPCRouter({ ) .mutation(async ({ input }) => { try { - let userId = ""; + let organizationId = ""; let ServerName = ""; if (input.ServerType === "Dokploy") { const result = await db @@ -354,7 +351,7 @@ export const notificationRouter = createTRPCRouter({ }); } - userId = result?.[0]?.id; + organizationId = result?.[0]?.id; ServerName = "Dokploy"; } else { const result = await db @@ -364,18 +361,18 @@ export const notificationRouter = createTRPCRouter({ sql`${server.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`, ); - if (!result?.[0]?.userId) { + if (!result?.[0]?.organizationId) { throw new TRPCError({ code: "BAD_REQUEST", message: "Token not found", }); } - userId = result?.[0]?.userId; + organizationId = result?.[0]?.organizationId; ServerName = "Remote"; } - await sendServerThresholdNotifications(userId, { + await sendServerThresholdNotifications(organizationId, { ...input, ServerName, }); @@ -416,7 +413,7 @@ export const notificationRouter = createTRPCRouter({ } return await updateGotifyNotification({ ...input, - userId: ctx.user.ownerId, + organizationId: ctx.session.activeOrganizationId, }); } catch (error) { throw error; diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index 88bb21d76..b5beadf4d 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -49,7 +49,10 @@ export const projectRouter = createTRPCRouter({ }); } - const project = await createProject(input, ctx.user.ownerId); + const project = await createProject( + input, + ctx.session.activeOrganizationId, + ); if (ctx.user.rol === "member") { await addNewProject(ctx.user.id, project.projectId); } diff --git a/apps/dokploy/server/api/routers/ssh-key.ts b/apps/dokploy/server/api/routers/ssh-key.ts index 90f7cd6e4..d55a23794 100644 --- a/apps/dokploy/server/api/routers/ssh-key.ts +++ b/apps/dokploy/server/api/routers/ssh-key.ts @@ -41,10 +41,7 @@ export const sshRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const sshKey = await findSSHKeyById(input.sshKeyId); - if ( - IS_CLOUD && - sshKey.organizationId !== ctx.session.activeOrganizationId - ) { + if (sshKey.organizationId !== ctx.session.activeOrganizationId) { // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", @@ -62,11 +59,7 @@ export const sshRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const sshKey = await findSSHKeyById(input.sshKeyId); - if ( - IS_CLOUD && - sshKey.organizationId !== ctx.session.activeOrganizationId - ) { - // TODO: Remove isCloud in the next versions of dokploy + if (sshKey.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this SSH key", @@ -76,12 +69,9 @@ export const sshRouter = createTRPCRouter({ }), all: protectedProcedure.query(async ({ ctx }) => { return await db.query.sshKeys.findMany({ - ...(IS_CLOUD && { - where: eq(sshKeys.organizationId, ctx.session.activeOrganizationId), - }), + where: eq(sshKeys.organizationId, ctx.session.activeOrganizationId), orderBy: desc(sshKeys.createdAt), }); - // TODO: Remove this line when the cloud version is ready }), generate: protectedProcedure .input(apiGenerateSSHKey) @@ -93,11 +83,7 @@ export const sshRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { const sshKey = await findSSHKeyById(input.sshKeyId); - if ( - IS_CLOUD && - sshKey.organizationId !== ctx.session.activeOrganizationId - ) { - // TODO: Remove isCloud in the next versions of dokploy + if (sshKey.organizationId !== ctx.session.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to update this SSH key", diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index ccf9e5bc1..269da8f5a 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -5,6 +5,7 @@ import { member } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; +import { z } from "zod"; export const userRouter = createTRPCRouter({ all: adminProcedure.query(async ({ ctx }) => { return await db.query.member.findMany({ @@ -14,16 +15,20 @@ export const userRouter = createTRPCRouter({ }, }); }), - byAuthId: protectedProcedure - .input(apiFindOneUserByAuth) + get: protectedProcedure + .input( + z.object({ + userId: z.string(), + }), + ) .query(async ({ input, ctx }) => { - const user = await findUserByAuthId(input.authId); - if (user.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to access this user", - }); - } + const user = await findUserById(input.userId); + // if (user.adminId !== ctx.user.adminId) { + // throw new TRPCError({ + // code: "UNAUTHORIZED", + // message: "You are not allowed to access this user", + // }); + // } return user; }), byUserId: protectedProcedure diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 4e2917ca9..0179f3c7c 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -270,7 +270,7 @@ export const apiCreateGotify = notificationsSchema export const apiUpdateGotify = apiCreateGotify.partial().extend({ notificationId: z.string().min(1), gotifyId: z.string().min(1), - userId: z.string().optional(), + organizationId: z.string().optional(), }); export const apiTestGotifyConnection = apiCreateGotify diff --git a/packages/server/src/utils/notifications/server-threshold.ts b/packages/server/src/utils/notifications/server-threshold.ts index c606f0ef3..2e63ba25a 100644 --- a/packages/server/src/utils/notifications/server-threshold.ts +++ b/packages/server/src/utils/notifications/server-threshold.ts @@ -18,7 +18,7 @@ interface ServerThresholdPayload { } export const sendServerThresholdNotifications = async ( - userId: string, + organizationId: string, payload: ServerThresholdPayload, ) => { const date = new Date(payload.Timestamp); @@ -27,7 +27,7 @@ export const sendServerThresholdNotifications = async ( const notificationList = await db.query.notifications.findMany({ where: and( eq(notifications.serverThreshold, true), - eq(notifications.userId, userId), + eq(notifications.organizationId, organizationId), ), with: { email: true, From e7db0ccb70fb3acb985998cff340c910527ea9c6 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 16 Feb 2025 02:57:49 -0600 Subject: [PATCH 34/89] refactor: update invitation --- .../components/dashboard/search-command.tsx | 2 +- .../git/github/add-github-provider.tsx | 8 +- .../dashboard/settings/users/add-user.tsx | 28 ++-- apps/dokploy/lib/auth.ts | 2 +- .../accept-invitation/[accept-invitation].tsx | 30 ++++ .../pages/api/providers/github/setup.ts | 17 +- apps/dokploy/server/api/routers/bitbucket.ts | 36 ++--- apps/dokploy/server/api/routers/github.ts | 24 +-- apps/dokploy/server/api/routers/gitlab.ts | 19 +-- apps/dokploy/server/api/routers/project.ts | 2 +- apps/dokploy/server/api/routers/user.ts | 2 +- apps/dokploy/server/server.ts | 16 +- .../server/wss/docker-container-logs.ts | 4 +- .../server/wss/docker-container-terminal.ts | 4 +- apps/dokploy/server/wss/docker-stats.ts | 4 +- apps/dokploy/server/wss/drawer-logs.ts | 7 + apps/dokploy/server/wss/listen-deployment.ts | 4 +- apps/dokploy/server/wss/terminal.ts | 8 +- packages/server/src/auth/auth.ts | 78 ---------- packages/server/src/auth/token.ts | 146 +++++++++--------- packages/server/src/lib/auth.ts | 17 +- packages/server/src/services/application.ts | 56 +++---- packages/server/src/services/compose.ts | 40 ++--- .../server/src/services/preview-deployment.ts | 6 +- packages/server/src/services/settings.ts | 2 - packages/server/src/services/user.ts | 22 +-- .../src/utils/notifications/build-error.ts | 6 +- .../src/utils/notifications/build-success.ts | 6 +- .../src/utils/notifications/docker-cleanup.ts | 4 +- 29 files changed, 270 insertions(+), 330 deletions(-) create mode 100644 apps/dokploy/pages/accept-invitation/[accept-invitation].tsx diff --git a/apps/dokploy/components/dashboard/search-command.tsx b/apps/dokploy/components/dashboard/search-command.tsx index 952bbe5c8..8158a9ca8 100644 --- a/apps/dokploy/components/dashboard/search-command.tsx +++ b/apps/dokploy/components/dashboard/search-command.tsx @@ -36,7 +36,7 @@ export const SearchCommand = () => { const router = useRouter(); const [open, setOpen] = React.useState(false); const [search, setSearch] = React.useState(""); - const { data: session } = authClient.getSession(); + const { data: session } = authClient.useSession(); const { data } = api.project.all.useQuery(undefined, { enabled: !!session, }); diff --git a/apps/dokploy/components/dashboard/settings/git/github/add-github-provider.tsx b/apps/dokploy/components/dashboard/settings/git/github/add-github-provider.tsx index 0e3e56336..5f2cb934d 100644 --- a/apps/dokploy/components/dashboard/settings/git/github/add-github-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/github/add-github-provider.tsx @@ -10,12 +10,14 @@ import { } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; +import { authClient } from "@/lib/auth"; import { api } from "@/utils/api"; import { format } from "date-fns"; import { useEffect, useState } from "react"; export const AddGithubProvider = () => { const [isOpen, setIsOpen] = useState(false); + const { data: activeOrganization } = authClient.useActiveOrganization(); const { data } = api.auth.get.useQuery(); const [manifest, setManifest] = useState(""); const [isOrganization, setIsOrganization] = useState(false); @@ -25,7 +27,7 @@ export const AddGithubProvider = () => { const url = document.location.origin; const manifest = JSON.stringify( { - redirect_url: `${origin}/api/providers/github/setup?authId=${data?.id}`, + redirect_url: `${origin}/api/providers/github/setup?organizationId=${activeOrganization?.id}`, name: `Dokploy-${format(new Date(), "yyyy-MM-dd")}`, url: origin, hook_attributes: { @@ -93,8 +95,8 @@ export const AddGithubProvider = () => {
diff --git a/apps/dokploy/components/dashboard/settings/users/add-user.tsx b/apps/dokploy/components/dashboard/settings/users/add-user.tsx index 8fb6de27c..175f723f5 100644 --- a/apps/dokploy/components/dashboard/settings/users/add-user.tsx +++ b/apps/dokploy/components/dashboard/settings/users/add-user.tsx @@ -19,6 +19,7 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; +import { authClient } from "@/lib/auth"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { PlusIcon } from "lucide-react"; @@ -40,6 +41,7 @@ export const AddUser = () => { const [open, setOpen] = useState(false); const utils = api.useUtils(); + const { data: activeOrganization } = authClient.useActiveOrganization(); const { mutateAsync, isError, error, isLoading } = api.admin.createUserInvitation.useMutation(); @@ -54,17 +56,23 @@ export const AddUser = () => { }, [form, form.formState.isSubmitSuccessful, form.reset]); const onSubmit = async (data: AddUser) => { - await mutateAsync({ + const result = await authClient.organization.inviteMember({ email: data.email.toLowerCase(), - }) - .then(async () => { - toast.success("Invitation created"); - await utils.user.all.invalidate(); - setOpen(false); - }) - .catch(() => { - toast.error("Error creating the invitation"); - }); + role: "user", + organizationId: activeOrganization?.id, + }); + console.log(result); + // await mutateAsync({ + // email: data.email.toLowerCase(), + // }) + // .then(async () => { + // toast.success("Invitation created"); + // await utils.user.all.invalidate(); + // setOpen(false); + // }) + // .catch(() => { + // toast.error("Error creating the invitation"); + // }); }; return ( diff --git a/apps/dokploy/lib/auth.ts b/apps/dokploy/lib/auth.ts index a5b193700..12c3cc3e7 100644 --- a/apps/dokploy/lib/auth.ts +++ b/apps/dokploy/lib/auth.ts @@ -2,6 +2,6 @@ import { organizationClient } from "better-auth/client/plugins"; import { createAuthClient } from "better-auth/react"; export const authClient = createAuthClient({ - baseURL: "http://localhost:3000", // the base url of your auth server + // baseURL: "http://localhost:3000", // the base url of your auth server plugins: [organizationClient()], }); diff --git a/apps/dokploy/pages/accept-invitation/[accept-invitation].tsx b/apps/dokploy/pages/accept-invitation/[accept-invitation].tsx new file mode 100644 index 000000000..6936a802d --- /dev/null +++ b/apps/dokploy/pages/accept-invitation/[accept-invitation].tsx @@ -0,0 +1,30 @@ +import { Button } from "@/components/ui/button"; +import { authClient } from "@/lib/auth"; +import { useRouter } from "next/router"; + +export const AcceptInvitation = () => { + const { query } = useRouter(); + + const invitationId = query["accept-invitation"]; + + // const { data: organization } = api.organization.getById.useQuery({ + // id: id as string + // }) + + return ( +
+ +
+ ); +}; + +export default AcceptInvitation; diff --git a/apps/dokploy/pages/api/providers/github/setup.ts b/apps/dokploy/pages/api/providers/github/setup.ts index bd123c687..9a03ed3d7 100644 --- a/apps/dokploy/pages/api/providers/github/setup.ts +++ b/apps/dokploy/pages/api/providers/github/setup.ts @@ -1,10 +1,12 @@ import { db } from "@/server/db"; import { github } from "@/server/db/schema"; import { + auth, createGithub, findAdminByAuthId, findAuthById, findUserByAuthId, + findUserById, } from "@dokploy/server"; import { eq } from "drizzle-orm"; import type { NextApiRequest, NextApiResponse } from "next"; @@ -28,7 +30,7 @@ export default async function handler( return res.status(400).json({ error: "Missing code parameter" }); } const [action, value] = state?.split(":"); - // Value could be the authId or the githubProviderId + // Value could be the organizationId or the githubProviderId if (action === "gh_init") { const octokit = new Octokit({}); @@ -39,17 +41,6 @@ export default async function handler( }, ); - const auth = await findAuthById(value as string); - - let adminId = ""; - if (auth.role === "owner") { - const admin = await findAdminByAuthId(auth.id); - adminId = admin.adminId; - } else { - const user = await findUserByAuthId(auth.id); - adminId = user.adminId; - } - await createGithub( { name: data.name, @@ -60,7 +51,7 @@ export default async function handler( githubWebhookSecret: data.webhook_secret, githubPrivateKey: data.pem, }, - adminId, + value as string, ); } else if (action === "gh_setup") { await db diff --git a/apps/dokploy/server/api/routers/bitbucket.ts b/apps/dokploy/server/api/routers/bitbucket.ts index 987555e5f..7a8462641 100644 --- a/apps/dokploy/server/api/routers/bitbucket.ts +++ b/apps/dokploy/server/api/routers/bitbucket.ts @@ -8,7 +8,6 @@ import { apiUpdateBitbucket, } from "@/server/db/schema"; import { - IS_CLOUD, createBitbucket, findBitbucketById, getBitbucketBranches, @@ -37,11 +36,9 @@ export const bitbucketRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( - IS_CLOUD && bitbucketProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId + ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this bitbucket provider", @@ -59,14 +56,11 @@ export const bitbucketRouter = createTRPCRouter({ }, }); - if (IS_CLOUD) { - // TODO: mAyBe a rEfaCtoR 🤫 - result = result.filter( - (provider) => - provider.gitProvider.organizationId === - ctx.session.activeOrganizationId, - ); - } + result = result.filter( + (provider) => + provider.gitProvider.organizationId === + ctx.session.activeOrganizationId, + ); return result; }), @@ -75,11 +69,9 @@ export const bitbucketRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( - IS_CLOUD && bitbucketProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId + ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this bitbucket provider", @@ -94,11 +86,9 @@ export const bitbucketRouter = createTRPCRouter({ input.bitbucketId || "", ); if ( - IS_CLOUD && bitbucketProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId + ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this bitbucket provider", @@ -112,11 +102,9 @@ export const bitbucketRouter = createTRPCRouter({ try { const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( - IS_CLOUD && bitbucketProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId + ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this bitbucket provider", @@ -137,11 +125,9 @@ export const bitbucketRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const bitbucketProvider = await findBitbucketById(input.bitbucketId); if ( - IS_CLOUD && bitbucketProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId + ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this bitbucket provider", @@ -149,7 +135,7 @@ export const bitbucketRouter = createTRPCRouter({ } return await updateBitbucket(input.bitbucketId, { ...input, - userId: ctx.user.ownerId, + organizationId: ctx.session.activeOrganizationId, }); }), }); diff --git a/apps/dokploy/server/api/routers/github.ts b/apps/dokploy/server/api/routers/github.ts index 2b3f15029..691030e27 100644 --- a/apps/dokploy/server/api/routers/github.ts +++ b/apps/dokploy/server/api/routers/github.ts @@ -6,7 +6,6 @@ import { apiUpdateGithub, } from "@/server/db/schema"; import { - IS_CLOUD, findGithubById, getGithubBranches, getGithubRepositories, @@ -24,7 +23,6 @@ export const githubRouter = createTRPCRouter({ githubProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this github provider", @@ -40,7 +38,6 @@ export const githubRouter = createTRPCRouter({ githubProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this github provider", @@ -71,14 +68,11 @@ export const githubRouter = createTRPCRouter({ }, }); - if (IS_CLOUD) { - // TODO: mAyBe a rEfaCtoR 🤫 - result = result.filter( - (provider) => - provider.gitProvider.organizationId === - ctx.session.activeOrganizationId, - ); - } + result = result.filter( + (provider) => + provider.gitProvider.organizationId === + ctx.session.activeOrganizationId, + ); const filtered = result .filter((provider) => haveGithubRequirements(provider)) @@ -100,11 +94,9 @@ export const githubRouter = createTRPCRouter({ try { const githubProvider = await findGithubById(input.githubId); if ( - IS_CLOUD && githubProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId + ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this github provider", @@ -124,11 +116,9 @@ export const githubRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { const githubProvider = await findGithubById(input.githubId); if ( - IS_CLOUD && githubProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId + ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this github provider", diff --git a/apps/dokploy/server/api/routers/gitlab.ts b/apps/dokploy/server/api/routers/gitlab.ts index 338b8c64d..b702bc2a4 100644 --- a/apps/dokploy/server/api/routers/gitlab.ts +++ b/apps/dokploy/server/api/routers/gitlab.ts @@ -9,7 +9,6 @@ import { import { db } from "@/server/db"; import { - IS_CLOUD, createGitlab, findGitlabById, getGitlabBranches, @@ -43,7 +42,6 @@ export const gitlabRouter = createTRPCRouter({ gitlabProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this Gitlab provider", @@ -58,14 +56,11 @@ export const gitlabRouter = createTRPCRouter({ }, }); - if (IS_CLOUD) { - // TODO: mAyBe a rEfaCtoR 🤫 - result = result.filter( - (provider) => - provider.gitProvider.organizationId === - ctx.session.activeOrganizationId, - ); - } + result = result.filter( + (provider) => + provider.gitProvider.organizationId === + ctx.session.activeOrganizationId, + ); const filtered = result .filter((provider) => haveGitlabRequirements(provider)) .map((provider) => { @@ -87,7 +82,6 @@ export const gitlabRouter = createTRPCRouter({ gitlabProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this Gitlab provider", @@ -104,7 +98,6 @@ export const gitlabRouter = createTRPCRouter({ gitlabProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this Gitlab provider", @@ -121,7 +114,6 @@ export const gitlabRouter = createTRPCRouter({ gitlabProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this Gitlab provider", @@ -145,7 +137,6 @@ export const gitlabRouter = createTRPCRouter({ gitlabProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId ) { - //TODO: Remove this line when the cloud version is ready throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to access this Gitlab provider", diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index b5beadf4d..5fc79f437 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -71,7 +71,7 @@ export const projectRouter = createTRPCRouter({ .input(apiFindOneProject) .query(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - const { accessedServices } = await findUserByAuthId(ctx.user.id); + const { accessedServices } = await findUserById(ctx.user.id); await checkProjectAccess(ctx.user.id, "access", input.projectId); diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 269da8f5a..00c2bb82e 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -4,8 +4,8 @@ import { db } from "@dokploy/server/db"; import { member } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; -import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; import { z } from "zod"; +import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; export const userRouter = createTRPCRouter({ all: adminProcedure.query(async ({ ctx }) => { return await db.query.member.findMany({ diff --git a/apps/dokploy/server/server.ts b/apps/dokploy/server/server.ts index a277dc0ac..c8f53f6f9 100644 --- a/apps/dokploy/server/server.ts +++ b/apps/dokploy/server/server.ts @@ -34,14 +34,14 @@ void app.prepare().then(async () => { }); // WEBSOCKET - // setupDrawerLogsWebSocketServer(server); - // setupDeploymentLogsWebSocketServer(server); - // setupDockerContainerLogsWebSocketServer(server); - // setupDockerContainerTerminalWebSocketServer(server); - // setupTerminalWebSocketServer(server); - // if (!IS_CLOUD) { - // setupDockerStatsMonitoringSocketServer(server); - // } + setupDrawerLogsWebSocketServer(server); + setupDeploymentLogsWebSocketServer(server); + setupDockerContainerLogsWebSocketServer(server); + setupDockerContainerTerminalWebSocketServer(server); + setupTerminalWebSocketServer(server); + if (!IS_CLOUD) { + setupDockerStatsMonitoringSocketServer(server); + } if (process.env.NODE_ENV === "production" && !IS_CLOUD) { setupDirectories(); diff --git a/apps/dokploy/server/wss/docker-container-logs.ts b/apps/dokploy/server/wss/docker-container-logs.ts index 092f39735..8d08ebd46 100644 --- a/apps/dokploy/server/wss/docker-container-logs.ts +++ b/apps/dokploy/server/wss/docker-container-logs.ts @@ -1,5 +1,5 @@ import type http from "node:http"; -import { findServerById, validateWebSocketRequest } from "@dokploy/server"; +import { findServerById, validateRequest } from "@dokploy/server"; import { spawn } from "node-pty"; import { Client } from "ssh2"; import { WebSocketServer } from "ws"; @@ -35,7 +35,7 @@ export const setupDockerContainerLogsWebSocketServer = ( const since = url.searchParams.get("since"); const serverId = url.searchParams.get("serverId"); const runType = url.searchParams.get("runType"); - const { user, session } = await validateWebSocketRequest(req); + const { user, session } = await validateRequest(req); if (!containerId) { ws.close(4000, "containerId no provided"); diff --git a/apps/dokploy/server/wss/docker-container-terminal.ts b/apps/dokploy/server/wss/docker-container-terminal.ts index 8981ccbc2..04ef5c96c 100644 --- a/apps/dokploy/server/wss/docker-container-terminal.ts +++ b/apps/dokploy/server/wss/docker-container-terminal.ts @@ -1,5 +1,5 @@ import type http from "node:http"; -import { findServerById, validateWebSocketRequest } from "@dokploy/server"; +import { findServerById, validateRequest } from "@dokploy/server"; import { spawn } from "node-pty"; import { Client } from "ssh2"; import { WebSocketServer } from "ws"; @@ -32,7 +32,7 @@ export const setupDockerContainerTerminalWebSocketServer = ( const containerId = url.searchParams.get("containerId"); const activeWay = url.searchParams.get("activeWay"); const serverId = url.searchParams.get("serverId"); - const { user, session } = await validateWebSocketRequest(req); + const { user, session } = await validateRequest(req); if (!containerId) { ws.close(4000, "containerId no provided"); diff --git a/apps/dokploy/server/wss/docker-stats.ts b/apps/dokploy/server/wss/docker-stats.ts index b1e4585c1..99e993dce 100644 --- a/apps/dokploy/server/wss/docker-stats.ts +++ b/apps/dokploy/server/wss/docker-stats.ts @@ -4,7 +4,7 @@ import { execAsync, getLastAdvancedStatsFile, recordAdvancedStats, - validateWebSocketRequest, + validateRequest, } from "@dokploy/server"; import { WebSocketServer } from "ws"; @@ -36,7 +36,7 @@ export const setupDockerStatsMonitoringSocketServer = ( | "application" | "stack" | "docker-compose"; - const { user, session } = await validateWebSocketRequest(req); + const { user, session } = await validateRequest(req); if (!appName) { ws.close(4000, "appName no provided"); diff --git a/apps/dokploy/server/wss/drawer-logs.ts b/apps/dokploy/server/wss/drawer-logs.ts index c1dec315b..da2c529ac 100644 --- a/apps/dokploy/server/wss/drawer-logs.ts +++ b/apps/dokploy/server/wss/drawer-logs.ts @@ -3,6 +3,7 @@ import { applyWSSHandler } from "@trpc/server/adapters/ws"; import { WebSocketServer } from "ws"; import { appRouter } from "../api/root"; import { createTRPCContext } from "../api/trpc"; +import { validateRequest } from "@dokploy/server/index"; export const setupDrawerLogsWebSocketServer = ( server: http.Server, @@ -32,5 +33,11 @@ export const setupDrawerLogsWebSocketServer = ( wssTerm.on("connection", async (ws, req) => { const url = new URL(req.url || "", `http://${req.headers.host}`); + const { user, session } = await validateRequest(req); + + if (!user || !session) { + ws.close(); + return; + } }); }; diff --git a/apps/dokploy/server/wss/listen-deployment.ts b/apps/dokploy/server/wss/listen-deployment.ts index df77ceb41..ee470fcbf 100644 --- a/apps/dokploy/server/wss/listen-deployment.ts +++ b/apps/dokploy/server/wss/listen-deployment.ts @@ -1,6 +1,6 @@ import { spawn } from "node:child_process"; import type http from "node:http"; -import { findServerById, validateWebSocketRequest } from "@dokploy/server"; +import { findServerById, validateRequest } from "@dokploy/server"; import { Client } from "ssh2"; import { WebSocketServer } from "ws"; @@ -29,7 +29,7 @@ export const setupDeploymentLogsWebSocketServer = ( const url = new URL(req.url || "", `http://${req.headers.host}`); const logPath = url.searchParams.get("logPath"); const serverId = url.searchParams.get("serverId"); - const { user, session } = await validateWebSocketRequest(req); + const { user, session } = await validateRequest(req); if (!logPath) { console.log("logPath no provided"); diff --git a/apps/dokploy/server/wss/terminal.ts b/apps/dokploy/server/wss/terminal.ts index 5fa1accc2..6e9c3614f 100644 --- a/apps/dokploy/server/wss/terminal.ts +++ b/apps/dokploy/server/wss/terminal.ts @@ -1,9 +1,5 @@ import type http from "node:http"; -import { - IS_CLOUD, - findServerById, - validateWebSocketRequest, -} from "@dokploy/server"; +import { IS_CLOUD, findServerById, validateRequest } from "@dokploy/server"; import { publicIpv4, publicIpv6 } from "public-ip"; import { Client, type ConnectConfig } from "ssh2"; import { WebSocketServer } from "ws"; @@ -71,7 +67,7 @@ export const setupTerminalWebSocketServer = ( wssTerm.on("connection", async (ws, req) => { const url = new URL(req.url || "", `http://${req.headers.host}`); const serverId = url.searchParams.get("serverId"); - const { user, session } = await validateWebSocketRequest(req); + const { user, session } = await validateRequest(req); if (!user || !session || !serverId) { ws.close(); return; diff --git a/packages/server/src/auth/auth.ts b/packages/server/src/auth/auth.ts index ab18955f2..28052f5f6 100644 --- a/packages/server/src/auth/auth.ts +++ b/packages/server/src/auth/auth.ts @@ -1,6 +1,3 @@ -import type { IncomingMessage, ServerResponse } from "node:http"; -import { findAdminByAuthId } from "@dokploy/server/services/admin"; -import { findUserByAuthId } from "@dokploy/server/services/user"; import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle"; import { TimeSpan } from "lucia"; import { Lucia } from "lucia/dist/core.js"; @@ -42,78 +39,3 @@ export type ReturnValidateToken = Promise<{ user: (User & { authId: string; adminId: string }) | null; session: Session | null; }>; - -export async function validateRequest( - req: IncomingMessage, - res: ServerResponse, -): ReturnValidateToken { - console.log(session); - const sessionId = lucia.readSessionCookie(req.headers.cookie ?? ""); - - if (!sessionId) { - return { - user: null, - session: null, - }; - } - const result = await lucia.validateSession(sessionId); - if (result?.session?.fresh) { - res.appendHeader( - "Set-Cookie", - lucia.createSessionCookie(result.session.id).serialize(), - ); - } - if (!result.session) { - res.appendHeader( - "Set-Cookie", - lucia.createBlankSessionCookie().serialize(), - ); - } - if (result.user) { - try { - if (result.user?.rol === "owner") { - const admin = await findAdminByAuthId(result.user.id); - result.user.adminId = admin.adminId; - } else if (result.user?.rol === "member") { - const userResult = await findUserByAuthId(result.user.id); - result.user.adminId = userResult.adminId; - } - } catch (error) { - return { - user: null, - session: null, - }; - } - } - - return { - session: result.session, - ...((result.user && { - user: { - authId: result.user.id, - email: result.user.email, - rol: result.user.rol, - id: result.user.id, - secret: result.user.secret, - adminId: result.user.adminId, - }, - }) || { - user: null, - }), - }; -} - -export async function validateWebSocketRequest( - req: IncomingMessage, -): Promise<{ user: User; session: Session } | { user: null; session: null }> { - const sessionId = lucia.readSessionCookie(req.headers.cookie ?? ""); - - if (!sessionId) { - return { - user: null, - session: null, - }; - } - const result = await lucia.validateSession(sessionId); - return result; -} diff --git a/packages/server/src/auth/token.ts b/packages/server/src/auth/token.ts index 9dcf99736..e3f404b05 100644 --- a/packages/server/src/auth/token.ts +++ b/packages/server/src/auth/token.ts @@ -21,79 +21,79 @@ export const luciaToken = new Lucia(adapter, { }, }); -export const validateBearerToken = async ( - req: IncomingMessage, -): ReturnValidateToken => { - const authorizationHeader = req.headers.authorization; - const sessionId = luciaToken.readBearerToken(authorizationHeader ?? ""); - if (!sessionId) { - return { - user: null, - session: null, - }; - } - const result = await luciaToken.validateSession(sessionId); +// export const validateBearerToken = async ( +// req: IncomingMessage, +// ): ReturnValidateToken => { +// const authorizationHeader = req.headers.authorization; +// const sessionId = luciaToken.readBearerToken(authorizationHeader ?? ""); +// if (!sessionId) { +// return { +// user: null, +// session: null, +// }; +// } +// const result = await luciaToken.validateSession(sessionId); - if (result.user) { - if (result.user?.rol === "owner") { - const admin = await findAdminByAuthId(result.user.id); - result.user.adminId = admin.adminId; - } else if (result.user?.rol === "member") { - const userResult = await findUserByAuthId(result.user.id); - result.user.adminId = userResult.adminId; - } - } - return { - session: result.session, - ...((result.user && { - user: { - adminId: result.user.adminId, - authId: result.user.id, - email: result.user.email, - rol: result.user.rol, - id: result.user.id, - secret: result.user.secret, - }, - }) || { - user: null, - }), - }; -}; +// if (result.user) { +// if (result.user?.rol === "owner") { +// const admin = await findAdminByAuthId(result.user.id); +// result.user.adminId = admin.adminId; +// } else if (result.user?.rol === "member") { +// const userResult = await findUserByAuthId(result.user.id); +// result.user.adminId = userResult.adminId; +// } +// } +// return { +// session: result.session, +// ...((result.user && { +// user: { +// adminId: result.user.adminId, +// authId: result.user.id, +// email: result.user.email, +// rol: result.user.rol, +// id: result.user.id, +// secret: result.user.secret, +// }, +// }) || { +// user: null, +// }), +// }; +// }; -export const validateBearerTokenAPI = async ( - authorizationHeader: string, -): ReturnValidateToken => { - const sessionId = luciaToken.readBearerToken(authorizationHeader ?? ""); - if (!sessionId) { - return { - user: null, - session: null, - }; - } - const result = await luciaToken.validateSession(sessionId); +// export const validateBearerTokenAPI = async ( +// authorizationHeader: string, +// ): ReturnValidateToken => { +// const sessionId = luciaToken.readBearerToken(authorizationHeader ?? ""); +// if (!sessionId) { +// return { +// user: null, +// session: null, +// }; +// } +// const result = await luciaToken.validateSession(sessionId); - if (result.user) { - if (result.user?.rol === "owner") { - const admin = await findAdminByAuthId(result.user.id); - result.user.adminId = admin.adminId; - } else if (result.user?.rol === "member") { - const userResult = await findUserByAuthId(result.user.id); - result.user.adminId = userResult.adminId; - } - } - return { - session: result.session, - ...((result.user && { - user: { - adminId: result.user.adminId, - authId: result.user.id, - email: result.user.email, - rol: result.user.rol, - id: result.user.id, - secret: result.user.secret, - }, - }) || { - user: null, - }), - }; -}; +// if (result.user) { +// if (result.user?.rol === "owner") { +// const admin = await findAdminByAuthId(result.user.id); +// result.user.adminId = admin.adminId; +// } else if (result.user?.rol === "member") { +// const userResult = await findUserByAuthId(result.user.id); +// result.user.adminId = userResult.adminId; +// } +// } +// return { +// session: result.session, +// ...((result.user && { +// user: { +// adminId: result.user.adminId, +// authId: result.user.id, +// email: result.user.email, +// rol: result.user.rol, +// id: result.user.id, +// secret: result.user.secret, +// }, +// }) || { +// user: null, +// }), +// }; +// }; diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 3b29e0240..a7fbde9a5 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -84,7 +84,22 @@ export const auth = betterAuth({ }, }, - plugins: [organization()], + plugins: [ + organization({ + async sendInvitationEmail(data, request) { + const inviteLink = `https://example.com/accept-invitation/${data.id}`; + // https://example.com/accept-invitation/8jlBi9Tb9isDb8mc8Sb85u1BaJYklKB2 + // sendOrganizationInvitation({ + // email: data.email, + // invitedByUsername: data.inviter.user.name, + // invitedByEmail: data.inviter.user.email, + // teamName: data.organization.name, + // inviteLink + // }) + console.log("Invitation link", inviteLink); + }, + }), + ], }); export const validateRequest = async (request: IncomingMessage) => { diff --git a/packages/server/src/services/application.ts b/packages/server/src/services/application.ts index b60665304..ddc3a4504 100644 --- a/packages/server/src/services/application.ts +++ b/packages/server/src/services/application.ts @@ -185,11 +185,11 @@ export const deployApplication = async ({ }); try { - const admin = await findUserById(application.project.userId); + // const admin = await findUserById(application.project.userId); - if (admin.cleanupCacheApplications) { - await cleanupFullDocker(application?.serverId); - } + // if (admin.cleanupCacheApplications) { + // await cleanupFullDocker(application?.serverId); + // } if (application.sourceType === "github") { await cloneGithubRepository({ @@ -220,7 +220,7 @@ export const deployApplication = async ({ applicationName: application.name, applicationType: "application", buildLink, - userId: application.project.userId, + organizationId: application.project.organizationId, domains: application.domains, }); } catch (error) { @@ -233,7 +233,7 @@ export const deployApplication = async ({ // @ts-ignore errorMessage: error?.message || "Error building", buildLink, - userId: application.project.userId, + organizationId: application.project.organizationId, }); throw error; @@ -260,11 +260,11 @@ export const rebuildApplication = async ({ }); try { - const admin = await findUserById(application.project.userId); + // const admin = await findUserById(application.project.userId); - if (admin.cleanupCacheApplications) { - await cleanupFullDocker(application?.serverId); - } + // if (admin.cleanupCacheApplications) { + // await cleanupFullDocker(application?.serverId); + // } if (application.sourceType === "github") { await buildApplication(application, deployment.logPath); } else if (application.sourceType === "gitlab") { @@ -309,11 +309,11 @@ export const deployRemoteApplication = async ({ try { if (application.serverId) { - const admin = await findUserById(application.project.userId); + // const admin = await findUserById(application.project.userId); - if (admin.cleanupCacheApplications) { - await cleanupFullDocker(application?.serverId); - } + // if (admin.cleanupCacheApplications) { + // await cleanupFullDocker(application?.serverId); + // } let command = "set -e;"; if (application.sourceType === "github") { command += await getGithubCloneCommand({ @@ -352,7 +352,7 @@ export const deployRemoteApplication = async ({ applicationName: application.name, applicationType: "application", buildLink, - userId: application.project.userId, + organizationId: application.project.organizationId, domains: application.domains, }); } catch (error) { @@ -376,7 +376,7 @@ export const deployRemoteApplication = async ({ // @ts-ignore errorMessage: error?.message || "Error building", buildLink, - userId: application.project.userId, + organizationId: application.project.organizationId, }); throw error; @@ -454,11 +454,11 @@ export const deployPreviewApplication = async ({ application.env = `${application.previewEnv}\nDOKPLOY_DEPLOY_URL=${previewDeployment?.domain}`; application.buildArgs = application.previewBuildArgs; - const admin = await findUserById(application.project.userId); + // const admin = await findUserById(application.project.userId); - if (admin.cleanupCacheOnPreviews) { - await cleanupFullDocker(application?.serverId); - } + // if (admin.cleanupCacheOnPreviews) { + // await cleanupFullDocker(application?.serverId); + // } if (application.sourceType === "github") { await cloneGithubRepository({ @@ -568,11 +568,11 @@ export const deployRemotePreviewApplication = async ({ application.buildArgs = application.previewBuildArgs; if (application.serverId) { - const admin = await findUserById(application.project.userId); + // const admin = await findUserById(application.project.userId); - if (admin.cleanupCacheOnPreviews) { - await cleanupFullDocker(application?.serverId); - } + // if (admin.cleanupCacheOnPreviews) { + // await cleanupFullDocker(application?.serverId); + // } let command = "set -e;"; if (application.sourceType === "github") { command += await getGithubCloneCommand({ @@ -637,11 +637,11 @@ export const rebuildRemoteApplication = async ({ try { if (application.serverId) { - const admin = await findUserById(application.project.userId); + // const admin = await findUserById(application.project.userId); - if (admin.cleanupCacheApplications) { - await cleanupFullDocker(application?.serverId); - } + // if (admin.cleanupCacheApplications) { + // await cleanupFullDocker(application?.serverId); + // } if (application.sourceType !== "docker") { let command = "set -e;"; command += getBuildCommand(application, deployment.logPath); diff --git a/packages/server/src/services/compose.ts b/packages/server/src/services/compose.ts index a4126a0d0..70bc411c1 100644 --- a/packages/server/src/services/compose.ts +++ b/packages/server/src/services/compose.ts @@ -217,10 +217,10 @@ export const deployCompose = async ({ }); try { - const admin = await findUserById(compose.project.userId); - if (admin.cleanupCacheOnCompose) { - await cleanupFullDocker(compose?.serverId); - } + // const admin = await findUserById(compose.project.userId); + // if (admin.cleanupCacheOnCompose) { + // await cleanupFullDocker(compose?.serverId); + // } if (compose.sourceType === "github") { await cloneGithubRepository({ ...compose, @@ -247,7 +247,7 @@ export const deployCompose = async ({ applicationName: compose.name, applicationType: "compose", buildLink, - userId: compose.project.userId, + organizationId: compose.project.organizationId, domains: compose.domains, }); } catch (error) { @@ -262,7 +262,7 @@ export const deployCompose = async ({ // @ts-ignore errorMessage: error?.message || "Error building", buildLink, - userId: compose.project.userId, + organizationId: compose.project.organizationId, }); throw error; } @@ -286,10 +286,10 @@ export const rebuildCompose = async ({ }); try { - const admin = await findUserById(compose.project.userId); - if (admin.cleanupCacheOnCompose) { - await cleanupFullDocker(compose?.serverId); - } + // const admin = await findUserById(compose.project.userId); + // if (admin.cleanupCacheOnCompose) { + // await cleanupFullDocker(compose?.serverId); + // } if (compose.serverId) { await getBuildComposeCommand(compose, deployment.logPath); } else { @@ -332,10 +332,10 @@ export const deployRemoteCompose = async ({ }); try { if (compose.serverId) { - const admin = await findUserById(compose.project.userId); - if (admin.cleanupCacheOnCompose) { - await cleanupFullDocker(compose?.serverId); - } + // const admin = await findUserById(compose.project.userId); + // if (admin.cleanupCacheOnCompose) { + // await cleanupFullDocker(compose?.serverId); + // } let command = "set -e;"; if (compose.sourceType === "github") { @@ -381,7 +381,7 @@ export const deployRemoteCompose = async ({ applicationName: compose.name, applicationType: "compose", buildLink, - userId: compose.project.userId, + organizationId: compose.project.organizationId, domains: compose.domains, }); } catch (error) { @@ -406,7 +406,7 @@ export const deployRemoteCompose = async ({ // @ts-ignore errorMessage: error?.message || "Error building", buildLink, - userId: compose.project.userId, + organizationId: compose.project.organizationId, }); throw error; } @@ -430,10 +430,10 @@ export const rebuildRemoteCompose = async ({ }); try { - const admin = await findUserById(compose.project.userId); - if (admin.cleanupCacheOnCompose) { - await cleanupFullDocker(compose?.serverId); - } + // const admin = await findUserById(compose.project.userId); + // if (admin.cleanupCacheOnCompose) { + // await cleanupFullDocker(compose?.serverId); + // } if (compose.serverId) { await getBuildComposeCommand(compose, deployment.logPath); } diff --git a/packages/server/src/services/preview-deployment.ts b/packages/server/src/services/preview-deployment.ts index 69279b027..d5a2149a7 100644 --- a/packages/server/src/services/preview-deployment.ts +++ b/packages/server/src/services/preview-deployment.ts @@ -2,6 +2,7 @@ import { db } from "@dokploy/server/db"; import { type apiCreatePreviewDeployment, deployments, + organization, previewDeployments, } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; @@ -154,11 +155,14 @@ export const createPreviewDeployment = async ( const application = await findApplicationById(schema.applicationId); const appName = `preview-${application.appName}-${generatePassword(6)}`; + const org = await db.query.organization.findFirst({ + where: eq(organization.id, application.project.organizationId), + }); const generateDomain = await generateWildcardDomain( application.previewWildcard || "*.traefik.me", appName, application.server?.ipAddress || "", - application.project.userId, + org?.ownerId || "", ); const octokit = authGithub(application?.github as Github); diff --git a/packages/server/src/services/settings.ts b/packages/server/src/services/settings.ts index dd5b4e183..01ac43a14 100644 --- a/packages/server/src/services/settings.ts +++ b/packages/server/src/services/settings.ts @@ -5,8 +5,6 @@ import { execAsync, execAsyncRemote, } from "@dokploy/server/utils/process/execAsync"; -import { findAdminById } from "./admin"; -// import packageInfo from "../../../package.json"; export interface IUpdateData { latestVersion: string | null; diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index c32ceef2c..fbd81cf1b 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -20,17 +20,17 @@ export type User = typeof users_temp.$inferSelect; // }; export const findUserByAuthId = async (authId: string) => { - const userR = await db.query.user.findFirst({ - where: eq(user.id, authId), - with: {}, - }); - if (!userR) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "User not found", - }); - } - return userR; + // const userR = await db.query.user.findFirst({ + // where: eq(user.id, authId), + // with: {}, + // }); + // if (!userR) { + // throw new TRPCError({ + // code: "NOT_FOUND", + // message: "User not found", + // }); + // } + // return userR; }; export const findUsers = async (adminId: string) => { diff --git a/packages/server/src/utils/notifications/build-error.ts b/packages/server/src/utils/notifications/build-error.ts index 4ed227e1e..c873c9ab5 100644 --- a/packages/server/src/utils/notifications/build-error.ts +++ b/packages/server/src/utils/notifications/build-error.ts @@ -18,7 +18,7 @@ interface Props { applicationType: string; errorMessage: string; buildLink: string; - userId: string; + organizationId: string; } export const sendBuildErrorNotifications = async ({ @@ -27,14 +27,14 @@ export const sendBuildErrorNotifications = async ({ applicationType, errorMessage, buildLink, - userId, + organizationId, }: Props) => { const date = new Date(); const unixDate = ~~(Number(date) / 1000); const notificationList = await db.query.notifications.findMany({ where: and( eq(notifications.appBuildError, true), - eq(notifications.userId, userId), + eq(notifications.organizationId, organizationId), ), with: { email: true, diff --git a/packages/server/src/utils/notifications/build-success.ts b/packages/server/src/utils/notifications/build-success.ts index dfa4824f6..ac470c49f 100644 --- a/packages/server/src/utils/notifications/build-success.ts +++ b/packages/server/src/utils/notifications/build-success.ts @@ -18,7 +18,7 @@ interface Props { applicationName: string; applicationType: string; buildLink: string; - userId: string; + organizationId: string; domains: Domain[]; } @@ -27,7 +27,7 @@ export const sendBuildSuccessNotifications = async ({ applicationName, applicationType, buildLink, - userId, + organizationId, domains, }: Props) => { const date = new Date(); @@ -35,7 +35,7 @@ export const sendBuildSuccessNotifications = async ({ const notificationList = await db.query.notifications.findMany({ where: and( eq(notifications.appDeploy, true), - eq(notifications.userId, userId), + eq(notifications.organizationId, organizationId), ), with: { email: true, diff --git a/packages/server/src/utils/notifications/docker-cleanup.ts b/packages/server/src/utils/notifications/docker-cleanup.ts index 0acf1b6c4..b3959cccd 100644 --- a/packages/server/src/utils/notifications/docker-cleanup.ts +++ b/packages/server/src/utils/notifications/docker-cleanup.ts @@ -13,7 +13,7 @@ import { } from "./utils"; export const sendDockerCleanupNotifications = async ( - userId: string, + organizationId: string, message = "Docker cleanup for dokploy", ) => { const date = new Date(); @@ -21,7 +21,7 @@ export const sendDockerCleanupNotifications = async ( const notificationList = await db.query.notifications.findMany({ where: and( eq(notifications.dockerCleanup, true), - eq(notifications.userId, userId), + eq(notifications.organizationId, organizationId), ), with: { email: true, From 27736c7c97679896f724efc41285490520393c99 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 16 Feb 2025 03:06:22 -0600 Subject: [PATCH 35/89] refactor: update role and validation handling across multiple pages --- .../dashboard/settings/users/add-user.tsx | 2 +- .../pages/dashboard/project/[projectId].tsx | 4 ++-- .../pages/dashboard/settings/certificates.tsx | 6 +++--- .../pages/dashboard/settings/cluster.tsx | 6 +++--- .../pages/dashboard/settings/destinations.tsx | 6 +++--- .../dashboard/settings/git-providers.tsx | 16 +++++++------- .../pages/dashboard/settings/index.tsx | 6 +++--- .../dashboard/settings/notifications.tsx | 6 +++--- .../pages/dashboard/settings/profile.tsx | 21 +++++++++++-------- .../pages/dashboard/settings/registry.tsx | 6 +++--- .../pages/dashboard/settings/server.tsx | 6 +++--- .../pages/dashboard/settings/servers.tsx | 6 +++--- .../pages/dashboard/settings/ssh-keys.tsx | 15 +++++++------ .../pages/dashboard/settings/users.tsx | 6 +++--- apps/dokploy/pages/register.tsx | 2 +- apps/dokploy/server/wss/drawer-logs.ts | 2 +- 16 files changed, 58 insertions(+), 58 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/users/add-user.tsx b/apps/dokploy/components/dashboard/settings/users/add-user.tsx index 175f723f5..fa1c8bf95 100644 --- a/apps/dokploy/components/dashboard/settings/users/add-user.tsx +++ b/apps/dokploy/components/dashboard/settings/users/add-user.tsx @@ -58,7 +58,7 @@ export const AddUser = () => { const onSubmit = async (data: AddUser) => { const result = await authClient.organization.inviteMember({ email: data.email.toLowerCase(), - role: "user", + role: "member", organizationId: activeOrganization?.id, }); console.log(result); diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index b5d6b18f8..abedd10fe 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -674,8 +674,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/settings/certificates.tsx b/apps/dokploy/pages/dashboard/settings/certificates.tsx index 14d020c41..d045208e1 100644 --- a/apps/dokploy/pages/dashboard/settings/certificates.tsx +++ b/apps/dokploy/pages/dashboard/settings/certificates.tsx @@ -24,7 +24,7 @@ export async function getServerSideProps( ctx: GetServerSidePropsContext<{ serviceId: string }>, ) { const { req, res } = ctx; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user || user.role === "member") { return { redirect: { @@ -40,8 +40,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/settings/cluster.tsx b/apps/dokploy/pages/dashboard/settings/cluster.tsx index dd12723c4..8d70f8692 100644 --- a/apps/dokploy/pages/dashboard/settings/cluster.tsx +++ b/apps/dokploy/pages/dashboard/settings/cluster.tsx @@ -33,7 +33,7 @@ export async function getServerSideProps( }, }; } - const { user, session } = await validateRequest(ctx.req, ctx.res); + const { user, session } = await validateRequest(ctx.req); if (!user || user.role === "member") { return { redirect: { @@ -48,8 +48,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/settings/destinations.tsx b/apps/dokploy/pages/dashboard/settings/destinations.tsx index 5d34ec5f4..d9d17d538 100644 --- a/apps/dokploy/pages/dashboard/settings/destinations.tsx +++ b/apps/dokploy/pages/dashboard/settings/destinations.tsx @@ -25,7 +25,7 @@ export async function getServerSideProps( ctx: GetServerSidePropsContext<{ serviceId: string }>, ) { const { req, res } = ctx; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user || user.role === "member") { return { redirect: { @@ -41,8 +41,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx index c9135fee6..d0d9ca7f1 100644 --- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx +++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx @@ -24,7 +24,7 @@ Page.getLayout = (page: ReactElement) => { export async function getServerSideProps( ctx: GetServerSidePropsContext<{ serviceId: string }>, ) { - const { user, session } = await validateRequest(ctx.req, ctx.res); + const { user, session } = await validateRequest(ctx.req); if (!user) { return { redirect: { @@ -40,8 +40,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); @@ -49,14 +49,12 @@ export async function getServerSideProps( try { await helpers.project.all.prefetch(); await helpers.settings.isCloud.prefetch(); - const auth = await helpers.auth.get.fetch(); - - if (auth.role === "member") { - const user = await helpers.user.byAuthId.fetch({ - authId: auth.id, + if (user.role === "member") { + const userR = await helpers.user.get.fetch({ + userId: user.id, }); - if (!user.canAccessToGitProviders) { + if (!userR.canAccessToGitProviders) { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/index.tsx b/apps/dokploy/pages/dashboard/settings/index.tsx index 577c2b7c7..a12db093d 100644 --- a/apps/dokploy/pages/dashboard/settings/index.tsx +++ b/apps/dokploy/pages/dashboard/settings/index.tsx @@ -181,7 +181,7 @@ export async function getServerSideProps( ctx: GetServerSidePropsContext<{ serviceId: string }>, ) { const { req, res } = ctx; - const { user, session } = await validateRequest(ctx.req, ctx.res); + const { user, session } = await validateRequest(ctx.req); if (!user) { return { redirect: { @@ -205,8 +205,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/settings/notifications.tsx b/apps/dokploy/pages/dashboard/settings/notifications.tsx index 840eb9d4a..d0e0c65fe 100644 --- a/apps/dokploy/pages/dashboard/settings/notifications.tsx +++ b/apps/dokploy/pages/dashboard/settings/notifications.tsx @@ -25,7 +25,7 @@ export async function getServerSideProps( ctx: GetServerSidePropsContext<{ serviceId: string }>, ) { const { req, res } = ctx; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user || user.role === "member") { return { redirect: { @@ -41,8 +41,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index 656c30996..73b90c722 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -14,12 +14,12 @@ import superjson from "superjson"; const Page = () => { const { data } = api.auth.get.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( + const { data: user } = api.user.get.useQuery( { authId: data?.id || "", }, { - enabled: !!data?.id && data?.role === "user", + enabled: !!data?.id && data?.role === "member", }, ); @@ -46,7 +46,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const locale = getLocale(req.cookies); - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); const helpers = createServerSideHelpers({ router: appRouter, @@ -54,18 +54,21 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); await helpers.settings.isCloud.prefetch(); await helpers.auth.get.prefetch(); - if (user?.role === "user") { - await helpers.user.byAuthId.prefetch({ - authId: user.authId, - }); + if (user?.role === "member") { + // const userR = await helpers.user.get.fetch({ + // userId: user.id, + // }); + // await helpers.user.byAuthId.prefetch({ + // authId: user.authId, + // }); } if (!user) { diff --git a/apps/dokploy/pages/dashboard/settings/registry.tsx b/apps/dokploy/pages/dashboard/settings/registry.tsx index 61f62614a..0a01e255f 100644 --- a/apps/dokploy/pages/dashboard/settings/registry.tsx +++ b/apps/dokploy/pages/dashboard/settings/registry.tsx @@ -25,7 +25,7 @@ export async function getServerSideProps( ctx: GetServerSidePropsContext<{ serviceId: string }>, ) { const { req, res } = ctx; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user || user.role === "member") { return { redirect: { @@ -40,8 +40,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/settings/server.tsx b/apps/dokploy/pages/dashboard/settings/server.tsx index 498e97ce1..7a9eff3c6 100644 --- a/apps/dokploy/pages/dashboard/settings/server.tsx +++ b/apps/dokploy/pages/dashboard/settings/server.tsx @@ -98,7 +98,7 @@ export async function getServerSideProps( }, }; } - const { user, session } = await validateRequest(ctx.req, ctx.res); + const { user, session } = await validateRequest(ctx.req); if (!user) { return { redirect: { @@ -122,8 +122,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/settings/servers.tsx b/apps/dokploy/pages/dashboard/settings/servers.tsx index 6f83fb669..85ca5bb31 100644 --- a/apps/dokploy/pages/dashboard/settings/servers.tsx +++ b/apps/dokploy/pages/dashboard/settings/servers.tsx @@ -27,7 +27,7 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const locale = await getLocale(req.cookies); - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user) { return { redirect: { @@ -51,8 +51,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx index d7876641f..f3b9cf1b8 100644 --- a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx +++ b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx @@ -24,7 +24,7 @@ Page.getLayout = (page: ReactElement) => { export async function getServerSideProps( ctx: GetServerSidePropsContext<{ serviceId: string }>, ) { - const { user, session } = await validateRequest(ctx.req, ctx.res); + const { user, session } = await validateRequest(ctx.req); if (!user) { return { redirect: { @@ -40,23 +40,22 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); try { await helpers.project.all.prefetch(); - const auth = await helpers.auth.get.fetch(); await helpers.settings.isCloud.prefetch(); - if (auth.role === "member") { - const user = await helpers.user.byAuthId.fetch({ - authId: auth.id, + if (user.role === "member") { + const userR = await helpers.user.get.fetch({ + userId: user.id, }); - if (!user.canAccessToSSHKeys) { + if (!userR.canAccessToSSHKeys) { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/users.tsx b/apps/dokploy/pages/dashboard/settings/users.tsx index 8f97e2b6c..1c53c82b1 100644 --- a/apps/dokploy/pages/dashboard/settings/users.tsx +++ b/apps/dokploy/pages/dashboard/settings/users.tsx @@ -25,7 +25,7 @@ export async function getServerSideProps( ctx: GetServerSidePropsContext<{ serviceId: string }>, ) { const { req, res } = ctx; - const { user, session } = await validateRequest(req, res); + const { user, session } = await validateRequest(req); if (!user || user.role === "member") { return { redirect: { @@ -41,8 +41,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/register.tsx b/apps/dokploy/pages/register.tsx index f79024788..73dce5e77 100644 --- a/apps/dokploy/pages/register.tsx +++ b/apps/dokploy/pages/register.tsx @@ -274,7 +274,7 @@ Register.getLayout = (page: ReactElement) => { }; export async function getServerSideProps(context: GetServerSidePropsContext) { if (IS_CLOUD) { - const { user } = await validateRequest(context.req, context.res); + const { user } = await validateRequest(context.req); if (user) { return { diff --git a/apps/dokploy/server/wss/drawer-logs.ts b/apps/dokploy/server/wss/drawer-logs.ts index da2c529ac..9fe947ffa 100644 --- a/apps/dokploy/server/wss/drawer-logs.ts +++ b/apps/dokploy/server/wss/drawer-logs.ts @@ -1,9 +1,9 @@ import type http from "node:http"; +import { validateRequest } from "@dokploy/server/index"; import { applyWSSHandler } from "@trpc/server/adapters/ws"; import { WebSocketServer } from "ws"; import { appRouter } from "../api/root"; import { createTRPCContext } from "../api/trpc"; -import { validateRequest } from "@dokploy/server/index"; export const setupDrawerLogsWebSocketServer = ( server: http.Server, From a8d1471b16377be400c5e6406a2127307aed0bca Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 16 Feb 2025 13:28:29 -0600 Subject: [PATCH 36/89] refactor: update --- apps/dokploy/server/api/routers/auth.ts | 137 +++++++++--------- apps/dokploy/server/api/routers/user.ts | 26 ++-- apps/dokploy/server/api/trpc.ts | 4 +- packages/server/src/auth/auth.ts | 41 ------ packages/server/src/auth/token.ts | 99 ------------- packages/server/src/index.ts | 2 - packages/server/src/services/admin.ts | 47 +++--- packages/server/src/services/user.ts | 14 -- .../server/src/utils/access-log/handler.ts | 35 +++-- packages/server/src/utils/backups/mariadb.ts | 4 +- packages/server/src/utils/backups/mongo.ts | 4 +- packages/server/src/utils/backups/mysql.ts | 4 +- packages/server/src/utils/backups/postgres.ts | 4 +- .../utils/notifications/database-backup.ts | 6 +- 14 files changed, 133 insertions(+), 294 deletions(-) delete mode 100644 packages/server/src/auth/auth.ts delete mode 100644 packages/server/src/auth/token.ts diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index cc149b3c0..9fc66cf2a 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -20,8 +20,6 @@ import { findUserById, generate2FASecret, getUserByToken, - lucia, - luciaToken, removeAdminByAuthId, sendDiscordNotification, sendEmailNotification, @@ -68,11 +66,11 @@ export const authRouter = createTRPCRouter({ type: "cloud", }; } - const session = await lucia.createSession(newAdmin.id || "", {}); - ctx.res.appendHeader( - "Set-Cookie", - lucia.createSessionCookie(session.id).serialize(), - ); + // const session = await lucia.createSession(newAdmin.id || "", {}); + // ctx.res.appendHeader( + // "Set-Cookie", + // lucia.createSessionCookie(session.id).serialize(), + // ); return { status: "success", type: "selfhosted", @@ -91,24 +89,24 @@ export const authRouter = createTRPCRouter({ .mutation(async ({ ctx, input }) => { try { const token = await getUserByToken(input.token); - if (token.isExpired) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Invalid token", - }); - } + // if (token.isExpired) { + // throw new TRPCError({ + // code: "BAD_REQUEST", + // message: "Invalid token", + // }); + // } - const newUser = await createUser(input); + // const newUser = await createUser(input); - if (IS_CLOUD) { - await sendVerificationEmail(token.authId); - return true; - } - const session = await lucia.createSession(newUser?.authId || "", {}); - ctx.res.appendHeader( - "Set-Cookie", - lucia.createSessionCookie(session.id).serialize(), - ); + // if (IS_CLOUD) { + // await sendVerificationEmail(token.authId); + // return true; + // } + // const session = await lucia.createSession(newUser?.authId || "", {}); + // ctx.res.appendHeader( + // "Set-Cookie", + // lucia.createSessionCookie(session.id).serialize(), + // ); return true; } catch (error) { throw new TRPCError({ @@ -151,12 +149,12 @@ export const authRouter = createTRPCRouter({ }; } - const session = await lucia.createSession(auth?.id || "", {}); + // const session = await lucia.createSession(auth?.id || "", {}); - ctx.res.appendHeader( - "Set-Cookie", - lucia.createSessionCookie(session.id).serialize(), - ); + // ctx.res.appendHeader( + // "Set-Cookie", + // lucia.createSessionCookie(session.id).serialize(), + // ); return { is2FAEnabled: false, authId: auth?.id, @@ -186,11 +184,11 @@ export const authRouter = createTRPCRouter({ logout: protectedProcedure.mutation(async ({ ctx }) => { const { req, res } = ctx; - const { session } = await validateRequest(req, res); + const { session } = await validateRequest(req); if (!session) return false; - await lucia.invalidateSession(session.id); - res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); + // await lucia.invalidateSession(session.id); + // res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); return true; }), @@ -211,13 +209,13 @@ export const authRouter = createTRPCRouter({ }); } } - const auth = await updateAuthById(ctx.user.authId, { - ...(input.email && { email: input.email.toLowerCase() }), - ...(input.password && { - password: bcrypt.hashSync(input.password, 10), - }), - ...(input.image && { image: input.image }), - }); + // const auth = await updateAuthById(ctx.user.authId, { + // ...(input.email && { email: input.email.toLowerCase() }), + // ...(input.password && { + // password: bcrypt.hashSync(input.password, 10), + // }), + // ...(input.image && { image: input.image }), + // }); return auth; }), @@ -248,17 +246,17 @@ export const authRouter = createTRPCRouter({ }); } const { req, res } = ctx; - const { session } = await validateRequest(req, res); + const { session } = await validateRequest(req); if (!session) return false; - await lucia.invalidateSession(session.id); - res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); + // await lucia.invalidateSession(session.id); + // res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); - if (ctx.user.rol === "owner") { - await removeAdminByAuthId(ctx.user.authId); - } else { - await removeUserByAuthId(ctx.user.authId); - } + // if (ctx.user.rol === "owner") { + // await removeAdminByAuthId(ctx.user.authId); + // } else { + // await removeUserByAuthId(ctx.user.authId); + // } return true; }), @@ -267,9 +265,9 @@ export const authRouter = createTRPCRouter({ const auth = await findUserById(ctx.user.id); console.log(auth); - if (auth.token) { - await luciaToken.invalidateSession(auth.token); - } + // if (auth.token) { + // await luciaToken.invalidateSession(auth.token); + // } // const session = await luciaToken.createSession(auth?.id || "", { // expiresIn: 60 * 60 * 24 * 30, // }); @@ -292,39 +290,38 @@ export const authRouter = createTRPCRouter({ verify2FASetup: protectedProcedure .input(apiVerify2FA) .mutation(async ({ ctx, input }) => { - const auth = await findAuthById(ctx.user.authId); - - await verify2FA(auth, input.secret, input.pin); - await updateAuthById(auth.id, { - is2FAEnabled: true, - secret: input.secret, - }); - return auth; + // const auth = await findAuthById(ctx.user.authId); + // await verify2FA(auth, input.secret, input.pin); + // await updateAuthById(auth.id, { + // is2FAEnabled: true, + // secret: input.secret, + // }); + // return auth; }), verifyLogin2FA: publicProcedure .input(apiVerifyLogin2FA) .mutation(async ({ ctx, input }) => { - const auth = await findAuthById(input.id); + // const auth = await findAuthById(input.id); - await verify2FA(auth, auth.secret || "", input.pin); + // await verify2FA(auth, auth.secret || "", input.pin); - const session = await lucia.createSession(auth.id, {}); + // const session = await lucia.createSession(auth.id, {}); - ctx.res.appendHeader( - "Set-Cookie", - lucia.createSessionCookie(session.id).serialize(), - ); + // ctx.res.appendHeader( + // "Set-Cookie", + // lucia.createSessionCookie(session.id).serialize(), + // ); return true; }), disable2FA: protectedProcedure.mutation(async ({ ctx }) => { - const auth = await findAuthById(ctx.user.authId); - await updateAuthById(auth.id, { - is2FAEnabled: false, - secret: null, - }); - return auth; + // const auth = await findAuthById(ctx.user.authId); + // await updateAuthById(auth.id, { + // is2FAEnabled: false, + // secret: null, + // }); + // return auth; }), sendResetPasswordEmail: publicProcedure .input( diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 00c2bb82e..f4de4d9f7 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -1,5 +1,5 @@ import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema"; -import { findUserByAuthId, findUserById, findUsers } from "@dokploy/server"; +import { findUserByAuthId, findUserById } from "@dokploy/server"; import { db } from "@dokploy/server/db"; import { member } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; @@ -31,16 +31,16 @@ export const userRouter = createTRPCRouter({ // } return user; }), - byUserId: protectedProcedure - .input(apiFindOneUser) - .query(async ({ input, ctx }) => { - const user = await findUserById(input.userId); - if (user.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to access this user", - }); - } - return user; - }), + // byUserId: protectedProcedure + // .input(apiFindOneUser) + // .query(async ({ input, ctx }) => { + // const user = await findUserById(input.userId); + // if (user.adminId !== ctx.user.adminId) { + // throw new TRPCError({ + // code: "UNAUTHORIZED", + // message: "You are not allowed to access this user", + // }); + // } + // return user; + // }), }); diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index 7f8f0f756..c63839c5e 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -75,8 +75,8 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { // user = cookieResult.user; // } - console.log("session", session); - console.log("user", user); + // console.log("session", session); + // console.log("user", user); return createInnerTRPCContext({ req, diff --git a/packages/server/src/auth/auth.ts b/packages/server/src/auth/auth.ts deleted file mode 100644 index 28052f5f6..000000000 --- a/packages/server/src/auth/auth.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle"; -import { TimeSpan } from "lucia"; -import { Lucia } from "lucia/dist/core.js"; -import type { Session, User } from "lucia/dist/core.js"; -import { db } from "../db"; -import { type DatabaseUser, auth, session } from "../db/schema"; - -export const adapter = new DrizzlePostgreSQLAdapter(db, session, auth); - -export const lucia = new Lucia(adapter, { - sessionCookie: { - attributes: { - secure: false, - }, - }, - - sessionExpiresIn: new TimeSpan(1, "d"), - getUserAttributes: (attributes) => { - return { - email: attributes.email, - rol: attributes.rol, - secret: attributes.secret !== null, - adminId: attributes.adminId, - }; - }, -}); - -declare module "lucia" { - interface Register { - Lucia: typeof lucia; - DatabaseUserAttributes: Omit & { - authId: string; - adminId: string; - }; - } -} - -export type ReturnValidateToken = Promise<{ - user: (User & { authId: string; adminId: string }) | null; - session: Session | null; -}>; diff --git a/packages/server/src/auth/token.ts b/packages/server/src/auth/token.ts deleted file mode 100644 index e3f404b05..000000000 --- a/packages/server/src/auth/token.ts +++ /dev/null @@ -1,99 +0,0 @@ -import type { IncomingMessage } from "node:http"; -import { TimeSpan } from "lucia"; -import { Lucia } from "lucia/dist/core.js"; -import { findAdminByAuthId } from "../services/admin"; -import { findUserByAuthId } from "../services/user"; -import { type ReturnValidateToken, adapter } from "./auth"; - -export const luciaToken = new Lucia(adapter, { - sessionCookie: { - attributes: { - secure: false, - }, - }, - sessionExpiresIn: new TimeSpan(365, "d"), - getUserAttributes: (attributes) => { - return { - email: attributes.email, - rol: attributes.rol, - secret: attributes.secret !== null, - }; - }, -}); - -// export const validateBearerToken = async ( -// req: IncomingMessage, -// ): ReturnValidateToken => { -// const authorizationHeader = req.headers.authorization; -// const sessionId = luciaToken.readBearerToken(authorizationHeader ?? ""); -// if (!sessionId) { -// return { -// user: null, -// session: null, -// }; -// } -// const result = await luciaToken.validateSession(sessionId); - -// if (result.user) { -// if (result.user?.rol === "owner") { -// const admin = await findAdminByAuthId(result.user.id); -// result.user.adminId = admin.adminId; -// } else if (result.user?.rol === "member") { -// const userResult = await findUserByAuthId(result.user.id); -// result.user.adminId = userResult.adminId; -// } -// } -// return { -// session: result.session, -// ...((result.user && { -// user: { -// adminId: result.user.adminId, -// authId: result.user.id, -// email: result.user.email, -// rol: result.user.rol, -// id: result.user.id, -// secret: result.user.secret, -// }, -// }) || { -// user: null, -// }), -// }; -// }; - -// export const validateBearerTokenAPI = async ( -// authorizationHeader: string, -// ): ReturnValidateToken => { -// const sessionId = luciaToken.readBearerToken(authorizationHeader ?? ""); -// if (!sessionId) { -// return { -// user: null, -// session: null, -// }; -// } -// const result = await luciaToken.validateSession(sessionId); - -// if (result.user) { -// if (result.user?.rol === "owner") { -// const admin = await findAdminByAuthId(result.user.id); -// result.user.adminId = admin.adminId; -// } else if (result.user?.rol === "member") { -// const userResult = await findUserByAuthId(result.user.id); -// result.user.adminId = userResult.adminId; -// } -// } -// return { -// session: result.session, -// ...((result.user && { -// user: { -// adminId: result.user.adminId, -// authId: result.user.id, -// email: result.user.email, -// rol: result.user.rol, -// id: result.user.id, -// secret: result.user.secret, -// }, -// }) || { -// user: null, -// }), -// }; -// }; diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 345849ed9..554b4c124 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1,5 +1,3 @@ -export * from "./auth/auth"; -export * from "./auth/token"; export * from "./auth/random-password"; // export * from "./db"; export * from "./services/admin"; diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index 78a0375a8..41b92587f 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -143,27 +143,26 @@ export const findAdmin = async () => { }; export const getUserByToken = async (token: string) => { - const user = await db.query.users.findFirst({ - where: eq(users.token, token), - with: { - auth: { - columns: { - password: false, - }, - }, - }, - }); - - if (!user) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Invitation not found", - }); - } - return { - ...user, - isExpired: user.isRegistered, - }; + // const user = await db.query.users.findFirst({ + // where: eq(users.token, token), + // with: { + // auth: { + // columns: { + // password: false, + // }, + // }, + // }, + // }); + // if (!user) { + // throw new TRPCError({ + // code: "NOT_FOUND", + // message: "Invitation not found", + // }); + // } + // return { + // ...user, + // isExpired: user.isRegistered, + // }; }; export const removeUserById = async (userId: string) => { @@ -181,9 +180,9 @@ export const removeAdminByAuthId = async (authId: string) => { // First delete all associated users const users = admin.users; - for (const user of users) { - await removeUserById(user.id); - } + // for (const user of users) { + // await removeUserById(user.id); + // } // Then delete the auth record which will cascade delete the admin return await db .delete(auth) diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index fbd81cf1b..170af9084 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -33,20 +33,6 @@ export const findUserByAuthId = async (authId: string) => { // return userR; }; -export const findUsers = async (adminId: string) => { - const currentUsers = await db.query.user.findMany({ - where: eq(user.adminId, adminId), - with: { - auth: { - columns: { - secret: false, - }, - }, - }, - }); - return currentUsers; -}; - export const addNewProject = async (userId: string, projectId: string) => { const userR = await findUserById(userId); diff --git a/packages/server/src/utils/access-log/handler.ts b/packages/server/src/utils/access-log/handler.ts index 668855144..574717323 100644 --- a/packages/server/src/utils/access-log/handler.ts +++ b/packages/server/src/utils/access-log/handler.ts @@ -1,5 +1,4 @@ import { IS_CLOUD, paths } from "@dokploy/server/constants"; -import { updateAdmin } from "@dokploy/server/services/admin"; import { type RotatingFileStream, createStream } from "rotating-file-stream"; import { db } from "../../db"; import { execAsync } from "../process/execAsync"; @@ -23,27 +22,27 @@ class LogRotationManager { } private async initialize(): Promise { - // const isActive = await this.getStateFromDB(); - // if (isActive) { - // await this.activateStream(); - // } + const isActive = await this.getStateFromDB(); + if (isActive) { + await this.activateStream(); + } } - // private async getStateFromDB(): Promise { - // const setting = await db.query.admins.findFirst({}); - // return setting?.enableLogRotation ?? false; - // } + private async getStateFromDB(): Promise { + const setting = await db.query.admins.findFirst({}); + return setting?.enableLogRotation ?? false; + } - // private async setStateInDB(active: boolean): Promise { - // const admin = await db.query.admins.findFirst({}); + private async setStateInDB(active: boolean): Promise { + const admin = await db.query.admins.findFirst({}); - // if (!admin) { - // return; - // } - // await updateAdmin(admin?.authId, { - // enableLogRotation: active, - // }); - // } + if (!admin) { + return; + } + // await updateAdmin(admin?.authId, { + // enableLogRotation: active, + // }); + } private async activateStream(): Promise { const { DYNAMIC_TRAEFIK_PATH } = paths(); diff --git a/packages/server/src/utils/backups/mariadb.ts b/packages/server/src/utils/backups/mariadb.ts index 7ffa16e11..56c2919c4 100644 --- a/packages/server/src/utils/backups/mariadb.ts +++ b/packages/server/src/utils/backups/mariadb.ts @@ -49,7 +49,7 @@ export const runMariadbBackup = async ( projectName: project.name, databaseType: "mariadb", type: "success", - userId: project.userId, + organizationId: project.organizationId, }); } catch (error) { console.log(error); @@ -60,7 +60,7 @@ export const runMariadbBackup = async ( type: "error", // @ts-ignore errorMessage: error?.message || "Error message not provided", - userId: project.userId, + organizationId: project.organizationId, }); throw error; } diff --git a/packages/server/src/utils/backups/mongo.ts b/packages/server/src/utils/backups/mongo.ts index d6860a010..a40ec4f47 100644 --- a/packages/server/src/utils/backups/mongo.ts +++ b/packages/server/src/utils/backups/mongo.ts @@ -46,7 +46,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => { projectName: project.name, databaseType: "mongodb", type: "success", - userId: project.userId, + organizationId: project.organizationId, }); } catch (error) { console.log(error); @@ -57,7 +57,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => { type: "error", // @ts-ignore errorMessage: error?.message || "Error message not provided", - userId: project.userId, + organizationId: project.organizationId, }); throw error; } diff --git a/packages/server/src/utils/backups/mysql.ts b/packages/server/src/utils/backups/mysql.ts index a73179417..009a02cf2 100644 --- a/packages/server/src/utils/backups/mysql.ts +++ b/packages/server/src/utils/backups/mysql.ts @@ -46,7 +46,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => { projectName: project.name, databaseType: "mysql", type: "success", - userId: project.userId, + organizationId: project.organizationId, }); } catch (error) { console.log(error); @@ -57,7 +57,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => { type: "error", // @ts-ignore errorMessage: error?.message || "Error message not provided", - userId: project.userId, + organizationId: project.organizationId, }); throw error; } diff --git a/packages/server/src/utils/backups/postgres.ts b/packages/server/src/utils/backups/postgres.ts index 33c37b862..5ada2aa9d 100644 --- a/packages/server/src/utils/backups/postgres.ts +++ b/packages/server/src/utils/backups/postgres.ts @@ -49,7 +49,7 @@ export const runPostgresBackup = async ( projectName: project.name, databaseType: "postgres", type: "success", - userId: project.userId, + organizationId: project.organizationId, }); } catch (error) { await sendDatabaseBackupNotifications({ @@ -59,7 +59,7 @@ export const runPostgresBackup = async ( type: "error", // @ts-ignore errorMessage: error?.message || "Error message not provided", - userId: project.userId, + organizationId: project.organizationId, }); throw error; diff --git a/packages/server/src/utils/notifications/database-backup.ts b/packages/server/src/utils/notifications/database-backup.ts index 3ce36aa9f..08cff4b54 100644 --- a/packages/server/src/utils/notifications/database-backup.ts +++ b/packages/server/src/utils/notifications/database-backup.ts @@ -19,13 +19,13 @@ export const sendDatabaseBackupNotifications = async ({ databaseType, type, errorMessage, - userId, + organizationId, }: { projectName: string; applicationName: string; databaseType: "postgres" | "mysql" | "mongodb" | "mariadb"; type: "error" | "success"; - userId: string; + organizationId: string; errorMessage?: string; }) => { const date = new Date(); @@ -33,7 +33,7 @@ export const sendDatabaseBackupNotifications = async ({ const notificationList = await db.query.notifications.findMany({ where: and( eq(notifications.databaseBackup, true), - eq(notifications.userId, userId), + eq(notifications.organizationId, organizationId), ), with: { email: true, From 9856502ece59841a1861213746b9df137fe055a1 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 16 Feb 2025 13:55:27 -0600 Subject: [PATCH 37/89] refactor: remove old references --- apps/dokploy/__test__/drop/drop.test.test.ts | 2 +- .../server/update-server-config.test.ts | 8 +- apps/dokploy/pages/api/stripe/webhook.ts | 2 +- .../pages/dashboard/project/[projectId].tsx | 11 +- .../services/application/[applicationId].tsx | 16 +- .../services/compose/[composeId].tsx | 15 +- .../services/mariadb/[mariadbId].tsx | 16 +- .../[projectId]/services/mongo/[mongoId].tsx | 15 +- .../[projectId]/services/mysql/[mysqlId].tsx | 15 +- .../services/postgres/[postgresId].tsx | 16 +- .../[projectId]/services/redis/[redisId].tsx | 15 +- apps/dokploy/server/api/routers/admin.ts | 25 +- apps/dokploy/server/api/routers/auth.ts | 241 ++++++++---------- packages/server/src/db/schema/admin.ts | 210 --------------- packages/server/src/db/schema/auth.ts | 130 ---------- packages/server/src/db/schema/certificate.ts | 3 - packages/server/src/db/schema/deployment.ts | 2 +- packages/server/src/db/schema/destination.ts | 8 - packages/server/src/db/schema/git-provider.ts | 3 - packages/server/src/db/schema/index.ts | 2 - packages/server/src/db/schema/notification.ts | 2 - packages/server/src/db/schema/project.ts | 4 - packages/server/src/db/schema/registry.ts | 7 - packages/server/src/db/schema/server.ts | 8 - packages/server/src/db/schema/session.ts | 13 - packages/server/src/db/schema/source.ts | 27 -- packages/server/src/db/schema/ssh-key.ts | 3 - packages/server/src/db/schema/user.ts | 142 +++++++---- packages/server/src/services/admin.ts | 2 - packages/server/src/services/auth.ts | 106 +------- 30 files changed, 250 insertions(+), 819 deletions(-) delete mode 100644 packages/server/src/db/schema/admin.ts delete mode 100644 packages/server/src/db/schema/auth.ts delete mode 100644 packages/server/src/db/schema/source.ts diff --git a/apps/dokploy/__test__/drop/drop.test.test.ts b/apps/dokploy/__test__/drop/drop.test.test.ts index c4b2ba8d8..4e6f20d3f 100644 --- a/apps/dokploy/__test__/drop/drop.test.test.ts +++ b/apps/dokploy/__test__/drop/drop.test.test.ts @@ -45,7 +45,7 @@ const baseApp: ApplicationNested = { previewWildcard: "", project: { env: "", - adminId: "", + organizationId: "", name: "", description: "", createdAt: "", diff --git a/apps/dokploy/__test__/traefik/server/update-server-config.test.ts b/apps/dokploy/__test__/traefik/server/update-server-config.test.ts index e38c19e40..f7bf3595a 100644 --- a/apps/dokploy/__test__/traefik/server/update-server-config.test.ts +++ b/apps/dokploy/__test__/traefik/server/update-server-config.test.ts @@ -5,7 +5,7 @@ vi.mock("node:fs", () => ({ default: fs, })); -import type { Admin, FileConfig } from "@dokploy/server"; +import type { Admin, FileConfig, User } from "@dokploy/server"; import { createDefaultServerTraefikConfig, loadOrCreateConfig, @@ -13,7 +13,7 @@ import { } from "@dokploy/server"; import { beforeEach, expect, test, vi } from "vitest"; -const baseAdmin: Admin = { +const baseAdmin: Partial = { enablePaidFeatures: false, metricsConfig: { containers: { @@ -40,9 +40,7 @@ const baseAdmin: Admin = { cleanupCacheApplications: false, cleanupCacheOnCompose: false, cleanupCacheOnPreviews: false, - createdAt: "", - authId: "", - adminId: "string", + createdAt: new Date(), serverIp: null, certificateType: "none", host: null, diff --git a/apps/dokploy/pages/api/stripe/webhook.ts b/apps/dokploy/pages/api/stripe/webhook.ts index e8416c5d0..d9cbedc8a 100644 --- a/apps/dokploy/pages/api/stripe/webhook.ts +++ b/apps/dokploy/pages/api/stripe/webhook.ts @@ -1,6 +1,6 @@ import { buffer } from "node:stream/consumers"; import { db } from "@/server/db"; -import { admins, server, users_temp } from "@/server/db/schema"; +import { server, users_temp } from "@/server/db/schema"; import { findAdminById, findUserById } from "@dokploy/server"; import { asc, eq } from "drizzle-orm"; import type { NextApiRequest, NextApiResponse } from "next"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index abedd10fe..db70a59af 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -201,14 +201,7 @@ const Project = ( const [isBulkActionLoading, setIsBulkActionLoading] = useState(false); const { projectId } = props; const { data: auth } = api.auth.get.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: auth?.id || "", - }, - { - enabled: !!auth?.id && auth?.role === "member", - }, - ); + const { data, isLoading, refetch } = api.project.one.useQuery({ projectId }); const router = useRouter(); @@ -335,7 +328,7 @@ const Project = ( {data?.description} - {(auth?.role === "owner" || user?.canCreateServices) && ( + {(auth?.role === "owner" || auth?.user?.canCreateServices) && (
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx index a394f320f..5bdb2ee6c 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx @@ -40,7 +40,6 @@ import { cn } from "@/lib/utils"; import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; import { validateRequest } from "@dokploy/server/lib/auth"; -// import { validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import copy from "copy-to-clipboard"; import { GlobeIcon, HelpCircle, ServerOff, Trash2 } from "lucide-react"; @@ -89,14 +88,6 @@ const Service = ( const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: auth } = api.auth.get.useQuery(); const { data: monitoring } = api.admin.getMetricsToken.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: auth?.id || "", - }, - { - enabled: !!auth?.id && auth?.role === "member", - }, - ); return (
@@ -187,7 +178,8 @@ const Service = (
- {(auth?.role === "owner" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || + auth?.user?.canDeleteServices) && ( )}
@@ -387,8 +379,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx index 8bd3e8638..f2c4062a7 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx @@ -82,14 +82,6 @@ const Service = ( const { data: auth } = api.auth.get.useQuery(); const { data: monitoring } = api.admin.getMetricsToken.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: auth?.id || "", - }, - { - enabled: !!auth?.id && auth?.role === "member", - }, - ); return (
@@ -181,7 +173,8 @@ const Service = (
- {(auth?.role === "owner" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || + auth?.user?.canDeleteServices) && ( )}
@@ -382,8 +375,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx index 9adbad15c..b9ad1e226 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx @@ -63,14 +63,7 @@ const Mariadb = ( const { data } = api.mariadb.one.useQuery({ mariadbId }); const { data: auth } = api.auth.get.useQuery(); const { data: monitoring } = api.admin.getMetricsToken.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: auth?.id || "", - }, - { - enabled: !!auth?.id && auth?.role === "member", - }, - ); + const { data: isCloud } = api.settings.isCloud.useQuery(); return ( @@ -154,7 +147,8 @@ const Mariadb = (
- {(auth?.role === "owner" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || + auth?.user?.canDeleteServices) && ( )}
@@ -332,8 +326,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx index a5ba6b5de..218e3da9c 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx @@ -63,14 +63,6 @@ const Mongo = ( const { data: auth } = api.auth.get.useQuery(); const { data: monitoring } = api.admin.getMetricsToken.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: auth?.id || "", - }, - { - enabled: !!auth?.id && auth?.role === "member", - }, - ); const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -156,7 +148,8 @@ const Mongo = (
- {(auth?.role === "owner" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || + auth?.user?.canDeleteServices) && ( )}
@@ -334,8 +327,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx index 3e17c4fac..87011428e 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx @@ -62,14 +62,6 @@ const MySql = ( const { data } = api.mysql.one.useQuery({ mysqlId }); const { data: auth } = api.auth.get.useQuery(); const { data: monitoring } = api.admin.getMetricsToken.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: auth?.id || "", - }, - { - enabled: !!auth?.id && auth?.role === "member", - }, - ); const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -156,7 +148,8 @@ const MySql = (
- {(auth?.role === "owner" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || + auth?.user?.canDeleteServices) && ( )}
@@ -339,8 +332,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx index 0b1d2aee6..b78fd569c 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx @@ -61,14 +61,7 @@ const Postgresql = ( const [tab, setSab] = useState(activeTab); const { data } = api.postgres.one.useQuery({ postgresId }); const { data: auth } = api.auth.get.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: auth?.id || "", - }, - { - enabled: !!auth?.id && auth?.role === "member", - }, - ); + const { data: monitoring } = api.admin.getMetricsToken.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -154,7 +147,8 @@ const Postgresql = (
- {(auth?.role === "owner" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || + auth?.user?.canDeleteServices) && ( )}
@@ -335,8 +329,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx index 853e6688b..9ed8c47a1 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx @@ -62,14 +62,6 @@ const Redis = ( const { data: auth } = api.auth.get.useQuery(); const { data: monitoring } = api.admin.getMetricsToken.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: auth?.id || "", - }, - { - enabled: !!auth?.id && auth?.role === "member", - }, - ); const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -155,7 +147,8 @@ const Redis = (
- {(auth?.role === "owner" || user?.canDeleteServices) && ( + {(auth?.role === "owner" || + auth?.user?.canDeleteServices) && ( )}
@@ -327,8 +320,8 @@ export async function getServerSideProps( req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); diff --git a/apps/dokploy/server/api/routers/admin.ts b/apps/dokploy/server/api/routers/admin.ts index 55df35afe..695cdb336 100644 --- a/apps/dokploy/server/api/routers/admin.ts +++ b/apps/dokploy/server/api/routers/admin.ts @@ -4,7 +4,6 @@ import { apiCreateUserInvitation, apiFindOneToken, apiRemoveUser, - apiUpdateAdmin, apiUpdateWebServerMonitoring, } from "@/server/db/schema"; import { @@ -36,19 +35,17 @@ export const adminRouter = createTRPCRouter({ ...rest, }; }), - update: adminProcedure - .input(apiUpdateAdmin) - .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "member") { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to update this admin", - }); - } - const { id } = await findUserById(ctx.user.id); - // @ts-ignore - return updateAdmin(id, input); - }), + update: adminProcedure.mutation(async ({ input, ctx }) => { + if (ctx.user.rol === "member") { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not allowed to update this admin", + }); + } + const { id } = await findUserById(ctx.user.id); + // @ts-ignore + return updateAdmin(id, input); + }), createUserInvitation: adminProcedure .input(apiCreateUserInvitation) .mutation(async ({ input, ctx }) => { diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index 9fc66cf2a..ad2fab07e 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -1,30 +1,23 @@ import { - apiCreateAdmin, - apiCreateUser, - apiFindOneAuth, - apiLogin, - apiUpdateAuth, - apiVerify2FA, - apiVerifyLogin2FA, - auth, + // apiCreateAdmin, + // apiCreateUser, + // apiFindOneAuth, + // apiLogin, + // apiUpdateAuth, + // apiVerify2FA, + // apiVerifyLogin2FA, + // auth, member, } from "@/server/db/schema"; import { WEBSITE_URL } from "@/server/utils/stripe"; import { - type Auth, IS_CLOUD, - createAdmin, - createUser, - findAuthByEmail, findAuthById, findUserById, generate2FASecret, getUserByToken, - removeAdminByAuthId, sendDiscordNotification, sendEmailNotification, - updateAuthById, - updateUser, validateRequest, verify2FA, } from "@dokploy/server"; @@ -43,81 +36,77 @@ import { } from "../trpc"; export const authRouter = createTRPCRouter({ - createAdmin: publicProcedure - .input(apiCreateAdmin) - .mutation(async ({ ctx, input }) => { - try { - if (!IS_CLOUD) { - const admin = await db.query.admins.findFirst({}); - if (admin) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Admin already exists", - }); - } + createAdmin: publicProcedure.mutation(async ({ ctx, input }) => { + try { + if (!IS_CLOUD) { + const admin = await db.query.admins.findFirst({}); + if (admin) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Admin already exists", + }); } - const newAdmin = await createAdmin(input); + } + const newAdmin = await createAdmin(input); - if (IS_CLOUD) { - await sendDiscordNotificationWelcome(newAdmin); - await sendVerificationEmail(newAdmin.id); - return { - status: "success", - type: "cloud", - }; - } - // const session = await lucia.createSession(newAdmin.id || "", {}); - // ctx.res.appendHeader( - // "Set-Cookie", - // lucia.createSessionCookie(session.id).serialize(), - // ); + if (IS_CLOUD) { + await sendDiscordNotificationWelcome(newAdmin); + await sendVerificationEmail(newAdmin.id); return { status: "success", - type: "selfhosted", + type: "cloud", }; - } catch (error) { - throw new TRPCError({ - code: "BAD_REQUEST", - // @ts-ignore - message: `Error: ${error?.code === "23505" ? "Email already exists" : "Error creating admin"}`, - cause: error, - }); } - }), - createUser: publicProcedure - .input(apiCreateUser) - .mutation(async ({ ctx, input }) => { - try { - const token = await getUserByToken(input.token); - // if (token.isExpired) { - // throw new TRPCError({ - // code: "BAD_REQUEST", - // message: "Invalid token", - // }); - // } + // const session = await lucia.createSession(newAdmin.id || "", {}); + // ctx.res.appendHeader( + // "Set-Cookie", + // lucia.createSessionCookie(session.id).serialize(), + // ); + return { + status: "success", + type: "selfhosted", + }; + } catch (error) { + throw new TRPCError({ + code: "BAD_REQUEST", + // @ts-ignore + message: `Error: ${error?.code === "23505" ? "Email already exists" : "Error creating admin"}`, + cause: error, + }); + } + }), + createUser: publicProcedure.mutation(async ({ ctx, input }) => { + try { + const token = await getUserByToken(input.token); + // if (token.isExpired) { + // throw new TRPCError({ + // code: "BAD_REQUEST", + // message: "Invalid token", + // }); + // } - // const newUser = await createUser(input); + // const newUser = await createUser(input); - // if (IS_CLOUD) { - // await sendVerificationEmail(token.authId); - // return true; - // } - // const session = await lucia.createSession(newUser?.authId || "", {}); - // ctx.res.appendHeader( - // "Set-Cookie", - // lucia.createSessionCookie(session.id).serialize(), - // ); - return true; - } catch (error) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error creating the user", - cause: error, - }); - } - }), + // if (IS_CLOUD) { + // await sendVerificationEmail(token.authId); + // return true; + // } + // const session = await lucia.createSession(newUser?.authId || "", {}); + // ctx.res.appendHeader( + // "Set-Cookie", + // lucia.createSessionCookie(session.id).serialize(), + // ); + return true; + } catch (error) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Error creating the user", + cause: error, + }); + } + }), - login: publicProcedure.input(apiLogin).mutation(async ({ ctx, input }) => { + login: publicProcedure.mutation(async ({ ctx, input }) => { try { const auth = await findAuthByEmail(input.email); @@ -192,33 +181,31 @@ export const authRouter = createTRPCRouter({ return true; }), - update: protectedProcedure - .input(apiUpdateAuth) - .mutation(async ({ ctx, input }) => { - const currentAuth = await findAuthByEmail(ctx.user.email); + update: protectedProcedure.mutation(async ({ ctx, input }) => { + const currentAuth = await findAuthByEmail(ctx.user.email); - if (input.currentPassword || input.password) { - const correctPassword = bcrypt.compareSync( - input.currentPassword || "", - currentAuth?.password || "", - ); - if (!correctPassword) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Current password is incorrect", - }); - } + if (input.currentPassword || input.password) { + const correctPassword = bcrypt.compareSync( + input.currentPassword || "", + currentAuth?.password || "", + ); + if (!correctPassword) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Current password is incorrect", + }); } - // const auth = await updateAuthById(ctx.user.authId, { - // ...(input.email && { email: input.email.toLowerCase() }), - // ...(input.password && { - // password: bcrypt.hashSync(input.password, 10), - // }), - // ...(input.image && { image: input.image }), - // }); + } + // const auth = await updateAuthById(ctx.user.authId, { + // ...(input.email && { email: input.email.toLowerCase() }), + // ...(input.password && { + // password: bcrypt.hashSync(input.password, 10), + // }), + // ...(input.image && { image: input.image }), + // }); - return auth; - }), + return auth; + }), removeSelfAccount: protectedProcedure .input( z.object({ @@ -279,7 +266,7 @@ export const authRouter = createTRPCRouter({ verifyToken: protectedProcedure.mutation(async () => { return true; }), - one: adminProcedure.input(apiFindOneAuth).query(async ({ input }) => { + one: adminProcedure.query(async ({ input }) => { const auth = await findAuthById(input.id); return auth; }), @@ -287,34 +274,30 @@ export const authRouter = createTRPCRouter({ generate2FASecret: protectedProcedure.query(async ({ ctx }) => { return await generate2FASecret(ctx.user.id); }), - verify2FASetup: protectedProcedure - .input(apiVerify2FA) - .mutation(async ({ ctx, input }) => { - // const auth = await findAuthById(ctx.user.authId); - // await verify2FA(auth, input.secret, input.pin); - // await updateAuthById(auth.id, { - // is2FAEnabled: true, - // secret: input.secret, - // }); - // return auth; - }), + verify2FASetup: protectedProcedure.mutation(async ({ ctx, input }) => { + // const auth = await findAuthById(ctx.user.authId); + // await verify2FA(auth, input.secret, input.pin); + // await updateAuthById(auth.id, { + // is2FAEnabled: true, + // secret: input.secret, + // }); + // return auth; + }), - verifyLogin2FA: publicProcedure - .input(apiVerifyLogin2FA) - .mutation(async ({ ctx, input }) => { - // const auth = await findAuthById(input.id); + verifyLogin2FA: publicProcedure.mutation(async ({ ctx, input }) => { + // const auth = await findAuthById(input.id); - // await verify2FA(auth, auth.secret || "", input.pin); + // await verify2FA(auth, auth.secret || "", input.pin); - // const session = await lucia.createSession(auth.id, {}); + // const session = await lucia.createSession(auth.id, {}); - // ctx.res.appendHeader( - // "Set-Cookie", - // lucia.createSessionCookie(session.id).serialize(), - // ); + // ctx.res.appendHeader( + // "Set-Cookie", + // lucia.createSessionCookie(session.id).serialize(), + // ); - return true; - }), + return true; + }), disable2FA: protectedProcedure.mutation(async ({ ctx }) => { // const auth = await findAuthById(ctx.user.authId); // await updateAuthById(auth.id, { diff --git a/packages/server/src/db/schema/admin.ts b/packages/server/src/db/schema/admin.ts deleted file mode 100644 index 983f99fd6..000000000 --- a/packages/server/src/db/schema/admin.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { relations } from "drizzle-orm"; -import { - boolean, - integer, - json, - jsonb, - pgTable, - text, -} from "drizzle-orm/pg-core"; -import { createInsertSchema } from "drizzle-zod"; -import { nanoid } from "nanoid"; -import { z } from "zod"; -import { auth } from "./auth"; -import { certificates } from "./certificate"; -import { registry } from "./registry"; -import { certificateType } from "./shared"; -import { sshKeys } from "./ssh-key"; -import { users } from "./user"; - -export const admins = pgTable("admin", { - adminId: text("adminId") - .notNull() - .primaryKey() - .$defaultFn(() => nanoid()), - serverIp: text("serverIp"), - certificateType: certificateType("certificateType").notNull().default("none"), - host: text("host"), - letsEncryptEmail: text("letsEncryptEmail"), - sshPrivateKey: text("sshPrivateKey"), - enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false), - enableLogRotation: boolean("enableLogRotation").notNull().default(false), - authId: text("authId") - .notNull() - .references(() => auth.id, { onDelete: "cascade" }), - createdAt: text("createdAt") - .notNull() - .$defaultFn(() => new Date().toISOString()), - stripeCustomerId: text("stripeCustomerId"), - stripeSubscriptionId: text("stripeSubscriptionId"), - serversQuantity: integer("serversQuantity").notNull().default(0), - - // Metrics - enablePaidFeatures: boolean("enablePaidFeatures").notNull().default(false), - metricsConfig: jsonb("metricsConfig") - .$type<{ - server: { - type: "Dokploy" | "Remote"; - refreshRate: number; - port: number; - token: string; - urlCallback: string; - retentionDays: number; - cronJob: string; - thresholds: { - cpu: number; - memory: number; - }; - }; - containers: { - refreshRate: number; - services: { - include: string[]; - exclude: string[]; - }; - }; - }>() - .notNull() - .default({ - server: { - type: "Dokploy", - refreshRate: 60, - port: 4500, - token: "", - retentionDays: 2, - cronJob: "", - urlCallback: "", - thresholds: { - cpu: 0, - memory: 0, - }, - }, - containers: { - refreshRate: 60, - services: { - include: [], - exclude: [], - }, - }, - }), - cleanupCacheApplications: boolean("cleanupCacheApplications") - .notNull() - .default(false), - cleanupCacheOnPreviews: boolean("cleanupCacheOnPreviews") - .notNull() - .default(false), - cleanupCacheOnCompose: boolean("cleanupCacheOnCompose") - .notNull() - .default(false), -}); - -export const adminsRelations = relations(admins, ({ one, many }) => ({ - auth: one(auth, { - fields: [admins.authId], - references: [auth.id], - }), - users: many(users), - registry: many(registry), - sshKeys: many(sshKeys), - certificates: many(certificates), -})); - -const createSchema = createInsertSchema(admins, { - adminId: z.string(), - enableDockerCleanup: z.boolean().optional(), - sshPrivateKey: z.string().optional(), - certificateType: z.enum(["letsencrypt", "none"]).default("none"), - serverIp: z.string().optional(), - letsEncryptEmail: z.string().optional(), -}); - -export const apiUpdateAdmin = createSchema.partial(); - -export const apiSaveSSHKey = createSchema - .pick({ - sshPrivateKey: true, - }) - .required(); - -export const apiAssignDomain = createSchema - .pick({ - host: true, - certificateType: true, - letsEncryptEmail: true, - }) - .required() - .partial({ - letsEncryptEmail: true, - }); - -export const apiUpdateDockerCleanup = createSchema - .pick({ - enableDockerCleanup: true, - }) - .required() - .extend({ - serverId: z.string().optional(), - }); - -export const apiTraefikConfig = z.object({ - traefikConfig: z.string().min(1), -}); - -export const apiModifyTraefikConfig = z.object({ - path: z.string().min(1), - traefikConfig: z.string().min(1), - serverId: z.string().optional(), -}); -export const apiReadTraefikConfig = z.object({ - path: z.string().min(1), - serverId: z.string().optional(), -}); - -export const apiEnableDashboard = z.object({ - enableDashboard: z.boolean().optional(), - serverId: z.string().optional(), -}); - -export const apiServerSchema = z - .object({ - serverId: z.string().optional(), - }) - .optional(); - -export const apiReadStatsLogs = z.object({ - page: z - .object({ - pageIndex: z.number(), - pageSize: z.number(), - }) - .optional(), - status: z.string().array().optional(), - search: z.string().optional(), - sort: z.object({ id: z.string(), desc: z.boolean() }).optional(), -}); - -export const apiUpdateWebServerMonitoring = z.object({ - metricsConfig: z - .object({ - server: z.object({ - refreshRate: z.number().min(2), - port: z.number().min(1), - token: z.string(), - urlCallback: z.string().url(), - retentionDays: z.number().min(1), - cronJob: z.string().min(1), - thresholds: z.object({ - cpu: z.number().min(0), - memory: z.number().min(0), - }), - }), - containers: z.object({ - refreshRate: z.number().min(2), - services: z.object({ - include: z.array(z.string()).optional(), - exclude: z.array(z.string()).optional(), - }), - }), - }) - .required(), -}); diff --git a/packages/server/src/db/schema/auth.ts b/packages/server/src/db/schema/auth.ts deleted file mode 100644 index 7093a40c3..000000000 --- a/packages/server/src/db/schema/auth.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { getRandomValues } from "node:crypto"; -import { relations } from "drizzle-orm"; -import { boolean, pgEnum, pgTable, text } from "drizzle-orm/pg-core"; -import { createInsertSchema } from "drizzle-zod"; -import { nanoid } from "nanoid"; -import { z } from "zod"; -// import { admins } from "./admin"; -import { users } from "./user"; - -const randomImages = [ - "/avatars/avatar-1.png", - "/avatars/avatar-2.png", - "/avatars/avatar-3.png", - "/avatars/avatar-4.png", - "/avatars/avatar-5.png", - "/avatars/avatar-6.png", - "/avatars/avatar-7.png", - "/avatars/avatar-8.png", - "/avatars/avatar-9.png", - "/avatars/avatar-10.png", - "/avatars/avatar-11.png", - "/avatars/avatar-12.png", -]; - -const generateRandomImage = () => { - return ( - randomImages[ - // @ts-ignore - getRandomValues(new Uint32Array(1))[0] % randomImages.length - ] || "/avatars/avatar-1.png" - ); -}; -export type DatabaseUser = typeof auth.$inferSelect; -export const roles = pgEnum("Roles", ["admin", "user"]); - -export const auth = pgTable("auth", { - id: text("id") - .notNull() - .primaryKey() - .$defaultFn(() => nanoid()), - email: text("email").notNull().unique(), - password: text("password").notNull(), - rol: roles("rol").notNull(), - image: text("image").$defaultFn(() => generateRandomImage()), - secret: text("secret"), - token: text("token"), - is2FAEnabled: boolean("is2FAEnabled").notNull().default(false), - createdAt: text("createdAt") - .notNull() - .$defaultFn(() => new Date().toISOString()), - resetPasswordToken: text("resetPasswordToken"), - resetPasswordExpiresAt: text("resetPasswordExpiresAt"), - confirmationToken: text("confirmationToken"), - confirmationExpiresAt: text("confirmationExpiresAt"), -}); - -export const authRelations = relations(auth, ({ many }) => ({ - // admins: many(admins), - users: many(users), -})); -const createSchema = createInsertSchema(auth, { - email: z.string().email(), - password: z.string().min(8), - rol: z.enum(["admin", "user"]), - image: z.string().optional(), -}); - -export const apiCreateAdmin = createSchema.pick({ - email: true, - password: true, -}); - -export const apiCreateUser = createSchema - .pick({ - password: true, - id: true, - token: true, - }) - .required() - .extend({ - token: z.string().min(1), - }); - -export const apiLogin = createSchema - .pick({ - email: true, - password: true, - }) - .required(); - -export const apiUpdateAuth = createSchema.partial().extend({ - email: z.string().nullable(), - password: z.string().nullable(), - image: z.string().optional(), - currentPassword: z.string().nullable(), -}); - -export const apiUpdateAuthByAdmin = createSchema.partial().extend({ - email: z.string().nullable(), - password: z.string().nullable(), - image: z.string().optional(), - id: z.string().min(1), -}); - -export const apiFindOneAuth = createSchema - .pick({ - id: true, - }) - .required(); - -export const apiVerify2FA = createSchema - .extend({ - pin: z.string().min(6), - secret: z.string().min(1), - }) - .pick({ - pin: true, - secret: true, - }) - .required(); - -export const apiVerifyLogin2FA = createSchema - .extend({ - pin: z.string().min(6), - }) - .pick({ - pin: true, - id: true, - }) - .required(); diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts index dd121b504..80d533508 100644 --- a/packages/server/src/db/schema/certificate.ts +++ b/packages/server/src/db/schema/certificate.ts @@ -4,10 +4,7 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { organization } from "./account"; -import { admins } from "./admin"; import { server } from "./server"; -import { users_temp } from "./user"; -// import { user } from "./user"; import { generateAppName } from "./utils"; export const certificates = pgTable("certificate", { diff --git a/packages/server/src/db/schema/deployment.ts b/packages/server/src/db/schema/deployment.ts index 1be5db5ef..4dfed76b6 100644 --- a/packages/server/src/db/schema/deployment.ts +++ b/packages/server/src/db/schema/deployment.ts @@ -1,4 +1,4 @@ -import { is, relations } from "drizzle-orm"; +import { relations } from "drizzle-orm"; import { type AnyPgColumn, boolean, diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts index 4d8dbc13d..0aeb14902 100644 --- a/packages/server/src/db/schema/destination.ts +++ b/packages/server/src/db/schema/destination.ts @@ -4,10 +4,7 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { organization } from "./account"; -import { admins } from "./admin"; import { backups } from "./backups"; -import { users_temp } from "./user"; -// import { user } from "./user"; export const destinations = pgTable("destination", { destinationId: text("destinationId") @@ -20,7 +17,6 @@ export const destinations = pgTable("destination", { secretAccessKey: text("secretAccessKey").notNull(), bucket: text("bucket").notNull(), region: text("region").notNull(), - // maybe it can be null endpoint: text("endpoint").notNull(), organizationId: text("organizationId") .notNull() @@ -35,10 +31,6 @@ export const destinationsRelations = relations( fields: [destinations.organizationId], references: [organization.id], }), - // user: one(user, { - // fields: [destinations.userId], - // references: [user.id], - // }), }), ); diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index e42557141..dc88131a9 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -4,12 +4,9 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { organization } from "./account"; -import { admins } from "./admin"; import { bitbucket } from "./bitbucket"; import { github } from "./github"; import { gitlab } from "./gitlab"; -import { users_temp } from "./user"; -// import { user } from "./user"; export const gitProviderType = pgEnum("gitProviderType", [ "github", diff --git a/packages/server/src/db/schema/index.ts b/packages/server/src/db/schema/index.ts index 405fa383b..5eb7f369e 100644 --- a/packages/server/src/db/schema/index.ts +++ b/packages/server/src/db/schema/index.ts @@ -1,8 +1,6 @@ export * from "./application"; export * from "./postgres"; export * from "./user"; -export * from "./admin"; -export * from "./auth"; export * from "./project"; export * from "./domain"; export * from "./mariadb"; diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 0179f3c7c..4adce37d1 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -4,8 +4,6 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { organization } from "./account"; -import { users_temp } from "./user"; -// import { user } from "./user"; export const notificationType = pgEnum("notificationType", [ "slack", diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index cf4ea8a86..deeba4aca 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -1,12 +1,9 @@ import { relations } from "drizzle-orm"; - import { pgTable, text } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { organization } from "./account"; -import { admins } from "./admin"; -// import { admins } from "./admin"; import { applications } from "./application"; import { compose } from "./compose"; import { mariadb } from "./mariadb"; @@ -14,7 +11,6 @@ import { mongo } from "./mongo"; import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; -import { users, users_temp } from "./user"; export const projects = pgTable("project", { projectId: text("projectId") diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index aa362a050..35526f90c 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -4,10 +4,7 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { organization } from "./account"; -import { admins } from "./admin"; import { applications } from "./application"; -import { users_temp } from "./user"; -// import { user } from "./user"; /** * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same * database instance for multiple projects. @@ -36,10 +33,6 @@ export const registry = pgTable("registry", { }); export const registryRelations = relations(registry, ({ one, many }) => ({ - // user: one(user, { - // fields: [registry.userId], - // references: [user.id], - // }), applications: many(applications), })); diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index c94fd693e..26bb46326 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -10,9 +10,7 @@ import { import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; - import { organization } from "./account"; -import { admins } from "./admin"; import { applications } from "./application"; import { certificates } from "./certificate"; import { compose } from "./compose"; @@ -23,8 +21,6 @@ import { mysql } from "./mysql"; import { postgres } from "./postgres"; import { redis } from "./redis"; import { sshKeys } from "./ssh-key"; -import { users_temp } from "./user"; -// import { user } from "./user"; import { generateAppName } from "./utils"; export const serverStatus = pgEnum("serverStatus", ["active", "inactive"]); @@ -101,10 +97,6 @@ export const server = pgTable("server", { }); export const serverRelations = relations(server, ({ one, many }) => ({ - // user: one(user, { - // fields: [server.userId], - // references: [user.id], - // }), deployments: many(deployments), sshKey: one(sshKeys, { fields: [server.sshKeyId], diff --git a/packages/server/src/db/schema/session.ts b/packages/server/src/db/schema/session.ts index 4e9d28835..99df9218e 100644 --- a/packages/server/src/db/schema/session.ts +++ b/packages/server/src/db/schema/session.ts @@ -1,6 +1,4 @@ -import { sql } from "drizzle-orm"; import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; -import { auth } from "./auth"; import { users_temp } from "./user"; // OLD TABLE @@ -18,14 +16,3 @@ export const session = pgTable("session_temp", { impersonatedBy: text("impersonated_by"), activeOrganizationId: text("active_organization_id"), }); - -export const sessionTable = pgTable("session", { - id: text("id").primaryKey(), - userId: text("user_id") - .notNull() - .references(() => auth.id, { onDelete: "cascade" }), - expiresAt: timestamp("expires_at", { - withTimezone: true, - mode: "date", - }).notNull(), -}); diff --git a/packages/server/src/db/schema/source.ts b/packages/server/src/db/schema/source.ts deleted file mode 100644 index 6618ced77..000000000 --- a/packages/server/src/db/schema/source.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { pgTable, text } from "drizzle-orm/pg-core"; -import { createInsertSchema } from "drizzle-zod"; -import { nanoid } from "nanoid"; -import { z } from "zod"; - -export const source = pgTable("project", { - projectId: text("projectId") - .notNull() - .primaryKey() - .$defaultFn(() => nanoid()), - name: text("name").notNull(), - description: text("description"), - createdAt: text("createdAt") - .notNull() - .$defaultFn(() => new Date().toISOString()), -}); - -const createSchema = createInsertSchema(source, { - name: z.string().min(1), - description: z.string(), - projectId: z.string(), -}); - -export const apiCreate = createSchema.pick({ - name: true, - description: true, -}); diff --git a/packages/server/src/db/schema/ssh-key.ts b/packages/server/src/db/schema/ssh-key.ts index b705be36e..8a66d6d9d 100644 --- a/packages/server/src/db/schema/ssh-key.ts +++ b/packages/server/src/db/schema/ssh-key.ts @@ -4,12 +4,9 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { sshKeyCreate, sshKeyType } from "../validations"; import { organization } from "./account"; -import { admins } from "./admin"; import { applications } from "./application"; import { compose } from "./compose"; import { server } from "./server"; -import { users_temp } from "./user"; -// import { user } from "./user"; export const sshKeys = pgTable("ssh-key", { sshKeyId: text("sshKeyId") diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index e2755b8f9..33e9e4fcd 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -11,8 +11,6 @@ import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { account, organization } from "./account"; -import { admins } from "./admin"; -import { auth } from "./auth"; import { projects } from "./project"; import { certificateType } from "./shared"; /** @@ -24,50 +22,6 @@ import { certificateType } from "./shared"; // OLD TABLE -export const users = pgTable("user", { - userId: text("userId") - .notNull() - .primaryKey() - .$defaultFn(() => nanoid()), - - token: text("token").notNull(), - isRegistered: boolean("isRegistered").notNull().default(false), - expirationDate: timestamp("expirationDate", { - precision: 3, - mode: "string", - }).notNull(), - createdAt: text("createdAt") - .notNull() - .$defaultFn(() => new Date().toISOString()), - canCreateProjects: boolean("canCreateProjects").notNull().default(false), - canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false), - canCreateServices: boolean("canCreateServices").notNull().default(false), - canDeleteProjects: boolean("canDeleteProjects").notNull().default(false), - canDeleteServices: boolean("canDeleteServices").notNull().default(false), - canAccessToDocker: boolean("canAccessToDocker").notNull().default(false), - canAccessToAPI: boolean("canAccessToAPI").notNull().default(false), - canAccessToGitProviders: boolean("canAccessToGitProviders") - .notNull() - .default(false), - canAccessToTraefikFiles: boolean("canAccessToTraefikFiles") - .notNull() - .default(false), - accessedProjects: text("accesedProjects") - .array() - .notNull() - .default(sql`ARRAY[]::text[]`), - accessedServices: text("accesedServices") - .array() - .notNull() - .default(sql`ARRAY[]::text[]`), - adminId: text("adminId") - .notNull() - .references(() => admins.adminId, { onDelete: "cascade" }), - authId: text("authId") - .notNull() - .references(() => auth.id, { onDelete: "cascade" }), -}); - // TEMP export const users_temp = pgTable("user_temp", { id: text("id") @@ -187,19 +141,11 @@ export const users_temp = pgTable("user_temp", { }); export const usersRelations = relations(users_temp, ({ one, many }) => ({ - // auth: one(auth, { - // fields: [users.authId], - // references: [auth.id], - // }), account: one(account, { fields: [users_temp.id], references: [account.userId], }), organizations: many(organization), - // admin: one(admins, { - // fields: [users.adminId], - // references: [admins.adminId], - // }), projects: many(projects), })); @@ -263,3 +209,91 @@ export const apiFindOneUserByAuth = createSchema // authId: true, }) .required(); +export const apiSaveSSHKey = createSchema + .pick({ + sshPrivateKey: true, + }) + .required(); + +export const apiAssignDomain = createSchema + .pick({ + host: true, + certificateType: true, + letsEncryptEmail: true, + }) + .required() + .partial({ + letsEncryptEmail: true, + }); + +export const apiUpdateDockerCleanup = createSchema + .pick({ + enableDockerCleanup: true, + }) + .required() + .extend({ + serverId: z.string().optional(), + }); + +export const apiTraefikConfig = z.object({ + traefikConfig: z.string().min(1), +}); + +export const apiModifyTraefikConfig = z.object({ + path: z.string().min(1), + traefikConfig: z.string().min(1), + serverId: z.string().optional(), +}); +export const apiReadTraefikConfig = z.object({ + path: z.string().min(1), + serverId: z.string().optional(), +}); + +export const apiEnableDashboard = z.object({ + enableDashboard: z.boolean().optional(), + serverId: z.string().optional(), +}); + +export const apiServerSchema = z + .object({ + serverId: z.string().optional(), + }) + .optional(); + +export const apiReadStatsLogs = z.object({ + page: z + .object({ + pageIndex: z.number(), + pageSize: z.number(), + }) + .optional(), + status: z.string().array().optional(), + search: z.string().optional(), + sort: z.object({ id: z.string(), desc: z.boolean() }).optional(), +}); + +export const apiUpdateWebServerMonitoring = z.object({ + metricsConfig: z + .object({ + server: z.object({ + refreshRate: z.number().min(2), + port: z.number().min(1), + token: z.string(), + urlCallback: z.string().url(), + retentionDays: z.number().min(1), + cronJob: z.string().min(1), + thresholds: z.object({ + cpu: z.number().min(0), + memory: z.number().min(0), + }), + }), + containers: z.object({ + refreshRate: z.number().min(2), + services: z.object({ + include: z.array(z.string()).optional(), + exclude: z.array(z.string()).optional(), + }), + }), + }) + .required(), +}); diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index 41b92587f..4e1b1bb33 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -2,9 +2,7 @@ import { randomBytes } from "node:crypto"; import { db } from "@dokploy/server/db"; import { account, - admins, type apiCreateUserInvitation, - auth, member, organization, users_temp, diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts index 74cd04197..dbdf538b8 100644 --- a/packages/server/src/services/auth.ts +++ b/packages/server/src/services/auth.ts @@ -1,12 +1,6 @@ import { randomBytes } from "node:crypto"; import { db } from "@dokploy/server/db"; -import { - admins, - type apiCreateAdmin, - type apiCreateUser, - auth, - users_temp, -} from "@dokploy/server/db/schema"; +import { users_temp } from "@dokploy/server/db/schema"; import { getPublicIpWithFallback } from "@dokploy/server/wss/utils"; import { TRPCError } from "@trpc/server"; import * as bcrypt from "bcrypt"; @@ -17,89 +11,6 @@ import QRCode from "qrcode"; import { IS_CLOUD } from "../constants"; import { findUserById } from "./admin"; -export type Auth = typeof auth.$inferSelect; - -export const createAdmin = async (input: typeof apiCreateAdmin._type) => { - return await db.transaction(async (tx) => { - const hashedPassword = bcrypt.hashSync(input.password, 10); - const newAuth = await tx - .insert(auth) - .values({ - email: input.email.toLowerCase(), - password: hashedPassword, - rol: "admin", - }) - .returning() - .then((res) => res[0]); - - if (!newAuth) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error creating the user", - }); - } - - await tx - .insert(admins) - .values({ - authId: newAuth.id, - ...(!IS_CLOUD && { - serverIp: - process.env.ADVERTISE_ADDR || (await getPublicIpWithFallback()), - }), - }) - .returning(); - - return newAuth; - }); -}; - -export const createUser = async (input: typeof apiCreateUser._type) => { - return await db.transaction(async (tx) => { - const hashedPassword = bcrypt.hashSync(input.password, 10); - const res = await tx - .update(auth) - .set({ - password: hashedPassword, - }) - .where(eq(auth.id, input.id)) - .returning() - .then((res) => res[0]); - - if (!res) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error creating the user", - }); - } - - const user = await tx - .update(users) - .set({ - isRegistered: true, - expirationDate: undefined, - }) - .where(eq(users.token, input.token)) - .returning() - .then((res) => res[0]); - - return user; - }); -}; - -export const findAuthByEmail = async (email: string) => { - const result = await db.query.auth.findFirst({ - where: eq(auth.email, email), - }); - if (!result) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "User not found", - }); - } - return result; -}; - export const findAuthById = async (authId: string) => { const result = await db.query.users_temp.findFirst({ where: eq(users_temp.id, authId), @@ -117,21 +28,6 @@ export const findAuthById = async (authId: string) => { return result; }; -export const updateAuthById = async ( - authId: string, - authData: Partial, -) => { - const result = await db - .update(auth) - .set({ - ...authData, - }) - .where(eq(auth.id, authId)) - .returning(); - - return result[0]; -}; - export const generate2FASecret = async (userId: string) => { const user = await findUserById(userId); From 90156da5709214b6d0a7463612e4433b0bc015e4 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 16 Feb 2025 14:11:47 -0600 Subject: [PATCH 38/89] refactor: remove tables --- .../server/update-server-config.test.ts | 28 +- apps/dokploy/__test__/traefik/traefik.test.ts | 2 +- .../components/dashboard/projects/show.tsx | 12 +- .../servers/welcome-stripe/create-ssh-key.tsx | 1 + apps/dokploy/drizzle/0073_brave_wolfpack.sql | 5 + apps/dokploy/drizzle/meta/0073_snapshot.json | 4821 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + .../pages/dashboard/settings/profile.tsx | 12 +- .../server/src/utils/traefik/web-server.ts | 6 +- 9 files changed, 4869 insertions(+), 25 deletions(-) create mode 100644 apps/dokploy/drizzle/0073_brave_wolfpack.sql create mode 100644 apps/dokploy/drizzle/meta/0073_snapshot.json diff --git a/apps/dokploy/__test__/traefik/server/update-server-config.test.ts b/apps/dokploy/__test__/traefik/server/update-server-config.test.ts index f7bf3595a..458266dc2 100644 --- a/apps/dokploy/__test__/traefik/server/update-server-config.test.ts +++ b/apps/dokploy/__test__/traefik/server/update-server-config.test.ts @@ -5,7 +5,7 @@ vi.mock("node:fs", () => ({ default: fs, })); -import type { Admin, FileConfig, User } from "@dokploy/server"; +import type { FileConfig, User } from "@dokploy/server"; import { createDefaultServerTraefikConfig, loadOrCreateConfig, @@ -13,7 +13,7 @@ import { } from "@dokploy/server"; import { beforeEach, expect, test, vi } from "vitest"; -const baseAdmin: Partial = { +const baseAdmin: User = { enablePaidFeatures: false, metricsConfig: { containers: { @@ -51,6 +51,30 @@ const baseAdmin: Partial = { serversQuantity: 0, stripeCustomerId: "", stripeSubscriptionId: "", + accessedProjects: [], + accessedServices: [], + banExpires: new Date(), + banned: true, + banReason: "", + canAccessToAPI: false, + canCreateProjects: false, + canDeleteProjects: false, + canDeleteServices: false, + canAccessToDocker: false, + canAccessToSSHKeys: false, + canCreateServices: false, + canAccessToTraefikFiles: false, + canAccessToGitProviders: false, + email: "", + expirationDate: "", + id: "", + isRegistered: false, + name: "", + createdAt2: new Date().toISOString(), + emailVerified: false, + image: "", + token: "", + updatedAt: new Date(), }; beforeEach(() => { diff --git a/apps/dokploy/__test__/traefik/traefik.test.ts b/apps/dokploy/__test__/traefik/traefik.test.ts index d05dda81d..955103dec 100644 --- a/apps/dokploy/__test__/traefik/traefik.test.ts +++ b/apps/dokploy/__test__/traefik/traefik.test.ts @@ -26,7 +26,7 @@ const baseApp: ApplicationNested = { previewWildcard: "", project: { env: "", - adminId: "", + organizationId: "", name: "", description: "", createdAt: "", diff --git a/apps/dokploy/components/dashboard/projects/show.tsx b/apps/dokploy/components/dashboard/projects/show.tsx index 206137f56..b9c96d314 100644 --- a/apps/dokploy/components/dashboard/projects/show.tsx +++ b/apps/dokploy/components/dashboard/projects/show.tsx @@ -52,14 +52,6 @@ export const ShowProjects = () => { const utils = api.useUtils(); const { data, isLoading } = api.project.all.useQuery(); const { data: auth } = api.auth.get.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: auth?.id || "", - }, - { - enabled: !!auth?.id && auth?.role === "member", - }, - ); const { mutateAsync } = api.project.remove.useMutation(); const [searchQuery, setSearchQuery] = useState(""); @@ -91,7 +83,7 @@ export const ShowProjects = () => { - {(auth?.role === "owner" || user?.canCreateProjects) && ( + {(auth?.role === "owner" || auth?.user?.canCreateProjects) && (
@@ -294,7 +286,7 @@ export const ShowProjects = () => { onClick={(e) => e.stopPropagation()} > {(auth?.role === "owner" || - user?.canDeleteProjects) && ( + auth?.user?.canDeleteProjects) && ( { description: "Used on Dokploy Cloud", privateKey: keys.privateKey, publicKey: keys.publicKey, + organizationId: "", }); await refetch(); } catch (error) { diff --git a/apps/dokploy/drizzle/0073_brave_wolfpack.sql b/apps/dokploy/drizzle/0073_brave_wolfpack.sql new file mode 100644 index 000000000..05bf5cb47 --- /dev/null +++ b/apps/dokploy/drizzle/0073_brave_wolfpack.sql @@ -0,0 +1,5 @@ +DROP TABLE "user" CASCADE;--> statement-breakpoint +DROP TABLE "admin" CASCADE;--> statement-breakpoint +DROP TABLE "auth" CASCADE;--> statement-breakpoint +DROP TABLE "session" CASCADE;--> statement-breakpoint +DROP TYPE "public"."Roles"; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0073_snapshot.json b/apps/dokploy/drizzle/meta/0073_snapshot.json new file mode 100644 index 000000000..e61b447ca --- /dev/null +++ b/apps/dokploy/drizzle/meta/0073_snapshot.json @@ -0,0 +1,4821 @@ +{ + "id": "07170d9f-4d67-48f5-890f-393043396973", + "prevId": "4eb71c0e-5bdb-427b-b198-39b1059dcd16", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_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": "''" + }, + "token": { + "name": "token", + "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()" + }, + "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[]" + }, + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "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": "no action", + "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 + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "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 + } + }, + "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 + } + }, + "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" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bitbucket": { + "name": "bitbucket", + "schema": "", + "columns": { + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "bitbucketUsername": { + "name": "bitbucketUsername", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "appPassword": { + "name": "appPassword", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketWorkspaceName": { + "name": "bitbucketWorkspaceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bitbucket_gitProviderId_git_provider_gitProviderId_fk": { + "name": "bitbucket_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "bitbucket", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.github": { + "name": "github", + "schema": "", + "columns": { + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "githubAppName": { + "name": "githubAppName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubAppId": { + "name": "githubAppId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "githubClientId": { + "name": "githubClientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubClientSecret": { + "name": "githubClientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubInstallationId": { + "name": "githubInstallationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubPrivateKey": { + "name": "githubPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubWebhookSecret": { + "name": "githubWebhookSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "github_gitProviderId_git_provider_gitProviderId_fk": { + "name": "github_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "github", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gitlab": { + "name": "gitlab", + "schema": "", + "columns": { + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "gitlabUrl": { + "name": "gitlabUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'https://gitlab.com'" + }, + "application_id": { + "name": "application_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_name": { + "name": "group_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "gitlab_gitProviderId_git_provider_gitProviderId_fk": { + "name": "gitlab_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "gitlab", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.server": { + "name": "server", + "schema": "", + "columns": { + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'root'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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.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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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 + } + }, + "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": "no action", + "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": "no action", + "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": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index aae9728d3..b591cceda 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -512,6 +512,13 @@ "when": 1739672367223, "tag": "0072_lazy_pixie", "breakpoints": true + }, + { + "idx": 73, + "version": "7", + "when": 1739735739336, + "tag": "0073_brave_wolfpack", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index 73b90c722..bfae14e62 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -14,21 +14,15 @@ import superjson from "superjson"; const Page = () => { const { data } = api.auth.get.useQuery(); - const { data: user } = api.user.get.useQuery( - { - authId: data?.id || "", - }, - { - enabled: !!data?.id && data?.role === "member", - }, - ); const { data: isCloud } = api.settings.isCloud.useQuery(); return (
- {(user?.canAccessToAPI || data?.role === "owner") && } + {(data?.user?.canAccessToAPI || data?.role === "owner") && ( + + )} {isCloud && }
diff --git a/packages/server/src/utils/traefik/web-server.ts b/packages/server/src/utils/traefik/web-server.ts index 0aa4d35d5..76733e751 100644 --- a/packages/server/src/utils/traefik/web-server.ts +++ b/packages/server/src/utils/traefik/web-server.ts @@ -1,14 +1,14 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { paths } from "@dokploy/server/constants"; -import type { Admin } from "@dokploy/server/services/admin"; import { dump, load } from "js-yaml"; import { loadOrCreateConfig, writeTraefikConfig } from "./application"; import type { FileConfig } from "./file-types"; import type { MainTraefikConfig } from "./types"; +import type { User } from "@dokploy/server/services/user"; export const updateServerTraefik = ( - admin: Admin | null, + user: User | null, newHost: string | null, ) => { const appName = "dokploy"; @@ -22,7 +22,7 @@ export const updateServerTraefik = ( if (currentRouterConfig && newHost) { currentRouterConfig.rule = `Host(\`${newHost}\`)`; - if (admin?.certificateType === "letsencrypt") { + if (user?.certificateType === "letsencrypt") { config.http.routers[`${appName}-router-app-secure`] = { ...currentRouterConfig, entryPoints: ["websecure"], From e1632cbdb3cb6688be1dda359585cd2e985a40f3 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 16 Feb 2025 15:32:57 -0600 Subject: [PATCH 39/89] refactor: update user and authentication schema with two-factor support --- .../settings/users/add-permissions.tsx | 4 +- .../dashboard/settings/users/show-users.tsx | 8 +- .../settings/web-server/update-server-ip.tsx | 5 +- apps/dokploy/drizzle/0066_yielding_echo.sql | 11 +- ...fpack.sql => 0073_polite_miss_america.sql} | 1 + apps/dokploy/drizzle/meta/0066_snapshot.json | 57 +++++++++ apps/dokploy/drizzle/meta/0067_snapshot.json | 57 +++++++++ apps/dokploy/drizzle/meta/0068_snapshot.json | 57 +++++++++ apps/dokploy/drizzle/meta/0069_snapshot.json | 57 +++++++++ apps/dokploy/drizzle/meta/0070_snapshot.json | 57 +++++++++ apps/dokploy/drizzle/meta/0071_snapshot.json | 57 +++++++++ apps/dokploy/drizzle/meta/0072_snapshot.json | 57 +++++++++ apps/dokploy/drizzle/meta/0073_snapshot.json | 59 ++++++++- apps/dokploy/drizzle/meta/_journal.json | 4 +- apps/dokploy/pages/dashboard/docker.tsx | 2 +- .../dashboard/settings/git-providers.tsx | 2 +- .../pages/dashboard/settings/profile.tsx | 2 +- .../pages/dashboard/settings/ssh-keys.tsx | 2 +- apps/dokploy/pages/dashboard/swarm.tsx | 2 +- apps/dokploy/pages/dashboard/traefik.tsx | 2 +- apps/dokploy/pages/swagger.tsx | 12 +- apps/dokploy/server/api/routers/admin.ts | 27 ++-- apps/dokploy/server/api/routers/auth.ts | 11 +- apps/dokploy/server/api/routers/settings.ts | 50 ++++---- apps/dokploy/server/api/routers/user.ts | 46 ++++--- packages/server/auth-schema.ts | 14 ++- packages/server/src/db/schema/account.ts | 9 ++ packages/server/src/db/schema/user.ts | 31 ++++- packages/server/src/lib/auth.ts | 7 +- packages/server/src/services/admin.ts | 117 +++++------------- packages/server/src/services/auth.ts | 7 +- packages/server/src/utils/backups/index.ts | 1 - .../server/src/utils/traefik/web-server.ts | 2 +- 33 files changed, 657 insertions(+), 180 deletions(-) rename apps/dokploy/drizzle/{0073_brave_wolfpack.sql => 0073_polite_miss_america.sql} (90%) diff --git a/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx b/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx index 7c1f50375..bde2e71ca 100644 --- a/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx +++ b/apps/dokploy/components/dashboard/settings/users/add-permissions.tsx @@ -52,7 +52,7 @@ interface Props { export const AddUserPermissions = ({ userId }: Props) => { const { data: projects } = api.project.all.useQuery(); - const { data, refetch } = api.user.byUserId.useQuery( + const { data, refetch } = api.auth.one.useQuery( { userId, }, @@ -92,7 +92,7 @@ export const AddUserPermissions = ({ userId }: Props) => { const onSubmit = async (data: AddPermissions) => { await mutateAsync({ - userId, + id: userId, canCreateServices: data.canCreateServices, canCreateProjects: data.canCreateProjects, canDeleteServices: data.canDeleteServices, diff --git a/apps/dokploy/components/dashboard/settings/users/show-users.tsx b/apps/dokploy/components/dashboard/settings/users/show-users.tsx index 8aa2a37b4..e0ffac139 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-users.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-users.tsx @@ -104,9 +104,9 @@ export const ShowUsers = () => { - {user.user.is2FAEnabled + {/* {user.user.is2FAEnabled ? "2FA Enabled" - : "2FA Not Enabled"} + : "2FA Not Enabled"} */} {/* @@ -156,7 +156,7 @@ export const ShowUsers = () => { /> )} */} - {user.role !== "owner" && ( + {/* {user.role !== "owner" && ( { Delete User - )} + )} */} diff --git a/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx b/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx index dd3f81fdc..07103d5ba 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx @@ -1,5 +1,4 @@ import { AlertBlock } from "@/components/shared/alert-block"; -import { CodeEditor } from "@/components/shared/code-editor"; import { Button } from "@/components/ui/button"; import { Dialog, @@ -47,11 +46,11 @@ interface Props { export const UpdateServerIp = ({ children, serverId }: Props) => { const [isOpen, setIsOpen] = useState(false); - const { data } = api.admin.one.useQuery(); + const { data } = api.user.get.useQuery(); const { data: ip } = api.server.publicIp.useQuery(); const { mutateAsync, isLoading, error, isError } = - api.admin.update.useMutation(); + api.user.update.useMutation(); const form = useForm({ defaultValues: { diff --git a/apps/dokploy/drizzle/0066_yielding_echo.sql b/apps/dokploy/drizzle/0066_yielding_echo.sql index c66e2318b..d69a4c659 100644 --- a/apps/dokploy/drizzle/0066_yielding_echo.sql +++ b/apps/dokploy/drizzle/0066_yielding_echo.sql @@ -16,6 +16,7 @@ CREATE TABLE "user_temp" ( "canAccessToTraefikFiles" boolean DEFAULT false NOT NULL, "accesedProjects" text[] DEFAULT ARRAY[]::text[] NOT NULL, "accesedServices" text[] DEFAULT ARRAY[]::text[] NOT NULL, + "two_factor_enabled" boolean DEFAULT false NOT NULL, "email" text NOT NULL, "email_verified" boolean NOT NULL, "image" text, @@ -113,6 +114,13 @@ CREATE TABLE "verification" ( "created_at" timestamp, "updated_at" timestamp ); + +CREATE TABLE "two_factor" ( + "id" text PRIMARY KEY NOT NULL, + "secret" text NOT NULL, + "backup_codes" text NOT NULL, + "user_id" text NOT NULL +); --> statement-breakpoint ALTER TABLE "certificate" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint ALTER TABLE "notification" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint @@ -124,4 +132,5 @@ ALTER TABLE "invitation" ADD CONSTRAINT "invitation_organization_id_organization ALTER TABLE "invitation" ADD CONSTRAINT "invitation_inviter_id_user_temp_id_fk" FOREIGN KEY ("inviter_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_temp_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action; \ No newline at end of file +ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_temp_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action; +ALTER TABLE "two_factor" ADD CONSTRAINT "two_factor_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint diff --git a/apps/dokploy/drizzle/0073_brave_wolfpack.sql b/apps/dokploy/drizzle/0073_polite_miss_america.sql similarity index 90% rename from apps/dokploy/drizzle/0073_brave_wolfpack.sql rename to apps/dokploy/drizzle/0073_polite_miss_america.sql index 05bf5cb47..030f8a883 100644 --- a/apps/dokploy/drizzle/0073_brave_wolfpack.sql +++ b/apps/dokploy/drizzle/0073_polite_miss_america.sql @@ -1,3 +1,4 @@ +--> statement-breakpoint DROP TABLE "user" CASCADE;--> statement-breakpoint DROP TABLE "admin" CASCADE;--> statement-breakpoint DROP TABLE "auth" CASCADE;--> statement-breakpoint diff --git a/apps/dokploy/drizzle/meta/0066_snapshot.json b/apps/dokploy/drizzle/meta/0066_snapshot.json index bcb7807a7..06b899346 100644 --- a/apps/dokploy/drizzle/meta/0066_snapshot.json +++ b/apps/dokploy/drizzle/meta/0066_snapshot.json @@ -1010,6 +1010,12 @@ "notNull": true, "default": "ARRAY[]::text[]" }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, "email": { "name": "email", "type": "text", @@ -5045,6 +5051,57 @@ "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": "", diff --git a/apps/dokploy/drizzle/meta/0067_snapshot.json b/apps/dokploy/drizzle/meta/0067_snapshot.json index 69d4a4ee8..be43b406b 100644 --- a/apps/dokploy/drizzle/meta/0067_snapshot.json +++ b/apps/dokploy/drizzle/meta/0067_snapshot.json @@ -1010,6 +1010,12 @@ "notNull": true, "default": "ARRAY[]::text[]" }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, "email": { "name": "email", "type": "text", @@ -5045,6 +5051,57 @@ "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": "", diff --git a/apps/dokploy/drizzle/meta/0068_snapshot.json b/apps/dokploy/drizzle/meta/0068_snapshot.json index 02e33084f..2139b1321 100644 --- a/apps/dokploy/drizzle/meta/0068_snapshot.json +++ b/apps/dokploy/drizzle/meta/0068_snapshot.json @@ -1010,6 +1010,12 @@ "notNull": true, "default": "ARRAY[]::text[]" }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, "email": { "name": "email", "type": "text", @@ -5045,6 +5051,57 @@ "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": "", diff --git a/apps/dokploy/drizzle/meta/0069_snapshot.json b/apps/dokploy/drizzle/meta/0069_snapshot.json index 41b53582e..d3e5be98b 100644 --- a/apps/dokploy/drizzle/meta/0069_snapshot.json +++ b/apps/dokploy/drizzle/meta/0069_snapshot.json @@ -1018,6 +1018,12 @@ "notNull": true, "default": "ARRAY[]::text[]" }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, "email": { "name": "email", "type": "text", @@ -5053,6 +5059,57 @@ "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": "", diff --git a/apps/dokploy/drizzle/meta/0070_snapshot.json b/apps/dokploy/drizzle/meta/0070_snapshot.json index 681bded7e..e3864a19c 100644 --- a/apps/dokploy/drizzle/meta/0070_snapshot.json +++ b/apps/dokploy/drizzle/meta/0070_snapshot.json @@ -1018,6 +1018,12 @@ "notNull": true, "default": "ARRAY[]::text[]" }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, "email": { "name": "email", "type": "text", @@ -5205,6 +5211,57 @@ "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": "", diff --git a/apps/dokploy/drizzle/meta/0071_snapshot.json b/apps/dokploy/drizzle/meta/0071_snapshot.json index 4214343a0..cce94ce93 100644 --- a/apps/dokploy/drizzle/meta/0071_snapshot.json +++ b/apps/dokploy/drizzle/meta/0071_snapshot.json @@ -1018,6 +1018,12 @@ "notNull": true, "default": "ARRAY[]::text[]" }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, "email": { "name": "email", "type": "text", @@ -5205,6 +5211,57 @@ "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": "", diff --git a/apps/dokploy/drizzle/meta/0072_snapshot.json b/apps/dokploy/drizzle/meta/0072_snapshot.json index 2f38d98d9..53797c0b9 100644 --- a/apps/dokploy/drizzle/meta/0072_snapshot.json +++ b/apps/dokploy/drizzle/meta/0072_snapshot.json @@ -1018,6 +1018,12 @@ "notNull": true, "default": "ARRAY[]::text[]" }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, "email": { "name": "email", "type": "text", @@ -5053,6 +5059,57 @@ "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": "", diff --git a/apps/dokploy/drizzle/meta/0073_snapshot.json b/apps/dokploy/drizzle/meta/0073_snapshot.json index e61b447ca..6b65df2f7 100644 --- a/apps/dokploy/drizzle/meta/0073_snapshot.json +++ b/apps/dokploy/drizzle/meta/0073_snapshot.json @@ -1,5 +1,5 @@ { - "id": "07170d9f-4d67-48f5-890f-393043396973", + "id": "e357a19a-dd1e-4843-b567-0c0243ade7a8", "prevId": "4eb71c0e-5bdb-427b-b198-39b1059dcd16", "version": "7", "dialect": "postgresql", @@ -858,6 +858,12 @@ "notNull": true, "default": "ARRAY[]::text[]" }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, "email": { "name": "email", "type": "text", @@ -4602,6 +4608,57 @@ "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": "", diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index b591cceda..39903f65a 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -516,8 +516,8 @@ { "idx": 73, "version": "7", - "when": 1739735739336, - "tag": "0073_brave_wolfpack", + "when": 1739740193879, + "tag": "0073_polite_miss_america", "breakpoints": true } ] diff --git a/apps/dokploy/pages/dashboard/docker.tsx b/apps/dokploy/pages/dashboard/docker.tsx index 202935aa6..fee202fce 100644 --- a/apps/dokploy/pages/dashboard/docker.tsx +++ b/apps/dokploy/pages/dashboard/docker.tsx @@ -54,7 +54,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); if (user.role === "member") { - const userR = await helpers.user.get.fetch({ + const userR = await helpers.user.one.fetch({ userId: user.id, }); diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx index d0d9ca7f1..cfded9915 100644 --- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx +++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx @@ -50,7 +50,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); await helpers.settings.isCloud.prefetch(); if (user.role === "member") { - const userR = await helpers.user.get.fetch({ + const userR = await helpers.user.one.fetch({ userId: user.id, }); diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index bfae14e62..a84fb4dba 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -57,7 +57,7 @@ export async function getServerSideProps( await helpers.settings.isCloud.prefetch(); await helpers.auth.get.prefetch(); if (user?.role === "member") { - // const userR = await helpers.user.get.fetch({ + // const userR = await helpers.user.one.fetch({ // userId: user.id, // }); // await helpers.user.byAuthId.prefetch({ diff --git a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx index f3b9cf1b8..c97df7ba1 100644 --- a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx +++ b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx @@ -51,7 +51,7 @@ export async function getServerSideProps( await helpers.settings.isCloud.prefetch(); if (user.role === "member") { - const userR = await helpers.user.get.fetch({ + const userR = await helpers.user.one.fetch({ userId: user.id, }); diff --git a/apps/dokploy/pages/dashboard/swarm.tsx b/apps/dokploy/pages/dashboard/swarm.tsx index 8278ed181..3b59c47b0 100644 --- a/apps/dokploy/pages/dashboard/swarm.tsx +++ b/apps/dokploy/pages/dashboard/swarm.tsx @@ -54,7 +54,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); if (user.role === "member") { - const userR = await helpers.user.get.fetch({ + const userR = await helpers.user.one.fetch({ userId: user.id, }); diff --git a/apps/dokploy/pages/dashboard/traefik.tsx b/apps/dokploy/pages/dashboard/traefik.tsx index 6939eabdf..8dcd3f084 100644 --- a/apps/dokploy/pages/dashboard/traefik.tsx +++ b/apps/dokploy/pages/dashboard/traefik.tsx @@ -54,7 +54,7 @@ export async function getServerSideProps( await helpers.project.all.prefetch(); if (user.role === "member") { - const userR = await helpers.user.get.fetch({ + const userR = await helpers.user.one.fetch({ userId: user.id, }); diff --git a/apps/dokploy/pages/swagger.tsx b/apps/dokploy/pages/swagger.tsx index 765194f1c..e4a6fac8d 100644 --- a/apps/dokploy/pages/swagger.tsx +++ b/apps/dokploy/pages/swagger.tsx @@ -38,7 +38,7 @@ const Home: NextPage = () => { export default Home; export async function getServerSideProps(context: GetServerSidePropsContext) { const { req, res } = context; - const { user, session } = await validateRequest(context.req, context.res); + const { user, session } = await validateRequest(context.req); if (!user) { return { redirect: { @@ -53,17 +53,17 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { req: req as any, res: res as any, db: null as any, - session: session, - user: user, + session: session as any, + user: user as any, }, transformer: superjson, }); if (user.role === "member") { - const result = await helpers.user.byAuthId.fetch({ - authId: user.id, + const userR = await helpers.user.one.fetch({ + userId: user.id, }); - if (!result.canAccessToAPI) { + if (!userR.canAccessToAPI) { return { redirect: { permanent: true, diff --git a/apps/dokploy/server/api/routers/admin.ts b/apps/dokploy/server/api/routers/admin.ts index 695cdb336..97e3a1fa4 100644 --- a/apps/dokploy/server/api/routers/admin.ts +++ b/apps/dokploy/server/api/routers/admin.ts @@ -35,17 +35,22 @@ export const adminRouter = createTRPCRouter({ ...rest, }; }), - update: adminProcedure.mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "member") { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to update this admin", - }); - } - const { id } = await findUserById(ctx.user.id); - // @ts-ignore - return updateAdmin(id, input); - }), + update: adminProcedure + .input( + z.object({ + enableDockerCleanup: z.boolean(), + }), + ) + .mutation(async ({ input, ctx }) => { + if (ctx.user.rol === "member") { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not allowed to update this admin", + }); + } + const user = await findUserById(ctx.user.ownerId); + return updateUser(user.id, {}); + }), createUserInvitation: adminProcedure .input(apiCreateUserInvitation) .mutation(async ({ input, ctx }) => { diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index ad2fab07e..4cfbe71a2 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -266,10 +266,13 @@ export const authRouter = createTRPCRouter({ verifyToken: protectedProcedure.mutation(async () => { return true; }), - one: adminProcedure.query(async ({ input }) => { - const auth = await findAuthById(input.id); - return auth; - }), + one: adminProcedure + .input(z.object({ userId: z.string().min(1) })) + .query(async ({ input }) => { + // TODO: Check if the user is admin or member + const user = await findUserById(input.userId); + return user; + }), generate2FASecret: protectedProcedure.query(async ({ ctx }) => { return await generate2FASecret(ctx.user.id); diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index cd1f8bd3b..ee69da22d 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -22,9 +22,8 @@ import { cleanUpUnusedVolumes, execAsync, execAsyncRemote, - findAdmin, - findAdminById, findServerById, + findUserById, getDokployImage, getDokployImageTag, getUpdateData, @@ -50,6 +49,7 @@ import { updateLetsEncryptEmail, updateServerById, updateServerTraefik, + updateUser, writeConfig, writeMainConfig, writeTraefikConfigInPath, @@ -163,7 +163,7 @@ export const settingsRouter = createTRPCRouter({ if (IS_CLOUD) { return true; } - await updateAdmin(ctx.user.authId, { + await updateUser(ctx.user.id, { sshPrivateKey: input.sshPrivateKey, }); @@ -175,7 +175,7 @@ export const settingsRouter = createTRPCRouter({ if (IS_CLOUD) { return true; } - const admin = await updateAdmin(ctx.user.authId, { + const user = await updateUser(ctx.user.id, { host: input.host, ...(input.letsEncryptEmail && { letsEncryptEmail: input.letsEncryptEmail, @@ -183,25 +183,25 @@ export const settingsRouter = createTRPCRouter({ certificateType: input.certificateType, }); - if (!admin) { + if (!user) { throw new TRPCError({ code: "NOT_FOUND", - message: "Admin not found", + message: "User not found", }); } - updateServerTraefik(admin, input.host); + updateServerTraefik(user, input.host); if (input.letsEncryptEmail) { updateLetsEncryptEmail(input.letsEncryptEmail); } - return admin; + return user; }), cleanSSHPrivateKey: adminProcedure.mutation(async ({ ctx }) => { if (IS_CLOUD) { return true; } - await updateAdmin(ctx.user.authId, { + await updateUser(ctx.user.id, { sshPrivateKey: null, }); return true; @@ -216,7 +216,7 @@ export const settingsRouter = createTRPCRouter({ const server = await findServerById(input.serverId); - if (server.adminId !== ctx.user.adminId) { + if (server.organizationId !== ctx.session?.activeOrganizationId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this server", @@ -245,7 +245,7 @@ export const settingsRouter = createTRPCRouter({ await cleanUpUnusedImages(server.serverId); await cleanUpDockerBuilder(server.serverId); await cleanUpSystemPrune(server.serverId); - await sendDockerCleanupNotifications(server.adminId); + await sendDockerCleanupNotifications(server.organizationId); }); } } else { @@ -261,19 +261,11 @@ export const settingsRouter = createTRPCRouter({ } } } else if (!IS_CLOUD) { - const admin = await findAdminById(ctx.user.adminId); - - if (admin.adminId !== ctx.user.adminId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to access this admin", - }); - } - const adminUpdated = await updateAdmin(ctx.user.authId, { + const userUpdated = await updateUser(ctx.user.id, { enableDockerCleanup: input.enableDockerCleanup, }); - if (adminUpdated?.enableDockerCleanup) { + if (userUpdated?.enableDockerCleanup) { scheduleJob("docker-cleanup", "0 0 * * *", async () => { console.log( `Docker Cleanup ${new Date().toLocaleString()}] Running...`, @@ -281,7 +273,9 @@ export const settingsRouter = createTRPCRouter({ await cleanUpUnusedImages(); await cleanUpDockerBuilder(); await cleanUpSystemPrune(); - await sendDockerCleanupNotifications(admin.adminId); + await sendDockerCleanupNotifications( + ctx.session.activeOrganizationId, + ); }); } else { const currentJob = scheduledJobs["docker-cleanup"]; @@ -383,7 +377,7 @@ export const settingsRouter = createTRPCRouter({ .query(async ({ ctx, input }) => { try { if (ctx.user.rol === "member") { - const canAccess = await canAccessToTraefikFiles(ctx.user.authId); + const canAccess = await canAccessToTraefikFiles(ctx.user.id); if (!canAccess) { throw new TRPCError({ code: "UNAUTHORIZED" }); @@ -401,7 +395,7 @@ export const settingsRouter = createTRPCRouter({ .input(apiModifyTraefikConfig) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - const canAccess = await canAccessToTraefikFiles(ctx.user.authId); + const canAccess = await canAccessToTraefikFiles(ctx.user.id); if (!canAccess) { throw new TRPCError({ code: "UNAUTHORIZED" }); @@ -419,7 +413,7 @@ export const settingsRouter = createTRPCRouter({ .input(apiReadTraefikConfig) .query(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - const canAccess = await canAccessToTraefikFiles(ctx.user.authId); + const canAccess = await canAccessToTraefikFiles(ctx.user.id); if (!canAccess) { throw new TRPCError({ code: "UNAUTHORIZED" }); @@ -427,12 +421,12 @@ export const settingsRouter = createTRPCRouter({ } return readConfigInPath(input.path, input.serverId); }), - getIp: protectedProcedure.query(async () => { + getIp: protectedProcedure.query(async ({ ctx }) => { if (IS_CLOUD) { return true; } - const admin = await findAdmin(); - return admin.serverIp; + const user = await findUserById(ctx.user.ownerId); + return user.serverIp; }), getOpenApiDocument: protectedProcedure.query( diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index f4de4d9f7..addbdb23c 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -1,7 +1,12 @@ import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema"; -import { findUserByAuthId, findUserById } from "@dokploy/server"; +import { + findUserByAuthId, + findUserById, + updateUser, + verify2FA, +} from "@dokploy/server"; import { db } from "@dokploy/server/db"; -import { member } from "@dokploy/server/db/schema"; +import { apiUpdateUser, member } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { z } from "zod"; @@ -15,7 +20,7 @@ export const userRouter = createTRPCRouter({ }, }); }), - get: protectedProcedure + one: protectedProcedure .input( z.object({ userId: z.string(), @@ -31,16 +36,27 @@ export const userRouter = createTRPCRouter({ // } return user; }), - // byUserId: protectedProcedure - // .input(apiFindOneUser) - // .query(async ({ input, ctx }) => { - // const user = await findUserById(input.userId); - // if (user.adminId !== ctx.user.adminId) { - // throw new TRPCError({ - // code: "UNAUTHORIZED", - // message: "You are not allowed to access this user", - // }); - // } - // return user; - // }), + get: protectedProcedure.query(async ({ ctx }) => { + return await findUserById(ctx.user.id); + }), + update: protectedProcedure + .input(apiUpdateUser) + .mutation(async ({ input, ctx }) => { + return await updateUser(ctx.user.id, input); + }), + verify2FASetup: protectedProcedure + .input( + z.object({ + secret: z.string(), + pin: z.string(), + }), + ) + .mutation(async ({ ctx, input }) => { + const user = await findUserById(ctx.user.id); + await verify2FA(user, input.secret, input.pin); + await updateUser(user.id, { + secret: input.secret, + }); + return user; + }), }); diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index 38839afbf..045a75235 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,9 +1,9 @@ import { - boolean, - integer, pgTable, text, + integer, timestamp, + boolean, } from "drizzle-orm/pg-core"; export const users_temp = pgTable("users_temp", { @@ -14,6 +14,7 @@ export const users_temp = pgTable("users_temp", { image: text("image"), createdAt: timestamp("created_at").notNull(), updatedAt: timestamp("updated_at").notNull(), + twoFactorEnabled: boolean("two_factor_enabled"), role: text("role").notNull(), ownerId: text("owner_id").notNull(), }); @@ -59,6 +60,15 @@ export const verification = pgTable("verification", { updatedAt: timestamp("updated_at"), }); +export const twoFactor = pgTable("two_factor", { + id: text("id").primaryKey(), + secret: text("secret").notNull(), + backupCodes: text("backup_codes").notNull(), + userId: text("user_id") + .notNull() + .references(() => users_temp.id, { onDelete: "cascade" }), +}); + export const organization = pgTable("organization", { id: text("id").primaryKey(), name: text("name").notNull(), diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 3bb7dcfca..1c0b10e9a 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -119,3 +119,12 @@ export const invitationRelations = relations(invitation, ({ one }) => ({ references: [organization.id], }), })); + +export const twoFactor = pgTable("two_factor", { + id: text("id").primaryKey(), + secret: text("secret").notNull(), + backupCodes: text("backup_codes").notNull(), + userId: text("user_id") + .notNull() + .references(() => users_temp.id, { onDelete: "cascade" }), +}); diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 33e9e4fcd..a8f4cbcf0 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -59,10 +59,12 @@ export const users_temp = pgTable("user_temp", { .array() .notNull() .default(sql`ARRAY[]::text[]`), + // authId: text("authId") // .notNull() // .references(() => auth.id, { onDelete: "cascade" }), // Auth + twoFactorEnabled: boolean("two_factor_enabled"), email: text("email").notNull().unique(), emailVerified: boolean("email_verified").notNull(), image: text("image"), @@ -151,10 +153,8 @@ export const usersRelations = relations(users_temp, ({ one, many }) => ({ const createSchema = createInsertSchema(users_temp, { id: z.string().min(1), - // authId: z.string().min(1), token: z.string().min(1), isRegistered: z.boolean().optional(), - // adminId: z.string(), accessedProjects: z.array(z.string()).optional(), accessedServices: z.array(z.string()).optional(), canCreateProjects: z.boolean().optional(), @@ -297,3 +297,30 @@ export const apiUpdateWebServerMonitoring = z.object({ }) .required(), }); + +export const apiUpdateUser = createSchema.partial().extend({ + metricsConfig: z + .object({ + server: z.object({ + type: z.enum(["Dokploy", "Remote"]), + refreshRate: z.number(), + port: z.number(), + token: z.string(), + urlCallback: z.string(), + retentionDays: z.number(), + cronJob: z.string(), + thresholds: z.object({ + cpu: z.number(), + memory: z.number(), + }), + }), + containers: z.object({ + refreshRate: z.number(), + services: z.object({ + include: z.array(z.string()), + exclude: z.array(z.string()), + }), + }), + }) + .optional(), +}); diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index a7fbde9a5..fece335b2 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -2,7 +2,11 @@ import type { IncomingMessage } from "node:http"; import * as bcrypt from "bcrypt"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; -import { createAuthMiddleware, organization } from "better-auth/plugins"; +import { + createAuthMiddleware, + organization, + twoFactor, +} from "better-auth/plugins"; import { desc, eq } from "drizzle-orm"; import { db } from "../db"; import * as schema from "../db/schema"; @@ -85,6 +89,7 @@ export const auth = betterAuth({ }, plugins: [ + twoFactor(), organization({ async sendInvitationEmail(data, request) { const inviteLink = `https://example.com/accept-invitation/${data.id}`; diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index 4e1b1bb33..53de805e9 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -12,41 +12,40 @@ import * as bcrypt from "bcrypt"; import { eq } from "drizzle-orm"; import { IS_CLOUD } from "../constants"; -export type Admin = typeof users_temp.$inferSelect; +export type User = typeof users_temp.$inferSelect; export const createInvitation = async ( input: typeof apiCreateUserInvitation._type, adminId: string, ) => { - await db.transaction(async (tx) => { - const result = await tx - .insert(auth) - .values({ - email: input.email.toLowerCase(), - rol: "user", - password: bcrypt.hashSync("01231203012312", 10), - }) - .returning() - .then((res) => res[0]); - - if (!result) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error creating the user", - }); - } - const expiresIn24Hours = new Date(); - expiresIn24Hours.setDate(expiresIn24Hours.getDate() + 1); - const token = randomBytes(32).toString("hex"); - // await tx - // .insert(users) - // .values({ - // adminId: adminId, - // authId: result.id, - // token, - // expirationDate: expiresIn24Hours.toISOString(), - // }) - // .returning(); - }); + // await db.transaction(async (tx) => { + // const result = await tx + // .insert(auth) + // .values({ + // email: input.email.toLowerCase(), + // rol: "user", + // password: bcrypt.hashSync("01231203012312", 10), + // }) + // .returning() + // .then((res) => res[0]); + // if (!result) { + // throw new TRPCError({ + // code: "BAD_REQUEST", + // message: "Error creating the user", + // }); + // } + // const expiresIn24Hours = new Date(); + // expiresIn24Hours.setDate(expiresIn24Hours.getDate() + 1); + // const token = randomBytes(32).toString("hex"); + // await tx + // .insert(users) + // .values({ + // adminId: adminId, + // authId: result.id, + // token, + // expirationDate: expiresIn24Hours.toISOString(), + // }) + // .returning(); + // }); }; export const findUserById = async (userId: string) => { @@ -65,7 +64,7 @@ export const findUserById = async (userId: string) => { return user; }; -export const updateUser = async (userId: string, userData: Partial) => { +export const updateUser = async (userId: string, userData: Partial) => { const user = await db .update(users_temp) .set({ @@ -80,7 +79,7 @@ export const updateUser = async (userId: string, userData: Partial) => { export const updateAdminById = async ( adminId: string, - adminData: Partial, + adminData: Partial, ) => { // const admin = await db // .update(admins) @@ -93,13 +92,6 @@ export const updateAdminById = async ( // return admin; }; -export const findAdminById = async (userId: string) => { - const admin = await db.query.admins.findFirst({ - // where: eq(admins.userId, userId), - }); - return admin; -}; - export const isAdminPresent = async () => { const admin = await db.query.member.findFirst({ where: eq(member.role, "owner"), @@ -113,33 +105,6 @@ export const isAdminPresent = async () => { return true; }; -export const findAdminByAuthId = async (authId: string) => { - const admin = await db.query.admins.findFirst({ - where: eq(admins.authId, authId), - with: { - users: true, - }, - }); - if (!admin) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Admin not found", - }); - } - return admin; -}; - -export const findAdmin = async () => { - const admin = await db.query.admins.findFirst({}); - if (!admin) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Admin not found", - }); - } - return admin; -}; - export const getUserByToken = async (token: string) => { // const user = await db.query.users.findFirst({ // where: eq(users.token, token), @@ -171,24 +136,6 @@ export const removeUserById = async (userId: string) => { .then((res) => res[0]); }; -export const removeAdminByAuthId = async (authId: string) => { - const admin = await findAdminByAuthId(authId); - if (!admin) return null; - - // First delete all associated users - const users = admin.users; - - // for (const user of users) { - // await removeUserById(user.id); - // } - // Then delete the auth record which will cascade delete the admin - return await db - .delete(auth) - .where(eq(auth.id, authId)) - .returning() - .then((res) => res[0]); -}; - export const getDokployUrl = async () => { if (IS_CLOUD) { return "https://app.dokploy.com"; diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts index dbdf538b8..8f3564be9 100644 --- a/packages/server/src/services/auth.ts +++ b/packages/server/src/services/auth.ts @@ -10,6 +10,7 @@ import { TOTP } from "otpauth"; import QRCode from "qrcode"; import { IS_CLOUD } from "../constants"; import { findUserById } from "./admin"; +import type { User } from "./user"; export const findAuthById = async (authId: string) => { const result = await db.query.users_temp.findFirst({ @@ -51,11 +52,7 @@ export const generate2FASecret = async (userId: string) => { }; }; -export const verify2FA = async ( - auth: Omit, - secret: string, - pin: string, -) => { +export const verify2FA = async (auth: User, secret: string, pin: string) => { const totp = new TOTP({ issuer: "Dokploy", label: `${auth?.email}`, diff --git a/packages/server/src/utils/backups/index.ts b/packages/server/src/utils/backups/index.ts index 922232a0c..d1b87d692 100644 --- a/packages/server/src/utils/backups/index.ts +++ b/packages/server/src/utils/backups/index.ts @@ -1,4 +1,3 @@ -import { findAdmin } from "@dokploy/server/services/admin"; import { getAllServers } from "@dokploy/server/services/server"; import { scheduleJob } from "node-schedule"; import { db } from "../../db/index"; diff --git a/packages/server/src/utils/traefik/web-server.ts b/packages/server/src/utils/traefik/web-server.ts index 76733e751..78046c673 100644 --- a/packages/server/src/utils/traefik/web-server.ts +++ b/packages/server/src/utils/traefik/web-server.ts @@ -1,11 +1,11 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { paths } from "@dokploy/server/constants"; +import type { User } from "@dokploy/server/services/user"; import { dump, load } from "js-yaml"; import { loadOrCreateConfig, writeTraefikConfig } from "./application"; import type { FileConfig } from "./file-types"; import type { MainTraefikConfig } from "./types"; -import type { User } from "@dokploy/server/services/user"; export const updateServerTraefik = ( user: User | null, From 0e8e92c71574e2bb8e5609fedcf8a5f8fb8405c6 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 16 Feb 2025 20:56:50 -0600 Subject: [PATCH 40/89] refactor: add 2fa --- .../dashboard/settings/users/show-users.tsx | 59 ++++++++++--------- apps/dokploy/drizzle/0067_migrate-data.sql | 49 +++++++++++++-- apps/dokploy/pages/invitation.tsx | 9 ++- packages/server/auth-schema.ts | 4 +- packages/server/src/lib/auth.ts | 11 +++- packages/server/src/services/admin.ts | 39 ++++++------ .../server/src/utils/access-log/handler.ts | 13 ++-- 7 files changed, 119 insertions(+), 65 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/users/show-users.tsx b/apps/dokploy/components/dashboard/settings/users/show-users.tsx index e0ffac139..7e3ed6f15 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-users.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-users.tsx @@ -78,7 +78,9 @@ export const ShowUsers = () => { Email Role 2FA - {/* Status */} + + Is Registered + Created At @@ -104,15 +106,15 @@ export const ShowUsers = () => { - {/* {user.user.is2FAEnabled - ? "2FA Enabled" - : "2FA Not Enabled"} */} + {user.user.twoFactorEnabled + ? "Enabled" + : "Disabled"} + + + {user.user.isRegistered || user.role === "owner" + ? "Registered" + : "Not Registered"} - {/* - - {format(new Date(user.createdAt), "PPpp")} - - */} {format(new Date(user.createdAt), "PPpp")} @@ -134,29 +136,30 @@ export const ShowUsers = () => { Actions - {/* {!user.isRegistered && ( - { - copy( - `${origin}/invitation?token=${user.token}`, - ); - toast.success( - "Invitation Copied to clipboard", - ); - }} - > - Copy Invitation - - )} */} + {!user.user.isRegistered && + user.role !== "owner" && ( + { + copy( + `${origin}/invitation?token=${user.user.token}`, + ); + toast.success( + "Invitation Copied to clipboard", + ); + }} + > + Copy Invitation + + )} - {/* {user.isRegistered && ( + {user.user.isRegistered && ( - )} */} + )} - {/* {user.role !== "owner" && ( + {user.role !== "owner" && ( { Delete User - )} */} + )} diff --git a/apps/dokploy/drizzle/0067_migrate-data.sql b/apps/dokploy/drizzle/0067_migrate-data.sql index 074de9fa6..4b860a32f 100644 --- a/apps/dokploy/drizzle/0067_migrate-data.sql +++ b/apps/dokploy/drizzle/0067_migrate-data.sql @@ -25,7 +25,8 @@ WITH inserted_users AS ( "stripeSubscriptionId", "serversQuantity", "expirationDate", - "createdAt" + "createdAt", + "two_factor_enabled" ) SELECT a."adminId", @@ -50,11 +51,30 @@ WITH inserted_users AS ( a."stripeSubscriptionId", a."serversQuantity", NOW() + INTERVAL '1 year', - NOW() + NOW(), + COALESCE(auth."is2FAEnabled", false) FROM admin a JOIN auth ON auth.id = a."authId" RETURNING * ), +inserted_two_factor_admin AS ( + -- Insertar registros en two_factor para admins con 2FA habilitado + INSERT INTO two_factor ( + id, + secret, + backup_codes, + user_id + ) + SELECT + gen_random_uuid(), + auth.secret, + gen_random_uuid()::text, + a."adminId" + FROM admin a + JOIN auth ON auth.id = a."authId" + WHERE auth."is2FAEnabled" = true + RETURNING * +), inserted_accounts AS ( -- Insertar cuentas para los admins INSERT INTO account ( @@ -120,7 +140,8 @@ inserted_members AS ( "canDeleteServices", "accesedProjects", "accesedServices", - "expirationDate" + "expirationDate", + "two_factor_enabled" ) SELECT u."userId", @@ -141,7 +162,8 @@ inserted_members AS ( COALESCE(u."canDeleteServices", false), COALESCE(u."accesedProjects", '{}'), COALESCE(u."accesedServices", '{}'), - NOW() + INTERVAL '1 year' + NOW() + INTERVAL '1 year', + COALESCE(auth."is2FAEnabled", false) FROM "user" u JOIN admin a ON u."adminId" = a."adminId" JOIN auth ON auth.id = u."authId" @@ -173,6 +195,25 @@ inserted_member_accounts AS ( JOIN auth ON auth.id = u."authId" RETURNING * ), +inserted_two_factor_members AS ( + -- Insertar registros en two_factor para miembros con 2FA habilitado + INSERT INTO two_factor ( + id, + secret, + backup_codes, + user_id + ) + SELECT + gen_random_uuid(), + auth.secret, + gen_random_uuid()::text, + u."userId" + FROM "user" u + JOIN admin a ON u."adminId" = a."adminId" + JOIN auth ON auth.id = u."authId" + WHERE auth."is2FAEnabled" = true + RETURNING * +), inserted_admin_members AS ( -- Insertar miembros en las organizaciones (admins como owners) INSERT INTO member ( diff --git a/apps/dokploy/pages/invitation.tsx b/apps/dokploy/pages/invitation.tsx index 77f9f2493..e8bfc3fc3 100644 --- a/apps/dokploy/pages/invitation.tsx +++ b/apps/dokploy/pages/invitation.tsx @@ -27,6 +27,7 @@ import { type ReactElement, useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; +import superjson from "superjson"; const registerSchema = z .object({ @@ -98,9 +99,9 @@ const Invitation = ({ token, invitation, isCloud }: Props) => { }); useEffect(() => { - if (data?.auth?.email) { + if (data?.email) { form.reset({ - email: data?.auth?.email || "", + email: data?.email || "", password: "", confirmPassword: "", }); @@ -109,7 +110,7 @@ const Invitation = ({ token, invitation, isCloud }: Props) => { const onSubmit = async (values: Register) => { await mutateAsync({ - id: data?.authId, + id: data?.id, password: values.password, token: token, }) @@ -254,6 +255,7 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) { const { query } = ctx; const token = query.token; + console.log("query", query); if (typeof token !== "string") { return { @@ -266,6 +268,7 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) { try { const invitation = await getUserByToken(token); + console.log("invitation", invitation); if (invitation.isExpired) { return { diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index 045a75235..2500b615f 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,9 +1,9 @@ import { + boolean, + integer, pgTable, text, - integer, timestamp, - boolean, } from "drizzle-orm/pg-core"; export const users_temp = pgTable("users_temp", { diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index fece335b2..cc144345b 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -16,7 +16,16 @@ export const auth = betterAuth({ provider: "pg", schema: schema, }), - + socialProviders: { + github: { + clientId: process.env.GITHUB_CLIENT_ID as string, + clientSecret: process.env.GITHUB_CLIENT_SECRET as string, + }, + google: { + clientId: process.env.GOOGLE_CLIENT_ID as string, + clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, + }, + }, emailAndPassword: { enabled: true, diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index 53de805e9..eee6bb37c 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -106,26 +106,25 @@ export const isAdminPresent = async () => { }; export const getUserByToken = async (token: string) => { - // const user = await db.query.users.findFirst({ - // where: eq(users.token, token), - // with: { - // auth: { - // columns: { - // password: false, - // }, - // }, - // }, - // }); - // if (!user) { - // throw new TRPCError({ - // code: "NOT_FOUND", - // message: "Invitation not found", - // }); - // } - // return { - // ...user, - // isExpired: user.isRegistered, - // }; + const user = await db.query.users_temp.findFirst({ + where: eq(users_temp.token, token), + columns: { + id: true, + email: true, + token: true, + isRegistered: true, + }, + }); + if (!user) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Invitation not found", + }); + } + return { + ...user, + isExpired: user.isRegistered, + }; }; export const removeUserById = async (userId: string) => { diff --git a/packages/server/src/utils/access-log/handler.ts b/packages/server/src/utils/access-log/handler.ts index 574717323..30b18ea42 100644 --- a/packages/server/src/utils/access-log/handler.ts +++ b/packages/server/src/utils/access-log/handler.ts @@ -29,16 +29,15 @@ class LogRotationManager { } private async getStateFromDB(): Promise { - const setting = await db.query.admins.findFirst({}); - return setting?.enableLogRotation ?? false; + // const setting = await db.query.admins.findFirst({}); + // return setting?.enableLogRotation ?? false; } private async setStateInDB(active: boolean): Promise { - const admin = await db.query.admins.findFirst({}); - - if (!admin) { - return; - } + // const admin = await db.query.admins.findFirst({}); + // if (!admin) { + // return; + // } // await updateAdmin(admin?.authId, { // enableLogRotation: active, // }); From 7abe060fcf3dea922d9850acfed97385fe5a0f14 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Mon, 17 Feb 2025 00:07:36 -0600 Subject: [PATCH 41/89] feat: enhance two-factor authentication and auth client implementation --- .../server/update-server-config.test.ts | 1 + .../dashboard/projects/handle-project.tsx | 2 +- .../components/dashboard/search-command.tsx | 2 +- .../git/github/add-github-provider.tsx | 2 +- .../settings/profile/disable-2fa.tsx | 127 ++++-- .../dashboard/settings/profile/enable-2fa.tsx | 365 +++++++++++++----- .../settings/profile/profile-form.tsx | 7 +- .../settings/users/add-invitation.tsx | 166 ++++++++ .../dashboard/settings/users/add-user.tsx | 2 +- .../settings/users/show-invitations.tsx | 191 +++++++++ .../dashboard/settings/users/show-users.tsx | 2 +- apps/dokploy/components/layouts/side.tsx | 2 +- apps/dokploy/components/layouts/user-nav.tsx | 2 +- apps/dokploy/drizzle/0067_migrate-data.sql | 12 +- apps/dokploy/lib/{auth.ts => auth-client.ts} | 3 +- .../accept-invitation/[accept-invitation].tsx | 2 +- .../pages/dashboard/settings/users.tsx | 2 + apps/dokploy/pages/index.tsx | 307 +++++++++------ apps/dokploy/pages/invitation.tsx | 2 +- apps/dokploy/pages/register.tsx | 2 +- .../server/api/routers/organization.ts | 8 +- packages/server/package.json | 1 + packages/server/src/lib/auth.ts | 1 + packages/server/src/services/auth.ts | 159 +++++++- pnpm-lock.yaml | 3 + 25 files changed, 1103 insertions(+), 270 deletions(-) create mode 100644 apps/dokploy/components/dashboard/settings/users/add-invitation.tsx create mode 100644 apps/dokploy/components/dashboard/settings/users/show-invitations.tsx rename apps/dokploy/lib/{auth.ts => auth-client.ts} (67%) diff --git a/apps/dokploy/__test__/traefik/server/update-server-config.test.ts b/apps/dokploy/__test__/traefik/server/update-server-config.test.ts index 458266dc2..49d71bc4c 100644 --- a/apps/dokploy/__test__/traefik/server/update-server-config.test.ts +++ b/apps/dokploy/__test__/traefik/server/update-server-config.test.ts @@ -75,6 +75,7 @@ const baseAdmin: User = { image: "", token: "", updatedAt: new Date(), + twoFactorEnabled: false, }; beforeEach(() => { diff --git a/apps/dokploy/components/dashboard/projects/handle-project.tsx b/apps/dokploy/components/dashboard/projects/handle-project.tsx index fb2cbf67a..492c03c93 100644 --- a/apps/dokploy/components/dashboard/projects/handle-project.tsx +++ b/apps/dokploy/components/dashboard/projects/handle-project.tsx @@ -21,7 +21,7 @@ import { import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; -import { authClient } from "@/lib/auth"; +import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { PlusIcon, SquarePen } from "lucide-react"; diff --git a/apps/dokploy/components/dashboard/search-command.tsx b/apps/dokploy/components/dashboard/search-command.tsx index 8158a9ca8..7ea53d72f 100644 --- a/apps/dokploy/components/dashboard/search-command.tsx +++ b/apps/dokploy/components/dashboard/search-command.tsx @@ -18,7 +18,7 @@ import { CommandList, CommandSeparator, } from "@/components/ui/command"; -import { authClient } from "@/lib/auth"; +import { authClient } from "@/lib/auth-client"; import { type Services, extractServices, diff --git a/apps/dokploy/components/dashboard/settings/git/github/add-github-provider.tsx b/apps/dokploy/components/dashboard/settings/git/github/add-github-provider.tsx index 5f2cb934d..819d8e703 100644 --- a/apps/dokploy/components/dashboard/settings/git/github/add-github-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/github/add-github-provider.tsx @@ -10,7 +10,7 @@ import { } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; -import { authClient } from "@/lib/auth"; +import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; import { format } from "date-fns"; import { useEffect, useState } from "react"; diff --git a/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx b/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx index 2850332ef..79306bf18 100644 --- a/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx @@ -1,52 +1,131 @@ import { AlertDialog, - AlertDialogAction, - AlertDialogCancel, AlertDialogContent, AlertDialogDescription, - AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useState } from "react"; +import { useForm } from "react-hook-form"; import { toast } from "sonner"; +import { z } from "zod"; + +const PasswordSchema = z.object({ + password: z.string().min(8, { + message: "Password is required", + }), +}); + +type PasswordForm = z.infer; export const Disable2FA = () => { const utils = api.useUtils(); - const { mutateAsync, isLoading } = api.auth.disable2FA.useMutation(); + const [isLoading, setIsLoading] = useState(false); + + const form = useForm({ + resolver: zodResolver(PasswordSchema), + defaultValues: { + password: "", + }, + }); + + const handleSubmit = async (formData: PasswordForm) => { + setIsLoading(true); + try { + const result = await authClient.twoFactor.disable({ + password: formData.password, + }); + + if (result.error) { + form.setError("password", { + message: result.error.message, + }); + toast.error(result.error.message); + return; + } + + toast.success("2FA disabled successfully"); + utils.auth.get.invalidate(); + } catch (error) { + form.setError("password", { + message: "Connection error. Please try again.", + }); + toast.error("Connection error. Please try again."); + } finally { + setIsLoading(false); + } + }; + return ( - + Are you absolutely sure? - This action cannot be undone. This will permanently delete the 2FA + This action cannot be undone. This will permanently disable + Two-Factor Authentication for your account. - - Cancel - { - await mutateAsync() - .then(() => { - utils.auth.get.invalidate(); - toast.success("2FA Disabled"); - }) - .catch(() => { - toast.error("Error disabling 2FA"); - }); - }} + + + - Confirm - - + ( + + Password + + + + + Enter your password to disable 2FA + + + + )} + /> +
+ + +
+ +
); diff --git a/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx b/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx index cf5910b8a..b1da3ec1a 100644 --- a/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx @@ -17,144 +17,315 @@ import { FormLabel, FormMessage, } from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; import { InputOTP, InputOTPGroup, InputOTPSlot, } from "@/components/ui/input-otp"; +import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { AlertTriangle, Fingerprint } from "lucide-react"; -import { useEffect } from "react"; +import { Fingerprint, QrCode } from "lucide-react"; +import QRCode from "qrcode"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; -const Enable2FASchema = z.object({ +const PasswordSchema = z.object({ + password: z.string().min(8, { + message: "Password is required", + }), +}); + +const PinSchema = z.object({ pin: z.string().min(6, { message: "Pin is required", }), }); -type Enable2FA = z.infer; +type PasswordForm = z.infer; +type PinForm = z.infer; + +type TwoFactorEnableResponse = { + totpURI: string; + backupCodes: string[]; +}; + +type TwoFactorSetupData = { + qrCodeUrl: string; + secret: string; + totpURI: string; +}; export const Enable2FA = () => { const utils = api.useUtils(); + const { data: session } = authClient.useSession(); + const [data, setData] = useState(null); + const [backupCodes, setBackupCodes] = useState([]); + const [isDialogOpen, setIsDialogOpen] = useState(false); + const [step, setStep] = useState<"password" | "verify">("password"); + const [isPasswordLoading, setIsPasswordLoading] = useState(false); - const { data } = api.auth.generate2FASecret.useQuery(undefined, { - refetchOnWindowFocus: false, + const handlePasswordSubmit = async (formData: PasswordForm) => { + setIsPasswordLoading(true); + try { + const { data: enableData } = await authClient.twoFactor.enable({ + password: formData.password, + }); + + if (!enableData) { + throw new Error("No data received from server"); + } + + if (enableData.backupCodes) { + setBackupCodes(enableData.backupCodes); + } + + if (enableData.totpURI) { + const qrCodeUrl = await QRCode.toDataURL(enableData.totpURI); + + setData({ + qrCodeUrl, + secret: enableData.totpURI.split("secret=")[1]?.split("&")[0] || "", + totpURI: enableData.totpURI, + }); + + setStep("verify"); + toast.success("Scan the QR code with your authenticator app"); + } else { + throw new Error("No TOTP URI received from server"); + } + } catch (error) { + toast.error( + error instanceof Error ? error.message : "Error setting up 2FA", + ); + passwordForm.setError("password", { + message: "Error verifying password", + }); + } finally { + setIsPasswordLoading(false); + } + }; + + const handleVerifySubmit = async (formData: PinForm) => { + try { + const result = await authClient.twoFactor.verifyTotp({ + code: formData.pin, + }); + + if (result.error) { + if (result.error.code === "INVALID_TWO_FACTOR_AUTHENTICATION") { + pinForm.setError("pin", { + message: "Invalid code. Please try again.", + }); + toast.error("Invalid verification code"); + return; + } + + throw result.error; + } + + if (!result.data) { + throw new Error("No response received from server"); + } + + toast.success("2FA configured successfully"); + utils.auth.get.invalidate(); + setIsDialogOpen(false); + } catch (error) { + if (error instanceof Error) { + const errorMessage = + error.message === "Failed to fetch" + ? "Connection error. Please check your internet connection." + : error.message; + + pinForm.setError("pin", { + message: errorMessage, + }); + toast.error(errorMessage); + } else { + pinForm.setError("pin", { + message: "Error verifying code", + }); + toast.error("Error verifying 2FA code"); + } + } + }; + + const passwordForm = useForm({ + resolver: zodResolver(PasswordSchema), + defaultValues: { + password: "", + }, }); - const { mutateAsync, isLoading, error, isError } = - api.auth.verify2FASetup.useMutation(); - - const form = useForm({ + const pinForm = useForm({ + resolver: zodResolver(PinSchema), defaultValues: { pin: "", }, - resolver: zodResolver(Enable2FASchema), }); useEffect(() => { - form.reset({ - pin: "", - }); - }, [form, form.reset, form.formState.isSubmitSuccessful]); + if (!isDialogOpen) { + setStep("password"); + setData(null); + setBackupCodes([]); + passwordForm.reset(); + pinForm.reset(); + } + }, [isDialogOpen, passwordForm, pinForm]); - const onSubmit = async (formData: Enable2FA) => { - await mutateAsync({ - pin: formData.pin, - secret: data?.secret || "", - }) - .then(async () => { - toast.success("2FA Verified"); - utils.auth.get.invalidate(); - }) - .catch(() => { - toast.error("Error verifying the 2FA"); - }); - }; return ( - + - + 2FA Setup - Add a 2FA to your account + + {step === "password" + ? "Enter your password to begin 2FA setup" + : "Scan the QR code and verify with your authenticator app"} + - {isError && ( -
- - - {error?.message} - -
- )} -
- -
- - {data?.qrCodeUrl ? "Scan the QR code to add 2FA" : ""} - - qrCode -
- - {data?.secret ? `Secret: ${data?.secret}` : ""} - -
-
- ( - - Pin - - - - - - - - - - - - - - Please enter the 6 digits code provided by your - authenticator app. - - - - )} - /> - - - - - - + ( + + Password + + + + + Enter your password to enable 2FA + + + + )} + /> + + + + ) : ( +
+ +
+ {data?.qrCodeUrl ? ( + <> +
+ + + Scan this QR code with your authenticator app + + 2FA QR Code +
+ + Can't scan the QR code? + + + {data.secret} + +
+
+ + {backupCodes && backupCodes.length > 0 && ( +
+

Backup Codes

+
+ {backupCodes.map((code, index) => ( + + {code} + + ))} +
+

+ Save these backup codes in a secure place. You can use + them to access your account if you lose access to your + authenticator device. +

+
+ )} + + ) : ( +
+ +
+ )} +
+ + ( + + Verification Code + + + + + + + + + + + + + + Enter the 6-digit code from your authenticator app + + + + )} + /> + + + + + )}
); diff --git a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx index 4da97d18b..944b2ff49 100644 --- a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx @@ -1,4 +1,5 @@ import { AlertBlock } from "@/components/shared/alert-block"; +import { DialogAction } from "@/components/shared/dialog-action"; import { Button } from "@/components/ui/button"; import { Card, @@ -17,6 +18,7 @@ import { } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; +import { authClient } from "@/lib/auth-client"; import { generateSHA256Hash } from "@/lib/utils"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; @@ -54,6 +56,9 @@ const randomImages = [ ]; export const ProfileForm = () => { + const utils = api.useUtils(); + const { mutateAsync: disable2FA, isLoading: isDisabling } = + api.auth.disable2FA.useMutation(); const { data, refetch, isLoading } = api.auth.get.useQuery(); const { mutateAsync, @@ -130,7 +135,7 @@ export const ProfileForm = () => { {t("settings.profile.description")}
- {!data?.is2FAEnabled ? : } + {!data?.user.twoFactorEnabled ? : } diff --git a/apps/dokploy/components/dashboard/settings/users/add-invitation.tsx b/apps/dokploy/components/dashboard/settings/users/add-invitation.tsx new file mode 100644 index 000000000..d05409fb7 --- /dev/null +++ b/apps/dokploy/components/dashboard/settings/users/add-invitation.tsx @@ -0,0 +1,166 @@ +import { AlertBlock } from "@/components/shared/alert-block"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { authClient } from "@/lib/auth-client"; +import { api } from "@/utils/api"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { PlusIcon } from "lucide-react"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import { toast } from "sonner"; +import { z } from "zod"; + +const addInvitation = z.object({ + email: z + .string() + .min(1, "Email is required") + .email({ message: "Invalid email" }), + role: z.enum(["member", "admin"]), +}); + +type AddInvitation = z.infer; + +export const AddInvitation = () => { + const [open, setOpen] = useState(false); + const utils = api.useUtils(); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const { data: activeOrganization } = authClient.useActiveOrganization(); + + const form = useForm({ + defaultValues: { + email: "", + role: "member", + }, + resolver: zodResolver(addInvitation), + }); + useEffect(() => { + form.reset(); + }, [form, form.formState.isSubmitSuccessful, form.reset]); + + const onSubmit = async (data: AddInvitation) => { + setIsLoading(true); + const result = await authClient.organization.inviteMember({ + email: data.email.toLowerCase(), + role: data.role, + organizationId: activeOrganization?.id, + }); + + if (result.error) { + setError(result.error.message || ""); + } else { + toast.success("Invitation created"); + setError(null); + setOpen(false); + } + + utils.organization.allInvitations.invalidate(); + setIsLoading(false); + }; + return ( + + + + + + + Add Invitation + Invite a new user + + {error && {error}} + +
+ + { + return ( + + Email + + + + + This will be the email of the new user + + + + ); + }} + /> + + { + return ( + + Role + + + Select the role for the new user + + + + ); + }} + /> + + + + + +
+
+ ); +}; diff --git a/apps/dokploy/components/dashboard/settings/users/add-user.tsx b/apps/dokploy/components/dashboard/settings/users/add-user.tsx index fa1c8bf95..78c8ebdb4 100644 --- a/apps/dokploy/components/dashboard/settings/users/add-user.tsx +++ b/apps/dokploy/components/dashboard/settings/users/add-user.tsx @@ -19,7 +19,7 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; -import { authClient } from "@/lib/auth"; +import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { PlusIcon } from "lucide-react"; diff --git a/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx new file mode 100644 index 000000000..e6067e7b3 --- /dev/null +++ b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx @@ -0,0 +1,191 @@ +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { + Table, + TableBody, + TableCaption, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { authClient } from "@/lib/auth-client"; +import { api } from "@/utils/api"; +import { format } from "date-fns"; +import { Mail, MoreHorizontal, Users } from "lucide-react"; +import { Loader2 } from "lucide-react"; +import { toast } from "sonner"; +import { AddInvitation } from "./add-invitation"; + +export const ShowInvitations = () => { + const { data, isLoading, refetch } = + api.organization.allInvitations.useQuery(); + const { mutateAsync, isLoading: isRemoving } = + api.admin.removeUser.useMutation(); + + return ( +
+ +
+ + + + Invitations + + + Create invitations to your organization. + + + + {isLoading ? ( +
+ Loading... + +
+ ) : ( + <> + {data?.length === 0 ? ( +
+ + + Invite users to your organization + + +
+ ) : ( +
+ + See all invitations + + + Email + Role + Status + + Expires At + + Actions + + + + {data?.map((invitation) => { + return ( + + + {invitation.email} + + + + {invitation.role} + + + + + {invitation.status} + + + + {format(new Date(invitation.expiresAt), "PPpp")} + + + + + + + + + + Actions + + + {/* { + copy( + `${origin}/invitation?token=${user.user.token}`, + ); + toast.success( + "Invitation Copied to clipboard", + ); + }} + > + Copy Invitation + */} + {invitation.status === "pending" && ( + { + const result = + await authClient.organization.cancelInvitation( + { + invitationId: invitation.id, + }, + ); + + if (result.error) { + toast.error(result.error.message); + } else { + toast.success("Invitation deleted"); + refetch(); + } + }} + > + Cancel Invitation + + )} + + + + + ); + })} + +
+ +
+ +
+
+ )} + + )} +
+
+
+
+ ); +}; diff --git a/apps/dokploy/components/dashboard/settings/users/show-users.tsx b/apps/dokploy/components/dashboard/settings/users/show-users.tsx index 7e3ed6f15..40fbea0d3 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-users.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-users.tsx @@ -153,7 +153,7 @@ export const ShowUsers = () => {
)} - {user.user.isRegistered && ( + {user.role !== "owner" && ( diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index cc27dc389..bd10352f5 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -495,7 +495,7 @@ import { DropdownMenuShortcut, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import { authClient } from "@/lib/auth"; +import { authClient } from "@/lib/auth-client"; import { toast } from "sonner"; import { AddOrganization } from "../dashboard/organization/handle-organization"; import { DialogAction } from "../shared/dialog-action"; diff --git a/apps/dokploy/components/layouts/user-nav.tsx b/apps/dokploy/components/layouts/user-nav.tsx index d4de2019c..49fc92e59 100644 --- a/apps/dokploy/components/layouts/user-nav.tsx +++ b/apps/dokploy/components/layouts/user-nav.tsx @@ -15,7 +15,7 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { authClient } from "@/lib/auth"; +import { authClient } from "@/lib/auth-client"; import { Languages } from "@/lib/languages"; import { api } from "@/utils/api"; import useLocale from "@/utils/hooks/use-locale"; diff --git a/apps/dokploy/drizzle/0067_migrate-data.sql b/apps/dokploy/drizzle/0067_migrate-data.sql index 4b860a32f..279acbfb9 100644 --- a/apps/dokploy/drizzle/0067_migrate-data.sql +++ b/apps/dokploy/drizzle/0067_migrate-data.sql @@ -26,7 +26,8 @@ WITH inserted_users AS ( "serversQuantity", "expirationDate", "createdAt", - "two_factor_enabled" + "two_factor_enabled", + "isRegistered" ) SELECT a."adminId", @@ -52,7 +53,8 @@ WITH inserted_users AS ( a."serversQuantity", NOW() + INTERVAL '1 year', NOW(), - COALESCE(auth."is2FAEnabled", false) + COALESCE(auth."is2FAEnabled", false), + true FROM admin a JOIN auth ON auth.id = a."authId" RETURNING * @@ -141,7 +143,8 @@ inserted_members AS ( "accesedProjects", "accesedServices", "expirationDate", - "two_factor_enabled" + "two_factor_enabled", + "isRegistered" ) SELECT u."userId", @@ -163,7 +166,8 @@ inserted_members AS ( COALESCE(u."accesedProjects", '{}'), COALESCE(u."accesedServices", '{}'), NOW() + INTERVAL '1 year', - COALESCE(auth."is2FAEnabled", false) + COALESCE(auth."is2FAEnabled", false), + COALESCE(u."isRegistered", false) FROM "user" u JOIN admin a ON u."adminId" = a."adminId" JOIN auth ON auth.id = u."authId" diff --git a/apps/dokploy/lib/auth.ts b/apps/dokploy/lib/auth-client.ts similarity index 67% rename from apps/dokploy/lib/auth.ts rename to apps/dokploy/lib/auth-client.ts index 12c3cc3e7..9a184959b 100644 --- a/apps/dokploy/lib/auth.ts +++ b/apps/dokploy/lib/auth-client.ts @@ -1,7 +1,8 @@ import { organizationClient } from "better-auth/client/plugins"; +import { twoFactorClient } from "better-auth/client/plugins"; import { createAuthClient } from "better-auth/react"; export const authClient = createAuthClient({ // baseURL: "http://localhost:3000", // the base url of your auth server - plugins: [organizationClient()], + plugins: [organizationClient(), twoFactorClient()], }); diff --git a/apps/dokploy/pages/accept-invitation/[accept-invitation].tsx b/apps/dokploy/pages/accept-invitation/[accept-invitation].tsx index 6936a802d..bc60d970f 100644 --- a/apps/dokploy/pages/accept-invitation/[accept-invitation].tsx +++ b/apps/dokploy/pages/accept-invitation/[accept-invitation].tsx @@ -1,5 +1,5 @@ import { Button } from "@/components/ui/button"; -import { authClient } from "@/lib/auth"; +import { authClient } from "@/lib/auth-client"; import { useRouter } from "next/router"; export const AcceptInvitation = () => { diff --git a/apps/dokploy/pages/dashboard/settings/users.tsx b/apps/dokploy/pages/dashboard/settings/users.tsx index 1c53c82b1..7945bf86d 100644 --- a/apps/dokploy/pages/dashboard/settings/users.tsx +++ b/apps/dokploy/pages/dashboard/settings/users.tsx @@ -1,3 +1,4 @@ +import { ShowInvitations } from "@/components/dashboard/settings/users/show-invitations"; import { ShowUsers } from "@/components/dashboard/settings/users/show-users"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; @@ -12,6 +13,7 @@ const Page = () => { return (
+
); }; diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index b85b1c7e1..8013c6319 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -3,17 +3,24 @@ import { OnboardingLayout } from "@/components/layouts/onboarding-layout"; import { AlertBlock } from "@/components/shared/alert-block"; import { Logo } from "@/components/shared/logo"; import { Button, buttonVariants } from "@/components/ui/button"; -import { CardContent } from "@/components/ui/card"; +import { CardContent, CardDescription } from "@/components/ui/card"; import { Form, FormControl, + FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; -import { authClient } from "@/lib/auth"; +import { + InputOTP, + InputOTPGroup, + InputOTPSlot, +} from "@/components/ui/input-otp"; +import { Label } from "@/components/ui/label"; +import { authClient } from "@/lib/auth-client"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { IS_CLOUD, auth, isAdminPresent } from "@dokploy/server"; @@ -21,110 +28,118 @@ import { validateRequest } from "@dokploy/server/lib/auth"; import { zodResolver } from "@hookform/resolvers/zod"; import { Session, getSessionCookie } from "better-auth"; import { betterFetch } from "better-auth/react"; +import base32 from "hi-base32"; +import { REGEXP_ONLY_DIGITS } from "input-otp"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; +import { TOTP } from "otpauth"; import { type ReactElement, useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; -const loginSchema = z.object({ - email: z - .string() - .min(1, { - message: "Email is required", - }) - .email({ - message: "Email must be a valid email", - }), - - password: z - .string() - .min(1, { - message: "Password is required", - }) - .min(8, { - message: "Password must be at least 8 characters", - }), +const LoginSchema = z.object({ + email: z.string().email(), + password: z.string().min(8), }); -type Login = z.infer; +const TwoFactorSchema = z.object({ + code: z.string().min(6), +}); -type AuthResponse = { - is2FAEnabled: boolean; - authId: string; -}; +type LoginForm = z.infer; +type TwoFactorForm = z.infer; interface Props { IS_CLOUD: boolean; } export default function Home({ IS_CLOUD }: Props) { - const [isLoading, setIsLoading] = useState(false); - const [isError, setIsError] = useState(false); - const [error, setError] = useState(null); - const [temp, setTemp] = useState({ - is2FAEnabled: false, - authId: "", - }); const router = useRouter(); - const form = useForm({ + const [isLoginLoading, setIsLoginLoading] = useState(false); + const [isTwoFactorLoading, setIsTwoFactorLoading] = useState(false); + const [isTwoFactor, setIsTwoFactor] = useState(false); + const [error, setError] = useState(null); + const [twoFactorCode, setTwoFactorCode] = useState(""); + + const loginForm = useForm({ + resolver: zodResolver(LoginSchema), defaultValues: { email: "siumauricio@hotmail.com", password: "Password123", }, - resolver: zodResolver(loginSchema), }); - useEffect(() => { - form.reset(); - }, [form, form.reset, form.formState.isSubmitSuccessful]); - - const onSubmit = async (values: Login) => { - setIsLoading(true); - const { data, error } = await authClient.signIn.email({ - email: values.email, - password: values.password, - }); - - if (!error) { - // if (data) { - // setTemp(data); - // } else { - toast.success("Successfully signed in", { - duration: 2000, + const onSubmit = async (values: LoginForm) => { + setIsLoginLoading(true); + try { + const { data, error } = await authClient.signIn.email({ + email: values.email, + password: values.password, }); + + if (error) { + toast.error(error.message); + setError(error.message || "An error occurred while logging in"); + return; + } + + if (data?.twoFactorRedirect as boolean) { + setTwoFactorCode(""); + setIsTwoFactor(true); + toast.info("Please enter your 2FA code"); + return; + } + + toast.success("Logged in successfully"); router.push("/dashboard/projects"); - // } - } else { - setIsError(true); - setError(error.message ?? "Error to signup"); - toast.error("Error to sign up", { - description: error.message, - }); + } catch (error) { + toast.error("An error occurred while logging in"); + } finally { + setIsLoginLoading(false); + } + }; + + const onTwoFactorSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (twoFactorCode.length !== 6) { + toast.error("Please enter a valid 6-digit code"); + return; } - setIsLoading(false); - // await mutateAsync({ - // email: values.email.toLowerCase(), - // password: values.password, - // }) - // .then((data) => { - // if (data.is2FAEnabled) { - // setTemp(data); - // } else { - // toast.success("Successfully signed in", { - // duration: 2000, - // }); - // router.push("/dashboard/projects"); - // } - // }) - // .catch(() => { - // toast.error("Signin failed", { - // duration: 2000, - // }); - // }); + setIsTwoFactorLoading(true); + try { + const { data, error } = await authClient.twoFactor.verifyTotp({ + code: twoFactorCode.replace(/\s/g, ""), + }); + + if (error) { + toast.error(error.message); + setError(error.message || "An error occurred while verifying 2FA code"); + return; + } + + toast.success("Logged in successfully"); + router.push("/dashboard/projects"); + } catch (error) { + toast.error("An error occurred while verifying 2FA code"); + } finally { + setIsTwoFactorLoading(false); + } }; + + const convertBase32ToHex = (base32Secret: string) => { + try { + // Usar asBytes() para obtener los bytes directamente + const bytes = base32.decode.asBytes(base32Secret.toUpperCase()); + // Convertir bytes a hex + return Buffer.from(bytes).toString("hex"); + } catch (error) { + console.error("Error converting base32 to hex:", error); + return base32Secret; // Fallback al valor original si hay error + } + }; + return ( <>
@@ -138,55 +153,109 @@ export default function Home({ IS_CLOUD }: Props) { Enter your email and password to sign in

- {isError && ( + {error && ( {error} )} - {!temp.is2FAEnabled ? ( -
- -
- ( - - Email - - - - - - )} - /> - ( - - Password - - - - - - )} - /> - - -
+ {!isTwoFactor ? ( + + + ( + + Email + + + + + + )} + /> + ( + + Password + + + + + + )} + /> + ) : ( - +
+
+ + + + + + + + + + + + + Enter the 6-digit code from your authenticator app + +
+ +
+ + +
+
)}
diff --git a/apps/dokploy/pages/invitation.tsx b/apps/dokploy/pages/invitation.tsx index e8bfc3fc3..0dd8dbe4d 100644 --- a/apps/dokploy/pages/invitation.tsx +++ b/apps/dokploy/pages/invitation.tsx @@ -26,8 +26,8 @@ import { useRouter } from "next/router"; import { type ReactElement, useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; -import { z } from "zod"; import superjson from "superjson"; +import { z } from "zod"; const registerSchema = z .object({ diff --git a/apps/dokploy/pages/register.tsx b/apps/dokploy/pages/register.tsx index 73dce5e77..e8fd15cf5 100644 --- a/apps/dokploy/pages/register.tsx +++ b/apps/dokploy/pages/register.tsx @@ -17,7 +17,7 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; -import { authClient } from "@/lib/auth"; +import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; import { IS_CLOUD, isAdminPresent, validateRequest } from "@dokploy/server"; import { zodResolver } from "@hookform/resolvers/zod"; diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts index db0c64385..444a80ba8 100644 --- a/apps/dokploy/server/api/routers/organization.ts +++ b/apps/dokploy/server/api/routers/organization.ts @@ -1,5 +1,5 @@ import { db } from "@/server/db"; -import { member, organization } from "@/server/db/schema"; +import { invitation, member, organization } from "@/server/db/schema"; import { TRPCError } from "@trpc/server"; import { desc, eq } from "drizzle-orm"; import { nanoid } from "nanoid"; @@ -83,4 +83,10 @@ export const organizationRouter = createTRPCRouter({ .where(eq(organization.id, input.organizationId)); return result; }), + allInvitations: adminProcedure.query(async ({ ctx }) => { + return await db.query.invitation.findMany({ + where: eq(invitation.organizationId, ctx.session.activeOrganizationId), + orderBy: [desc(invitation.status)], + }); + }), }); diff --git a/packages/server/package.json b/packages/server/package.json index d8f72a868..dbc24375e 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -28,6 +28,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@better-auth/utils":"0.2.3", "@oslojs/encoding":"1.1.0", "@oslojs/crypto":"1.0.1", "drizzle-dbml-generator":"0.10.0", diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index cc144345b..a4b9a4f1f 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -16,6 +16,7 @@ export const auth = betterAuth({ provider: "pg", schema: schema, }), + appName: "Dokploy", socialProviders: { github: { clientId: process.env.GITHUB_CLIENT_ID as string, diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts index 8f3564be9..0a9f4e945 100644 --- a/packages/server/src/services/auth.ts +++ b/packages/server/src/services/auth.ts @@ -1,4 +1,5 @@ import { randomBytes } from "node:crypto"; +import { createOTP } from "@better-auth/utils/otp"; import { db } from "@dokploy/server/db"; import { users_temp } from "@dokploy/server/db/schema"; import { getPublicIpWithFallback } from "@dokploy/server/wss/utils"; @@ -29,26 +30,41 @@ export const findAuthById = async (authId: string) => { return result; }; -export const generate2FASecret = async (userId: string) => { - const user = await findUserById(userId); +const generateBase32Secret = () => { + // Generamos 32 bytes (256 bits) para asegurar que tengamos suficiente longitud + const buffer = randomBytes(32); + // Convertimos directamente a hex para Better Auth + const hex = buffer.toString("hex"); + // También necesitamos la versión base32 para el QR code + const base32 = encode.encode(buffer).replace(/=/g, "").substring(0, 32); + return { + hex, + base32, + }; +}; - const base32_secret = generateBase32Secret(); +export const generate2FASecret = () => { + const secret = "46JMUCG4NJ3CIU6LQAIVFWUW"; const totp = new TOTP({ issuer: "Dokploy", - label: `${user?.email}`, + label: "siumauricio@hotmail.com", algorithm: "SHA1", digits: 6, - secret: base32_secret, + secret: secret, }); - const otpauth_url = totp.toString(); + // Convertir los bytes del secreto a hex + const secretBytes = totp.secret.bytes; + const hexSecret = Buffer.from(secretBytes).toString("hex"); - const qrUrl = await QRCode.toDataURL(otpauth_url); + console.log("Secret bytes:", secretBytes); + console.log("Hex secret:", hexSecret); return { - qrCodeUrl: qrUrl, - secret: base32_secret, + secret, + hexSecret, + totp, }; }; @@ -59,6 +75,7 @@ export const verify2FA = async (auth: User, secret: string, pin: string) => { algorithm: "SHA1", digits: 6, secret: secret, + period: 30, }); const delta = totp.validate({ token: pin }); @@ -72,8 +89,124 @@ export const verify2FA = async (auth: User, secret: string, pin: string) => { return auth; }; -const generateBase32Secret = () => { - const buffer = randomBytes(15); - const base32 = encode.encode(buffer).replace(/=/g, "").substring(0, 24); - return base32; +const convertBase32ToHex = (base32Secret: string) => { + try { + // Asegurarnos de que la longitud sea múltiplo de 8 agregando padding + let paddedSecret = base32Secret; + while (paddedSecret.length % 8 !== 0) { + paddedSecret += "="; + } + + const bytes = encode.decode.asBytes(paddedSecret.toUpperCase()); + let hex = Buffer.from(bytes).toString("hex"); + + // Asegurarnos de que el hex tenga al menos 32 caracteres (16 bytes) + while (hex.length < 32) { + hex += "0"; + } + + return hex; + } catch (error) { + console.error("Error converting base32 to hex:", error); + return base32Secret; + } }; + +// Para probar +// const testSecret = "46JMUCG4NJ3CIU6LQAIVFWUW"; +// console.log("Original:", testSecret); +// console.log("Converted:", convertBase32ToHex(testSecret)); +// console.log( +// "Length in bytes:", +// Buffer.from(convertBase32ToHex(testSecret), "hex").length, +// ); +// console.log(generate2FASecret().secret.secret); + +// // Para probar +// const testResult = generate2FASecret(); +// console.log("\nResultados:"); +// console.log("Original base32:", testResult.secret); +// console.log("Hex convertido:", testResult.hexSecret); +// console.log( +// "Longitud en bytes:", +// Buffer.from(testResult.hexSecret, "hex").length, +// ); +export const symmetricDecrypt = async ({ key, data }) => { + const keyAsBytes = await createHash("SHA-256").digest(key); + const dataAsBytes = hexToBytes(data); + const chacha = managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes)); + return new TextDecoder().decode(chacha.decrypt(dataAsBytes)); +}; +export const migrateExistingSecret = async ( + existingBase32Secret: string, + encryptionKey: string, +) => { + try { + // 1. Primero asegurarnos que el secreto base32 tenga el padding correcto + let paddedSecret = existingBase32Secret; + while (paddedSecret.length % 8 !== 0) { + paddedSecret += "="; + } + + // 2. Decodificar el base32 a bytes usando hi-base32 + const bytes = encode.decode.asBytes(paddedSecret.toUpperCase()); + + // 3. Convertir los bytes a hex + const hexSecret = Buffer.from(bytes).toString("hex"); + + // 4. Encriptar el secreto hex usando Better Auth + const encryptedSecret = await symmetricEncrypt({ + key: encryptionKey, + data: hexSecret, + }); + + // 5. Crear TOTP con el secreto original para validación + const originalTotp = new TOTP({ + issuer: "Dokploy", + label: "migration-test", + algorithm: "SHA1", + digits: 6, + secret: existingBase32Secret, + }); + + // 6. Generar un código de prueba con el secreto original + const testCode = originalTotp.generate(); + + // 7. Validar que el código funcione con el secreto original + const isValid = originalTotp.validate({ token: testCode }) !== null; + + return { + originalSecret: existingBase32Secret, + hexSecret, + encryptedSecret, // Este es el valor que debes guardar en la base de datos + isValid, + testCode, + secretLength: hexSecret.length, + }; + } catch (error: unknown) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + console.error("Error durante la migración:", errorMessage); + throw new Error(`Error al migrar el secreto: ${errorMessage}`); + } +}; + +// // Ejemplo de uso con el secreto de prueba +// const testMigration = await migrateExistingSecret( +// "46JMUCG4NJ3CIU6LQAIVFWUW", +// process.env.BETTER_AUTH_SECRET || "your-encryption-key", +// ); +// console.log("\nPrueba de migración:"); +// console.log("Secreto original (base32):", testMigration.originalSecret); +// console.log("Secreto convertido (hex):", testMigration.hexSecret); +// console.log("Secreto encriptado:", testMigration.encryptedSecret); +// console.log("Longitud del secreto hex:", testMigration.secretLength); +// console.log("¿Conversión válida?:", testMigration.isValid); +// console.log("Código de prueba:", testMigration.testCode); +const secret = "46JMUCG4NJ3CIU6LQAIVFWUW"; +const isValid = createOTP(secret, { + digits: 6, + period: 30, +}).verify("123456"); + +console.log(isValid.then((isValid) => console.log(isValid))); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 09f7885b4..ee68b3995 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -549,6 +549,9 @@ importers: packages/server: dependencies: + '@better-auth/utils': + specifier: 0.2.3 + version: 0.2.3 '@faker-js/faker': specifier: ^8.4.1 version: 8.4.1 From 8c282233436c86ccbdb7a94d90b20df76d1ae111 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Mon, 17 Feb 2025 00:10:34 -0600 Subject: [PATCH 42/89] refactor: remove 2fa migration --- apps/dokploy/drizzle/0067_migrate-data.sql | 45 ---------------------- 1 file changed, 45 deletions(-) diff --git a/apps/dokploy/drizzle/0067_migrate-data.sql b/apps/dokploy/drizzle/0067_migrate-data.sql index 279acbfb9..8f26fc13e 100644 --- a/apps/dokploy/drizzle/0067_migrate-data.sql +++ b/apps/dokploy/drizzle/0067_migrate-data.sql @@ -26,7 +26,6 @@ WITH inserted_users AS ( "serversQuantity", "expirationDate", "createdAt", - "two_factor_enabled", "isRegistered" ) SELECT @@ -53,30 +52,11 @@ WITH inserted_users AS ( a."serversQuantity", NOW() + INTERVAL '1 year', NOW(), - COALESCE(auth."is2FAEnabled", false), true FROM admin a JOIN auth ON auth.id = a."authId" RETURNING * ), -inserted_two_factor_admin AS ( - -- Insertar registros en two_factor para admins con 2FA habilitado - INSERT INTO two_factor ( - id, - secret, - backup_codes, - user_id - ) - SELECT - gen_random_uuid(), - auth.secret, - gen_random_uuid()::text, - a."adminId" - FROM admin a - JOIN auth ON auth.id = a."authId" - WHERE auth."is2FAEnabled" = true - RETURNING * -), inserted_accounts AS ( -- Insertar cuentas para los admins INSERT INTO account ( @@ -85,7 +65,6 @@ inserted_accounts AS ( "provider_id", "user_id", password, - "is2FAEnabled", "created_at", "updated_at" ) @@ -95,7 +74,6 @@ inserted_accounts AS ( 'credential', a."adminId", auth.password, - COALESCE(auth."is2FAEnabled", false), NOW(), NOW() FROM admin a @@ -143,7 +121,6 @@ inserted_members AS ( "accesedProjects", "accesedServices", "expirationDate", - "two_factor_enabled", "isRegistered" ) SELECT @@ -166,7 +143,6 @@ inserted_members AS ( COALESCE(u."accesedProjects", '{}'), COALESCE(u."accesedServices", '{}'), NOW() + INTERVAL '1 year', - COALESCE(auth."is2FAEnabled", false), COALESCE(u."isRegistered", false) FROM "user" u JOIN admin a ON u."adminId" = a."adminId" @@ -181,7 +157,6 @@ inserted_member_accounts AS ( "provider_id", "user_id", password, - "is2FAEnabled", "created_at", "updated_at" ) @@ -191,7 +166,6 @@ inserted_member_accounts AS ( 'credential', u."userId", auth.password, - COALESCE(auth."is2FAEnabled", false), NOW(), NOW() FROM "user" u @@ -199,25 +173,6 @@ inserted_member_accounts AS ( JOIN auth ON auth.id = u."authId" RETURNING * ), -inserted_two_factor_members AS ( - -- Insertar registros en two_factor para miembros con 2FA habilitado - INSERT INTO two_factor ( - id, - secret, - backup_codes, - user_id - ) - SELECT - gen_random_uuid(), - auth.secret, - gen_random_uuid()::text, - u."userId" - FROM "user" u - JOIN admin a ON u."adminId" = a."adminId" - JOIN auth ON auth.id = u."authId" - WHERE auth."is2FAEnabled" = true - RETURNING * -), inserted_admin_members AS ( -- Insertar miembros en las organizaciones (admins como owners) INSERT INTO member ( From c7d47a60038b2c5717f5eb3338e990881ad831ff Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Mon, 17 Feb 2025 00:30:15 -0600 Subject: [PATCH 43/89] refactor: update database foreign key constraints and user management --- .../dashboard/settings/users/add-user.tsx | 129 - .../dashboard/settings/users/show-users.tsx | 79 +- .../dokploy/drizzle/0074_lowly_jack_power.sql | 18 + apps/dokploy/drizzle/meta/0074_snapshot.json | 4878 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + apps/dokploy/server/api/routers/user.ts | 22 +- packages/server/src/db/schema/account.ts | 12 +- 7 files changed, 4967 insertions(+), 178 deletions(-) delete mode 100644 apps/dokploy/components/dashboard/settings/users/add-user.tsx create mode 100644 apps/dokploy/drizzle/0074_lowly_jack_power.sql create mode 100644 apps/dokploy/drizzle/meta/0074_snapshot.json diff --git a/apps/dokploy/components/dashboard/settings/users/add-user.tsx b/apps/dokploy/components/dashboard/settings/users/add-user.tsx deleted file mode 100644 index 78c8ebdb4..000000000 --- a/apps/dokploy/components/dashboard/settings/users/add-user.tsx +++ /dev/null @@ -1,129 +0,0 @@ -import { AlertBlock } from "@/components/shared/alert-block"; -import { Button } from "@/components/ui/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { authClient } from "@/lib/auth-client"; -import { api } from "@/utils/api"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { PlusIcon } from "lucide-react"; -import { useEffect, useState } from "react"; -import { useForm } from "react-hook-form"; -import { toast } from "sonner"; -import { z } from "zod"; - -const addUser = z.object({ - email: z - .string() - .min(1, "Email is required") - .email({ message: "Invalid email" }), -}); - -type AddUser = z.infer; - -export const AddUser = () => { - const [open, setOpen] = useState(false); - const utils = api.useUtils(); - - const { data: activeOrganization } = authClient.useActiveOrganization(); - const { mutateAsync, isError, error, isLoading } = - api.admin.createUserInvitation.useMutation(); - - const form = useForm({ - defaultValues: { - email: "", - }, - resolver: zodResolver(addUser), - }); - useEffect(() => { - form.reset(); - }, [form, form.formState.isSubmitSuccessful, form.reset]); - - const onSubmit = async (data: AddUser) => { - const result = await authClient.organization.inviteMember({ - email: data.email.toLowerCase(), - role: "member", - organizationId: activeOrganization?.id, - }); - console.log(result); - // await mutateAsync({ - // email: data.email.toLowerCase(), - // }) - // .then(async () => { - // toast.success("Invitation created"); - // await utils.user.all.invalidate(); - // setOpen(false); - // }) - // .catch(() => { - // toast.error("Error creating the invitation"); - // }); - }; - return ( - - - - - - - Add User - Invite a new user - - {isError && {error?.message}} - -
- - { - return ( - - Email - - - - - This will be the email of the new user - - - - ); - }} - /> - - - - - -
-
- ); -}; diff --git a/apps/dokploy/components/dashboard/settings/users/show-users.tsx b/apps/dokploy/components/dashboard/settings/users/show-users.tsx index 40fbea0d3..c09ebf9f8 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-users.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-users.tsx @@ -27,18 +27,16 @@ import { api } from "@/utils/api"; import copy from "copy-to-clipboard"; import { format } from "date-fns"; import { MoreHorizontal, Users } from "lucide-react"; -import { useEffect, useState } from "react"; import { toast } from "sonner"; import { AddUserPermissions } from "./add-permissions"; -import { AddUser } from "./add-user"; - import { DialogAction } from "@/components/shared/dialog-action"; import { Loader2 } from "lucide-react"; +import { authClient } from "@/lib/auth-client"; export const ShowUsers = () => { + const { data: isCloud } = api.settings.isCloud.useQuery(); const { data, isLoading, refetch } = api.user.all.useQuery(); - const { mutateAsync, isLoading: isRemoving } = - api.admin.removeUser.useMutation(); + const { mutateAsync, isLoading: isRemoving } = api.user.remove.useMutation(); return (
@@ -67,7 +65,6 @@ export const ShowUsers = () => { Invite users to your Dokploy account -
) : (
@@ -88,36 +85,37 @@ export const ShowUsers = () => { - {data?.map((user) => { + {data?.map((member) => { return ( - + - {user.user.email} + {member.user.email} - {user.role} + {member.role} - {user.user.twoFactorEnabled + {member.user.twoFactorEnabled ? "Enabled" : "Disabled"} - {user.user.isRegistered || user.role === "owner" + {member.user.isRegistered || + member.role === "owner" ? "Registered" : "Not Registered"} - {format(new Date(user.createdAt), "PPpp")} + {format(new Date(member.createdAt), "PPpp")} @@ -136,13 +134,13 @@ export const ShowUsers = () => { Actions - {!user.user.isRegistered && - user.role !== "owner" && ( + {!member.user.isRegistered && + member.role !== "owner" && ( { copy( - `${origin}/invitation?token=${user.user.token}`, + `${origin}/invitation?token=${member.user.token}`, ); toast.success( "Invitation Copied to clipboard", @@ -153,32 +151,53 @@ export const ShowUsers = () => { )} - {user.role !== "owner" && ( + {member.role !== "owner" && ( )} - {user.role !== "owner" && ( + {member.role !== "owner" && ( { - await mutateAsync({ - userId: user.userId, - }) - .then(() => { + if (isCloud) { + const { error } = + await authClient.organization.removeMember( + { + memberIdOrEmail: + member.user.id, + }, + ); + + if (!error) { toast.success( "User deleted successfully", ); refetch(); - }) - .catch(() => { + } else { toast.error( - "Error deleting destination", + "Error deleting user", ); - }); + } + } else { + await mutateAsync({ + userId: member.user.id, + }) + .then(() => { + toast.success( + "User deleted successfully", + ); + refetch(); + }) + .catch(() => { + toast.error( + "Error deleting destination", + ); + }); + } }} > { })} - -
- -
)} diff --git a/apps/dokploy/drizzle/0074_lowly_jack_power.sql b/apps/dokploy/drizzle/0074_lowly_jack_power.sql new file mode 100644 index 000000000..4f09535f4 --- /dev/null +++ b/apps/dokploy/drizzle/0074_lowly_jack_power.sql @@ -0,0 +1,18 @@ +ALTER TABLE "account" DROP CONSTRAINT "account_user_id_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "invitation" DROP CONSTRAINT "invitation_organization_id_organization_id_fk"; +--> statement-breakpoint +ALTER TABLE "invitation" DROP CONSTRAINT "invitation_inviter_id_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "member" DROP CONSTRAINT "member_organization_id_organization_id_fk"; +--> statement-breakpoint +ALTER TABLE "member" DROP CONSTRAINT "member_user_id_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "organization" DROP CONSTRAINT "organization_owner_id_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "invitation" ADD CONSTRAINT "invitation_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "invitation" ADD CONSTRAINT "invitation_inviter_id_user_temp_id_fk" FOREIGN KEY ("inviter_id") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_temp_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0074_snapshot.json b/apps/dokploy/drizzle/meta/0074_snapshot.json new file mode 100644 index 000000000..7c3df01b3 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0074_snapshot.json @@ -0,0 +1,4878 @@ +{ + "id": "9cb79f1e-14c2-4deb-b1ab-a1d038f72356", + "prevId": "e357a19a-dd1e-4843-b567-0c0243ade7a8", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_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": "''" + }, + "token": { + "name": "token", + "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()" + }, + "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[]" + }, + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "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": "no action", + "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 + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "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 + } + }, + "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 + } + }, + "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" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bitbucket": { + "name": "bitbucket", + "schema": "", + "columns": { + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "bitbucketUsername": { + "name": "bitbucketUsername", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "appPassword": { + "name": "appPassword", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketWorkspaceName": { + "name": "bitbucketWorkspaceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bitbucket_gitProviderId_git_provider_gitProviderId_fk": { + "name": "bitbucket_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "bitbucket", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.github": { + "name": "github", + "schema": "", + "columns": { + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "githubAppName": { + "name": "githubAppName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubAppId": { + "name": "githubAppId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "githubClientId": { + "name": "githubClientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubClientSecret": { + "name": "githubClientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubInstallationId": { + "name": "githubInstallationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubPrivateKey": { + "name": "githubPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubWebhookSecret": { + "name": "githubWebhookSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "github_gitProviderId_git_provider_gitProviderId_fk": { + "name": "github_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "github", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gitlab": { + "name": "gitlab", + "schema": "", + "columns": { + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "gitlabUrl": { + "name": "gitlabUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'https://gitlab.com'" + }, + "application_id": { + "name": "application_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_name": { + "name": "group_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "gitlab_gitProviderId_git_provider_gitProviderId_fk": { + "name": "gitlab_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "gitlab", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.server": { + "name": "server", + "schema": "", + "columns": { + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'root'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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.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.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 + } + }, + "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 + } + }, + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 39903f65a..6f38bc1bb 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -519,6 +519,13 @@ "when": 1739740193879, "tag": "0073_polite_miss_america", "breakpoints": true + }, + { + "idx": 74, + "version": "7", + "when": 1739773539709, + "tag": "0074_lowly_jack_power", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index addbdb23c..c5382e9a9 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -2,11 +2,13 @@ import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema"; import { findUserByAuthId, findUserById, + IS_CLOUD, + removeUserById, updateUser, verify2FA, } from "@dokploy/server"; import { db } from "@dokploy/server/db"; -import { apiUpdateUser, member } from "@dokploy/server/db/schema"; +import { account, apiUpdateUser, member } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { z } from "zod"; @@ -44,19 +46,17 @@ export const userRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { return await updateUser(ctx.user.id, input); }), - verify2FASetup: protectedProcedure + + remove: protectedProcedure .input( z.object({ - secret: z.string(), - pin: z.string(), + userId: z.string(), }), ) - .mutation(async ({ ctx, input }) => { - const user = await findUserById(ctx.user.id); - await verify2FA(user, input.secret, input.pin); - await updateUser(user.id, { - secret: input.secret, - }); - return user; + .mutation(async ({ input, ctx }) => { + if (IS_CLOUD) { + return true; + } + return await removeUserById(input.userId); }), }); diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 1c0b10e9a..185de1368 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -15,7 +15,7 @@ export const account = pgTable("account", { providerId: text("provider_id").notNull(), userId: text("user_id") .notNull() - .references(() => users_temp.id), + .references(() => users_temp.id, { onDelete: "cascade" }), accessToken: text("access_token"), refreshToken: text("refresh_token"), idToken: text("id_token"), @@ -59,7 +59,7 @@ export const organization = pgTable("organization", { metadata: text("metadata"), ownerId: text("owner_id") .notNull() - .references(() => users_temp.id), + .references(() => users_temp.id, { onDelete: "cascade" }), }); export const organizationRelations = relations( @@ -80,10 +80,10 @@ export const member = pgTable("member", { .$defaultFn(() => nanoid()), organizationId: text("organization_id") .notNull() - .references(() => organization.id), + .references(() => organization.id, { onDelete: "cascade" }), userId: text("user_id") .notNull() - .references(() => users_temp.id), + .references(() => users_temp.id, { onDelete: "cascade" }), role: text("role").notNull().$type<"owner" | "member" | "admin">(), createdAt: timestamp("created_at").notNull(), }); @@ -103,14 +103,14 @@ export const invitation = pgTable("invitation", { id: text("id").primaryKey(), organizationId: text("organization_id") .notNull() - .references(() => organization.id), + .references(() => organization.id, { onDelete: "cascade" }), email: text("email").notNull(), role: text("role").$type<"owner" | "member" | "admin">(), status: text("status").notNull(), expiresAt: timestamp("expires_at").notNull(), inviterId: text("inviter_id") .notNull() - .references(() => users_temp.id), + .references(() => users_temp.id, { onDelete: "cascade" }), }); export const invitationRelations = relations(invitation, ({ one }) => ({ From b73e4102ddf0d50d686830556d21e0f5943de47b Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Mon, 17 Feb 2025 02:48:42 -0600 Subject: [PATCH 44/89] feat: add organizations and members --- .../settings/users/show-invitations.tsx | 30 +- .../dashboard/settings/users/show-users.tsx | 9 +- apps/dokploy/components/layouts/side.tsx | 149 +- apps/dokploy/components/layouts/user-nav.tsx | 14 +- .../drizzle/0075_heavy_metal_master.sql | 3 + apps/dokploy/drizzle/meta/0075_snapshot.json | 4878 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + .../pages/dashboard/settings/users.tsx | 2 + apps/dokploy/pages/invitation.tsx | 306 +- apps/dokploy/server/api/routers/admin.ts | 15 +- .../server/api/routers/organization.ts | 89 +- apps/dokploy/server/api/routers/user.ts | 2 +- packages/server/src/db/schema/account.ts | 1 + packages/server/src/db/schema/session.ts | 2 +- packages/server/src/lib/auth.ts | 49 +- packages/server/src/services/admin.ts | 30 +- packages/server/src/services/auth.ts | 128 +- 17 files changed, 5385 insertions(+), 329 deletions(-) create mode 100644 apps/dokploy/drizzle/0075_heavy_metal_master.sql create mode 100644 apps/dokploy/drizzle/meta/0075_snapshot.json diff --git a/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx index e6067e7b3..3a36b780e 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx @@ -14,6 +14,7 @@ import { DropdownMenuLabel, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; +import copy from "copy-to-clipboard"; import { Table, TableBody, @@ -132,19 +133,22 @@ export const ShowInvitations = () => { Actions - {/* { - copy( - `${origin}/invitation?token=${user.user.token}`, - ); - toast.success( - "Invitation Copied to clipboard", - ); - }} - > - Copy Invitation - */} + {invitation.status === "pending" && ( + { + copy( + `${origin}/invitation?token=${invitation.id}`, + ); + toast.success( + "Invitation Copied to clipboard", + ); + }} + > + Copy Invitation + + )} + {invitation.status === "pending" && ( { const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -167,8 +167,7 @@ export const ShowUsers = () => { const { error } = await authClient.organization.removeMember( { - memberIdOrEmail: - member.user.id, + memberIdOrEmail: member.id, }, ); diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index bd10352f5..f8c24d360 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -78,7 +78,6 @@ import { UserNav } from "./user-nav"; // The types of the queries we are going to use type AuthQueryOutput = inferRouterOutputs["auth"]["get"]; -type UserQueryOutput = inferRouterOutputs["user"]["byAuthId"]; type SingleNavItem = { isSingle?: true; @@ -87,7 +86,6 @@ type SingleNavItem = { icon?: LucideIcon; isEnabled?: (opts: { auth?: AuthQueryOutput; - user?: UserQueryOutput; isCloud: boolean; }) => boolean; }; @@ -105,7 +103,6 @@ type NavItem = items: SingleNavItem[]; isEnabled?: (opts: { auth?: AuthQueryOutput; - user?: UserQueryOutput; isCloud: boolean; }) => boolean; }; @@ -118,7 +115,6 @@ type ExternalLink = { icon: React.ComponentType<{ className?: string }>; isEnabled?: (opts: { auth?: AuthQueryOutput; - user?: UserQueryOutput; isCloud: boolean; }) => boolean; }; @@ -149,7 +145,7 @@ const MENU: Menu = { url: "/dashboard/monitoring", icon: BarChartHorizontalBigIcon, // Only enabled in non-cloud environments - isEnabled: ({ auth, user, isCloud }) => !isCloud, + isEnabled: ({ auth, isCloud }) => !isCloud, }, { isSingle: true, @@ -157,9 +153,9 @@ const MENU: Menu = { url: "/dashboard/traefik", icon: GalleryVerticalEnd, // Only enabled for admins and users with access to Traefik files in non-cloud environments - isEnabled: ({ auth, user, isCloud }) => + isEnabled: ({ auth, isCloud }) => !!( - (auth?.role === "owner" || user?.canAccessToTraefikFiles) && + (auth?.role === "owner" || auth?.user?.canAccessToTraefikFiles) && !isCloud ), }, @@ -169,8 +165,11 @@ const MENU: Menu = { url: "/dashboard/docker", icon: BlocksIcon, // Only enabled for admins and users with access to Docker in non-cloud environments - isEnabled: ({ auth, user, isCloud }) => - !!((auth?.role === "owner" || user?.canAccessToDocker) && !isCloud), + isEnabled: ({ auth, isCloud }) => + !!( + (auth?.role === "owner" || auth?.user?.canAccessToDocker) && + !isCloud + ), }, { isSingle: true, @@ -178,8 +177,11 @@ const MENU: Menu = { url: "/dashboard/swarm", icon: PieChart, // Only enabled for admins and users with access to Docker in non-cloud environments - isEnabled: ({ auth, user, isCloud }) => - !!((auth?.role === "owner" || user?.canAccessToDocker) && !isCloud), + isEnabled: ({ auth, isCloud }) => + !!( + (auth?.role === "owner" || auth?.user?.canAccessToDocker) && + !isCloud + ), }, { isSingle: true, @@ -187,8 +189,11 @@ const MENU: Menu = { url: "/dashboard/requests", icon: Forward, // Only enabled for admins and users with access to Docker in non-cloud environments - isEnabled: ({ auth, user, isCloud }) => - !!((auth?.role === "owner" || user?.canAccessToDocker) && !isCloud), + isEnabled: ({ auth, isCloud }) => + !!( + (auth?.role === "owner" || auth?.user?.canAccessToDocker) && + !isCloud + ), }, // Legacy unused menu, adjusted to the new structure @@ -255,8 +260,7 @@ const MENU: Menu = { url: "/dashboard/settings/server", icon: Activity, // Only enabled for admins in non-cloud environments - isEnabled: ({ auth, user, isCloud }) => - !!(auth?.role === "owner" && !isCloud), + isEnabled: ({ auth, isCloud }) => !!(auth?.role === "owner" && !isCloud), }, { isSingle: true, @@ -270,7 +274,7 @@ const MENU: Menu = { url: "/dashboard/settings/servers", icon: Server, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), + isEnabled: ({ auth, isCloud }) => !!(auth?.role === "owner"), }, { isSingle: true, @@ -278,7 +282,7 @@ const MENU: Menu = { icon: Users, url: "/dashboard/settings/users", // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), + isEnabled: ({ auth }) => !!(auth?.role === "owner"), }, { isSingle: true, @@ -286,8 +290,8 @@ const MENU: Menu = { icon: KeyRound, url: "/dashboard/settings/ssh-keys", // Only enabled for admins and users with access to SSH keys - isEnabled: ({ auth, user }) => - !!(auth?.role === "owner" || user?.canAccessToSSHKeys), + isEnabled: ({ auth }) => + !!(auth?.role === "owner" || auth?.user?.canAccessToSSHKeys), }, { isSingle: true, @@ -295,8 +299,8 @@ const MENU: Menu = { url: "/dashboard/settings/git-providers", icon: GitBranch, // Only enabled for admins and users with access to Git providers - isEnabled: ({ auth, user }) => - !!(auth?.role === "owner" || user?.canAccessToGitProviders), + isEnabled: ({ auth }) => + !!(auth?.role === "owner" || auth?.user?.canAccessToGitProviders), }, { isSingle: true, @@ -304,7 +308,7 @@ const MENU: Menu = { url: "/dashboard/settings/registry", icon: Package, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), + isEnabled: ({ auth }) => !!(auth?.role === "owner"), }, { isSingle: true, @@ -312,7 +316,7 @@ const MENU: Menu = { url: "/dashboard/settings/destinations", icon: Database, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), + isEnabled: ({ auth }) => !!(auth?.role === "owner"), }, { @@ -321,7 +325,7 @@ const MENU: Menu = { url: "/dashboard/settings/certificates", icon: ShieldCheck, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), + isEnabled: ({ auth }) => !!(auth?.role === "owner"), }, { isSingle: true, @@ -329,8 +333,7 @@ const MENU: Menu = { url: "/dashboard/settings/cluster", icon: Boxes, // Only enabled for admins in non-cloud environments - isEnabled: ({ auth, user, isCloud }) => - !!(auth?.role === "owner" && !isCloud), + isEnabled: ({ auth, isCloud }) => !!(auth?.role === "owner" && !isCloud), }, { isSingle: true, @@ -338,7 +341,7 @@ const MENU: Menu = { url: "/dashboard/settings/notifications", icon: Bell, // Only enabled for admins - isEnabled: ({ auth, user, isCloud }) => !!(auth?.role === "owner"), + isEnabled: ({ auth }) => !!(auth?.role === "owner"), }, { isSingle: true, @@ -346,8 +349,7 @@ const MENU: Menu = { url: "/dashboard/settings/billing", icon: CreditCard, // Only enabled for admins in cloud environments - isEnabled: ({ auth, user, isCloud }) => - !!(auth?.role === "owner" && isCloud), + isEnabled: ({ auth, isCloud }) => !!(auth?.role === "owner" && isCloud), }, ], @@ -383,7 +385,6 @@ const MENU: Menu = { */ function createMenuForAuthUser(opts: { auth?: AuthQueryOutput; - user?: UserQueryOutput; isCloud: boolean; }): Menu { return { @@ -394,7 +395,6 @@ function createMenuForAuthUser(opts: { ? true : item.isEnabled({ auth: opts.auth, - user: opts.user, isCloud: opts.isCloud, }), ), @@ -405,7 +405,6 @@ function createMenuForAuthUser(opts: { ? true : item.isEnabled({ auth: opts.auth, - user: opts.user, isCloud: opts.isCloud, }), ), @@ -416,7 +415,6 @@ function createMenuForAuthUser(opts: { ? true : item.isEnabled({ auth: opts.auth, - user: opts.user, isCloud: opts.isCloud, }), ), @@ -525,10 +523,12 @@ const data = { ], }; -const teams = data.teams; function SidebarLogo() { const { state } = useSidebar(); + const { data: isCloud } = api.settings.isCloud.useQuery(); + const { data: user } = api.auth.get.useQuery(); const { data: dokployVersion } = api.settings.getDokployVersion.useQuery(); + const { data: session } = authClient.useSession(); const { data: organizations, refetch, @@ -617,42 +617,51 @@ function SidebarLogo() { />
{org.name} - {/* ⌘{index + 1} */} - {/* */} -
- - { - await deleteOrganization({ - organizationId: org.id, - }) - .then(() => { - refetch(); - toast.success("Port deleted successfully"); + {(org.ownerId === session?.user?.id || isCloud) && ( +
+ + { + await deleteOrganization({ + organizationId: org.id, }) - .catch(() => { - toast.error("Error deleting port"); - }); - }} - > - - -
+ +
+
+ )}
))} - - + {!isCloud && user?.role === "owner" && ( + <> + + + + )} @@ -706,14 +715,6 @@ export default function Page({ children }: Props) { const pathname = usePathname(); const currentPath = router.pathname; const { data: auth } = api.auth.get.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: auth?.id || "", - }, - { - enabled: !!auth?.id && auth?.role === "member", - }, - ); const includesProjects = pathname?.includes("/dashboard/project"); const { data: isCloud, isLoading } = api.settings.isCloud.useQuery(); @@ -722,7 +723,7 @@ export default function Page({ children }: Props) { home: filteredHome, settings: filteredSettings, help, - } = createMenuForAuthUser({ auth, user, isCloud: !!isCloud }); + } = createMenuForAuthUser({ auth, isCloud: !!isCloud }); const activeItem = findActiveNavItem( [...filteredHome, ...filteredSettings], diff --git a/apps/dokploy/components/layouts/user-nav.tsx b/apps/dokploy/components/layouts/user-nav.tsx index 49fc92e59..809f9c178 100644 --- a/apps/dokploy/components/layouts/user-nav.tsx +++ b/apps/dokploy/components/layouts/user-nav.tsx @@ -32,14 +32,7 @@ export const UserNav = () => { const router = useRouter(); const { data } = api.auth.get.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery(); - const { data: user } = api.user.byAuthId.useQuery( - { - authId: data?.id || "", - }, - { - enabled: !!data?.id && data?.role === "member", - }, - ); + const { locale, setLocale } = useLocale(); // const { mutateAsync } = api.auth.logout.useMutation(); @@ -99,7 +92,8 @@ export const UserNav = () => { > Monitoring - {(data?.role === "owner" || user?.canAccessToTraefikFiles) && ( + {(data?.role === "owner" || + data?.user?.canAccessToTraefikFiles) && ( { @@ -109,7 +103,7 @@ export const UserNav = () => { Traefik )} - {(data?.role === "owner" || user?.canAccessToDocker) && ( + {(data?.role === "owner" || data?.user?.canAccessToDocker) && ( { diff --git a/apps/dokploy/drizzle/0075_heavy_metal_master.sql b/apps/dokploy/drizzle/0075_heavy_metal_master.sql new file mode 100644 index 000000000..850f532d0 --- /dev/null +++ b/apps/dokploy/drizzle/0075_heavy_metal_master.sql @@ -0,0 +1,3 @@ +ALTER TABLE "session_temp" DROP CONSTRAINT "session_temp_user_id_user_temp_id_fk"; +--> statement-breakpoint +ALTER TABLE "session_temp" ADD CONSTRAINT "session_temp_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0075_snapshot.json b/apps/dokploy/drizzle/meta/0075_snapshot.json new file mode 100644 index 000000000..fb28e29c9 --- /dev/null +++ b/apps/dokploy/drizzle/meta/0075_snapshot.json @@ -0,0 +1,4878 @@ +{ + "id": "c5e17a87-0aa3-4178-be24-cfa7cde0f75d", + "prevId": "9cb79f1e-14c2-4deb-b1ab-a1d038f72356", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerContextPath": { + "name": "dockerContextPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerBuildStage": { + "name": "dockerBuildStage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dropBuildPath": { + "name": "dropBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "healthCheckSwarm": { + "name": "healthCheckSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "restartPolicySwarm": { + "name": "restartPolicySwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "placementSwarm": { + "name": "placementSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "updateConfigSwarm": { + "name": "updateConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "rollbackConfigSwarm": { + "name": "rollbackConfigSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "modeSwarm": { + "name": "modeSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "labelsSwarm": { + "name": "labelsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "networkSwarm": { + "name": "networkSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "buildType": { + "name": "buildType", + "type": "buildType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'nixpacks'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "application_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "application_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "application", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_registryId_registry_registryId_fk": { + "name": "application_registryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "registryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_projectId_project_projectId_fk": { + "name": "application_projectId_project_projectId_fk", + "tableFrom": "application", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.postgres": { + "name": "postgres", + "schema": "", + "columns": { + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_projectId_project_projectId_fk": { + "name": "postgres_projectId_project_projectId_fk", + "tableFrom": "postgres", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "postgres_serverId_server_serverId_fk": { + "name": "postgres_serverId_server_serverId_fk", + "tableFrom": "postgres", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "postgres_appName_unique": { + "name": "postgres_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_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": "''" + }, + "token": { + "name": "token", + "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()" + }, + "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[]" + }, + "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'" + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableLogRotation": { + "name": "enableLogRotation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metricsConfig": { + "name": "metricsConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"server\":{\"type\":\"Dokploy\",\"refreshRate\":60,\"port\":4500,\"token\":\"\",\"retentionDays\":2,\"cronJob\":\"\",\"urlCallback\":\"\",\"thresholds\":{\"cpu\":0,\"memory\":0}},\"containers\":{\"refreshRate\":60,\"services\":{\"include\":[],\"exclude\":[]}}}'::jsonb" + }, + "cleanupCacheApplications": { + "name": "cleanupCacheApplications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnPreviews": { + "name": "cleanupCacheOnPreviews", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cleanupCacheOnCompose": { + "name": "cleanupCacheOnCompose", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + } + }, + "indexes": {}, + "foreignKeys": { + "domain_composeId_compose_composeId_fk": { + "name": "domain_composeId_compose_composeId_fk", + "tableFrom": "domain", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_applicationId_application_applicationId_fk": { + "name": "domain_applicationId_application_applicationId_fk", + "tableFrom": "domain", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "domain_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "domain", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mariadb": { + "name": "mariadb", + "schema": "", + "columns": { + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_projectId_project_projectId_fk": { + "name": "mariadb_projectId_project_projectId_fk", + "tableFrom": "mariadb", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mariadb_serverId_server_serverId_fk": { + "name": "mariadb_serverId_server_serverId_fk", + "tableFrom": "mariadb", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mariadb_appName_unique": { + "name": "mariadb_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mongo": { + "name": "mongo", + "schema": "", + "columns": { + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "replicaSets": { + "name": "replicaSets", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_projectId_project_projectId_fk": { + "name": "mongo_projectId_project_projectId_fk", + "tableFrom": "mongo", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mongo_serverId_server_serverId_fk": { + "name": "mongo_serverId_server_serverId_fk", + "tableFrom": "mongo", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mongo_appName_unique": { + "name": "mongo_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mysql": { + "name": "mysql", + "schema": "", + "columns": { + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "databaseName": { + "name": "databaseName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseUser": { + "name": "databaseUser", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databasePassword": { + "name": "databasePassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rootPassword": { + "name": "rootPassword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_projectId_project_projectId_fk": { + "name": "mysql_projectId_project_projectId_fk", + "tableFrom": "mysql", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mysql_serverId_server_serverId_fk": { + "name": "mysql_serverId_server_serverId_fk", + "tableFrom": "mysql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mysql_appName_unique": { + "name": "mysql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.destination": { + "name": "destination", + "schema": "", + "columns": { + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "accessKey": { + "name": "accessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secretAccessKey": { + "name": "secretAccessKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bucket": { + "name": "bucket", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region": { + "name": "region", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "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 + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mount": { + "name": "mount", + "schema": "", + "columns": { + "mountId": { + "name": "mountId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "mountType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "hostPath": { + "name": "hostPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "mountPath": { + "name": "mountPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "mount_applicationId_application_applicationId_fk": { + "name": "mount_applicationId_application_applicationId_fk", + "tableFrom": "mount", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mariadbId_mariadb_mariadbId_fk": { + "name": "mount_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "mount", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mongoId_mongo_mongoId_fk": { + "name": "mount_mongoId_mongo_mongoId_fk", + "tableFrom": "mount", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_mysqlId_mysql_mysqlId_fk": { + "name": "mount_mysqlId_mysql_mysqlId_fk", + "tableFrom": "mount", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_redisId_redis_redisId_fk": { + "name": "mount_redisId_redis_redisId_fk", + "tableFrom": "mount", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.certificate": { + "name": "certificate", + "schema": "", + "columns": { + "certificateId": { + "name": "certificateId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificateData": { + "name": "certificateData", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "privateKey": { + "name": "privateKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "certificatePath": { + "name": "certificatePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "autoRenew": { + "name": "autoRenew", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "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 + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redis": { + "name": "redis", + "schema": "", + "columns": { + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryReservation": { + "name": "memoryReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "memoryLimit": { + "name": "memoryLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuReservation": { + "name": "cpuReservation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cpuLimit": { + "name": "cpuLimit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "externalPort": { + "name": "externalPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_projectId_project_projectId_fk": { + "name": "redis_projectId_project_projectId_fk", + "tableFrom": "redis", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "redis_serverId_server_serverId_fk": { + "name": "redis_serverId_server_serverId_fk", + "tableFrom": "redis", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redis_appName_unique": { + "name": "redis_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.compose": { + "name": "compose", + "schema": "", + "columns": { + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeFile": { + "name": "composeFile", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceTypeCompose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "composeType": { + "name": "composeType", + "type": "composeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'docker-compose'" + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk": { + "name": "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk", + "tableFrom": "compose", + "tableTo": "ssh-key", + "columnsFrom": [ + "customGitSSHKeyId" + ], + "columnsTo": [ + "sshKeyId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_projectId_project_projectId_fk": { + "name": "compose_projectId_project_projectId_fk", + "tableFrom": "compose", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.registry": { + "name": "registry", + "schema": "", + "columns": { + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "registryName": { + "name": "registryName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "imagePrefix": { + "name": "imagePrefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "selfHosted": { + "name": "selfHosted", + "type": "RegistryType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "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 + } + }, + "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 + } + }, + "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" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bitbucket": { + "name": "bitbucket", + "schema": "", + "columns": { + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "bitbucketUsername": { + "name": "bitbucketUsername", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "appPassword": { + "name": "appPassword", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketWorkspaceName": { + "name": "bitbucketWorkspaceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "bitbucket_gitProviderId_git_provider_gitProviderId_fk": { + "name": "bitbucket_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "bitbucket", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.github": { + "name": "github", + "schema": "", + "columns": { + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "githubAppName": { + "name": "githubAppName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubAppId": { + "name": "githubAppId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "githubClientId": { + "name": "githubClientId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubClientSecret": { + "name": "githubClientSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubInstallationId": { + "name": "githubInstallationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubPrivateKey": { + "name": "githubPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "githubWebhookSecret": { + "name": "githubWebhookSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "github_gitProviderId_git_provider_gitProviderId_fk": { + "name": "github_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "github", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gitlab": { + "name": "gitlab", + "schema": "", + "columns": { + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "gitlabUrl": { + "name": "gitlabUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'https://gitlab.com'" + }, + "application_id": { + "name": "application_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "group_name": { + "name": "group_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "gitlab_gitProviderId_git_provider_gitProviderId_fk": { + "name": "gitlab_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "gitlab", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.server": { + "name": "server", + "schema": "", + "columns": { + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ipAddress": { + "name": "ipAddress", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'root'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "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.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.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 + } + }, + "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 + } + }, + "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 + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "drop" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "raw" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "gotify" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 6f38bc1bb..674994c1d 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -526,6 +526,13 @@ "when": 1739773539709, "tag": "0074_lowly_jack_power", "breakpoints": true + }, + { + "idx": 75, + "version": "7", + "when": 1739781534192, + "tag": "0075_heavy_metal_master", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/pages/dashboard/settings/users.tsx b/apps/dokploy/pages/dashboard/settings/users.tsx index 7945bf86d..e9fb65608 100644 --- a/apps/dokploy/pages/dashboard/settings/users.tsx +++ b/apps/dokploy/pages/dashboard/settings/users.tsx @@ -28,6 +28,8 @@ export async function getServerSideProps( ) { const { req, res } = ctx; const { user, session } = await validateRequest(req); + + console.log("user", user, session); if (!user || user.role === "member") { return { redirect: { diff --git a/apps/dokploy/pages/invitation.tsx b/apps/dokploy/pages/invitation.tsx index 0dd8dbe4d..60cdfa854 100644 --- a/apps/dokploy/pages/invitation.tsx +++ b/apps/dokploy/pages/invitation.tsx @@ -1,4 +1,5 @@ import { OnboardingLayout } from "@/components/layouts/onboarding-layout"; +import { AlertBlock } from "@/components/shared/alert-block"; import { Logo } from "@/components/shared/logo"; import { Button } from "@/components/ui/button"; import { @@ -16,21 +17,24 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; +import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; import { IS_CLOUD, getUserByToken } from "@dokploy/server"; import { zodResolver } from "@hookform/resolvers/zod"; -import { AlertTriangle } from "lucide-react"; +import { AlertCircle, AlertTriangle } from "lucide-react"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; import { type ReactElement, useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; -import superjson from "superjson"; import { z } from "zod"; const registerSchema = z .object({ + name: z.string().min(1, { + message: "Name is required", + }), email: z .string() .min(1, { @@ -39,7 +43,6 @@ const registerSchema = z .email({ message: "Email must be a valid email", }), - password: z .string() .min(1, { @@ -72,9 +75,15 @@ interface Props { token: string; invitation: Awaited>; isCloud: boolean; + userAlreadyExists: boolean; } -const Invitation = ({ token, invitation, isCloud }: Props) => { +const Invitation = ({ + token, + invitation, + isCloud, + userAlreadyExists, +}: Props) => { const router = useRouter(); const { data } = api.admin.getUserByToken.useQuery( { @@ -91,6 +100,7 @@ const Invitation = ({ token, invitation, isCloud }: Props) => { const form = useForm({ defaultValues: { + name: "", email: "", password: "", confirmPassword: "", @@ -109,20 +119,32 @@ const Invitation = ({ token, invitation, isCloud }: Props) => { }, [form, form.reset, form.formState.isSubmitSuccessful, data]); const onSubmit = async (values: Register) => { - await mutateAsync({ - id: data?.id, - password: values.password, - token: token, - }) - .then(() => { - toast.success("User registered successfuly", { - description: - "Please check your inbox or spam folder to confirm your account.", - duration: 100000, - }); - router.push("/dashboard/projects"); - }) - .catch((e) => e); + try { + const { data, error } = await authClient.signUp.email({ + email: values.email, + password: values.password, + name: values.name, + fetchOptions: { + headers: { + "x-dokploy-token": token, + }, + }, + }); + + if (error) { + toast.error(error.message); + return; + } + + const result = await authClient.organization.acceptInvitation({ + invitationId: token, + }); + + toast.success("Account created successfully"); + router.push("/dashboard/projects"); + } catch (error) { + toast.error("An error occurred while creating your account"); + } }; return ( @@ -139,114 +161,155 @@ const Invitation = ({ token, invitation, isCloud }: Props) => { Invitation - - Fill the form below to create your account - -
-
+ {userAlreadyExists ? ( +
+ +
+ Valid Invitation! + + We detected that you already have an account with this + email. Please sign in to accept the invitation. + +
+
- {isError && ( -
- - - {error?.message} - -
- )} + +
+ ) : ( + <> + + Fill the form below to create your account + +
+
- -
- -
- ( - - Email - - - - - - )} - /> - ( - - Password - - - - - - )} - /> + {isError && ( +
+ + + {error?.message} + +
+ )} - ( - - Confirm Password - - - - - - )} - /> - - -
+
+ ( + + Name + + + + + + )} + /> + ( + + Email + + + + + + )} + /> + ( + + Password + + + + + + )} + /> -
- {isCloud && ( - <> - ( + + Confirm Password + + + + + + )} + /> + +
- - - -
+ Register + +
+ +
+ {isCloud && ( + <> + + Login + + + Lost your password? + + + )} +
+ + + +
+ + )}
); }; - +// http://localhost:3000/invitation?token=CZK4BLrUdMa32RVkAdZiLsPDdvnPiAgZ +// /f7af93acc1a99eae864972ab4c92fee089f0d83473d415ede8e821e5dbabe79c export default Invitation; Invitation.getLayout = (page: ReactElement) => { return {page}; @@ -268,7 +331,17 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) { try { const invitation = await getUserByToken(token); - console.log("invitation", invitation); + + if (invitation.userAlreadyExists) { + return { + props: { + isCloud: IS_CLOUD, + token: token, + invitation: invitation, + userAlreadyExists: true, + }, + }; + } if (invitation.isExpired) { return { @@ -287,6 +360,7 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) { }, }; } catch (error) { + console.log("error", error); return { redirect: { permanent: true, diff --git a/apps/dokploy/server/api/routers/admin.ts b/apps/dokploy/server/api/routers/admin.ts index 97e3a1fa4..b15ed616e 100644 --- a/apps/dokploy/server/api/routers/admin.ts +++ b/apps/dokploy/server/api/routers/admin.ts @@ -9,7 +9,7 @@ import { import { IS_CLOUD, createInvitation, - findUserByAuthId, + findOrganizationById, findUserById, getUserByToken, removeUserById, @@ -98,21 +98,20 @@ export const adminRouter = createTRPCRouter({ try { const user = await findUserById(input.id); - if (user.id !== ctx.user.ownerId) { + const organization = await findOrganizationById( + ctx.session?.activeOrganizationId || "", + ); + + if (organization?.ownerId !== ctx.user.ownerId) { throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to assign permissions", }); } + await updateUser(user.id, { ...input, }); - // await db - // .update(users) - // .set({ - // ...input, - // }) - // .where(eq(users.userId, input.userId)); } catch (error) { throw error; } diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts index 444a80ba8..7158a01ae 100644 --- a/apps/dokploy/server/api/routers/organization.ts +++ b/apps/dokploy/server/api/routers/organization.ts @@ -1,29 +1,43 @@ import { db } from "@/server/db"; -import { invitation, member, organization } from "@/server/db/schema"; +import { + invitation, + member, + organization, + users_temp, +} from "@/server/db/schema"; import { TRPCError } from "@trpc/server"; -import { desc, eq } from "drizzle-orm"; +import { and, desc, eq, exists } from "drizzle-orm"; import { nanoid } from "nanoid"; import { z } from "zod"; -import { adminProcedure, createTRPCRouter } from "../trpc"; +import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; +import { auth, IS_CLOUD } from "@dokploy/server/index"; export const organizationRouter = createTRPCRouter({ - create: adminProcedure + create: protectedProcedure .input( z.object({ name: z.string(), }), ) .mutation(async ({ ctx, input }) => { + if (ctx.user.rol !== "owner" && !IS_CLOUD) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "Only the organization owner can create an organization", + }); + } const result = await db .insert(organization) .values({ ...input, slug: nanoid(), createdAt: new Date(), - ownerId: ctx.user.ownerId, + ownerId: ctx.user.id, }) .returning() .then((res) => res[0]); + console.log("result", result); + if (!result) { throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", @@ -39,13 +53,24 @@ export const organizationRouter = createTRPCRouter({ }); return result; }), - all: adminProcedure.query(async ({ ctx }) => { - return await db.query.organization.findMany({ - where: eq(organization.ownerId, ctx.user.ownerId), - orderBy: [desc(organization.createdAt)], + all: protectedProcedure.query(async ({ ctx }) => { + const memberResult = await db.query.organization.findMany({ + where: (organization) => + exists( + db + .select() + .from(member) + .where( + and( + eq(member.organizationId, organization.id), + eq(member.userId, ctx.user.id), + ), + ), + ), }); + return memberResult; }), - one: adminProcedure + one: protectedProcedure .input( z.object({ organizationId: z.string(), @@ -56,7 +81,7 @@ export const organizationRouter = createTRPCRouter({ where: eq(organization.id, input.organizationId), }); }), - update: adminProcedure + update: protectedProcedure .input( z.object({ organizationId: z.string(), @@ -64,6 +89,12 @@ export const organizationRouter = createTRPCRouter({ }), ) .mutation(async ({ ctx, input }) => { + if (ctx.user.rol !== "owner" && !IS_CLOUD) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "Only the organization owner can update it", + }); + } const result = await db .update(organization) .set({ name: input.name }) @@ -71,16 +102,41 @@ export const organizationRouter = createTRPCRouter({ .returning(); return result[0]; }), - delete: adminProcedure + delete: protectedProcedure .input( z.object({ organizationId: z.string(), }), ) .mutation(async ({ ctx, input }) => { + if (ctx.user.rol !== "owner" && !IS_CLOUD) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "Only the organization owner can delete it", + }); + } + const org = await db.query.organization.findFirst({ + where: eq(organization.id, input.organizationId), + }); + + if (!org) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Organization not found", + }); + } + + if (org.ownerId !== ctx.user.id) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "Only the organization owner can delete it", + }); + } + const result = await db .delete(organization) .where(eq(organization.id, input.organizationId)); + return result; }), allInvitations: adminProcedure.query(async ({ ctx }) => { @@ -89,4 +145,13 @@ export const organizationRouter = createTRPCRouter({ orderBy: [desc(invitation.status)], }); }), + acceptInvitation: adminProcedure + .input(z.object({ invitationId: z.string() })) + .mutation(async ({ ctx, input }) => { + const result = await auth.api.acceptInvitation({ + invitationId: input.invitationId, + }); + + return result; + }), }); diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index c5382e9a9..2bfc06f78 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -1,8 +1,8 @@ import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema"; import { + IS_CLOUD, findUserByAuthId, findUserById, - IS_CLOUD, removeUserById, updateUser, verify2FA, diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 185de1368..969919030 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -71,6 +71,7 @@ export const organizationRelations = relations( }), servers: many(server), projects: many(projects), + members: many(member), }), ); diff --git a/packages/server/src/db/schema/session.ts b/packages/server/src/db/schema/session.ts index 99df9218e..f7c12dae0 100644 --- a/packages/server/src/db/schema/session.ts +++ b/packages/server/src/db/schema/session.ts @@ -12,7 +12,7 @@ export const session = pgTable("session_temp", { userAgent: text("user_agent"), userId: text("user_id") .notNull() - .references(() => users_temp.id), + .references(() => users_temp.id, { onDelete: "cascade" }), impersonatedBy: text("impersonated_by"), activeOrganizationId: text("active_organization_id"), }); diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index a4b9a4f1f..a8d75637b 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -7,7 +7,7 @@ import { organization, twoFactor, } from "better-auth/plugins"; -import { desc, eq } from "drizzle-orm"; +import { and, desc, eq } from "drizzle-orm"; import { db } from "../db"; import * as schema from "../db/schema"; @@ -43,22 +43,25 @@ export const auth = betterAuth({ after: createAuthMiddleware(async (ctx) => { if (ctx.path.startsWith("/sign-up")) { const newSession = ctx.context.newSession; - const organization = await db - .insert(schema.organization) - .values({ - name: "My Organization", - ownerId: newSession?.user?.id || "", - createdAt: new Date(), - }) - .returning() - .then((res) => res[0]); + if (ctx.headers?.get("x-dokploy-token")) { + } else { + const organization = await db + .insert(schema.organization) + .values({ + name: "My Organization", + ownerId: newSession?.user?.id || "", + createdAt: new Date(), + }) + .returning() + .then((res) => res[0]); - await db.insert(schema.member).values({ - userId: newSession?.user?.id || "", - organizationId: organization?.id || "", - role: "owner", - createdAt: new Date(), - }); + await db.insert(schema.member).values({ + userId: newSession?.user?.id || "", + organizationId: organization?.id || "", + role: "owner", + createdAt: new Date(), + }); + } } }), }, @@ -89,11 +92,13 @@ export const auth = betterAuth({ additionalFields: { role: { type: "string", - required: true, + // required: true, + input: false, }, ownerId: { type: "string", - required: true, + // required: true, + input: false, }, }, }, @@ -133,7 +138,13 @@ export const validateRequest = async (request: IncomingMessage) => { if (session?.user) { const member = await db.query.member.findFirst({ - where: eq(schema.member.userId, session.user.id), + where: and( + eq(schema.member.userId, session.user.id), + eq( + schema.member.organizationId, + session.session.activeOrganizationId || "", + ), + ), with: { organization: true, }, diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index eee6bb37c..07c537dea 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -3,6 +3,7 @@ import { db } from "@dokploy/server/db"; import { account, type apiCreateUserInvitation, + invitation, member, organization, users_temp, @@ -64,6 +65,13 @@ export const findUserById = async (userId: string) => { return user; }; +export const findOrganizationById = async (organizationId: string) => { + const organizationResult = await db.query.organization.findFirst({ + where: eq(organization.id, organizationId), + }); + return organizationResult; +}; + export const updateUser = async (userId: string, userData: Partial) => { const user = await db .update(users_temp) @@ -106,24 +114,34 @@ export const isAdminPresent = async () => { }; export const getUserByToken = async (token: string) => { - const user = await db.query.users_temp.findFirst({ - where: eq(users_temp.token, token), + const user = await db.query.invitation.findFirst({ + where: eq(invitation.id, token), columns: { id: true, email: true, - token: true, - isRegistered: true, + status: true, + expiresAt: true, + role: true, + inviterId: true, }, }); + if (!user) { throw new TRPCError({ code: "NOT_FOUND", message: "Invitation not found", }); } + + const userAlreadyExists = await db.query.users_temp.findFirst({ + where: eq(users_temp.email, user?.email || ""), + }); + + const { expiresAt, ...rest } = user; return { - ...user, - isExpired: user.isRegistered, + ...rest, + isExpired: user.expiresAt < new Date(), + userAlreadyExists: !!userAlreadyExists, }; }; diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts index 0a9f4e945..5a7484eb9 100644 --- a/packages/server/src/services/auth.ts +++ b/packages/server/src/services/auth.ts @@ -137,76 +137,76 @@ export const symmetricDecrypt = async ({ key, data }) => { const chacha = managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes)); return new TextDecoder().decode(chacha.decrypt(dataAsBytes)); }; -export const migrateExistingSecret = async ( - existingBase32Secret: string, - encryptionKey: string, -) => { - try { - // 1. Primero asegurarnos que el secreto base32 tenga el padding correcto - let paddedSecret = existingBase32Secret; - while (paddedSecret.length % 8 !== 0) { - paddedSecret += "="; - } +// export const migrateExistingSecret = async ( +// existingBase32Secret: string, +// encryptionKey: string, +// ) => { +// try { +// // 1. Primero asegurarnos que el secreto base32 tenga el padding correcto +// let paddedSecret = existingBase32Secret; +// while (paddedSecret.length % 8 !== 0) { +// paddedSecret += "="; +// } - // 2. Decodificar el base32 a bytes usando hi-base32 - const bytes = encode.decode.asBytes(paddedSecret.toUpperCase()); +// // 2. Decodificar el base32 a bytes usando hi-base32 +// const bytes = encode.decode.asBytes(paddedSecret.toUpperCase()); - // 3. Convertir los bytes a hex - const hexSecret = Buffer.from(bytes).toString("hex"); +// // 3. Convertir los bytes a hex +// const hexSecret = Buffer.from(bytes).toString("hex"); - // 4. Encriptar el secreto hex usando Better Auth - const encryptedSecret = await symmetricEncrypt({ - key: encryptionKey, - data: hexSecret, - }); +// // 4. Encriptar el secreto hex usando Better Auth +// const encryptedSecret = await symmetricEncrypt({ +// key: encryptionKey, +// data: hexSecret, +// }); - // 5. Crear TOTP con el secreto original para validación - const originalTotp = new TOTP({ - issuer: "Dokploy", - label: "migration-test", - algorithm: "SHA1", - digits: 6, - secret: existingBase32Secret, - }); +// // 5. Crear TOTP con el secreto original para validación +// const originalTotp = new TOTP({ +// issuer: "Dokploy", +// label: "migration-test", +// algorithm: "SHA1", +// digits: 6, +// secret: existingBase32Secret, +// }); - // 6. Generar un código de prueba con el secreto original - const testCode = originalTotp.generate(); +// // 6. Generar un código de prueba con el secreto original +// const testCode = originalTotp.generate(); - // 7. Validar que el código funcione con el secreto original - const isValid = originalTotp.validate({ token: testCode }) !== null; +// // 7. Validar que el código funcione con el secreto original +// const isValid = originalTotp.validate({ token: testCode }) !== null; - return { - originalSecret: existingBase32Secret, - hexSecret, - encryptedSecret, // Este es el valor que debes guardar en la base de datos - isValid, - testCode, - secretLength: hexSecret.length, - }; - } catch (error: unknown) { - const errorMessage = - error instanceof Error ? error.message : "Unknown error"; - console.error("Error durante la migración:", errorMessage); - throw new Error(`Error al migrar el secreto: ${errorMessage}`); - } -}; +// return { +// originalSecret: existingBase32Secret, +// hexSecret, +// encryptedSecret, // Este es el valor que debes guardar en la base de datos +// isValid, +// testCode, +// secretLength: hexSecret.length, +// }; +// } catch (error: unknown) { +// const errorMessage = +// error instanceof Error ? error.message : "Unknown error"; +// console.error("Error durante la migración:", errorMessage); +// throw new Error(`Error al migrar el secreto: ${errorMessage}`); +// } +// }; -// // Ejemplo de uso con el secreto de prueba -// const testMigration = await migrateExistingSecret( -// "46JMUCG4NJ3CIU6LQAIVFWUW", -// process.env.BETTER_AUTH_SECRET || "your-encryption-key", -// ); -// console.log("\nPrueba de migración:"); -// console.log("Secreto original (base32):", testMigration.originalSecret); -// console.log("Secreto convertido (hex):", testMigration.hexSecret); -// console.log("Secreto encriptado:", testMigration.encryptedSecret); -// console.log("Longitud del secreto hex:", testMigration.secretLength); -// console.log("¿Conversión válida?:", testMigration.isValid); -// console.log("Código de prueba:", testMigration.testCode); -const secret = "46JMUCG4NJ3CIU6LQAIVFWUW"; -const isValid = createOTP(secret, { - digits: 6, - period: 30, -}).verify("123456"); +// // // Ejemplo de uso con el secreto de prueba +// // const testMigration = await migrateExistingSecret( +// // "46JMUCG4NJ3CIU6LQAIVFWUW", +// // process.env.BETTER_AUTH_SECRET || "your-encryption-key", +// // ); +// // console.log("\nPrueba de migración:"); +// // console.log("Secreto original (base32):", testMigration.originalSecret); +// // console.log("Secreto convertido (hex):", testMigration.hexSecret); +// // console.log("Secreto encriptado:", testMigration.encryptedSecret); +// // console.log("Longitud del secreto hex:", testMigration.secretLength); +// // console.log("¿Conversión válida?:", testMigration.isValid); +// // console.log("Código de prueba:", testMigration.testCode); +// const secret = "46JMUCG4NJ3CIU6LQAIVFWUW"; +// const isValid = createOTP(secret, { +// digits: 6, +// period: 30, +// }).verify("123456"); -console.log(isValid.then((isValid) => console.log(isValid))); +// console.log(isValid.then((isValid) => console.log(isValid))); From a9e12c2b18d6335ad9130812c8a5aa08e7219e96 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 20 Feb 2025 01:42:35 -0600 Subject: [PATCH 45/89] refactor: update organization context in API routers --- .../settings/users/show-invitations.tsx | 2 +- apps/dokploy/server/api/routers/bitbucket.ts | 2 +- .../dokploy/server/api/routers/destination.ts | 7 +++++-- apps/dokploy/server/api/routers/gitlab.ts | 2 +- .../server/api/routers/notification.ts | 20 +++++++++++++++---- .../server/api/routers/organization.ts | 11 +++++----- apps/dokploy/server/api/trpc.ts | 1 - 7 files changed, 29 insertions(+), 16 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx index 3a36b780e..b2ee81684 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx @@ -14,7 +14,6 @@ import { DropdownMenuLabel, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -import copy from "copy-to-clipboard"; import { Table, TableBody, @@ -26,6 +25,7 @@ import { } from "@/components/ui/table"; import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; +import copy from "copy-to-clipboard"; import { format } from "date-fns"; import { Mail, MoreHorizontal, Users } from "lucide-react"; import { Loader2 } from "lucide-react"; diff --git a/apps/dokploy/server/api/routers/bitbucket.ts b/apps/dokploy/server/api/routers/bitbucket.ts index 7a8462641..fa02be8d6 100644 --- a/apps/dokploy/server/api/routers/bitbucket.ts +++ b/apps/dokploy/server/api/routers/bitbucket.ts @@ -22,7 +22,7 @@ export const bitbucketRouter = createTRPCRouter({ .input(apiCreateBitbucket) .mutation(async ({ input, ctx }) => { try { - return await createBitbucket(input, ctx.user.ownerId); + return await createBitbucket(input, ctx.session.activeOrganizationId); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", diff --git a/apps/dokploy/server/api/routers/destination.ts b/apps/dokploy/server/api/routers/destination.ts index 770cb699f..f1d582c50 100644 --- a/apps/dokploy/server/api/routers/destination.ts +++ b/apps/dokploy/server/api/routers/destination.ts @@ -28,7 +28,10 @@ export const destinationRouter = createTRPCRouter({ .input(apiCreateDestination) .mutation(async ({ input, ctx }) => { try { - return await createDestintation(input, ctx.user.ownerId); + return await createDestintation( + input, + ctx.session.activeOrganizationId, + ); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -111,7 +114,7 @@ export const destinationRouter = createTRPCRouter({ } return await removeDestinationById( input.destinationId, - ctx.user.ownerId, + ctx.session.activeOrganizationId, ); } catch (error) { throw error; diff --git a/apps/dokploy/server/api/routers/gitlab.ts b/apps/dokploy/server/api/routers/gitlab.ts index b702bc2a4..daae68a5a 100644 --- a/apps/dokploy/server/api/routers/gitlab.ts +++ b/apps/dokploy/server/api/routers/gitlab.ts @@ -25,7 +25,7 @@ export const gitlabRouter = createTRPCRouter({ .input(apiCreateGitlab) .mutation(async ({ input, ctx }) => { try { - return await createGitlab(input, ctx.user.ownerId); + return await createGitlab(input, ctx.session.activeOrganizationId); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", diff --git a/apps/dokploy/server/api/routers/notification.ts b/apps/dokploy/server/api/routers/notification.ts index bba6c7db9..6a893d363 100644 --- a/apps/dokploy/server/api/routers/notification.ts +++ b/apps/dokploy/server/api/routers/notification.ts @@ -110,7 +110,10 @@ export const notificationRouter = createTRPCRouter({ .input(apiCreateTelegram) .mutation(async ({ input, ctx }) => { try { - return await createTelegramNotification(input, ctx.user.ownerId); + return await createTelegramNotification( + input, + ctx.session.activeOrganizationId, + ); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -162,7 +165,10 @@ export const notificationRouter = createTRPCRouter({ .input(apiCreateDiscord) .mutation(async ({ input, ctx }) => { try { - return await createDiscordNotification(input, ctx.user.ownerId); + return await createDiscordNotification( + input, + ctx.session.activeOrganizationId, + ); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -223,7 +229,10 @@ export const notificationRouter = createTRPCRouter({ .input(apiCreateEmail) .mutation(async ({ input, ctx }) => { try { - return await createEmailNotification(input, ctx.user.ownerId); + return await createEmailNotification( + input, + ctx.session.activeOrganizationId, + ); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", @@ -388,7 +397,10 @@ export const notificationRouter = createTRPCRouter({ .input(apiCreateGotify) .mutation(async ({ input, ctx }) => { try { - return await createGotifyNotification(input, ctx.user.ownerId); + return await createGotifyNotification( + input, + ctx.session.activeOrganizationId, + ); } catch (error) { throw new TRPCError({ code: "BAD_REQUEST", diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts index 7158a01ae..30c2630d6 100644 --- a/apps/dokploy/server/api/routers/organization.ts +++ b/apps/dokploy/server/api/routers/organization.ts @@ -5,12 +5,12 @@ import { organization, users_temp, } from "@/server/db/schema"; +import { IS_CLOUD, auth } from "@dokploy/server/index"; import { TRPCError } from "@trpc/server"; import { and, desc, eq, exists } from "drizzle-orm"; import { nanoid } from "nanoid"; import { z } from "zod"; import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; -import { auth, IS_CLOUD } from "@dokploy/server/index"; export const organizationRouter = createTRPCRouter({ create: protectedProcedure .input( @@ -148,10 +148,9 @@ export const organizationRouter = createTRPCRouter({ acceptInvitation: adminProcedure .input(z.object({ invitationId: z.string() })) .mutation(async ({ ctx, input }) => { - const result = await auth.api.acceptInvitation({ - invitationId: input.invitationId, - }); - - return result; + // const result = await auth.api.acceptInvitation({ + // invitationId: input.invitationId, + // }); + // return result; }), }); diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index c63839c5e..8e8206427 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -9,7 +9,6 @@ // import { getServerAuthSession } from "@/server/auth"; import { db } from "@/server/db"; -import { validateBearerToken } from "@dokploy/server"; import { validateRequest } from "@dokploy/server/lib/auth"; import type { OpenApiMeta } from "@dokploy/trpc-openapi"; import { TRPCError, initTRPC } from "@trpc/server"; From 5a1145996daf3abd9f1db0bbce5ad7a0879b59c9 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 20 Feb 2025 01:50:01 -0600 Subject: [PATCH 46/89] feat: add backup code authentication for 2FA login --- .../settings/profile/disable-2fa.tsx | 4 +- apps/dokploy/pages/index.tsx | 212 +++++++++++++----- 2 files changed, 156 insertions(+), 60 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx b/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx index 79306bf18..f07aaed6a 100644 --- a/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx @@ -35,6 +35,7 @@ type PasswordForm = z.infer; export const Disable2FA = () => { const utils = api.useUtils(); + const [isOpen, setIsOpen] = useState(false); const [isLoading, setIsLoading] = useState(false); const form = useForm({ @@ -72,7 +73,7 @@ export const Disable2FA = () => { }; return ( - + @@ -116,6 +117,7 @@ export const Disable2FA = () => { variant="outline" onClick={() => { form.reset(); + setIsOpen(false); }} > Cancel diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 8013c6319..cb3684a5a 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -20,16 +20,23 @@ import { InputOTPSlot, } from "@/components/ui/input-otp"; import { Label } from "@/components/ui/label"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; import { authClient } from "@/lib/auth-client"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { IS_CLOUD, auth, isAdminPresent } from "@dokploy/server"; import { validateRequest } from "@dokploy/server/lib/auth"; import { zodResolver } from "@hookform/resolvers/zod"; -import { Session, getSessionCookie } from "better-auth"; -import { betterFetch } from "better-auth/react"; import base32 from "hi-base32"; import { REGEXP_ONLY_DIGITS } from "input-otp"; +import { AlertTriangle } from "lucide-react"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; @@ -48,8 +55,14 @@ const TwoFactorSchema = z.object({ code: z.string().min(6), }); +const BackupCodeSchema = z.object({ + code: z.string().min(8, { + message: "Backup code must be at least 8 characters", + }), +}); + type LoginForm = z.infer; -type TwoFactorForm = z.infer; +type BackupCodeForm = z.infer; interface Props { IS_CLOUD: boolean; @@ -58,9 +71,12 @@ export default function Home({ IS_CLOUD }: Props) { const router = useRouter(); const [isLoginLoading, setIsLoginLoading] = useState(false); const [isTwoFactorLoading, setIsTwoFactorLoading] = useState(false); + const [isBackupCodeLoading, setIsBackupCodeLoading] = useState(false); const [isTwoFactor, setIsTwoFactor] = useState(false); const [error, setError] = useState(null); const [twoFactorCode, setTwoFactorCode] = useState(""); + const [isBackupCodeModalOpen, setIsBackupCodeModalOpen] = useState(false); + const [backupCode, setBackupCode] = useState(""); const loginForm = useForm({ resolver: zodResolver(LoginSchema), @@ -128,15 +144,33 @@ export default function Home({ IS_CLOUD }: Props) { } }; - const convertBase32ToHex = (base32Secret: string) => { + const onBackupCodeSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (backupCode.length < 8) { + toast.error("Please enter a valid backup code"); + return; + } + + setIsBackupCodeLoading(true); try { - // Usar asBytes() para obtener los bytes directamente - const bytes = base32.decode.asBytes(base32Secret.toUpperCase()); - // Convertir bytes a hex - return Buffer.from(bytes).toString("hex"); + const { data, error } = await authClient.twoFactor.verifyBackupCode({ + code: backupCode.trim(), + }); + + if (error) { + toast.error(error.message); + setError( + error.message || "An error occurred while verifying backup code", + ); + return; + } + + toast.success("Logged in successfully"); + router.push("/dashboard/projects"); } catch (error) { - console.error("Error converting base32 to hex:", error); - return base32Secret; // Fallback al valor original si hay error + toast.error("An error occurred while verifying backup code"); + } finally { + setIsBackupCodeLoading(false); } }; @@ -206,56 +240,116 @@ export default function Home({ IS_CLOUD }: Props) { ) : ( -
-
- - - - - - - - - - - - - Enter the 6-digit code from your authenticator app - -
+ <> + +
+ + + + + + + + + + + + + Enter the 6-digit code from your authenticator app + + +
-
- - -
-
+
+ + +
+ + + + + + Enter Backup Code + + Enter one of your backup codes to access your account + + + +
+
+ + setBackupCode(e.target.value)} + placeholder="Enter your backup code" + className="font-mono" + /> + + Enter one of the backup codes you received when setting up + 2FA + +
+ +
+ + +
+
+
+
+ )}
From 790894ab93589fbe63676b236fe3e39c516df9d7 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 20 Feb 2025 23:02:02 -0600 Subject: [PATCH 47/89] refactor: migrate admin API calls to user router --- .../show-paid-container-monitoring.tsx | 2 +- .../paid/servers/show-paid-monitoring.tsx | 2 +- .../components/dashboard/projects/show.tsx | 2 +- .../settings/billing/show-billing.tsx | 12 +-- .../settings/billing/show-welcome-dokploy.tsx | 2 +- .../git/bitbucket/add-bitbucket-provider.tsx | 2 +- .../git/github/add-github-provider.tsx | 2 +- .../git/gitlab/add-gitlab-provider.tsx | 2 +- .../settings/profile/disable-2fa.tsx | 1 + .../settings/profile/generate-token.tsx | 2 +- .../settings/profile/profile-form.tsx | 2 +- .../settings/profile/remove-self-account.tsx | 2 +- .../servers/actions/toggle-docker-cleanup.tsx | 4 +- .../settings/servers/setup-monitoring.tsx | 2 +- .../settings/users/add-permissions.tsx | 2 +- .../settings/users/show-invitations.tsx | 97 +++++++++++-------- .../dashboard/settings/users/show-users.tsx | 26 +---- .../dashboard/settings/web-domain.tsx | 2 +- .../dashboard/settings/web-server.tsx | 4 +- .../settings/web-server/update-server-ip.tsx | 4 +- apps/dokploy/components/layouts/side.tsx | 4 +- apps/dokploy/components/layouts/user-nav.tsx | 2 +- apps/dokploy/pages/dashboard/monitoring.tsx | 2 +- .../pages/dashboard/project/[projectId].tsx | 2 +- .../services/application/[applicationId].tsx | 4 +- .../services/compose/[composeId].tsx | 4 +- .../services/mariadb/[mariadbId].tsx | 4 +- .../[projectId]/services/mongo/[mongoId].tsx | 4 +- .../[projectId]/services/mysql/[mysqlId].tsx | 4 +- .../services/postgres/[postgresId].tsx | 4 +- .../[projectId]/services/redis/[redisId].tsx | 4 +- .../pages/dashboard/settings/index.tsx | 10 +- .../pages/dashboard/settings/profile.tsx | 2 +- .../pages/dashboard/settings/server.tsx | 14 --- apps/dokploy/pages/index.tsx | 16 +-- apps/dokploy/pages/invitation.tsx | 2 +- apps/dokploy/server/api/routers/admin.ts | 5 +- apps/dokploy/server/api/routers/compose.ts | 1 - .../server/api/routers/organization.ts | 13 +-- apps/dokploy/server/api/routers/user.ts | 69 ++++++++++++- 40 files changed, 185 insertions(+), 159 deletions(-) diff --git a/apps/dokploy/components/dashboard/monitoring/paid/container/show-paid-container-monitoring.tsx b/apps/dokploy/components/dashboard/monitoring/paid/container/show-paid-container-monitoring.tsx index 3636a391a..3b189c2ac 100644 --- a/apps/dokploy/components/dashboard/monitoring/paid/container/show-paid-container-monitoring.tsx +++ b/apps/dokploy/components/dashboard/monitoring/paid/container/show-paid-container-monitoring.tsx @@ -79,7 +79,7 @@ export const ContainerPaidMonitoring = ({ appName, baseUrl, token }: Props) => { data, isLoading, error: queryError, - } = api.admin.getContainerMetrics.useQuery( + } = api.user.getContainerMetrics.useQuery( { url: baseUrl, token, diff --git a/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx b/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx index 043b5c625..87c030570 100644 --- a/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx +++ b/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx @@ -73,7 +73,7 @@ export const ShowPaidMonitoring = ({ data, isLoading, error: queryError, - } = api.admin.getServerMetrics.useQuery( + } = api.user.getServerMetrics.useQuery( { url: BASE_URL, token, diff --git a/apps/dokploy/components/dashboard/projects/show.tsx b/apps/dokploy/components/dashboard/projects/show.tsx index b9c96d314..a8c3ed5c1 100644 --- a/apps/dokploy/components/dashboard/projects/show.tsx +++ b/apps/dokploy/components/dashboard/projects/show.tsx @@ -51,7 +51,7 @@ import { ProjectEnvironment } from "./project-environment"; export const ShowProjects = () => { const utils = api.useUtils(); const { data, isLoading } = api.project.all.useQuery(); - const { data: auth } = api.auth.get.useQuery(); + const { data: auth } = api.user.get.useQuery(); const { mutateAsync } = api.project.remove.useMutation(); const [searchQuery, setSearchQuery] = useState(""); diff --git a/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx b/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx index 9f3430de0..c76ec33e8 100644 --- a/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx +++ b/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx @@ -39,7 +39,7 @@ export const calculatePrice = (count: number, isAnnual = false) => { }; export const ShowBilling = () => { const { data: servers } = api.server.all.useQuery(undefined); - const { data: admin } = api.admin.one.useQuery(); + const { data: admin } = api.user.get.useQuery(); const { data, isLoading } = api.stripe.getProducts.useQuery(); const { mutateAsync: createCheckoutSession } = api.stripe.createCheckoutSession.useMutation(); @@ -70,7 +70,7 @@ export const ShowBilling = () => { return isAnnual ? interval === "year" : interval === "month"; }); - const maxServers = admin?.serversQuantity ?? 1; + const maxServers = admin?.user.serversQuantity ?? 1; const percentage = ((servers?.length ?? 0) / maxServers) * 100; const safePercentage = Math.min(percentage, 100); @@ -98,17 +98,17 @@ export const ShowBilling = () => { Annual - {admin?.stripeSubscriptionId && ( + {admin?.user.stripeSubscriptionId && (

Servers Plan

You have {servers?.length} server on your plan of{" "} - {admin?.serversQuantity} servers + {admin?.user.serversQuantity} servers

- {admin && admin.serversQuantity! <= servers?.length! && ( + {admin && admin.user.serversQuantity! <= servers?.length! && (
@@ -279,7 +279,7 @@ export const ShowBilling = () => { "flex flex-row items-center gap-2 mt-4", )} > - {admin?.stripeCustomerId && ( + {admin?.user.stripeCustomerId && ( diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx index b78e750c3..7eebf7083 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx @@ -178,8 +178,7 @@ const Service = (
- {(auth?.role === "owner" || - auth?.user?.canDeleteServices) && ( + {(auth?.role === "owner" || auth?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx index cceda8858..46c9864b4 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx @@ -173,8 +173,7 @@ const Service = (
- {(auth?.role === "owner" || - auth?.user?.canDeleteServices) && ( + {(auth?.role === "owner" || auth?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx index 788846e1d..6aa7677a3 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx @@ -147,8 +147,7 @@ const Mariadb = (
- {(auth?.role === "owner" || - auth?.user?.canDeleteServices) && ( + {(auth?.role === "owner" || auth?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx index f03c4dfc4..2e3aae31f 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx @@ -148,8 +148,7 @@ const Mongo = (
- {(auth?.role === "owner" || - auth?.user?.canDeleteServices) && ( + {(auth?.role === "owner" || auth?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx index 52e2cd072..3e75603dd 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx @@ -148,8 +148,7 @@ const MySql = (
- {(auth?.role === "owner" || - auth?.user?.canDeleteServices) && ( + {(auth?.role === "owner" || auth?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx index 8ff2044b5..dd0c312d0 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx @@ -147,8 +147,7 @@ const Postgresql = (
- {(auth?.role === "owner" || - auth?.user?.canDeleteServices) && ( + {(auth?.role === "owner" || auth?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx index 9ad8d53c2..c7e5643a6 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx @@ -147,8 +147,7 @@ const Redis = (
- {(auth?.role === "owner" || - auth?.user?.canDeleteServices) && ( + {(auth?.role === "owner" || auth?.canDeleteServices) && ( )}
diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx index cfded9915..7bacde246 100644 --- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx +++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx @@ -54,7 +54,7 @@ export async function getServerSideProps( userId: user.id, }); - if (!userR.canAccessToGitProviders) { + if (!userR?.canAccessToGitProviders) { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index da0dec728..79a3366d4 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -20,9 +20,7 @@ const Page = () => {
- {(data?.user?.canAccessToAPI || data?.role === "owner") && ( - - )} + {(data?.canAccessToAPI || data?.role === "owner") && } {isCloud && }
diff --git a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx index c97df7ba1..8c5082e39 100644 --- a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx +++ b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx @@ -55,7 +55,7 @@ export async function getServerSideProps( userId: user.id, }); - if (!userR.canAccessToSSHKeys) { + if (!userR?.canAccessToSSHKeys) { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/swarm.tsx b/apps/dokploy/pages/dashboard/swarm.tsx index 3b59c47b0..c693fd8cf 100644 --- a/apps/dokploy/pages/dashboard/swarm.tsx +++ b/apps/dokploy/pages/dashboard/swarm.tsx @@ -58,7 +58,7 @@ export async function getServerSideProps( userId: user.id, }); - if (!userR.canAccessToDocker) { + if (!userR?.canAccessToDocker) { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/dashboard/traefik.tsx b/apps/dokploy/pages/dashboard/traefik.tsx index 8dcd3f084..3153e80d3 100644 --- a/apps/dokploy/pages/dashboard/traefik.tsx +++ b/apps/dokploy/pages/dashboard/traefik.tsx @@ -58,7 +58,7 @@ export async function getServerSideProps( userId: user.id, }); - if (!userR.canAccessToTraefikFiles) { + if (!userR?.canAccessToTraefikFiles) { return { redirect: { permanent: true, diff --git a/apps/dokploy/pages/swagger.tsx b/apps/dokploy/pages/swagger.tsx index e4a6fac8d..3d8cc01d9 100644 --- a/apps/dokploy/pages/swagger.tsx +++ b/apps/dokploy/pages/swagger.tsx @@ -63,7 +63,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { userId: user.id, }); - if (!userR.canAccessToAPI) { + if (!userR?.canAccessToAPI) { return { redirect: { permanent: true, diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index 5fc79f437..e3c24e538 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -8,6 +8,7 @@ import { applications, compose, mariadb, + member, mongo, mysql, postgres, @@ -29,8 +30,8 @@ import { findUserByAuthId, findUserById, updateProjectById, + findMemberById, } from "@dokploy/server"; - export const projectRouter = createTRPCRouter({ create: protectedProcedure .input(apiCreateProject) @@ -71,7 +72,10 @@ export const projectRouter = createTRPCRouter({ .input(apiFindOneProject) .query(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - const { accessedServices } = await findUserById(ctx.user.id); + const { accessedServices } = await findMemberById( + ctx.user.id, + ctx.session.activeOrganizationId, + ); await checkProjectAccess(ctx.user.id, "access", input.projectId); @@ -129,8 +133,9 @@ export const projectRouter = createTRPCRouter({ all: protectedProcedure.query(async ({ ctx }) => { // console.log(ctx.user); if (ctx.user.rol === "member") { - const { accessedProjects, accessedServices } = await findUserById( + const { accessedProjects, accessedServices } = await findMemberById( ctx.user.id, + ctx.session.activeOrganizationId, ); if (accessedProjects.length === 0) { diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index 170af9084..9351a0031 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -1,7 +1,7 @@ import { db } from "@dokploy/server/db"; -import type { users_temp } from "@dokploy/server/db/schema"; +import { type users_temp, member } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; -import { eq } from "drizzle-orm"; +import { and, eq } from "drizzle-orm"; import { findUserById } from "./admin"; export type User = typeof users_temp.$inferSelect; @@ -191,3 +191,26 @@ export const checkProjectAccess = async ( }); } }; + +export const findMemberById = async ( + userId: string, + organizationId: string, +) => { + const result = await db.query.member.findFirst({ + where: and( + eq(member.userId, userId), + eq(member.organizationId, organizationId), + ), + with: { + user: true, + }, + }); + + if (!result) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "Permission denied", + }); + } + return result; +}; From 5ae103e779f03a0900d0e3e9b61cb0c159f1a461 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Fri, 21 Feb 2025 00:48:04 -0600 Subject: [PATCH 52/89] refactor: update permission checks to use organization context --- apps/dokploy/components/layouts/side.tsx | 21 ++-- apps/dokploy/server/api/routers/project.ts | 25 ++++- packages/server/src/services/user.ts | 111 +++++++++++++++------ 3 files changed, 107 insertions(+), 50 deletions(-) diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 22f86fb08..f1296ce33 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -155,7 +155,7 @@ const MENU: Menu = { // Only enabled for admins and users with access to Traefik files in non-cloud environments isEnabled: ({ auth, isCloud }) => !!( - (auth?.role === "owner" || auth?.user?.canAccessToTraefikFiles) && + (auth?.role === "owner" || auth?.canAccessToTraefikFiles) && !isCloud ), }, @@ -166,10 +166,7 @@ const MENU: Menu = { icon: BlocksIcon, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, isCloud }) => - !!( - (auth?.role === "owner" || auth?.user?.canAccessToDocker) && - !isCloud - ), + !!((auth?.role === "owner" || auth?.canAccessToDocker) && !isCloud), }, { isSingle: true, @@ -178,10 +175,7 @@ const MENU: Menu = { icon: PieChart, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, isCloud }) => - !!( - (auth?.role === "owner" || auth?.user?.canAccessToDocker) && - !isCloud - ), + !!((auth?.role === "owner" || auth?.canAccessToDocker) && !isCloud), }, { isSingle: true, @@ -190,10 +184,7 @@ const MENU: Menu = { icon: Forward, // Only enabled for admins and users with access to Docker in non-cloud environments isEnabled: ({ auth, isCloud }) => - !!( - (auth?.role === "owner" || auth?.user?.canAccessToDocker) && - !isCloud - ), + !!((auth?.role === "owner" || auth?.canAccessToDocker) && !isCloud), }, // Legacy unused menu, adjusted to the new structure @@ -291,7 +282,7 @@ const MENU: Menu = { url: "/dashboard/settings/ssh-keys", // Only enabled for admins and users with access to SSH keys isEnabled: ({ auth }) => - !!(auth?.role === "owner" || auth?.user?.canAccessToSSHKeys), + !!(auth?.role === "owner" || auth?.canAccessToSSHKeys), }, { isSingle: true, @@ -300,7 +291,7 @@ const MENU: Menu = { icon: GitBranch, // Only enabled for admins and users with access to Git providers isEnabled: ({ auth }) => - !!(auth?.role === "owner" || auth?.user?.canAccessToGitProviders), + !!(auth?.role === "owner" || auth?.canAccessToGitProviders), }, { isSingle: true, diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index e3c24e538..68b068bc3 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -38,7 +38,11 @@ export const projectRouter = createTRPCRouter({ .mutation(async ({ ctx, input }) => { try { if (ctx.user.rol === "member") { - await checkProjectAccess(ctx.user.id, "create"); + await checkProjectAccess( + ctx.user.id, + "create", + ctx.session.activeOrganizationId, + ); } const admin = await findUserById(ctx.user.ownerId); @@ -55,7 +59,11 @@ export const projectRouter = createTRPCRouter({ ctx.session.activeOrganizationId, ); if (ctx.user.rol === "member") { - await addNewProject(ctx.user.id, project.projectId); + await addNewProject( + ctx.user.id, + project.projectId, + ctx.session.activeOrganizationId, + ); } return project; @@ -77,7 +85,12 @@ export const projectRouter = createTRPCRouter({ ctx.session.activeOrganizationId, ); - await checkProjectAccess(ctx.user.id, "access", input.projectId); + await checkProjectAccess( + ctx.user.id, + "access", + ctx.session.activeOrganizationId, + input.projectId, + ); const project = await db.query.projects.findFirst({ where: and( @@ -212,7 +225,11 @@ export const projectRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "member") { - await checkProjectAccess(ctx.user.id, "delete"); + await checkProjectAccess( + ctx.user.id, + "delete", + ctx.session.activeOrganizationId, + ); } const currentProject = await findProjectById(input.projectId); if ( diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index 9351a0031..9e924e9f1 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -33,32 +33,48 @@ export const findUserByAuthId = async (authId: string) => { // return userR; }; -export const addNewProject = async (userId: string, projectId: string) => { - const userR = await findUserById(userId); +export const addNewProject = async ( + userId: string, + projectId: string, + organizationId: string, +) => { + const userR = await findMemberById(userId, organizationId); - // await db - // .update(user) - // .set({ - // accessedProjects: [...userR.accessedProjects, projectId], - // }) - // .where(eq(user.authId, authId)); + await db + .update(member) + .set({ + accessedProjects: [...userR.accessedProjects, projectId], + }) + .where( + and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), + ); }; -export const addNewService = async (userId: string, serviceId: string) => { - const userR = await findUserById(userId); - // await db - // .update(user) - // .set({ - // accessedServices: [...userR.accessedServices, serviceId], - // }) - // .where(eq(user.userId, userId)); +export const addNewService = async ( + userId: string, + serviceId: string, + organizationId: string, +) => { + const userR = await findMemberById(userId, organizationId); + await db + .update(member) + .set({ + accessedServices: [...userR.accessedServices, serviceId], + }) + .where( + and(eq(member.id, userR.id), eq(member.organizationId, organizationId)), + ); }; export const canPerformCreationService = async ( userId: string, projectId: string, + organizationId: string, ) => { - const { accessedProjects, canCreateServices } = await findUserById(userId); + const { accessedProjects, canCreateServices } = await findMemberById( + userId, + organizationId, + ); const haveAccessToProject = accessedProjects.includes(projectId); if (canCreateServices && haveAccessToProject) { @@ -71,8 +87,9 @@ export const canPerformCreationService = async ( export const canPerformAccessService = async ( userId: string, serviceId: string, + organizationId: string, ) => { - const { accessedServices } = await findUserById(userId); + const { accessedServices } = await findMemberById(userId, organizationId); const haveAccessToService = accessedServices.includes(serviceId); if (haveAccessToService) { @@ -85,8 +102,12 @@ export const canPerformAccessService = async ( export const canPeformDeleteService = async ( userId: string, serviceId: string, + organizationId: string, ) => { - const { accessedServices, canDeleteServices } = await findUserById(userId); + const { accessedServices, canDeleteServices } = await findMemberById( + userId, + organizationId, + ); const haveAccessToService = accessedServices.includes(serviceId); if (canDeleteServices && haveAccessToService) { @@ -96,8 +117,11 @@ export const canPeformDeleteService = async ( return false; }; -export const canPerformCreationProject = async (userId: string) => { - const { canCreateProjects } = await findUserById(userId); +export const canPerformCreationProject = async ( + userId: string, + organizationId: string, +) => { + const { canCreateProjects } = await findMemberById(userId, organizationId); if (canCreateProjects) { return true; @@ -106,8 +130,11 @@ export const canPerformCreationProject = async (userId: string) => { return false; }; -export const canPerformDeleteProject = async (userId: string) => { - const { canDeleteProjects } = await findUserById(userId); +export const canPerformDeleteProject = async ( + userId: string, + organizationId: string, +) => { + const { canDeleteProjects } = await findMemberById(userId, organizationId); if (canDeleteProjects) { return true; @@ -119,8 +146,9 @@ export const canPerformDeleteProject = async (userId: string) => { export const canPerformAccessProject = async ( userId: string, projectId: string, + organizationId: string, ) => { - const { accessedProjects } = await findUserById(userId); + const { accessedProjects } = await findMemberById(userId, organizationId); const haveAccessToProject = accessedProjects.includes(projectId); @@ -130,26 +158,45 @@ export const canPerformAccessProject = async ( return false; }; -export const canAccessToTraefikFiles = async (userId: string) => { - const { canAccessToTraefikFiles } = await findUserById(userId); +export const canAccessToTraefikFiles = async ( + userId: string, + organizationId: string, +) => { + const { canAccessToTraefikFiles } = await findMemberById( + userId, + organizationId, + ); return canAccessToTraefikFiles; }; export const checkServiceAccess = async ( userId: string, serviceId: string, + organizationId: string, action = "access" as "access" | "create" | "delete", ) => { let hasPermission = false; switch (action) { case "create": - hasPermission = await canPerformCreationService(userId, serviceId); + hasPermission = await canPerformCreationService( + userId, + serviceId, + organizationId, + ); break; case "access": - hasPermission = await canPerformAccessService(userId, serviceId); + hasPermission = await canPerformAccessService( + userId, + serviceId, + organizationId, + ); break; case "delete": - hasPermission = await canPeformDeleteService(userId, serviceId); + hasPermission = await canPeformDeleteService( + userId, + serviceId, + organizationId, + ); break; default: hasPermission = false; @@ -165,6 +212,7 @@ export const checkServiceAccess = async ( export const checkProjectAccess = async ( authId: string, action: "create" | "delete" | "access", + organizationId: string, projectId?: string, ) => { let hasPermission = false; @@ -173,13 +221,14 @@ export const checkProjectAccess = async ( hasPermission = await canPerformAccessProject( authId, projectId as string, + organizationId, ); break; case "create": - hasPermission = await canPerformCreationProject(authId); + hasPermission = await canPerformCreationProject(authId, organizationId); break; case "delete": - hasPermission = await canPerformDeleteProject(authId); + hasPermission = await canPerformDeleteProject(authId, organizationId); break; default: hasPermission = false; From b02195db17ac05369cfad80311f44c98a35be7f2 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 02:31:04 -0600 Subject: [PATCH 53/89] feat: add organization invitation system and update user profile management --- .../settings/profile/profile-form.tsx | 2 +- apps/dokploy/components/layouts/side.tsx | 190 ++++++++++-------- .../dokploy/server/api/routers/application.ts | 6 +- apps/dokploy/server/api/routers/compose.ts | 12 +- apps/dokploy/server/api/routers/mariadb.ts | 6 +- apps/dokploy/server/api/routers/mongo.ts | 6 +- apps/dokploy/server/api/routers/mysql.ts | 6 +- apps/dokploy/server/api/routers/postgres.ts | 6 +- apps/dokploy/server/api/routers/redis.ts | 6 +- apps/dokploy/server/api/routers/registry.ts | 2 +- apps/dokploy/server/api/routers/user.ts | 27 ++- 11 files changed, 169 insertions(+), 100 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx index ba2009bd2..ca1bf3c21 100644 --- a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx @@ -65,7 +65,7 @@ export const ProfileForm = () => { isLoading: isUpdating, isError, error, - } = api.auth.update.useMutation(); + } = api.user.update.useMutation(); const { t } = useTranslation("settings"); const [gravatarHash, setGravatarHash] = useState(null); diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index f1296ce33..cba10ca0f 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -27,6 +27,8 @@ import { Trash2, User, Users, + ChevronsUpDown, + Plus, } from "lucide-react"; import { usePathname } from "next/navigation"; import type * as React from "react"; @@ -75,6 +77,20 @@ import { useRouter } from "next/router"; import { Logo } from "../shared/logo"; import { UpdateServerButton } from "./update-server"; import { UserNav } from "./user-nav"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { authClient } from "@/lib/auth-client"; +import { toast } from "sonner"; +import { AddOrganization } from "../dashboard/organization/handle-organization"; +import { DialogAction } from "../shared/dialog-action"; +import { Button } from "../ui/button"; // The types of the queries we are going to use type AuthQueryOutput = inferRouterOutputs["auth"]["get"]; @@ -473,46 +489,6 @@ interface Props { function LogoWrapper() { return ; } -import { ChevronsUpDown, Plus } from "lucide-react"; - -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { authClient } from "@/lib/auth-client"; -import { toast } from "sonner"; -import { AddOrganization } from "../dashboard/organization/handle-organization"; -import { DialogAction } from "../shared/dialog-action"; -import { Button } from "../ui/button"; -const data = { - user: { - name: "shadcn", - email: "m@example.com", - avatar: "/avatars/shadcn.jpg", - }, - teams: [ - { - name: "Acme Inc", - logo: GalleryVerticalEnd, - plan: "Enterprise", - }, - { - name: "Acme Corp.", - logo: AudioWaveform, - plan: "Startup", - }, - { - name: "Evil Corp.", - logo: Command, - plan: "Free", - }, - ], -}; function SidebarLogo() { const { state } = useSidebar(); @@ -529,6 +505,10 @@ function SidebarLogo() { api.organization.delete.useMutation(); const { isMobile } = useSidebar(); const { data: activeOrganization } = authClient.useActiveOrganization(); + const utils = api.useUtils(); + + const { data: invitations, refetch: refetchInvitations } = + api.user.getInvitations.useQuery(); const [activeTeam, setActiveTeam] = useState< typeof activeOrganization | null @@ -549,31 +529,27 @@ function SidebarLogo() {
) : ( - + - {/*
*/} -
- -
-
- - {activeTeam?.name} - +
+
+ +
+
+

+ {activeOrganization?.name} +

+
@@ -587,14 +563,13 @@ function SidebarLogo() { Organizations - {organizations?.map((org, index) => ( + {organizations?.map((org) => (
{ await authClient.organization.setActive({ organizationId: org.id, }); - window.location.reload(); }} className="w-full gap-2 p-2" @@ -655,35 +630,76 @@ function SidebarLogo() { )} + + + + + + + Pending Invitations + {invitations && invitations.length > 0 ? ( + invitations.map((invitation) => ( +
+ e.preventDefault()} + > +
{invitation.email}
+
+ Expires:{" "} + {new Date(invitation.expiresAt).toLocaleDateString()} +
+
+ Role: {invitation.role} +
+
+ { + const { error } = + await authClient.organization.acceptInvitation({ + invitationId: invitation.id, + }); + + if (error) { + toast.error( + error.message || "Error accepting invitation", + ); + } else { + toast.success("Invitation accepted successfully"); + await refetchInvitations(); + } + }} + > + + +
+ )) + ) : ( + + No pending invitations + + )} +
+
)} - - {/* -
- -
- -
-

Dokploy

-

- {dokployVersion} -

-
- */} ); } diff --git a/apps/dokploy/server/api/routers/application.ts b/apps/dokploy/server/api/routers/application.ts index 490da340a..269ac77b5 100644 --- a/apps/dokploy/server/api/routers/application.ts +++ b/apps/dokploy/server/api/routers/application.ts @@ -81,7 +81,11 @@ export const applicationRouter = createTRPCRouter({ const newApplication = await createApplication(input); if (ctx.user.rol === "member") { - await addNewService(ctx.user.id, newApplication.applicationId); + await addNewService( + ctx.user.id, + newApplication.applicationId, + project.organizationId, + ); } return newApplication; } catch (error: unknown) { diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index d9cd46d24..258a03d4b 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -80,7 +80,11 @@ export const composeRouter = createTRPCRouter({ const newService = await createCompose(input); if (ctx.user.rol === "member") { - await addNewService(ctx.user.id, newService.composeId); + await addNewService( + ctx.user.id, + newService.composeId, + project.organizationId, + ); } return newService; @@ -424,7 +428,11 @@ export const composeRouter = createTRPCRouter({ }); if (ctx.user.rol === "member") { - await addNewService(ctx.user.id, compose.composeId); + await addNewService( + ctx.user.id, + compose.composeId, + project.organizationId, + ); } if (mounts && mounts?.length > 0) { diff --git a/apps/dokploy/server/api/routers/mariadb.ts b/apps/dokploy/server/api/routers/mariadb.ts index 4276560c6..5735620e7 100644 --- a/apps/dokploy/server/api/routers/mariadb.ts +++ b/apps/dokploy/server/api/routers/mariadb.ts @@ -57,7 +57,11 @@ export const mariadbRouter = createTRPCRouter({ } const newMariadb = await createMariadb(input); if (ctx.user.rol === "member") { - await addNewService(ctx.user.id, newMariadb.mariadbId); + await addNewService( + ctx.user.id, + newMariadb.mariadbId, + project.organizationId, + ); } await createMount({ diff --git a/apps/dokploy/server/api/routers/mongo.ts b/apps/dokploy/server/api/routers/mongo.ts index d1d12bd0b..7f8716a59 100644 --- a/apps/dokploy/server/api/routers/mongo.ts +++ b/apps/dokploy/server/api/routers/mongo.ts @@ -56,7 +56,11 @@ export const mongoRouter = createTRPCRouter({ } const newMongo = await createMongo(input); if (ctx.user.rol === "member") { - await addNewService(ctx.user.id, newMongo.mongoId); + await addNewService( + ctx.user.id, + newMongo.mongoId, + project.organizationId, + ); } await createMount({ diff --git a/apps/dokploy/server/api/routers/mysql.ts b/apps/dokploy/server/api/routers/mysql.ts index dc107bdba..96ea4846f 100644 --- a/apps/dokploy/server/api/routers/mysql.ts +++ b/apps/dokploy/server/api/routers/mysql.ts @@ -59,7 +59,11 @@ export const mysqlRouter = createTRPCRouter({ const newMysql = await createMysql(input); if (ctx.user.rol === "member") { - await addNewService(ctx.user.id, newMysql.mysqlId); + await addNewService( + ctx.user.id, + newMysql.mysqlId, + project.organizationId, + ); } await createMount({ diff --git a/apps/dokploy/server/api/routers/postgres.ts b/apps/dokploy/server/api/routers/postgres.ts index b74bc0f68..aa3a0459d 100644 --- a/apps/dokploy/server/api/routers/postgres.ts +++ b/apps/dokploy/server/api/routers/postgres.ts @@ -64,7 +64,11 @@ export const postgresRouter = createTRPCRouter({ } const newPostgres = await createPostgres(input); if (ctx.user.rol === "member") { - await addNewService(ctx.user.id, newPostgres.postgresId); + await addNewService( + ctx.user.id, + newPostgres.postgresId, + project.organizationId, + ); } await createMount({ diff --git a/apps/dokploy/server/api/routers/redis.ts b/apps/dokploy/server/api/routers/redis.ts index db76ee6ce..6d5a84d5e 100644 --- a/apps/dokploy/server/api/routers/redis.ts +++ b/apps/dokploy/server/api/routers/redis.ts @@ -56,7 +56,11 @@ export const redisRouter = createTRPCRouter({ } const newRedis = await createRedis(input); if (ctx.user.rol === "member") { - await addNewService(ctx.user.id, newRedis.redisId); + await addNewService( + ctx.user.id, + newRedis.redisId, + project.organizationId, + ); } await createMount({ diff --git a/apps/dokploy/server/api/routers/registry.ts b/apps/dokploy/server/api/routers/registry.ts index 6ad7e2a94..62c8a9b65 100644 --- a/apps/dokploy/server/api/routers/registry.ts +++ b/apps/dokploy/server/api/routers/registry.ts @@ -18,7 +18,7 @@ import { import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; - +import { db } from "@/server/db"; export const registryRouter = createTRPCRouter({ create: adminProcedure .input(apiCreateRegistry) diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 6b4e8eded..872ee0744 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -15,10 +15,11 @@ import { apiAssignPermissions, apiFindOneToken, apiUpdateUser, + invitation, member, } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; -import { and, asc, desc, eq } from "drizzle-orm"; +import { and, asc, desc, eq, gt } from "drizzle-orm"; import { z } from "zod"; import { adminProcedure, @@ -115,14 +116,34 @@ export const userRouter = createTRPCRouter({ }); } + const { id, ...rest } = input; + + console.log(rest); await db .update(member) .set({ - ...input, + ...rest, }) - .where(eq(member.userId, input.id)); + .where( + and( + eq(member.userId, input.id), + eq( + member.organizationId, + ctx.session?.activeOrganizationId || "", + ), + ), + ); } catch (error) { throw error; } }), + getInvitations: protectedProcedure.query(async ({ ctx }) => { + return await db.query.invitation.findMany({ + where: and( + eq(invitation.email, ctx.user.email), + gt(invitation.expiresAt, new Date()), + eq(invitation.status, "pending"), + ), + }); + }), }); From c52725420ef81cf066c006a4a59e6c6b5f6d0e61 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 02:35:44 -0600 Subject: [PATCH 54/89] refactor: use organization context for server creation --- apps/dokploy/server/api/routers/server.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts index 3662345d4..1d7fd40e8 100644 --- a/apps/dokploy/server/api/routers/server.ts +++ b/apps/dokploy/server/api/routers/server.ts @@ -50,7 +50,10 @@ export const serverRouter = createTRPCRouter({ message: "You cannot create more servers", }); } - const project = await createServer(input, ctx.user.ownerId); + const project = await createServer( + input, + ctx.session.activeOrganizationId, + ); return project; } catch (error) { throw new TRPCError({ From 81a881b07e1548fd5e2062834c7e607a4d10a1cf Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 13:53:57 -0600 Subject: [PATCH 55/89] feat: enhance organization invitation UI and add organization details --- apps/dokploy/components/layouts/side.tsx | 103 ++++++++++++----------- apps/dokploy/server/api/routers/user.ts | 3 + packages/server/src/db/schema/user.ts | 7 +- 3 files changed, 63 insertions(+), 50 deletions(-) diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index cba10ca0f..e0931b08f 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -555,7 +555,7 @@ function SidebarLogo() { - -
- )) - ) : ( - - No pending invitations - - )} + if (error) { + toast.error( + error.message || "Error accepting invitation", + ); + } else { + toast.success("Invitation accepted successfully"); + await refetchInvitations(); + await refetch(); + } + }} + > + + +
+ )) + ) : ( + + No pending invitations + + )} +
diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 872ee0744..5c4eb56d5 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -144,6 +144,9 @@ export const userRouter = createTRPCRouter({ gt(invitation.expiresAt, new Date()), eq(invitation.status, "pending"), ), + with: { + organization: true, + }, }); }), }); diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 5860875f6..67a247414 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -140,7 +140,12 @@ export const apiRemoveUser = createSchema }) .required(); -export const apiFindOneToken = createSchema.pick({}).required(); +export const apiFindOneToken = createSchema + .pick({}) + .required() + .extend({ + token: z.string().min(1), + }); export const apiAssignPermissions = createSchema .pick({ From 1a415b96c90b428a903a6516de1cc94cbe04ec11 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 18:03:12 -0600 Subject: [PATCH 56/89] refactor: remove unused auth service and clean up server-side code --- apps/api/src/index.ts | 2 +- apps/api/src/utils.ts | 2 +- .../__test__/compose/config/config.test.ts | 2 +- .../compose/network/network-root.test.ts | 23 -- .../compose/secrets/secret-root.test.ts | 2 +- .../__test__/compose/volume/volume.test.ts | 6 +- .../server/update-server-config.test.ts | 2 - apps/dokploy/components/auth/login-2fa.tsx | 1 - .../cluster/show-cluster-settings.tsx | 1 - .../advanced/general/add-command.tsx | 1 - .../application/advanced/ports/show-port.tsx | 1 - .../advanced/redirects/show-redirects.tsx | 1 - .../advanced/security/show-security.tsx | 1 - .../application/advanced/show-resources.tsx | 2 +- .../advanced/traefik/show-traefik-config.tsx | 1 - .../advanced/volumes/show-volumes.tsx | 1 - .../advanced/volumes/update-volume.tsx | 2 +- .../application/deployments/refresh-token.tsx | 1 - .../environment/show-enviroment.tsx | 2 +- .../application/environment/show.tsx | 2 +- .../application/general/generic/show.tsx | 2 +- .../dashboard/application/general/show.tsx | 1 - .../show-preview-builds.tsx | 1 - .../show-preview-deployments.tsx | 1 - .../application/update-application.tsx | 2 +- .../compose/advanced/add-command.tsx | 1 - .../deployments/refresh-token-compose.tsx | 1 - .../compose/general/generic/show.tsx | 2 +- .../compose/general/randomize-compose.tsx | 2 +- .../dashboard/compose/general/show.tsx | 1 - .../dashboard/compose/logs/show.tsx | 2 +- .../database/backups/show-backups.tsx | 1 - .../database/backups/update-backup.tsx | 2 +- .../docker/logs/since-logs-filter.tsx | 1 - .../dashboard/docker/logs/terminal-line.tsx | 1 - .../dashboard/docker/show/colums.tsx | 1 - .../dashboard/docker/show/show-containers.tsx | 28 +-- .../file-system/show-traefik-system.tsx | 3 +- .../show-external-mariadb-credentials.tsx | 2 +- .../mariadb/general/show-general-mariadb.tsx | 2 +- .../show-internal-mariadb-credentials.tsx | 1 - .../dashboard/mariadb/update-mariadb.tsx | 2 +- .../show-external-mongo-credentials.tsx | 2 +- .../mongo/general/show-general-mongo.tsx | 2 +- .../show-internal-mongo-credentials.tsx | 1 - .../show-free-compose-monitoring.tsx | 1 - .../show-free-container-monitoring.tsx | 10 +- .../paid/servers/show-paid-monitoring.tsx | 1 - .../show-external-mysql-credentials.tsx | 2 +- .../mysql/general/show-general-mysql.tsx | 2 +- .../show-internal-mysql-credentials.tsx | 1 - .../dashboard/mysql/update-mysql.tsx | 2 +- .../organization/handle-organization.tsx | 2 +- .../postgres/advanced/show-custom-command.tsx | 2 +- .../show-external-postgres-credentials.tsx | 2 +- .../general/show-general-postgres.tsx | 2 +- .../show-internal-postgres-credentials.tsx | 1 - .../dashboard/postgres/update-postgres.tsx | 2 +- .../dashboard/project/add-database.tsx | 1 - .../dashboard/project/add-template.tsx | 1 - .../dashboard/projects/handle-project.tsx | 1 - .../show-external-redis-credentials.tsx | 2 +- .../redis/general/show-general-redis.tsx | 2 +- .../show-internal-redis-credentials.tsx | 1 - .../dashboard/redis/update-redis.tsx | 2 +- .../components/dashboard/requests/columns.tsx | 1 - .../dashboard/requests/show-requests.tsx | 1 - .../components/dashboard/search-command.tsx | 2 - .../settings/billing/show-billing.tsx | 2 +- .../settings/billing/show-welcome-dokploy.tsx | 1 - .../settings/cluster/nodes/show-nodes.tsx | 1 - .../git/bitbucket/add-bitbucket-provider.tsx | 6 +- .../git/bitbucket/edit-bitbucket-provider.tsx | 2 +- .../git/gitlab/edit-gitlab-provider.tsx | 2 +- .../dashboard/settings/profile/enable-2fa.tsx | 1 - .../settings/profile/profile-form.tsx | 2 - .../servers/actions/show-dokploy-actions.tsx | 1 - .../servers/actions/show-storage-actions.tsx | 1 - .../servers/actions/show-traefik-actions.tsx | 14 +- .../settings/servers/gpu-support.tsx | 1 - .../settings/servers/setup-monitoring.tsx | 2 - .../servers/show-docker-containers-modal.tsx | 8 +- .../servers/show-swarm-overview-modal.tsx | 9 +- .../dashboard/settings/users/show-users.tsx | 83 ++++--- .../dashboard/settings/web-domain.tsx | 2 +- .../dashboard/settings/web-server.tsx | 2 - .../web-server/local-server-config.tsx | 1 - .../settings/web-server/show-modal-logs.tsx | 1 - .../settings/web-server/update-server.tsx | 2 - .../dashboard/swarm/applications/columns.tsx | 1 - .../swarm/applications/show-applications.tsx | 1 - .../components/icons/data-tools-icons.tsx | 1 - apps/dokploy/components/layouts/side.tsx | 30 +-- apps/dokploy/components/layouts/user-nav.tsx | 2 - .../components/shared/dialog-action.tsx | 1 - .../dokploy/components/shared/drawer-logs.tsx | 9 +- apps/dokploy/components/shared/logo.tsx | 2 - apps/dokploy/components/ui/modeToggle.tsx | 1 - apps/dokploy/migrate.ts | 1 - apps/dokploy/pages/api/deploy/github.ts | 2 - .../pages/api/providers/github/setup.ts | 9 +- apps/dokploy/pages/api/stripe/webhook.ts | 2 +- apps/dokploy/pages/dashboard/docker.tsx | 2 +- apps/dokploy/pages/dashboard/monitoring.tsx | 4 - .../services/application/[applicationId].tsx | 5 +- .../services/compose/[composeId].tsx | 3 +- .../services/mariadb/[mariadbId].tsx | 6 +- .../[projectId]/services/mongo/[mongoId].tsx | 6 +- .../[projectId]/services/mysql/[mysqlId].tsx | 6 +- .../services/postgres/[postgresId].tsx | 6 +- .../[projectId]/services/redis/[redisId].tsx | 4 +- apps/dokploy/pages/dashboard/projects.tsx | 1 - apps/dokploy/pages/dashboard/requests.tsx | 1 - .../pages/dashboard/settings/billing.tsx | 2 +- .../pages/dashboard/settings/certificates.tsx | 2 +- .../pages/dashboard/settings/cluster.tsx | 2 +- .../pages/dashboard/settings/destinations.tsx | 2 +- .../dashboard/settings/git-providers.tsx | 2 +- .../pages/dashboard/settings/index.tsx | 3 +- .../dashboard/settings/notifications.tsx | 2 +- .../pages/dashboard/settings/profile.tsx | 2 +- .../pages/dashboard/settings/registry.tsx | 2 +- .../pages/dashboard/settings/server.tsx | 5 +- .../pages/dashboard/settings/servers.tsx | 2 +- .../pages/dashboard/settings/ssh-keys.tsx | 2 +- .../pages/dashboard/settings/users.tsx | 2 +- apps/dokploy/pages/dashboard/traefik.tsx | 2 +- apps/dokploy/pages/index.tsx | 14 +- apps/dokploy/pages/invitation.tsx | 9 +- apps/dokploy/pages/register.tsx | 8 +- apps/dokploy/pages/send-reset-password.tsx | 7 +- apps/dokploy/server/api/routers/admin.ts | 234 +----------------- .../dokploy/server/api/routers/application.ts | 25 +- apps/dokploy/server/api/routers/auth.ts | 39 --- apps/dokploy/server/api/routers/backup.ts | 33 +-- apps/dokploy/server/api/routers/cluster.ts | 4 +- apps/dokploy/server/api/routers/compose.ts | 32 ++- .../server/api/routers/git-provider.ts | 6 +- apps/dokploy/server/api/routers/mariadb.ts | 24 +- apps/dokploy/server/api/routers/mongo.ts | 23 +- apps/dokploy/server/api/routers/mysql.ts | 23 +- .../server/api/routers/notification.ts | 6 +- .../server/api/routers/organization.ts | 10 +- apps/dokploy/server/api/routers/port.ts | 8 +- apps/dokploy/server/api/routers/postgres.ts | 31 ++- apps/dokploy/server/api/routers/project.ts | 11 +- apps/dokploy/server/api/routers/redis.ts | 23 +- apps/dokploy/server/api/routers/registry.ts | 2 +- apps/dokploy/server/api/routers/server.ts | 4 +- apps/dokploy/server/api/routers/settings.ts | 22 +- apps/dokploy/server/api/routers/ssh-key.ts | 1 - apps/dokploy/server/api/routers/stripe.ts | 50 ++-- apps/dokploy/server/api/routers/user.ts | 10 +- apps/dokploy/server/db/seed.ts | 1 - apps/dokploy/server/utils/backup.ts | 1 - apps/dokploy/templates/excalidraw/index.ts | 1 - apps/dokploy/templates/ghost/index.ts | 1 - apps/dokploy/templates/penpot/index.ts | 2 - apps/dokploy/templates/photoprism/index.ts | 1 - apps/dokploy/templates/triggerdotdev/index.ts | 1 - apps/dokploy/templates/unsend/index.ts | 1 - biome.json | 5 +- packages/server/auth-schema.ts | 8 +- packages/server/src/db/schema/user.ts | 2 +- .../server/src/emails/emails/build-failed.tsx | 1 - .../src/emails/emails/build-success.tsx | 1 - .../src/emails/emails/database-backup.tsx | 1 - .../src/emails/emails/docker-cleanup.tsx | 2 - .../src/emails/emails/dokploy-restart.tsx | 1 - .../src/emails/emails/notion-magic-link.tsx | 1 - .../emails/emails/plaid-verify-identity.tsx | 1 - .../src/emails/emails/stripe-welcome.tsx | 1 - .../src/emails/emails/vercel-invite-user.tsx | 1 - packages/server/src/index.ts | 2 - packages/server/src/lib/auth.ts | 1 - packages/server/src/services/admin.ts | 3 - packages/server/src/services/application.ts | 5 +- packages/server/src/services/auth.ts | 212 ---------------- packages/server/src/services/backup.ts | 2 - packages/server/src/services/compose.ts | 3 +- packages/server/src/services/deployment.ts | 10 +- packages/server/src/services/domain.ts | 2 +- packages/server/src/services/gitlab.ts | 2 - packages/server/src/services/mariadb.ts | 2 +- packages/server/src/services/mongo.ts | 2 +- packages/server/src/services/mount.ts | 4 +- packages/server/src/services/postgres.ts | 2 +- .../server/src/services/preview-deployment.ts | 16 +- packages/server/src/services/redirect.ts | 6 +- packages/server/src/services/redis.ts | 2 +- packages/server/src/services/registry.ts | 4 +- packages/server/src/services/security.ts | 8 +- packages/server/src/services/server.ts | 2 +- packages/server/src/services/settings.ts | 1 - packages/server/src/services/user.ts | 30 +-- packages/server/src/setup/monitoring-setup.ts | 2 +- .../server/src/utils/access-log/handler.ts | 1 - packages/server/src/utils/backups/mysql.ts | 1 - packages/server/src/utils/builders/compose.ts | 1 - .../utils/notifications/database-backup.ts | 1 - .../server/src/utils/traefik/middleware.ts | 2 +- 201 files changed, 434 insertions(+), 1035 deletions(-) delete mode 100644 packages/server/src/services/auth.ts diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 4b405e9c7..0db565995 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -28,7 +28,7 @@ app.use(async (c, next) => { app.post("/deploy", zValidator("json", deployJobSchema), (c) => { const data = c.req.valid("json"); - const res = queue.add(data, { groupName: data.serverId }); + queue.add(data, { groupName: data.serverId }); return c.json( { message: "Deployment Added", diff --git a/apps/api/src/utils.ts b/apps/api/src/utils.ts index d919f29e9..3f3c9698b 100644 --- a/apps/api/src/utils.ts +++ b/apps/api/src/utils.ts @@ -64,7 +64,7 @@ export const deploy = async (job: DeployJob) => { } } } - } catch (error) { + } catch (_) { if (job.applicationType === "application") { await updateApplicationStatus(job.applicationId, "error"); } else if (job.applicationType === "compose") { diff --git a/apps/dokploy/__test__/compose/config/config.test.ts b/apps/dokploy/__test__/compose/config/config.test.ts index 3f98525a2..aed3350f5 100644 --- a/apps/dokploy/__test__/compose/config/config.test.ts +++ b/apps/dokploy/__test__/compose/config/config.test.ts @@ -1,5 +1,5 @@ import { generateRandomHash } from "@dokploy/server"; -import { addSuffixToAllConfigs, addSuffixToConfigsRoot } from "@dokploy/server"; +import { addSuffixToAllConfigs } from "@dokploy/server"; import type { ComposeSpecification } from "@dokploy/server"; import { load } from "js-yaml"; import { expect, test } from "vitest"; diff --git a/apps/dokploy/__test__/compose/network/network-root.test.ts b/apps/dokploy/__test__/compose/network/network-root.test.ts index 7e06a9f0b..980502fff 100644 --- a/apps/dokploy/__test__/compose/network/network-root.test.ts +++ b/apps/dokploy/__test__/compose/network/network-root.test.ts @@ -293,29 +293,6 @@ networks: dokploy-network: `; -const expectedComposeFile7 = ` -version: "3.8" - -services: - web: - image: nginx:latest - networks: - - dokploy-network - -networks: - dokploy-network: - driver: bridge - driver_opts: - com.docker.network.driver.mtu: 1200 - - backend: - driver: bridge - attachable: true - - external_network: - external: true - name: dokploy-network -`; test("It shoudn't add suffix to dokploy-network", () => { const composeData = load(composeFile7) as ComposeSpecification; diff --git a/apps/dokploy/__test__/compose/secrets/secret-root.test.ts b/apps/dokploy/__test__/compose/secrets/secret-root.test.ts index 2bd91b58a..1b1898c59 100644 --- a/apps/dokploy/__test__/compose/secrets/secret-root.test.ts +++ b/apps/dokploy/__test__/compose/secrets/secret-root.test.ts @@ -1,7 +1,7 @@ import { generateRandomHash } from "@dokploy/server"; import { addSuffixToSecretsRoot } from "@dokploy/server"; import type { ComposeSpecification } from "@dokploy/server"; -import { dump, load } from "js-yaml"; +import { load } from "js-yaml"; import { expect, test } from "vitest"; test("Generate random hash with 8 characters", () => { diff --git a/apps/dokploy/__test__/compose/volume/volume.test.ts b/apps/dokploy/__test__/compose/volume/volume.test.ts index d4623aeb1..6c4344762 100644 --- a/apps/dokploy/__test__/compose/volume/volume.test.ts +++ b/apps/dokploy/__test__/compose/volume/volume.test.ts @@ -1,8 +1,4 @@ -import { generateRandomHash } from "@dokploy/server"; -import { - addSuffixToAllVolumes, - addSuffixToVolumesInServices, -} from "@dokploy/server"; +import { addSuffixToAllVolumes } from "@dokploy/server"; import type { ComposeSpecification } from "@dokploy/server"; import { load } from "js-yaml"; import { expect, test } from "vitest"; diff --git a/apps/dokploy/__test__/traefik/server/update-server-config.test.ts b/apps/dokploy/__test__/traefik/server/update-server-config.test.ts index 49d71bc4c..7e4a3c82a 100644 --- a/apps/dokploy/__test__/traefik/server/update-server-config.test.ts +++ b/apps/dokploy/__test__/traefik/server/update-server-config.test.ts @@ -126,8 +126,6 @@ test("Should not touch config without host", () => { }); test("Should remove websecure if https rollback to http", () => { - const originalConfig: FileConfig = loadOrCreateConfig("dokploy"); - updateServerTraefik( { ...baseAdmin, certificateType: "letsencrypt" }, "example.com", diff --git a/apps/dokploy/components/auth/login-2fa.tsx b/apps/dokploy/components/auth/login-2fa.tsx index 6a11268e0..634f28146 100644 --- a/apps/dokploy/components/auth/login-2fa.tsx +++ b/apps/dokploy/components/auth/login-2fa.tsx @@ -13,7 +13,6 @@ import { CardTitle } from "@/components/ui/card"; import { InputOTP, InputOTPGroup, - InputOTPSeparator, InputOTPSlot, } from "@/components/ui/input-otp"; import { api } from "@/utils/api"; diff --git a/apps/dokploy/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx b/apps/dokploy/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx index cf7314cf6..1eadf8bab 100644 --- a/apps/dokploy/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/cluster/show-cluster-settings.tsx @@ -29,7 +29,6 @@ import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { Server } from "lucide-react"; import Link from "next/link"; -import React from "react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/application/advanced/general/add-command.tsx b/apps/dokploy/components/dashboard/application/advanced/general/add-command.tsx index 4cd839a11..50e36ad76 100644 --- a/apps/dokploy/components/dashboard/application/advanced/general/add-command.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/general/add-command.tsx @@ -17,7 +17,6 @@ import { import { Input } from "@/components/ui/input"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import React from "react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/application/advanced/ports/show-port.tsx b/apps/dokploy/components/dashboard/application/advanced/ports/show-port.tsx index a2c6ddcf1..4cd29a36d 100644 --- a/apps/dokploy/components/dashboard/application/advanced/ports/show-port.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/ports/show-port.tsx @@ -10,7 +10,6 @@ import { } from "@/components/ui/card"; import { api } from "@/utils/api"; import { Rss, Trash2 } from "lucide-react"; -import React from "react"; import { toast } from "sonner"; import { HandlePorts } from "./handle-ports"; interface Props { diff --git a/apps/dokploy/components/dashboard/application/advanced/redirects/show-redirects.tsx b/apps/dokploy/components/dashboard/application/advanced/redirects/show-redirects.tsx index 4ee597917..5c2c5943c 100644 --- a/apps/dokploy/components/dashboard/application/advanced/redirects/show-redirects.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/redirects/show-redirects.tsx @@ -9,7 +9,6 @@ import { } from "@/components/ui/card"; import { api } from "@/utils/api"; import { Split, Trash2 } from "lucide-react"; -import React from "react"; import { toast } from "sonner"; import { HandleRedirect } from "./handle-redirect"; diff --git a/apps/dokploy/components/dashboard/application/advanced/security/show-security.tsx b/apps/dokploy/components/dashboard/application/advanced/security/show-security.tsx index 33022c097..92439f511 100644 --- a/apps/dokploy/components/dashboard/application/advanced/security/show-security.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/security/show-security.tsx @@ -9,7 +9,6 @@ import { } from "@/components/ui/card"; import { api } from "@/utils/api"; import { LockKeyhole, Trash2 } from "lucide-react"; -import React from "react"; import { toast } from "sonner"; import { HandleSecurity } from "./handle-security"; diff --git a/apps/dokploy/components/dashboard/application/advanced/show-resources.tsx b/apps/dokploy/components/dashboard/application/advanced/show-resources.tsx index 227bca559..3d26716fc 100644 --- a/apps/dokploy/components/dashboard/application/advanced/show-resources.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/show-resources.tsx @@ -25,7 +25,7 @@ import { import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { InfoIcon } from "lucide-react"; -import React, { useEffect } from "react"; +import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; diff --git a/apps/dokploy/components/dashboard/application/advanced/traefik/show-traefik-config.tsx b/apps/dokploy/components/dashboard/application/advanced/traefik/show-traefik-config.tsx index fb6fc0c15..58601fb49 100644 --- a/apps/dokploy/components/dashboard/application/advanced/traefik/show-traefik-config.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/traefik/show-traefik-config.tsx @@ -8,7 +8,6 @@ import { } from "@/components/ui/card"; import { api } from "@/utils/api"; import { File, Loader2 } from "lucide-react"; -import React from "react"; import { UpdateTraefikConfig } from "./update-traefik-config"; interface Props { applicationId: string; diff --git a/apps/dokploy/components/dashboard/application/advanced/volumes/show-volumes.tsx b/apps/dokploy/components/dashboard/application/advanced/volumes/show-volumes.tsx index e0f842ce3..2a2d2c032 100644 --- a/apps/dokploy/components/dashboard/application/advanced/volumes/show-volumes.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/volumes/show-volumes.tsx @@ -10,7 +10,6 @@ import { } from "@/components/ui/card"; import { api } from "@/utils/api"; import { Package, Trash2 } from "lucide-react"; -import React from "react"; import { toast } from "sonner"; import type { ServiceType } from "../show-resources"; import { AddVolumes } from "./add-volumes"; diff --git a/apps/dokploy/components/dashboard/application/advanced/volumes/update-volume.tsx b/apps/dokploy/components/dashboard/application/advanced/volumes/update-volume.tsx index d8481d652..687d0f608 100644 --- a/apps/dokploy/components/dashboard/application/advanced/volumes/update-volume.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/volumes/update-volume.tsx @@ -21,7 +21,7 @@ import { import { Input } from "@/components/ui/input"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { PenBoxIcon, Pencil } from "lucide-react"; +import { PenBoxIcon } from "lucide-react"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/application/deployments/refresh-token.tsx b/apps/dokploy/components/dashboard/application/deployments/refresh-token.tsx index c268e6d51..b80450f9f 100644 --- a/apps/dokploy/components/dashboard/application/deployments/refresh-token.tsx +++ b/apps/dokploy/components/dashboard/application/deployments/refresh-token.tsx @@ -11,7 +11,6 @@ import { } from "@/components/ui/alert-dialog"; import { api } from "@/utils/api"; import { RefreshCcw } from "lucide-react"; -import React from "react"; import { toast } from "sonner"; interface Props { diff --git a/apps/dokploy/components/dashboard/application/environment/show-enviroment.tsx b/apps/dokploy/components/dashboard/application/environment/show-enviroment.tsx index b65a18161..ba20db315 100644 --- a/apps/dokploy/components/dashboard/application/environment/show-enviroment.tsx +++ b/apps/dokploy/components/dashboard/application/environment/show-enviroment.tsx @@ -18,7 +18,7 @@ import { Toggle } from "@/components/ui/toggle"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { EyeIcon, EyeOffIcon } from "lucide-react"; -import React, { type CSSProperties, useEffect, useState } from "react"; +import { type CSSProperties, useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; diff --git a/apps/dokploy/components/dashboard/application/environment/show.tsx b/apps/dokploy/components/dashboard/application/environment/show.tsx index 7200f2a71..d97c39e2f 100644 --- a/apps/dokploy/components/dashboard/application/environment/show.tsx +++ b/apps/dokploy/components/dashboard/application/environment/show.tsx @@ -1,5 +1,5 @@ import { Button } from "@/components/ui/button"; -import { Card, CardContent } from "@/components/ui/card"; +import { Card } from "@/components/ui/card"; import { Form } from "@/components/ui/form"; import { Secrets } from "@/components/ui/secrets"; import { api } from "@/utils/api"; diff --git a/apps/dokploy/components/dashboard/application/general/generic/show.tsx b/apps/dokploy/components/dashboard/application/general/generic/show.tsx index 73f5e8f8f..b00a34953 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/show.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/show.tsx @@ -11,7 +11,7 @@ import { import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { api } from "@/utils/api"; -import { GitBranch, LockIcon, UploadCloud } from "lucide-react"; +import { GitBranch, UploadCloud } from "lucide-react"; import Link from "next/link"; import { useState } from "react"; import { SaveBitbucketProvider } from "./save-bitbucket-provider"; diff --git a/apps/dokploy/components/dashboard/application/general/show.tsx b/apps/dokploy/components/dashboard/application/general/show.tsx index 83e4b6f06..0ea331e94 100644 --- a/apps/dokploy/components/dashboard/application/general/show.tsx +++ b/apps/dokploy/components/dashboard/application/general/show.tsx @@ -7,7 +7,6 @@ import { Switch } from "@/components/ui/switch"; import { api } from "@/utils/api"; import { Ban, CheckCircle2, Hammer, RefreshCcw, Terminal } from "lucide-react"; import { useRouter } from "next/router"; -import React from "react"; import { toast } from "sonner"; import { DockerTerminalModal } from "../../settings/web-server/docker-terminal-modal"; interface Props { diff --git a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-builds.tsx b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-builds.tsx index 55b31f3f0..90800f757 100644 --- a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-builds.tsx +++ b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-builds.tsx @@ -5,7 +5,6 @@ import { Dialog, DialogContent, DialogDescription, - DialogFooter, DialogHeader, DialogTitle, DialogTrigger, diff --git a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-deployments.tsx b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-deployments.tsx index 371276bdd..ec3680f10 100644 --- a/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-deployments.tsx +++ b/apps/dokploy/components/dashboard/application/preview-deployments/show-preview-deployments.tsx @@ -22,7 +22,6 @@ import { RocketIcon, Trash2, } from "lucide-react"; -import React from "react"; import { toast } from "sonner"; import { ShowModalLogs } from "../../settings/web-server/show-modal-logs"; import { AddPreviewDomain } from "./add-preview-domain"; diff --git a/apps/dokploy/components/dashboard/application/update-application.tsx b/apps/dokploy/components/dashboard/application/update-application.tsx index a49fc5383..90b63f08e 100644 --- a/apps/dokploy/components/dashboard/application/update-application.tsx +++ b/apps/dokploy/components/dashboard/application/update-application.tsx @@ -21,7 +21,7 @@ import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { AlertTriangle, PenBoxIcon, SquarePen } from "lucide-react"; +import { PenBoxIcon } from "lucide-react"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/compose/advanced/add-command.tsx b/apps/dokploy/components/dashboard/compose/advanced/add-command.tsx index 1bbd38205..c5a34b3c1 100644 --- a/apps/dokploy/components/dashboard/compose/advanced/add-command.tsx +++ b/apps/dokploy/components/dashboard/compose/advanced/add-command.tsx @@ -19,7 +19,6 @@ import { import { Input } from "@/components/ui/input"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import React from "react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/compose/deployments/refresh-token-compose.tsx b/apps/dokploy/components/dashboard/compose/deployments/refresh-token-compose.tsx index 95fafaab1..b062b0994 100644 --- a/apps/dokploy/components/dashboard/compose/deployments/refresh-token-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/deployments/refresh-token-compose.tsx @@ -11,7 +11,6 @@ import { } from "@/components/ui/alert-dialog"; import { api } from "@/utils/api"; import { RefreshCcw } from "lucide-react"; -import React from "react"; import { toast } from "sonner"; interface Props { diff --git a/apps/dokploy/components/dashboard/compose/general/generic/show.tsx b/apps/dokploy/components/dashboard/compose/general/generic/show.tsx index 1681039cc..347c134e3 100644 --- a/apps/dokploy/components/dashboard/compose/general/generic/show.tsx +++ b/apps/dokploy/components/dashboard/compose/general/generic/show.tsx @@ -7,7 +7,7 @@ import { import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { api } from "@/utils/api"; -import { CodeIcon, GitBranch, LockIcon } from "lucide-react"; +import { CodeIcon, GitBranch } from "lucide-react"; import Link from "next/link"; import { useState } from "react"; import { ComposeFileEditor } from "../compose-file-editor"; diff --git a/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx b/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx index b1a00985f..4462ef0eb 100644 --- a/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx @@ -19,7 +19,7 @@ import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { AlertTriangle, Dices } from "lucide-react"; +import { AlertTriangle } from "lucide-react"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/compose/general/show.tsx b/apps/dokploy/components/dashboard/compose/general/show.tsx index d002b409c..71752525c 100644 --- a/apps/dokploy/components/dashboard/compose/general/show.tsx +++ b/apps/dokploy/components/dashboard/compose/general/show.tsx @@ -7,7 +7,6 @@ import { CardTitle, } from "@/components/ui/card"; import { api } from "@/utils/api"; -import React from "react"; import { ComposeActions } from "./actions"; import { ShowProviderFormCompose } from "./generic/show"; interface Props { diff --git a/apps/dokploy/components/dashboard/compose/logs/show.tsx b/apps/dokploy/components/dashboard/compose/logs/show.tsx index 4530e0ddd..571190549 100644 --- a/apps/dokploy/components/dashboard/compose/logs/show.tsx +++ b/apps/dokploy/components/dashboard/compose/logs/show.tsx @@ -18,7 +18,7 @@ import { SelectValue, } from "@/components/ui/select"; import { api } from "@/utils/api"; -import { Loader, Loader2 } from "lucide-react"; +import { Loader2 } from "lucide-react"; import dynamic from "next/dynamic"; import { useEffect, useState } from "react"; export const DockerLogs = dynamic( diff --git a/apps/dokploy/components/dashboard/database/backups/show-backups.tsx b/apps/dokploy/components/dashboard/database/backups/show-backups.tsx index 21fe28d4a..6619ceae7 100644 --- a/apps/dokploy/components/dashboard/database/backups/show-backups.tsx +++ b/apps/dokploy/components/dashboard/database/backups/show-backups.tsx @@ -16,7 +16,6 @@ import { import { api } from "@/utils/api"; import { DatabaseBackup, Play, Trash2 } from "lucide-react"; import Link from "next/link"; -import React from "react"; import { toast } from "sonner"; import type { ServiceType } from "../../application/advanced/show-resources"; import { AddBackup } from "./add-backup"; diff --git a/apps/dokploy/components/dashboard/database/backups/update-backup.tsx b/apps/dokploy/components/dashboard/database/backups/update-backup.tsx index 0083bb1df..99f7692a9 100644 --- a/apps/dokploy/components/dashboard/database/backups/update-backup.tsx +++ b/apps/dokploy/components/dashboard/database/backups/update-backup.tsx @@ -35,7 +35,7 @@ import { Switch } from "@/components/ui/switch"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { CheckIcon, ChevronsUpDown, PenBoxIcon, Pencil } from "lucide-react"; +import { CheckIcon, ChevronsUpDown, PenBoxIcon } from "lucide-react"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/docker/logs/since-logs-filter.tsx b/apps/dokploy/components/dashboard/docker/logs/since-logs-filter.tsx index b7caafe71..44f2cdfc3 100644 --- a/apps/dokploy/components/dashboard/docker/logs/since-logs-filter.tsx +++ b/apps/dokploy/components/dashboard/docker/logs/since-logs-filter.tsx @@ -15,7 +15,6 @@ import { Separator } from "@/components/ui/separator"; import { Switch } from "@/components/ui/switch"; import { cn } from "@/lib/utils"; import { CheckIcon } from "lucide-react"; -import React from "react"; export type TimeFilter = "all" | "1h" | "6h" | "24h" | "168h" | "720h"; diff --git a/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx b/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx index c25acc67f..ee674e0fe 100644 --- a/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx +++ b/apps/dokploy/components/dashboard/docker/logs/terminal-line.tsx @@ -9,7 +9,6 @@ import { import { cn } from "@/lib/utils"; import { FancyAnsi } from "fancy-ansi"; import { escapeRegExp } from "lodash"; -import React from "react"; import { type LogLine, getLogType } from "./utils"; interface LogLineProps { diff --git a/apps/dokploy/components/dashboard/docker/show/colums.tsx b/apps/dokploy/components/dashboard/docker/show/colums.tsx index 3feae176a..1cf0200f2 100644 --- a/apps/dokploy/components/dashboard/docker/show/colums.tsx +++ b/apps/dokploy/components/dashboard/docker/show/colums.tsx @@ -1,6 +1,5 @@ import type { ColumnDef } from "@tanstack/react-table"; import { ArrowUpDown, MoreHorizontal } from "lucide-react"; -import * as React from "react"; import { Button } from "@/components/ui/button"; import { diff --git a/apps/dokploy/components/dashboard/docker/show/show-containers.tsx b/apps/dokploy/components/dashboard/docker/show/show-containers.tsx index c66c9b9ba..024b00618 100644 --- a/apps/dokploy/components/dashboard/docker/show/show-containers.tsx +++ b/apps/dokploy/components/dashboard/docker/show/show-containers.tsx @@ -1,18 +1,3 @@ -import { - type ColumnFiltersState, - type SortingState, - type VisibilityState, - flexRender, - getCoreRowModel, - getFilteredRowModel, - getPaginationRowModel, - getSortedRowModel, - useReactTable, -} from "@tanstack/react-table"; -import { ChevronDown, Container } from "lucide-react"; -import * as React from "react"; - -import { AlertBlock } from "@/components/shared/alert-block"; import { Button } from "@/components/ui/button"; import { Card, @@ -37,6 +22,19 @@ import { TableRow, } from "@/components/ui/table"; import { type RouterOutputs, api } from "@/utils/api"; +import { + type ColumnFiltersState, + type SortingState, + type VisibilityState, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; +import { ChevronDown, Container } from "lucide-react"; +import * as React from "react"; import { columns } from "./colums"; export type Container = NonNullable< RouterOutputs["docker"]["getContainers"] diff --git a/apps/dokploy/components/dashboard/file-system/show-traefik-system.tsx b/apps/dokploy/components/dashboard/file-system/show-traefik-system.tsx index ed2ed1974..c9272f293 100644 --- a/apps/dokploy/components/dashboard/file-system/show-traefik-system.tsx +++ b/apps/dokploy/components/dashboard/file-system/show-traefik-system.tsx @@ -7,9 +7,8 @@ import { CardTitle, } from "@/components/ui/card"; import { Tree } from "@/components/ui/file-tree"; -import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; -import { FileIcon, Folder, Link, Loader2, Workflow } from "lucide-react"; +import { FileIcon, Folder, Loader2, Workflow } from "lucide-react"; import React from "react"; import { ShowTraefikFile } from "./show-traefik-file"; diff --git a/apps/dokploy/components/dashboard/mariadb/general/show-external-mariadb-credentials.tsx b/apps/dokploy/components/dashboard/mariadb/general/show-external-mariadb-credentials.tsx index f20449178..4a5c43a26 100644 --- a/apps/dokploy/components/dashboard/mariadb/general/show-external-mariadb-credentials.tsx +++ b/apps/dokploy/components/dashboard/mariadb/general/show-external-mariadb-credentials.tsx @@ -19,7 +19,7 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; diff --git a/apps/dokploy/components/dashboard/mariadb/general/show-general-mariadb.tsx b/apps/dokploy/components/dashboard/mariadb/general/show-general-mariadb.tsx index 98773685f..ad6b1164b 100644 --- a/apps/dokploy/components/dashboard/mariadb/general/show-general-mariadb.tsx +++ b/apps/dokploy/components/dashboard/mariadb/general/show-general-mariadb.tsx @@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { api } from "@/utils/api"; import { Ban, CheckCircle2, RefreshCcw, Terminal } from "lucide-react"; -import React, { useState } from "react"; +import { useState } from "react"; import { toast } from "sonner"; import { type LogLine, parseLogs } from "../../docker/logs/utils"; import { DockerTerminalModal } from "../../settings/web-server/docker-terminal-modal"; diff --git a/apps/dokploy/components/dashboard/mariadb/general/show-internal-mariadb-credentials.tsx b/apps/dokploy/components/dashboard/mariadb/general/show-internal-mariadb-credentials.tsx index b409ac4d8..170269269 100644 --- a/apps/dokploy/components/dashboard/mariadb/general/show-internal-mariadb-credentials.tsx +++ b/apps/dokploy/components/dashboard/mariadb/general/show-internal-mariadb-credentials.tsx @@ -3,7 +3,6 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; -import React from "react"; interface Props { mariadbId: string; diff --git a/apps/dokploy/components/dashboard/mariadb/update-mariadb.tsx b/apps/dokploy/components/dashboard/mariadb/update-mariadb.tsx index 4c9be0903..48d944898 100644 --- a/apps/dokploy/components/dashboard/mariadb/update-mariadb.tsx +++ b/apps/dokploy/components/dashboard/mariadb/update-mariadb.tsx @@ -21,7 +21,7 @@ import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { AlertTriangle, PenBoxIcon, SquarePen } from "lucide-react"; +import { PenBoxIcon } from "lucide-react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/mongo/general/show-external-mongo-credentials.tsx b/apps/dokploy/components/dashboard/mongo/general/show-external-mongo-credentials.tsx index 6dd2e9198..9fe6e7137 100644 --- a/apps/dokploy/components/dashboard/mongo/general/show-external-mongo-credentials.tsx +++ b/apps/dokploy/components/dashboard/mongo/general/show-external-mongo-credentials.tsx @@ -19,7 +19,7 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; diff --git a/apps/dokploy/components/dashboard/mongo/general/show-general-mongo.tsx b/apps/dokploy/components/dashboard/mongo/general/show-general-mongo.tsx index df01e36d4..a20d46378 100644 --- a/apps/dokploy/components/dashboard/mongo/general/show-general-mongo.tsx +++ b/apps/dokploy/components/dashboard/mongo/general/show-general-mongo.tsx @@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { api } from "@/utils/api"; import { Ban, CheckCircle2, RefreshCcw, Terminal } from "lucide-react"; -import React, { useState } from "react"; +import { useState } from "react"; import { toast } from "sonner"; import { type LogLine, parseLogs } from "../../docker/logs/utils"; import { DockerTerminalModal } from "../../settings/web-server/docker-terminal-modal"; diff --git a/apps/dokploy/components/dashboard/mongo/general/show-internal-mongo-credentials.tsx b/apps/dokploy/components/dashboard/mongo/general/show-internal-mongo-credentials.tsx index 6636688d9..e66ea8c36 100644 --- a/apps/dokploy/components/dashboard/mongo/general/show-internal-mongo-credentials.tsx +++ b/apps/dokploy/components/dashboard/mongo/general/show-internal-mongo-credentials.tsx @@ -3,7 +3,6 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; -import React from "react"; interface Props { mongoId: string; diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/show-free-compose-monitoring.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/show-free-compose-monitoring.tsx index 99be6d9d9..2bf6c9005 100644 --- a/apps/dokploy/components/dashboard/monitoring/free/container/show-free-compose-monitoring.tsx +++ b/apps/dokploy/components/dashboard/monitoring/free/container/show-free-compose-monitoring.tsx @@ -1,6 +1,5 @@ import { Button } from "@/components/ui/button"; import { - Card, CardContent, CardDescription, CardHeader, diff --git a/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx b/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx index 64a46bdb2..278e09360 100644 --- a/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx +++ b/apps/dokploy/components/dashboard/monitoring/free/container/show-free-container-monitoring.tsx @@ -1,13 +1,7 @@ -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Progress } from "@/components/ui/progress"; import { api } from "@/utils/api"; -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { DockerBlockChart } from "./docker-block-chart"; import { DockerCpuChart } from "./docker-cpu-chart"; import { DockerDiskChart } from "./docker-disk-chart"; diff --git a/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx b/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx index 87c030570..e299cfb38 100644 --- a/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx +++ b/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx @@ -7,7 +7,6 @@ import { } from "@/components/ui/select"; import { api } from "@/utils/api"; import { Clock, Cpu, HardDrive, Loader2, MemoryStick } from "lucide-react"; -import type React from "react"; import { useEffect, useState } from "react"; import { CPUChart } from "./cpu-chart"; import { DiskChart } from "./disk-chart"; diff --git a/apps/dokploy/components/dashboard/mysql/general/show-external-mysql-credentials.tsx b/apps/dokploy/components/dashboard/mysql/general/show-external-mysql-credentials.tsx index dc1ca3a7d..7a0527b17 100644 --- a/apps/dokploy/components/dashboard/mysql/general/show-external-mysql-credentials.tsx +++ b/apps/dokploy/components/dashboard/mysql/general/show-external-mysql-credentials.tsx @@ -19,7 +19,7 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; diff --git a/apps/dokploy/components/dashboard/mysql/general/show-general-mysql.tsx b/apps/dokploy/components/dashboard/mysql/general/show-general-mysql.tsx index 56a191ceb..13f46caee 100644 --- a/apps/dokploy/components/dashboard/mysql/general/show-general-mysql.tsx +++ b/apps/dokploy/components/dashboard/mysql/general/show-general-mysql.tsx @@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { api } from "@/utils/api"; import { Ban, CheckCircle2, RefreshCcw, Terminal } from "lucide-react"; -import React, { useState } from "react"; +import { useState } from "react"; import { toast } from "sonner"; import { type LogLine, parseLogs } from "../../docker/logs/utils"; import { DockerTerminalModal } from "../../settings/web-server/docker-terminal-modal"; diff --git a/apps/dokploy/components/dashboard/mysql/general/show-internal-mysql-credentials.tsx b/apps/dokploy/components/dashboard/mysql/general/show-internal-mysql-credentials.tsx index 2c09efb84..3f1872371 100644 --- a/apps/dokploy/components/dashboard/mysql/general/show-internal-mysql-credentials.tsx +++ b/apps/dokploy/components/dashboard/mysql/general/show-internal-mysql-credentials.tsx @@ -3,7 +3,6 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; -import React from "react"; interface Props { mysqlId: string; diff --git a/apps/dokploy/components/dashboard/mysql/update-mysql.tsx b/apps/dokploy/components/dashboard/mysql/update-mysql.tsx index 645575cdc..efe1eb11d 100644 --- a/apps/dokploy/components/dashboard/mysql/update-mysql.tsx +++ b/apps/dokploy/components/dashboard/mysql/update-mysql.tsx @@ -21,7 +21,7 @@ import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { AlertTriangle, PenBoxIcon, SquarePen } from "lucide-react"; +import { PenBoxIcon } from "lucide-react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/organization/handle-organization.tsx b/apps/dokploy/components/dashboard/organization/handle-organization.tsx index 24bb5c0eb..905a244cc 100644 --- a/apps/dokploy/components/dashboard/organization/handle-organization.tsx +++ b/apps/dokploy/components/dashboard/organization/handle-organization.tsx @@ -12,7 +12,7 @@ import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; -import { PenBoxIcon, Plus, SquarePen } from "lucide-react"; +import { PenBoxIcon, Plus } from "lucide-react"; import { useEffect, useState } from "react"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx b/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx index 6e912db95..2bae245ec 100644 --- a/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx +++ b/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx @@ -11,7 +11,7 @@ import { import { Input } from "@/components/ui/input"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import React, { useEffect } from "react"; +import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; diff --git a/apps/dokploy/components/dashboard/postgres/general/show-external-postgres-credentials.tsx b/apps/dokploy/components/dashboard/postgres/general/show-external-postgres-credentials.tsx index e8fff7dca..dbd57d0bf 100644 --- a/apps/dokploy/components/dashboard/postgres/general/show-external-postgres-credentials.tsx +++ b/apps/dokploy/components/dashboard/postgres/general/show-external-postgres-credentials.tsx @@ -19,7 +19,7 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; diff --git a/apps/dokploy/components/dashboard/postgres/general/show-general-postgres.tsx b/apps/dokploy/components/dashboard/postgres/general/show-general-postgres.tsx index 43c3f4322..89d275236 100644 --- a/apps/dokploy/components/dashboard/postgres/general/show-general-postgres.tsx +++ b/apps/dokploy/components/dashboard/postgres/general/show-general-postgres.tsx @@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { api } from "@/utils/api"; import { Ban, CheckCircle2, RefreshCcw, Terminal } from "lucide-react"; -import React, { useState } from "react"; +import { useState } from "react"; import { toast } from "sonner"; import { type LogLine, parseLogs } from "../../docker/logs/utils"; import { DockerTerminalModal } from "../../settings/web-server/docker-terminal-modal"; diff --git a/apps/dokploy/components/dashboard/postgres/general/show-internal-postgres-credentials.tsx b/apps/dokploy/components/dashboard/postgres/general/show-internal-postgres-credentials.tsx index e01226101..545150f87 100644 --- a/apps/dokploy/components/dashboard/postgres/general/show-internal-postgres-credentials.tsx +++ b/apps/dokploy/components/dashboard/postgres/general/show-internal-postgres-credentials.tsx @@ -3,7 +3,6 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; -import React from "react"; interface Props { postgresId: string; diff --git a/apps/dokploy/components/dashboard/postgres/update-postgres.tsx b/apps/dokploy/components/dashboard/postgres/update-postgres.tsx index 54ad5bce0..7be6908f1 100644 --- a/apps/dokploy/components/dashboard/postgres/update-postgres.tsx +++ b/apps/dokploy/components/dashboard/postgres/update-postgres.tsx @@ -21,7 +21,7 @@ import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { AlertTriangle, PenBoxIcon, SquarePen } from "lucide-react"; +import { PenBoxIcon } from "lucide-react"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/project/add-database.tsx b/apps/dokploy/components/dashboard/project/add-database.tsx index 1ca0d6a5e..cd75ba468 100644 --- a/apps/dokploy/components/dashboard/project/add-database.tsx +++ b/apps/dokploy/components/dashboard/project/add-database.tsx @@ -18,7 +18,6 @@ import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; import { Form, FormControl, - FormDescription, FormField, FormItem, FormLabel, diff --git a/apps/dokploy/components/dashboard/project/add-template.tsx b/apps/dokploy/components/dashboard/project/add-template.tsx index cc6962aab..3965f8172 100644 --- a/apps/dokploy/components/dashboard/project/add-template.tsx +++ b/apps/dokploy/components/dashboard/project/add-template.tsx @@ -57,7 +57,6 @@ import { BookText, CheckIcon, ChevronsUpDown, - Code, Github, Globe, HelpCircle, diff --git a/apps/dokploy/components/dashboard/projects/handle-project.tsx b/apps/dokploy/components/dashboard/projects/handle-project.tsx index 492c03c93..f5d62dfc6 100644 --- a/apps/dokploy/components/dashboard/projects/handle-project.tsx +++ b/apps/dokploy/components/dashboard/projects/handle-project.tsx @@ -21,7 +21,6 @@ import { import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; -import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { PlusIcon, SquarePen } from "lucide-react"; diff --git a/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx b/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx index 40ae0574e..25b5f2ba7 100644 --- a/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx +++ b/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx @@ -19,7 +19,7 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; diff --git a/apps/dokploy/components/dashboard/redis/general/show-general-redis.tsx b/apps/dokploy/components/dashboard/redis/general/show-general-redis.tsx index ec4aeb6cb..e309ef49a 100644 --- a/apps/dokploy/components/dashboard/redis/general/show-general-redis.tsx +++ b/apps/dokploy/components/dashboard/redis/general/show-general-redis.tsx @@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { api } from "@/utils/api"; import { Ban, CheckCircle2, RefreshCcw, Terminal } from "lucide-react"; -import React, { useState } from "react"; +import { useState } from "react"; import { toast } from "sonner"; import { type LogLine, parseLogs } from "../../docker/logs/utils"; import { DockerTerminalModal } from "../../settings/web-server/docker-terminal-modal"; diff --git a/apps/dokploy/components/dashboard/redis/general/show-internal-redis-credentials.tsx b/apps/dokploy/components/dashboard/redis/general/show-internal-redis-credentials.tsx index 092006748..47ad0df0b 100644 --- a/apps/dokploy/components/dashboard/redis/general/show-internal-redis-credentials.tsx +++ b/apps/dokploy/components/dashboard/redis/general/show-internal-redis-credentials.tsx @@ -3,7 +3,6 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; -import React from "react"; interface Props { redisId: string; diff --git a/apps/dokploy/components/dashboard/redis/update-redis.tsx b/apps/dokploy/components/dashboard/redis/update-redis.tsx index c3557bee8..193aec3b3 100644 --- a/apps/dokploy/components/dashboard/redis/update-redis.tsx +++ b/apps/dokploy/components/dashboard/redis/update-redis.tsx @@ -21,7 +21,7 @@ import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { AlertTriangle, PenBoxIcon, SquarePen } from "lucide-react"; +import { PenBoxIcon } from "lucide-react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/requests/columns.tsx b/apps/dokploy/components/dashboard/requests/columns.tsx index 529d64a48..c1814190e 100644 --- a/apps/dokploy/components/dashboard/requests/columns.tsx +++ b/apps/dokploy/components/dashboard/requests/columns.tsx @@ -3,7 +3,6 @@ import { Button } from "@/components/ui/button"; import type { ColumnDef } from "@tanstack/react-table"; import { format } from "date-fns"; import { ArrowUpDown } from "lucide-react"; -import * as React from "react"; import type { LogEntry } from "./show-requests"; export const getStatusColor = (status: number) => { diff --git a/apps/dokploy/components/dashboard/requests/show-requests.tsx b/apps/dokploy/components/dashboard/requests/show-requests.tsx index 05ba6e51f..c3d92dd6d 100644 --- a/apps/dokploy/components/dashboard/requests/show-requests.tsx +++ b/apps/dokploy/components/dashboard/requests/show-requests.tsx @@ -11,7 +11,6 @@ import { import { type RouterOutputs, api } from "@/utils/api"; import { ArrowDownUp } from "lucide-react"; import Link from "next/link"; -import * as React from "react"; import { toast } from "sonner"; import { RequestDistributionChart } from "./request-distribution-chart"; import { RequestsTable } from "./requests-table"; diff --git a/apps/dokploy/components/dashboard/search-command.tsx b/apps/dokploy/components/dashboard/search-command.tsx index 7ea53d72f..5726dc99a 100644 --- a/apps/dokploy/components/dashboard/search-command.tsx +++ b/apps/dokploy/components/dashboard/search-command.tsx @@ -7,9 +7,7 @@ import { PostgresqlIcon, RedisIcon, } from "@/components/icons/data-tools-icons"; -import { Badge } from "@/components/ui/badge"; import { - Command, CommandDialog, CommandEmpty, CommandGroup, diff --git a/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx b/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx index c76ec33e8..029eaa90f 100644 --- a/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx +++ b/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx @@ -23,7 +23,7 @@ import { PlusIcon, } from "lucide-react"; import Link from "next/link"; -import React, { useState } from "react"; +import { useState } from "react"; const stripePromise = loadStripe( process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!, diff --git a/apps/dokploy/components/dashboard/settings/billing/show-welcome-dokploy.tsx b/apps/dokploy/components/dashboard/settings/billing/show-welcome-dokploy.tsx index 201aed445..64362b25c 100644 --- a/apps/dokploy/components/dashboard/settings/billing/show-welcome-dokploy.tsx +++ b/apps/dokploy/components/dashboard/settings/billing/show-welcome-dokploy.tsx @@ -6,7 +6,6 @@ import { DialogTitle, } from "@/components/ui/dialog"; import { api } from "@/utils/api"; -import type React from "react"; import { useEffect, useState } from "react"; export const ShowWelcomeDokploy = () => { diff --git a/apps/dokploy/components/dashboard/settings/cluster/nodes/show-nodes.tsx b/apps/dokploy/components/dashboard/settings/cluster/nodes/show-nodes.tsx index b55396bfe..ba3eefa56 100644 --- a/apps/dokploy/components/dashboard/settings/cluster/nodes/show-nodes.tsx +++ b/apps/dokploy/components/dashboard/settings/cluster/nodes/show-nodes.tsx @@ -33,7 +33,6 @@ import { } from "@/components/ui/tooltip"; import { api } from "@/utils/api"; import { Boxes, HelpCircle, LockIcon, MoreHorizontal } from "lucide-react"; -import React from "react"; import { toast } from "sonner"; import { AddNode } from "./add-node"; import { ShowNodeData } from "./show-node-data"; diff --git a/apps/dokploy/components/dashboard/settings/git/bitbucket/add-bitbucket-provider.tsx b/apps/dokploy/components/dashboard/settings/git/bitbucket/add-bitbucket-provider.tsx index 9cb605a64..2c0f30466 100644 --- a/apps/dokploy/components/dashboard/settings/git/bitbucket/add-bitbucket-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/bitbucket/add-bitbucket-provider.tsx @@ -1,8 +1,4 @@ -import { - BitbucketIcon, - GithubIcon, - GitlabIcon, -} from "@/components/icons/data-tools-icons"; +import { BitbucketIcon } from "@/components/icons/data-tools-icons"; import { AlertBlock } from "@/components/shared/alert-block"; import { Button } from "@/components/ui/button"; import { CardContent } from "@/components/ui/card"; diff --git a/apps/dokploy/components/dashboard/settings/git/bitbucket/edit-bitbucket-provider.tsx b/apps/dokploy/components/dashboard/settings/git/bitbucket/edit-bitbucket-provider.tsx index 25c5e5daf..e5a7f7529 100644 --- a/apps/dokploy/components/dashboard/settings/git/bitbucket/edit-bitbucket-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/bitbucket/edit-bitbucket-provider.tsx @@ -20,7 +20,7 @@ import { import { Input } from "@/components/ui/input"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { Edit, PenBoxIcon } from "lucide-react"; +import { PenBoxIcon } from "lucide-react"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx b/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx index fb688b89d..6c5d488eb 100644 --- a/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/gitlab/edit-gitlab-provider.tsx @@ -20,7 +20,7 @@ import { import { Input } from "@/components/ui/input"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { Edit, PenBoxIcon } from "lucide-react"; +import { PenBoxIcon } from "lucide-react"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx b/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx index b1da3ec1a..918df4353 100644 --- a/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx @@ -3,7 +3,6 @@ import { Dialog, DialogContent, DialogDescription, - DialogFooter, DialogHeader, DialogTitle, DialogTrigger, diff --git a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx index ca1bf3c21..f4299709a 100644 --- a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx @@ -1,5 +1,4 @@ import { AlertBlock } from "@/components/shared/alert-block"; -import { DialogAction } from "@/components/shared/dialog-action"; import { Button } from "@/components/ui/button"; import { Card, @@ -18,7 +17,6 @@ import { } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; -import { authClient } from "@/lib/auth-client"; import { generateSHA256Hash } from "@/lib/utils"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/show-dokploy-actions.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/show-dokploy-actions.tsx index 3a1af2063..f57dad3cd 100644 --- a/apps/dokploy/components/dashboard/settings/servers/actions/show-dokploy-actions.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/actions/show-dokploy-actions.tsx @@ -1,5 +1,4 @@ import { Button } from "@/components/ui/button"; -import React from "react"; import { UpdateServerIp } from "@/components/dashboard/settings/web-server/update-server-ip"; import { diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/show-storage-actions.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/show-storage-actions.tsx index c45c0c8b5..cb60effd1 100644 --- a/apps/dokploy/components/dashboard/settings/servers/actions/show-storage-actions.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/actions/show-storage-actions.tsx @@ -1,5 +1,4 @@ import { Button } from "@/components/ui/button"; -import React from "react"; import { DropdownMenu, diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx index 17a6ae757..0968931d7 100644 --- a/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/actions/show-traefik-actions.tsx @@ -1,14 +1,4 @@ import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; -import React from "react"; import { DropdownMenu, @@ -20,10 +10,8 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { api } from "@/utils/api"; -import { toast } from "sonner"; - -import { cn } from "@/lib/utils"; import { useTranslation } from "next-i18next"; +import { toast } from "sonner"; import { EditTraefikEnv } from "../../web-server/edit-traefik-env"; import { ManageTraefikPorts } from "../../web-server/manage-traefik-ports"; import { ShowModalLogs } from "../../web-server/show-modal-logs"; diff --git a/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx b/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx index 3cda7e806..ec60fed6d 100644 --- a/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx @@ -9,7 +9,6 @@ import { CardTitle, } from "@/components/ui/card"; import { api } from "@/utils/api"; -import { TRPCClientError } from "@trpc/client"; import { CheckCircle2, Cpu, Loader2, RefreshCw, XCircle } from "lucide-react"; import { useEffect, useState } from "react"; import { toast } from "sonner"; diff --git a/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx b/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx index db9545a64..23173047e 100644 --- a/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx @@ -2,7 +2,6 @@ import { AlertBlock } from "@/components/shared/alert-block"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { - Card, CardContent, CardDescription, CardHeader, @@ -30,7 +29,6 @@ import { PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; -import { ScrollArea } from "@/components/ui/scroll-area"; import { extractServices } from "@/pages/dashboard/project/[projectId]"; import { api } from "@/utils/api"; import { useUrl } from "@/utils/hooks/use-url"; diff --git a/apps/dokploy/components/dashboard/settings/servers/show-docker-containers-modal.tsx b/apps/dokploy/components/dashboard/settings/servers/show-docker-containers-modal.tsx index 1cdab23bc..ad82085c7 100644 --- a/apps/dokploy/components/dashboard/settings/servers/show-docker-containers-modal.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/show-docker-containers-modal.tsx @@ -1,10 +1,4 @@ -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; +import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"; import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; import { useState } from "react"; import { ShowContainers } from "../../docker/show/show-containers"; diff --git a/apps/dokploy/components/dashboard/settings/servers/show-swarm-overview-modal.tsx b/apps/dokploy/components/dashboard/settings/servers/show-swarm-overview-modal.tsx index a47005d07..b86311840 100644 --- a/apps/dokploy/components/dashboard/settings/servers/show-swarm-overview-modal.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/show-swarm-overview-modal.tsx @@ -1,12 +1,5 @@ -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; +import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"; import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; -import { ContainerIcon } from "lucide-react"; import { useState } from "react"; import SwarmMonitorCard from "../../swarm/monitoring-card"; diff --git a/apps/dokploy/components/dashboard/settings/users/show-users.tsx b/apps/dokploy/components/dashboard/settings/users/show-users.tsx index 0ccb23e7d..ff56698e4 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-users.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-users.tsx @@ -26,7 +26,6 @@ import { } from "@/components/ui/table"; import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; -import copy from "copy-to-clipboard"; import { format } from "date-fns"; import { MoreHorizontal, Users } from "lucide-react"; import { Loader2 } from "lucide-react"; @@ -134,12 +133,45 @@ export const ShowUsers = () => { )} {member.role !== "owner" && ( - { - if (isCloud) { + <> + {!isCloud && ( + { + await mutateAsync({ + userId: member.user.id, + }) + .then(() => { + toast.success( + "User deleted successfully", + ); + refetch(); + }) + .catch(() => { + toast.error( + "Error deleting destination", + ); + }); + }} + > + + e.preventDefault() + } + > + Delete User + + + )} + + { const { error } = await authClient.organization.removeMember( { @@ -149,39 +181,24 @@ export const ShowUsers = () => { if (!error) { toast.success( - "User deleted successfully", + "User unlinked successfully", ); refetch(); } else { toast.error( - "Error deleting user", + "Error unlinking user", ); } - } else { - await mutateAsync({ - userId: member.user.id, - }) - .then(() => { - toast.success( - "User deleted successfully", - ); - refetch(); - }) - .catch(() => { - toast.error( - "Error deleting destination", - ); - }); - } - }} - > - e.preventDefault()} + }} > - Delete User - - + e.preventDefault()} + > + Unlink User + + + )} diff --git a/apps/dokploy/components/dashboard/settings/web-domain.tsx b/apps/dokploy/components/dashboard/settings/web-domain.tsx index 13750e2aa..3b3f70ba5 100644 --- a/apps/dokploy/components/dashboard/settings/web-domain.tsx +++ b/apps/dokploy/components/dashboard/settings/web-domain.tsx @@ -24,7 +24,7 @@ import { } from "@/components/ui/select"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { GlobeIcon, ServerIcon, User } from "lucide-react"; +import { GlobeIcon } from "lucide-react"; import { useTranslation } from "next-i18next"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; diff --git a/apps/dokploy/components/dashboard/settings/web-server.tsx b/apps/dokploy/components/dashboard/settings/web-server.tsx index 0cc4772f2..326cb0eaf 100644 --- a/apps/dokploy/components/dashboard/settings/web-server.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server.tsx @@ -5,11 +5,9 @@ import { CardHeader, CardTitle, } from "@/components/ui/card"; -import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { ServerIcon } from "lucide-react"; import { useTranslation } from "next-i18next"; -import React from "react"; import { ShowDokployActions } from "./servers/actions/show-dokploy-actions"; import { ShowStorageActions } from "./servers/actions/show-storage-actions"; import { ShowTraefikActions } from "./servers/actions/show-traefik-actions"; diff --git a/apps/dokploy/components/dashboard/settings/web-server/local-server-config.tsx b/apps/dokploy/components/dashboard/settings/web-server/local-server-config.tsx index f68046dbb..e30408e6d 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/local-server-config.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/local-server-config.tsx @@ -18,7 +18,6 @@ import { cn } from "@/lib/utils"; import { zodResolver } from "@hookform/resolvers/zod"; import { Settings } from "lucide-react"; import { useTranslation } from "next-i18next"; -import React from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; diff --git a/apps/dokploy/components/dashboard/settings/web-server/show-modal-logs.tsx b/apps/dokploy/components/dashboard/settings/web-server/show-modal-logs.tsx index 12e7b6704..bedecf517 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/show-modal-logs.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/show-modal-logs.tsx @@ -6,7 +6,6 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; import { Label } from "@/components/ui/label"; import { Select, diff --git a/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx b/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx index 816687f58..2cfc459b6 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/update-server.tsx @@ -1,4 +1,3 @@ -import { AlertBlock } from "@/components/shared/alert-block"; import { Button } from "@/components/ui/button"; import { Dialog, @@ -14,7 +13,6 @@ import { Info, RefreshCcw, Server, - ServerCrash, Sparkles, Stars, } from "lucide-react"; diff --git a/apps/dokploy/components/dashboard/swarm/applications/columns.tsx b/apps/dokploy/components/dashboard/swarm/applications/columns.tsx index 69ccc41d6..ab058e851 100644 --- a/apps/dokploy/components/dashboard/swarm/applications/columns.tsx +++ b/apps/dokploy/components/dashboard/swarm/applications/columns.tsx @@ -1,6 +1,5 @@ import type { ColumnDef } from "@tanstack/react-table"; import { ArrowUpDown, MoreHorizontal } from "lucide-react"; -import * as React from "react"; import { Button } from "@/components/ui/button"; import { diff --git a/apps/dokploy/components/dashboard/swarm/applications/show-applications.tsx b/apps/dokploy/components/dashboard/swarm/applications/show-applications.tsx index 41d7b113b..681afd755 100644 --- a/apps/dokploy/components/dashboard/swarm/applications/show-applications.tsx +++ b/apps/dokploy/components/dashboard/swarm/applications/show-applications.tsx @@ -9,7 +9,6 @@ import { } from "@/components/ui/dialog"; import { api } from "@/utils/api"; import { Layers, Loader2 } from "lucide-react"; -import React from "react"; import { type ApplicationList, columns } from "./columns"; import { DataTable } from "./data-table"; diff --git a/apps/dokploy/components/icons/data-tools-icons.tsx b/apps/dokploy/components/icons/data-tools-icons.tsx index 93da14a06..e2c0922a8 100644 --- a/apps/dokploy/components/icons/data-tools-icons.tsx +++ b/apps/dokploy/components/icons/data-tools-icons.tsx @@ -1,5 +1,4 @@ import { cn } from "@/lib/utils"; -import React from "react"; // https://worldvectorlogo.com/downloaded/redis Ref diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index e0931b08f..939d10841 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -1,15 +1,14 @@ "use client"; import { Activity, - AudioWaveform, BarChartHorizontalBigIcon, Bell, BlocksIcon, BookIcon, Boxes, ChevronRight, + ChevronsUpDown, CircleHelp, - Command, CreditCard, Database, Folder, @@ -27,8 +26,6 @@ import { Trash2, User, Users, - ChevronsUpDown, - Plus, } from "lucide-react"; import { usePathname } from "next/navigation"; import type * as React from "react"; @@ -47,6 +44,14 @@ import { CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; import { Separator } from "@/components/ui/separator"; import { SIDEBAR_COOKIE_NAME, @@ -68,29 +73,20 @@ import { SidebarTrigger, useSidebar, } from "@/components/ui/sidebar"; +import { authClient } from "@/lib/auth-client"; import { cn } from "@/lib/utils"; import type { AppRouter } from "@/server/api/root"; import { api } from "@/utils/api"; import type { inferRouterOutputs } from "@trpc/server"; import Link from "next/link"; import { useRouter } from "next/router"; -import { Logo } from "../shared/logo"; -import { UpdateServerButton } from "./update-server"; -import { UserNav } from "./user-nav"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { authClient } from "@/lib/auth-client"; import { toast } from "sonner"; import { AddOrganization } from "../dashboard/organization/handle-organization"; import { DialogAction } from "../shared/dialog-action"; +import { Logo } from "../shared/logo"; import { Button } from "../ui/button"; +import { UpdateServerButton } from "./update-server"; +import { UserNav } from "./user-nav"; // The types of the queries we are going to use type AuthQueryOutput = inferRouterOutputs["auth"]["get"]; diff --git a/apps/dokploy/components/layouts/user-nav.tsx b/apps/dokploy/components/layouts/user-nav.tsx index 30579f300..196f6d77d 100644 --- a/apps/dokploy/components/layouts/user-nav.tsx +++ b/apps/dokploy/components/layouts/user-nav.tsx @@ -20,9 +20,7 @@ import { Languages } from "@/lib/languages"; import { api } from "@/utils/api"; import useLocale from "@/utils/hooks/use-locale"; import { ChevronsUpDown } from "lucide-react"; -import { useTranslation } from "next-i18next"; import { useRouter } from "next/router"; -import { useEffect, useRef, useState } from "react"; import { ModeToggle } from "../ui/modeToggle"; import { SidebarMenuButton } from "../ui/sidebar"; diff --git a/apps/dokploy/components/shared/dialog-action.tsx b/apps/dokploy/components/shared/dialog-action.tsx index 3724242d0..444440a2d 100644 --- a/apps/dokploy/components/shared/dialog-action.tsx +++ b/apps/dokploy/components/shared/dialog-action.tsx @@ -9,7 +9,6 @@ import { AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog"; -import { Button } from "../ui/button"; interface Props { title?: string | React.ReactNode; diff --git a/apps/dokploy/components/shared/drawer-logs.tsx b/apps/dokploy/components/shared/drawer-logs.tsx index f5a56cd6a..5e4ab554b 100644 --- a/apps/dokploy/components/shared/drawer-logs.tsx +++ b/apps/dokploy/components/shared/drawer-logs.tsx @@ -1,6 +1,3 @@ -import { DialogAction } from "@/components/shared/dialog-action"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Sheet, SheetContent, @@ -8,10 +5,8 @@ import { SheetHeader, SheetTitle, } from "@/components/ui/sheet"; -import { api } from "@/utils/api"; -import { Ban, CheckCircle2, Loader2, RefreshCcw, Terminal } from "lucide-react"; -import React, { useState, useEffect, useRef } from "react"; -import { toast } from "sonner"; +import { Loader2 } from "lucide-react"; +import { useEffect, useRef, useState } from "react"; import { TerminalLine } from "../dashboard/docker/logs/terminal-line"; import type { LogLine } from "../dashboard/docker/logs/utils"; diff --git a/apps/dokploy/components/shared/logo.tsx b/apps/dokploy/components/shared/logo.tsx index 5d192cfdc..086ef3b0c 100644 --- a/apps/dokploy/components/shared/logo.tsx +++ b/apps/dokploy/components/shared/logo.tsx @@ -1,5 +1,3 @@ -import React from "react"; - interface Props { className?: string; } diff --git a/apps/dokploy/components/ui/modeToggle.tsx b/apps/dokploy/components/ui/modeToggle.tsx index 7965a3395..9b6ba27b9 100644 --- a/apps/dokploy/components/ui/modeToggle.tsx +++ b/apps/dokploy/components/ui/modeToggle.tsx @@ -3,7 +3,6 @@ import { Button } from "@/components/ui/button"; import { Moon, Sun } from "lucide-react"; import { useTheme } from "next-themes"; -import * as React from "react"; export function ModeToggle() { const { theme, setTheme } = useTheme(); diff --git a/apps/dokploy/migrate.ts b/apps/dokploy/migrate.ts index 38f48784c..febd1c0e2 100644 --- a/apps/dokploy/migrate.ts +++ b/apps/dokploy/migrate.ts @@ -1,5 +1,4 @@ import { drizzle } from "drizzle-orm/postgres-js"; -import { migrate } from "drizzle-orm/postgres-js/migrator"; import { nanoid } from "nanoid"; import postgres from "postgres"; import * as schema from "./server/db/schema"; diff --git a/apps/dokploy/pages/api/deploy/github.ts b/apps/dokploy/pages/api/deploy/github.ts index 761c38663..5e64d8b26 100644 --- a/apps/dokploy/pages/api/deploy/github.ts +++ b/apps/dokploy/pages/api/deploy/github.ts @@ -3,9 +3,7 @@ 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 { generateRandomDomain } from "@/templates/utils"; import { - type Domain, IS_CLOUD, createPreviewDeployment, findPreviewDeploymentByApplicationId, diff --git a/apps/dokploy/pages/api/providers/github/setup.ts b/apps/dokploy/pages/api/providers/github/setup.ts index 9a03ed3d7..ac5e7a6b0 100644 --- a/apps/dokploy/pages/api/providers/github/setup.ts +++ b/apps/dokploy/pages/api/providers/github/setup.ts @@ -1,13 +1,6 @@ import { db } from "@/server/db"; import { github } from "@/server/db/schema"; -import { - auth, - createGithub, - findAdminByAuthId, - findAuthById, - findUserByAuthId, - findUserById, -} from "@dokploy/server"; +import { createGithub } from "@dokploy/server"; import { eq } from "drizzle-orm"; import type { NextApiRequest, NextApiResponse } from "next"; import { Octokit } from "octokit"; diff --git a/apps/dokploy/pages/api/stripe/webhook.ts b/apps/dokploy/pages/api/stripe/webhook.ts index d9cbedc8a..6200a79ec 100644 --- a/apps/dokploy/pages/api/stripe/webhook.ts +++ b/apps/dokploy/pages/api/stripe/webhook.ts @@ -1,7 +1,7 @@ import { buffer } from "node:stream/consumers"; import { db } from "@/server/db"; import { server, users_temp } from "@/server/db/schema"; -import { findAdminById, findUserById } from "@dokploy/server"; +import { findUserById } from "@dokploy/server"; import { asc, eq } from "drizzle-orm"; import type { NextApiRequest, NextApiResponse } from "next"; import Stripe from "stripe"; diff --git a/apps/dokploy/pages/dashboard/docker.tsx b/apps/dokploy/pages/dashboard/docker.tsx index 5685dcfc5..a9d80353f 100644 --- a/apps/dokploy/pages/dashboard/docker.tsx +++ b/apps/dokploy/pages/dashboard/docker.tsx @@ -5,7 +5,7 @@ import { IS_CLOUD } from "@dokploy/server/constants"; import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Dashboard = () => { diff --git a/apps/dokploy/pages/dashboard/monitoring.tsx b/apps/dokploy/pages/dashboard/monitoring.tsx index c5c617a7f..4d8b072f5 100644 --- a/apps/dokploy/pages/dashboard/monitoring.tsx +++ b/apps/dokploy/pages/dashboard/monitoring.tsx @@ -1,17 +1,13 @@ import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-container-monitoring"; import { ShowPaidMonitoring } from "@/components/dashboard/monitoring/paid/servers/show-paid-monitoring"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { AlertBlock } from "@/components/shared/alert-block"; import { Card } from "@/components/ui/card"; -import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; import { useLocalStorage } from "@/hooks/useLocalStorage"; import { api } from "@/utils/api"; import { IS_CLOUD } from "@dokploy/server/constants"; import { validateRequest } from "@dokploy/server/lib/auth"; import { Loader2 } from "lucide-react"; import type { GetServerSidePropsContext } from "next"; -import type React from "react"; import type { ReactElement } from "react"; const BASE_URL = "http://localhost:3001/metrics"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx index 7eebf7083..59dba68ce 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx @@ -28,7 +28,6 @@ import { CardTitle, } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tooltip, @@ -42,7 +41,7 @@ import { api } from "@/utils/api"; import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import copy from "copy-to-clipboard"; -import { GlobeIcon, HelpCircle, ServerOff, Trash2 } from "lucide-react"; +import { GlobeIcon, HelpCircle, ServerOff } from "lucide-react"; import type { GetServerSidePropsContext, InferGetServerSidePropsType, @@ -50,7 +49,7 @@ import type { import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useState, useEffect, type ReactElement } from "react"; +import { type ReactElement, useEffect, useState } from "react"; import { toast } from "sonner"; import superjson from "superjson"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx index 46c9864b4..c1331e23f 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx @@ -22,7 +22,6 @@ import { CardTitle, } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tooltip, @@ -45,7 +44,7 @@ import type { import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useState, useEffect, type ReactElement } from "react"; +import { type ReactElement, useEffect, useState } from "react"; import { toast } from "sonner"; import superjson from "superjson"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx index 6aa7677a3..033b88a9d 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx @@ -24,7 +24,6 @@ import { CardTitle, } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tooltip, @@ -37,7 +36,7 @@ import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; -import { HelpCircle, ServerOff, Trash2 } from "lucide-react"; +import { HelpCircle, ServerOff } from "lucide-react"; import type { GetServerSidePropsContext, InferGetServerSidePropsType, @@ -45,8 +44,7 @@ import type { import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useState, type ReactElement } from "react"; -import { toast } from "sonner"; +import { type ReactElement, useState } from "react"; import superjson from "superjson"; type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx index 2e3aae31f..dea8cd57b 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx @@ -24,7 +24,6 @@ import { CardTitle, } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tooltip, @@ -37,7 +36,7 @@ import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; -import { HelpCircle, ServerOff, Trash2 } from "lucide-react"; +import { HelpCircle, ServerOff } from "lucide-react"; import type { GetServerSidePropsContext, InferGetServerSidePropsType, @@ -45,8 +44,7 @@ import type { import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useState, type ReactElement } from "react"; -import { toast } from "sonner"; +import { type ReactElement, useState } from "react"; import superjson from "superjson"; type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx index 3e75603dd..cc4eb4aa3 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx @@ -24,7 +24,6 @@ import { CardTitle, } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tooltip, @@ -37,7 +36,7 @@ import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; -import { HelpCircle, ServerOff, Trash2 } from "lucide-react"; +import { HelpCircle, ServerOff } from "lucide-react"; import type { GetServerSidePropsContext, InferGetServerSidePropsType, @@ -45,8 +44,7 @@ import type { import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useState, type ReactElement } from "react"; -import { toast } from "sonner"; +import { type ReactElement, useState } from "react"; import superjson from "superjson"; type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx index dd0c312d0..d0f1dc106 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx @@ -24,7 +24,6 @@ import { CardTitle, } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tooltip, @@ -37,7 +36,7 @@ import { appRouter } from "@/server/api/root"; import { api } from "@/utils/api"; import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; -import { HelpCircle, ServerOff, Trash2 } from "lucide-react"; +import { HelpCircle, ServerOff } from "lucide-react"; import type { GetServerSidePropsContext, InferGetServerSidePropsType, @@ -45,8 +44,7 @@ import type { import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useState, type ReactElement } from "react"; -import { toast } from "sonner"; +import { type ReactElement, useState } from "react"; import superjson from "superjson"; type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced"; diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx index c7e5643a6..2b053df47 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx @@ -23,7 +23,6 @@ import { CardTitle, } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tooltip, @@ -44,8 +43,7 @@ import type { import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useState, type ReactElement } from "react"; -import { toast } from "sonner"; +import { type ReactElement, useState } from "react"; import superjson from "superjson"; type TabState = "projects" | "monitoring" | "settings" | "advanced"; diff --git a/apps/dokploy/pages/dashboard/projects.tsx b/apps/dokploy/pages/dashboard/projects.tsx index abeee6695..49427c25b 100644 --- a/apps/dokploy/pages/dashboard/projects.tsx +++ b/apps/dokploy/pages/dashboard/projects.tsx @@ -6,7 +6,6 @@ import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; import dynamic from "next/dynamic"; -import type React from "react"; import type { ReactElement } from "react"; import superjson from "superjson"; diff --git a/apps/dokploy/pages/dashboard/requests.tsx b/apps/dokploy/pages/dashboard/requests.tsx index 580b936a2..cb4545875 100644 --- a/apps/dokploy/pages/dashboard/requests.tsx +++ b/apps/dokploy/pages/dashboard/requests.tsx @@ -4,7 +4,6 @@ import { IS_CLOUD } from "@dokploy/server/constants"; import { validateRequest } from "@dokploy/server/lib/auth"; import type { GetServerSidePropsContext } from "next"; import type { ReactElement } from "react"; -import * as React from "react"; export default function Requests() { return ; diff --git a/apps/dokploy/pages/dashboard/settings/billing.tsx b/apps/dokploy/pages/dashboard/settings/billing.tsx index 3acce0b01..ee1ecdbe5 100644 --- a/apps/dokploy/pages/dashboard/settings/billing.tsx +++ b/apps/dokploy/pages/dashboard/settings/billing.tsx @@ -6,7 +6,7 @@ import { IS_CLOUD } from "@dokploy/server/constants"; import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { diff --git a/apps/dokploy/pages/dashboard/settings/certificates.tsx b/apps/dokploy/pages/dashboard/settings/certificates.tsx index d045208e1..96bec90bf 100644 --- a/apps/dokploy/pages/dashboard/settings/certificates.tsx +++ b/apps/dokploy/pages/dashboard/settings/certificates.tsx @@ -5,7 +5,7 @@ import { appRouter } from "@/server/api/root"; import { validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { return ( diff --git a/apps/dokploy/pages/dashboard/settings/cluster.tsx b/apps/dokploy/pages/dashboard/settings/cluster.tsx index 8d70f8692..77ece29b8 100644 --- a/apps/dokploy/pages/dashboard/settings/cluster.tsx +++ b/apps/dokploy/pages/dashboard/settings/cluster.tsx @@ -5,7 +5,7 @@ import { appRouter } from "@/server/api/root"; import { IS_CLOUD, validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { diff --git a/apps/dokploy/pages/dashboard/settings/destinations.tsx b/apps/dokploy/pages/dashboard/settings/destinations.tsx index d9d17d538..8605a7c18 100644 --- a/apps/dokploy/pages/dashboard/settings/destinations.tsx +++ b/apps/dokploy/pages/dashboard/settings/destinations.tsx @@ -5,7 +5,7 @@ import { appRouter } from "@/server/api/root"; import { validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx index 7bacde246..4187a0ef7 100644 --- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx +++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx @@ -5,7 +5,7 @@ import { appRouter } from "@/server/api/root"; import { validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { diff --git a/apps/dokploy/pages/dashboard/settings/index.tsx b/apps/dokploy/pages/dashboard/settings/index.tsx index 2bfce2f2e..713e51133 100644 --- a/apps/dokploy/pages/dashboard/settings/index.tsx +++ b/apps/dokploy/pages/dashboard/settings/index.tsx @@ -17,7 +17,6 @@ import { FormField, FormItem, FormLabel, - FormMessage, } from "@/components/ui/form"; import { Switch } from "@/components/ui/switch"; import { appRouter } from "@/server/api/root"; @@ -27,7 +26,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { createServerSideHelpers } from "@trpc/react-query/server"; import { Settings } from "lucide-react"; import type { GetServerSidePropsContext } from "next"; -import React, { useEffect, type ReactElement } from "react"; +import { type ReactElement, useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import superjson from "superjson"; diff --git a/apps/dokploy/pages/dashboard/settings/notifications.tsx b/apps/dokploy/pages/dashboard/settings/notifications.tsx index d0e0c65fe..76566fdf2 100644 --- a/apps/dokploy/pages/dashboard/settings/notifications.tsx +++ b/apps/dokploy/pages/dashboard/settings/notifications.tsx @@ -5,7 +5,7 @@ import { appRouter } from "@/server/api/root"; import { validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index 79a3366d4..446e6c875 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -9,7 +9,7 @@ import { getLocale, serverSideTranslations } from "@/utils/i18n"; import { validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { diff --git a/apps/dokploy/pages/dashboard/settings/registry.tsx b/apps/dokploy/pages/dashboard/settings/registry.tsx index 0a01e255f..678e0da46 100644 --- a/apps/dokploy/pages/dashboard/settings/registry.tsx +++ b/apps/dokploy/pages/dashboard/settings/registry.tsx @@ -5,7 +5,7 @@ import { appRouter } from "@/server/api/root"; import { validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { diff --git a/apps/dokploy/pages/dashboard/settings/server.tsx b/apps/dokploy/pages/dashboard/settings/server.tsx index dbd049579..4f88c794b 100644 --- a/apps/dokploy/pages/dashboard/settings/server.tsx +++ b/apps/dokploy/pages/dashboard/settings/server.tsx @@ -1,4 +1,3 @@ -import { SetupMonitoring } from "@/components/dashboard/settings/servers/setup-monitoring"; import { WebDomain } from "@/components/dashboard/settings/web-domain"; import { WebServer } from "@/components/dashboard/settings/web-server"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; @@ -6,10 +5,8 @@ import { appRouter } from "@/server/api/root"; import { getLocale, serverSideTranslations } from "@/utils/i18n"; import { IS_CLOUD, validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; -import { LayoutDashboardIcon } from "lucide-react"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; -import { toast } from "sonner"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { diff --git a/apps/dokploy/pages/dashboard/settings/servers.tsx b/apps/dokploy/pages/dashboard/settings/servers.tsx index 85ca5bb31..08d4ab694 100644 --- a/apps/dokploy/pages/dashboard/settings/servers.tsx +++ b/apps/dokploy/pages/dashboard/settings/servers.tsx @@ -6,7 +6,7 @@ import { getLocale, serverSideTranslations } from "@/utils/i18n"; import { validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { diff --git a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx index 8c5082e39..738c647d4 100644 --- a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx +++ b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx @@ -5,7 +5,7 @@ import { appRouter } from "@/server/api/root"; import { validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { diff --git a/apps/dokploy/pages/dashboard/settings/users.tsx b/apps/dokploy/pages/dashboard/settings/users.tsx index e9fb65608..ac5355218 100644 --- a/apps/dokploy/pages/dashboard/settings/users.tsx +++ b/apps/dokploy/pages/dashboard/settings/users.tsx @@ -6,7 +6,7 @@ import { appRouter } from "@/server/api/root"; import { validateRequest } from "@dokploy/server"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Page = () => { diff --git a/apps/dokploy/pages/dashboard/traefik.tsx b/apps/dokploy/pages/dashboard/traefik.tsx index 3153e80d3..90359ccd6 100644 --- a/apps/dokploy/pages/dashboard/traefik.tsx +++ b/apps/dokploy/pages/dashboard/traefik.tsx @@ -5,7 +5,7 @@ import { IS_CLOUD } from "@dokploy/server/constants"; import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import React, { type ReactElement } from "react"; +import type { ReactElement } from "react"; import superjson from "superjson"; const Dashboard = () => { diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 795d7a862..c910e78ec 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -1,8 +1,7 @@ -import { Login2FA } from "@/components/auth/login-2fa"; import { OnboardingLayout } from "@/components/layouts/onboarding-layout"; import { AlertBlock } from "@/components/shared/alert-block"; import { Logo } from "@/components/shared/logo"; -import { Button, buttonVariants } from "@/components/ui/button"; +import { Button } from "@/components/ui/button"; import { CardContent, CardDescription } from "@/components/ui/card"; import { Dialog, @@ -10,12 +9,10 @@ import { DialogDescription, DialogHeader, DialogTitle, - DialogTrigger, } from "@/components/ui/dialog"; import { Form, FormControl, - FormDescription, FormField, FormItem, FormLabel, @@ -29,19 +26,14 @@ import { } from "@/components/ui/input-otp"; import { Label } from "@/components/ui/label"; import { authClient } from "@/lib/auth-client"; -import { cn } from "@/lib/utils"; -import { api } from "@/utils/api"; -import { IS_CLOUD, auth, isAdminPresent } from "@dokploy/server"; +import { IS_CLOUD, isAdminPresent } from "@dokploy/server"; import { validateRequest } from "@dokploy/server/lib/auth"; import { zodResolver } from "@hookform/resolvers/zod"; -import base32 from "hi-base32"; import { REGEXP_ONLY_DIGITS } from "input-otp"; -import { AlertTriangle } from "lucide-react"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; -import { TOTP } from "otpauth"; -import { type ReactElement, useEffect, useState } from "react"; +import { type ReactElement, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; diff --git a/apps/dokploy/pages/invitation.tsx b/apps/dokploy/pages/invitation.tsx index c11cc8225..91ca1d0d7 100644 --- a/apps/dokploy/pages/invitation.tsx +++ b/apps/dokploy/pages/invitation.tsx @@ -2,12 +2,7 @@ import { OnboardingLayout } from "@/components/layouts/onboarding-layout"; import { AlertBlock } from "@/components/shared/alert-block"; import { Logo } from "@/components/shared/logo"; import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardTitle, -} from "@/components/ui/card"; +import { CardContent, CardDescription, CardTitle } from "@/components/ui/card"; import { Form, FormControl, @@ -21,7 +16,7 @@ import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; import { IS_CLOUD, getUserByToken } from "@dokploy/server"; import { zodResolver } from "@hookform/resolvers/zod"; -import { AlertCircle, AlertTriangle } from "lucide-react"; +import { AlertTriangle } from "lucide-react"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; diff --git a/apps/dokploy/pages/register.tsx b/apps/dokploy/pages/register.tsx index e8fd15cf5..701d8f5b5 100644 --- a/apps/dokploy/pages/register.tsx +++ b/apps/dokploy/pages/register.tsx @@ -2,12 +2,7 @@ import { OnboardingLayout } from "@/components/layouts/onboarding-layout"; import { AlertBlock } from "@/components/shared/alert-block"; import { Logo } from "@/components/shared/logo"; import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardTitle, -} from "@/components/ui/card"; +import { CardContent, CardDescription, CardTitle } from "@/components/ui/card"; import { Form, FormControl, @@ -27,7 +22,6 @@ import Link from "next/link"; import { useRouter } from "next/router"; import { type ReactElement, useEffect } from "react"; import { useForm } from "react-hook-form"; -import { toast } from "sonner"; import { z } from "zod"; const registerSchema = z diff --git a/apps/dokploy/pages/send-reset-password.tsx b/apps/dokploy/pages/send-reset-password.tsx index c4cd851ce..ce73fbb82 100644 --- a/apps/dokploy/pages/send-reset-password.tsx +++ b/apps/dokploy/pages/send-reset-password.tsx @@ -3,12 +3,7 @@ import { OnboardingLayout } from "@/components/layouts/onboarding-layout"; import { AlertBlock } from "@/components/shared/alert-block"; import { Logo } from "@/components/shared/logo"; import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardTitle, -} from "@/components/ui/card"; +import { CardContent, CardDescription, CardTitle } from "@/components/ui/card"; import { Form, FormControl, diff --git a/apps/dokploy/server/api/routers/admin.ts b/apps/dokploy/server/api/routers/admin.ts index 293b7dfe5..47bd9cd9c 100644 --- a/apps/dokploy/server/api/routers/admin.ts +++ b/apps/dokploy/server/api/routers/admin.ts @@ -1,119 +1,14 @@ -import { - apiAssignPermissions, - apiCreateUserInvitation, - apiFindOneToken, - apiRemoveUser, - apiUpdateWebServerMonitoring, -} from "@/server/db/schema"; +import { apiUpdateWebServerMonitoring } from "@/server/db/schema"; import { IS_CLOUD, - createInvitation, - findOrganizationById, findUserById, - getUserByToken, - removeUserById, setupWebMonitoring, updateUser, } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; -import { z } from "zod"; -import { - adminProcedure, - createTRPCRouter, - protectedProcedure, - publicProcedure, -} from "../trpc"; +import { adminProcedure, createTRPCRouter } from "../trpc"; export const adminRouter = createTRPCRouter({ - one: adminProcedure.query(async ({ ctx }) => { - const { sshPrivateKey, ...rest } = await findUserById(ctx.user.id); - return { - haveSSH: !!sshPrivateKey, - ...rest, - }; - }), - update: adminProcedure - .input( - z.object({ - enableDockerCleanup: z.boolean(), - }), - ) - .mutation(async ({ input, ctx }) => { - if (ctx.user.rol === "member") { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to update this admin", - }); - } - const user = await findUserById(ctx.user.ownerId); - return updateUser(user.id, {}); - }), - createUserInvitation: adminProcedure - .input(apiCreateUserInvitation) - .mutation(async ({ input, ctx }) => { - try { - await createInvitation(input, ctx.user.id); - } catch (error) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: - "Error creating this user\ncheck if the email is not registered", - cause: error, - }); - } - }), - removeUser: adminProcedure - .input(apiRemoveUser) - .mutation(async ({ input, ctx }) => { - try { - const user = await findUserById(input.id); - - if (user.id !== ctx.user.ownerId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to delete this user", - }); - } - - return await removeUserById(input.id); - } catch (error) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error deleting this user", - cause: error, - }); - } - }), - getUserByToken: publicProcedure - .input(apiFindOneToken) - .query(async ({ input }) => { - return await getUserByToken(input.token); - }), - assignPermissions: adminProcedure - .input(apiAssignPermissions) - .mutation(async ({ input, ctx }) => { - try { - const user = await findUserById(input.id); - - const organization = await findOrganizationById( - ctx.session?.activeOrganizationId || "", - ); - - if (organization?.ownerId !== ctx.user.ownerId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to assign permissions", - }); - } - - await updateUser(user.id, { - ...input, - }); - } catch (error) { - throw error; - } - }), - setupMonitoring: adminProcedure .input(apiUpdateWebServerMonitoring) .mutation(async ({ input, ctx }) => { @@ -163,129 +58,4 @@ export const adminRouter = createTRPCRouter({ throw error; } }), - getMetricsToken: protectedProcedure.query(async ({ ctx }) => { - const user = await findUserById(ctx.user.ownerId); - return { - serverIp: user.serverIp, - enabledFeatures: user.enablePaidFeatures, - metricsConfig: user?.metricsConfig, - }; - }), - - getServerMetrics: protectedProcedure - .input( - z.object({ - url: z.string(), - token: z.string(), - dataPoints: z.string(), - }), - ) - .query(async ({ ctx, input }) => { - try { - const url = new URL(input.url); - url.searchParams.append("limit", input.dataPoints); - const response = await fetch(url.toString(), { - headers: { - Authorization: `Bearer ${input.token}`, - }, - }); - if (!response.ok) { - throw new Error( - `Error ${response.status}: ${response.statusText}. Ensure the container is running and this service is included in the monitoring configuration.`, - ); - } - - const data = await response.json(); - if (!Array.isArray(data) || data.length === 0) { - throw new Error( - [ - "No monitoring data available. This could be because:", - "", - "1. You don't have setup the monitoring service, you can do in web server section.", - "2. If you already have setup the monitoring service, wait a few minutes and refresh the page.", - ].join("\n"), - ); - } - return data as { - cpu: string; - cpuModel: string; - cpuCores: number; - cpuPhysicalCores: number; - cpuSpeed: number; - os: string; - distro: string; - kernel: string; - arch: string; - memUsed: string; - memUsedGB: string; - memTotal: string; - uptime: number; - diskUsed: string; - totalDisk: string; - networkIn: string; - networkOut: string; - timestamp: string; - }[]; - } catch (error) { - throw error; - } - }), - getContainerMetrics: protectedProcedure - .input( - z.object({ - url: z.string(), - token: z.string(), - appName: z.string(), - dataPoints: z.string(), - }), - ) - .query(async ({ ctx, input }) => { - try { - if (!input.appName) { - throw new Error( - [ - "No Application Selected:", - "", - "Make Sure to select an application to monitor.", - ].join("\n"), - ); - } - const url = new URL(`${input.url}/metrics/containers`); - url.searchParams.append("limit", input.dataPoints); - url.searchParams.append("appName", input.appName); - const response = await fetch(url.toString(), { - headers: { - Authorization: `Bearer ${input.token}`, - }, - }); - if (!response.ok) { - throw new Error( - `Error ${response.status}: ${response.statusText}. Please verify that the application "${input.appName}" is running and this service is included in the monitoring configuration.`, - ); - } - - const data = await response.json(); - if (!Array.isArray(data) || data.length === 0) { - throw new Error( - [ - `No monitoring data available for "${input.appName}". This could be because:`, - "", - "1. The container was recently started - wait a few minutes for data to be collected", - "2. The container is not running - verify its status", - "3. The service is not included in your monitoring configuration", - ].join("\n"), - ); - } - return data as { - containerId: string; - containerName: string; - containerImage: string; - containerLabels: string; - containerCommand: string; - containerCreated: string; - }[]; - } catch (error) { - throw error; - } - }), }); diff --git a/apps/dokploy/server/api/routers/application.ts b/apps/dokploy/server/api/routers/application.ts index 269ac77b5..e1629b4cb 100644 --- a/apps/dokploy/server/api/routers/application.ts +++ b/apps/dokploy/server/api/routers/application.ts @@ -61,7 +61,12 @@ export const applicationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.projectId, "create"); + await checkServiceAccess( + ctx.user.id, + input.projectId, + ctx.session.activeOrganizationId, + "create", + ); } if (IS_CLOUD && !input.serverId) { @@ -103,7 +108,12 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .query(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.applicationId, "access"); + await checkServiceAccess( + ctx.user.id, + input.applicationId, + ctx.session.activeOrganizationId, + "access", + ); } const application = await findApplicationById(input.applicationId); if ( @@ -149,7 +159,12 @@ export const applicationRouter = createTRPCRouter({ .input(apiFindOneApplication) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.applicationId, "delete"); + await checkServiceAccess( + ctx.user.id, + input.applicationId, + ctx.session.activeOrganizationId, + "delete", + ); } const application = await findApplicationById(input.applicationId); @@ -186,7 +201,7 @@ export const applicationRouter = createTRPCRouter({ for (const operation of cleanupOperations) { try { await operation(); - } catch (error) {} + } catch (_) {} } return result[0]; @@ -642,7 +657,7 @@ export const applicationRouter = createTRPCRouter({ }), readAppMonitoring: protectedProcedure .input(apiFindMonitoringStats) - .query(async ({ input, ctx }) => { + .query(async ({ input }) => { if (IS_CLOUD) { throw new TRPCError({ code: "UNAUTHORIZED", diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index 4cfbe71a2..da3121b2e 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -12,14 +12,11 @@ import { import { WEBSITE_URL } from "@/server/utils/stripe"; import { IS_CLOUD, - findAuthById, findUserById, - generate2FASecret, getUserByToken, sendDiscordNotification, sendEmailNotification, validateRequest, - verify2FA, } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; import * as bcrypt from "bcrypt"; @@ -273,42 +270,6 @@ export const authRouter = createTRPCRouter({ const user = await findUserById(input.userId); return user; }), - - generate2FASecret: protectedProcedure.query(async ({ ctx }) => { - return await generate2FASecret(ctx.user.id); - }), - verify2FASetup: protectedProcedure.mutation(async ({ ctx, input }) => { - // const auth = await findAuthById(ctx.user.authId); - // await verify2FA(auth, input.secret, input.pin); - // await updateAuthById(auth.id, { - // is2FAEnabled: true, - // secret: input.secret, - // }); - // return auth; - }), - - verifyLogin2FA: publicProcedure.mutation(async ({ ctx, input }) => { - // const auth = await findAuthById(input.id); - - // await verify2FA(auth, auth.secret || "", input.pin); - - // const session = await lucia.createSession(auth.id, {}); - - // ctx.res.appendHeader( - // "Set-Cookie", - // lucia.createSessionCookie(session.id).serialize(), - // ); - - return true; - }), - disable2FA: protectedProcedure.mutation(async ({ ctx }) => { - // const auth = await findAuthById(ctx.user.authId); - // await updateAuthById(auth.id, { - // is2FAEnabled: false, - // secret: null, - // }); - // return auth; - }), sendResetPasswordEmail: publicProcedure .input( z.object({ diff --git a/apps/dokploy/server/api/routers/backup.ts b/apps/dokploy/server/api/routers/backup.ts index 0b8d7ab15..8a7a5f22f 100644 --- a/apps/dokploy/server/api/routers/backup.ts +++ b/apps/dokploy/server/api/routers/backup.ts @@ -30,7 +30,7 @@ import { TRPCError } from "@trpc/server"; export const backupRouter = createTRPCRouter({ create: protectedProcedure .input(apiCreateBackup) - .mutation(async ({ input, ctx }) => { + .mutation(async ({ input }) => { try { const newBackup = await createBackup(input); @@ -74,16 +74,14 @@ export const backupRouter = createTRPCRouter({ }); } }), - one: protectedProcedure - .input(apiFindOneBackup) - .query(async ({ input, ctx }) => { - const backup = await findBackupById(input.backupId); + one: protectedProcedure.input(apiFindOneBackup).query(async ({ input }) => { + const backup = await findBackupById(input.backupId); - return backup; - }), + return backup; + }), update: protectedProcedure .input(apiUpdateBackup) - .mutation(async ({ input, ctx }) => { + .mutation(async ({ input }) => { try { await updateBackupById(input.backupId, input); const backup = await findBackupById(input.backupId); @@ -111,15 +109,17 @@ export const backupRouter = createTRPCRouter({ } } } catch (error) { + const message = + error instanceof Error ? error.message : "Error updating this Backup"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error updating this Backup", + message, }); } }), remove: protectedProcedure .input(apiRemoveBackup) - .mutation(async ({ input, ctx }) => { + .mutation(async ({ input }) => { try { const value = await removeBackupById(input.backupId); if (IS_CLOUD && value) { @@ -133,10 +133,11 @@ export const backupRouter = createTRPCRouter({ } return value; } catch (error) { + const message = + error instanceof Error ? error.message : "Error deleting this Backup"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error deleting this Backup", - cause: error, + message, }); } }), @@ -149,11 +150,13 @@ export const backupRouter = createTRPCRouter({ await runPostgresBackup(postgres, backup); return true; } catch (error) { - console.log(error); + const message = + error instanceof Error + ? error.message + : "Error running manual Postgres backup "; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error running manual Postgres backup ", - cause: error, + message, }); } }), diff --git a/apps/dokploy/server/api/routers/cluster.ts b/apps/dokploy/server/api/routers/cluster.ts index 7ded632c6..0d8407576 100644 --- a/apps/dokploy/server/api/routers/cluster.ts +++ b/apps/dokploy/server/api/routers/cluster.ts @@ -40,7 +40,7 @@ export const clusterRouter = createTRPCRouter({ }); } }), - addWorker: protectedProcedure.query(async ({ input }) => { + addWorker: protectedProcedure.query(async () => { if (IS_CLOUD) { return { command: "", @@ -57,7 +57,7 @@ export const clusterRouter = createTRPCRouter({ version: docker_version.Version, }; }), - addManager: protectedProcedure.query(async ({ input }) => { + addManager: protectedProcedure.query(async () => { if (IS_CLOUD) { return { command: "", diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index 258a03d4b..bae926d05 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -61,7 +61,12 @@ export const composeRouter = createTRPCRouter({ .mutation(async ({ ctx, input }) => { try { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.projectId, "create"); + await checkServiceAccess( + ctx.user.id, + input.projectId, + ctx.session.activeOrganizationId, + "create", + ); } if (IS_CLOUD && !input.serverId) { @@ -97,7 +102,12 @@ export const composeRouter = createTRPCRouter({ .input(apiFindCompose) .query(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.composeId, "access"); + await checkServiceAccess( + ctx.user.id, + input.composeId, + ctx.session.activeOrganizationId, + "access", + ); } const compose = await findComposeById(input.composeId); @@ -126,7 +136,12 @@ export const composeRouter = createTRPCRouter({ .input(apiDeleteCompose) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.composeId, "delete"); + await checkServiceAccess( + ctx.user.id, + input.composeId, + ctx.session.activeOrganizationId, + "delete", + ); } const composeResult = await findComposeById(input.composeId); @@ -155,7 +170,7 @@ export const composeRouter = createTRPCRouter({ for (const operation of cleanupOperations) { try { await operation(); - } catch (error) {} + } catch (_) {} } return result[0]; @@ -385,7 +400,12 @@ export const composeRouter = createTRPCRouter({ .input(apiCreateComposeByTemplate) .mutation(async ({ ctx, input }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.projectId, "create"); + await checkServiceAccess( + ctx.user.id, + input.projectId, + ctx.session.activeOrganizationId, + "create", + ); } if (IS_CLOUD && !input.serverId) { @@ -476,7 +496,7 @@ export const composeRouter = createTRPCRouter({ return templatesData; }), - getTags: protectedProcedure.query(async ({ input }) => { + getTags: protectedProcedure.query(async () => { const allTags = templates.flatMap((template) => template.tags); const uniqueTags = _.uniq(allTags); return uniqueTags; diff --git a/apps/dokploy/server/api/routers/git-provider.ts b/apps/dokploy/server/api/routers/git-provider.ts index 39194ed31..ed37869d5 100644 --- a/apps/dokploy/server/api/routers/git-provider.ts +++ b/apps/dokploy/server/api/routers/git-provider.ts @@ -31,9 +31,13 @@ export const gitProviderRouter = createTRPCRouter({ } return await removeGitProvider(input.gitProviderId); } catch (error) { + const message = + error instanceof Error + ? error.message + : "Error deleting this Git provider"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error deleting this Git provider", + message, }); } }), diff --git a/apps/dokploy/server/api/routers/mariadb.ts b/apps/dokploy/server/api/routers/mariadb.ts index 5735620e7..be0ffd39a 100644 --- a/apps/dokploy/server/api/routers/mariadb.ts +++ b/apps/dokploy/server/api/routers/mariadb.ts @@ -20,7 +20,6 @@ import { findBackupsByDbId, findMariadbById, findProjectById, - findServerById, removeMariadbById, removeService, startService, @@ -38,7 +37,12 @@ export const mariadbRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.projectId, "create"); + await checkServiceAccess( + ctx.user.id, + input.projectId, + ctx.session.activeOrganizationId, + "create", + ); } if (IS_CLOUD && !input.serverId) { @@ -84,7 +88,12 @@ export const mariadbRouter = createTRPCRouter({ .input(apiFindOneMariaDB) .query(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.mariadbId, "access"); + await checkServiceAccess( + ctx.user.id, + input.mariadbId, + ctx.session.activeOrganizationId, + "access", + ); } const mariadb = await findMariadbById(input.mariadbId); if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) { @@ -206,7 +215,12 @@ export const mariadbRouter = createTRPCRouter({ .input(apiFindOneMariaDB) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.mariadbId, "delete"); + await checkServiceAccess( + ctx.user.id, + input.mariadbId, + ctx.session.activeOrganizationId, + "delete", + ); } const mongo = await findMariadbById(input.mariadbId); @@ -227,7 +241,7 @@ export const mariadbRouter = createTRPCRouter({ for (const operation of cleanupOperations) { try { await operation(); - } catch (error) {} + } catch (_) {} } return mongo; diff --git a/apps/dokploy/server/api/routers/mongo.ts b/apps/dokploy/server/api/routers/mongo.ts index 7f8716a59..1c3ba6bb7 100644 --- a/apps/dokploy/server/api/routers/mongo.ts +++ b/apps/dokploy/server/api/routers/mongo.ts @@ -37,7 +37,12 @@ export const mongoRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.projectId, "create"); + await checkServiceAccess( + ctx.user.id, + input.projectId, + ctx.session.activeOrganizationId, + "create", + ); } if (IS_CLOUD && !input.serverId) { @@ -87,7 +92,12 @@ export const mongoRouter = createTRPCRouter({ .input(apiFindOneMongo) .query(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.mongoId, "access"); + await checkServiceAccess( + ctx.user.id, + input.mongoId, + ctx.session.activeOrganizationId, + "access", + ); } const mongo = await findMongoById(input.mongoId); @@ -247,7 +257,12 @@ export const mongoRouter = createTRPCRouter({ .input(apiFindOneMongo) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.mongoId, "delete"); + await checkServiceAccess( + ctx.user.id, + input.mongoId, + ctx.session.activeOrganizationId, + "delete", + ); } const mongo = await findMongoById(input.mongoId); @@ -269,7 +284,7 @@ export const mongoRouter = createTRPCRouter({ for (const operation of cleanupOperations) { try { await operation(); - } catch (error) {} + } catch (_) {} } return mongo; diff --git a/apps/dokploy/server/api/routers/mysql.ts b/apps/dokploy/server/api/routers/mysql.ts index 96ea4846f..594403f24 100644 --- a/apps/dokploy/server/api/routers/mysql.ts +++ b/apps/dokploy/server/api/routers/mysql.ts @@ -39,7 +39,12 @@ export const mysqlRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.projectId, "create"); + await checkServiceAccess( + ctx.user.id, + input.projectId, + ctx.session.activeOrganizationId, + "create", + ); } if (IS_CLOUD && !input.serverId) { @@ -90,7 +95,12 @@ export const mysqlRouter = createTRPCRouter({ .input(apiFindOneMySql) .query(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.mysqlId, "access"); + await checkServiceAccess( + ctx.user.id, + input.mysqlId, + ctx.session.activeOrganizationId, + "access", + ); } const mysql = await findMySqlById(input.mysqlId); if (mysql.project.organizationId !== ctx.session.activeOrganizationId) { @@ -245,7 +255,12 @@ export const mysqlRouter = createTRPCRouter({ .input(apiFindOneMySql) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.mysqlId, "delete"); + await checkServiceAccess( + ctx.user.id, + input.mysqlId, + ctx.session.activeOrganizationId, + "delete", + ); } const mongo = await findMySqlById(input.mysqlId); if (mongo.project.organizationId !== ctx.session.activeOrganizationId) { @@ -265,7 +280,7 @@ export const mysqlRouter = createTRPCRouter({ for (const operation of cleanupOperations) { try { await operation(); - } catch (error) {} + } catch (_) {} } return mongo; diff --git a/apps/dokploy/server/api/routers/notification.ts b/apps/dokploy/server/api/routers/notification.ts index 6a893d363..48ef50b9d 100644 --- a/apps/dokploy/server/api/routers/notification.ts +++ b/apps/dokploy/server/api/routers/notification.ts @@ -297,9 +297,13 @@ export const notificationRouter = createTRPCRouter({ } return await removeNotificationById(input.notificationId); } catch (error) { + const message = + error instanceof Error + ? error.message + : "Error deleting this notification"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error deleting this notification", + message, }); } }), diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts index ad77b85cc..b98fc26c4 100644 --- a/apps/dokploy/server/api/routers/organization.ts +++ b/apps/dokploy/server/api/routers/organization.ts @@ -71,7 +71,7 @@ export const organizationRouter = createTRPCRouter({ organizationId: z.string(), }), ) - .query(async ({ ctx, input }) => { + .query(async ({ input }) => { return await db.query.organization.findFirst({ where: eq(organization.id, input.organizationId), }); @@ -140,12 +140,4 @@ export const organizationRouter = createTRPCRouter({ orderBy: [desc(invitation.status), desc(invitation.expiresAt)], }); }), - acceptInvitation: adminProcedure - .input(z.object({ invitationId: z.string() })) - .mutation(async ({ ctx, input }) => { - // const result = await auth.api.acceptInvitation({ - // invitationId: input.invitationId, - // }); - // return result; - }), }); diff --git a/apps/dokploy/server/api/routers/port.ts b/apps/dokploy/server/api/routers/port.ts index bfbc98633..923fea573 100644 --- a/apps/dokploy/server/api/routers/port.ts +++ b/apps/dokploy/server/api/routers/port.ts @@ -44,9 +44,11 @@ export const portRouter = createTRPCRouter({ try { return removePortById(input.portId); } catch (error) { + const message = + error instanceof Error ? error.message : "Error input: Deleting port"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error input: Deleting port", + message, }); } }), @@ -56,9 +58,11 @@ export const portRouter = createTRPCRouter({ try { return updatePortById(input.portId, input); } catch (error) { + const message = + error instanceof Error ? error.message : "Error updating the port"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error updating the port", + message, }); } }), diff --git a/apps/dokploy/server/api/routers/postgres.ts b/apps/dokploy/server/api/routers/postgres.ts index aa3a0459d..cf3221b48 100644 --- a/apps/dokploy/server/api/routers/postgres.ts +++ b/apps/dokploy/server/api/routers/postgres.ts @@ -1,9 +1,4 @@ -import { EventEmitter } from "node:events"; -import { - createTRPCRouter, - protectedProcedure, - publicProcedure, -} from "@/server/api/trpc"; +import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; import { apiChangePostgresStatus, apiCreatePostgres, @@ -35,9 +30,6 @@ import { } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; import { observable } from "@trpc/server/observable"; -import { z } from "zod"; - -const ee = new EventEmitter(); export const postgresRouter = createTRPCRouter({ create: protectedProcedure @@ -45,7 +37,12 @@ export const postgresRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.projectId, "create"); + await checkServiceAccess( + ctx.user.id, + input.projectId, + ctx.session.activeOrganizationId, + "create", + ); } if (IS_CLOUD && !input.serverId) { @@ -95,7 +92,12 @@ export const postgresRouter = createTRPCRouter({ .input(apiFindOnePostgres) .query(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.postgresId, "access"); + await checkServiceAccess( + ctx.user.id, + input.postgresId, + ctx.session.activeOrganizationId, + "access", + ); } const postgres = await findPostgresById(input.postgresId); @@ -238,7 +240,12 @@ export const postgresRouter = createTRPCRouter({ .input(apiFindOnePostgres) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.postgresId, "delete"); + await checkServiceAccess( + ctx.user.id, + input.postgresId, + ctx.session.activeOrganizationId, + "delete", + ); } const postgres = await findPostgresById(input.postgresId); diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index 68b068bc3..438a3f077 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -8,7 +8,6 @@ import { applications, compose, mariadb, - member, mongo, mysql, postgres, @@ -16,22 +15,20 @@ import { redis, } from "@/server/db/schema"; -import { TRPCError } from "@trpc/server"; -import { and, desc, eq, sql } from "drizzle-orm"; -import type { AnyPgColumn } from "drizzle-orm/pg-core"; - import { IS_CLOUD, addNewProject, checkProjectAccess, createProject, deleteProject, + findMemberById, findProjectById, - findUserByAuthId, findUserById, updateProjectById, - findMemberById, } from "@dokploy/server"; +import { TRPCError } from "@trpc/server"; +import { and, desc, eq, sql } from "drizzle-orm"; +import type { AnyPgColumn } from "drizzle-orm/pg-core"; export const projectRouter = createTRPCRouter({ create: protectedProcedure .input(apiCreateProject) diff --git a/apps/dokploy/server/api/routers/redis.ts b/apps/dokploy/server/api/routers/redis.ts index 6d5a84d5e..a80660bf5 100644 --- a/apps/dokploy/server/api/routers/redis.ts +++ b/apps/dokploy/server/api/routers/redis.ts @@ -37,7 +37,12 @@ export const redisRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { try { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.projectId, "create"); + await checkServiceAccess( + ctx.user.id, + input.projectId, + ctx.session.activeOrganizationId, + "create", + ); } if (IS_CLOUD && !input.serverId) { @@ -80,7 +85,12 @@ export const redisRouter = createTRPCRouter({ .input(apiFindOneRedis) .query(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.redisId, "access"); + await checkServiceAccess( + ctx.user.id, + input.redisId, + ctx.session.activeOrganizationId, + "access", + ); } const redis = await findRedisById(input.redisId); @@ -237,7 +247,12 @@ export const redisRouter = createTRPCRouter({ .input(apiFindOneRedis) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - await checkServiceAccess(ctx.user.id, input.redisId, "delete"); + await checkServiceAccess( + ctx.user.id, + input.redisId, + ctx.session.activeOrganizationId, + "delete", + ); } const redis = await findRedisById(input.redisId); @@ -256,7 +271,7 @@ export const redisRouter = createTRPCRouter({ for (const operation of cleanupOperations) { try { await operation(); - } catch (error) {} + } catch (_) {} } return redis; diff --git a/apps/dokploy/server/api/routers/registry.ts b/apps/dokploy/server/api/routers/registry.ts index 62c8a9b65..a9a6be891 100644 --- a/apps/dokploy/server/api/routers/registry.ts +++ b/apps/dokploy/server/api/routers/registry.ts @@ -1,3 +1,4 @@ +import { db } from "@/server/db"; import { apiCreateRegistry, apiFindOneRegistry, @@ -18,7 +19,6 @@ import { import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc"; -import { db } from "@/server/db"; export const registryRouter = createTRPCRouter({ create: adminProcedure .input(apiCreateRegistry) diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts index 1d7fd40e8..3215226e3 100644 --- a/apps/dokploy/server/api/routers/server.ts +++ b/apps/dokploy/server/api/routers/server.ts @@ -79,7 +79,7 @@ export const serverRouter = createTRPCRouter({ }), getDefaultCommand: protectedProcedure .input(apiFindOneServer) - .query(async ({ input, ctx }) => { + .query(async () => { return defaultCommand(); }), all: protectedProcedure.query(async ({ ctx }) => { @@ -358,7 +358,7 @@ export const serverRouter = createTRPCRouter({ throw error; } }), - publicIp: protectedProcedure.query(async ({ ctx }) => { + publicIp: protectedProcedure.query(async () => { if (IS_CLOUD) { return ""; } diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index ee69da22d..d2455fdb7 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -377,7 +377,10 @@ export const settingsRouter = createTRPCRouter({ .query(async ({ ctx, input }) => { try { if (ctx.user.rol === "member") { - const canAccess = await canAccessToTraefikFiles(ctx.user.id); + const canAccess = await canAccessToTraefikFiles( + ctx.user.id, + ctx.session.activeOrganizationId, + ); if (!canAccess) { throw new TRPCError({ code: "UNAUTHORIZED" }); @@ -395,7 +398,10 @@ export const settingsRouter = createTRPCRouter({ .input(apiModifyTraefikConfig) .mutation(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - const canAccess = await canAccessToTraefikFiles(ctx.user.id); + const canAccess = await canAccessToTraefikFiles( + ctx.user.id, + ctx.session.activeOrganizationId, + ); if (!canAccess) { throw new TRPCError({ code: "UNAUTHORIZED" }); @@ -413,7 +419,10 @@ export const settingsRouter = createTRPCRouter({ .input(apiReadTraefikConfig) .query(async ({ input, ctx }) => { if (ctx.user.rol === "member") { - const canAccess = await canAccessToTraefikFiles(ctx.user.id); + const canAccess = await canAccessToTraefikFiles( + ctx.user.id, + ctx.session.activeOrganizationId, + ); if (!canAccess) { throw new TRPCError({ code: "UNAUTHORIZED" }); @@ -708,7 +717,12 @@ export const settingsRouter = createTRPCRouter({ try { return await checkGPUStatus(input.serverId || ""); } catch (error) { - throw new Error("Failed to check GPU status"); + const message = + error instanceof Error ? error.message : "Failed to check GPU status"; + throw new TRPCError({ + code: "BAD_REQUEST", + message, + }); } }), updateTraefikPorts: adminProcedure diff --git a/apps/dokploy/server/api/routers/ssh-key.ts b/apps/dokploy/server/api/routers/ssh-key.ts index d55a23794..fe321de4f 100644 --- a/apps/dokploy/server/api/routers/ssh-key.ts +++ b/apps/dokploy/server/api/routers/ssh-key.ts @@ -9,7 +9,6 @@ import { sshKeys, } from "@/server/db/schema"; import { - IS_CLOUD, createSshKey, findSSHKeyById, generateSSHKey, diff --git a/apps/dokploy/server/api/routers/stripe.ts b/apps/dokploy/server/api/routers/stripe.ts index 540820f25..0e0e07a47 100644 --- a/apps/dokploy/server/api/routers/stripe.ts +++ b/apps/dokploy/server/api/routers/stripe.ts @@ -87,36 +87,34 @@ export const stripeRouter = createTRPCRouter({ return { sessionId: session.id }; }), - createCustomerPortalSession: adminProcedure.mutation( - async ({ ctx, input }) => { - const user = await findUserById(ctx.user.ownerId); + createCustomerPortalSession: adminProcedure.mutation(async ({ ctx }) => { + const user = await findUserById(ctx.user.ownerId); - if (!user.stripeCustomerId) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Stripe Customer ID not found", - }); - } - const stripeCustomerId = user.stripeCustomerId; + if (!user.stripeCustomerId) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Stripe Customer ID not found", + }); + } + const stripeCustomerId = user.stripeCustomerId; - const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { - apiVersion: "2024-09-30.acacia", + const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { + apiVersion: "2024-09-30.acacia", + }); + + try { + const session = await stripe.billingPortal.sessions.create({ + customer: stripeCustomerId, + return_url: `${WEBSITE_URL}/dashboard/settings/billing`, }); - try { - const session = await stripe.billingPortal.sessions.create({ - customer: stripeCustomerId, - return_url: `${WEBSITE_URL}/dashboard/settings/billing`, - }); - - return { url: session.url }; - } catch (error) { - return { - url: "", - }; - } - }, - ), + return { url: session.url }; + } catch (_) { + return { + url: "", + }; + } + }), canCreateMoreServers: adminProcedure.query(async ({ ctx }) => { const user = await findUserById(ctx.user.ownerId); diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 5c4eb56d5..43cffd9e1 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -1,17 +1,13 @@ -import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema"; import { IS_CLOUD, findOrganizationById, - findUserByAuthId, findUserById, getUserByToken, removeUserById, updateUser, - verify2FA, } from "@dokploy/server"; import { db } from "@dokploy/server/db"; import { - account, apiAssignPermissions, apiFindOneToken, apiUpdateUser, @@ -19,7 +15,7 @@ import { member, } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; -import { and, asc, desc, eq, gt } from "drizzle-orm"; +import { and, asc, eq, gt } from "drizzle-orm"; import { z } from "zod"; import { adminProcedure, @@ -93,7 +89,7 @@ export const userRouter = createTRPCRouter({ userId: z.string(), }), ) - .mutation(async ({ input, ctx }) => { + .mutation(async ({ input }) => { if (IS_CLOUD) { return true; } @@ -103,8 +99,6 @@ export const userRouter = createTRPCRouter({ .input(apiAssignPermissions) .mutation(async ({ input, ctx }) => { try { - const user = await findUserById(input.id); - const organization = await findOrganizationById( ctx.session?.activeOrganizationId || "", ); diff --git a/apps/dokploy/server/db/seed.ts b/apps/dokploy/server/db/seed.ts index b79350797..3216a44b4 100644 --- a/apps/dokploy/server/db/seed.ts +++ b/apps/dokploy/server/db/seed.ts @@ -1,7 +1,6 @@ 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!; diff --git a/apps/dokploy/server/utils/backup.ts b/apps/dokploy/server/utils/backup.ts index 2f1419719..4fc9db931 100644 --- a/apps/dokploy/server/utils/backup.ts +++ b/apps/dokploy/server/utils/backup.ts @@ -2,7 +2,6 @@ import { type BackupScheduleList, IS_CLOUD, removeScheduleBackup, - scheduleBackup, } from "@dokploy/server/index"; type QueueJob = diff --git a/apps/dokploy/templates/excalidraw/index.ts b/apps/dokploy/templates/excalidraw/index.ts index 13a43c440..7f73f395f 100644 --- a/apps/dokploy/templates/excalidraw/index.ts +++ b/apps/dokploy/templates/excalidraw/index.ts @@ -2,7 +2,6 @@ import { type DomainSchema, type Schema, type Template, - generateHash, generateRandomDomain, } from "../utils"; diff --git a/apps/dokploy/templates/ghost/index.ts b/apps/dokploy/templates/ghost/index.ts index 1a88c3629..052b7c6bb 100644 --- a/apps/dokploy/templates/ghost/index.ts +++ b/apps/dokploy/templates/ghost/index.ts @@ -2,7 +2,6 @@ import { type DomainSchema, type Schema, type Template, - generateHash, generateRandomDomain, } from "../utils"; diff --git a/apps/dokploy/templates/penpot/index.ts b/apps/dokploy/templates/penpot/index.ts index f657c698f..a3e90e8ae 100644 --- a/apps/dokploy/templates/penpot/index.ts +++ b/apps/dokploy/templates/penpot/index.ts @@ -2,8 +2,6 @@ import { type DomainSchema, type Schema, type Template, - generateBase64, - generatePassword, generateRandomDomain, } from "../utils"; diff --git a/apps/dokploy/templates/photoprism/index.ts b/apps/dokploy/templates/photoprism/index.ts index d20ac29c8..4a103a624 100644 --- a/apps/dokploy/templates/photoprism/index.ts +++ b/apps/dokploy/templates/photoprism/index.ts @@ -2,7 +2,6 @@ import { type DomainSchema, type Schema, type Template, - generateHash, generatePassword, generateRandomDomain, } from "../utils"; diff --git a/apps/dokploy/templates/triggerdotdev/index.ts b/apps/dokploy/templates/triggerdotdev/index.ts index 7b894acba..c11c708b5 100644 --- a/apps/dokploy/templates/triggerdotdev/index.ts +++ b/apps/dokploy/templates/triggerdotdev/index.ts @@ -1,4 +1,3 @@ -import { Secrets } from "@/components/ui/secrets"; import { type DomainSchema, type Schema, diff --git a/apps/dokploy/templates/unsend/index.ts b/apps/dokploy/templates/unsend/index.ts index 1c4c9c715..dcc80f66e 100644 --- a/apps/dokploy/templates/unsend/index.ts +++ b/apps/dokploy/templates/unsend/index.ts @@ -3,7 +3,6 @@ import { type Schema, type Template, generateBase64, - generateHash, generateRandomDomain, } from "../utils"; diff --git a/biome.json b/biome.json index f5a6c2328..cf677ec40 100644 --- a/biome.json +++ b/biome.json @@ -24,7 +24,10 @@ }, "correctness": { "useExhaustiveDependencies": "off", - "noUnsafeOptionalChaining": "off" + "noUnsafeOptionalChaining": "off", + "noUnusedImports": "error", + "noUnusedFunctionParameters": "error", + "noUnusedVariables": "error" }, "style": { "noNonNullAssertion": "off" diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index de0f4bbb4..a7be9b051 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,10 +1,4 @@ -import { - pgTable, - text, - integer, - timestamp, - boolean, -} from "drizzle-orm/pg-core"; +import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; export const users_temp = pgTable("users_temp", { id: text("id").primaryKey(), diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 67a247414..2f3761fec 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -1,4 +1,4 @@ -import { relations, sql } from "drizzle-orm"; +import { relations } from "drizzle-orm"; import { boolean, integer, diff --git a/packages/server/src/emails/emails/build-failed.tsx b/packages/server/src/emails/emails/build-failed.tsx index b3d999192..79e7b718d 100644 --- a/packages/server/src/emails/emails/build-failed.tsx +++ b/packages/server/src/emails/emails/build-failed.tsx @@ -12,7 +12,6 @@ import { Tailwind, Text, } from "@react-email/components"; -import * as React from "react"; export type TemplateProps = { projectName: string; diff --git a/packages/server/src/emails/emails/build-success.tsx b/packages/server/src/emails/emails/build-success.tsx index eadf7c44b..d9e500ab9 100644 --- a/packages/server/src/emails/emails/build-success.tsx +++ b/packages/server/src/emails/emails/build-success.tsx @@ -12,7 +12,6 @@ import { Tailwind, Text, } from "@react-email/components"; -import * as React from "react"; export type TemplateProps = { projectName: string; diff --git a/packages/server/src/emails/emails/database-backup.tsx b/packages/server/src/emails/emails/database-backup.tsx index 2bdf944c3..754d4d982 100644 --- a/packages/server/src/emails/emails/database-backup.tsx +++ b/packages/server/src/emails/emails/database-backup.tsx @@ -10,7 +10,6 @@ import { Tailwind, Text, } from "@react-email/components"; -import * as React from "react"; export type TemplateProps = { projectName: string; diff --git a/packages/server/src/emails/emails/docker-cleanup.tsx b/packages/server/src/emails/emails/docker-cleanup.tsx index 05d93ed75..985406ae0 100644 --- a/packages/server/src/emails/emails/docker-cleanup.tsx +++ b/packages/server/src/emails/emails/docker-cleanup.tsx @@ -1,6 +1,5 @@ import { Body, - Button, Container, Head, Heading, @@ -11,7 +10,6 @@ import { Tailwind, Text, } from "@react-email/components"; -import * as React from "react"; export type TemplateProps = { message: string; diff --git a/packages/server/src/emails/emails/dokploy-restart.tsx b/packages/server/src/emails/emails/dokploy-restart.tsx index 1ad3d6004..db4edd69c 100644 --- a/packages/server/src/emails/emails/dokploy-restart.tsx +++ b/packages/server/src/emails/emails/dokploy-restart.tsx @@ -10,7 +10,6 @@ import { Tailwind, Text, } from "@react-email/components"; -import * as React from "react"; export type TemplateProps = { date: string; diff --git a/packages/server/src/emails/emails/notion-magic-link.tsx b/packages/server/src/emails/emails/notion-magic-link.tsx index b2286c340..f4071ce00 100644 --- a/packages/server/src/emails/emails/notion-magic-link.tsx +++ b/packages/server/src/emails/emails/notion-magic-link.tsx @@ -9,7 +9,6 @@ import { Preview, Text, } from "@react-email/components"; -import * as React from "react"; interface NotionMagicLinkEmailProps { loginCode?: string; diff --git a/packages/server/src/emails/emails/plaid-verify-identity.tsx b/packages/server/src/emails/emails/plaid-verify-identity.tsx index 650ab4866..88cf893d7 100644 --- a/packages/server/src/emails/emails/plaid-verify-identity.tsx +++ b/packages/server/src/emails/emails/plaid-verify-identity.tsx @@ -9,7 +9,6 @@ import { Section, Text, } from "@react-email/components"; -import * as React from "react"; interface PlaidVerifyIdentityEmailProps { validationCode?: string; diff --git a/packages/server/src/emails/emails/stripe-welcome.tsx b/packages/server/src/emails/emails/stripe-welcome.tsx index 9377853be..dbf02ea0e 100644 --- a/packages/server/src/emails/emails/stripe-welcome.tsx +++ b/packages/server/src/emails/emails/stripe-welcome.tsx @@ -11,7 +11,6 @@ import { Section, Text, } from "@react-email/components"; -import * as React from "react"; const baseUrl = process.env.VERCEL_URL!; diff --git a/packages/server/src/emails/emails/vercel-invite-user.tsx b/packages/server/src/emails/emails/vercel-invite-user.tsx index 53b31987c..79f50cd71 100644 --- a/packages/server/src/emails/emails/vercel-invite-user.tsx +++ b/packages/server/src/emails/emails/vercel-invite-user.tsx @@ -15,7 +15,6 @@ import { Tailwind, Text, } from "@react-email/components"; -import * as React from "react"; interface VercelInviteUserEmailProps { username?: string; diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 554b4c124..f74b8d9d0 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1,5 +1,4 @@ export * from "./auth/random-password"; -// export * from "./db"; export * from "./services/admin"; export * from "./services/user"; export * from "./services/project"; @@ -28,7 +27,6 @@ export * from "./services/ssh-key"; export * from "./services/git-provider"; export * from "./services/bitbucket"; export * from "./services/github"; -export * from "./services/auth"; export * from "./services/gitlab"; export * from "./services/server"; export * from "./services/application"; diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 368b43c99..a8d75637b 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -10,7 +10,6 @@ import { import { and, desc, eq } from "drizzle-orm"; import { db } from "../db"; import * as schema from "../db/schema"; -import { ac } from "./permissions"; export const auth = betterAuth({ database: drizzleAdapter(db, { diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index 07c537dea..1e2b569f4 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -1,7 +1,5 @@ -import { randomBytes } from "node:crypto"; import { db } from "@dokploy/server/db"; import { - account, type apiCreateUserInvitation, invitation, member, @@ -9,7 +7,6 @@ import { users_temp, } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; -import * as bcrypt from "bcrypt"; import { eq } from "drizzle-orm"; import { IS_CLOUD } from "../constants"; diff --git a/packages/server/src/services/application.ts b/packages/server/src/services/application.ts index ddc3a4504..425a6adbc 100644 --- a/packages/server/src/services/application.ts +++ b/packages/server/src/services/application.ts @@ -4,7 +4,6 @@ import { type apiCreateApplication, applications, buildAppName, - cleanAppName, } from "@dokploy/server/db/schema"; import { getAdvancedStats } from "@dokploy/server/monitoring/utils"; import { @@ -28,7 +27,6 @@ import { getCustomGitCloneCommand, } from "@dokploy/server/utils/providers/git"; import { - authGithub, cloneGithubRepository, getGithubCloneCommand, } from "@dokploy/server/utils/providers/github"; @@ -40,7 +38,7 @@ import { createTraefikConfig } from "@dokploy/server/utils/traefik/application"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { encodeBase64 } from "../utils/docker/utils"; -import { findAdminById, findUserById, getDokployUrl } from "./admin"; +import { getDokployUrl } from "./admin"; import { createDeployment, createDeploymentPreview, @@ -58,7 +56,6 @@ import { updatePreviewDeployment, } from "./preview-deployment"; import { validUniqueServerAppName } from "./project"; -import { cleanupFullDocker } from "./settings"; export type Application = typeof applications.$inferSelect; export const createApplication = async ( diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts deleted file mode 100644 index 5a7484eb9..000000000 --- a/packages/server/src/services/auth.ts +++ /dev/null @@ -1,212 +0,0 @@ -import { randomBytes } from "node:crypto"; -import { createOTP } from "@better-auth/utils/otp"; -import { db } from "@dokploy/server/db"; -import { users_temp } from "@dokploy/server/db/schema"; -import { getPublicIpWithFallback } from "@dokploy/server/wss/utils"; -import { TRPCError } from "@trpc/server"; -import * as bcrypt from "bcrypt"; -import { eq } from "drizzle-orm"; -import encode from "hi-base32"; -import { TOTP } from "otpauth"; -import QRCode from "qrcode"; -import { IS_CLOUD } from "../constants"; -import { findUserById } from "./admin"; -import type { User } from "./user"; - -export const findAuthById = async (authId: string) => { - const result = await db.query.users_temp.findFirst({ - where: eq(users_temp.id, authId), - columns: { - createdAt: false, - updatedAt: false, - }, - }); - if (!result) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Auth not found", - }); - } - return result; -}; - -const generateBase32Secret = () => { - // Generamos 32 bytes (256 bits) para asegurar que tengamos suficiente longitud - const buffer = randomBytes(32); - // Convertimos directamente a hex para Better Auth - const hex = buffer.toString("hex"); - // También necesitamos la versión base32 para el QR code - const base32 = encode.encode(buffer).replace(/=/g, "").substring(0, 32); - return { - hex, - base32, - }; -}; - -export const generate2FASecret = () => { - const secret = "46JMUCG4NJ3CIU6LQAIVFWUW"; - - const totp = new TOTP({ - issuer: "Dokploy", - label: "siumauricio@hotmail.com", - algorithm: "SHA1", - digits: 6, - secret: secret, - }); - - // Convertir los bytes del secreto a hex - const secretBytes = totp.secret.bytes; - const hexSecret = Buffer.from(secretBytes).toString("hex"); - - console.log("Secret bytes:", secretBytes); - console.log("Hex secret:", hexSecret); - - return { - secret, - hexSecret, - totp, - }; -}; - -export const verify2FA = async (auth: User, secret: string, pin: string) => { - const totp = new TOTP({ - issuer: "Dokploy", - label: `${auth?.email}`, - algorithm: "SHA1", - digits: 6, - secret: secret, - period: 30, - }); - - const delta = totp.validate({ token: pin }); - - if (delta === null) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Invalid 2FA code", - }); - } - return auth; -}; - -const convertBase32ToHex = (base32Secret: string) => { - try { - // Asegurarnos de que la longitud sea múltiplo de 8 agregando padding - let paddedSecret = base32Secret; - while (paddedSecret.length % 8 !== 0) { - paddedSecret += "="; - } - - const bytes = encode.decode.asBytes(paddedSecret.toUpperCase()); - let hex = Buffer.from(bytes).toString("hex"); - - // Asegurarnos de que el hex tenga al menos 32 caracteres (16 bytes) - while (hex.length < 32) { - hex += "0"; - } - - return hex; - } catch (error) { - console.error("Error converting base32 to hex:", error); - return base32Secret; - } -}; - -// Para probar -// const testSecret = "46JMUCG4NJ3CIU6LQAIVFWUW"; -// console.log("Original:", testSecret); -// console.log("Converted:", convertBase32ToHex(testSecret)); -// console.log( -// "Length in bytes:", -// Buffer.from(convertBase32ToHex(testSecret), "hex").length, -// ); -// console.log(generate2FASecret().secret.secret); - -// // Para probar -// const testResult = generate2FASecret(); -// console.log("\nResultados:"); -// console.log("Original base32:", testResult.secret); -// console.log("Hex convertido:", testResult.hexSecret); -// console.log( -// "Longitud en bytes:", -// Buffer.from(testResult.hexSecret, "hex").length, -// ); -export const symmetricDecrypt = async ({ key, data }) => { - const keyAsBytes = await createHash("SHA-256").digest(key); - const dataAsBytes = hexToBytes(data); - const chacha = managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes)); - return new TextDecoder().decode(chacha.decrypt(dataAsBytes)); -}; -// export const migrateExistingSecret = async ( -// existingBase32Secret: string, -// encryptionKey: string, -// ) => { -// try { -// // 1. Primero asegurarnos que el secreto base32 tenga el padding correcto -// let paddedSecret = existingBase32Secret; -// while (paddedSecret.length % 8 !== 0) { -// paddedSecret += "="; -// } - -// // 2. Decodificar el base32 a bytes usando hi-base32 -// const bytes = encode.decode.asBytes(paddedSecret.toUpperCase()); - -// // 3. Convertir los bytes a hex -// const hexSecret = Buffer.from(bytes).toString("hex"); - -// // 4. Encriptar el secreto hex usando Better Auth -// const encryptedSecret = await symmetricEncrypt({ -// key: encryptionKey, -// data: hexSecret, -// }); - -// // 5. Crear TOTP con el secreto original para validación -// const originalTotp = new TOTP({ -// issuer: "Dokploy", -// label: "migration-test", -// algorithm: "SHA1", -// digits: 6, -// secret: existingBase32Secret, -// }); - -// // 6. Generar un código de prueba con el secreto original -// const testCode = originalTotp.generate(); - -// // 7. Validar que el código funcione con el secreto original -// const isValid = originalTotp.validate({ token: testCode }) !== null; - -// return { -// originalSecret: existingBase32Secret, -// hexSecret, -// encryptedSecret, // Este es el valor que debes guardar en la base de datos -// isValid, -// testCode, -// secretLength: hexSecret.length, -// }; -// } catch (error: unknown) { -// const errorMessage = -// error instanceof Error ? error.message : "Unknown error"; -// console.error("Error durante la migración:", errorMessage); -// throw new Error(`Error al migrar el secreto: ${errorMessage}`); -// } -// }; - -// // // Ejemplo de uso con el secreto de prueba -// // const testMigration = await migrateExistingSecret( -// // "46JMUCG4NJ3CIU6LQAIVFWUW", -// // process.env.BETTER_AUTH_SECRET || "your-encryption-key", -// // ); -// // console.log("\nPrueba de migración:"); -// // console.log("Secreto original (base32):", testMigration.originalSecret); -// // console.log("Secreto convertido (hex):", testMigration.hexSecret); -// // console.log("Secreto encriptado:", testMigration.encryptedSecret); -// // console.log("Longitud del secreto hex:", testMigration.secretLength); -// // console.log("¿Conversión válida?:", testMigration.isValid); -// // console.log("Código de prueba:", testMigration.testCode); -// const secret = "46JMUCG4NJ3CIU6LQAIVFWUW"; -// const isValid = createOTP(secret, { -// digits: 6, -// period: 30, -// }).verify("123456"); - -// console.log(isValid.then((isValid) => console.log(isValid))); diff --git a/packages/server/src/services/backup.ts b/packages/server/src/services/backup.ts index ef3d04467..327057869 100644 --- a/packages/server/src/services/backup.ts +++ b/packages/server/src/services/backup.ts @@ -2,8 +2,6 @@ import { db } from "@dokploy/server/db"; import { type apiCreateBackup, backups } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; -import { IS_CLOUD } from "../constants"; -import { removeScheduleBackup, scheduleBackup } from "../utils/backups/utils"; export type Backup = typeof backups.$inferSelect; diff --git a/packages/server/src/services/compose.ts b/packages/server/src/services/compose.ts index 70bc411c1..a3ebc26ce 100644 --- a/packages/server/src/services/compose.ts +++ b/packages/server/src/services/compose.ts @@ -44,10 +44,9 @@ import { import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { encodeBase64 } from "../utils/docker/utils"; -import { findAdminById, findUserById, getDokployUrl } from "./admin"; +import { getDokployUrl } from "./admin"; import { createDeploymentCompose, updateDeploymentStatus } from "./deployment"; import { validUniqueServerAppName } from "./project"; -import { cleanupFullDocker } from "./settings"; export type Compose = typeof compose.$inferSelect; diff --git a/packages/server/src/services/deployment.ts b/packages/server/src/services/deployment.ts index 096bdf19c..86d6c88e8 100644 --- a/packages/server/src/services/deployment.ts +++ b/packages/server/src/services/deployment.ts @@ -12,7 +12,7 @@ import { import { removeDirectoryIfExistsContent } from "@dokploy/server/utils/filesystem/directory"; import { TRPCError } from "@trpc/server"; import { format } from "date-fns"; -import { and, desc, eq, isNull } from "drizzle-orm"; +import { desc, eq } from "drizzle-orm"; import { type Application, findApplicationById, @@ -278,9 +278,11 @@ export const removeDeployment = async (deploymentId: string) => { .returning(); return deployment[0]; } catch (error) { + const message = + error instanceof Error ? error.message : "Error creating the deployment"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error deleting this deployment", + message, }); } }; @@ -535,9 +537,11 @@ export const createServerDeployment = async ( } return deploymentCreate[0]; } catch (error) { + const message = + error instanceof Error ? error.message : "Error creating the deployment"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error creating the deployment", + message, }); } }; diff --git a/packages/server/src/services/domain.ts b/packages/server/src/services/domain.ts index 99dcde559..fe068fc22 100644 --- a/packages/server/src/services/domain.ts +++ b/packages/server/src/services/domain.ts @@ -4,7 +4,7 @@ import { manageDomain } from "@dokploy/server/utils/traefik/domain"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { type apiCreateDomain, domains } from "../db/schema"; -import { findAdmin, findAdminById, findUserById } from "./admin"; +import { findUserById } from "./admin"; import { findApplicationById } from "./application"; import { findServerById } from "./server"; diff --git a/packages/server/src/services/gitlab.ts b/packages/server/src/services/gitlab.ts index 0822aaaba..fdca2775e 100644 --- a/packages/server/src/services/gitlab.ts +++ b/packages/server/src/services/gitlab.ts @@ -1,9 +1,7 @@ import { db } from "@dokploy/server/db"; import { type apiCreateGitlab, - type bitbucket, gitProvider, - type github, gitlab, } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; diff --git a/packages/server/src/services/mariadb.ts b/packages/server/src/services/mariadb.ts index 8257b5875..00be29d6a 100644 --- a/packages/server/src/services/mariadb.ts +++ b/packages/server/src/services/mariadb.ts @@ -4,7 +4,7 @@ import { backups, mariadb, } from "@dokploy/server/db/schema"; -import { buildAppName, cleanAppName } from "@dokploy/server/db/schema"; +import { buildAppName } from "@dokploy/server/db/schema"; import { generatePassword } from "@dokploy/server/templates/utils"; import { buildMariadb } from "@dokploy/server/utils/databases/mariadb"; import { pullImage } from "@dokploy/server/utils/docker/utils"; diff --git a/packages/server/src/services/mongo.ts b/packages/server/src/services/mongo.ts index 031a60131..0ac4cc632 100644 --- a/packages/server/src/services/mongo.ts +++ b/packages/server/src/services/mongo.ts @@ -1,6 +1,6 @@ import { db } from "@dokploy/server/db"; import { type apiCreateMongo, backups, mongo } from "@dokploy/server/db/schema"; -import { buildAppName, cleanAppName } from "@dokploy/server/db/schema"; +import { buildAppName } from "@dokploy/server/db/schema"; import { generatePassword } from "@dokploy/server/templates/utils"; import { buildMongo } from "@dokploy/server/utils/databases/mongo"; import { pullImage } from "@dokploy/server/utils/docker/utils"; diff --git a/packages/server/src/services/mount.ts b/packages/server/src/services/mount.ts index 38e82d1a1..55557ea0e 100644 --- a/packages/server/src/services/mount.ts +++ b/packages/server/src/services/mount.ts @@ -123,8 +123,8 @@ export const updateMount = async ( mountId: string, mountData: Partial, ) => { - return await db.transaction(async (transaction) => { - const mount = await db + return await db.transaction(async (tx) => { + const mount = await tx .update(mounts) .set({ ...mountData, diff --git a/packages/server/src/services/postgres.ts b/packages/server/src/services/postgres.ts index 682d3f78d..75b81c506 100644 --- a/packages/server/src/services/postgres.ts +++ b/packages/server/src/services/postgres.ts @@ -4,7 +4,7 @@ import { backups, postgres, } from "@dokploy/server/db/schema"; -import { buildAppName, cleanAppName } from "@dokploy/server/db/schema"; +import { buildAppName } from "@dokploy/server/db/schema"; import { generatePassword } from "@dokploy/server/templates/utils"; import { buildPostgres } from "@dokploy/server/utils/databases/postgres"; import { pullImage } from "@dokploy/server/utils/docker/utils"; diff --git a/packages/server/src/services/preview-deployment.ts b/packages/server/src/services/preview-deployment.ts index d5a2149a7..775621773 100644 --- a/packages/server/src/services/preview-deployment.ts +++ b/packages/server/src/services/preview-deployment.ts @@ -7,19 +7,15 @@ import { } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { and, desc, eq } from "drizzle-orm"; -import { slugify } from "../setup/server-setup"; -import { generatePassword, generateRandomDomain } from "../templates/utils"; +import { generatePassword } from "../templates/utils"; import { removeService } from "../utils/docker/utils"; import { removeDirectoryCode } from "../utils/filesystem/directory"; import { authGithub } from "../utils/providers/github"; import { removeTraefikConfig } from "../utils/traefik/application"; import { manageDomain } from "../utils/traefik/domain"; -import { findAdminById, findUserById } from "./admin"; +import { findUserById } from "./admin"; import { findApplicationById } from "./application"; -import { - removeDeployments, - removeDeploymentsByPreviewDeploymentId, -} from "./deployment"; +import { removeDeploymentsByPreviewDeploymentId } from "./deployment"; import { createDomain } from "./domain"; import { type Github, getIssueComment } from "./github"; @@ -111,9 +107,13 @@ export const removePreviewDeployment = async (previewDeploymentId: string) => { } return deployment[0]; } catch (error) { + const message = + error instanceof Error + ? error.message + : "Error deleting this preview deployment"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error deleting this preview deployment", + message, }); } }; diff --git a/packages/server/src/services/redirect.ts b/packages/server/src/services/redirect.ts index f16dbe428..1896105fe 100644 --- a/packages/server/src/services/redirect.ts +++ b/packages/server/src/services/redirect.ts @@ -6,7 +6,7 @@ import { updateRedirectMiddleware, } from "@dokploy/server/utils/traefik/redirect"; import { TRPCError } from "@trpc/server"; -import { desc, eq } from "drizzle-orm"; +import { eq } from "drizzle-orm"; import type { z } from "zod"; import { findApplicationById } from "./application"; export type Redirect = typeof redirects.$inferSelect; @@ -114,9 +114,11 @@ export const updateRedirectById = async ( return redirect; } catch (error) { + const message = + error instanceof Error ? error.message : "Error updating this redirect"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error updating this redirect", + message, }); } }; diff --git a/packages/server/src/services/redis.ts b/packages/server/src/services/redis.ts index e0dbbe025..9f4a1f9e6 100644 --- a/packages/server/src/services/redis.ts +++ b/packages/server/src/services/redis.ts @@ -1,6 +1,6 @@ import { db } from "@dokploy/server/db"; import { type apiCreateRedis, redis } from "@dokploy/server/db/schema"; -import { buildAppName, cleanAppName } from "@dokploy/server/db/schema"; +import { buildAppName } from "@dokploy/server/db/schema"; import { generatePassword } from "@dokploy/server/templates/utils"; import { buildRedis } from "@dokploy/server/utils/databases/redis"; import { pullImage } from "@dokploy/server/utils/docker/utils"; diff --git a/packages/server/src/services/registry.ts b/packages/server/src/services/registry.ts index 853f4cf7b..6468cd970 100644 --- a/packages/server/src/services/registry.ts +++ b/packages/server/src/services/registry.ts @@ -112,9 +112,11 @@ export const updateRegistry = async ( return response; } catch (error) { + const message = + error instanceof Error ? error.message : "Error updating this registry"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error updating this registry", + message, }); } }; diff --git a/packages/server/src/services/security.ts b/packages/server/src/services/security.ts index 5efca19fd..d6947b887 100644 --- a/packages/server/src/services/security.ts +++ b/packages/server/src/services/security.ts @@ -76,9 +76,11 @@ export const deleteSecurityById = async (securityId: string) => { await removeSecurityMiddleware(application, result); return result; } catch (error) { + const message = + error instanceof Error ? error.message : "Error removing this security"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error removing this security", + message, }); } }; @@ -98,9 +100,11 @@ export const updateSecurityById = async ( return response[0]; } catch (error) { + const message = + error instanceof Error ? error.message : "Error updating this security"; throw new TRPCError({ code: "BAD_REQUEST", - message: "Error updating this security", + message, }); } }; diff --git a/packages/server/src/services/server.ts b/packages/server/src/services/server.ts index afe851ef5..a4d5c5d85 100644 --- a/packages/server/src/services/server.ts +++ b/packages/server/src/services/server.ts @@ -5,7 +5,7 @@ import { server, } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; -import { desc, eq } from "drizzle-orm"; +import { eq } from "drizzle-orm"; export type Server = typeof server.$inferSelect; diff --git a/packages/server/src/services/settings.ts b/packages/server/src/services/settings.ts index 01ac43a14..75613be02 100644 --- a/packages/server/src/services/settings.ts +++ b/packages/server/src/services/settings.ts @@ -169,7 +169,6 @@ echo "$json_output" const result = JSON.parse(stdout); return result; } - const items = readdirSync(dirPath, { withFileTypes: true }); const stack = [dirPath]; const result: TreeDataItem[] = []; diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index 9e924e9f1..f36d8ef65 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -1,38 +1,10 @@ import { db } from "@dokploy/server/db"; -import { type users_temp, member } from "@dokploy/server/db/schema"; +import { member, type users_temp } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { and, eq } from "drizzle-orm"; -import { findUserById } from "./admin"; export type User = typeof users_temp.$inferSelect; -// export const findUserById = async (userId: string) => { -// // const userR = await db.query.user.findFirst({ -// // where: eq(user.userId, userId), -// // }); -// // if (!userR) { -// // throw new TRPCError({ -// // code: "NOT_FOUND", -// // message: "User not found", -// // }); -// // } -// // return user; -// }; - -export const findUserByAuthId = async (authId: string) => { - // const userR = await db.query.user.findFirst({ - // where: eq(user.id, authId), - // with: {}, - // }); - // if (!userR) { - // throw new TRPCError({ - // code: "NOT_FOUND", - // message: "User not found", - // }); - // } - // return userR; -}; - export const addNewProject = async ( userId: string, projectId: string, diff --git a/packages/server/src/setup/monitoring-setup.ts b/packages/server/src/setup/monitoring-setup.ts index ea6c768ba..afadb6c10 100644 --- a/packages/server/src/setup/monitoring-setup.ts +++ b/packages/server/src/setup/monitoring-setup.ts @@ -1,7 +1,7 @@ import { findServerById } from "@dokploy/server/services/server"; import type { ContainerCreateOptions } from "dockerode"; import { IS_CLOUD } from "../constants"; -import { findAdminById, findUserById } from "../services/admin"; +import { findUserById } from "../services/admin"; import { getDokployImageTag } from "../services/settings"; import { pullImage, pullRemoteImage } from "../utils/docker/utils"; import { execAsync, execAsyncRemote } from "../utils/process/execAsync"; diff --git a/packages/server/src/utils/access-log/handler.ts b/packages/server/src/utils/access-log/handler.ts index 30b18ea42..5cff7f837 100644 --- a/packages/server/src/utils/access-log/handler.ts +++ b/packages/server/src/utils/access-log/handler.ts @@ -1,6 +1,5 @@ import { IS_CLOUD, paths } from "@dokploy/server/constants"; import { type RotatingFileStream, createStream } from "rotating-file-stream"; -import { db } from "../../db"; import { execAsync } from "../process/execAsync"; class LogRotationManager { diff --git a/packages/server/src/utils/backups/mysql.ts b/packages/server/src/utils/backups/mysql.ts index 009a02cf2..1272fc3ed 100644 --- a/packages/server/src/utils/backups/mysql.ts +++ b/packages/server/src/utils/backups/mysql.ts @@ -1,4 +1,3 @@ -import { unlink } from "node:fs/promises"; import path from "node:path"; import type { BackupSchedule } from "@dokploy/server/services/backup"; import type { MySql } from "@dokploy/server/services/mysql"; diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts index 838cf74e3..cbf951c73 100644 --- a/packages/server/src/utils/builders/compose.ts +++ b/packages/server/src/utils/builders/compose.ts @@ -2,7 +2,6 @@ import { createWriteStream, existsSync, mkdirSync, - readFileSync, writeFileSync, } from "node:fs"; import { dirname, join } from "node:path"; diff --git a/packages/server/src/utils/notifications/database-backup.ts b/packages/server/src/utils/notifications/database-backup.ts index 08cff4b54..37a4a1ff2 100644 --- a/packages/server/src/utils/notifications/database-backup.ts +++ b/packages/server/src/utils/notifications/database-backup.ts @@ -1,4 +1,3 @@ -import { error } from "node:console"; import { db } from "@dokploy/server/db"; import { notifications } from "@dokploy/server/db/schema"; import DatabaseBackupEmail from "@dokploy/server/emails/emails/database-backup"; diff --git a/packages/server/src/utils/traefik/middleware.ts b/packages/server/src/utils/traefik/middleware.ts index 60345f66c..934d637e1 100644 --- a/packages/server/src/utils/traefik/middleware.ts +++ b/packages/server/src/utils/traefik/middleware.ts @@ -95,7 +95,7 @@ export const loadRemoteMiddlewares = async (serverId: string) => { } const config = load(stdout) as FileConfig; return config; - } catch (error) { + } catch (_) { throw new Error(`File not found: ${configPath}`); } }; From 8ab6d6b2828d27522a9a3a1243306973b1bd0ac7 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 20:35:21 -0600 Subject: [PATCH 57/89] chore: clean up unused variables and improve error handling across codebase This commit focuses on removing unused variables, adding placeholder error handling, and generally tidying up various files across the Dokploy application. Changes include: - Removing unused imports and variables - Adding placeholder error handling in catch blocks - Cleaning up commented-out code - Removing deprecated utility files - Improving type safety and code consistency --- .../cluster/modify-swarm-settings.tsx | 2 +- .../advanced/volumes/update-volume.tsx | 2 +- .../generic/save-bitbucket-provider.tsx | 1 - .../dashboard/application/general/show.tsx | 3 +- .../show-preview-settings.tsx | 2 +- .../dashboard/compose/delete-service.tsx | 2 +- .../compose/domains/show-domains.tsx | 2 +- .../compose/general/compose-file-editor.tsx | 5 +- .../save-bitbucket-provider-compose.tsx | 1 - .../compose/general/isolated-deployment.tsx | 2 +- .../compose/general/randomize-compose.tsx | 4 +- .../general/show-converted-compose.tsx | 2 +- .../paid/container/container-block-chart.tsx | 8 -- .../organization/handle-organization.tsx | 2 +- .../postgres/advanced/show-custom-command.tsx | 2 +- .../dashboard/project/add-application.tsx | 2 +- .../dashboard/project/add-template.tsx | 4 +- .../show-external-redis-credentials.tsx | 2 +- .../components/dashboard/requests/columns.tsx | 2 +- .../dashboard/requests/requests-table.tsx | 4 +- .../components/dashboard/search-command.tsx | 5 +- .../settings/billing/show-billing.tsx | 8 +- .../settings/cluster/nodes/show-nodes.tsx | 3 +- .../cluster/registry/handle-registry.tsx | 2 +- .../git/bitbucket/add-bitbucket-provider.tsx | 4 +- .../settings/git/show-git-providers.tsx | 2 +- .../notifications/handle-notifications.tsx | 4 +- .../notifications/show-notifications.tsx | 2 +- .../settings/profile/disable-2fa.tsx | 2 +- .../dashboard/settings/profile/enable-2fa.tsx | 12 --- .../settings/profile/profile-form.tsx | 4 +- .../servers/actions/show-storage-actions.tsx | 2 +- .../servers/actions/toggle-docker-cleanup.tsx | 2 +- .../settings/servers/edit-script.tsx | 2 +- .../settings/servers/gpu-support.tsx | 4 +- .../settings/servers/handle-servers.tsx | 2 +- .../settings/servers/security-audit.tsx | 2 +- .../settings/servers/setup-monitoring.tsx | 2 +- .../settings/servers/validate-server.tsx | 2 +- .../servers/welcome-stripe/create-server.tsx | 6 +- .../servers/welcome-stripe/verify.tsx | 9 -- .../settings/users/show-invitations.tsx | 4 +- .../dashboard/settings/users/show-users.tsx | 2 +- .../dashboard/settings/web-server.tsx | 5 +- .../web-server/manage-traefik-ports.tsx | 2 +- .../settings/web-server/update-server-ip.tsx | 2 +- .../dashboard/swarm/applications/columns.tsx | 2 +- .../swarm/applications/data-table.tsx | 2 +- .../swarm/details/show-node-config.tsx | 2 +- apps/dokploy/components/layouts/side.tsx | 25 ++--- .../components/layouts/update-server.tsx | 2 +- apps/dokploy/components/layouts/user-nav.tsx | 2 +- .../components/shared/breadcrumb-sidebar.tsx | 2 +- .../dokploy/components/shared/drawer-logs.tsx | 2 +- apps/dokploy/components/ui/file-tree.tsx | 2 +- apps/dokploy/migrate.ts | 2 +- apps/dokploy/pages/_error.tsx | 2 +- apps/dokploy/pages/api/health.ts | 2 +- .../pages/api/providers/github/setup.ts | 3 +- apps/dokploy/pages/api/stripe/webhook.ts | 46 ++++++--- apps/dokploy/pages/dashboard/docker.tsx | 2 +- apps/dokploy/pages/dashboard/monitoring.tsx | 3 +- .../pages/dashboard/project/[projectId].tsx | 6 +- .../services/application/[applicationId].tsx | 5 +- .../services/compose/[composeId].tsx | 5 +- .../services/mariadb/[mariadbId].tsx | 5 +- .../[projectId]/services/mongo/[mongoId].tsx | 5 +- .../[projectId]/services/mysql/[mysqlId].tsx | 5 +- .../services/postgres/[postgresId].tsx | 5 +- .../[projectId]/services/redis/[redisId].tsx | 5 +- .../dashboard/settings/git-providers.tsx | 2 +- .../pages/dashboard/settings/ssh-keys.tsx | 4 +- apps/dokploy/pages/dashboard/swarm.tsx | 2 +- apps/dokploy/pages/dashboard/traefik.tsx | 2 +- apps/dokploy/pages/index.tsx | 21 ++--- apps/dokploy/pages/invitation.tsx | 15 +-- apps/dokploy/pages/register.tsx | 55 +++++------ apps/dokploy/pages/reset-password.tsx | 2 +- apps/dokploy/pages/send-reset-password.tsx | 8 +- apps/dokploy/server/api/routers/auth.ts | 20 ++-- apps/dokploy/server/api/routers/server.ts | 13 +++ apps/dokploy/server/api/routers/stripe.ts | 6 +- apps/dokploy/server/db/seed.ts | 7 +- apps/dokploy/server/utils/docker.ts | 2 +- .../server/wss/docker-container-terminal.ts | 10 +- apps/dokploy/server/wss/drawer-logs.ts | 2 +- apps/dokploy/server/wss/listen-deployment.ts | 2 +- apps/dokploy/server/wss/terminal.ts | 10 +- apps/dokploy/templates/appsmith/index.ts | 2 +- apps/dokploy/templates/blender/index.ts | 2 +- apps/dokploy/templates/cloudflared/index.ts | 2 +- apps/dokploy/templates/drawio/index.ts | 2 +- apps/dokploy/templates/immich/index.ts | 2 +- apps/dokploy/templates/unifi/index.ts | 2 +- packages/server/src/db/schema/certificate.ts | 21 ++--- packages/server/src/db/schema/git-provider.ts | 2 +- packages/server/src/db/schema/registry.ts | 2 +- packages/server/src/lib/auth.ts | 77 ++++++++------- packages/server/src/lib/crypto.ts | 94 ------------------- packages/server/src/lib/scrypt/index.ts | 1 - packages/server/src/monitoring/utils.ts | 4 +- packages/server/src/services/admin.ts | 10 +- packages/server/src/services/docker.ts | 20 ++-- packages/server/src/services/github.ts | 2 +- packages/server/src/services/mount.ts | 2 +- .../server/src/services/preview-deployment.ts | 2 +- packages/server/src/setup/monitoring-setup.ts | 4 +- packages/server/src/setup/postgres-setup.ts | 2 +- packages/server/src/setup/redis-setup.ts | 2 +- packages/server/src/setup/server-audit.ts | 2 +- packages/server/src/setup/server-validate.ts | 2 +- packages/server/src/setup/setup.ts | 4 +- packages/server/src/setup/traefik-setup.ts | 2 +- packages/server/src/types/with.ts | 2 +- .../server/src/utils/access-log/handler.ts | 2 +- packages/server/src/utils/backups/utils.ts | 2 +- packages/server/src/utils/builders/compose.ts | 3 +- packages/server/src/utils/builders/index.ts | 2 +- .../server/src/utils/builders/nixpacks.ts | 2 +- .../server/src/utils/databases/mariadb.ts | 2 +- packages/server/src/utils/databases/mongo.ts | 2 +- packages/server/src/utils/databases/mysql.ts | 2 +- packages/server/src/utils/databases/redis.ts | 2 +- packages/server/src/utils/docker/domain.ts | 2 +- packages/server/src/utils/docker/utils.ts | 4 +- packages/server/src/utils/gpu-setup.ts | 4 +- .../server/src/utils/process/execAsync.ts | 2 +- .../server/src/utils/providers/bitbucket.ts | 1 - packages/server/src/utils/providers/git.ts | 2 +- packages/server/src/utils/providers/gitlab.ts | 11 +-- .../server/src/utils/traefik/application.ts | 8 +- .../verification/send-verification-email.tsx | 49 ++++++++++ 132 files changed, 375 insertions(+), 471 deletions(-) delete mode 100644 packages/server/src/lib/crypto.ts delete mode 100644 packages/server/src/lib/scrypt/index.ts create mode 100644 packages/server/src/verification/send-verification-email.tsx diff --git a/apps/dokploy/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx b/apps/dokploy/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx index 9b71a042a..95a559f66 100644 --- a/apps/dokploy/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/cluster/modify-swarm-settings.tsx @@ -130,7 +130,7 @@ const createStringToJSONSchema = (schema: z.ZodTypeAny) => { } try { return JSON.parse(str); - } catch (e) { + } catch (_e) { ctx.addIssue({ code: "custom", message: "Invalid JSON format" }); return z.NEVER; } diff --git a/apps/dokploy/components/dashboard/application/advanced/volumes/update-volume.tsx b/apps/dokploy/components/dashboard/application/advanced/volumes/update-volume.tsx index 687d0f608..8da09b58b 100644 --- a/apps/dokploy/components/dashboard/application/advanced/volumes/update-volume.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/volumes/update-volume.tsx @@ -77,7 +77,7 @@ export const UpdateVolume = ({ serviceType, }: Props) => { const [isOpen, setIsOpen] = useState(false); - const utils = api.useUtils(); + const _utils = api.useUtils(); const { data } = api.mounts.one.useQuery( { mountId, diff --git a/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx b/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx index 9b207d636..9af040b79 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx @@ -84,7 +84,6 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => { data: repositories, isLoading: isLoadingRepositories, error, - isError, } = api.bitbucket.getBitbucketRepositories.useQuery( { bitbucketId, diff --git a/apps/dokploy/components/dashboard/application/general/show.tsx b/apps/dokploy/components/dashboard/application/general/show.tsx index 0ea331e94..8989ca198 100644 --- a/apps/dokploy/components/dashboard/application/general/show.tsx +++ b/apps/dokploy/components/dashboard/application/general/show.tsx @@ -27,8 +27,7 @@ export const ShowGeneralApplication = ({ applicationId }: Props) => { const { mutateAsync: stop, isLoading: isStopping } = api.application.stop.useMutation(); - const { mutateAsync: deploy, isLoading: isDeploying } = - api.application.deploy.useMutation(); + const { mutateAsync: deploy } = api.application.deploy.useMutation(); const { mutateAsync: reload, isLoading: isReloading } = api.application.reload.useMutation(); 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 fec61ca60..9d53f31d8 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 @@ -279,7 +279,7 @@ export const ShowPreviewSettings = ({ applicationId }: Props) => { ( + render={() => ( { compose: () => api.compose.one.useQuery({ composeId: id }, { enabled: !!id }), }; - const { data, refetch } = queryMap[type] + const { data } = queryMap[type] ? queryMap[type]() : api.mongo.one.useQuery({ mongoId: id }, { enabled: !!id }); diff --git a/apps/dokploy/components/dashboard/compose/domains/show-domains.tsx b/apps/dokploy/components/dashboard/compose/domains/show-domains.tsx index 7bc451e00..e6468d6fa 100644 --- a/apps/dokploy/components/dashboard/compose/domains/show-domains.tsx +++ b/apps/dokploy/components/dashboard/compose/domains/show-domains.tsx @@ -118,7 +118,7 @@ export const ShowDomainsCompose = ({ composeId }: Props) => { await deleteDomain({ domainId: item.domainId, }) - .then((data) => { + .then((_data) => { refetch(); toast.success("Domain deleted successfully"); }) diff --git a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx index c4ce44e52..725895821 100644 --- a/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx +++ b/apps/dokploy/components/dashboard/compose/general/compose-file-editor.tsx @@ -35,8 +35,7 @@ export const ComposeFileEditor = ({ composeId }: Props) => { { enabled: !!composeId }, ); - const { mutateAsync, isLoading, error, isError } = - api.compose.update.useMutation(); + const { mutateAsync, isLoading } = api.compose.update.useMutation(); const form = useForm({ defaultValues: { @@ -76,7 +75,7 @@ export const ComposeFileEditor = ({ composeId }: Props) => { composeId, }); }) - .catch((e) => { + .catch((_e) => { toast.error("Error updating the Compose config"); }); }; diff --git a/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx b/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx index 1c06fe881..875841338 100644 --- a/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx @@ -84,7 +84,6 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => { data: repositories, isLoading: isLoadingRepositories, error, - isError, } = api.bitbucket.getBitbucketRepositories.useQuery( { bitbucketId, diff --git a/apps/dokploy/components/dashboard/compose/general/isolated-deployment.tsx b/apps/dokploy/components/dashboard/compose/general/isolated-deployment.tsx index 70d685efb..3ae2e9fe3 100644 --- a/apps/dokploy/components/dashboard/compose/general/isolated-deployment.tsx +++ b/apps/dokploy/components/dashboard/compose/general/isolated-deployment.tsx @@ -70,7 +70,7 @@ export const IsolatedDeployment = ({ composeId }: Props) => { composeId, isolatedDeployment: formData?.isolatedDeployment || false, }) - .then(async (data) => { + .then(async (_data) => { randomizeCompose(); refetch(); toast.success("Compose updated"); diff --git a/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx b/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx index 4462ef0eb..4cc877fde 100644 --- a/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/randomize-compose.tsx @@ -39,7 +39,7 @@ type Schema = z.infer; export const RandomizeCompose = ({ composeId }: Props) => { const utils = api.useUtils(); const [compose, setCompose] = useState(""); - const [isOpen, setIsOpen] = useState(false); + const [_isOpen, _setIsOpen] = useState(false); const { mutateAsync, error, isError } = api.compose.randomizeCompose.useMutation(); @@ -76,7 +76,7 @@ export const RandomizeCompose = ({ composeId }: Props) => { suffix: formData?.suffix || "", randomize: formData?.randomize || false, }) - .then(async (data) => { + .then(async (_data) => { randomizeCompose(); refetch(); toast.success("Compose updated"); diff --git a/apps/dokploy/components/dashboard/compose/general/show-converted-compose.tsx b/apps/dokploy/components/dashboard/compose/general/show-converted-compose.tsx index 8a2186d9e..49606645c 100644 --- a/apps/dokploy/components/dashboard/compose/general/show-converted-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/show-converted-compose.tsx @@ -40,7 +40,7 @@ export const ShowConvertedCompose = ({ composeId }: Props) => { .then(() => { refetch(); }) - .catch((err) => {}); + .catch((_err) => {}); } }, [isOpen]); diff --git a/apps/dokploy/components/dashboard/monitoring/paid/container/container-block-chart.tsx b/apps/dokploy/components/dashboard/monitoring/paid/container/container-block-chart.tsx index 9150dbcde..12af6b91d 100644 --- a/apps/dokploy/components/dashboard/monitoring/paid/container/container-block-chart.tsx +++ b/apps/dokploy/components/dashboard/monitoring/paid/container/container-block-chart.tsx @@ -29,14 +29,6 @@ interface Props { data: ContainerMetric[]; } -interface FormattedMetric { - timestamp: string; - read: number; - write: number; - readUnit: string; - writeUnit: string; -} - const chartConfig = { read: { label: "Read", diff --git a/apps/dokploy/components/dashboard/organization/handle-organization.tsx b/apps/dokploy/components/dashboard/organization/handle-organization.tsx index 905a244cc..2a595f436 100644 --- a/apps/dokploy/components/dashboard/organization/handle-organization.tsx +++ b/apps/dokploy/components/dashboard/organization/handle-organization.tsx @@ -20,7 +20,7 @@ interface Props { organizationId?: string; children?: React.ReactNode; } -export function AddOrganization({ organizationId, children }: Props) { +export function AddOrganization({ organizationId }: Props) { const utils = api.useUtils(); const { data: organization } = api.organization.one.useQuery( { diff --git a/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx b/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx index 2bae245ec..40e84844f 100644 --- a/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx +++ b/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx @@ -53,7 +53,7 @@ export const ShowCustomCommand = ({ id, type }: Props) => { mongo: () => api.mongo.update.useMutation(), }; - const { mutateAsync, isLoading } = mutationMap[type] + const { mutateAsync } = mutationMap[type] ? mutationMap[type]() : api.mongo.update.useMutation(); diff --git a/apps/dokploy/components/dashboard/project/add-application.tsx b/apps/dokploy/components/dashboard/project/add-application.tsx index da30cfee3..16c56917d 100644 --- a/apps/dokploy/components/dashboard/project/add-application.tsx +++ b/apps/dokploy/components/dashboard/project/add-application.tsx @@ -103,7 +103,7 @@ export const AddApplication = ({ projectId, projectName }: Props) => { projectId, }); }) - .catch((e) => { + .catch((_e) => { toast.error("Error creating the service"); }); }; diff --git a/apps/dokploy/components/dashboard/project/add-template.tsx b/apps/dokploy/components/dashboard/project/add-template.tsx index 3965f8172..5363e6f36 100644 --- a/apps/dokploy/components/dashboard/project/add-template.tsx +++ b/apps/dokploy/components/dashboard/project/add-template.tsx @@ -434,14 +434,14 @@ export const AddTemplate = ({ projectId }: Props) => { }); toast.promise(promise, { loading: "Setting up...", - success: (data) => { + success: (_data) => { utils.project.one.invalidate({ projectId, }); setOpen(false); return `${template.name} template created successfully`; }, - error: (err) => { + error: (_err) => { return `An error ocurred deploying ${template.name} template`; }, }); diff --git a/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx b/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx index 25b5f2ba7..75112cf6e 100644 --- a/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx +++ b/apps/dokploy/components/dashboard/redis/general/show-external-redis-credentials.tsx @@ -79,7 +79,7 @@ export const ShowExternalRedisCredentials = ({ redisId }: Props) => { useEffect(() => { const buildConnectionUrl = () => { - const hostname = window.location.hostname; + const _hostname = window.location.hostname; const port = form.watch("externalPort") || data?.externalPort; return `redis://default:${data?.databasePassword}@${getIp}:${port}`; diff --git a/apps/dokploy/components/dashboard/requests/columns.tsx b/apps/dokploy/components/dashboard/requests/columns.tsx index c1814190e..2c0391f80 100644 --- a/apps/dokploy/components/dashboard/requests/columns.tsx +++ b/apps/dokploy/components/dashboard/requests/columns.tsx @@ -24,7 +24,7 @@ export const getStatusColor = (status: number) => { export const columns: ColumnDef[] = [ { accessorKey: "level", - header: ({ column }) => { + header: () => { return ; }, cell: ({ row }) => { diff --git a/apps/dokploy/components/dashboard/requests/requests-table.tsx b/apps/dokploy/components/dashboard/requests/requests-table.tsx index cd2949c34..4926ce4e3 100644 --- a/apps/dokploy/components/dashboard/requests/requests-table.tsx +++ b/apps/dokploy/components/dashboard/requests/requests-table.tsx @@ -92,7 +92,7 @@ export const RequestsTable = () => { pageSize: 10, }); - const { data: statsLogs, isLoading } = api.settings.readStatsLogs.useQuery( + const { data: statsLogs } = api.settings.readStatsLogs.useQuery( { sort: sorting[0], page: pagination, @@ -300,7 +300,7 @@ export const RequestsTable = () => {
setSelectedRow(undefined)} + onOpenChange={(_open) => setSelectedRow(undefined)} > diff --git a/apps/dokploy/components/dashboard/search-command.tsx b/apps/dokploy/components/dashboard/search-command.tsx index 5726dc99a..b36703036 100644 --- a/apps/dokploy/components/dashboard/search-command.tsx +++ b/apps/dokploy/components/dashboard/search-command.tsx @@ -22,14 +22,11 @@ import { extractServices, } from "@/pages/dashboard/project/[projectId]"; import { api } from "@/utils/api"; -import type { findProjectById } from "@dokploy/server/services/project"; import { BookIcon, CircuitBoard, GlobeIcon } from "lucide-react"; import { useRouter } from "next/router"; import React from "react"; import { StatusTooltip } from "../shared/status-tooltip"; -type Project = Awaited>; - export const SearchCommand = () => { const router = useRouter(); const [open, setOpen] = React.useState(false); @@ -38,7 +35,7 @@ export const SearchCommand = () => { const { data } = api.project.all.useQuery(undefined, { enabled: !!session, }); - const { data: isCloud, isLoading } = api.settings.isCloud.useQuery(); + const { data: isCloud } = api.settings.isCloud.useQuery(); React.useEffect(() => { const down = (e: KeyboardEvent) => { diff --git a/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx b/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx index 029eaa90f..2c20bb81d 100644 --- a/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx +++ b/apps/dokploy/components/dashboard/settings/billing/show-billing.tsx @@ -38,7 +38,7 @@ export const calculatePrice = (count: number, isAnnual = false) => { return count * 3.5; }; export const ShowBilling = () => { - const { data: servers } = api.server.all.useQuery(undefined); + const { data: servers } = api.server.count.useQuery(); const { data: admin } = api.user.get.useQuery(); const { data, isLoading } = api.stripe.getProducts.useQuery(); const { mutateAsync: createCheckoutSession } = @@ -71,7 +71,7 @@ export const ShowBilling = () => { }); const maxServers = admin?.user.serversQuantity ?? 1; - const percentage = ((servers?.length ?? 0) / maxServers) * 100; + const percentage = ((servers ?? 0) / maxServers) * 100; const safePercentage = Math.min(percentage, 100); return ( @@ -102,13 +102,13 @@ export const ShowBilling = () => {

Servers Plan

- You have {servers?.length} server on your plan of{" "} + You have {servers} server on your plan of{" "} {admin?.user.serversQuantity} servers

- {admin && admin.user.serversQuantity! <= servers?.length! && ( + {admin && admin.user.serversQuantity! <= (servers ?? 0) && (
diff --git a/apps/dokploy/components/dashboard/settings/cluster/nodes/show-nodes.tsx b/apps/dokploy/components/dashboard/settings/cluster/nodes/show-nodes.tsx index ba3eefa56..b84c3b636 100644 --- a/apps/dokploy/components/dashboard/settings/cluster/nodes/show-nodes.tsx +++ b/apps/dokploy/components/dashboard/settings/cluster/nodes/show-nodes.tsx @@ -41,8 +41,7 @@ export const ShowNodes = () => { const { data, isLoading, refetch } = api.cluster.getNodes.useQuery(); const { data: registry } = api.registry.all.useQuery(); - const { mutateAsync: deleteNode, isLoading: isRemoving } = - api.cluster.removeWorker.useMutation(); + const { mutateAsync: deleteNode } = api.cluster.removeWorker.useMutation(); const haveAtLeastOneRegistry = !!(registry && registry?.length > 0); return ( diff --git a/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx b/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx index 78f3b868a..55daedca2 100644 --- a/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx +++ b/apps/dokploy/components/dashboard/settings/cluster/registry/handle-registry.tsx @@ -131,7 +131,7 @@ export const HandleRegistry = ({ registryId }: Props) => { serverId: data.serverId, registryId: registryId || "", }) - .then(async (data) => { + .then(async (_data) => { await utils.registry.all.invalidate(); toast.success(registryId ? "Registry updated" : "Registry added"); setIsOpen(false); diff --git a/apps/dokploy/components/dashboard/settings/git/bitbucket/add-bitbucket-provider.tsx b/apps/dokploy/components/dashboard/settings/git/bitbucket/add-bitbucket-provider.tsx index 2c0f30466..0df2d0610 100644 --- a/apps/dokploy/components/dashboard/settings/git/bitbucket/add-bitbucket-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/bitbucket/add-bitbucket-provider.tsx @@ -47,10 +47,10 @@ type Schema = z.infer; export const AddBitbucketProvider = () => { const utils = api.useUtils(); const [isOpen, setIsOpen] = useState(false); - const url = useUrl(); + const _url = useUrl(); const { mutateAsync, error, isError } = api.bitbucket.create.useMutation(); const { data: auth } = api.user.get.useQuery(); - const router = useRouter(); + const _router = useRouter(); const form = useForm({ defaultValues: { username: "", diff --git a/apps/dokploy/components/dashboard/settings/git/show-git-providers.tsx b/apps/dokploy/components/dashboard/settings/git/show-git-providers.tsx index 3343409fe..451ea5d17 100644 --- a/apps/dokploy/components/dashboard/settings/git/show-git-providers.tsx +++ b/apps/dokploy/components/dashboard/settings/git/show-git-providers.tsx @@ -102,7 +102,7 @@ export const ShowGitProviders = () => {
- {data?.map((gitProvider, index) => { + {data?.map((gitProvider, _index) => { const isGithub = gitProvider.providerType === "github"; const isGitlab = gitProvider.providerType === "gitlab"; const isBitbucket = diff --git a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx index 6f6d8ff11..d2d3b450d 100644 --- a/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx +++ b/apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx @@ -136,7 +136,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { const [visible, setVisible] = useState(false); const { data: isCloud } = api.settings.isCloud.useQuery(); - const { data: notification, refetch } = api.notification.one.useQuery( + const { data: notification } = api.notification.one.useQuery( { notificationId: notificationId || "", }, @@ -1038,7 +1038,7 @@ export const HandleNotifications = ({ notificationId }: Props) => { }); } toast.success("Connection Success"); - } catch (err) { + } catch (_err) { toast.error("Error testing the provider"); } }} diff --git a/apps/dokploy/components/dashboard/settings/notifications/show-notifications.tsx b/apps/dokploy/components/dashboard/settings/notifications/show-notifications.tsx index d65069d4b..782b92413 100644 --- a/apps/dokploy/components/dashboard/settings/notifications/show-notifications.tsx +++ b/apps/dokploy/components/dashboard/settings/notifications/show-notifications.tsx @@ -56,7 +56,7 @@ export const ShowNotifications = () => { ) : (
- {data?.map((notification, index) => ( + {data?.map((notification, _index) => (
{ toast.success("2FA disabled successfully"); utils.auth.get.invalidate(); setIsOpen(false); - } catch (error) { + } catch (_error) { form.setError("password", { message: "Connection error. Please try again.", }); diff --git a/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx b/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx index 918df4353..3ececb649 100644 --- a/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx @@ -47,20 +47,8 @@ const PinSchema = z.object({ type PasswordForm = z.infer; type PinForm = z.infer; -type TwoFactorEnableResponse = { - totpURI: string; - backupCodes: string[]; -}; - -type TwoFactorSetupData = { - qrCodeUrl: string; - secret: string; - totpURI: string; -}; - export const Enable2FA = () => { const utils = api.useUtils(); - const { data: session } = authClient.useSession(); const [data, setData] = useState(null); const [backupCodes, setBackupCodes] = useState([]); const [isDialogOpen, setIsDialogOpen] = useState(false); diff --git a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx index f4299709a..761cfb71b 100644 --- a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx @@ -54,9 +54,7 @@ const randomImages = [ ]; export const ProfileForm = () => { - const utils = api.useUtils(); - const { mutateAsync: disable2FA, isLoading: isDisabling } = - api.auth.disable2FA.useMutation(); + const _utils = api.useUtils(); const { data, refetch, isLoading } = api.user.get.useQuery(); const { mutateAsync, diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/show-storage-actions.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/show-storage-actions.tsx index cb60effd1..3492ba7c2 100644 --- a/apps/dokploy/components/dashboard/settings/servers/actions/show-storage-actions.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/actions/show-storage-actions.tsx @@ -26,7 +26,7 @@ export const ShowStorageActions = ({ serverId }: Props) => { isLoading: cleanDockerBuilderIsLoading, } = api.settings.cleanDockerBuilder.useMutation(); - const { mutateAsync: cleanMonitoring, isLoading: cleanMonitoringIsLoading } = + const { mutateAsync: cleanMonitoring } = api.settings.cleanMonitoring.useMutation(); const { mutateAsync: cleanUnusedImages, diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/toggle-docker-cleanup.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/toggle-docker-cleanup.tsx index e574593d5..12e279423 100644 --- a/apps/dokploy/components/dashboard/settings/servers/actions/toggle-docker-cleanup.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/actions/toggle-docker-cleanup.tsx @@ -36,7 +36,7 @@ export const ToggleDockerCleanup = ({ serverId }: Props) => { await refetch(); } toast.success("Docker Cleanup updated"); - } catch (error) { + } catch (_error) { toast.error("Docker Cleanup Error"); } }; diff --git a/apps/dokploy/components/dashboard/settings/servers/edit-script.tsx b/apps/dokploy/components/dashboard/settings/servers/edit-script.tsx index 0a22220ed..6225ee771 100644 --- a/apps/dokploy/components/dashboard/settings/servers/edit-script.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/edit-script.tsx @@ -82,7 +82,7 @@ export const EditScript = ({ serverId }: Props) => { command: formData.command || "", serverId, }) - .then((data) => { + .then((_data) => { toast.success("Script modified successfully"); }) .catch(() => { diff --git a/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx b/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx index ec60fed6d..c24440a61 100644 --- a/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/gpu-support.tsx @@ -56,7 +56,7 @@ export function GPUSupport({ serverId }: GPUSupportProps) { try { await utils.settings.checkGPUStatus.invalidate({ serverId }); await refetch(); - } catch (error) { + } catch (_error) { toast.error("Failed to refresh GPU status"); } finally { setIsRefreshing(false); @@ -74,7 +74,7 @@ export function GPUSupport({ serverId }: GPUSupportProps) { try { await setupGPU.mutateAsync({ serverId }); - } catch (error) { + } catch (_error) { // Error handling is done in mutation's onError } }; diff --git a/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx b/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx index be71d8367..979941458 100644 --- a/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx @@ -118,7 +118,7 @@ export const HandleServers = ({ serverId }: Props) => { sshKeyId: data.sshKeyId || "", serverId: serverId || "", }) - .then(async (data) => { + .then(async (_data) => { await utils.server.all.invalidate(); refetchServer(); toast.success(serverId ? "Server Updated" : "Server Created"); diff --git a/apps/dokploy/components/dashboard/settings/servers/security-audit.tsx b/apps/dokploy/components/dashboard/settings/servers/security-audit.tsx index 475f2b8ff..5f693707f 100644 --- a/apps/dokploy/components/dashboard/settings/servers/security-audit.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/security-audit.tsx @@ -25,7 +25,7 @@ export const SecurityAudit = ({ serverId }: Props) => { enabled: !!serverId, }, ); - const utils = api.useUtils(); + const _utils = api.useUtils(); return (
diff --git a/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx b/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx index 23173047e..b8c699268 100644 --- a/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx @@ -80,7 +80,7 @@ const Schema = z.object({ type Schema = z.infer; export const SetupMonitoring = ({ serverId }: Props) => { - const { data, isLoading } = serverId + const { data } = serverId ? api.server.one.useQuery( { serverId: serverId || "", diff --git a/apps/dokploy/components/dashboard/settings/servers/validate-server.tsx b/apps/dokploy/components/dashboard/settings/servers/validate-server.tsx index db4f17b76..0632b97c2 100644 --- a/apps/dokploy/components/dashboard/settings/servers/validate-server.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/validate-server.tsx @@ -25,7 +25,7 @@ export const ValidateServer = ({ serverId }: Props) => { enabled: !!serverId, }, ); - const utils = api.useUtils(); + const _utils = api.useUtils(); return (
diff --git a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/create-server.tsx b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/create-server.tsx index a025ad379..24d01553b 100644 --- a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/create-server.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/create-server.tsx @@ -52,10 +52,10 @@ interface Props { export const CreateServer = ({ stepper }: Props) => { const { data: sshKeys } = api.sshKey.all.useQuery(); - const [isOpen, setIsOpen] = useState(false); + const [isOpen, _setIsOpen] = useState(false); const { data: canCreateMoreServers, refetch } = api.stripe.canCreateMoreServers.useQuery(); - const { mutateAsync, error, isError } = api.server.create.useMutation(); + const { mutateAsync } = api.server.create.useMutation(); const cloudSSHKey = sshKeys?.find( (sshKey) => sshKey.name === "dokploy-cloud-ssh-key", ); @@ -96,7 +96,7 @@ export const CreateServer = ({ stepper }: Props) => { username: data.username || "root", sshKeyId: data.sshKeyId || "", }) - .then(async (data) => { + .then(async (_data) => { toast.success("Server Created"); stepper.next(); }) diff --git a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/verify.tsx b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/verify.tsx index fe8c36c2c..f7c2a987c 100644 --- a/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/verify.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/welcome-stripe/verify.tsx @@ -37,15 +37,6 @@ export const Verify = () => { ); const [isRefreshing, setIsRefreshing] = useState(false); - const { data: server } = api.server.one.useQuery( - { - serverId, - }, - { - enabled: !!serverId, - }, - ); - return (
diff --git a/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx index 12670c280..1bf7aa086 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-invitations.tsx @@ -143,7 +143,7 @@ export const ShowInvitations = () => { {invitation.status === "pending" && ( { + onSelect={(_e) => { copy( `${origin}/invitation?token=${invitation.id}`, ); @@ -159,7 +159,7 @@ export const ShowInvitations = () => { {invitation.status === "pending" && ( { + onSelect={async (_e) => { const result = await authClient.organization.cancelInvitation( { diff --git a/apps/dokploy/components/dashboard/settings/users/show-users.tsx b/apps/dokploy/components/dashboard/settings/users/show-users.tsx index ff56698e4..6847558b7 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-users.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-users.tsx @@ -35,7 +35,7 @@ import { AddUserPermissions } from "./add-permissions"; export const ShowUsers = () => { const { data: isCloud } = api.settings.isCloud.useQuery(); const { data, isLoading, refetch } = api.user.all.useQuery(); - const { mutateAsync, isLoading: isRemoving } = api.user.remove.useMutation(); + const { mutateAsync } = api.user.remove.useMutation(); return (
diff --git a/apps/dokploy/components/dashboard/settings/web-server.tsx b/apps/dokploy/components/dashboard/settings/web-server.tsx index 326cb0eaf..64b6d634e 100644 --- a/apps/dokploy/components/dashboard/settings/web-server.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server.tsx @@ -14,10 +14,7 @@ import { ShowTraefikActions } from "./servers/actions/show-traefik-actions"; import { ToggleDockerCleanup } from "./servers/actions/toggle-docker-cleanup"; import { UpdateServer } from "./web-server/update-server"; -interface Props { - className?: string; -} -export const WebServer = ({ className }: Props) => { +export const WebServer = () => { const { t } = useTranslation("settings"); const { data } = api.user.get.useQuery(); diff --git a/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx b/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx index a30823363..a6958b16f 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx @@ -99,7 +99,7 @@ export const ManageTraefikPorts = ({ children, serverId }: Props) => { }); toast.success(t("settings.server.webServer.traefik.portsUpdated")); setOpen(false); - } catch (error) { + } catch (_error) { toast.error(t("settings.server.webServer.traefik.portsUpdateError")); } }; diff --git a/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx b/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx index d6e7345e1..3a511d8ea 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx @@ -43,7 +43,7 @@ interface Props { serverId?: string; } -export const UpdateServerIp = ({ children, serverId }: Props) => { +export const UpdateServerIp = ({ children }: Props) => { const [isOpen, setIsOpen] = useState(false); const { data } = api.user.get.useQuery(); diff --git a/apps/dokploy/components/dashboard/swarm/applications/columns.tsx b/apps/dokploy/components/dashboard/swarm/applications/columns.tsx index ab058e851..5ae091a95 100644 --- a/apps/dokploy/components/dashboard/swarm/applications/columns.tsx +++ b/apps/dokploy/components/dashboard/swarm/applications/columns.tsx @@ -214,7 +214,7 @@ export const columns: ColumnDef[] = [ { accessorKey: "Logs", accessorFn: (row) => row.Error, - header: ({ column }) => { + header: () => { return Logs; }, cell: ({ row }) => { diff --git a/apps/dokploy/components/dashboard/swarm/applications/data-table.tsx b/apps/dokploy/components/dashboard/swarm/applications/data-table.tsx index 03915c19b..96f43e617 100644 --- a/apps/dokploy/components/dashboard/swarm/applications/data-table.tsx +++ b/apps/dokploy/components/dashboard/swarm/applications/data-table.tsx @@ -48,7 +48,7 @@ export function DataTable({ const [columnVisibility, setColumnVisibility] = React.useState({}); const [rowSelection, setRowSelection] = React.useState({}); - const [pagination, setPagination] = React.useState({ + const [_pagination, _setPagination] = React.useState({ pageIndex: 0, //initial page index pageSize: 8, //default page size }); diff --git a/apps/dokploy/components/dashboard/swarm/details/show-node-config.tsx b/apps/dokploy/components/dashboard/swarm/details/show-node-config.tsx index a41c5a497..7f27fe3bf 100644 --- a/apps/dokploy/components/dashboard/swarm/details/show-node-config.tsx +++ b/apps/dokploy/components/dashboard/swarm/details/show-node-config.tsx @@ -17,7 +17,7 @@ interface Props { } export const ShowNodeConfig = ({ nodeId, serverId }: Props) => { - const { data, isLoading } = api.swarm.getNodeInfo.useQuery({ + const { data } = api.swarm.getNodeInfo.useQuery({ nodeId, serverId, }); diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 939d10841..63155f8eb 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -157,7 +157,7 @@ const MENU: Menu = { url: "/dashboard/monitoring", icon: BarChartHorizontalBigIcon, // Only enabled in non-cloud environments - isEnabled: ({ auth, isCloud }) => !isCloud, + isEnabled: ({ isCloud }) => !isCloud, }, { isSingle: true, @@ -277,7 +277,7 @@ const MENU: Menu = { url: "/dashboard/settings/servers", icon: Server, // Only enabled for admins - isEnabled: ({ auth, isCloud }) => !!(auth?.role === "owner"), + isEnabled: ({ auth }) => !!(auth?.role === "owner"), }, { isSingle: true, @@ -490,8 +490,9 @@ function SidebarLogo() { const { state } = useSidebar(); const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: user } = api.user.get.useQuery(); - const { data: dokployVersion } = api.settings.getDokployVersion.useQuery(); + // const { data: dokployVersion } = api.settings.getDokployVersion.useQuery(); const { data: session } = authClient.useSession(); + const { data: organizations, refetch, @@ -501,12 +502,12 @@ function SidebarLogo() { api.organization.delete.useMutation(); const { isMobile } = useSidebar(); const { data: activeOrganization } = authClient.useActiveOrganization(); - const utils = api.useUtils(); + const _utils = api.useUtils(); const { data: invitations, refetch: refetchInvitations } = api.user.getInvitations.useQuery(); - const [activeTeam, setActiveTeam] = useState< + const [_activeTeam, setActiveTeam] = useState< typeof activeOrganization | null >(null); @@ -543,7 +544,7 @@ function SidebarLogo() {

- {activeOrganization?.name} + {activeOrganization?.name ?? "Select Organization"}

@@ -551,7 +552,7 @@ function SidebarLogo() { +
{org.name}
- {org.name} - {(org.ownerId === session?.user?.id || isCloud) && ( + {org.ownerId === session?.user?.id && (
))} - {!isCloud && user?.role === "owner" && ( + {(user?.role === "owner" || isCloud) && ( <> @@ -721,11 +722,11 @@ export default function Page({ children }: Props) { const router = useRouter(); const pathname = usePathname(); - const currentPath = router.pathname; + const _currentPath = router.pathname; const { data: auth } = api.user.get.useQuery(); const includesProjects = pathname?.includes("/dashboard/project"); - const { data: isCloud, isLoading } = api.settings.isCloud.useQuery(); + const { data: isCloud } = api.settings.isCloud.useQuery(); const { home: filteredHome, diff --git a/apps/dokploy/components/layouts/update-server.tsx b/apps/dokploy/components/layouts/update-server.tsx index fa748f849..5d7978859 100644 --- a/apps/dokploy/components/layouts/update-server.tsx +++ b/apps/dokploy/components/layouts/update-server.tsx @@ -11,7 +11,7 @@ export const UpdateServerButton = () => { latestVersion: null, updateAvailable: false, }); - const router = useRouter(); + const _router = useRouter(); const { data: isCloud } = api.settings.isCloud.useQuery(); const { mutateAsync: getUpdateData } = api.settings.getUpdateData.useMutation(); diff --git a/apps/dokploy/components/layouts/user-nav.tsx b/apps/dokploy/components/layouts/user-nav.tsx index 196f6d77d..4a9624de4 100644 --- a/apps/dokploy/components/layouts/user-nav.tsx +++ b/apps/dokploy/components/layouts/user-nav.tsx @@ -24,7 +24,7 @@ import { useRouter } from "next/router"; import { ModeToggle } from "../ui/modeToggle"; import { SidebarMenuButton } from "../ui/sidebar"; -const AUTO_CHECK_UPDATES_INTERVAL_MINUTES = 7; +const _AUTO_CHECK_UPDATES_INTERVAL_MINUTES = 7; export const UserNav = () => { const router = useRouter(); diff --git a/apps/dokploy/components/shared/breadcrumb-sidebar.tsx b/apps/dokploy/components/shared/breadcrumb-sidebar.tsx index 60730c96b..74e9fdf63 100644 --- a/apps/dokploy/components/shared/breadcrumb-sidebar.tsx +++ b/apps/dokploy/components/shared/breadcrumb-sidebar.tsx @@ -26,7 +26,7 @@ export const BreadcrumbSidebar = ({ list }: Props) => { - {list.map((item, index) => ( + {list.map((item, _index) => ( diff --git a/apps/dokploy/components/shared/drawer-logs.tsx b/apps/dokploy/components/shared/drawer-logs.tsx index 5e4ab554b..d8d1affb7 100644 --- a/apps/dokploy/components/shared/drawer-logs.tsx +++ b/apps/dokploy/components/shared/drawer-logs.tsx @@ -43,7 +43,7 @@ export const DrawerLogs = ({ isOpen, onClose, filteredLogs }: Props) => { return ( { + onOpenChange={(_open) => { onClose(); }} > diff --git a/apps/dokploy/components/ui/file-tree.tsx b/apps/dokploy/components/ui/file-tree.tsx index 9db3786e6..0f50d5089 100644 --- a/apps/dokploy/components/ui/file-tree.tsx +++ b/apps/dokploy/components/ui/file-tree.tsx @@ -85,7 +85,7 @@ const Tree = React.forwardRef( return ids; }, [data, initialSlelectedItemId]); - const { ref: refRoot, width, height } = useResizeObserver(); + const { ref: refRoot } = useResizeObserver(); return (
diff --git a/apps/dokploy/migrate.ts b/apps/dokploy/migrate.ts index febd1c0e2..097459b96 100644 --- a/apps/dokploy/migrate.ts +++ b/apps/dokploy/migrate.ts @@ -136,7 +136,7 @@ await db }, }); for (const project of projects) { - const user = await db.update(schema.projects).set({ + const _user = await db.update(schema.projects).set({ organizationId: project.user.organizations[0]?.id || "", }); } diff --git a/apps/dokploy/pages/_error.tsx b/apps/dokploy/pages/_error.tsx index 958e17407..d28e2cb00 100644 --- a/apps/dokploy/pages/_error.tsx +++ b/apps/dokploy/pages/_error.tsx @@ -90,7 +90,7 @@ export default function Custom404({ statusCode, error }: Props) { } // @ts-ignore -Error.getInitialProps = ({ res, err, ...rest }: NextPageContext) => { +Error.getInitialProps = ({ res, err }: NextPageContext) => { const statusCode = res ? res.statusCode : err ? err.statusCode : 404; return { statusCode, error: err }; }; diff --git a/apps/dokploy/pages/api/health.ts b/apps/dokploy/pages/api/health.ts index 9dc8101e5..57875a192 100644 --- a/apps/dokploy/pages/api/health.ts +++ b/apps/dokploy/pages/api/health.ts @@ -1,7 +1,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; export default async function handler( - req: NextApiRequest, + _req: NextApiRequest, res: NextApiResponse, ) { return res.status(200).json({ ok: true }); diff --git a/apps/dokploy/pages/api/providers/github/setup.ts b/apps/dokploy/pages/api/providers/github/setup.ts index ac5e7a6b0..327122509 100644 --- a/apps/dokploy/pages/api/providers/github/setup.ts +++ b/apps/dokploy/pages/api/providers/github/setup.ts @@ -16,8 +16,7 @@ export default async function handler( req: NextApiRequest, res: NextApiResponse, ) { - const { code, state, installation_id, setup_action }: Query = - req.query as Query; + const { code, state, installation_id }: Query = req.query as Query; if (!code) { return res.status(400).json({ error: "Missing code parameter" }); diff --git a/apps/dokploy/pages/api/stripe/webhook.ts b/apps/dokploy/pages/api/stripe/webhook.ts index 6200a79ec..592803b15 100644 --- a/apps/dokploy/pages/api/stripe/webhook.ts +++ b/apps/dokploy/pages/api/stripe/webhook.ts @@ -1,7 +1,7 @@ import { buffer } from "node:stream/consumers"; import { db } from "@/server/db"; -import { server, users_temp } from "@/server/db/schema"; -import { findUserById } from "@dokploy/server"; +import { organization, server, users_temp } from "@/server/db/schema"; +import { findUserById, type Server } from "@dokploy/server"; import { asc, eq } from "drizzle-orm"; import type { NextApiRequest, NextApiResponse } from "next"; import Stripe from "stripe"; @@ -172,11 +172,11 @@ export default async function handler( } await db - .update(admins) + .update(users_temp) .set({ serversQuantity: suscription?.items?.data?.[0]?.quantity ?? 0, }) - .where(eq(admins.stripeCustomerId, suscription.customer as string)); + .where(eq(users_temp.stripeCustomerId, suscription.customer as string)); const admin = await findUserByStripeCustomerId( suscription.customer as string, @@ -205,11 +205,13 @@ export default async function handler( return res.status(400).send("Webhook Error: Admin not found"); } await db - .update(admins) + .update(users_temp) .set({ serversQuantity: 0, }) - .where(eq(admins.stripeCustomerId, newInvoice.customer as string)); + .where( + eq(users_temp.stripeCustomerId, newInvoice.customer as string), + ); await disableServers(admin.id); } @@ -245,12 +247,18 @@ export default async function handler( } const disableServers = async (userId: string) => { - await db - .update(server) - .set({ - serverStatus: "inactive", - }) - .where(eq(server.userId, userId)); + const organizations = await db.query.organization.findMany({ + where: eq(organization.ownerId, userId), + }); + + for (const org of organizations) { + await db + .update(server) + .set({ + serverStatus: "inactive", + }) + .where(eq(server.organizationId, org.id)); + } }; const findUserByStripeCustomerId = async (stripeCustomerId: string) => { @@ -275,11 +283,19 @@ const deactivateServer = async (serverId: string) => { }; export const findServersByUserIdSorted = async (userId: string) => { - const servers = await db.query.server.findMany({ - where: eq(server.userId, userId), - orderBy: asc(server.createdAt), + const organizations = await db.query.organization.findMany({ + where: eq(organization.ownerId, userId), }); + const servers: Server[] = []; + for (const org of organizations) { + const serversByOrg = await db.query.server.findMany({ + where: eq(server.organizationId, org.id), + orderBy: asc(server.createdAt), + }); + servers.push(...serversByOrg); + } + return servers; }; export const updateServersBasedOnQuantity = async ( diff --git a/apps/dokploy/pages/dashboard/docker.tsx b/apps/dokploy/pages/dashboard/docker.tsx index a9d80353f..e01a763be 100644 --- a/apps/dokploy/pages/dashboard/docker.tsx +++ b/apps/dokploy/pages/dashboard/docker.tsx @@ -72,7 +72,7 @@ export async function getServerSideProps( trpcState: helpers.dehydrate(), }, }; - } catch (error) { + } catch (_error) { return { props: {}, }; diff --git a/apps/dokploy/pages/dashboard/monitoring.tsx b/apps/dokploy/pages/dashboard/monitoring.tsx index 4d8b072f5..4272c4536 100644 --- a/apps/dokploy/pages/dashboard/monitoring.tsx +++ b/apps/dokploy/pages/dashboard/monitoring.tsx @@ -15,8 +15,7 @@ const BASE_URL = "http://localhost:3001/metrics"; const DEFAULT_TOKEN = "metrics"; const Dashboard = () => { - const { data: isCloud } = api.settings.isCloud.useQuery(); - const [toggleMonitoring, setToggleMonitoring] = useLocalStorage( + const [toggleMonitoring, _setToggleMonitoring] = useLocalStorage( "monitoring-enabled", false, ); diff --git a/apps/dokploy/pages/dashboard/project/[projectId].tsx b/apps/dokploy/pages/dashboard/project/[projectId].tsx index f85aa9ee8..62de98c13 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId].tsx @@ -261,7 +261,7 @@ const Project = ( try { await composeActions.start.mutateAsync({ composeId: serviceId }); success++; - } catch (error) { + } catch (_error) { toast.error(`Error starting service ${serviceId}`); } } @@ -281,7 +281,7 @@ const Project = ( try { await composeActions.stop.mutateAsync({ composeId: serviceId }); success++; - } catch (error) { + } catch (_error) { toast.error(`Error stopping service ${serviceId}`); } } @@ -685,7 +685,7 @@ export async function getServerSideProps( projectId: params?.projectId, }, }; - } catch (error) { + } catch (_error) { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx index 59dba68ce..94b8f5f5d 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx @@ -65,7 +65,7 @@ type TabState = const Service = ( props: InferGetServerSidePropsType, ) => { - const [toggleMonitoring, setToggleMonitoring] = useState(false); + const [_toggleMonitoring, _setToggleMonitoring] = useState(false); const { applicationId, activeTab } = props; const router = useRouter(); const { projectId } = router.query; @@ -86,7 +86,6 @@ const Service = ( const { data: isCloud } = api.settings.isCloud.useQuery(); const { data: auth } = api.user.get.useQuery(); - const { data: monitoring } = api.user.getMetricsToken.useQuery(); return (
@@ -399,7 +398,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (error) { + } catch (_error) { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx index c1331e23f..46b727d2a 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx @@ -59,7 +59,7 @@ type TabState = const Service = ( props: InferGetServerSidePropsType, ) => { - const [toggleMonitoring, setToggleMonitoring] = useState(false); + const [_toggleMonitoring, _setToggleMonitoring] = useState(false); const { composeId, activeTab } = props; const router = useRouter(); const { projectId } = router.query; @@ -79,7 +79,6 @@ const Service = ( ); const { data: auth } = api.user.get.useQuery(); - const { data: monitoring } = api.user.getMetricsToken.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery(); return ( @@ -393,7 +392,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (error) { + } catch (_error) { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx index 033b88a9d..e91e0978d 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx @@ -52,7 +52,7 @@ type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced"; const Mariadb = ( props: InferGetServerSidePropsType, ) => { - const [toggleMonitoring, setToggleMonitoring] = useState(false); + const [_toggleMonitoring, _setToggleMonitoring] = useState(false); const { mariadbId, activeTab } = props; const router = useRouter(); @@ -60,7 +60,6 @@ const Mariadb = ( const [tab, setSab] = useState(activeTab); const { data } = api.mariadb.one.useQuery({ mariadbId }); const { data: auth } = api.user.get.useQuery(); - const { data: monitoring } = api.user.getMetricsToken.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -342,7 +341,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (error) { + } catch (_error) { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx index dea8cd57b..b10b7b93d 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx @@ -52,7 +52,7 @@ type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced"; const Mongo = ( props: InferGetServerSidePropsType, ) => { - const [toggleMonitoring, setToggleMonitoring] = useState(false); + const [_toggleMonitoring, _setToggleMonitoring] = useState(false); const { mongoId, activeTab } = props; const router = useRouter(); const { projectId } = router.query; @@ -60,7 +60,6 @@ const Mongo = ( const { data } = api.mongo.one.useQuery({ mongoId }); const { data: auth } = api.user.get.useQuery(); - const { data: monitoring } = api.user.getMetricsToken.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -343,7 +342,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (error) { + } catch (_error) { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx index cc4eb4aa3..261a2762b 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx @@ -52,14 +52,13 @@ type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced"; const MySql = ( props: InferGetServerSidePropsType, ) => { - const [toggleMonitoring, setToggleMonitoring] = useState(false); + const [_toggleMonitoring, _setToggleMonitoring] = useState(false); const { mysqlId, activeTab } = props; const router = useRouter(); const { projectId } = router.query; const [tab, setSab] = useState(activeTab); const { data } = api.mysql.one.useQuery({ mysqlId }); const { data: auth } = api.user.get.useQuery(); - const { data: monitoring } = api.user.getMetricsToken.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -348,7 +347,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (error) { + } catch (_error) { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx index d0f1dc106..5d8fd3b1b 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/postgres/[postgresId].tsx @@ -52,7 +52,7 @@ type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced"; const Postgresql = ( props: InferGetServerSidePropsType, ) => { - const [toggleMonitoring, setToggleMonitoring] = useState(false); + const [_toggleMonitoring, _setToggleMonitoring] = useState(false); const { postgresId, activeTab } = props; const router = useRouter(); const { projectId } = router.query; @@ -60,7 +60,6 @@ const Postgresql = ( const { data } = api.postgres.one.useQuery({ postgresId }); const { data: auth } = api.user.get.useQuery(); - const { data: monitoring } = api.user.getMetricsToken.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery(); return ( @@ -345,7 +344,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (error) { + } catch (_error) { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx index 2b053df47..c4f40281f 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/redis/[redisId].tsx @@ -51,7 +51,7 @@ type TabState = "projects" | "monitoring" | "settings" | "advanced"; const Redis = ( props: InferGetServerSidePropsType, ) => { - const [toggleMonitoring, setToggleMonitoring] = useState(false); + const [_toggleMonitoring, _setToggleMonitoring] = useState(false); const { redisId, activeTab } = props; const router = useRouter(); const { projectId } = router.query; @@ -59,7 +59,6 @@ const Redis = ( const { data } = api.redis.one.useQuery({ redisId }); const { data: auth } = api.user.get.useQuery(); - const { data: monitoring } = api.user.getMetricsToken.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery(); @@ -335,7 +334,7 @@ export async function getServerSideProps( activeTab: (activeTab || "general") as TabState, }, }; - } catch (error) { + } catch (_error) { return { redirect: { permanent: false, diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx index 4187a0ef7..ce2adc9ce 100644 --- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx +++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx @@ -68,7 +68,7 @@ export async function getServerSideProps( trpcState: helpers.dehydrate(), }, }; - } catch (error) { + } catch (_error) { return { props: {}, }; diff --git a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx index 738c647d4..2472feab4 100644 --- a/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx +++ b/apps/dokploy/pages/dashboard/settings/ssh-keys.tsx @@ -33,7 +33,7 @@ export async function getServerSideProps( }, }; } - const { req, res, resolvedUrl } = ctx; + const { req, res } = ctx; const helpers = createServerSideHelpers({ router: appRouter, ctx: { @@ -69,7 +69,7 @@ export async function getServerSideProps( trpcState: helpers.dehydrate(), }, }; - } catch (error) { + } catch (_error) { return { props: {}, }; diff --git a/apps/dokploy/pages/dashboard/swarm.tsx b/apps/dokploy/pages/dashboard/swarm.tsx index c693fd8cf..155531160 100644 --- a/apps/dokploy/pages/dashboard/swarm.tsx +++ b/apps/dokploy/pages/dashboard/swarm.tsx @@ -72,7 +72,7 @@ export async function getServerSideProps( trpcState: helpers.dehydrate(), }, }; - } catch (error) { + } catch (_error) { return { props: {}, }; diff --git a/apps/dokploy/pages/dashboard/traefik.tsx b/apps/dokploy/pages/dashboard/traefik.tsx index 90359ccd6..ce8208beb 100644 --- a/apps/dokploy/pages/dashboard/traefik.tsx +++ b/apps/dokploy/pages/dashboard/traefik.tsx @@ -72,7 +72,7 @@ export async function getServerSideProps( trpcState: helpers.dehydrate(), }, }; - } catch (error) { + } catch (_error) { return { props: {}, }; diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index c910e78ec..783ec651d 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -43,18 +43,11 @@ const LoginSchema = z.object({ password: z.string().min(8), }); -const TwoFactorSchema = z.object({ +const _TwoFactorSchema = z.object({ code: z.string().min(6), }); -const BackupCodeSchema = z.object({ - code: z.string().min(8, { - message: "Backup code must be at least 8 characters", - }), -}); - type LoginForm = z.infer; -type BackupCodeForm = z.infer; interface Props { IS_CLOUD: boolean; @@ -101,7 +94,7 @@ export default function Home({ IS_CLOUD }: Props) { toast.success("Logged in successfully"); router.push("/dashboard/projects"); - } catch (error) { + } catch (_error) { toast.error("An error occurred while logging in"); } finally { setIsLoginLoading(false); @@ -117,7 +110,7 @@ export default function Home({ IS_CLOUD }: Props) { setIsTwoFactorLoading(true); try { - const { data, error } = await authClient.twoFactor.verifyTotp({ + const { error } = await authClient.twoFactor.verifyTotp({ code: twoFactorCode.replace(/\s/g, ""), }); @@ -129,7 +122,7 @@ export default function Home({ IS_CLOUD }: Props) { toast.success("Logged in successfully"); router.push("/dashboard/projects"); - } catch (error) { + } catch (_error) { toast.error("An error occurred while verifying 2FA code"); } finally { setIsTwoFactorLoading(false); @@ -145,7 +138,7 @@ export default function Home({ IS_CLOUD }: Props) { setIsBackupCodeLoading(true); try { - const { data, error } = await authClient.twoFactor.verifyBackupCode({ + const { error } = await authClient.twoFactor.verifyBackupCode({ code: backupCode.trim(), }); @@ -159,7 +152,7 @@ export default function Home({ IS_CLOUD }: Props) { toast.success("Logged in successfully"); router.push("/dashboard/projects"); - } catch (error) { + } catch (_error) { toast.error("An error occurred while verifying backup code"); } finally { setIsBackupCodeLoading(false); @@ -396,7 +389,7 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { }, }; } - } catch (error) {} + } catch (_error) {} return { props: { diff --git a/apps/dokploy/pages/invitation.tsx b/apps/dokploy/pages/invitation.tsx index 91ca1d0d7..813ec74cc 100644 --- a/apps/dokploy/pages/invitation.tsx +++ b/apps/dokploy/pages/invitation.tsx @@ -16,7 +16,6 @@ import { authClient } from "@/lib/auth-client"; import { api } from "@/utils/api"; import { IS_CLOUD, getUserByToken } from "@dokploy/server"; import { zodResolver } from "@hookform/resolvers/zod"; -import { AlertTriangle } from "lucide-react"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; @@ -90,9 +89,6 @@ const Invitation = ({ }, ); - const { mutateAsync, error, isError, isSuccess } = - api.auth.createUser.useMutation(); - const form = useForm({ defaultValues: { name: "", @@ -115,7 +111,7 @@ const Invitation = ({ const onSubmit = async (values: Register) => { try { - const { data, error } = await authClient.signUp.email({ + const { error } = await authClient.signUp.email({ email: values.email, password: values.password, name: values.name, @@ -131,13 +127,13 @@ const Invitation = ({ return; } - const result = await authClient.organization.acceptInvitation({ + const _result = await authClient.organization.acceptInvitation({ invitationId: token, }); toast.success("Account created successfully"); router.push("/dashboard/projects"); - } catch (error) { + } catch (_error) { toast.error("An error occurred while creating your account"); } }; @@ -180,14 +176,14 @@ const Invitation = ({
- {isError && ( + {/* {isError && (
{error?.message}
- )} + )} */}
@@ -313,7 +309,6 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) { const { query } = ctx; const token = query.token; - console.log("query", query); if (typeof token !== "string") { return { diff --git a/apps/dokploy/pages/register.tsx b/apps/dokploy/pages/register.tsx index 701d8f5b5..980f641f6 100644 --- a/apps/dokploy/pages/register.tsx +++ b/apps/dokploy/pages/register.tsx @@ -13,15 +13,15 @@ import { } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { authClient } from "@/lib/auth-client"; -import { api } from "@/utils/api"; import { IS_CLOUD, isAdminPresent, validateRequest } from "@dokploy/server"; import { zodResolver } from "@hookform/resolvers/zod"; import { AlertTriangle } from "lucide-react"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; -import { type ReactElement, useEffect } from "react"; +import { type ReactElement, useEffect, useState } from "react"; import { useForm } from "react-hook-form"; +import { toast } from "sonner"; import { z } from "zod"; const registerSchema = z @@ -72,15 +72,16 @@ interface Props { const Register = ({ isCloud }: Props) => { const router = useRouter(); - const { mutateAsync, error, isError, data } = - api.auth.createAdmin.useMutation(); + const [isError, setIsError] = useState(false); + const [error, setError] = useState(null); + const [data, setData] = useState(null); const form = useForm({ defaultValues: { name: "Mauricio Siu", email: "user5@yopmail.com", - password: "Password1234", - confirmPassword: "Password1234", + password: "Password123", + confirmPassword: "Password123", }, resolver: zodResolver(registerSchema), }); @@ -96,27 +97,19 @@ const Register = ({ isCloud }: Props) => { name: values.name, }); - // const { data, error } = await authClient.admin.createUser({ - // name: values.name, - // email: values.email, - // password: values.password, - // role: "superAdmin", - // }); - - // consol/e.log(data, error); - // await mutateAsync({ - // email: values.email.toLowerCase(), - // password: values.password, - // }) - // .then(() => { - // toast.success("User registered successfuly", { - // duration: 2000, - // }); - // if (!isCloud) { - // router.push("/"); - // } - // }) - // .catch((e) => e); + if (error) { + setIsError(true); + setError(error.message || "An error occurred"); + } else { + toast.success("User registered successfuly", { + duration: 2000, + }); + if (!isCloud) { + router.push("/"); + } else { + setData(data); + } + } }; return (
@@ -138,15 +131,15 @@ const Register = ({ isCloud }: Props) => {
{isError && ( -
+
- {error?.message} + {error}
)} - {data?.type === "cloud" && ( - + {isCloud && data && ( + Registered successfully, please check your inbox or spam folder to confirm your account. diff --git a/apps/dokploy/pages/reset-password.tsx b/apps/dokploy/pages/reset-password.tsx index 42e2ce002..a34a25ed0 100644 --- a/apps/dokploy/pages/reset-password.tsx +++ b/apps/dokploy/pages/reset-password.tsx @@ -77,7 +77,7 @@ export default function Home({ token }: Props) { resetPasswordToken: token, password: values.password, }) - .then((data) => { + .then((_data) => { toast.success("Password reset successfully", { duration: 2000, }); diff --git a/apps/dokploy/pages/send-reset-password.tsx b/apps/dokploy/pages/send-reset-password.tsx index ce73fbb82..0ea59cf85 100644 --- a/apps/dokploy/pages/send-reset-password.tsx +++ b/apps/dokploy/pages/send-reset-password.tsx @@ -43,13 +43,13 @@ type AuthResponse = { }; export default function Home() { - const [temp, setTemp] = useState({ + const [temp, _setTemp] = useState({ is2FAEnabled: false, authId: "", }); const { mutateAsync, isLoading, isError, error } = api.auth.sendResetPasswordEmail.useMutation(); - const router = useRouter(); + const _router = useRouter(); const form = useForm({ defaultValues: { email: "", @@ -65,7 +65,7 @@ export default function Home() { await mutateAsync({ email: values.email, }) - .then((data) => { + .then((_data) => { toast.success("Email sent", { duration: 2000, }); @@ -150,7 +150,7 @@ export default function Home() { Home.getLayout = (page: ReactElement) => { return {page}; }; -export async function getServerSideProps(context: GetServerSidePropsContext) { +export async function getServerSideProps(_context: GetServerSidePropsContext) { if (!IS_CLOUD) { return { redirect: { diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index da3121b2e..31a50c67b 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -33,7 +33,7 @@ import { } from "../trpc"; export const authRouter = createTRPCRouter({ - createAdmin: publicProcedure.mutation(async ({ ctx, input }) => { + createAdmin: publicProcedure.mutation(async ({ input }) => { try { if (!IS_CLOUD) { const admin = await db.query.admins.findFirst({}); @@ -72,9 +72,9 @@ export const authRouter = createTRPCRouter({ }); } }), - createUser: publicProcedure.mutation(async ({ ctx, input }) => { + createUser: publicProcedure.mutation(async ({ input }) => { try { - const token = await getUserByToken(input.token); + const _token = await getUserByToken(input.token); // if (token.isExpired) { // throw new TRPCError({ // code: "BAD_REQUEST", @@ -103,7 +103,7 @@ export const authRouter = createTRPCRouter({ } }), - login: publicProcedure.mutation(async ({ ctx, input }) => { + login: publicProcedure.mutation(async ({ input }) => { try { const auth = await findAuthByEmail(input.email); @@ -169,7 +169,7 @@ export const authRouter = createTRPCRouter({ }), logout: protectedProcedure.mutation(async ({ ctx }) => { - const { req, res } = ctx; + const { req } = ctx; const { session } = await validateRequest(req); if (!session) return false; @@ -229,7 +229,7 @@ export const authRouter = createTRPCRouter({ message: "Password is incorrect", }); } - const { req, res } = ctx; + const { req } = ctx; const { session } = await validateRequest(req); if (!session) return false; @@ -245,7 +245,7 @@ export const authRouter = createTRPCRouter({ return true; }), - generateToken: protectedProcedure.mutation(async ({ ctx, input }) => { + generateToken: protectedProcedure.mutation(async ({ ctx }) => { const auth = await findUserById(ctx.user.id); console.log(auth); @@ -276,7 +276,7 @@ export const authRouter = createTRPCRouter({ email: z.string().min(1).email(), }), ) - .mutation(async ({ ctx, input }) => { + .mutation(async ({ input }) => { if (!IS_CLOUD) { throw new TRPCError({ code: "NOT_FOUND", @@ -329,7 +329,7 @@ export const authRouter = createTRPCRouter({ password: z.string().min(1), }), ) - .mutation(async ({ ctx, input }) => { + .mutation(async ({ input }) => { if (!IS_CLOUD) { throw new TRPCError({ code: "NOT_FOUND", @@ -373,7 +373,7 @@ export const authRouter = createTRPCRouter({ confirmationToken: z.string().min(1), }), ) - .mutation(async ({ ctx, input }) => { + .mutation(async ({ input }) => { if (!IS_CLOUD) { throw new TRPCError({ code: "NOT_FOUND", diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts index 3215226e3..1ebb161a4 100644 --- a/apps/dokploy/server/api/routers/server.ts +++ b/apps/dokploy/server/api/routers/server.ts @@ -12,6 +12,7 @@ import { mariadb, mongo, mysql, + organization, postgres, redis, server, @@ -102,6 +103,18 @@ export const serverRouter = createTRPCRouter({ return result; }), + count: protectedProcedure.query(async ({ ctx }) => { + const organizations = await db.query.organization.findMany({ + where: eq(organization.ownerId, ctx.user.id), + with: { + servers: true, + }, + }); + + const servers = organizations.flatMap((org) => org.servers); + + return servers.length ?? 0; + }), withSSHKey: protectedProcedure.query(async ({ ctx }) => { const result = await db.query.server.findMany({ orderBy: desc(server.createdAt), diff --git a/apps/dokploy/server/api/routers/stripe.ts b/apps/dokploy/server/api/routers/stripe.ts index 0e0e07a47..a226eeac8 100644 --- a/apps/dokploy/server/api/routers/stripe.ts +++ b/apps/dokploy/server/api/routers/stripe.ts @@ -56,7 +56,7 @@ export const stripeRouter = createTRPCRouter({ }); const items = getStripeItems(input.serverQuantity, input.isAnnual); - const user = await findUserById(ctx.user.ownerId); + const user = await findUserById(ctx.user.id); let stripeCustomerId = user.stripeCustomerId; @@ -78,7 +78,7 @@ export const stripeRouter = createTRPCRouter({ customer: stripeCustomerId, }), metadata: { - ownerId: user.id, + adminId: user.id, }, allow_promotion_codes: true, success_url: `${WEBSITE_URL}/dashboard/settings/servers?success=true`, @@ -88,7 +88,7 @@ export const stripeRouter = createTRPCRouter({ return { sessionId: session.id }; }), createCustomerPortalSession: adminProcedure.mutation(async ({ ctx }) => { - const user = await findUserById(ctx.user.ownerId); + const user = await findUserById(ctx.user.id); if (!user.stripeCustomerId) { throw new TRPCError({ diff --git a/apps/dokploy/server/db/seed.ts b/apps/dokploy/server/db/seed.ts index 3216a44b4..5b3eb6c62 100644 --- a/apps/dokploy/server/db/seed.ts +++ b/apps/dokploy/server/db/seed.ts @@ -1,15 +1,10 @@ -import bc from "bcrypt"; 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); - -function password(txt: string) { - return bc.hashSync(txt, 10); -} +const _db = drizzle(pg); async function seed() { console.log("> Seed:", process.env.DATABASE_PATH, "\n"); diff --git a/apps/dokploy/server/utils/docker.ts b/apps/dokploy/server/utils/docker.ts index 92008678f..3314eb62e 100644 --- a/apps/dokploy/server/utils/docker.ts +++ b/apps/dokploy/server/utils/docker.ts @@ -6,7 +6,7 @@ export const isWSL = async () => { const { stdout } = await execAsync("uname -r"); const isWSL = stdout.includes("microsoft"); return isWSL; - } catch (error) { + } catch (_error) { return false; } }; diff --git a/apps/dokploy/server/wss/docker-container-terminal.ts b/apps/dokploy/server/wss/docker-container-terminal.ts index 04ef5c96c..2f25edb1a 100644 --- a/apps/dokploy/server/wss/docker-container-terminal.ts +++ b/apps/dokploy/server/wss/docker-container-terminal.ts @@ -50,8 +50,8 @@ export const setupDockerContainerTerminalWebSocketServer = ( throw new Error("No SSH key available for this server"); const conn = new Client(); - let stdout = ""; - let stderr = ""; + let _stdout = ""; + let _stderr = ""; conn .once("ready", () => { conn.exec( @@ -61,16 +61,16 @@ export const setupDockerContainerTerminalWebSocketServer = ( if (err) throw err; stream - .on("close", (code: number, signal: string) => { + .on("close", (code: number, _signal: string) => { ws.send(`\nContainer closed with code: ${code}\n`); conn.end(); }) .on("data", (data: string) => { - stdout += data.toString(); + _stdout += data.toString(); ws.send(data.toString()); }) .stderr.on("data", (data) => { - stderr += data.toString(); + _stderr += data.toString(); ws.send(data.toString()); console.error("Error: ", data.toString()); }); diff --git a/apps/dokploy/server/wss/drawer-logs.ts b/apps/dokploy/server/wss/drawer-logs.ts index 9fe947ffa..404dfeee5 100644 --- a/apps/dokploy/server/wss/drawer-logs.ts +++ b/apps/dokploy/server/wss/drawer-logs.ts @@ -32,7 +32,7 @@ export const setupDrawerLogsWebSocketServer = ( }); wssTerm.on("connection", async (ws, req) => { - const url = new URL(req.url || "", `http://${req.headers.host}`); + const _url = new URL(req.url || "", `http://${req.headers.host}`); const { user, session } = await validateRequest(req); if (!user || !session) { diff --git a/apps/dokploy/server/wss/listen-deployment.ts b/apps/dokploy/server/wss/listen-deployment.ts index ee470fcbf..4a25c6f0e 100644 --- a/apps/dokploy/server/wss/listen-deployment.ts +++ b/apps/dokploy/server/wss/listen-deployment.ts @@ -103,7 +103,7 @@ export const setupDeploymentLogsWebSocketServer = ( ws.close(); }); } - } catch (error) { + } catch (_error) { // @ts-ignore // const errorMessage = error?.message as unknown as string; // ws.send(errorMessage); diff --git a/apps/dokploy/server/wss/terminal.ts b/apps/dokploy/server/wss/terminal.ts index 6e9c3614f..094c5e157 100644 --- a/apps/dokploy/server/wss/terminal.ts +++ b/apps/dokploy/server/wss/terminal.ts @@ -144,8 +144,8 @@ export const setupTerminalWebSocketServer = ( } const conn = new Client(); - let stdout = ""; - let stderr = ""; + let _stdout = ""; + let _stderr = ""; ws.send("Connecting...\n"); @@ -158,16 +158,16 @@ export const setupTerminalWebSocketServer = ( if (err) throw err; stream - .on("close", (code: number, signal: string) => { + .on("close", (code: number, _signal: string) => { ws.send(`\nContainer closed with code: ${code}\n`); conn.end(); }) .on("data", (data: string) => { - stdout += data.toString(); + _stdout += data.toString(); ws.send(data.toString()); }) .stderr.on("data", (data) => { - stderr += data.toString(); + _stderr += data.toString(); ws.send(data.toString()); console.error("Error: ", data.toString()); }); diff --git a/apps/dokploy/templates/appsmith/index.ts b/apps/dokploy/templates/appsmith/index.ts index ff744a249..73279e91b 100644 --- a/apps/dokploy/templates/appsmith/index.ts +++ b/apps/dokploy/templates/appsmith/index.ts @@ -7,7 +7,7 @@ import { } from "../utils"; export function generate(schema: Schema): Template { - const mainServiceHash = generateHash(schema.projectName); + const _mainServiceHash = generateHash(schema.projectName); const domains: DomainSchema[] = [ { diff --git a/apps/dokploy/templates/blender/index.ts b/apps/dokploy/templates/blender/index.ts index 84e527554..79508bed5 100644 --- a/apps/dokploy/templates/blender/index.ts +++ b/apps/dokploy/templates/blender/index.ts @@ -7,7 +7,7 @@ import { } from "../utils"; export function generate(schema: Schema): Template { - const mainServiceHash = generateHash(schema.projectName); + const _mainServiceHash = generateHash(schema.projectName); const mainDomain = generateRandomDomain(schema); const domains: DomainSchema[] = [ diff --git a/apps/dokploy/templates/cloudflared/index.ts b/apps/dokploy/templates/cloudflared/index.ts index 661fa31d0..93ea091c6 100644 --- a/apps/dokploy/templates/cloudflared/index.ts +++ b/apps/dokploy/templates/cloudflared/index.ts @@ -1,6 +1,6 @@ import type { Schema, Template } from "../utils"; -export function generate(schema: Schema): Template { +export function generate(_schema: Schema): Template { const envs = [`CLOUDFLARE_TUNNEL_TOKEN=""`]; return { diff --git a/apps/dokploy/templates/drawio/index.ts b/apps/dokploy/templates/drawio/index.ts index e3c57c5a5..701283c8d 100644 --- a/apps/dokploy/templates/drawio/index.ts +++ b/apps/dokploy/templates/drawio/index.ts @@ -8,7 +8,7 @@ import { export function generate(schema: Schema): Template { const mainDomain = generateRandomDomain(schema); - const secretKeyBase = generateBase64(64); + const _secretKeyBase = generateBase64(64); const domains: DomainSchema[] = [ { diff --git a/apps/dokploy/templates/immich/index.ts b/apps/dokploy/templates/immich/index.ts index b1b11afb1..4beca87da 100644 --- a/apps/dokploy/templates/immich/index.ts +++ b/apps/dokploy/templates/immich/index.ts @@ -11,7 +11,7 @@ export function generate(schema: Schema): Template { const mainDomain = generateRandomDomain(schema); const dbPassword = generatePassword(); const dbUser = "immich"; - const appSecret = generateBase64(32); + const _appSecret = generateBase64(32); const domains: DomainSchema[] = [ { diff --git a/apps/dokploy/templates/unifi/index.ts b/apps/dokploy/templates/unifi/index.ts index 975ce63d9..ea67b0fae 100644 --- a/apps/dokploy/templates/unifi/index.ts +++ b/apps/dokploy/templates/unifi/index.ts @@ -1,6 +1,6 @@ import type { Schema, Template } from "../utils"; -export function generate(schema: Schema): Template { +export function generate(_schema: Schema): Template { const mounts: Template["mounts"] = [ { filePath: "init-mongo.sh", diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts index 80d533508..bf72f7db3 100644 --- a/packages/server/src/db/schema/certificate.ts +++ b/packages/server/src/db/schema/certificate.ts @@ -28,19 +28,16 @@ export const certificates = pgTable("certificate", { }), }); -export const certificatesRelations = relations( - certificates, - ({ one, many }) => ({ - server: one(server, { - fields: [certificates.serverId], - references: [server.serverId], - }), - organization: one(organization, { - fields: [certificates.organizationId], - references: [organization.id], - }), +export const certificatesRelations = relations(certificates, ({ one }) => ({ + server: one(server, { + fields: [certificates.serverId], + references: [server.serverId], }), -); + organization: one(organization, { + fields: [certificates.organizationId], + references: [organization.id], + }), +})); export const apiCreateCertificate = createInsertSchema(certificates, { name: z.string().min(1), diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index dc88131a9..922307376 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -29,7 +29,7 @@ export const gitProvider = pgTable("git_provider", { .references(() => organization.id, { onDelete: "cascade" }), }); -export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({ +export const gitProviderRelations = relations(gitProvider, ({ one }) => ({ github: one(github, { fields: [gitProvider.gitProviderId], references: [github.gitProviderId], diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index 35526f90c..b18747095 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -32,7 +32,7 @@ export const registry = pgTable("registry", { .references(() => organization.id, { onDelete: "cascade" }), }); -export const registryRelations = relations(registry, ({ one, many }) => ({ +export const registryRelations = relations(registry, ({ many }) => ({ applications: many(applications), })); diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index a8d75637b..192f6d0ea 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -2,14 +2,12 @@ import type { IncomingMessage } from "node:http"; import * as bcrypt from "bcrypt"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; -import { - createAuthMiddleware, - organization, - twoFactor, -} from "better-auth/plugins"; +import { organization, twoFactor } from "better-auth/plugins"; import { and, desc, eq } from "drizzle-orm"; import { db } from "../db"; import * as schema from "../db/schema"; +import { sendVerificationEmail } from "../verification/send-verification-email"; +import { IS_CLOUD } from "../constants"; export const auth = betterAuth({ database: drizzleAdapter(db, { @@ -27,9 +25,18 @@ export const auth = betterAuth({ clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }, }, + emailVerification: { + sendOnSignUp: true, + autoSignInAfterVerification: true, + sendVerificationEmail: async ({ user, url }) => { + console.log("Sending verification email to", user.email); + await sendVerificationEmail(user.email, url); + }, + }, emailAndPassword: { enabled: true, - + autoSignIn: !IS_CLOUD, + requireEmailVerification: IS_CLOUD, password: { async hash(password) { return bcrypt.hashSync(password, 10); @@ -39,33 +46,37 @@ export const auth = betterAuth({ }, }, }, - hooks: { - after: createAuthMiddleware(async (ctx) => { - if (ctx.path.startsWith("/sign-up")) { - const newSession = ctx.context.newSession; - if (ctx.headers?.get("x-dokploy-token")) { - } else { - const organization = await db - .insert(schema.organization) - .values({ - name: "My Organization", - ownerId: newSession?.user?.id || "", - createdAt: new Date(), - }) - .returning() - .then((res) => res[0]); - - await db.insert(schema.member).values({ - userId: newSession?.user?.id || "", - organizationId: organization?.id || "", - role: "owner", - createdAt: new Date(), - }); - } - } - }), - }, databaseHooks: { + user: { + create: { + after: async (user) => { + const isAdminPresent = await db.query.member.findFirst({ + where: eq(schema.member.role, "owner"), + }); + + if (IS_CLOUD || !isAdminPresent) { + await db.transaction(async (tx) => { + const organization = await tx + .insert(schema.organization) + .values({ + name: "My Organization", + ownerId: user.id, + createdAt: new Date(), + }) + .returning() + .then((res) => res[0]); + + await tx.insert(schema.member).values({ + userId: user.id, + organizationId: organization?.id || "", + role: "owner", + createdAt: new Date(), + }); + }); + } + }, + }, + }, session: { create: { before: async (session) => { @@ -106,7 +117,7 @@ export const auth = betterAuth({ plugins: [ twoFactor(), organization({ - async sendInvitationEmail(data, request) { + async sendInvitationEmail(data, _request) { const inviteLink = `https://example.com/accept-invitation/${data.id}`; // https://example.com/accept-invitation/8jlBi9Tb9isDb8mc8Sb85u1BaJYklKB2 // sendOrganizationInvitation({ diff --git a/packages/server/src/lib/crypto.ts b/packages/server/src/lib/crypto.ts deleted file mode 100644 index 27d86dbd5..000000000 --- a/packages/server/src/lib/crypto.ts +++ /dev/null @@ -1,94 +0,0 @@ -// import { -// decodeHex, -// encodeBase32LowerCaseNoPadding, -// encodeHexLowerCase, -// } from "@oslojs/encoding"; -// import { generateRandomString } from "@oslojs/crypto/random"; -// import { constantTimeEqual } from "@oslojs/crypto/subtle"; -// import { scrypt } from "./scrypt/index"; - -// import type { RandomReader } from "@oslojs/crypto/random"; - -// async function generateScryptKey( -// data: string, -// salt: string, -// blockSize = 16, -// ): Promise { -// const encodedData = new TextEncoder().encode(data); -// const encodedSalt = new TextEncoder().encode(salt); -// const keyUint8Array = await scrypt(encodedData, encodedSalt, { -// N: 16384, -// r: blockSize, -// p: 1, -// dkLen: 64, -// }); -// return new Uint8Array(keyUint8Array); -// } - -// const random: RandomReader = { -// read(bytes: Uint8Array): void { -// crypto.getRandomValues(bytes); -// }, -// }; - -// export function generateId(length: number): string { -// const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; -// return generateRandomString(random, alphabet, length); -// } - -// export function generateIdFromEntropySize(size: number): string { -// const buffer = crypto.getRandomValues(new Uint8Array(size)); -// return encodeBase32LowerCaseNoPadding(buffer); -// } - -// export class Scrypt implements PasswordHashingAlgorithm { -// async hash(password: string): Promise { -// const salt = encodeHexLowerCase(crypto.getRandomValues(new Uint8Array(16))); -// const key = await generateScryptKey(password.normalize("NFKC"), salt); -// return `${salt}:${encodeHexLowerCase(key)}`; -// } -// async verify(hash: string, password: string): Promise { -// const parts = hash.split(":"); -// if (parts.length !== 2) return false; - -// const [salt, key] = parts; -// const targetKey = await generateScryptKey(password.normalize("NFKC"), salt); -// return constantTimeEqual(targetKey, decodeHex(key)); -// } -// } - -// export class LegacyScrypt implements PasswordHashingAlgorithm { -// async hash(password: string): Promise { -// const salt = encodeHexLowerCase(crypto.getRandomValues(new Uint8Array(16))); -// const key = await generateScryptKey(password.normalize("NFKC"), salt); -// return `s2:${salt}:${encodeHexLowerCase(key)}`; -// } -// async verify(hash: string, password: string): Promise { -// const parts = hash.split(":"); -// if (parts.length === 2) { -// const [salt, key] = parts; -// const targetKey = await generateScryptKey( -// password.normalize("NFKC"), -// salt, -// 8, -// ); -// const result = constantTimeEqual(targetKey, decodeHex(key)); -// return result; -// } -// if (parts.length !== 3) return false; -// const [version, salt, key] = parts; -// if (version === "s2") { -// const targetKey = await generateScryptKey( -// password.normalize("NFKC"), -// salt, -// ); -// return constantTimeEqual(targetKey, decodeHex(key)); -// } -// return false; -// } -// } - -// export interface PasswordHashingAlgorithm { -// hash(password: string): Promise; -// verify(hash: string, password: string): Promise; -// } diff --git a/packages/server/src/lib/scrypt/index.ts b/packages/server/src/lib/scrypt/index.ts deleted file mode 100644 index 8337712ea..000000000 --- a/packages/server/src/lib/scrypt/index.ts +++ /dev/null @@ -1 +0,0 @@ -// diff --git a/packages/server/src/monitoring/utils.ts b/packages/server/src/monitoring/utils.ts index 561cc8355..147ade0ad 100644 --- a/packages/server/src/monitoring/utils.ts +++ b/packages/server/src/monitoring/utils.ts @@ -73,7 +73,7 @@ export const readStatsFile = async ( const filePath = `${MONITORING_PATH}/${appName}/${statType}.json`; const data = await promises.readFile(filePath, "utf-8"); return JSON.parse(data); - } catch (error) { + } catch (_error) { return []; } }; @@ -108,7 +108,7 @@ export const readLastValueStatsFile = async ( const data = await promises.readFile(filePath, "utf-8"); const stats = JSON.parse(data); return stats[stats.length - 1] || null; - } catch (error) { + } catch (_error) { return null; } }; diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index 1e2b569f4..78df14aa4 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -12,8 +12,8 @@ import { IS_CLOUD } from "../constants"; export type User = typeof users_temp.$inferSelect; export const createInvitation = async ( - input: typeof apiCreateUserInvitation._type, - adminId: string, + _input: typeof apiCreateUserInvitation._type, + _adminId: string, ) => { // await db.transaction(async (tx) => { // const result = await tx @@ -83,8 +83,8 @@ export const updateUser = async (userId: string, userData: Partial) => { }; export const updateAdminById = async ( - adminId: string, - adminData: Partial, + _adminId: string, + _adminData: Partial, ) => { // const admin = await db // .update(admins) @@ -102,8 +102,6 @@ export const isAdminPresent = async () => { where: eq(member.role, "owner"), }); - console.log("admin", admin); - if (!admin) { return false; } diff --git a/packages/server/src/services/docker.ts b/packages/server/src/services/docker.ts index 597c03fa1..a4a3b0b5e 100644 --- a/packages/server/src/services/docker.ts +++ b/packages/server/src/services/docker.ts @@ -98,7 +98,7 @@ export const getConfig = async ( const config = JSON.parse(stdout); return config; - } catch (error) {} + } catch (_error) {} }; export const getContainersByAppNameMatch = async ( @@ -156,7 +156,7 @@ export const getContainersByAppNameMatch = async ( }); return containers || []; - } catch (error) {} + } catch (_error) {} return []; }; @@ -214,7 +214,7 @@ export const getStackContainersByAppName = async ( }); return containers || []; - } catch (error) {} + } catch (_error) {} return []; }; @@ -274,7 +274,7 @@ export const getServiceContainersByAppName = async ( }); return containers || []; - } catch (error) {} + } catch (_error) {} return []; }; @@ -325,7 +325,7 @@ export const getContainersByAppLabel = async ( }); return containers || []; - } catch (error) {} + } catch (_error) {} return []; }; @@ -344,7 +344,7 @@ export const containerRestart = async (containerId: string) => { const config = JSON.parse(stdout); return config; - } catch (error) {} + } catch (_error) {} }; export const getSwarmNodes = async (serverId?: string) => { @@ -373,7 +373,7 @@ export const getSwarmNodes = async (serverId?: string) => { .split("\n") .map((line) => JSON.parse(line)); return nodesArray; - } catch (error) {} + } catch (_error) {} }; export const getNodeInfo = async (nodeId: string, serverId?: string) => { @@ -399,7 +399,7 @@ export const getNodeInfo = async (nodeId: string, serverId?: string) => { const nodeInfo = JSON.parse(stdout); return nodeInfo; - } catch (error) {} + } catch (_error) {} }; export const getNodeApplications = async (serverId?: string) => { @@ -431,7 +431,7 @@ export const getNodeApplications = async (serverId?: string) => { .filter((service) => !service.Name.startsWith("dokploy-")); return appArray; - } catch (error) {} + } catch (_error) {} }; export const getApplicationInfo = async ( @@ -464,5 +464,5 @@ export const getApplicationInfo = async ( .map((line) => JSON.parse(line)); return appArray; - } catch (error) {} + } catch (_error) {} }; diff --git a/packages/server/src/services/github.ts b/packages/server/src/services/github.ts index deb5f3fa2..19deb2b24 100644 --- a/packages/server/src/services/github.ts +++ b/packages/server/src/services/github.ts @@ -119,7 +119,7 @@ export const issueCommentExists = async ({ comment_id: comment_id, }); return true; - } catch (error) { + } catch (_error) { return false; } }; diff --git a/packages/server/src/services/mount.ts b/packages/server/src/services/mount.ts index 55557ea0e..836feacec 100644 --- a/packages/server/src/services/mount.ts +++ b/packages/server/src/services/mount.ts @@ -211,7 +211,7 @@ export const deleteFileMount = async (mountId: string) => { } else { await removeFileOrDirectory(fullPath); } - } catch (error) {} + } catch (_error) {} }; export const getBaseFilesPath = async (mountId: string) => { diff --git a/packages/server/src/services/preview-deployment.ts b/packages/server/src/services/preview-deployment.ts index 775621773..a1ffca4ba 100644 --- a/packages/server/src/services/preview-deployment.ts +++ b/packages/server/src/services/preview-deployment.ts @@ -103,7 +103,7 @@ export const removePreviewDeployment = async (previewDeploymentId: string) => { for (const operation of cleanupOperations) { try { await operation(); - } catch (error) {} + } catch (_error) {} } return deployment[0]; } catch (error) { diff --git a/packages/server/src/setup/monitoring-setup.ts b/packages/server/src/setup/monitoring-setup.ts index afadb6c10..75b9a928f 100644 --- a/packages/server/src/setup/monitoring-setup.ts +++ b/packages/server/src/setup/monitoring-setup.ts @@ -66,7 +66,7 @@ export const setupMonitoring = async (serverId: string) => { await container.inspect(); await container.remove({ force: true }); console.log("Removed existing container"); - } catch (error) { + } catch (_error) { // Container doesn't exist, continue } @@ -135,7 +135,7 @@ export const setupWebMonitoring = async (userId: string) => { await container.inspect(); await container.remove({ force: true }); console.log("Removed existing container"); - } catch (error) {} + } catch (_error) {} await docker.createContainer(settings); const newContainer = docker.getContainer(containerName); diff --git a/packages/server/src/setup/postgres-setup.ts b/packages/server/src/setup/postgres-setup.ts index b5794c2b2..55361b689 100644 --- a/packages/server/src/setup/postgres-setup.ts +++ b/packages/server/src/setup/postgres-setup.ts @@ -56,7 +56,7 @@ export const initializePostgres = async () => { }); console.log("Postgres Started ✅"); - } catch (error) { + } catch (_error) { await docker.createService(settings); console.log("Postgres Not Found: Starting ✅"); } diff --git a/packages/server/src/setup/redis-setup.ts b/packages/server/src/setup/redis-setup.ts index 1c3b545a5..774e41927 100644 --- a/packages/server/src/setup/redis-setup.ts +++ b/packages/server/src/setup/redis-setup.ts @@ -52,7 +52,7 @@ export const initializeRedis = async () => { ...settings, }); console.log("Redis Started ✅"); - } catch (error) { + } catch (_error) { await docker.createService(settings); console.log("Redis Not Found: Starting ✅"); } diff --git a/packages/server/src/setup/server-audit.ts b/packages/server/src/setup/server-audit.ts index df00e9a74..b9283c313 100644 --- a/packages/server/src/setup/server-audit.ts +++ b/packages/server/src/setup/server-audit.ts @@ -89,7 +89,7 @@ export const serverAudit = async (serverId: string) => { .on("data", (data: string) => { output += data; }) - .stderr.on("data", (data) => {}); + .stderr.on("data", (_data) => {}); }); }) .on("error", (err) => { diff --git a/packages/server/src/setup/server-validate.ts b/packages/server/src/setup/server-validate.ts index 4ca21df85..c86206b61 100644 --- a/packages/server/src/setup/server-validate.ts +++ b/packages/server/src/setup/server-validate.ts @@ -128,7 +128,7 @@ export const serverValidate = async (serverId: string) => { .on("data", (data: string) => { output += data; }) - .stderr.on("data", (data) => {}); + .stderr.on("data", (_data) => {}); }); }) .on("error", (err) => { diff --git a/packages/server/src/setup/setup.ts b/packages/server/src/setup/setup.ts index c59877022..eeef32dd2 100644 --- a/packages/server/src/setup/setup.ts +++ b/packages/server/src/setup/setup.ts @@ -18,7 +18,7 @@ export const dockerSwarmInitialized = async () => { await docker.swarmInspect(); return true; - } catch (e) { + } catch (_e) { return false; } }; @@ -41,7 +41,7 @@ export const dockerNetworkInitialized = async () => { try { await docker.getNetwork("dokploy-network").inspect(); return true; - } catch (e) { + } catch (_e) { return false; } }; diff --git a/packages/server/src/setup/traefik-setup.ts b/packages/server/src/setup/traefik-setup.ts index 1d60e577c..4fb570f2d 100644 --- a/packages/server/src/setup/traefik-setup.ts +++ b/packages/server/src/setup/traefik-setup.ts @@ -127,7 +127,7 @@ export const initializeTraefik = async ({ }); console.log("Traefik Started ✅"); - } catch (error) { + } catch (_error) { await docker.createService(settings); console.log("Traefik Not Found: Starting ✅"); } diff --git a/packages/server/src/types/with.ts b/packages/server/src/types/with.ts index c4826f734..467020a21 100644 --- a/packages/server/src/types/with.ts +++ b/packages/server/src/types/with.ts @@ -36,7 +36,7 @@ type AnyObj = Record; type ZodObj = { [key in keyof T]: z.ZodType; }; -const zObject = (arg: ZodObj) => z.object(arg); +const _zObject = (arg: ZodObj) => z.object(arg); // const goodDogScheme = zObject({ // // prueba: schema.selectDatabaseSchema, diff --git a/packages/server/src/utils/access-log/handler.ts b/packages/server/src/utils/access-log/handler.ts index 5cff7f837..bbd32cff2 100644 --- a/packages/server/src/utils/access-log/handler.ts +++ b/packages/server/src/utils/access-log/handler.ts @@ -32,7 +32,7 @@ class LogRotationManager { // return setting?.enableLogRotation ?? false; } - private async setStateInDB(active: boolean): Promise { + private async setStateInDB(_active: boolean): Promise { // const admin = await db.query.admins.findFirst({}); // if (!admin) { // return; diff --git a/packages/server/src/utils/backups/utils.ts b/packages/server/src/utils/backups/utils.ts index 0d78ff961..c76f79626 100644 --- a/packages/server/src/utils/backups/utils.ts +++ b/packages/server/src/utils/backups/utils.ts @@ -28,7 +28,7 @@ export const removeScheduleBackup = (backupId: string) => { }; export const getS3Credentials = (destination: Destination) => { - const { accessKey, secretAccessKey, bucket, region, endpoint, provider } = + const { accessKey, secretAccessKey, region, endpoint, provider } = destination; const rcloneFlags = [ `--s3-access-key-id=${accessKey}`, diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts index cbf951c73..19e7d1529 100644 --- a/packages/server/src/utils/builders/compose.ts +++ b/packages/server/src/utils/builders/compose.ts @@ -98,8 +98,7 @@ export const getBuildComposeCommand = async ( logPath: string, ) => { const { COMPOSE_PATH } = paths(true); - const { sourceType, appName, mounts, composeType, domains, composePath } = - compose; + const { sourceType, appName, mounts, composeType, domains } = compose; const command = createCommand(compose); const envCommand = getCreateEnvFileCommand(compose); const projectPath = join(COMPOSE_PATH, compose.appName, "code"); diff --git a/packages/server/src/utils/builders/index.ts b/packages/server/src/utils/builders/index.ts index d67482755..d777b1a36 100644 --- a/packages/server/src/utils/builders/index.ts +++ b/packages/server/src/utils/builders/index.ts @@ -197,7 +197,7 @@ export const mechanizeDockerContainer = async ( ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1, }, }); - } catch (error) { + } catch (_error) { await docker.createService(settings); } }; diff --git a/packages/server/src/utils/builders/nixpacks.ts b/packages/server/src/utils/builders/nixpacks.ts index 56560e4e2..c13f82a56 100644 --- a/packages/server/src/utils/builders/nixpacks.ts +++ b/packages/server/src/utils/builders/nixpacks.ts @@ -91,7 +91,7 @@ export const getNixpacksCommand = ( application: ApplicationNested, logPath: string, ) => { - const { env, appName, publishDirectory, serverId } = application; + const { env, appName, publishDirectory } = application; const buildAppDirectory = getBuildAppDirectory(application); const buildContainerId = `${appName}-${nanoid(10)}`; diff --git a/packages/server/src/utils/databases/mariadb.ts b/packages/server/src/utils/databases/mariadb.ts index d1b41fc33..ead5a618a 100644 --- a/packages/server/src/utils/databases/mariadb.ts +++ b/packages/server/src/utils/databases/mariadb.ts @@ -98,7 +98,7 @@ export const buildMariadb = async (mariadb: MariadbNested) => { version: Number.parseInt(inspect.Version.Index), ...settings, }); - } catch (error) { + } catch (_error) { await docker.createService(settings); } }; diff --git a/packages/server/src/utils/databases/mongo.ts b/packages/server/src/utils/databases/mongo.ts index 5af58eef7..ace9c9721 100644 --- a/packages/server/src/utils/databases/mongo.ts +++ b/packages/server/src/utils/databases/mongo.ts @@ -152,7 +152,7 @@ ${command ?? "wait $MONGOD_PID"}`; version: Number.parseInt(inspect.Version.Index), ...settings, }); - } catch (error) { + } catch (_error) { await docker.createService(settings); } }; diff --git a/packages/server/src/utils/databases/mysql.ts b/packages/server/src/utils/databases/mysql.ts index 5a6911771..de28cfe6b 100644 --- a/packages/server/src/utils/databases/mysql.ts +++ b/packages/server/src/utils/databases/mysql.ts @@ -104,7 +104,7 @@ export const buildMysql = async (mysql: MysqlNested) => { version: Number.parseInt(inspect.Version.Index), ...settings, }); - } catch (error) { + } catch (_error) { await docker.createService(settings); } }; diff --git a/packages/server/src/utils/databases/redis.ts b/packages/server/src/utils/databases/redis.ts index 724069a17..aef862802 100644 --- a/packages/server/src/utils/databases/redis.ts +++ b/packages/server/src/utils/databases/redis.ts @@ -95,7 +95,7 @@ export const buildRedis = async (redis: RedisNested) => { version: Number.parseInt(inspect.Version.Index), ...settings, }); - } catch (error) { + } catch (_error) { await docker.createService(settings); } }; diff --git a/packages/server/src/utils/docker/domain.ts b/packages/server/src/utils/docker/domain.ts index 8a1b0608f..c4ced3f44 100644 --- a/packages/server/src/utils/docker/domain.ts +++ b/packages/server/src/utils/docker/domain.ts @@ -109,7 +109,7 @@ export const loadDockerComposeRemote = async ( if (!stdout) return null; const parsedConfig = load(stdout) as ComposeSpecification; return parsedConfig; - } catch (err) { + } catch (_err) { return null; } }; diff --git a/packages/server/src/utils/docker/utils.ts b/packages/server/src/utils/docker/utils.ts index 062e07226..71b7e4aac 100644 --- a/packages/server/src/utils/docker/utils.ts +++ b/packages/server/src/utils/docker/utils.ts @@ -100,7 +100,7 @@ export const containerExists = async (containerName: string) => { try { await container.inspect(); return true; - } catch (error) { + } catch (_error) { return false; } }; @@ -240,7 +240,7 @@ export const startServiceRemote = async (serverId: string, appName: string) => { export const removeService = async ( appName: string, serverId?: string | null, - deleteVolumes = false, + _deleteVolumes = false, ) => { try { const command = `docker service rm ${appName}`; diff --git a/packages/server/src/utils/gpu-setup.ts b/packages/server/src/utils/gpu-setup.ts index 6a6611b4a..a815a00cc 100644 --- a/packages/server/src/utils/gpu-setup.ts +++ b/packages/server/src/utils/gpu-setup.ts @@ -34,7 +34,7 @@ export async function checkGPUStatus(serverId?: string): Promise { ...gpuInfo, ...cudaInfo, }; - } catch (error) { + } catch (_error) { return { driverInstalled: false, driverVersion: undefined, @@ -315,7 +315,7 @@ const setupLocalServer = async (daemonConfig: any) => { try { await execAsync(setupCommands); - } catch (error) { + } catch (_error) { throw new Error( "Failed to configure GPU support. Please ensure you have sudo privileges and try again.", ); diff --git a/packages/server/src/utils/process/execAsync.ts b/packages/server/src/utils/process/execAsync.ts index 19a16ac1e..aee1e821a 100644 --- a/packages/server/src/utils/process/execAsync.ts +++ b/packages/server/src/utils/process/execAsync.ts @@ -27,7 +27,7 @@ export const execAsyncRemote = async ( throw err; } stream - .on("close", (code: number, signal: string) => { + .on("close", (code: number, _signal: string) => { conn.end(); if (code === 0) { resolve({ stdout, stderr }); diff --git a/packages/server/src/utils/providers/bitbucket.ts b/packages/server/src/utils/providers/bitbucket.ts index 7059e65f7..dd98a93bd 100644 --- a/packages/server/src/utils/providers/bitbucket.ts +++ b/packages/server/src/utils/providers/bitbucket.ts @@ -176,7 +176,6 @@ export const getBitbucketCloneCommand = async ( bitbucketBranch, bitbucketId, serverId, - bitbucket, } = entity; if (!serverId) { diff --git a/packages/server/src/utils/providers/git.ts b/packages/server/src/utils/providers/git.ts index 8f8a38301..c26af3af2 100644 --- a/packages/server/src/utils/providers/git.ts +++ b/packages/server/src/utils/providers/git.ts @@ -320,7 +320,7 @@ export const cloneGitRawRepository = async (entity: { outputPath, "--progress", ], - (data) => {}, + (_data) => {}, { env: { ...process.env, diff --git a/packages/server/src/utils/providers/gitlab.ts b/packages/server/src/utils/providers/gitlab.ts index a2c4b8ccb..c380a9203 100644 --- a/packages/server/src/utils/providers/gitlab.ts +++ b/packages/server/src/utils/providers/gitlab.ts @@ -162,8 +162,6 @@ export const getGitlabCloneCommand = async ( ) => { const { appName, - gitlabRepository, - gitlabOwner, gitlabPathNamespace, gitlabBranch, gitlabId, @@ -328,14 +326,7 @@ export const getGitlabBranches = async (input: { }; export const cloneRawGitlabRepository = async (entity: Compose) => { - const { - appName, - gitlabRepository, - gitlabOwner, - gitlabBranch, - gitlabId, - gitlabPathNamespace, - } = entity; + const { appName, gitlabBranch, gitlabId, gitlabPathNamespace } = entity; if (!gitlabId) { throw new TRPCError({ diff --git a/packages/server/src/utils/traefik/application.ts b/packages/server/src/utils/traefik/application.ts index 4434d8585..61150abf6 100644 --- a/packages/server/src/utils/traefik/application.ts +++ b/packages/server/src/utils/traefik/application.ts @@ -67,7 +67,7 @@ export const removeTraefikConfig = async ( if (fs.existsSync(configPath)) { await fs.promises.unlink(configPath); } - } catch (error) {} + } catch (_error) {} }; export const removeTraefikConfigRemote = async ( @@ -78,7 +78,7 @@ export const removeTraefikConfigRemote = async ( const { DYNAMIC_TRAEFIK_PATH } = paths(true); const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`); await execAsyncRemote(serverId, `rm ${configPath}`); - } catch (error) {} + } catch (_error) {} }; export const loadOrCreateConfig = (appName: string): FileConfig => { @@ -110,7 +110,7 @@ export const loadOrCreateConfigRemote = async ( http: { routers: {}, services: {} }, }; return parsedConfig; - } catch (err) { + } catch (_err) { return fileConfig; } }; @@ -132,7 +132,7 @@ export const readRemoteConfig = async (serverId: string, appName: string) => { const { stdout } = await execAsyncRemote(serverId, `cat ${configPath}`); if (!stdout) return null; return stdout; - } catch (err) { + } catch (_err) { return null; } }; diff --git a/packages/server/src/verification/send-verification-email.tsx b/packages/server/src/verification/send-verification-email.tsx new file mode 100644 index 000000000..0b3b3bdcc --- /dev/null +++ b/packages/server/src/verification/send-verification-email.tsx @@ -0,0 +1,49 @@ +import { + sendDiscordNotification, + sendEmailNotification, +} from "../utils/notifications/utils"; +export const sendVerificationEmail = async (email: string, url: string) => { + await sendEmailNotification( + { + fromAddress: process.env.SMTP_FROM_ADDRESS || "", + toAddresses: [email], + smtpServer: process.env.SMTP_SERVER || "", + smtpPort: Number(process.env.SMTP_PORT), + username: process.env.SMTP_USERNAME || "", + password: process.env.SMTP_PASSWORD || "", + }, + "Confirm your email | Dokploy", + ` + Welcome to Dokploy! + Please confirm your email by clicking the link below: + + Confirm Email + + `, + ); + + return true; +}; + +export const sendDiscordNotificationWelcome = async (email: string) => { + await sendDiscordNotification( + { + webhookUrl: process.env.DISCORD_WEBHOOK_URL || "", + }, + { + title: "New User Registered", + color: 0x00ff00, + fields: [ + { + name: "Email", + value: email, + inline: true, + }, + ], + timestamp: new Date(), + footer: { + text: "Dokploy User Registration Notification", + }, + }, + ); +}; From b00c12965ae38be0968e2342ee8bf76784702df9 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 21:09:21 -0600 Subject: [PATCH 58/89] refactor: update reset password and authentication flows This commit removes several authentication-related components and simplifies the password reset process: - Removed login-2fa component - Deleted confirm-email page - Updated reset password logic to use Drizzle ORM directly - Removed unused authentication-related functions - Simplified server-side authentication routes --- .../server/update-server-config.test.ts | 12 - apps/dokploy/components/auth/login-2fa.tsx | 131 ----------- .../paid/servers/show-paid-monitoring.tsx | 2 +- .../dashboard/settings/profile/enable-2fa.tsx | 6 + .../settings/web-server/update-server-ip.tsx | 2 +- apps/dokploy/pages/api/stripe/webhook.ts | 2 +- apps/dokploy/pages/confirm-email.tsx | 96 -------- apps/dokploy/pages/index.tsx | 1 + apps/dokploy/pages/send-reset-password.tsx | 5 +- apps/dokploy/reset-password.ts | 13 +- apps/dokploy/server/api/routers/auth.ts | 207 +++++------------- apps/dokploy/server/api/routers/server.ts | 59 +++++ apps/dokploy/server/api/routers/user.ts | 59 +++++ packages/server/src/services/admin.ts | 23 +- 14 files changed, 214 insertions(+), 404 deletions(-) delete mode 100644 apps/dokploy/components/auth/login-2fa.tsx delete mode 100644 apps/dokploy/pages/confirm-email.tsx diff --git a/apps/dokploy/__test__/traefik/server/update-server-config.test.ts b/apps/dokploy/__test__/traefik/server/update-server-config.test.ts index 7e4a3c82a..c72d72542 100644 --- a/apps/dokploy/__test__/traefik/server/update-server-config.test.ts +++ b/apps/dokploy/__test__/traefik/server/update-server-config.test.ts @@ -51,20 +51,9 @@ const baseAdmin: User = { serversQuantity: 0, stripeCustomerId: "", stripeSubscriptionId: "", - accessedProjects: [], - accessedServices: [], banExpires: new Date(), banned: true, banReason: "", - canAccessToAPI: false, - canCreateProjects: false, - canDeleteProjects: false, - canDeleteServices: false, - canAccessToDocker: false, - canAccessToSSHKeys: false, - canCreateServices: false, - canAccessToTraefikFiles: false, - canAccessToGitProviders: false, email: "", expirationDate: "", id: "", @@ -73,7 +62,6 @@ const baseAdmin: User = { createdAt2: new Date().toISOString(), emailVerified: false, image: "", - token: "", updatedAt: new Date(), twoFactorEnabled: false, }; diff --git a/apps/dokploy/components/auth/login-2fa.tsx b/apps/dokploy/components/auth/login-2fa.tsx deleted file mode 100644 index 634f28146..000000000 --- a/apps/dokploy/components/auth/login-2fa.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import { Button } from "@/components/ui/button"; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; - -import { CardTitle } from "@/components/ui/card"; -import { - InputOTP, - InputOTPGroup, - InputOTPSlot, -} from "@/components/ui/input-otp"; -import { api } from "@/utils/api"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { REGEXP_ONLY_DIGITS } from "input-otp"; -import { AlertTriangle } from "lucide-react"; -import { useRouter } from "next/router"; -import { useEffect } from "react"; -import { useForm } from "react-hook-form"; -import { toast } from "sonner"; -import { z } from "zod"; - -const Login2FASchema = z.object({ - pin: z.string().min(6, { - message: "Pin is required", - }), -}); - -type Login2FA = z.infer; - -interface Props { - authId: string; -} - -export const Login2FA = ({ authId }: Props) => { - const { push } = useRouter(); - - const { mutateAsync, isLoading, isError, error } = - api.auth.verifyLogin2FA.useMutation(); - - const form = useForm({ - defaultValues: { - pin: "", - }, - resolver: zodResolver(Login2FASchema), - }); - - useEffect(() => { - form.reset({ - pin: "", - }); - }, [form, form.reset, form.formState.isSubmitSuccessful]); - - const onSubmit = async (data: Login2FA) => { - await mutateAsync({ - pin: data.pin, - id: authId, - }) - .then(() => { - toast.success("Signin successfully", { - duration: 2000, - }); - - push("/dashboard/projects"); - }) - .catch(() => { - toast.error("Signin failed", { - duration: 2000, - }); - }); - }; - return ( - - - {isError && ( -
- - - {error?.message} - -
- )} - 2FA Login - - ( - - Pin - -
- - - - - - - - - - -
-
- - Please enter the 6 digits code provided by your authenticator - app. - - -
- )} - /> - - - - ); -}; diff --git a/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx b/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx index e299cfb38..e92ce03fc 100644 --- a/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx +++ b/apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx @@ -72,7 +72,7 @@ export const ShowPaidMonitoring = ({ data, isLoading, error: queryError, - } = api.user.getServerMetrics.useQuery( + } = api.server.getServerMetrics.useQuery( { url: BASE_URL, token, diff --git a/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx b/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx index 3ececb649..28fba67df 100644 --- a/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx @@ -44,6 +44,12 @@ const PinSchema = z.object({ }), }); +type TwoFactorSetupData = { + qrCodeUrl: string; + secret: string; + totpURI: string; +}; + type PasswordForm = z.infer; type PinForm = z.infer; diff --git a/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx b/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx index 3a511d8ea..afe1e4c36 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/update-server-ip.tsx @@ -80,7 +80,7 @@ export const UpdateServerIp = ({ children }: Props) => { }) .then(async () => { toast.success("Server IP Updated"); - await utils.admin.one.invalidate(); + await utils.user.get.invalidate(); setIsOpen(false); }) .catch(() => { diff --git a/apps/dokploy/pages/api/stripe/webhook.ts b/apps/dokploy/pages/api/stripe/webhook.ts index 592803b15..9e8c9da5e 100644 --- a/apps/dokploy/pages/api/stripe/webhook.ts +++ b/apps/dokploy/pages/api/stripe/webhook.ts @@ -1,7 +1,7 @@ import { buffer } from "node:stream/consumers"; import { db } from "@/server/db"; import { organization, server, users_temp } from "@/server/db/schema"; -import { findUserById, type Server } from "@dokploy/server"; +import { type Server, findUserById } from "@dokploy/server"; import { asc, eq } from "drizzle-orm"; import type { NextApiRequest, NextApiResponse } from "next"; import Stripe from "stripe"; diff --git a/apps/dokploy/pages/confirm-email.tsx b/apps/dokploy/pages/confirm-email.tsx deleted file mode 100644 index 2910a2677..000000000 --- a/apps/dokploy/pages/confirm-email.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { OnboardingLayout } from "@/components/layouts/onboarding-layout"; -import { Logo } from "@/components/shared/logo"; -import { CardDescription, CardTitle } from "@/components/ui/card"; -import { db } from "@/server/db"; -import { auth } from "@/server/db/schema"; -import { IS_CLOUD, updateAuthById } from "@dokploy/server"; -import { isBefore } from "date-fns"; -import { eq } from "drizzle-orm"; -import type { GetServerSidePropsContext } from "next"; -import Link from "next/link"; -import type { ReactElement } from "react"; - -export default function Home() { - return ( -
-
- - - Dokploy - - Email Confirmed - - Congratulations, your email is confirmed. - -
- - Click here to login - -
-
-
- ); -} - -Home.getLayout = (page: ReactElement) => { - return {page}; -}; -export async function getServerSideProps(context: GetServerSidePropsContext) { - if (!IS_CLOUD) { - return { - redirect: { - permanent: true, - destination: "/", - }, - }; - } - const { token } = context.query; - - if (typeof token !== "string") { - return { - redirect: { - permanent: true, - destination: "/", - }, - }; - } - - const authR = await db.query.auth.findFirst({ - where: eq(auth.confirmationToken, token), - }); - - if ( - !authR || - authR?.confirmationToken === null || - authR?.confirmationExpiresAt === null - ) { - return { - redirect: { - permanent: true, - destination: "/", - }, - }; - } - - const isExpired = isBefore(new Date(authR.confirmationExpiresAt), new Date()); - - if (isExpired) { - return { - redirect: { - permanent: true, - destination: "/", - }, - }; - } - - await updateAuthById(authR.id, { - confirmationToken: null, - confirmationExpiresAt: null, - }); - - return { - props: { - token: authR.confirmationToken, - }, - }; -} diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 783ec651d..4a85952e6 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -85,6 +85,7 @@ export default function Home({ IS_CLOUD }: Props) { return; } + // @ts-ignore if (data?.twoFactorRedirect as boolean) { setTwoFactorCode(""); setIsTwoFactor(true); diff --git a/apps/dokploy/pages/send-reset-password.tsx b/apps/dokploy/pages/send-reset-password.tsx index 0ea59cf85..8f6902f6e 100644 --- a/apps/dokploy/pages/send-reset-password.tsx +++ b/apps/dokploy/pages/send-reset-password.tsx @@ -1,4 +1,3 @@ -import { Login2FA } from "@/components/auth/login-2fa"; import { OnboardingLayout } from "@/components/layouts/onboarding-layout"; import { AlertBlock } from "@/components/shared/alert-block"; import { Logo } from "@/components/shared/logo"; @@ -126,9 +125,7 @@ export default function Home() {
- ) : ( - - )} + ) : null}
diff --git a/apps/dokploy/reset-password.ts b/apps/dokploy/reset-password.ts index 43b11fdf6..32cab4334 100644 --- a/apps/dokploy/reset-password.ts +++ b/apps/dokploy/reset-password.ts @@ -1,6 +1,8 @@ import { findAdmin } from "@dokploy/server"; -import { updateAuthById } from "@dokploy/server"; import { generateRandomPassword } from "@dokploy/server"; +import { db } from "@dokploy/server/db"; +import { account } from "@dokploy/server/db/schema"; +import { eq } from "drizzle-orm"; (async () => { try { @@ -8,9 +10,12 @@ import { generateRandomPassword } from "@dokploy/server"; const result = await findAdmin(); - const update = await updateAuthById(result.authId, { - password: randomPassword.hashedPassword, - }); + const update = await db + .update(account) + .set({ + password: randomPassword.hashedPassword, + }) + .where(eq(account.userId, result.userId)); if (update) { console.log("Password reset successful"); diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index 31a50c67b..1a6c046e3 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -14,13 +14,11 @@ import { IS_CLOUD, findUserById, getUserByToken, - sendDiscordNotification, sendEmailNotification, validateRequest, } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; import * as bcrypt from "bcrypt"; -import { isBefore } from "date-fns"; import { and, eq } from "drizzle-orm"; import { nanoid } from "nanoid"; import { z } from "zod"; @@ -321,157 +319,64 @@ export const authRouter = createTRPCRouter({ `, ); }), - - resetPassword: publicProcedure - .input( - z.object({ - resetPasswordToken: z.string().min(1), - password: z.string().min(1), - }), - ) - .mutation(async ({ input }) => { - if (!IS_CLOUD) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "This feature is only available in the cloud version", - }); - } - const authR = await db.query.auth.findFirst({ - where: eq(auth.resetPasswordToken, input.resetPasswordToken), - }); - - if (!authR || authR.resetPasswordExpiresAt === null) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Token not found", - }); - } - - const isExpired = isBefore( - new Date(authR.resetPasswordExpiresAt), - new Date(), - ); - - if (isExpired) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Token expired", - }); - } - - await updateAuthById(authR.id, { - resetPasswordExpiresAt: null, - resetPasswordToken: null, - password: bcrypt.hashSync(input.password, 10), - }); - - return true; - }), - confirmEmail: adminProcedure - .input( - z.object({ - confirmationToken: z.string().min(1), - }), - ) - .mutation(async ({ input }) => { - if (!IS_CLOUD) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Functionality not available in cloud version", - }); - } - const authR = await db.query.auth.findFirst({ - where: eq(auth.confirmationToken, input.confirmationToken), - }); - if (!authR || authR.confirmationExpiresAt === null) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Token not found", - }); - } - if (authR.confirmationToken !== input.confirmationToken) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Confirmation Token not found", - }); - } - - const isExpired = isBefore( - new Date(authR.confirmationExpiresAt), - new Date(), - ); - - if (isExpired) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Confirmation Token expired", - }); - } - 1; - await updateAuthById(authR.id, { - confirmationToken: null, - confirmationExpiresAt: null, - }); - return true; - }), }); -export const sendVerificationEmail = async (authId: string) => { - const token = nanoid(); - const result = await updateAuthById(authId, { - confirmationToken: token, - confirmationExpiresAt: new Date( - new Date().getTime() + 24 * 60 * 60 * 1000, - ).toISOString(), - }); +// export const sendVerificationEmail = async (authId: string) => { +// const token = nanoid(); +// const result = await updateAuthById(authId, { +// confirmationToken: token, +// confirmationExpiresAt: new Date( +// new Date().getTime() + 24 * 60 * 60 * 1000, +// ).toISOString(), +// }); - if (!result) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "User not found", - }); - } - await sendEmailNotification( - { - fromAddress: process.env.SMTP_FROM_ADDRESS || "", - toAddresses: [result?.email], - smtpServer: process.env.SMTP_SERVER || "", - smtpPort: Number(process.env.SMTP_PORT), - username: process.env.SMTP_USERNAME || "", - password: process.env.SMTP_PASSWORD || "", - }, - "Confirm your email | Dokploy", - ` - Welcome to Dokploy! - Please confirm your email by clicking the link below: - - Confirm Email - - `, - ); +// if (!result) { +// throw new TRPCError({ +// code: "BAD_REQUEST", +// message: "User not found", +// }); +// } +// await sendEmailNotification( +// { +// fromAddress: process.env.SMTP_FROM_ADDRESS || "", +// toAddresses: [result?.email], +// smtpServer: process.env.SMTP_SERVER || "", +// smtpPort: Number(process.env.SMTP_PORT), +// username: process.env.SMTP_USERNAME || "", +// password: process.env.SMTP_PASSWORD || "", +// }, +// "Confirm your email | Dokploy", +// ` +// Welcome to Dokploy! +// Please confirm your email by clicking the link below: +// +// Confirm Email +// +// `, +// ); - return true; -}; +// return true; +// }; -export const sendDiscordNotificationWelcome = async (newAdmin: Auth) => { - await sendDiscordNotification( - { - webhookUrl: process.env.DISCORD_WEBHOOK_URL || "", - }, - { - title: "New User Registered", - color: 0x00ff00, - fields: [ - { - name: "Email", - value: newAdmin.email, - inline: true, - }, - ], - timestamp: newAdmin.createdAt, - footer: { - text: "Dokploy User Registration Notification", - }, - }, - ); -}; +// export const sendDiscordNotificationWelcome = async (newAdmin: Auth) => { +// await sendDiscordNotification( +// { +// webhookUrl: process.env.DISCORD_WEBHOOK_URL || "", +// }, +// { +// title: "New User Registered", +// color: 0x00ff00, +// fields: [ +// { +// name: "Email", +// value: newAdmin.email, +// inline: true, +// }, +// ], +// timestamp: newAdmin.createdAt, +// footer: { +// text: "Dokploy User Registration Notification", +// }, +// }, +// ); +// }; diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts index 1ebb161a4..1a9ebc0ac 100644 --- a/apps/dokploy/server/api/routers/server.ts +++ b/apps/dokploy/server/api/routers/server.ts @@ -37,6 +37,7 @@ import { import { TRPCError } from "@trpc/server"; import { observable } from "@trpc/server/observable"; import { and, desc, eq, getTableColumns, isNotNull, sql } from "drizzle-orm"; +import { z } from "zod"; export const serverRouter = createTRPCRouter({ create: protectedProcedure @@ -378,4 +379,62 @@ export const serverRouter = createTRPCRouter({ const ip = await getPublicIpWithFallback(); return ip; }), + getServerMetrics: protectedProcedure + .input( + z.object({ + url: z.string(), + token: z.string(), + dataPoints: z.string(), + }), + ) + .query(async ({ input }) => { + try { + const url = new URL(input.url); + url.searchParams.append("limit", input.dataPoints); + const response = await fetch(url.toString(), { + headers: { + Authorization: `Bearer ${input.token}`, + }, + }); + if (!response.ok) { + throw new Error( + `Error ${response.status}: ${response.statusText}. Ensure the container is running and this service is included in the monitoring configuration.`, + ); + } + + const data = await response.json(); + if (!Array.isArray(data) || data.length === 0) { + throw new Error( + [ + "No monitoring data available. This could be because:", + "", + "1. You don't have setup the monitoring service, you can do in web server section.", + "2. If you already have setup the monitoring service, wait a few minutes and refresh the page.", + ].join("\n"), + ); + } + return data as { + cpu: string; + cpuModel: string; + cpuCores: number; + cpuPhysicalCores: number; + cpuSpeed: number; + os: string; + distro: string; + kernel: string; + arch: string; + memUsed: string; + memUsedGB: string; + memTotal: string; + uptime: number; + diskUsed: string; + totalDisk: string; + networkIn: string; + networkOut: string; + timestamp: string; + }[]; + } catch (error) { + throw error; + } + }), }); diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 43cffd9e1..5717d59bf 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -143,4 +143,63 @@ export const userRouter = createTRPCRouter({ }, }); }), + + getContainerMetrics: protectedProcedure + .input( + z.object({ + url: z.string(), + token: z.string(), + appName: z.string(), + dataPoints: z.string(), + }), + ) + .query(async ({ input }) => { + try { + if (!input.appName) { + throw new Error( + [ + "No Application Selected:", + "", + "Make Sure to select an application to monitor.", + ].join("\n"), + ); + } + const url = new URL(`${input.url}/metrics/containers`); + url.searchParams.append("limit", input.dataPoints); + url.searchParams.append("appName", input.appName); + const response = await fetch(url.toString(), { + headers: { + Authorization: `Bearer ${input.token}`, + }, + }); + if (!response.ok) { + throw new Error( + `Error ${response.status}: ${response.statusText}. Please verify that the application "${input.appName}" is running and this service is included in the monitoring configuration.`, + ); + } + + const data = await response.json(); + if (!Array.isArray(data) || data.length === 0) { + throw new Error( + [ + `No monitoring data available for "${input.appName}". This could be because:`, + "", + "1. The container was recently started - wait a few minutes for data to be collected", + "2. The container is not running - verify its status", + "3. The service is not included in your monitoring configuration", + ].join("\n"), + ); + } + return data as { + containerId: string; + containerName: string; + containerImage: string; + containerLabels: string; + containerCommand: string; + containerCreated: string; + }[]; + } catch (error) { + throw error; + } + }), }); diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index 78df14aa4..099018f2b 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -108,6 +108,23 @@ export const isAdminPresent = async () => { return true; }; +export const findAdmin = async () => { + const admin = await db.query.member.findFirst({ + where: eq(member.role, "owner"), + with: { + user: true, + }, + }); + + if (!admin) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Admin not found", + }); + } + return admin; +}; + export const getUserByToken = async (token: string) => { const user = await db.query.invitation.findFirst({ where: eq(invitation.id, token), @@ -154,8 +171,8 @@ export const getDokployUrl = async () => { } const admin = await findAdmin(); - if (admin.host) { - return `https://${admin.host}`; + if (admin.user.host) { + return `https://${admin.user.host}`; } - return `http://${admin.serverIp}:${process.env.PORT}`; + return `http://${admin.user.serverIp}:${process.env.PORT}`; }; From 0478419f7cb7df083e7fdf146aa19410db81b488 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 22:02:12 -0600 Subject: [PATCH 59/89] refactor: migrate authentication routes to user router and update related components This commit continues the refactoring of authentication-related code by: - Moving authentication routes from `auth.ts` to `user.ts` - Updating import paths and function calls across components - Removing commented-out authentication code - Simplifying user-related queries and mutations - Updating server-side authentication handling --- .../settings/profile/disable-2fa.tsx | 2 +- .../dashboard/settings/profile/enable-2fa.tsx | 2 +- .../settings/profile/generate-token.tsx | 4 +- .../settings/profile/remove-self-account.tsx | 138 ----- .../settings/servers/setup-monitoring.tsx | 2 +- apps/dokploy/components/layouts/side.tsx | 2 +- apps/dokploy/pages/api/[...trpc].ts | 10 +- apps/dokploy/pages/dashboard/projects.tsx | 2 +- .../pages/dashboard/settings/billing.tsx | 2 +- .../pages/dashboard/settings/certificates.tsx | 2 +- .../pages/dashboard/settings/cluster.tsx | 2 +- .../pages/dashboard/settings/destinations.tsx | 2 +- .../dashboard/settings/git-providers.tsx | 2 +- .../pages/dashboard/settings/index.tsx | 2 +- .../dashboard/settings/notifications.tsx | 2 +- .../pages/dashboard/settings/profile.tsx | 15 +- .../pages/dashboard/settings/registry.tsx | 2 +- .../pages/dashboard/settings/server.tsx | 2 +- .../pages/dashboard/settings/servers.tsx | 2 +- .../pages/dashboard/settings/users.tsx | 2 +- apps/dokploy/pages/reset-password.tsx | 85 +-- apps/dokploy/pages/send-reset-password.tsx | 34 +- apps/dokploy/server/api/routers/auth.ts | 550 +++++++++--------- apps/dokploy/server/api/routers/user.ts | 18 +- packages/server/src/lib/auth.ts | 15 +- packages/server/src/services/admin.ts | 65 --- packages/server/src/services/user.ts | 15 +- .../server/src/utils/access-log/handler.ts | 1 + packages/server/src/utils/backups/index.ts | 7 +- .../verification/send-verification-email.tsx | 20 +- 30 files changed, 394 insertions(+), 615 deletions(-) delete mode 100644 apps/dokploy/components/dashboard/settings/profile/remove-self-account.tsx diff --git a/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx b/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx index ceeb386d7..458bf5632 100644 --- a/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/disable-2fa.tsx @@ -61,7 +61,7 @@ export const Disable2FA = () => { } toast.success("2FA disabled successfully"); - utils.auth.get.invalidate(); + utils.user.get.invalidate(); setIsOpen(false); } catch (_error) { form.setError("password", { diff --git a/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx b/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx index 28fba67df..f47c8d9c0 100644 --- a/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/enable-2fa.tsx @@ -125,7 +125,7 @@ export const Enable2FA = () => { } toast.success("2FA configured successfully"); - utils.auth.get.invalidate(); + utils.user.get.invalidate(); setIsDialogOpen(false); } catch (error) { if (error instanceof Error) { diff --git a/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx b/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx index d0299eb6e..4d36ab7a1 100644 --- a/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx @@ -17,7 +17,7 @@ export const GenerateToken = () => { const { data, refetch } = api.user.get.useQuery(); const { mutateAsync: generateToken, isLoading: isLoadingToken } = - api.auth.generateToken.useMutation(); + api.user.generateToken.useMutation(); return (
@@ -51,7 +51,7 @@ export const GenerateToken = () => {
diff --git a/apps/dokploy/components/dashboard/settings/profile/remove-self-account.tsx b/apps/dokploy/components/dashboard/settings/profile/remove-self-account.tsx deleted file mode 100644 index 935019941..000000000 --- a/apps/dokploy/components/dashboard/settings/profile/remove-self-account.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { AlertBlock } from "@/components/shared/alert-block"; -import { DialogAction } from "@/components/shared/dialog-action"; -import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { api } from "@/utils/api"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useTranslation } from "next-i18next"; -import { useRouter } from "next/router"; -import { useEffect } from "react"; -import { useForm } from "react-hook-form"; -import { toast } from "sonner"; -import { z } from "zod"; - -const profileSchema = z.object({ - password: z.string().min(1, { - message: "Password is required", - }), -}); - -type Profile = z.infer; - -export const RemoveSelfAccount = () => { - const { data } = api.user.get.useQuery(); - const { mutateAsync, isLoading, error, isError } = - api.auth.removeSelfAccount.useMutation(); - const { t } = useTranslation("settings"); - const router = useRouter(); - - const form = useForm({ - defaultValues: { - password: "", - }, - resolver: zodResolver(profileSchema), - }); - - useEffect(() => { - if (data) { - form.reset({ - password: "", - }); - } - form.reset(); - }, [form, form.reset, data]); - - const onSubmit = async (values: Profile) => { - await mutateAsync({ - password: values.password, - }) - .then(async () => { - toast.success("Profile Deleted"); - router.push("/"); - }) - .catch(() => {}); - }; - - return ( -
- -
- -
- Remove Self Account - - If you want to remove your account, you can do it here - -
-
- - {isError && {error?.message}} - -
- e.preventDefault()} - onKeyDown={(e) => { - if (e.key === "Enter") { - e.preventDefault(); - } - }} - className="grid gap-4" - > -
- ( - - {t("settings.profile.password")} - - - - - - )} - /> -
-
- -
- form.handleSubmit(onSubmit)()} - > - - -
-
-
-
-
- ); -}; diff --git a/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx b/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx index b8c699268..9a49277e2 100644 --- a/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/setup-monitoring.tsx @@ -89,7 +89,7 @@ export const SetupMonitoring = ({ serverId }: Props) => { enabled: !!serverId, }, ) - : api.user.get.useQuery(); + : api.user.getServerMetrics.useQuery(); const url = useUrl(); diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 63155f8eb..9c61fb396 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -89,7 +89,7 @@ import { UpdateServerButton } from "./update-server"; import { UserNav } from "./user-nav"; // The types of the queries we are going to use -type AuthQueryOutput = inferRouterOutputs["auth"]["get"]; +type AuthQueryOutput = inferRouterOutputs["user"]["get"]; type SingleNavItem = { isSingle?: true; diff --git a/apps/dokploy/pages/api/[...trpc].ts b/apps/dokploy/pages/api/[...trpc].ts index df85440b9..85ddbb286 100644 --- a/apps/dokploy/pages/api/[...trpc].ts +++ b/apps/dokploy/pages/api/[...trpc].ts @@ -1,17 +1,11 @@ import { appRouter } from "@/server/api/root"; import { createTRPCContext } from "@/server/api/trpc"; -import { validateBearerToken, validateRequest } from "@dokploy/server"; +import { validateRequest } from "@dokploy/server"; import { createOpenApiNextHandler } from "@dokploy/trpc-openapi"; import type { NextApiRequest, NextApiResponse } from "next"; const handler = async (req: NextApiRequest, res: NextApiResponse) => { - let { session, user } = await validateBearerToken(req); - - if (!session) { - const cookieResult = await validateRequest(req, res); - session = cookieResult.session; - user = cookieResult.user; - } + const { session, user } = await validateRequest(req); if (!user || !session) { res.status(401).json({ message: "Unauthorized" }); diff --git a/apps/dokploy/pages/dashboard/projects.tsx b/apps/dokploy/pages/dashboard/projects.tsx index 49427c25b..5434163ad 100644 --- a/apps/dokploy/pages/dashboard/projects.tsx +++ b/apps/dokploy/pages/dashboard/projects.tsx @@ -52,7 +52,7 @@ export async function getServerSideProps( }); await helpers.settings.isCloud.prefetch(); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); if (!user) { return { redirect: { diff --git a/apps/dokploy/pages/dashboard/settings/billing.tsx b/apps/dokploy/pages/dashboard/settings/billing.tsx index ee1ecdbe5..7ba5717e9 100644 --- a/apps/dokploy/pages/dashboard/settings/billing.tsx +++ b/apps/dokploy/pages/dashboard/settings/billing.tsx @@ -52,7 +52,7 @@ export async function getServerSideProps( transformer: superjson, }); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); await helpers.settings.isCloud.prefetch(); diff --git a/apps/dokploy/pages/dashboard/settings/certificates.tsx b/apps/dokploy/pages/dashboard/settings/certificates.tsx index 96bec90bf..0c82ed4fb 100644 --- a/apps/dokploy/pages/dashboard/settings/certificates.tsx +++ b/apps/dokploy/pages/dashboard/settings/certificates.tsx @@ -45,7 +45,7 @@ export async function getServerSideProps( }, transformer: superjson, }); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); await helpers.settings.isCloud.prefetch(); return { diff --git a/apps/dokploy/pages/dashboard/settings/cluster.tsx b/apps/dokploy/pages/dashboard/settings/cluster.tsx index 77ece29b8..a1a46bb65 100644 --- a/apps/dokploy/pages/dashboard/settings/cluster.tsx +++ b/apps/dokploy/pages/dashboard/settings/cluster.tsx @@ -53,7 +53,7 @@ export async function getServerSideProps( }, transformer: superjson, }); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); return { props: { diff --git a/apps/dokploy/pages/dashboard/settings/destinations.tsx b/apps/dokploy/pages/dashboard/settings/destinations.tsx index 8605a7c18..3c906b55c 100644 --- a/apps/dokploy/pages/dashboard/settings/destinations.tsx +++ b/apps/dokploy/pages/dashboard/settings/destinations.tsx @@ -46,7 +46,7 @@ export async function getServerSideProps( }, transformer: superjson, }); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); await helpers.settings.isCloud.prefetch(); return { diff --git a/apps/dokploy/pages/dashboard/settings/git-providers.tsx b/apps/dokploy/pages/dashboard/settings/git-providers.tsx index ce2adc9ce..7a9b08df9 100644 --- a/apps/dokploy/pages/dashboard/settings/git-providers.tsx +++ b/apps/dokploy/pages/dashboard/settings/git-providers.tsx @@ -45,7 +45,7 @@ export async function getServerSideProps( }, transformer: superjson, }); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); try { await helpers.project.all.prefetch(); await helpers.settings.isCloud.prefetch(); diff --git a/apps/dokploy/pages/dashboard/settings/index.tsx b/apps/dokploy/pages/dashboard/settings/index.tsx index 713e51133..4c060cbb5 100644 --- a/apps/dokploy/pages/dashboard/settings/index.tsx +++ b/apps/dokploy/pages/dashboard/settings/index.tsx @@ -209,7 +209,7 @@ export async function getServerSideProps( }, transformer: superjson, }); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); return { props: { diff --git a/apps/dokploy/pages/dashboard/settings/notifications.tsx b/apps/dokploy/pages/dashboard/settings/notifications.tsx index 76566fdf2..fbdc2e205 100644 --- a/apps/dokploy/pages/dashboard/settings/notifications.tsx +++ b/apps/dokploy/pages/dashboard/settings/notifications.tsx @@ -46,7 +46,7 @@ export async function getServerSideProps( }, transformer: superjson, }); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); await helpers.settings.isCloud.prefetch(); return { diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index 446e6c875..404d400c8 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -1,6 +1,5 @@ import { GenerateToken } from "@/components/dashboard/settings/profile/generate-token"; import { ProfileForm } from "@/components/dashboard/settings/profile/profile-form"; -import { RemoveSelfAccount } from "@/components/dashboard/settings/profile/remove-self-account"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { appRouter } from "@/server/api/root"; @@ -15,14 +14,14 @@ import superjson from "superjson"; const Page = () => { const { data } = api.user.get.useQuery(); - const { data: isCloud } = api.settings.isCloud.useQuery(); + // const { data: isCloud } = api.settings.isCloud.useQuery(); return (
{(data?.canAccessToAPI || data?.role === "owner") && } - {isCloud && } + {/* {isCloud && } */}
); @@ -53,15 +52,7 @@ export async function getServerSideProps( }); await helpers.settings.isCloud.prefetch(); - await helpers.auth.get.prefetch(); - if (user?.role === "member") { - // const userR = await helpers.user.one.fetch({ - // userId: user.id, - // }); - // await helpers.user.byAuthId.prefetch({ - // authId: user.authId, - // }); - } + await helpers.user.get.prefetch(); if (!user) { return { diff --git a/apps/dokploy/pages/dashboard/settings/registry.tsx b/apps/dokploy/pages/dashboard/settings/registry.tsx index 678e0da46..42f0627f4 100644 --- a/apps/dokploy/pages/dashboard/settings/registry.tsx +++ b/apps/dokploy/pages/dashboard/settings/registry.tsx @@ -45,7 +45,7 @@ export async function getServerSideProps( }, transformer: superjson, }); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); await helpers.settings.isCloud.prefetch(); return { diff --git a/apps/dokploy/pages/dashboard/settings/server.tsx b/apps/dokploy/pages/dashboard/settings/server.tsx index 4f88c794b..0c5e36dc0 100644 --- a/apps/dokploy/pages/dashboard/settings/server.tsx +++ b/apps/dokploy/pages/dashboard/settings/server.tsx @@ -110,7 +110,7 @@ export async function getServerSideProps( }, transformer: superjson, }); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); return { props: { diff --git a/apps/dokploy/pages/dashboard/settings/servers.tsx b/apps/dokploy/pages/dashboard/settings/servers.tsx index 08d4ab694..5cc30b832 100644 --- a/apps/dokploy/pages/dashboard/settings/servers.tsx +++ b/apps/dokploy/pages/dashboard/settings/servers.tsx @@ -56,7 +56,7 @@ export async function getServerSideProps( }, transformer: superjson, }); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); await helpers.settings.isCloud.prefetch(); return { diff --git a/apps/dokploy/pages/dashboard/settings/users.tsx b/apps/dokploy/pages/dashboard/settings/users.tsx index ac5355218..226153145 100644 --- a/apps/dokploy/pages/dashboard/settings/users.tsx +++ b/apps/dokploy/pages/dashboard/settings/users.tsx @@ -50,7 +50,7 @@ export async function getServerSideProps( }, transformer: superjson, }); - await helpers.auth.get.prefetch(); + await helpers.user.get.prefetch(); await helpers.settings.isCloud.prefetch(); return { diff --git a/apps/dokploy/pages/reset-password.tsx b/apps/dokploy/pages/reset-password.tsx index a34a25ed0..0f6cf0b32 100644 --- a/apps/dokploy/pages/reset-password.tsx +++ b/apps/dokploy/pages/reset-password.tsx @@ -12,17 +12,13 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; -import { db } from "@/server/db"; -import { auth } from "@/server/db/schema"; -import { api } from "@/utils/api"; +import { authClient } from "@/lib/auth-client"; import { IS_CLOUD } from "@dokploy/server"; import { zodResolver } from "@hookform/resolvers/zod"; -import { isBefore } from "date-fns"; -import { eq } from "drizzle-orm"; import type { GetServerSidePropsContext } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; -import { type ReactElement, useEffect } from "react"; +import { type ReactElement, useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; @@ -54,11 +50,12 @@ const loginSchema = z type Login = z.infer; interface Props { - token: string; + tokenResetPassword: string; } -export default function Home({ token }: Props) { - const { mutateAsync, isLoading, isError, error } = - api.auth.resetPassword.useMutation(); +export default function Home({ tokenResetPassword }: Props) { + const [token, setToken] = useState(tokenResetPassword); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); const router = useRouter(); const form = useForm({ defaultValues: { @@ -68,26 +65,32 @@ export default function Home({ token }: Props) { resolver: zodResolver(loginSchema), }); + useEffect(() => { + const token = new URLSearchParams(window.location.search).get("token"); + + if (token) { + setToken(token); + } + }, [token]); + useEffect(() => { form.reset(); }, [form, form.reset, form.formState.isSubmitSuccessful]); const onSubmit = async (values: Login) => { - await mutateAsync({ - resetPasswordToken: token, - password: values.password, - }) - .then((_data) => { - toast.success("Password reset successfully", { - duration: 2000, - }); - router.push("/"); - }) - .catch(() => { - toast.error("Error resetting password", { - duration: 2000, - }); - }); + setIsLoading(true); + const { error } = await authClient.resetPassword({ + newPassword: values.password, + token: token || "", + }); + + if (error) { + setError(error.message || "An error occurred"); + } else { + toast.success("Password reset successfully"); + router.push("/"); + } + setIsLoading(false); }; return (
@@ -104,9 +107,9 @@ export default function Home({ token }: Props) {
- {isError && ( + {error && ( - {error?.message} + {error} )}
@@ -194,35 +197,9 @@ export async function getServerSideProps(context: GetServerSidePropsContext) { }; } - const authR = await db.query.auth.findFirst({ - where: eq(auth.resetPasswordToken, token), - }); - - if (!authR || authR?.resetPasswordExpiresAt === null) { - return { - redirect: { - permanent: true, - destination: "/", - }, - }; - } - const isExpired = isBefore( - new Date(authR.resetPasswordExpiresAt), - new Date(), - ); - - if (isExpired) { - return { - redirect: { - permanent: true, - destination: "/", - }, - }; - } - return { props: { - token: authR.resetPasswordToken, + tokenResetPassword: token, }, }; } diff --git a/apps/dokploy/pages/send-reset-password.tsx b/apps/dokploy/pages/send-reset-password.tsx index 8f6902f6e..10d1058aa 100644 --- a/apps/dokploy/pages/send-reset-password.tsx +++ b/apps/dokploy/pages/send-reset-password.tsx @@ -12,7 +12,7 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; -import { api } from "@/utils/api"; +import { authClient } from "@/lib/auth-client"; import { IS_CLOUD } from "@dokploy/server"; import { zodResolver } from "@hookform/resolvers/zod"; import type { GetServerSidePropsContext } from "next"; @@ -46,8 +46,9 @@ export default function Home() { is2FAEnabled: false, authId: "", }); - const { mutateAsync, isLoading, isError, error } = - api.auth.sendResetPasswordEmail.useMutation(); + + const [error, setError] = useState(null); + const [isLoading, setIsLoading] = useState(false); const _router = useRouter(); const form = useForm({ defaultValues: { @@ -61,19 +62,20 @@ export default function Home() { }, [form, form.reset, form.formState.isSubmitSuccessful]); const onSubmit = async (values: Login) => { - await mutateAsync({ + setIsLoading(true); + const { error } = await authClient.forgetPassword({ email: values.email, - }) - .then((_data) => { - toast.success("Email sent", { - duration: 2000, - }); - }) - .catch(() => { - toast.error("Error sending email", { - duration: 2000, - }); + redirectTo: "/reset-password", + }); + if (error) { + setError(error.message || "An error occurred"); + setIsLoading(false); + } else { + toast.success("Email sent", { + duration: 2000, }); + } + setIsLoading(false); }; return (
@@ -89,9 +91,9 @@ export default function Home() {
- {isError && ( + {error && ( - {error?.message} + {error} )} {!temp.is2FAEnabled ? ( diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index 1a6c046e3..68a2eba73 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -31,294 +31,268 @@ import { } from "../trpc"; export const authRouter = createTRPCRouter({ - createAdmin: publicProcedure.mutation(async ({ input }) => { - try { - if (!IS_CLOUD) { - const admin = await db.query.admins.findFirst({}); - if (admin) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Admin already exists", - }); - } - } - const newAdmin = await createAdmin(input); - - if (IS_CLOUD) { - await sendDiscordNotificationWelcome(newAdmin); - await sendVerificationEmail(newAdmin.id); - return { - status: "success", - type: "cloud", - }; - } - // const session = await lucia.createSession(newAdmin.id || "", {}); - // ctx.res.appendHeader( - // "Set-Cookie", - // lucia.createSessionCookie(session.id).serialize(), - // ); - return { - status: "success", - type: "selfhosted", - }; - } catch (error) { - throw new TRPCError({ - code: "BAD_REQUEST", - // @ts-ignore - message: `Error: ${error?.code === "23505" ? "Email already exists" : "Error creating admin"}`, - cause: error, - }); - } - }), - createUser: publicProcedure.mutation(async ({ input }) => { - try { - const _token = await getUserByToken(input.token); - // if (token.isExpired) { - // throw new TRPCError({ - // code: "BAD_REQUEST", - // message: "Invalid token", - // }); - // } - - // const newUser = await createUser(input); - - // if (IS_CLOUD) { - // await sendVerificationEmail(token.authId); - // return true; - // } - // const session = await lucia.createSession(newUser?.authId || "", {}); - // ctx.res.appendHeader( - // "Set-Cookie", - // lucia.createSessionCookie(session.id).serialize(), - // ); - return true; - } catch (error) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error creating the user", - cause: error, - }); - } - }), - - login: publicProcedure.mutation(async ({ input }) => { - try { - const auth = await findAuthByEmail(input.email); - - const correctPassword = bcrypt.compareSync( - input.password, - auth?.password || "", - ); - - if (!correctPassword) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Credentials do not match", - }); - } - - if (auth?.confirmationToken && IS_CLOUD) { - await sendVerificationEmail(auth.id); - throw new TRPCError({ - code: "BAD_REQUEST", - message: - "Email not confirmed, we have sent you a confirmation email please check your inbox.", - }); - } - - if (auth?.is2FAEnabled) { - return { - is2FAEnabled: true, - authId: auth.id, - }; - } - - // const session = await lucia.createSession(auth?.id || "", {}); - - // ctx.res.appendHeader( - // "Set-Cookie", - // lucia.createSessionCookie(session.id).serialize(), - // ); - return { - is2FAEnabled: false, - authId: auth?.id, - }; - } catch (error) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: `Error: ${error instanceof Error ? error.message : "Login error"}`, - cause: error, - }); - } - }), - - get: protectedProcedure.query(async ({ ctx }) => { - const memberResult = await db.query.member.findFirst({ - where: and( - eq(member.userId, ctx.user.id), - eq(member.organizationId, ctx.session?.activeOrganizationId || ""), - ), - with: { - user: true, - }, - }); - - return memberResult; - }), - - logout: protectedProcedure.mutation(async ({ ctx }) => { - const { req } = ctx; - const { session } = await validateRequest(req); - if (!session) return false; - - // await lucia.invalidateSession(session.id); - // res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); - return true; - }), - - update: protectedProcedure.mutation(async ({ ctx, input }) => { - const currentAuth = await findAuthByEmail(ctx.user.email); - - if (input.currentPassword || input.password) { - const correctPassword = bcrypt.compareSync( - input.currentPassword || "", - currentAuth?.password || "", - ); - if (!correctPassword) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Current password is incorrect", - }); - } - } - // const auth = await updateAuthById(ctx.user.authId, { - // ...(input.email && { email: input.email.toLowerCase() }), - // ...(input.password && { - // password: bcrypt.hashSync(input.password, 10), - // }), - // ...(input.image && { image: input.image }), - // }); - - return auth; - }), - removeSelfAccount: protectedProcedure - .input( - z.object({ - password: z.string().min(1), - }), - ) - .mutation(async ({ ctx, input }) => { - if (!IS_CLOUD) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "This feature is only available in the cloud version", - }); - } - const currentAuth = await findAuthByEmail(ctx.user.email); - - const correctPassword = bcrypt.compareSync( - input.password, - currentAuth?.password || "", - ); - - if (!correctPassword) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Password is incorrect", - }); - } - const { req } = ctx; - const { session } = await validateRequest(req); - if (!session) return false; - - // await lucia.invalidateSession(session.id); - // res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); - - // if (ctx.user.rol === "owner") { - // await removeAdminByAuthId(ctx.user.authId); - // } else { - // await removeUserByAuthId(ctx.user.authId); - // } - - return true; - }), - - generateToken: protectedProcedure.mutation(async ({ ctx }) => { - const auth = await findUserById(ctx.user.id); - console.log(auth); - - // if (auth.token) { - // await luciaToken.invalidateSession(auth.token); - // } - // const session = await luciaToken.createSession(auth?.id || "", { - // expiresIn: 60 * 60 * 24 * 30, - // }); - // await updateUser(auth.id, { - // token: session.id, - // }); - return auth; - }), - verifyToken: protectedProcedure.mutation(async () => { - return true; - }), - one: adminProcedure - .input(z.object({ userId: z.string().min(1) })) - .query(async ({ input }) => { - // TODO: Check if the user is admin or member - const user = await findUserById(input.userId); - return user; - }), - sendResetPasswordEmail: publicProcedure - .input( - z.object({ - email: z.string().min(1).email(), - }), - ) - .mutation(async ({ input }) => { - if (!IS_CLOUD) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "This feature is only available in the cloud version", - }); - } - const authR = await db.query.auth.findFirst({ - where: eq(auth.email, input.email), - }); - if (!authR) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "User not found", - }); - } - const token = nanoid(); - await updateAuthById(authR.id, { - resetPasswordToken: token, - // Make resetPassword in 24 hours - resetPasswordExpiresAt: new Date( - new Date().getTime() + 24 * 60 * 60 * 1000, - ).toISOString(), - }); - - await sendEmailNotification( - { - fromAddress: process.env.SMTP_FROM_ADDRESS!, - toAddresses: [authR.email], - smtpServer: process.env.SMTP_SERVER!, - smtpPort: Number(process.env.SMTP_PORT), - username: process.env.SMTP_USERNAME!, - password: process.env.SMTP_PASSWORD!, - }, - "Reset Password", - ` - Reset your password by clicking the link below: - The link will expire in 24 hours. - - Reset Password - - - `, - ); - }), + // createAdmin: publicProcedure.mutation(async ({ input }) => { + // try { + // if (!IS_CLOUD) { + // const admin = await db.query.admins.findFirst({}); + // if (admin) { + // throw new TRPCError({ + // code: "BAD_REQUEST", + // message: "Admin already exists", + // }); + // } + // } + // const newAdmin = await createAdmin(input); + // if (IS_CLOUD) { + // await sendDiscordNotificationWelcome(newAdmin); + // await sendVerificationEmail(newAdmin.id); + // return { + // status: "success", + // type: "cloud", + // }; + // } + // // const session = await lucia.createSession(newAdmin.id || "", {}); + // // ctx.res.appendHeader( + // // "Set-Cookie", + // // lucia.createSessionCookie(session.id).serialize(), + // // ); + // return { + // status: "success", + // type: "selfhosted", + // }; + // } catch (error) { + // throw new TRPCError({ + // code: "BAD_REQUEST", + // // @ts-ignore + // message: `Error: ${error?.code === "23505" ? "Email already exists" : "Error creating admin"}`, + // cause: error, + // }); + // } + // }), + // createUser: publicProcedure.mutation(async ({ input }) => { + // try { + // const _token = await getUserByToken(input.token); + // // if (token.isExpired) { + // // throw new TRPCError({ + // // code: "BAD_REQUEST", + // // message: "Invalid token", + // // }); + // // } + // // const newUser = await createUser(input); + // // if (IS_CLOUD) { + // // await sendVerificationEmail(token.authId); + // // return true; + // // } + // // const session = await lucia.createSession(newUser?.authId || "", {}); + // // ctx.res.appendHeader( + // // "Set-Cookie", + // // lucia.createSessionCookie(session.id).serialize(), + // // ); + // return true; + // } catch (error) { + // throw new TRPCError({ + // code: "BAD_REQUEST", + // message: "Error creating the user", + // cause: error, + // }); + // } + // }), + // login: publicProcedure.mutation(async ({ input }) => { + // try { + // const auth = await findAuthByEmail(input.email); + // const correctPassword = bcrypt.compareSync( + // input.password, + // auth?.password || "", + // ); + // if (!correctPassword) { + // throw new TRPCError({ + // code: "BAD_REQUEST", + // message: "Credentials do not match", + // }); + // } + // if (auth?.confirmationToken && IS_CLOUD) { + // await sendVerificationEmail(auth.id); + // throw new TRPCError({ + // code: "BAD_REQUEST", + // message: + // "Email not confirmed, we have sent you a confirmation email please check your inbox.", + // }); + // } + // if (auth?.is2FAEnabled) { + // return { + // is2FAEnabled: true, + // authId: auth.id, + // }; + // } + // // const session = await lucia.createSession(auth?.id || "", {}); + // // ctx.res.appendHeader( + // // "Set-Cookie", + // // lucia.createSessionCookie(session.id).serialize(), + // // ); + // return { + // is2FAEnabled: false, + // authId: auth?.id, + // }; + // } catch (error) { + // throw new TRPCError({ + // code: "BAD_REQUEST", + // message: `Error: ${error instanceof Error ? error.message : "Login error"}`, + // cause: error, + // }); + // } + // }), + // get: protectedProcedure.query(async ({ ctx }) => { + // const memberResult = await db.query.member.findFirst({ + // where: and( + // eq(member.userId, ctx.user.id), + // eq(member.organizationId, ctx.session?.activeOrganizationId || ""), + // ), + // with: { + // user: true, + // }, + // }); + // return memberResult; + // }), + // logout: protectedProcedure.mutation(async ({ ctx }) => { + // const { req } = ctx; + // const { session } = await validateRequest(req); + // if (!session) return false; + // // await lucia.invalidateSession(session.id); + // // res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); + // return true; + // }), + // update: protectedProcedure.mutation(async ({ ctx, input }) => { + // const currentAuth = await findAuthByEmail(ctx.user.email); + // if (input.currentPassword || input.password) { + // const correctPassword = bcrypt.compareSync( + // input.currentPassword || "", + // currentAuth?.password || "", + // ); + // if (!correctPassword) { + // throw new TRPCError({ + // code: "BAD_REQUEST", + // message: "Current password is incorrect", + // }); + // } + // } + // // const auth = await updateAuthById(ctx.user.authId, { + // // ...(input.email && { email: input.email.toLowerCase() }), + // // ...(input.password && { + // // password: bcrypt.hashSync(input.password, 10), + // // }), + // // ...(input.image && { image: input.image }), + // // }); + // return auth; + // }), + // removeSelfAccount: protectedProcedure + // .input( + // z.object({ + // password: z.string().min(1), + // }), + // ) + // .mutation(async ({ ctx, input }) => { + // if (!IS_CLOUD) { + // throw new TRPCError({ + // code: "NOT_FOUND", + // message: "This feature is only available in the cloud version", + // }); + // } + // const currentAuth = await findAuthByEmail(ctx.user.email); + // const correctPassword = bcrypt.compareSync( + // input.password, + // currentAuth?.password || "", + // ); + // if (!correctPassword) { + // throw new TRPCError({ + // code: "BAD_REQUEST", + // message: "Password is incorrect", + // }); + // } + // const { req } = ctx; + // const { session } = await validateRequest(req); + // if (!session) return false; + // // await lucia.invalidateSession(session.id); + // // res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize()); + // // if (ctx.user.rol === "owner") { + // // await removeAdminByAuthId(ctx.user.authId); + // // } else { + // // await removeUserByAuthId(ctx.user.authId); + // // } + // return true; + // }), + // generateToken: protectedProcedure.mutation(async ({ ctx }) => { + // const auth = await findUserById(ctx.user.id); + // console.log(auth); + // // if (auth.token) { + // // await luciaToken.invalidateSession(auth.token); + // // } + // // const session = await luciaToken.createSession(auth?.id || "", { + // // expiresIn: 60 * 60 * 24 * 30, + // // }); + // // await updateUser(auth.id, { + // // token: session.id, + // // }); + // return auth; + // }), + // verifyToken: protectedProcedure.mutation(async () => { + // return true; + // }), + // one: adminProcedure + // .input(z.object({ userId: z.string().min(1) })) + // .query(async ({ input }) => { + // // TODO: Check if the user is admin or member + // const user = await findUserById(input.userId); + // return user; + // }), + // sendResetPasswordEmail: publicProcedure + // .input( + // z.object({ + // email: z.string().min(1).email(), + // }), + // ) + // .mutation(async ({ input }) => { + // if (!IS_CLOUD) { + // throw new TRPCError({ + // code: "NOT_FOUND", + // message: "This feature is only available in the cloud version", + // }); + // } + // const authR = await db.query.auth.findFirst({ + // where: eq(auth.email, input.email), + // }); + // if (!authR) { + // throw new TRPCError({ + // code: "NOT_FOUND", + // message: "User not found", + // }); + // } + // const token = nanoid(); + // await updateAuthById(authR.id, { + // resetPasswordToken: token, + // // Make resetPassword in 24 hours + // resetPasswordExpiresAt: new Date( + // new Date().getTime() + 24 * 60 * 60 * 1000, + // ).toISOString(), + // }); + // await sendEmailNotification( + // { + // fromAddress: process.env.SMTP_FROM_ADDRESS!, + // toAddresses: [authR.email], + // smtpServer: process.env.SMTP_SERVER!, + // smtpPort: Number(process.env.SMTP_PORT), + // username: process.env.SMTP_USERNAME!, + // password: process.env.SMTP_PASSWORD!, + // }, + // "Reset Password", + // ` + // Reset your password by clicking the link below: + // The link will expire in 24 hours. + // + // Reset Password + // + // `, + // ); + // }), }); // export const sendVerificationEmail = async (authId: string) => { diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 5717d59bf..b9f0adcd0 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -65,6 +65,19 @@ export const userRouter = createTRPCRouter({ return memberResult; }), + getServerMetrics: protectedProcedure.query(async ({ ctx }) => { + const memberResult = await db.query.member.findFirst({ + where: and( + eq(member.userId, ctx.user.id), + eq(member.organizationId, ctx.session?.activeOrganizationId || ""), + ), + with: { + user: true, + }, + }); + + return memberResult?.user; + }), update: protectedProcedure .input(apiUpdateUser) .mutation(async ({ input, ctx }) => { @@ -112,7 +125,6 @@ export const userRouter = createTRPCRouter({ const { id, ...rest } = input; - console.log(rest); await db .update(member) .set({ @@ -202,4 +214,8 @@ export const userRouter = createTRPCRouter({ throw error; } }), + + generateToken: protectedProcedure.mutation(async () => { + return "token"; + }), }); diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 192f6d0ea..2b807a57d 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -6,7 +6,7 @@ import { organization, twoFactor } from "better-auth/plugins"; import { and, desc, eq } from "drizzle-orm"; import { db } from "../db"; import * as schema from "../db/schema"; -import { sendVerificationEmail } from "../verification/send-verification-email"; +import { sendEmail } from "../verification/send-verification-email"; import { IS_CLOUD } from "../constants"; export const auth = betterAuth({ @@ -30,7 +30,11 @@ export const auth = betterAuth({ autoSignInAfterVerification: true, sendVerificationEmail: async ({ user, url }) => { console.log("Sending verification email to", user.email); - await sendVerificationEmail(user.email, url); + await sendEmail({ + email: user.email, + subject: "Verify your email", + text: `Click the link to verify your email: ${url}`, + }); }, }, emailAndPassword: { @@ -45,6 +49,13 @@ export const auth = betterAuth({ return bcrypt.compareSync(password, hash); }, }, + sendResetPassword: async ({ user, url }) => { + await sendEmail({ + email: user.email, + subject: "Reset your password", + text: `Click the link to reset your password: ${url}`, + }); + }, }, databaseHooks: { user: { diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts index 099018f2b..3509868be 100644 --- a/packages/server/src/services/admin.ts +++ b/packages/server/src/services/admin.ts @@ -1,6 +1,5 @@ import { db } from "@dokploy/server/db"; import { - type apiCreateUserInvitation, invitation, member, organization, @@ -10,42 +9,6 @@ import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import { IS_CLOUD } from "../constants"; -export type User = typeof users_temp.$inferSelect; -export const createInvitation = async ( - _input: typeof apiCreateUserInvitation._type, - _adminId: string, -) => { - // await db.transaction(async (tx) => { - // const result = await tx - // .insert(auth) - // .values({ - // email: input.email.toLowerCase(), - // rol: "user", - // password: bcrypt.hashSync("01231203012312", 10), - // }) - // .returning() - // .then((res) => res[0]); - // if (!result) { - // throw new TRPCError({ - // code: "BAD_REQUEST", - // message: "Error creating the user", - // }); - // } - // const expiresIn24Hours = new Date(); - // expiresIn24Hours.setDate(expiresIn24Hours.getDate() + 1); - // const token = randomBytes(32).toString("hex"); - // await tx - // .insert(users) - // .values({ - // adminId: adminId, - // authId: result.id, - // token, - // expirationDate: expiresIn24Hours.toISOString(), - // }) - // .returning(); - // }); -}; - export const findUserById = async (userId: string) => { const user = await db.query.users_temp.findFirst({ where: eq(users_temp.id, userId), @@ -69,34 +32,6 @@ export const findOrganizationById = async (organizationId: string) => { return organizationResult; }; -export const updateUser = async (userId: string, userData: Partial) => { - const user = await db - .update(users_temp) - .set({ - ...userData, - }) - .where(eq(users_temp.id, userId)) - .returning() - .then((res) => res[0]); - - return user; -}; - -export const updateAdminById = async ( - _adminId: string, - _adminData: Partial, -) => { - // const admin = await db - // .update(admins) - // .set({ - // ...adminData, - // }) - // .where(eq(admins.adminId, adminId)) - // .returning() - // .then((res) => res[0]); - // return admin; -}; - export const isAdminPresent = async () => { const admin = await db.query.member.findFirst({ where: eq(member.role, "owner"), diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index f36d8ef65..a1901d716 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -1,5 +1,5 @@ import { db } from "@dokploy/server/db"; -import { member, type users_temp } from "@dokploy/server/db/schema"; +import { member, users_temp } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { and, eq } from "drizzle-orm"; @@ -235,3 +235,16 @@ export const findMemberById = async ( } return result; }; + +export const updateUser = async (userId: string, userData: Partial) => { + const user = await db + .update(users_temp) + .set({ + ...userData, + }) + .where(eq(users_temp.id, userId)) + .returning() + .then((res) => res[0]); + + return user; +}; diff --git a/packages/server/src/utils/access-log/handler.ts b/packages/server/src/utils/access-log/handler.ts index bbd32cff2..d05d805f3 100644 --- a/packages/server/src/utils/access-log/handler.ts +++ b/packages/server/src/utils/access-log/handler.ts @@ -30,6 +30,7 @@ class LogRotationManager { private async getStateFromDB(): Promise { // const setting = await db.query.admins.findFirst({}); // return setting?.enableLogRotation ?? false; + return false; } private async setStateInDB(_active: boolean): Promise { diff --git a/packages/server/src/utils/backups/index.ts b/packages/server/src/utils/backups/index.ts index d1b87d692..7699a42e4 100644 --- a/packages/server/src/utils/backups/index.ts +++ b/packages/server/src/utils/backups/index.ts @@ -11,13 +11,14 @@ import { runMariadbBackup } from "./mariadb"; import { runMongoBackup } from "./mongo"; import { runMySqlBackup } from "./mysql"; import { runPostgresBackup } from "./postgres"; +import { findAdmin } from "../../services/admin"; export const initCronJobs = async () => { console.log("Setting up cron jobs...."); const admin = await findAdmin(); - if (admin?.enableDockerCleanup) { + if (admin?.user.enableDockerCleanup) { scheduleJob("docker-cleanup", "0 0 * * *", async () => { console.log( `Docker Cleanup ${new Date().toLocaleString()}] Running docker cleanup`, @@ -25,7 +26,7 @@ export const initCronJobs = async () => { await cleanUpUnusedImages(); await cleanUpDockerBuilder(); await cleanUpSystemPrune(); - await sendDockerCleanupNotifications(admin.adminId); + await sendDockerCleanupNotifications(admin.user.id); }); } @@ -42,7 +43,7 @@ export const initCronJobs = async () => { await cleanUpDockerBuilder(serverId); await cleanUpSystemPrune(serverId); await sendDockerCleanupNotifications( - admin.adminId, + admin.user.id, `Docker cleanup for Server ${name} (${serverId})`, ); }); diff --git a/packages/server/src/verification/send-verification-email.tsx b/packages/server/src/verification/send-verification-email.tsx index 0b3b3bdcc..c673c0f77 100644 --- a/packages/server/src/verification/send-verification-email.tsx +++ b/packages/server/src/verification/send-verification-email.tsx @@ -2,7 +2,15 @@ import { sendDiscordNotification, sendEmailNotification, } from "../utils/notifications/utils"; -export const sendVerificationEmail = async (email: string, url: string) => { +export const sendEmail = async ({ + email, + subject, + text, +}: { + email: string; + subject: string; + text: string; +}) => { await sendEmailNotification( { fromAddress: process.env.SMTP_FROM_ADDRESS || "", @@ -12,14 +20,8 @@ export const sendVerificationEmail = async (email: string, url: string) => { username: process.env.SMTP_USERNAME || "", password: process.env.SMTP_PASSWORD || "", }, - "Confirm your email | Dokploy", - ` - Welcome to Dokploy! - Please confirm your email by clicking the link below: - - Confirm Email - - `, + subject, + text, ); return true; From 47f7648cb356a0228d8829ebba21d80ff3c2ec8f Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 22:37:57 -0600 Subject: [PATCH 60/89] feat: improve user profile update and password change functionality This commit adds enhanced password change validation and handling: - Add password change validation in user update route - Implement password verification before allowing changes - Update user schema to support optional password fields - Fix token display in generate token component - Disable migration script temporarily --- .../settings/profile/generate-token.tsx | 2 +- .../settings/profile/profile-form.tsx | 4 +- apps/dokploy/migrate.ts | 280 +++++++++--------- apps/dokploy/server/api/routers/user.ts | 31 ++ packages/server/src/db/schema/user.ts | 2 + 5 files changed, 176 insertions(+), 143 deletions(-) diff --git a/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx b/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx index 4d36ab7a1..5213c0b9d 100644 --- a/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx @@ -51,7 +51,7 @@ export const GenerateToken = () => {
diff --git a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx index 761cfb71b..32179378a 100644 --- a/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx +++ b/apps/dokploy/components/dashboard/settings/profile/profile-form.tsx @@ -103,9 +103,9 @@ export const ProfileForm = () => { const onSubmit = async (values: Profile) => { await mutateAsync({ email: values.email.toLowerCase(), - password: values.password, + password: values.password || undefined, image: values.image, - currentPassword: values.currentPassword, + currentPassword: values.currentPassword || undefined, }) .then(async () => { await refetch(); diff --git a/apps/dokploy/migrate.ts b/apps/dokploy/migrate.ts index 097459b96..e1f52c9a3 100644 --- a/apps/dokploy/migrate.ts +++ b/apps/dokploy/migrate.ts @@ -1,149 +1,149 @@ -import { drizzle } from "drizzle-orm/postgres-js"; -import { nanoid } from "nanoid"; -import postgres from "postgres"; -import * as schema from "./server/db/schema"; +// 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 connectionString = process.env.DATABASE_URL!; -const sql = postgres(connectionString, { max: 1 }); -const db = drizzle(sql, { - schema, -}); +// 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 +// .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(), - }); +// 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]); +// 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]); +// 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.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.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); - }); +// 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/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index b9f0adcd0..1dac65fef 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -8,12 +8,14 @@ import { } from "@dokploy/server"; import { db } from "@dokploy/server/db"; import { + account, apiAssignPermissions, apiFindOneToken, apiUpdateUser, invitation, member, } from "@dokploy/server/db/schema"; +import * as bcrypt from "bcrypt"; import { TRPCError } from "@trpc/server"; import { and, asc, eq, gt } from "drizzle-orm"; import { z } from "zod"; @@ -81,6 +83,35 @@ export const userRouter = createTRPCRouter({ update: protectedProcedure .input(apiUpdateUser) .mutation(async ({ input, ctx }) => { + if (input.password || input.currentPassword) { + const currentAuth = await db.query.account.findFirst({ + where: eq(account.userId, ctx.user.id), + }); + const correctPassword = bcrypt.compareSync( + input.currentPassword || "", + currentAuth?.password || "", + ); + + if (!correctPassword) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Current password is incorrect", + }); + } + + if (!input.password) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "New password is required", + }); + } + await db + .update(account) + .set({ + password: bcrypt.hashSync(input.password, 10), + }) + .where(eq(account.userId, ctx.user.id)); + } return await updateUser(ctx.user.id, input); }), getUserByToken: publicProcedure diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 2f3761fec..3916f1e70 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -278,6 +278,8 @@ export const apiUpdateWebServerMonitoring = z.object({ }); export const apiUpdateUser = createSchema.partial().extend({ + password: z.string().optional(), + currentPassword: z.string().optional(), metricsConfig: z .object({ server: z.object({ From 3f2722f28d55e94e84b67bad031acda272241829 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 22:38:38 -0600 Subject: [PATCH 61/89] refactor: remove unused imports and simplify auth router --- apps/dokploy/server/api/routers/auth.ts | 32 +------------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts index 68a2eba73..2c7469c3f 100644 --- a/apps/dokploy/server/api/routers/auth.ts +++ b/apps/dokploy/server/api/routers/auth.ts @@ -1,34 +1,4 @@ -import { - // apiCreateAdmin, - // apiCreateUser, - // apiFindOneAuth, - // apiLogin, - // apiUpdateAuth, - // apiVerify2FA, - // apiVerifyLogin2FA, - // auth, - member, -} from "@/server/db/schema"; -import { WEBSITE_URL } from "@/server/utils/stripe"; -import { - IS_CLOUD, - findUserById, - getUserByToken, - sendEmailNotification, - validateRequest, -} from "@dokploy/server"; -import { TRPCError } from "@trpc/server"; -import * as bcrypt from "bcrypt"; -import { and, eq } from "drizzle-orm"; -import { nanoid } from "nanoid"; -import { z } from "zod"; -import { db } from "../../db"; -import { - adminProcedure, - createTRPCRouter, - protectedProcedure, - publicProcedure, -} from "../trpc"; +import { createTRPCRouter } from "../trpc"; export const authRouter = createTRPCRouter({ // createAdmin: publicProcedure.mutation(async ({ input }) => { From 0ec8e2baa1a7c8ad3d36b9122f0f104adc6f589a Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 23:20:27 -0600 Subject: [PATCH 62/89] chore: update GitHub workflow branch trigger for authentication feature branch --- .github/workflows/dokploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dokploy.yml b/.github/workflows/dokploy.yml index 9914811e8..adcb1bb54 100644 --- a/.github/workflows/dokploy.yml +++ b/.github/workflows/dokploy.yml @@ -2,7 +2,7 @@ name: Dokploy Docker Build on: push: - branches: [main, canary, "feat/monitoring"] + branches: [main, canary, "feat/better-auth-2"] env: IMAGE_NAME: dokploy/dokploy From 30cbad93d21f9d732a4dc9b4897fd5efed09f1e3 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 23:22:15 -0600 Subject: [PATCH 63/89] refactor: improve Traefik error handling in service initialization --- packages/server/src/setup/traefik-setup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/setup/traefik-setup.ts b/packages/server/src/setup/traefik-setup.ts index 21caa5cf2..e8d019424 100644 --- a/packages/server/src/setup/traefik-setup.ts +++ b/packages/server/src/setup/traefik-setup.ts @@ -127,7 +127,7 @@ export const initializeTraefik = async ({ }); console.log("Traefik Started ✅"); - } catch (error) { + } catch (_) { try { await docker.createService(settings); } catch (error: any) { From 87836d23c37837a7571b1b4b5dd60f87c2696c16 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 22 Feb 2025 23:25:22 -0600 Subject: [PATCH 64/89] chore: disable TypeScript declaration generation in server tsconfig --- packages/server/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index 0eb9923a6..db7ded39e 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { /* Base Options: */ "esModuleInterop": true, + "declaration": false, "skipLibCheck": true, "target": "es2022", "allowJs": true, From 4a1a5a9bb1d11204c3a6ff44b5a0d82773e51307 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:04:24 -0600 Subject: [PATCH 65/89] chore: comment out database schema definitions in auth-schema --- packages/server/auth-schema.ts | 182 ++++++++++++++++----------------- 1 file changed, 90 insertions(+), 92 deletions(-) diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index a7be9b051..b9b682fbf 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,99 +1,97 @@ -import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; +// export const users_temp = pgTable("users_temp", { +// id: text("id").primaryKey(), +// name: text("name").notNull(), +// email: text("email").notNull().unique(), +// emailVerified: boolean("email_verified").notNull(), +// image: text("image"), +// createdAt: timestamp("created_at").notNull(), +// updatedAt: timestamp("updated_at").notNull(), +// twoFactorEnabled: boolean("two_factor_enabled"), +// role: text("role"), +// ownerId: text("owner_id"), +// }); -export const users_temp = pgTable("users_temp", { - id: text("id").primaryKey(), - name: text("name").notNull(), - email: text("email").notNull().unique(), - emailVerified: boolean("email_verified").notNull(), - image: text("image"), - createdAt: timestamp("created_at").notNull(), - updatedAt: timestamp("updated_at").notNull(), - twoFactorEnabled: boolean("two_factor_enabled"), - role: text("role"), - ownerId: text("owner_id"), -}); +// export const session = pgTable("session", { +// id: text("id").primaryKey(), +// expiresAt: timestamp("expires_at").notNull(), +// token: text("token").notNull().unique(), +// createdAt: timestamp("created_at").notNull(), +// updatedAt: timestamp("updated_at").notNull(), +// ipAddress: text("ip_address"), +// userAgent: text("user_agent"), +// userId: text("user_id") +// .notNull() +// .references(() => users_temp.id, { onDelete: "cascade" }), +// activeOrganizationId: text("active_organization_id"), +// }); -export const session = pgTable("session", { - id: text("id").primaryKey(), - expiresAt: timestamp("expires_at").notNull(), - token: text("token").notNull().unique(), - createdAt: timestamp("created_at").notNull(), - updatedAt: timestamp("updated_at").notNull(), - ipAddress: text("ip_address"), - userAgent: text("user_agent"), - userId: text("user_id") - .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), - activeOrganizationId: text("active_organization_id"), -}); +// export const account = pgTable("account", { +// id: text("id").primaryKey(), +// accountId: text("account_id").notNull(), +// providerId: text("provider_id").notNull(), +// userId: text("user_id") +// .notNull() +// .references(() => users_temp.id, { onDelete: "cascade" }), +// accessToken: text("access_token"), +// refreshToken: text("refresh_token"), +// idToken: text("id_token"), +// accessTokenExpiresAt: timestamp("access_token_expires_at"), +// refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), +// scope: text("scope"), +// password: text("password"), +// createdAt: timestamp("created_at").notNull(), +// updatedAt: timestamp("updated_at").notNull(), +// }); -export const account = pgTable("account", { - id: text("id").primaryKey(), - accountId: text("account_id").notNull(), - providerId: text("provider_id").notNull(), - userId: text("user_id") - .notNull() - .references(() => users_temp.id, { onDelete: "cascade" }), - accessToken: text("access_token"), - refreshToken: text("refresh_token"), - idToken: text("id_token"), - accessTokenExpiresAt: timestamp("access_token_expires_at"), - refreshTokenExpiresAt: timestamp("refresh_token_expires_at"), - scope: text("scope"), - password: text("password"), - createdAt: timestamp("created_at").notNull(), - updatedAt: timestamp("updated_at").notNull(), -}); +// export const verification = pgTable("verification", { +// id: text("id").primaryKey(), +// identifier: text("identifier").notNull(), +// value: text("value").notNull(), +// expiresAt: timestamp("expires_at").notNull(), +// createdAt: timestamp("created_at"), +// updatedAt: timestamp("updated_at"), +// }); -export const verification = pgTable("verification", { - id: text("id").primaryKey(), - identifier: text("identifier").notNull(), - value: text("value").notNull(), - expiresAt: timestamp("expires_at").notNull(), - createdAt: timestamp("created_at"), - updatedAt: timestamp("updated_at"), -}); +// export const twoFactor = pgTable("two_factor", { +// id: text("id").primaryKey(), +// secret: text("secret").notNull(), +// backupCodes: text("backup_codes").notNull(), +// userId: text("user_id") +// .notNull() +// .references(() => user.id, { onDelete: "cascade" }), +// }); -export const twoFactor = pgTable("two_factor", { - id: text("id").primaryKey(), - secret: text("secret").notNull(), - backupCodes: text("backup_codes").notNull(), - userId: text("user_id") - .notNull() - .references(() => user.id, { onDelete: "cascade" }), -}); +// export const organization = pgTable("organization", { +// id: text("id").primaryKey(), +// name: text("name").notNull(), +// slug: text("slug").unique(), +// logo: text("logo"), +// createdAt: timestamp("created_at").notNull(), +// metadata: text("metadata"), +// }); -export const organization = pgTable("organization", { - id: text("id").primaryKey(), - name: text("name").notNull(), - slug: text("slug").unique(), - logo: text("logo"), - createdAt: timestamp("created_at").notNull(), - metadata: text("metadata"), -}); +// export const member = pgTable("member", { +// id: text("id").primaryKey(), +// organizationId: text("organization_id") +// .notNull() +// .references(() => organization.id, { onDelete: "cascade" }), +// userId: text("user_id") +// .notNull() +// .references(() => user.id, { onDelete: "cascade" }), +// role: text("role").notNull(), +// createdAt: timestamp("created_at").notNull(), +// }); -export const member = pgTable("member", { - id: text("id").primaryKey(), - organizationId: text("organization_id") - .notNull() - .references(() => organization.id, { onDelete: "cascade" }), - userId: text("user_id") - .notNull() - .references(() => user.id, { onDelete: "cascade" }), - role: text("role").notNull(), - createdAt: timestamp("created_at").notNull(), -}); - -export const invitation = pgTable("invitation", { - id: text("id").primaryKey(), - organizationId: text("organization_id") - .notNull() - .references(() => organization.id, { onDelete: "cascade" }), - email: text("email").notNull(), - role: text("role"), - status: text("status").notNull(), - expiresAt: timestamp("expires_at").notNull(), - inviterId: text("inviter_id") - .notNull() - .references(() => user.id, { onDelete: "cascade" }), -}); +// export const invitation = pgTable("invitation", { +// id: text("id").primaryKey(), +// organizationId: text("organization_id") +// .notNull() +// .references(() => organization.id, { onDelete: "cascade" }), +// email: text("email").notNull(), +// role: text("role"), +// status: text("status").notNull(), +// expiresAt: timestamp("expires_at").notNull(), +// inviterId: text("inviter_id") +// .notNull() +// .references(() => user.id, { onDelete: "cascade" }), +// }); From 9dd7f51eebb2bc47663e657d5dc63c5aa6dea794 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:07:38 -0600 Subject: [PATCH 66/89] chore: disable TypeScript declaration generation in schedules tsconfig --- apps/schedules/tsconfig.json | 3 ++- packages/server/tsconfig.server.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/schedules/tsconfig.json b/apps/schedules/tsconfig.json index 3c0b02bc0..3d4adb168 100644 --- a/apps/schedules/tsconfig.json +++ b/apps/schedules/tsconfig.json @@ -7,7 +7,8 @@ "skipLibCheck": true, "outDir": "dist", "jsx": "react-jsx", - "jsxImportSource": "hono/jsx" + "jsxImportSource": "hono/jsx", + "declaration": false }, "exclude": ["node_modules", "dist"] } diff --git a/packages/server/tsconfig.server.json b/packages/server/tsconfig.server.json index 7f349eb82..9a7cdd1bb 100644 --- a/packages/server/tsconfig.server.json +++ b/packages/server/tsconfig.server.json @@ -6,7 +6,7 @@ "target": "ESNext", "isolatedModules": false, "noEmit": false, - "declaration": true, + "declaration": false, "moduleResolution": "Node", "rootDir": "./src", "baseUrl": ".", From 716c1db7992a720f8c2620a771497795d9504528 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:13:35 -0600 Subject: [PATCH 67/89] Revert "chore: disable TypeScript declaration generation in server tsconfig" This reverts commit 87836d23c37837a7571b1b4b5dd60f87c2696c16. --- packages/server/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index db7ded39e..0eb9923a6 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -2,7 +2,6 @@ "compilerOptions": { /* Base Options: */ "esModuleInterop": true, - "declaration": false, "skipLibCheck": true, "target": "es2022", "allowJs": true, From 7429a1f65f3e9f39dd452690b3610fbabae475a1 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:16:51 -0600 Subject: [PATCH 68/89] chore: enable TypeScript declaration generation in server tsconfig --- packages/server/tsconfig.server.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/server/tsconfig.server.json b/packages/server/tsconfig.server.json index 9a7cdd1bb..645d3425a 100644 --- a/packages/server/tsconfig.server.json +++ b/packages/server/tsconfig.server.json @@ -6,7 +6,8 @@ "target": "ESNext", "isolatedModules": false, "noEmit": false, - "declaration": false, + "declaration": true, + "declarationMap": true, "moduleResolution": "Node", "rootDir": "./src", "baseUrl": ".", From 579faf2f58273536b5f325d67a32e12f8c903790 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:20:27 -0600 Subject: [PATCH 69/89] chore: adjust TypeScript configuration in server tsconfig --- packages/server/tsconfig.server.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/server/tsconfig.server.json b/packages/server/tsconfig.server.json index 645d3425a..cd408f7ac 100644 --- a/packages/server/tsconfig.server.json +++ b/packages/server/tsconfig.server.json @@ -14,7 +14,9 @@ "jsx": "react-jsx", "paths": { "@dokploy/server/*": ["./src/*"] - } + }, + "skipLibCheck": true, + "noImplicitAny": false }, "include": ["next-env.d.ts", "./src/**/*"], "exclude": ["**/dist", "tsup.ts"], From c0a7347ef56b5edfd512bc6527453a9bd71a35ec Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:22:17 -0600 Subject: [PATCH 70/89] chore: remove additional TypeScript configuration options in server tsconfig --- packages/server/tsconfig.server.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/server/tsconfig.server.json b/packages/server/tsconfig.server.json index cd408f7ac..7f349eb82 100644 --- a/packages/server/tsconfig.server.json +++ b/packages/server/tsconfig.server.json @@ -7,16 +7,13 @@ "isolatedModules": false, "noEmit": false, "declaration": true, - "declarationMap": true, "moduleResolution": "Node", "rootDir": "./src", "baseUrl": ".", "jsx": "react-jsx", "paths": { "@dokploy/server/*": ["./src/*"] - }, - "skipLibCheck": true, - "noImplicitAny": false + } }, "include": ["next-env.d.ts", "./src/**/*"], "exclude": ["**/dist", "tsup.ts"], From b1e7ffea21d4386d1e46a9b26cd5dea902a6c825 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:22:35 -0600 Subject: [PATCH 71/89] chore: enable TypeScript size limit bypass in server tsconfig --- packages/server/tsconfig.server.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server/tsconfig.server.json b/packages/server/tsconfig.server.json index 7f349eb82..33777c025 100644 --- a/packages/server/tsconfig.server.json +++ b/packages/server/tsconfig.server.json @@ -1,6 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { + "disableSizeLimit": true, "module": "ESNext", "outDir": "dist/", "target": "ESNext", From 0ea138571d45e3b163af913df5480cd93f423962 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 23 Feb 2025 00:35:08 -0600 Subject: [PATCH 72/89] refactor: update auth module to separate handler and API --- packages/server/src/lib/auth.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 2b807a57d..24e23bfd7 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -9,7 +9,7 @@ import * as schema from "../db/schema"; import { sendEmail } from "../verification/send-verification-email"; import { IS_CLOUD } from "../constants"; -export const auth = betterAuth({ +const { handler, api } = betterAuth({ database: drizzleAdapter(db, { provider: "pg", schema: schema, @@ -144,8 +144,12 @@ export const auth = betterAuth({ ], }); +export const auth = { + handler, +}; + export const validateRequest = async (request: IncomingMessage) => { - const session = await auth.api.getSession({ + const session = await api.getSession({ headers: new Headers({ cookie: request.headers.cookie || "", }), From 73d3b5886745b835551347a418016511dab11b69 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 23 Feb 2025 01:59:00 -0600 Subject: [PATCH 73/89] feat: add GitHub sign-in option for cloud environment --- apps/dokploy/pages/index.tsx | 124 +++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 42 deletions(-) diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 4a85952e6..768498e8c 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -62,6 +62,7 @@ export default function Home({ IS_CLOUD }: Props) { const [twoFactorCode, setTwoFactorCode] = useState(""); const [isBackupCodeModalOpen, setIsBackupCodeModalOpen] = useState(false); const [backupCode, setBackupCode] = useState(""); + const [isGithubLoading, setIsGithubLoading] = useState(false); const loginForm = useForm({ resolver: zodResolver(LoginSchema), @@ -160,6 +161,26 @@ export default function Home({ IS_CLOUD }: Props) { } }; + const handleGithubSignIn = async () => { + setIsGithubLoading(true); + try { + const { error } = await authClient.signIn.social({ + provider: "github", + }); + + if (error) { + toast.error(error.message); + return; + } + } catch (error) { + toast.error("An error occurred while signing in with GitHub", { + description: error instanceof Error ? error.message : "Unknown error", + }); + } finally { + setIsGithubLoading(false); + } + }; + return ( <>
@@ -180,51 +201,70 @@ export default function Home({ IS_CLOUD }: Props) { )} {!isTwoFactor ? ( - - - ( - - Email - - - - - - )} - /> - ( - - Password - - - - - - )} - /> + <> + {IS_CLOUD && ( - - + )} +
+ + ( + + Email + + + + + + )} + /> + ( + + Password + + + + + + )} + /> + + + + ) : ( <>
Date: Tue, 25 Feb 2025 23:13:55 -0600 Subject: [PATCH 74/89] refactor(ui): enhance sidebar layout with responsive design and collapsed state --- apps/dokploy/components/layouts/side.tsx | 61 +++++++++++++++++++----- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 9c61fb396..054988713 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -525,34 +525,63 @@ function SidebarLogo() {
) : ( - - + + {/* Organization Logo and Selector */} + -
-
+
+
-
+

{activeOrganization?.name ?? "Select Organization"}

- + + + {/* Notification Bell */} + -
+
+ + setLogo(e.target.value)} + placeholder="https://example.com/logo.png" + className="col-span-3" + /> +
diff --git a/apps/dokploy/components/shared/logo.tsx b/apps/dokploy/components/shared/logo.tsx index 086ef3b0c..bad6346ce 100644 --- a/apps/dokploy/components/shared/logo.tsx +++ b/apps/dokploy/components/shared/logo.tsx @@ -1,8 +1,20 @@ interface Props { className?: string; + logoUrl?: string; } -export const Logo = ({ className = "size-14" }: Props) => { +export const Logo = ({ className = "size-14", logoUrl }: Props) => { + if (logoUrl) { + return ( + Organization Logo + ); + } + return ( { @@ -81,6 +82,7 @@ export const organizationRouter = createTRPCRouter({ z.object({ organizationId: z.string(), name: z.string(), + logo: z.string().optional(), }), ) .mutation(async ({ ctx, input }) => { @@ -92,7 +94,10 @@ export const organizationRouter = createTRPCRouter({ } const result = await db .update(organization) - .set({ name: input.name }) + .set({ + name: input.name, + logo: input.logo, + }) .where(eq(organization.id, input.organizationId)) .returning(); return result[0]; From 8c2707c4ea439c2387901e8586943a36a7438cf7 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Tue, 25 Feb 2025 23:33:26 -0600 Subject: [PATCH 76/89] refactor(organization): migrate to react-hook-form with zod validation --- .../organization/handle-organization.tsx | 133 ++++++++++++------ apps/dokploy/components/layouts/side.tsx | 4 +- apps/dokploy/components/shared/logo.tsx | 5 +- 3 files changed, 96 insertions(+), 46 deletions(-) diff --git a/apps/dokploy/components/dashboard/organization/handle-organization.tsx b/apps/dokploy/components/dashboard/organization/handle-organization.tsx index 249b8ccd0..014c37df1 100644 --- a/apps/dokploy/components/dashboard/organization/handle-organization.tsx +++ b/apps/dokploy/components/dashboard/organization/handle-organization.tsx @@ -9,18 +9,39 @@ import { DialogTrigger, } from "@/components/ui/dialog"; import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; +import { zodResolver } from "@hookform/resolvers/zod"; import { PenBoxIcon, Plus } from "lucide-react"; import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; import { toast } from "sonner"; +import { z } from "zod"; + +const organizationSchema = z.object({ + name: z.string().min(1, { + message: "Organization name is required", + }), + logo: z.string().optional(), +}); + +type OrganizationFormValues = z.infer; interface Props { organizationId?: string; children?: React.ReactNode; } + export function AddOrganization({ organizationId }: Props) { + const [open, setOpen] = useState(false); const utils = api.useUtils(); const { data: organization } = api.organization.one.useQuery( { @@ -33,24 +54,37 @@ export function AddOrganization({ organizationId }: Props) { const { mutateAsync, isLoading } = organizationId ? api.organization.update.useMutation() : api.organization.create.useMutation(); - const [open, setOpen] = useState(false); - const [name, setName] = useState(""); - const [logo, setLogo] = useState(""); + + const form = useForm({ + resolver: zodResolver(organizationSchema), + defaultValues: { + name: "", + logo: "", + }, + }); useEffect(() => { if (organization) { - setName(organization.name); - setLogo(organization.logo || ""); + form.reset({ + name: organization.name, + logo: organization.logo || "", + }); } - }, [organization]); - const handleSubmit = async () => { - await mutateAsync({ name, logo, organizationId: organizationId ?? "" }) + }, [organization, form]); + + const onSubmit = async (values: OrganizationFormValues) => { + await mutateAsync({ + name: values.name, + logo: values.logo, + organizationId: organizationId ?? "", + }) .then(() => { - setOpen(false); + form.reset(); toast.success( `Organization ${organizationId ? "updated" : "created"} successfully`, ); utils.organization.all.invalidate(); + setOpen(false); }) .catch((error) => { console.error(error); @@ -59,6 +93,7 @@ export function AddOrganization({ organizationId }: Props) { ); }); }; + return ( @@ -67,14 +102,11 @@ export function AddOrganization({ organizationId }: Props) { className="group cursor-pointer hover:bg-blue-500/10" onSelect={(e) => e.preventDefault()} > - + ) : ( { - setOpen(true); - }} onSelect={(e) => e.preventDefault()} >
@@ -97,36 +129,53 @@ export function AddOrganization({ organizationId }: Props) { : "Create a new organization to manage your projects."} -
-
- - setName(e.target.value)} - className="col-span-3" + + + ( + + Name + + + + + + )} /> -
-
- - setLogo(e.target.value)} - placeholder="https://example.com/logo.png" - className="col-span-3" + ( + + Logo URL + + + + + + )} /> -
-
- - - + + + + +
); diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 58638509e..805fe8dc7 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -534,7 +534,7 @@ function SidebarLogo() { )} > {/* Organization Logo and Selector */} - +
{ Organization Logo ); } From cbec0603bdd4572831bb6cf2b85103bd7bebbb17 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Tue, 25 Feb 2025 23:36:53 -0600 Subject: [PATCH 77/89] feat(ui): add loading state to sidebar layout --- apps/dokploy/components/layouts/side.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index 805fe8dc7..f7a63064e 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -751,6 +751,7 @@ export default function Page({ children }: Props) { const [defaultOpen, setDefaultOpen] = useState( undefined, ); + const [isLoaded, setIsLoaded] = useState(false); useEffect(() => { const cookieValue = document.cookie @@ -759,6 +760,7 @@ export default function Page({ children }: Props) { ?.split("=")[1]; setDefaultOpen(cookieValue === undefined ? true : cookieValue === "true"); + setIsLoaded(true); }, []); const router = useRouter(); @@ -780,9 +782,9 @@ export default function Page({ children }: Props) { pathname, ); - // const showProjectsButton = - // currentPath === "/dashboard/projects" && - // (auth?.rol === "owner" || user?.canCreateProjects); + if (!isLoaded) { + return
; // Placeholder mientras se carga + } return ( Date: Tue, 25 Feb 2025 23:37:22 -0600 Subject: [PATCH 78/89] refactor(ui): remove loading text in sidebar layout --- apps/dokploy/components/layouts/side.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index f7a63064e..19ef6f445 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -521,7 +521,6 @@ function SidebarLogo() { <> {isLoading ? (
- Loading...
) : ( From 55686298391eade54406b439c81caa63f6b50442 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 14:45:50 -0600 Subject: [PATCH 79/89] refactor: organize imports and improve template utility modules --- apps/dokploy/drizzle/0066_yielding_echo.sql | 35 +++- apps/dokploy/drizzle/meta/0066_snapshot.json | 177 ++++++++++++++++++- apps/dokploy/drizzle/meta/_journal.json | 7 + apps/dokploy/package.json | 2 +- packages/server/auth-schema.ts | 36 ++++ packages/server/package.json | 2 +- packages/server/src/db/schema/account.ts | 37 +++- packages/server/src/lib/auth.ts | 11 +- pnpm-lock.yaml | 54 ++++-- 9 files changed, 320 insertions(+), 41 deletions(-) diff --git a/apps/dokploy/drizzle/0066_yielding_echo.sql b/apps/dokploy/drizzle/0066_yielding_echo.sql index 4fd425387..a8a2501a8 100644 --- a/apps/dokploy/drizzle/0066_yielding_echo.sql +++ b/apps/dokploy/drizzle/0066_yielding_echo.sql @@ -72,7 +72,8 @@ CREATE TABLE "invitation" ( "role" text, "status" text NOT NULL, "expires_at" timestamp NOT NULL, - "inviter_id" text NOT NULL + "inviter_id" text NOT NULL, + "team_id" text ); --> statement-breakpoint CREATE TABLE "member" ( @@ -81,7 +82,6 @@ CREATE TABLE "member" ( "user_id" text NOT NULL, "role" text NOT NULL, "created_at" timestamp NOT NULL, - "token" text NOT NULL, "canCreateProjects" boolean DEFAULT false NOT NULL, "canAccessToSSHKeys" boolean DEFAULT false NOT NULL, "canCreateServices" boolean DEFAULT false NOT NULL, @@ -92,7 +92,8 @@ CREATE TABLE "member" ( "canAccessToGitProviders" boolean DEFAULT false NOT NULL, "canAccessToTraefikFiles" boolean DEFAULT false NOT NULL, "accesedProjects" text[] DEFAULT ARRAY[]::text[] NOT NULL, - "accesedServices" text[] DEFAULT ARRAY[]::text[] NOT NULL + "accesedServices" text[] DEFAULT ARRAY[]::text[] NOT NULL, + "team_id" text ); --> statement-breakpoint CREATE TABLE "organization" ( @@ -121,6 +122,30 @@ CREATE TABLE "two_factor" ( "backup_codes" text NOT NULL, "user_id" text NOT NULL ); + +CREATE TABLE "apikey" ( + "id" text PRIMARY KEY NOT NULL, + "name" text, + "start" text, + "prefix" text, + "key" text NOT NULL, + "user_id" text NOT NULL, + "refill_interval" integer, + "refill_amount" integer, + "last_refill_at" timestamp, + "enabled" boolean, + "rate_limit_enabled" boolean, + "rate_limit_time_window" integer, + "rate_limit_max" integer, + "request_count" integer, + "remaining" integer, + "last_request" timestamp, + "expires_at" timestamp, + "created_at" timestamp NOT NULL, + "updated_at" timestamp NOT NULL, + "permissions" text, + "metadata" text +); --> statement-breakpoint ALTER TABLE "certificate" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint ALTER TABLE "notification" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint @@ -134,9 +159,7 @@ ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_temp_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action; ALTER TABLE "two_factor" ADD CONSTRAINT "two_factor_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint - - - +ALTER TABLE "apikey" ADD CONSTRAINT "apikey_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -- Data Migration diff --git a/apps/dokploy/drizzle/meta/0066_snapshot.json b/apps/dokploy/drizzle/meta/0066_snapshot.json index 2264814c2..55804f0cc 100644 --- a/apps/dokploy/drizzle/meta/0066_snapshot.json +++ b/apps/dokploy/drizzle/meta/0066_snapshot.json @@ -4295,6 +4295,159 @@ "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": "", @@ -4340,6 +4493,13 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": false + } }, "indexes": {}, @@ -4411,6 +4571,12 @@ "primaryKey": false, "notNull": true }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, "canCreateProjects": { "name": "canCreateProjects", "type": "boolean", @@ -4487,13 +4653,6 @@ "primaryKey": false, "notNull": true, "default": "ARRAY[]::text[]" - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" } }, "indexes": {}, @@ -4508,7 +4667,7 @@ "columnsTo": [ "id" ], - "onDelete": "no action", + "onDelete": "cascade", "onUpdate": "no action" }, "member_user_id_user_temp_id_fk": { @@ -4521,7 +4680,7 @@ "columnsTo": [ "id" ], - "onDelete": "no action", + "onDelete": "cascade", "onUpdate": "no action" } }, diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 8bf49b3a0..29a356e0e 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -470,6 +470,13 @@ "when": 1739426913392, "tag": "0066_yielding_echo", "breakpoints": true + }, + { + "idx": 67, + "version": "7", + "when": 1740860314823, + "tag": "0067_goofy_red_skull", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 5f59efec0..a1626fc43 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -36,7 +36,7 @@ "test": "vitest --config __test__/vitest.config.ts" }, "dependencies": { - "better-auth": "1.1.16", + "better-auth": "beta", "bl": "6.0.11", "rotating-file-stream": "3.2.3", "qrcode": "^1.5.3", diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index b9b682fbf..a58290467 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,3 +1,11 @@ +// import { +// pgTable, +// text, +// integer, +// timestamp, +// boolean, +// } from "drizzle-orm/pg-core"; + // export const users_temp = pgTable("users_temp", { // id: text("id").primaryKey(), // name: text("name").notNull(), @@ -52,6 +60,32 @@ // updatedAt: timestamp("updated_at"), // }); +// export const apikey = pgTable("apikey", { +// id: text("id").primaryKey(), +// name: text("name"), +// start: text("start"), +// prefix: text("prefix"), +// key: text("key").notNull(), +// userId: text("user_id") +// .notNull() +// .references(() => user.id, { onDelete: "cascade" }), +// refillInterval: integer("refill_interval"), +// refillAmount: integer("refill_amount"), +// lastRefillAt: timestamp("last_refill_at"), +// enabled: boolean("enabled"), +// rateLimitEnabled: boolean("rate_limit_enabled"), +// rateLimitTimeWindow: integer("rate_limit_time_window"), +// rateLimitMax: integer("rate_limit_max"), +// requestCount: integer("request_count"), +// remaining: integer("remaining"), +// lastRequest: timestamp("last_request"), +// expiresAt: timestamp("expires_at"), +// createdAt: timestamp("created_at").notNull(), +// updatedAt: timestamp("updated_at").notNull(), +// permissions: text("permissions"), +// metadata: text("metadata"), +// }); + // export const twoFactor = pgTable("two_factor", { // id: text("id").primaryKey(), // secret: text("secret").notNull(), @@ -79,6 +113,7 @@ // .notNull() // .references(() => user.id, { onDelete: "cascade" }), // role: text("role").notNull(), +// teamId: text("team_id"), // createdAt: timestamp("created_at").notNull(), // }); @@ -89,6 +124,7 @@ // .references(() => organization.id, { onDelete: "cascade" }), // email: text("email").notNull(), // role: text("role"), +// teamId: text("team_id"), // status: text("status").notNull(), // expiresAt: timestamp("expires_at").notNull(), // inviterId: text("inviter_id") diff --git a/packages/server/package.json b/packages/server/package.json index dbc24375e..bd2d9ed06 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -32,7 +32,7 @@ "@oslojs/encoding":"1.1.0", "@oslojs/crypto":"1.0.1", "drizzle-dbml-generator":"0.10.0", - "better-auth":"1.1.16", + "better-auth":"beta", "rotating-file-stream": "3.2.3", "@faker-js/faker": "^8.4.1", "@lucia-auth/adapter-drizzle": "1.0.7", diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 9d55016d9..e5f2dab77 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -1,5 +1,11 @@ import { relations, sql } from "drizzle-orm"; -import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; +import { + boolean, + integer, + pgTable, + text, + timestamp, +} from "drizzle-orm/pg-core"; import { nanoid } from "nanoid"; import { projects } from "./project"; import { server } from "./server"; @@ -87,7 +93,7 @@ export const member = pgTable("member", { .references(() => users_temp.id, { onDelete: "cascade" }), role: text("role").notNull().$type<"owner" | "member" | "admin">(), createdAt: timestamp("created_at").notNull(), - + teamId: text("team_id"), // Permissions canCreateProjects: boolean("canCreateProjects").notNull().default(false), canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false), @@ -135,6 +141,7 @@ export const invitation = pgTable("invitation", { inviterId: text("inviter_id") .notNull() .references(() => users_temp.id, { onDelete: "cascade" }), + teamId: text("team_id"), }); export const invitationRelations = relations(invitation, ({ one }) => ({ @@ -152,3 +159,29 @@ export const twoFactor = pgTable("two_factor", { .notNull() .references(() => users_temp.id, { onDelete: "cascade" }), }); + +export const apikey = pgTable("apikey", { + id: text("id").primaryKey(), + name: text("name"), + start: text("start"), + prefix: text("prefix"), + key: text("key").notNull(), + userId: text("user_id") + .notNull() + .references(() => users_temp.id, { onDelete: "cascade" }), + refillInterval: integer("refill_interval"), + refillAmount: integer("refill_amount"), + lastRefillAt: timestamp("last_refill_at"), + enabled: boolean("enabled"), + rateLimitEnabled: boolean("rate_limit_enabled"), + rateLimitTimeWindow: integer("rate_limit_time_window"), + rateLimitMax: integer("rate_limit_max"), + requestCount: integer("request_count"), + remaining: integer("remaining"), + lastRequest: timestamp("last_request"), + expiresAt: timestamp("expires_at"), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), + permissions: text("permissions"), + metadata: text("metadata"), +}); diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 24e23bfd7..bebcd54ee 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -2,14 +2,14 @@ import type { IncomingMessage } from "node:http"; import * as bcrypt from "bcrypt"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; -import { organization, twoFactor } from "better-auth/plugins"; +import { organization, twoFactor, apiKey } from "better-auth/plugins"; import { and, desc, eq } from "drizzle-orm"; import { db } from "../db"; import * as schema from "../db/schema"; import { sendEmail } from "../verification/send-verification-email"; import { IS_CLOUD } from "../constants"; -const { handler, api } = betterAuth({ +export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", schema: schema, @@ -126,6 +126,7 @@ const { handler, api } = betterAuth({ }, plugins: [ + apiKey(), twoFactor(), organization({ async sendInvitationEmail(data, _request) { @@ -144,9 +145,9 @@ const { handler, api } = betterAuth({ ], }); -export const auth = { - handler, -}; +// export const auth = { +// handler, +// }; export const validateRequest = async (request: IncomingMessage) => { const session = await api.getSession({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ee68b3995..6e1c088b8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -239,8 +239,8 @@ importers: specifier: 5.1.1 version: 5.1.1(encoding@0.1.13) better-auth: - specifier: 1.1.16 - version: 1.1.16 + specifier: beta + version: 1.2.0-beta.18(typescript@5.5.3) bl: specifier: 6.0.11 version: 6.0.11 @@ -580,8 +580,8 @@ importers: specifier: 5.1.1 version: 5.1.1(encoding@0.1.13) better-auth: - specifier: 1.1.16 - version: 1.1.16 + specifier: beta + version: 1.2.0-beta.18(typescript@5.5.3) bl: specifier: 6.0.11 version: 6.0.11 @@ -769,8 +769,8 @@ packages: '@better-auth/utils@0.2.3': resolution: {integrity: sha512-Ap1GaSmo6JYhJhxJOpUB0HobkKPTNzfta+bLV89HfpyCAHN7p8ntCrmNFHNAVD0F6v0mywFVEUg1FUhNCc81Rw==} - '@better-fetch/fetch@1.1.12': - resolution: {integrity: sha512-B3bfloI/2UBQWIATRN6qmlORrvx3Mp0kkNjmXLv0b+DtbtR+pP4/I5kQA/rDUv+OReLywCCldf6co4LdDmh8JA==} + '@better-fetch/fetch@1.1.15': + resolution: {integrity: sha512-0Bl8YYj1f8qCTNHeSn5+1DWv2hy7rLBrQ8rS8Y9XYloiwZEfc3k4yspIG0llRxafxqhGCwlGRg+F8q1HZRCMXA==} '@biomejs/biome@1.9.4': resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} @@ -3879,11 +3879,11 @@ packages: before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} - better-auth@1.1.16: - resolution: {integrity: sha512-Xc5pxafKZw4QVU8WYfkV2z4Hd8KCXXbphrgOpe2gA/EfanysLBhE1G/F7cEi5e0bW2pGR+vw6gf0ARHA7VFihg==} + better-auth@1.2.0-beta.18: + resolution: {integrity: sha512-gEjNxmrkFiATTSTcE47rkyTT9vMFMLTjtLNun4W0IWmeqfi4pIbbWpo97foY1DNXXRDkDuajquoD58dzAatQxQ==} - better-call@0.3.3: - resolution: {integrity: sha512-N4lDVm0NGmFfDJ0XMQ4O83Zm/3dPlvIQdxvwvgSLSkjFX5PM4GUYSVAuxNzXN27QZMHDkrJTWUqxBrm4tPC3eA==} + better-call@1.0.3: + resolution: {integrity: sha512-DUKImKoDIy5UtCvQbHTg0wuBRse6gu1Yvznn7+1B3I5TeY8sclRPFce0HI+4WF2bcb+9PqmkET8nXZubrHQh9A==} binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} @@ -6567,6 +6567,9 @@ packages: set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -7114,6 +7117,14 @@ packages: v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + valibot@1.0.0-beta.15: + resolution: {integrity: sha512-BKy8XosZkDHWmYC+cJG74LBzP++Gfntwi33pP3D3RKztz2XV9jmFWnkOi21GoqARP8wAWARwhV6eTr1JcWzjGw==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + victory-vendor@36.9.2: resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} @@ -7383,7 +7394,7 @@ snapshots: dependencies: uncrypto: 0.1.3 - '@better-fetch/fetch@1.1.12': {} + '@better-fetch/fetch@1.1.15': {} '@biomejs/biome@1.9.4': optionalDependencies: @@ -10543,27 +10554,30 @@ snapshots: before-after-hook@2.2.3: {} - better-auth@1.1.16: + better-auth@1.2.0-beta.18(typescript@5.5.3): dependencies: '@better-auth/utils': 0.2.3 - '@better-fetch/fetch': 1.1.12 + '@better-fetch/fetch': 1.1.15 '@noble/ciphers': 0.6.0 '@noble/hashes': 1.7.1 '@simplewebauthn/browser': 13.1.0 '@simplewebauthn/server': 13.1.1 - better-call: 0.3.3 + better-call: 1.0.3 defu: 6.1.4 jose: 5.9.6 kysely: 0.27.5 nanostores: 0.11.3 + valibot: 1.0.0-beta.15(typescript@5.5.3) zod: 3.24.1 + transitivePeerDependencies: + - typescript - better-call@0.3.3: + better-call@1.0.3: dependencies: - '@better-fetch/fetch': 1.1.12 + '@better-fetch/fetch': 1.1.15 rou3: 0.5.1 + set-cookie-parser: 2.7.1 uncrypto: 0.1.3 - zod: 3.24.1 binary-extensions@2.3.0: {} @@ -13338,6 +13352,8 @@ snapshots: set-blocking@2.0.0: {} + set-cookie-parser@2.7.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -13970,6 +13986,10 @@ snapshots: v8-compile-cache-lib@3.0.1: optional: true + valibot@1.0.0-beta.15(typescript@5.5.3): + optionalDependencies: + typescript: 5.5.3 + victory-vendor@36.9.2: dependencies: '@types/d3-array': 3.2.1 From 5dc5292928b5732556517d000251c3c1ba3bf8bf Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 19:58:15 -0600 Subject: [PATCH 80/89] feat(api): implement advanced API key management with granular controls --- .../dashboard/settings/api/add-api-key.tsx | 468 ++++++++++++++++++ .../dashboard/settings/api/show-api-keys.tsx | 142 ++++++ .../settings/profile/generate-token.tsx | 77 --- apps/dokploy/drizzle/0066_yielding_echo.sql | 29 +- apps/dokploy/drizzle/meta/_journal.json | 7 - apps/dokploy/lib/auth-client.ts | 3 +- apps/dokploy/package.json | 2 +- .../pages/dashboard/settings/profile.tsx | 4 +- apps/dokploy/pages/swagger.tsx | 36 +- apps/dokploy/server/api/routers/settings.ts | 20 +- apps/dokploy/server/api/routers/user.ts | 66 ++- packages/server/package.json | 2 +- packages/server/src/db/schema/account.ts | 7 + packages/server/src/db/schema/user.ts | 3 +- packages/server/src/lib/auth.ts | 112 ++++- packages/server/src/services/user.ts | 46 +- pnpm-lock.yaml | 14 +- 17 files changed, 926 insertions(+), 112 deletions(-) create mode 100644 apps/dokploy/components/dashboard/settings/api/add-api-key.tsx create mode 100644 apps/dokploy/components/dashboard/settings/api/show-api-keys.tsx delete mode 100644 apps/dokploy/components/dashboard/settings/profile/generate-token.tsx diff --git a/apps/dokploy/components/dashboard/settings/api/add-api-key.tsx b/apps/dokploy/components/dashboard/settings/api/add-api-key.tsx new file mode 100644 index 000000000..a82a9b356 --- /dev/null +++ b/apps/dokploy/components/dashboard/settings/api/add-api-key.tsx @@ -0,0 +1,468 @@ +import { Button } from "@/components/ui/button"; +import { api } from "@/utils/api"; +import { toast } from "sonner"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, + DialogDescription, +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { useState } from "react"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, + FormDescription, +} from "@/components/ui/form"; +import { Switch } from "@/components/ui/switch"; + +const formSchema = z.object({ + name: z.string().min(1, "Name is required"), + prefix: z.string().optional(), + expiresIn: z.number().nullable(), + organizationId: z.string().min(1, "Organization is required"), + // Rate limiting fields + rateLimitEnabled: z.boolean().optional(), + rateLimitTimeWindow: z.number().nullable(), + rateLimitMax: z.number().nullable(), + // Request limiting fields + remaining: z.number().nullable().optional(), + refillAmount: z.number().nullable().optional(), + refillInterval: z.number().nullable().optional(), +}); + +type FormValues = z.infer; + +const EXPIRATION_OPTIONS = [ + { label: "Never", value: "0" }, + { label: "1 day", value: String(60 * 60 * 24) }, + { label: "7 days", value: String(60 * 60 * 24 * 7) }, + { label: "30 days", value: String(60 * 60 * 24 * 30) }, + { label: "90 days", value: String(60 * 60 * 24 * 90) }, + { label: "1 year", value: String(60 * 60 * 24 * 365) }, +]; + +const TIME_WINDOW_OPTIONS = [ + { label: "1 minute", value: String(60 * 1000) }, + { label: "5 minutes", value: String(5 * 60 * 1000) }, + { label: "15 minutes", value: String(15 * 60 * 1000) }, + { label: "30 minutes", value: String(30 * 60 * 1000) }, + { label: "1 hour", value: String(60 * 60 * 1000) }, + { label: "1 day", value: String(24 * 60 * 60 * 1000) }, +]; + +const REFILL_INTERVAL_OPTIONS = [ + { label: "1 hour", value: String(60 * 60 * 1000) }, + { label: "6 hours", value: String(6 * 60 * 60 * 1000) }, + { label: "12 hours", value: String(12 * 60 * 60 * 1000) }, + { label: "1 day", value: String(24 * 60 * 60 * 1000) }, + { label: "7 days", value: String(7 * 24 * 60 * 60 * 1000) }, + { label: "30 days", value: String(30 * 24 * 60 * 60 * 1000) }, +]; + +export const AddApiKey = () => { + const [open, setOpen] = useState(false); + const [showSuccessModal, setShowSuccessModal] = useState(false); + const [newApiKey, setNewApiKey] = useState(""); + const { refetch } = api.user.get.useQuery(); + const { data: organizations } = api.organization.all.useQuery(); + const createApiKey = api.user.createApiKey.useMutation({ + onSuccess: (data) => { + if (!data) return; + + setNewApiKey(data.key); + setOpen(false); + setShowSuccessModal(true); + form.reset(); + void refetch(); + }, + onError: () => { + toast.error("Failed to generate API key"); + }, + }); + + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: { + name: "", + prefix: "", + expiresIn: null, + organizationId: "", + rateLimitEnabled: false, + rateLimitTimeWindow: null, + rateLimitMax: null, + remaining: null, + refillAmount: null, + refillInterval: null, + }, + }); + + const rateLimitEnabled = form.watch("rateLimitEnabled"); + + const onSubmit = async (values: FormValues) => { + createApiKey.mutate({ + name: values.name, + expiresIn: values.expiresIn || undefined, + prefix: values.prefix || undefined, + metadata: { + organizationId: values.organizationId, + }, + // Rate limiting + rateLimitEnabled: values.rateLimitEnabled, + rateLimitTimeWindow: values.rateLimitTimeWindow || undefined, + rateLimitMax: values.rateLimitMax || undefined, + // Request limiting + remaining: values.remaining || undefined, + refillAmount: values.refillAmount || undefined, + refillInterval: values.refillInterval || undefined, + }); + }; + + return ( + <> + + + + + + + Generate API Key + + Create a new API key for accessing the API. You can set an + expiration date and a custom prefix for better organization. + + +
+ + ( + + Name + + + + + + )} + /> + ( + + Prefix + + + + + + )} + /> + ( + + Expiration + + + + )} + /> + ( + + Organization + + + + )} + /> + + {/* Rate Limiting Section */} +
+

Rate Limiting

+ ( + +
+ Enable Rate Limiting + + Limit the number of requests within a time window + +
+ + + +
+ )} + /> + + {rateLimitEnabled && ( + <> + ( + + Time Window + + + The duration in which requests are counted + + + + )} + /> + ( + + Maximum Requests + + + field.onChange( + e.target.value + ? Number.parseInt(e.target.value, 10) + : null, + ) + } + /> + + + Maximum number of requests allowed within the time + window + + + + )} + /> + + )} +
+ + {/* Request Limiting Section */} +
+

Request Limiting

+ ( + + Total Request Limit + + + field.onChange( + e.target.value + ? Number.parseInt(e.target.value, 10) + : null, + ) + } + /> + + + Total number of requests allowed (leave empty for + unlimited) + + + + )} + /> + + ( + + Refill Amount + + + field.onChange( + e.target.value + ? Number.parseInt(e.target.value, 10) + : null, + ) + } + /> + + + Number of requests to add on each refill + + + + )} + /> + + ( + + Refill Interval + + + How often to refill the request limit + + + + )} + /> +
+ +
+ + +
+ + +
+
+ + + + + API Key Generated Successfully + + Please copy your API key now. You won't be able to see it again! + + +
+
+ {newApiKey} +
+
+ + +
+
+
+
+ + ); +}; diff --git a/apps/dokploy/components/dashboard/settings/api/show-api-keys.tsx b/apps/dokploy/components/dashboard/settings/api/show-api-keys.tsx new file mode 100644 index 000000000..6744f1dea --- /dev/null +++ b/apps/dokploy/components/dashboard/settings/api/show-api-keys.tsx @@ -0,0 +1,142 @@ +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { api } from "@/utils/api"; +import { ExternalLinkIcon, KeyIcon, Trash2, Clock, Tag } from "lucide-react"; +import Link from "next/link"; +import { toast } from "sonner"; +import { formatDistanceToNow } from "date-fns"; +import { DialogAction } from "@/components/shared/dialog-action"; +import { AddApiKey } from "./add-api-key"; +import { Badge } from "@/components/ui/badge"; + +export const ShowApiKeys = () => { + const { data, refetch } = api.user.get.useQuery(); + const { mutateAsync: deleteApiKey, isLoading: isLoadingDelete } = + api.user.deleteApiKey.useMutation(); + + return ( +
+ +
+ +
+ + + API/CLI Keys + + + Generate and manage API keys to access the API/CLI + +
+
+ + Swagger API: + + + View + + +
+
+ +
+ {data?.user.apiKeys && data.user.apiKeys.length > 0 ? ( + data.user.apiKeys.map((apiKey) => ( +
+
+
+ {apiKey.name} +
+ + + Created{" "} + {formatDistanceToNow(new Date(apiKey.createdAt))}{" "} + ago + + {apiKey.prefix && ( + + + {apiKey.prefix} + + )} + {apiKey.expiresAt && ( + + + Expires in{" "} + {formatDistanceToNow( + new Date(apiKey.expiresAt), + )}{" "} + + )} +
+
+ { + try { + await deleteApiKey({ + apiKeyId: apiKey.id, + }); + await refetch(); + toast.success("API key deleted successfully"); + } catch (error) { + toast.error( + error instanceof Error + ? error.message + : "Error deleting API key", + ); + } + }} + > + + +
+
+ )) + ) : ( +
+ + + No API keys found + +
+ )} +
+ + {/* Generate new API key */} +
+ +
+
+
+
+
+ ); +}; diff --git a/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx b/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx deleted file mode 100644 index 5213c0b9d..000000000 --- a/apps/dokploy/components/dashboard/settings/profile/generate-token.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { ToggleVisibilityInput } from "@/components/shared/toggle-visibility-input"; -import { Button } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { Label } from "@/components/ui/label"; -import { api } from "@/utils/api"; -import { ExternalLinkIcon } from "lucide-react"; -import Link from "next/link"; -import { toast } from "sonner"; - -export const GenerateToken = () => { - const { data, refetch } = api.user.get.useQuery(); - - const { mutateAsync: generateToken, isLoading: isLoadingToken } = - api.user.generateToken.useMutation(); - - return ( -
- -
- -
- API/CLI - - Generate a token to access the API/CLI - -
-
- - Swagger API: - - - View - - -
-
- -
-
-
- - -
-
- -
-
-
-
-
- ); -}; diff --git a/apps/dokploy/drizzle/0066_yielding_echo.sql b/apps/dokploy/drizzle/0066_yielding_echo.sql index a8a2501a8..bb5c2511c 100644 --- a/apps/dokploy/drizzle/0066_yielding_echo.sql +++ b/apps/dokploy/drizzle/0066_yielding_echo.sql @@ -321,7 +321,6 @@ inserted_admin_members AS ( "user_id", role, "created_at", - "token", "canAccessToAPI", "canAccessToDocker", "canAccessToGitProviders", @@ -340,7 +339,6 @@ inserted_admin_members AS ( a."adminId", 'owner', NOW(), - COALESCE(auth.token, ''), true, -- Los admins tienen todos los permisos por defecto true, true, @@ -364,7 +362,6 @@ INSERT INTO member ( "user_id", role, "created_at", - "token", "canAccessToAPI", "canAccessToDocker", "canAccessToGitProviders", @@ -383,7 +380,6 @@ SELECT u."userId", 'member', NOW(), - COALESCE(auth.token, ''), COALESCE(u."canAccessToAPI", false), COALESCE(u."canAccessToDocker", false), COALESCE(u."canAccessToGitProviders", false), @@ -400,6 +396,29 @@ JOIN admin a ON u."adminId" = a."adminId" JOIN inserted_orgs o ON o."owner_id" = a."adminId" JOIN auth ON auth.id = u."authId"; +-- Migrar tokens de auth a apikey +INSERT INTO apikey ( + id, + name, + key, + user_id, + enabled, + created_at, + updated_at +) +SELECT + gen_random_uuid(), + 'Legacy Token', + auth.token, +user_temp.id, + true, + NOW(), + NOW() +FROM auth +JOIN admin ON auth.id = admin."authId" +JOIN user_temp ON user_temp.id = admin."adminId" +WHERE auth.token IS NOT NULL AND auth.token != ''; + -- Migration tables foreign keys ALTER TABLE "project" RENAME COLUMN "adminId" TO "userId";--> statement-breakpoint @@ -436,7 +455,6 @@ ALTER TABLE "git_provider" ADD CONSTRAINT "git_provider_userId_user_temp_id_fk" ALTER TABLE "server" ADD CONSTRAINT "server_userId_user_temp_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action; -ALTER TABLE "member" ALTER COLUMN "token" SET DEFAULT '';--> statement-breakpoint ALTER TABLE "user_temp" ADD COLUMN "created_at" timestamp DEFAULT now(); @@ -635,7 +653,6 @@ ALTER TABLE "git_provider" DROP COLUMN "userId";--> statement-breakpoint ALTER TABLE "server" DROP COLUMN "userId"; -- Drop tables ---> statement-breakpoint DROP TABLE "user" CASCADE;--> statement-breakpoint DROP TABLE "admin" CASCADE;--> statement-breakpoint DROP TABLE "auth" CASCADE;--> statement-breakpoint diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 29a356e0e..8bf49b3a0 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -470,13 +470,6 @@ "when": 1739426913392, "tag": "0066_yielding_echo", "breakpoints": true - }, - { - "idx": 67, - "version": "7", - "when": 1740860314823, - "tag": "0067_goofy_red_skull", - "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/lib/auth-client.ts b/apps/dokploy/lib/auth-client.ts index 9a184959b..f1088e73f 100644 --- a/apps/dokploy/lib/auth-client.ts +++ b/apps/dokploy/lib/auth-client.ts @@ -1,8 +1,9 @@ import { organizationClient } from "better-auth/client/plugins"; import { twoFactorClient } from "better-auth/client/plugins"; +import { apiKeyClient } from "better-auth/client/plugins"; import { createAuthClient } from "better-auth/react"; export const authClient = createAuthClient({ // baseURL: "http://localhost:3000", // the base url of your auth server - plugins: [organizationClient(), twoFactorClient()], + plugins: [organizationClient(), twoFactorClient(), apiKeyClient()], }); diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index a1626fc43..3c7b05284 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -36,7 +36,7 @@ "test": "vitest --config __test__/vitest.config.ts" }, "dependencies": { - "better-auth": "beta", + "better-auth": "1.2.0", "bl": "6.0.11", "rotating-file-stream": "3.2.3", "qrcode": "^1.5.3", diff --git a/apps/dokploy/pages/dashboard/settings/profile.tsx b/apps/dokploy/pages/dashboard/settings/profile.tsx index 404d400c8..83ff5624c 100644 --- a/apps/dokploy/pages/dashboard/settings/profile.tsx +++ b/apps/dokploy/pages/dashboard/settings/profile.tsx @@ -1,4 +1,4 @@ -import { GenerateToken } from "@/components/dashboard/settings/profile/generate-token"; +import { ShowApiKeys } from "@/components/dashboard/settings/api/show-api-keys"; import { ProfileForm } from "@/components/dashboard/settings/profile/profile-form"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; @@ -19,7 +19,7 @@ const Page = () => {
- {(data?.canAccessToAPI || data?.role === "owner") && } + {(data?.canAccessToAPI || data?.role === "owner") && } {/* {isCloud && } */}
diff --git a/apps/dokploy/pages/swagger.tsx b/apps/dokploy/pages/swagger.tsx index 3d8cc01d9..11ea0731d 100644 --- a/apps/dokploy/pages/swagger.tsx +++ b/apps/dokploy/pages/swagger.tsx @@ -30,7 +30,41 @@ const Home: NextPage = () => { return (
- + (args: any) => { + const result = ori(args); + const apiKey = args?.apiKey?.value; + if (apiKey) { + localStorage.setItem("swagger_api_key", apiKey); + } + return result; + }, + logout: (ori: any) => (args: any) => { + const result = ori(args); + localStorage.removeItem("swagger_api_key"); + return result; + }, + }, + }, + }, + }, + ]} + requestInterceptor={(request: any) => { + const apiKey = localStorage.getItem("swagger_api_key"); + if (apiKey) { + request.headers = request.headers || {}; + request.headers["x-api-key"] = apiKey; + } + return request; + }} + />
); }; diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index d2455fdb7..fc1255fcf 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -482,10 +482,28 @@ export const settingsRouter = createTRPCRouter({ openApiDocument.info = { title: "Dokploy API", description: "Endpoints for dokploy", - // TODO: get version from package.json version: "1.0.0", }; + // Add security schemes configuration + openApiDocument.components = { + ...openApiDocument.components, + securitySchemes: { + apiKey: { + type: "apiKey", + in: "header", + name: "x-api-key", + description: "API key authentication", + }, + }, + }; + + // Apply security globally to all endpoints + openApiDocument.security = [ + { + apiKey: [], + }, + ]; return openApiDocument; }, ), diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 1dac65fef..5a84742a0 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -5,6 +5,7 @@ import { getUserByToken, removeUserById, updateUser, + createApiKey, } from "@dokploy/server"; import { db } from "@dokploy/server/db"; import { @@ -14,6 +15,7 @@ import { apiUpdateUser, invitation, member, + apikey, } from "@dokploy/server/db/schema"; import * as bcrypt from "bcrypt"; import { TRPCError } from "@trpc/server"; @@ -25,6 +27,24 @@ import { protectedProcedure, publicProcedure, } from "../trpc"; + +const apiCreateApiKey = z.object({ + name: z.string().min(1), + prefix: z.string().optional(), + expiresIn: z.number().optional(), + metadata: z.object({ + organizationId: z.string(), + }), + // Rate limiting + rateLimitEnabled: z.boolean().optional(), + rateLimitTimeWindow: z.number().optional(), + rateLimitMax: z.number().optional(), + // Request limiting + remaining: z.number().optional(), + refillAmount: z.number().optional(), + refillInterval: z.number().optional(), +}); + export const userRouter = createTRPCRouter({ all: adminProcedure.query(async ({ ctx }) => { return await db.query.member.findMany({ @@ -61,7 +81,11 @@ export const userRouter = createTRPCRouter({ eq(member.organizationId, ctx.session?.activeOrganizationId || ""), ), with: { - user: true, + user: { + with: { + apiKeys: true, + }, + }, }, }); @@ -249,4 +273,44 @@ export const userRouter = createTRPCRouter({ generateToken: protectedProcedure.mutation(async () => { return "token"; }), + + deleteApiKey: protectedProcedure + .input( + z.object({ + apiKeyId: z.string(), + }), + ) + .mutation(async ({ input, ctx }) => { + try { + const apiKeyToDelete = await db.query.apikey.findFirst({ + where: eq(apikey.id, input.apiKeyId), + }); + + if (!apiKeyToDelete) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "API key not found", + }); + } + + if (apiKeyToDelete.userId !== ctx.user.id) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to delete this API key", + }); + } + + await db.delete(apikey).where(eq(apikey.id, input.apiKeyId)); + return true; + } catch (error) { + throw error; + } + }), + + createApiKey: protectedProcedure + .input(apiCreateApiKey) + .mutation(async ({ input, ctx }) => { + const apiKey = await createApiKey(ctx.user.id, input); + return apiKey; + }), }); diff --git a/packages/server/package.json b/packages/server/package.json index bd2d9ed06..d99f5c248 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -32,7 +32,7 @@ "@oslojs/encoding":"1.1.0", "@oslojs/crypto":"1.0.1", "drizzle-dbml-generator":"0.10.0", - "better-auth":"beta", + "better-auth":"1.2.0", "rotating-file-stream": "3.2.3", "@faker-js/faker": "^8.4.1", "@lucia-auth/adapter-drizzle": "1.0.7", diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index e5f2dab77..8291ea4d6 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -185,3 +185,10 @@ export const apikey = pgTable("apikey", { permissions: text("permissions"), metadata: text("metadata"), }); + +export const apikeyRelations = relations(apikey, ({ one }) => ({ + user: one(users_temp, { + fields: [apikey.userId], + references: [users_temp.id], + }), +})); diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 3916f1e70..9307127a1 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -10,7 +10,7 @@ import { import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; -import { account, organization } from "./account"; +import { account, organization, apikey } from "./account"; import { projects } from "./project"; import { certificateType } from "./shared"; /** @@ -123,6 +123,7 @@ export const usersRelations = relations(users_temp, ({ one, many }) => ({ }), organizations: many(organization), projects: many(projects), + apiKeys: many(apikey), })); const createSchema = createInsertSchema(users_temp, { diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index bebcd54ee..3089bb1d0 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -9,7 +9,7 @@ import * as schema from "../db/schema"; import { sendEmail } from "../verification/send-verification-email"; import { IS_CLOUD } from "../constants"; -export const auth = betterAuth({ +const { handler, api } = betterAuth({ database: drizzleAdapter(db, { provider: "pg", schema: schema, @@ -126,7 +126,9 @@ export const auth = betterAuth({ }, plugins: [ - apiKey(), + apiKey({ + enableMetadata: true, + }), twoFactor(), organization({ async sendInvitationEmail(data, _request) { @@ -145,11 +147,111 @@ export const auth = betterAuth({ ], }); -// export const auth = { -// handler, -// }; +export const auth = { + handler, + api, +}; export const validateRequest = async (request: IncomingMessage) => { + const apiKey = request.headers["x-api-key"] as string; + if (apiKey) { + try { + const { valid, key, error } = await api.verifyApiKey({ + body: { + key: apiKey, + }, + }); + + if (error) { + throw new Error(error.message || "Error verifying API key"); + } + if (!valid || !key) { + return { + session: null, + user: null, + }; + } + + const apiKeyRecord = await db.query.apikey.findFirst({ + where: eq(schema.apikey.id, key.id), + with: { + user: true, + }, + }); + + if (!apiKeyRecord) { + return { + session: null, + user: null, + }; + } + + const organizationId = JSON.parse( + apiKeyRecord.metadata || "{}", + ).organizationId; + + if (!organizationId) { + return { + session: null, + user: null, + }; + } + + const member = await db.query.member.findFirst({ + where: and( + eq(schema.member.userId, apiKeyRecord.user.id), + eq(schema.member.organizationId, organizationId), + ), + with: { + organization: true, + }, + }); + + const { + id, + name, + email, + emailVerified, + image, + createdAt, + updatedAt, + twoFactorEnabled, + } = apiKeyRecord.user; + + const mockSession = { + session: { + user: { + id: apiKeyRecord.user.id, + email: apiKeyRecord.user.email, + name: apiKeyRecord.user.name, + }, + activeOrganizationId: organizationId || "", + }, + user: { + id, + name, + email, + emailVerified, + image, + createdAt, + updatedAt, + twoFactorEnabled, + role: member?.role || "member", + ownerId: member?.organization.ownerId || apiKeyRecord.user.id, + }, + }; + + return mockSession; + } catch (error) { + console.error("Error verifying API key", error); + return { + session: null, + user: null, + }; + } + } + + // If no API key, proceed with normal session validation const session = await api.getSession({ headers: new Headers({ cookie: request.headers.cookie || "", diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index a1901d716..312753ffc 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -1,7 +1,8 @@ import { db } from "@dokploy/server/db"; -import { member, users_temp } from "@dokploy/server/db/schema"; +import { apikey, member, users_temp } from "@dokploy/server/db/schema"; import { TRPCError } from "@trpc/server"; import { and, eq } from "drizzle-orm"; +import { auth } from "../lib/auth"; export type User = typeof users_temp.$inferSelect; @@ -248,3 +249,46 @@ export const updateUser = async (userId: string, userData: Partial) => { return user; }; + +export const createApiKey = async ( + userId: string, + input: { + name: string; + prefix?: string; + expiresIn?: number; + metadata: { + organizationId: string; + }; + rateLimitEnabled?: boolean; + rateLimitTimeWindow?: number; + rateLimitMax?: number; + remaining?: number; + refillAmount?: number; + refillInterval?: number; + }, +) => { + const apiKey = await auth.api.createApiKey({ + body: { + name: input.name, + expiresIn: input.expiresIn, + prefix: input.prefix, + rateLimitEnabled: input.rateLimitEnabled, + rateLimitTimeWindow: input.rateLimitTimeWindow, + rateLimitMax: input.rateLimitMax, + remaining: input.remaining, + refillAmount: input.refillAmount, + refillInterval: input.refillInterval, + userId, + }, + }); + + if (input.metadata) { + await db + .update(apikey) + .set({ + metadata: JSON.stringify(input.metadata), + }) + .where(eq(apikey.id, apiKey.id)); + } + return apiKey; +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6e1c088b8..03fb11f7c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -239,8 +239,8 @@ importers: specifier: 5.1.1 version: 5.1.1(encoding@0.1.13) better-auth: - specifier: beta - version: 1.2.0-beta.18(typescript@5.5.3) + specifier: 1.2.0 + version: 1.2.0(typescript@5.5.3) bl: specifier: 6.0.11 version: 6.0.11 @@ -580,8 +580,8 @@ importers: specifier: 5.1.1 version: 5.1.1(encoding@0.1.13) better-auth: - specifier: beta - version: 1.2.0-beta.18(typescript@5.5.3) + specifier: 1.2.0 + version: 1.2.0(typescript@5.5.3) bl: specifier: 6.0.11 version: 6.0.11 @@ -3879,8 +3879,8 @@ packages: before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} - better-auth@1.2.0-beta.18: - resolution: {integrity: sha512-gEjNxmrkFiATTSTcE47rkyTT9vMFMLTjtLNun4W0IWmeqfi4pIbbWpo97foY1DNXXRDkDuajquoD58dzAatQxQ==} + better-auth@1.2.0: + resolution: {integrity: sha512-eIRGOXfix25bh4fgs8jslZAZssufpIkxfEeEokQu5G4wICoDee1wPctkFb8v80PvhtI4dPm28SuAoZaAdRc6Wg==} better-call@1.0.3: resolution: {integrity: sha512-DUKImKoDIy5UtCvQbHTg0wuBRse6gu1Yvznn7+1B3I5TeY8sclRPFce0HI+4WF2bcb+9PqmkET8nXZubrHQh9A==} @@ -10554,7 +10554,7 @@ snapshots: before-after-hook@2.2.3: {} - better-auth@1.2.0-beta.18(typescript@5.5.3): + better-auth@1.2.0(typescript@5.5.3): dependencies: '@better-auth/utils': 0.2.3 '@better-fetch/fetch': 1.1.15 From 0ad923308712447e8e92a8c2acc9430111581c1c Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 20:55:18 -0600 Subject: [PATCH 81/89] feat(logs): enable dynamic log rotation with database state management --- .../server/src/utils/access-log/handler.ts | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/packages/server/src/utils/access-log/handler.ts b/packages/server/src/utils/access-log/handler.ts index d05d805f3..69d0cc68b 100644 --- a/packages/server/src/utils/access-log/handler.ts +++ b/packages/server/src/utils/access-log/handler.ts @@ -1,6 +1,8 @@ import { IS_CLOUD, paths } from "@dokploy/server/constants"; import { type RotatingFileStream, createStream } from "rotating-file-stream"; import { execAsync } from "../process/execAsync"; +import { findAdmin } from "@dokploy/server/services/admin"; +import { updateUser } from "@dokploy/server/services/user"; class LogRotationManager { private static instance: LogRotationManager; @@ -28,19 +30,18 @@ class LogRotationManager { } private async getStateFromDB(): Promise { - // const setting = await db.query.admins.findFirst({}); - // return setting?.enableLogRotation ?? false; - return false; + const admin = await findAdmin(); + return admin?.user.enableLogRotation ?? false; } - private async setStateInDB(_active: boolean): Promise { - // const admin = await db.query.admins.findFirst({}); - // if (!admin) { - // return; - // } - // await updateAdmin(admin?.authId, { - // enableLogRotation: active, - // }); + private async setStateInDB(active: boolean): Promise { + const admin = await findAdmin(); + if (!admin) { + return; + } + await updateUser(admin.user.id, { + enableLogRotation: active, + }); } private async activateStream(): Promise { @@ -74,26 +75,26 @@ class LogRotationManager { } public async activate(): Promise { - // const currentState = await this.getStateFromDB(); - // if (currentState) { - // return true; - // } + const currentState = await this.getStateFromDB(); + if (currentState) { + return true; + } - // await this.setStateInDB(true); - // await this.activateStream(); + await this.setStateInDB(true); + await this.activateStream(); return true; } public async deactivate(): Promise { console.log("Deactivating log rotation..."); - // const currentState = await this.getStateFromDB(); - // if (!currentState) { - // console.log("Log rotation is already inactive in DB"); - // return true; - // } + const currentState = await this.getStateFromDB(); + if (!currentState) { + console.log("Log rotation is already inactive in DB"); + return true; + } - // await this.setStateInDB(false); - // await this.deactivateStream(); + await this.setStateInDB(false); + await this.deactivateStream(); console.log("Log rotation deactivated successfully"); return true; } @@ -113,9 +114,8 @@ class LogRotationManager { } } public async getStatus(): Promise { - // const dbState = await this.getStateFromDB(); - // return dbState; - return false; + const dbState = await this.getStateFromDB(); + return dbState; } } export const logRotationManager = LogRotationManager.getInstance(); From a3362e0b1513d29ca81f3850a1c056bc2fa73fa9 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 21:30:30 -0600 Subject: [PATCH 82/89] feat(auth): add Google sign-in support for cloud environment --- .../pages/dashboard/settings/users.tsx | 1 - apps/dokploy/pages/index.tsx | 50 ++++++++++++++++++- apps/dokploy/pages/invitation.tsx | 9 ++++ packages/server/src/lib/auth.ts | 31 +++++++----- 4 files changed, 77 insertions(+), 14 deletions(-) diff --git a/apps/dokploy/pages/dashboard/settings/users.tsx b/apps/dokploy/pages/dashboard/settings/users.tsx index 226153145..16f90abb1 100644 --- a/apps/dokploy/pages/dashboard/settings/users.tsx +++ b/apps/dokploy/pages/dashboard/settings/users.tsx @@ -29,7 +29,6 @@ export async function getServerSideProps( const { req, res } = ctx; const { user, session } = await validateRequest(req); - console.log("user", user, session); if (!user || user.role === "member") { return { redirect: { diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index 768498e8c..70aa2f10a 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -63,7 +63,7 @@ export default function Home({ IS_CLOUD }: Props) { const [isBackupCodeModalOpen, setIsBackupCodeModalOpen] = useState(false); const [backupCode, setBackupCode] = useState(""); const [isGithubLoading, setIsGithubLoading] = useState(false); - + const [isGoogleLoading, setIsGoogleLoading] = useState(false); const loginForm = useForm({ resolver: zodResolver(LoginSchema), defaultValues: { @@ -181,6 +181,25 @@ export default function Home({ IS_CLOUD }: Props) { } }; + const handleGoogleSignIn = async () => { + setIsGoogleLoading(true); + try { + const { error } = await authClient.signIn.social({ + provider: "google", + }); + + if (error) { + toast.error(error.message); + return; + } + } catch (error) { + toast.error("An error occurred while signing in with Google", { + description: error instanceof Error ? error.message : "Unknown error", + }); + } finally { + setIsGoogleLoading(false); + } + }; return ( <>
@@ -219,6 +238,35 @@ export default function Home({ IS_CLOUD }: Props) { Sign in with GitHub )} + {IS_CLOUD && ( + + )}
Click the link to verify your email: Verify Email

+ `, }); }, }, @@ -53,7 +55,9 @@ const { handler, api } = betterAuth({ await sendEmail({ email: user.email, subject: "Reset your password", - text: `Click the link to reset your password: ${url}`, + text: ` +

Click the link to reset your password: Reset Password

+ `, }); }, }, @@ -132,16 +136,19 @@ const { handler, api } = betterAuth({ twoFactor(), organization({ async sendInvitationEmail(data, _request) { - const inviteLink = `https://example.com/accept-invitation/${data.id}`; - // https://example.com/accept-invitation/8jlBi9Tb9isDb8mc8Sb85u1BaJYklKB2 - // sendOrganizationInvitation({ - // email: data.email, - // invitedByUsername: data.inviter.user.name, - // invitedByEmail: data.inviter.user.email, - // teamName: data.organization.name, - // inviteLink - // }) - console.log("Invitation link", inviteLink); + if (IS_CLOUD) { + const inviteLink = `http://localhost:3000/invitation?token=${data.id}`; + + console.log("Invitation link", inviteLink); + + await sendEmail({ + email: data.email, + subject: "Invitation to join organization", + text: ` +

You are invited to join ${data.organization.name} on Dokploy. Click the link to accept the invitation: Accept Invitation

+ `, + }); + } }, }), ], From 5c38a8265f1a905f67ee73af2b2a8f8921f46b7f Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 21:47:31 -0600 Subject: [PATCH 83/89] feat(auth): improve email verification and invitation link generation for cloud environment --- packages/server/src/lib/auth.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index b4605959c..3d96942b7 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -29,14 +29,15 @@ const { handler, api } = betterAuth({ sendOnSignUp: true, autoSignInAfterVerification: true, sendVerificationEmail: async ({ user, url }) => { - console.log("Sending verification email to", user.email); - await sendEmail({ - email: user.email, - subject: "Verify your email", - text: ` + if (IS_CLOUD) { + await sendEmail({ + email: user.email, + subject: "Verify your email", + text: `

Click the link to verify your email: Verify Email

`, - }); + }); + } }, }, emailAndPassword: { @@ -137,9 +138,11 @@ const { handler, api } = betterAuth({ organization({ async sendInvitationEmail(data, _request) { if (IS_CLOUD) { - const inviteLink = `http://localhost:3000/invitation?token=${data.id}`; - - console.log("Invitation link", inviteLink); + const host = + process.env.NODE_ENV === "development" + ? "http://localhost:3000" + : "https://dokploy.com"; + const inviteLink = `${host}/invitation?token=${data.id}`; await sendEmail({ email: data.email, From d7c94174b90cf50286a8572d53f3e0e840fb0bb2 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 21:49:56 -0600 Subject: [PATCH 84/89] refactor(auth): simplify API key export in authentication module --- packages/server/src/lib/auth.ts | 2 +- packages/server/src/services/user.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 3d96942b7..6bd3ec2ff 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -159,7 +159,7 @@ const { handler, api } = betterAuth({ export const auth = { handler, - api, + createApiKey: api.createApiKey, }; export const validateRequest = async (request: IncomingMessage) => { diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts index 312753ffc..39ac95cef 100644 --- a/packages/server/src/services/user.ts +++ b/packages/server/src/services/user.ts @@ -267,7 +267,7 @@ export const createApiKey = async ( refillInterval?: number; }, ) => { - const apiKey = await auth.api.createApiKey({ + const apiKey = await auth.createApiKey({ body: { name: input.name, expiresIn: input.expiresIn, From 43599e7a9724ef4d7980b115a8758000902f0a9a Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 21:54:47 -0600 Subject: [PATCH 85/89] fix(auth): handle null session and user with TypeScript ignore --- apps/dokploy/server/api/trpc.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index 8e8206427..4627155f8 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -80,12 +80,14 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { return createInnerTRPCContext({ req, res, + // @ts-ignore session: session ? { ...session, activeOrganizationId: session.activeOrganizationId || "", } : null, + // @ts-ignore user: user ? { ...user, From adeb8498f9d7dd53139edfe55908647d58de7ee9 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 21:56:22 -0600 Subject: [PATCH 86/89] refactor(auth): remove commented-out debug logging in TRPC context --- apps/dokploy/server/api/trpc.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts index 4627155f8..4c88eb22d 100644 --- a/apps/dokploy/server/api/trpc.ts +++ b/apps/dokploy/server/api/trpc.ts @@ -68,15 +68,6 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => { // Get from the request const { session, user } = await validateRequest(req); - // if (!session) { - // const cookieResult = await validateRequest(req); - // session = cookieResult.session; - // user = cookieResult.user; - // } - - // console.log("session", session); - // console.log("user", user); - return createInnerTRPCContext({ req, res, From 13eccaf8d9bb0562373f3ee3fb377a4480b391e0 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 22:14:12 -0600 Subject: [PATCH 87/89] feat(user): add organization count check before user deletion --- .../dashboard/settings/users/show-users.tsx | 30 +++++++++++++++++++ apps/dokploy/server/api/routers/user.ts | 14 +++++++++ 2 files changed, 44 insertions(+) diff --git a/apps/dokploy/components/dashboard/settings/users/show-users.tsx b/apps/dokploy/components/dashboard/settings/users/show-users.tsx index 6847558b7..9580240df 100644 --- a/apps/dokploy/components/dashboard/settings/users/show-users.tsx +++ b/apps/dokploy/components/dashboard/settings/users/show-users.tsx @@ -36,6 +36,7 @@ export const ShowUsers = () => { const { data: isCloud } = api.settings.isCloud.useQuery(); const { data, isLoading, refetch } = api.user.all.useQuery(); const { mutateAsync } = api.user.remove.useMutation(); + const utils = api.useUtils(); return (
@@ -172,6 +173,35 @@ export const ShowUsers = () => { description="Are you sure you want to unlink this user?" type="destructive" onClick={async () => { + if (!isCloud) { + const orgCount = + await utils.user.checkUserOrganizations.fetch( + { + userId: member.user.id, + }, + ); + + console.log(orgCount); + + if (orgCount === 1) { + await mutateAsync({ + userId: member.user.id, + }) + .then(() => { + toast.success( + "User deleted successfully", + ); + refetch(); + }) + .catch(() => { + toast.error( + "Error deleting user", + ); + }); + return; + } + } + const { error } = await authClient.organization.removeMember( { diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts index 5a84742a0..0b740ab74 100644 --- a/apps/dokploy/server/api/routers/user.ts +++ b/apps/dokploy/server/api/routers/user.ts @@ -313,4 +313,18 @@ export const userRouter = createTRPCRouter({ const apiKey = await createApiKey(ctx.user.id, input); return apiKey; }), + + checkUserOrganizations: protectedProcedure + .input( + z.object({ + userId: z.string(), + }), + ) + .query(async ({ input }) => { + const organizations = await db.query.member.findMany({ + where: eq(member.userId, input.userId), + }); + + return organizations.length; + }), }); From c51d63a4df8816b27dedc3ce913fa6710ac0efbf Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 22:21:03 -0600 Subject: [PATCH 88/89] chore: remove TODO comments and clean up code annotations --- apps/dokploy/components/dashboard/project/add-database.tsx | 1 - apps/dokploy/server/api/routers/notification.ts | 7 ------- apps/dokploy/server/api/routers/ssh-key.ts | 1 - packages/server/src/db/schema/application.ts | 1 - packages/server/src/services/domain.ts | 1 - 5 files changed, 11 deletions(-) diff --git a/apps/dokploy/components/dashboard/project/add-database.tsx b/apps/dokploy/components/dashboard/project/add-database.tsx index cd75ba468..b14e2cfa0 100644 --- a/apps/dokploy/components/dashboard/project/add-database.tsx +++ b/apps/dokploy/components/dashboard/project/add-database.tsx @@ -48,7 +48,6 @@ import { z } from "zod"; type DbType = typeof mySchema._type.type; -// TODO: Change to a real docker images const dockerImageDefaultPlaceholder: Record = { mongo: "mongo:6", mariadb: "mariadb:11", diff --git a/apps/dokploy/server/api/routers/notification.ts b/apps/dokploy/server/api/routers/notification.ts index 48ef50b9d..23283d971 100644 --- a/apps/dokploy/server/api/routers/notification.ts +++ b/apps/dokploy/server/api/routers/notification.ts @@ -51,7 +51,6 @@ import { TRPCError } from "@trpc/server"; import { desc, eq, sql } from "drizzle-orm"; import { z } from "zod"; -// TODO: Uncomment the validations when is cloud ready export const notificationRouter = createTRPCRouter({ createSlack: adminProcedure .input(apiCreateSlack) @@ -75,7 +74,6 @@ export const notificationRouter = createTRPCRouter({ try { const notification = await findNotificationById(input.notificationId); if (notification.organizationId !== ctx.session.activeOrganizationId) { - // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this notification", @@ -129,7 +127,6 @@ export const notificationRouter = createTRPCRouter({ try { const notification = await findNotificationById(input.notificationId); if (notification.organizationId !== ctx.session.activeOrganizationId) { - // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this notification", @@ -184,7 +181,6 @@ export const notificationRouter = createTRPCRouter({ try { const notification = await findNotificationById(input.notificationId); if (notification.organizationId !== ctx.session.activeOrganizationId) { - // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this notification", @@ -247,7 +243,6 @@ export const notificationRouter = createTRPCRouter({ try { const notification = await findNotificationById(input.notificationId); if (notification.organizationId !== ctx.session.activeOrganizationId) { - // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to update this notification", @@ -289,7 +284,6 @@ export const notificationRouter = createTRPCRouter({ try { const notification = await findNotificationById(input.notificationId); if (notification.organizationId !== ctx.session.activeOrganizationId) { - // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to delete this notification", @@ -312,7 +306,6 @@ export const notificationRouter = createTRPCRouter({ .query(async ({ input, ctx }) => { const notification = await findNotificationById(input.notificationId); if (notification.organizationId !== ctx.session.activeOrganizationId) { - // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized to access this notification", diff --git a/apps/dokploy/server/api/routers/ssh-key.ts b/apps/dokploy/server/api/routers/ssh-key.ts index fe321de4f..4663af8f2 100644 --- a/apps/dokploy/server/api/routers/ssh-key.ts +++ b/apps/dokploy/server/api/routers/ssh-key.ts @@ -41,7 +41,6 @@ export const sshRouter = createTRPCRouter({ try { const sshKey = await findSSHKeyById(input.sshKeyId); if (sshKey.organizationId !== ctx.session.activeOrganizationId) { - // TODO: Remove isCloud in the next versions of dokploy throw new TRPCError({ code: "UNAUTHORIZED", message: "You are not allowed to delete this SSH key", diff --git a/packages/server/src/db/schema/application.ts b/packages/server/src/db/schema/application.ts index 2437f59d6..e670e2e24 100644 --- a/packages/server/src/db/schema/application.ts +++ b/packages/server/src/db/schema/application.ts @@ -44,7 +44,6 @@ export const buildType = pgEnum("buildType", [ "static", ]); -// TODO: refactor this types export interface HealthCheckSwarm { Test?: string[] | undefined; Interval?: number | undefined; diff --git a/packages/server/src/services/domain.ts b/packages/server/src/services/domain.ts index fe068fc22..d2e23c06b 100644 --- a/packages/server/src/services/domain.ts +++ b/packages/server/src/services/domain.ts @@ -126,7 +126,6 @@ export const updateDomainById = async ( export const removeDomainById = async (domainId: string) => { await findDomainById(domainId); - // TODO: fix order const result = await db .delete(domains) .where(eq(domains.domainId, domainId)) From 5fb286666051e129c4871d0186f7fb9f36aef6e6 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 22:48:09 -0600 Subject: [PATCH 89/89] feat(auth): conditionally disable authentication logger in production --- packages/server/src/lib/auth.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 6bd3ec2ff..1efa17300 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -14,6 +14,9 @@ const { handler, api } = betterAuth({ provider: "pg", schema: schema, }), + logger: { + disabled: process.env.NODE_ENV === "production", + }, appName: "Dokploy", socialProviders: { github: {