From ae0cdc64564079e58a58ce9c57e6f71851455fce Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Thu, 24 Sep 2026 01:23:20 -0600 Subject: [PATCH] feat: enhance log management and organization handling - Updated API link conditions to allow skipping batch processing based on context. - Removed unused VECTOR_RESYNC_CRON_JOB constant from server constants. - Introduced logProviderIds field in server and webServerSettings schemas to manage log providers. - Added organization service to handle organization deletions and vector agent removals. - Enhanced server service to find servers with log management enabled and update log providers. - Updated vector setup to sync vector configurations based on organization and server log provider IDs. - Implemented Docker labels for resources to improve tracking and management. - Refactored vector agent setup and removal processes to streamline operations. --- .../log-management/vector-config.test.ts | 279 +- .../log-management/vector-setup-fixes.test.ts | 180 +- .../log-management/vector-setup-web.test.ts | 96 - .../server/update-server-config.test.ts | 2 +- .../log-management/handle-log-provider.tsx | 7 +- .../show-log-management-servers.tsx | 308 +- .../log-management/show-log-providers.tsx | 71 +- .../servers/actions/toggle-log-management.tsx | 125 - .../settings/servers/handle-servers.tsx | 5 +- apps/dokploy/drizzle/0198_kind_hemingway.sql | 4 + apps/dokploy/drizzle/meta/0198_snapshot.json | 9305 +++++++++++++++++ apps/dokploy/drizzle/meta/_journal.json | 7 + .../server/api/routers/log-provider.ts | 123 +- .../server/api/routers/organization.ts | 8 +- apps/dokploy/server/api/routers/server.ts | 146 +- apps/dokploy/server/api/routers/settings.ts | 71 - apps/dokploy/server/server.ts | 3 - apps/dokploy/server/utils/vector-resync.ts | 249 - apps/dokploy/utils/api.ts | 3 +- packages/server/src/constants/index.ts | 2 - packages/server/src/db/schema/server.ts | 7 +- .../src/db/schema/web-server-settings.ts | 7 +- packages/server/src/index.ts | 1 + .../log-management/providers/elasticsearch.ts | 1 + packages/server/src/services/organization.ts | 26 + packages/server/src/services/server.ts | 34 +- .../src/services/web-server-settings.ts | 7 +- packages/server/src/setup/vector-setup.ts | 656 +- packages/server/src/utils/builders/index.ts | 14 +- .../server/src/utils/docker/dokploy-labels.ts | 34 + packages/server/src/utils/docker/domain.ts | 65 +- 31 files changed, 10149 insertions(+), 1697 deletions(-) delete mode 100644 apps/dokploy/__test__/log-management/vector-setup-web.test.ts delete mode 100644 apps/dokploy/components/dashboard/settings/servers/actions/toggle-log-management.tsx create mode 100644 apps/dokploy/drizzle/0198_kind_hemingway.sql create mode 100644 apps/dokploy/drizzle/meta/0198_snapshot.json delete mode 100644 apps/dokploy/server/utils/vector-resync.ts create mode 100644 packages/server/src/services/organization.ts create mode 100644 packages/server/src/utils/docker/dokploy-labels.ts diff --git a/apps/dokploy/__test__/log-management/vector-config.test.ts b/apps/dokploy/__test__/log-management/vector-config.test.ts index c5e018805..438e311b1 100644 --- a/apps/dokploy/__test__/log-management/vector-config.test.ts +++ b/apps/dokploy/__test__/log-management/vector-config.test.ts @@ -1,71 +1,26 @@ -import { describe, expect, it, vi } from "vitest"; +import { buildVectorConfigYaml } from "@dokploy/server/setup/vector-setup"; +import { describe, expect, it } from "vitest"; import { parse } from "yaml"; -const mocks = vi.hoisted(() => ({ - findManyProjects: vi.fn(), - findEnabledLogProvidersByOrganization: vi.fn(), -})); - -vi.mock("@dokploy/server/db", () => ({ - db: { - query: { - projects: { - findMany: mocks.findManyProjects, - }, - }, - }, -})); - -vi.mock( - "@dokploy/server/services/log-management/service", - async (importOriginal) => ({ - ...(await importOriginal< - typeof import("@dokploy/server/services/log-management/service") - >()), - findEnabledLogProvidersByOrganization: - mocks.findEnabledLogProvidersByOrganization, - }), -); - -const { buildVectorConfigYaml } = await import( - "@dokploy/server/setup/vector-setup" -); +const provider = (overrides: Record) => + ({ + apiKey: null, + apiSecret: null, + endpoint: null, + extraConfig: null, + ...overrides, + }) as any; describe("buildVectorConfigYaml", () => { it("generates a source, a dokploy_scope transform and one sink per enabled provider", async () => { - mocks.findManyProjects.mockResolvedValue([ - { - projectId: "project-1", - name: "My Project", - environments: [ - { - environmentId: "env-1", - name: "production", - applications: [ - { - appName: "app-my-app-abc123", - applicationId: "application-1", - name: "my-app", - }, - ], - compose: [], - }, - ], - }, - ]); - mocks.findEnabledLogProvidersByOrganization.mockResolvedValue([ - { + const yamlStr = await buildVectorConfigYaml([ + provider({ logProviderId: "log-provider-1", name: "loki-prod", providerType: "loki", endpoint: "https://loki.example.com", - apiKey: null, - apiSecret: null, - extraConfig: null, - }, + }), ]); - - const yamlStr = await buildVectorConfigYaml("org-1"); const config = parse(yamlStr) as any; expect(config.data_dir).toBe("/var/lib/vector"); @@ -74,21 +29,6 @@ describe("buildVectorConfigYaml", () => { expect(config.transforms.dokploy_scope.inputs).toEqual([ "docker_logs_source", ]); - expect(config.transforms.dokploy_scope.source).toContain( - '.dokploy_organization = "org-1"', - ); - expect(config.transforms.dokploy_scope.source).toContain( - 'app_name == "app-my-app-abc123"', - ); - expect(config.transforms.dokploy_scope.source).toContain( - '.dokploy_project = "My Project"', - ); - expect(config.transforms.dokploy_scope.source).toContain( - '.dokploy_environment = "production"', - ); - expect(config.transforms.dokploy_scope.source).toContain( - '.dokploy_application = "my-app"', - ); const sinkIds = Object.keys(config.sinks); expect(sinkIds).toEqual(["sink_log-provider-1"]); @@ -99,195 +39,89 @@ describe("buildVectorConfigYaml", () => { }); it("chains scope -> transform -> sink for betterstack/datadog, and scope -> sink direct for loki", async () => { - mocks.findManyProjects.mockResolvedValue([]); - mocks.findEnabledLogProvidersByOrganization.mockResolvedValue([ - { + const yamlStr = await buildVectorConfigYaml([ + provider({ logProviderId: "loki-1", name: "loki", providerType: "loki", endpoint: "https://loki.example.com", - apiKey: null, - apiSecret: null, - extraConfig: null, - }, - { + }), + provider({ logProviderId: "bs-1", name: "betterstack", providerType: "betterstack", endpoint: "https://in.logs.betterstack.com", apiKey: "token", - apiSecret: null, - extraConfig: null, - }, - { + }), + provider({ logProviderId: "dd-1", name: "datadog", providerType: "datadog", - endpoint: null, apiKey: "dd-key", - apiSecret: null, - extraConfig: null, - }, + }), ]); - - const yamlStr = await buildVectorConfigYaml("org-1"); const config = parse(yamlStr) as any; expect(config.sinks["sink_loki-1"].inputs).toEqual(["dokploy_scope"]); - expect(config.transforms["transform_bs-1"]).toBeDefined(); expect(config.transforms["transform_bs-1"].inputs).toEqual([ "dokploy_scope", ]); expect(config.sinks["sink_bs-1"].inputs).toEqual(["transform_bs-1"]); - expect(config.transforms["transform_dd-1"]).toBeDefined(); expect(config.transforms["transform_dd-1"].inputs).toEqual([ "dokploy_scope", ]); expect(config.sinks["sink_dd-1"].inputs).toEqual(["transform_dd-1"]); }); - it("escapes double quotes in project/application names to avoid breaking the VRL string literal", async () => { - mocks.findManyProjects.mockResolvedValue([ - { - projectId: "project-1", - name: 'My "Project"', - environments: [ - { - environmentId: "env-1", - name: "production", - applications: [ - { - appName: "app-abc123", - applicationId: "application-1", - name: "app", - }, - ], - compose: [], - }, - ], - }, - ]); - mocks.findEnabledLogProvidersByOrganization.mockResolvedValue([]); - - const yamlStr = await buildVectorConfigYaml("org-1"); - const config = parse(yamlStr) as any; - - expect(config.transforms.dokploy_scope.source).toContain( - '.dokploy_project = "My \\"Project\\""', - ); - }); - - it("replaces every control character in a project name, not just newlines, before embedding it in VRL", async () => { - mocks.findManyProjects.mockResolvedValue([ - { - projectId: "project-1", - name: "Weird\r\x00Name", - environments: [ - { - environmentId: "env-1", - name: "production", - applications: [ - { - appName: "app-abc123", - applicationId: "application-1", - name: "app", - }, - ], - compose: [], - }, - ], - }, - ]); - mocks.findEnabledLogProvidersByOrganization.mockResolvedValue([]); - - const yamlStr = await buildVectorConfigYaml("org-1"); - const config = parse(yamlStr) as any; - const source = config.transforms.dokploy_scope.source as string; - - expect(source).toContain('.dokploy_project = "Weird Name"'); - }); - - it("keeps events without a matching appName unscoped (no crash, no filtering), with the scoping fields defaulted to empty string", async () => { - mocks.findManyProjects.mockResolvedValue([]); - mocks.findEnabledLogProvidersByOrganization.mockResolvedValue([]); - - const yamlStr = await buildVectorConfigYaml("org-1"); + it("reads the Dokploy metadata straight off the container labels, with empty defaults for containers Dokploy did not deploy", async () => { + const yamlStr = await buildVectorConfigYaml([]); const config = parse(yamlStr) as any; expect(config.transforms.dokploy_scope.source).toBe( [ - '.dokploy_organization = "org-1"', - '.dokploy_project = ""', - '.dokploy_project_id = ""', - '.dokploy_environment = ""', - '.dokploy_environment_id = ""', - '.dokploy_application = ""', - '.dokploy_application_id = ""', + '.dokploy_organization = .label."dokploy.organization.id" || ""', + '.dokploy_project = .label."dokploy.project" || ""', + '.dokploy_project_id = .label."dokploy.project.id" || ""', + '.dokploy_environment = .label."dokploy.environment" || ""', + '.dokploy_environment_id = .label."dokploy.environment.id" || ""', + '.dokploy_application = .label."dokploy.application" || ""', + '.dokploy_application_id = .label."dokploy.application.id" || ""', + '.dokploy_service = .label."dokploy.service" || ""', ].join("\n"), ); }); - it("uses preloaded org data instead of querying, when given (fan-out reuse)", async () => { - mocks.findManyProjects.mockClear(); - mocks.findEnabledLogProvidersByOrganization.mockClear(); - - const yamlStr = await buildVectorConfigYaml("org-1", { - providers: [], - lookup: {}, - }); - - expect(mocks.findManyProjects).not.toHaveBeenCalled(); - expect(mocks.findEnabledLogProvidersByOrganization).not.toHaveBeenCalled(); - const config = parse(yamlStr) as any; - expect(config.sinks).toEqual({}); - }); - it("skips a provider whose config an adapter rejects at build time, instead of failing the whole org's config", async () => { - const yamlStr = await buildVectorConfigYaml("org-1", { - providers: [ - { - logProviderId: "broken-es", - name: "es-broken", - providerType: "elasticsearch", - endpoint: "https://es.example.com:9200", - apiKey: null, - apiSecret: null, - extraConfig: { username: "elastic" }, - }, - { - logProviderId: "good-loki", - name: "loki-ok", - providerType: "loki", - endpoint: "https://loki.example.com", - apiKey: null, - apiSecret: null, - extraConfig: null, - }, - ] as any, - lookup: {}, - }); + const yamlStr = await buildVectorConfigYaml([ + provider({ + logProviderId: "broken-es", + name: "es-broken", + providerType: "elasticsearch", + endpoint: "https://es.example.com:9200", + extraConfig: { username: "elastic" }, + }), + provider({ + logProviderId: "good-loki", + name: "loki-ok", + providerType: "loki", + endpoint: "https://loki.example.com", + }), + ]); const config = parse(yamlStr) as any; expect(Object.keys(config.sinks)).toEqual(["sink_good-loki"]); }); - it("dropUnmatched (local host only) filters out events with no matching Dokploy app before any sink", async () => { + it("drops containers Dokploy did not deploy on the local host, which also runs unrelated containers", async () => { const yamlStr = await buildVectorConfigYaml( - "org-1", - { - providers: [ - { - logProviderId: "loki-1", - name: "loki", - providerType: "loki", - endpoint: "https://loki.example.com", - apiKey: null, - apiSecret: null, - extraConfig: null, - }, - ] as any, - lookup: {}, - }, + [ + provider({ + logProviderId: "loki-1", + name: "loki", + providerType: "loki", + endpoint: "https://loki.example.com", + }), + ], { dropUnmatched: true }, ); @@ -303,10 +137,7 @@ describe("buildVectorConfigYaml", () => { }); it("does not add the drop-unmatched filter for the per-server (non-local) path", async () => { - mocks.findManyProjects.mockResolvedValue([]); - mocks.findEnabledLogProvidersByOrganization.mockResolvedValue([]); - - const yamlStr = await buildVectorConfigYaml("org-1"); + const yamlStr = await buildVectorConfigYaml([]); const config = parse(yamlStr) as any; expect(config.transforms.dokploy_scope_local_only).toBeUndefined(); diff --git a/apps/dokploy/__test__/log-management/vector-setup-fixes.test.ts b/apps/dokploy/__test__/log-management/vector-setup-fixes.test.ts index e76568a8e..686508905 100644 --- a/apps/dokploy/__test__/log-management/vector-setup-fixes.test.ts +++ b/apps/dokploy/__test__/log-management/vector-setup-fixes.test.ts @@ -1,8 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; - -const mocks = vi.hoisted(() => ({ - reserve: vi.fn(), -})); +import { describe, expect, it, vi } from "vitest"; vi.mock("@dokploy/server/db", () => ({ db: { @@ -10,87 +6,9 @@ vi.mock("@dokploy/server/db", () => ({ }, })); -vi.mock("postgres", () => ({ - default: vi.fn(() => ({ reserve: mocks.reserve })), -})); - -const makeReservedMock = (locked: boolean) => { - const tag: any = vi - .fn() - .mockImplementation((strings: TemplateStringsArray) => { - const text = strings.join(""); - if (text.includes("pg_try_advisory_lock")) { - return Promise.resolve([{ locked }]); - } - return Promise.resolve([]); - }); - tag.release = vi.fn(); - return tag; -}; - -const { - withConfigWriteLock, - collectSecretValues, - redactSecrets, - stripImageDigest, - vectorServiceSpecUnchanged, - buildServiceSettings, -} = await import("@dokploy/server/setup/vector-setup"); - -describe("withConfigWriteLock — cross-process guard (session scoped pg_advisory_lock)", () => { - beforeEach(() => { - mocks.reserve.mockReset(); - }); - - it("runs fn and returns its result when the advisory lock is acquired", async () => { - const reserved = makeReservedMock(true); - mocks.reserve.mockResolvedValue(reserved); - const fn = vi.fn().mockResolvedValue("ok"); - - await expect(withConfigWriteLock("server-1", fn)).resolves.toBe("ok"); - expect(fn).toHaveBeenCalledTimes(1); - const joinedCalls = reserved.mock.calls.map((call: any[]) => - (call[0] as string[]).join(""), - ); - expect( - joinedCalls.some((text: string) => text.includes("pg_advisory_unlock")), - ).toBe(true); - expect(reserved.release).toHaveBeenCalledTimes(1); - }); - - it("retries, then throws without ever calling fn, when another process keeps holding the lock", async () => { - mocks.reserve.mockImplementation(async () => makeReservedMock(false)); - const fn = vi.fn(); - - await expect(withConfigWriteLock("server-1", fn)).rejects.toThrow( - /already in progress/i, - ); - expect(fn).not.toHaveBeenCalled(); - expect(mocks.reserve).toHaveBeenCalledTimes(3); - }, 10_000); - - it("still serializes two calls for the same serverId within this process", async () => { - mocks.reserve.mockImplementation(async () => makeReservedMock(true)); - const order: string[] = []; - const slow = async (label: string, ms: number) => { - order.push(`${label}:start`); - await new Promise((resolve) => setTimeout(resolve, ms)); - order.push(`${label}:end`); - return label; - }; - - const first = withConfigWriteLock("server-a", () => slow("first", 20)); - const second = withConfigWriteLock("server-a", () => slow("second", 1)); - await Promise.all([first, second]); - - expect(order).toEqual([ - "first:start", - "first:end", - "second:start", - "second:end", - ]); - }); -}); +const { collectSecretValues, redactSecrets } = await import( + "@dokploy/server/setup/vector-setup" +); describe("collectSecretValues / redactSecrets", () => { it("collects endpoint/apiKey/apiSecret and string extraConfig values across all providers", () => { @@ -152,93 +70,3 @@ describe("collectSecretValues / redactSecrets", () => { ); }); }); - -describe("stripImageDigest", () => { - it("drops an @sha256 digest suffix", () => { - expect( - stripImageDigest("timberio/vector:latest-alpine@sha256:abc123"), - ).toBe("timberio/vector:latest-alpine"); - }); - - it("returns the image unchanged when there's no digest", () => { - expect(stripImageDigest("timberio/vector:latest-alpine")).toBe( - "timberio/vector:latest-alpine", - ); - }); -}); - -describe("vectorServiceSpecUnchanged", () => { - const settings = { - TaskTemplate: { - ContainerSpec: { - Image: "timberio/vector:latest-alpine", - Args: ["--config", "/etc/vector/vector.yaml", "--watch-config"], - Mounts: [{ Type: "bind", Source: "/a", Target: "/b" }], - }, - Networks: [{ Target: "host" }], - }, - Mode: { Replicated: { Replicas: 1 } }, - } as any; - - it("is unchanged when inspect matches settings modulo an image digest suffix and a resolved network ID", () => { - const inspect = { - Spec: { - TaskTemplate: { - ContainerSpec: { - Image: "timberio/vector:latest-alpine@sha256:deadbeef", - Args: ["--config", "/etc/vector/vector.yaml", "--watch-config"], - Mounts: [{ Type: "bind", Source: "/a", Target: "/b" }], - }, - Networks: [{ Target: "k1vw5h40twado5nnk9n2hi8nt" }], - }, - Mode: { Replicated: { Replicas: 1 } }, - }, - } as any; - expect(vectorServiceSpecUnchanged(inspect, settings)).toBe(true); - }); - - it("is changed when a bind mount source differs", () => { - const inspect = { - Spec: { - TaskTemplate: { - ContainerSpec: { - Image: "timberio/vector:latest-alpine", - Args: ["--config", "/etc/vector/vector.yaml", "--watch-config"], - Mounts: [{ Type: "bind", Source: "/old-path", Target: "/b" }], - }, - Networks: [{ Target: "host" }], - }, - Mode: { Replicated: { Replicas: 1 } }, - }, - } as any; - expect(vectorServiceSpecUnchanged(inspect, settings)).toBe(false); - }); - - it("is changed when Mode differs", () => { - const inspect = { - Spec: { - TaskTemplate: settings.TaskTemplate, - Mode: { Global: {} }, - }, - } as any; - expect(vectorServiceSpecUnchanged(inspect, settings)).toBe(false); - }); -}); - -describe("buildServiceSettings", () => { - it("bind-mounts the config directory, not the vector.yaml file itself", () => { - const settings = buildServiceSettings("/etc/dokploy/vector") as any; - const mounts = settings.TaskTemplate.ContainerSpec.Mounts as Array<{ - Source: string; - Target: string; - }>; - const configMount = mounts.find((m) => m.Target === "/etc/vector"); - expect(configMount?.Source).toBe("/etc/dokploy/vector"); - expect(mounts.some((m) => m.Target === "/etc/vector/vector.yaml")).toBe( - false, - ); - expect(settings.TaskTemplate.ContainerSpec.Args).toContain( - "/etc/vector/vector.yaml", - ); - }); -}); diff --git a/apps/dokploy/__test__/log-management/vector-setup-web.test.ts b/apps/dokploy/__test__/log-management/vector-setup-web.test.ts deleted file mode 100644 index 9e2d12bfd..000000000 --- a/apps/dokploy/__test__/log-management/vector-setup-web.test.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; - -const mocks = vi.hoisted(() => ({ - getWebServerSettings: vi.fn(), - hasEnabledLogProvider: vi.fn(), - getService: vi.fn(), - remove: vi.fn(), -})); - -vi.mock("@dokploy/server/services/web-server-settings", () => ({ - getWebServerSettings: mocks.getWebServerSettings, -})); - -vi.mock( - "@dokploy/server/services/log-management/service", - async (importOriginal) => ({ - ...(await importOriginal< - typeof import("@dokploy/server/services/log-management/service") - >()), - hasEnabledLogProvider: mocks.hasEnabledLogProvider, - }), -); - -vi.mock("@dokploy/server/utils/servers/remote-docker", () => ({ - getRemoteDocker: vi.fn().mockResolvedValue({ - getService: mocks.getService, - }), -})); - -const { syncWebVectorAgent } = await import( - "@dokploy/server/setup/vector-setup" -); - -describe("syncWebVectorAgent — install condition", () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - it("tears down (never installs) when the local toggle is off", async () => { - mocks.getWebServerSettings.mockResolvedValue({ - enableLogManagement: false, - logManagementOrganizationId: "org-1", - }); - mocks.remove.mockResolvedValue(undefined); - mocks.getService.mockReturnValue({ remove: mocks.remove }); - - const result = await syncWebVectorAgent(); - - expect(result.installed).toBe(false); - expect(mocks.getService).toHaveBeenCalledWith("dokploy-vector"); - expect(mocks.remove).toHaveBeenCalled(); - }); - - it("tears down when no organization has claimed the local agent yet", async () => { - mocks.getWebServerSettings.mockResolvedValue({ - enableLogManagement: true, - logManagementOrganizationId: null, - }); - mocks.remove.mockResolvedValue(undefined); - mocks.getService.mockReturnValue({ remove: mocks.remove }); - - const result = await syncWebVectorAgent(); - - expect(result.installed).toBe(false); - expect(mocks.hasEnabledLogProvider).not.toHaveBeenCalled(); - }); - - it("tears down when the owning organization has no enabled log provider", async () => { - mocks.getWebServerSettings.mockResolvedValue({ - enableLogManagement: true, - logManagementOrganizationId: "org-1", - }); - mocks.hasEnabledLogProvider.mockResolvedValue(false); - mocks.remove.mockResolvedValue(undefined); - mocks.getService.mockReturnValue({ remove: mocks.remove }); - - const result = await syncWebVectorAgent(); - - expect(result.installed).toBe(false); - expect(mocks.hasEnabledLogProvider).toHaveBeenCalledWith("org-1"); - }); - - it("skips the hasEnabledLogProvider query when providers are already preloaded", async () => { - mocks.getWebServerSettings.mockResolvedValue({ - enableLogManagement: true, - logManagementOrganizationId: "org-1", - }); - mocks.remove.mockResolvedValue(undefined); - mocks.getService.mockReturnValue({ remove: mocks.remove }); - - const result = await syncWebVectorAgent({ providers: [], lookup: {} }); - - expect(result.installed).toBe(false); - expect(mocks.hasEnabledLogProvider).not.toHaveBeenCalled(); - }); -}); 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 9d43cec32..5eb46a9e4 100644 --- a/apps/dokploy/__test__/traefik/server/update-server-config.test.ts +++ b/apps/dokploy/__test__/traefik/server/update-server-config.test.ts @@ -25,7 +25,7 @@ const baseSettings: WebServerSettings = { letsEncryptEmail: null, sshPrivateKey: null, enableDockerCleanup: false, - enableLogManagement: false, + logProviderIds: [], logManagementOrganizationId: null, buildsConcurrency: 1, logCleanupCron: null, diff --git a/apps/dokploy/components/dashboard/settings/log-management/handle-log-provider.tsx b/apps/dokploy/components/dashboard/settings/log-management/handle-log-provider.tsx index 8559c39d9..5d24a42c7 100644 --- a/apps/dokploy/components/dashboard/settings/log-management/handle-log-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/log-management/handle-log-provider.tsx @@ -179,16 +179,11 @@ export const HandleLogProvider = ({ logProviderId }: Props) => { ...(logProviderId ? { logProviderId } : {}), ...payload, } as any) - .then((result: any) => { + .then(() => { utils.logProvider.all.invalidate(); toast.success( logProviderId ? "Log provider updated" : "Log provider added", ); - if (result?.syncErrors && result.syncErrors.length > 0) { - toast.error( - `Failed to sync ${result.syncErrors.length} server(s) — they may still be shipping with the old config`, - ); - } setIsOpen(false); }) .catch(() => { diff --git a/apps/dokploy/components/dashboard/settings/log-management/show-log-management-servers.tsx b/apps/dokploy/components/dashboard/settings/log-management/show-log-management-servers.tsx index 845d8cce3..166c25fd0 100644 --- a/apps/dokploy/components/dashboard/settings/log-management/show-log-management-servers.tsx +++ b/apps/dokploy/components/dashboard/settings/log-management/show-log-management-servers.tsx @@ -1,5 +1,11 @@ -import { Loader2, ScrollText, Server } from "lucide-react"; -import Link from "next/link"; +import { Copy, Loader2, ScrollText, Server } from "lucide-react"; +import { useState } from "react"; +import { toast } from "sonner"; +import { logProviderIcons } from "@/components/icons/log-provider-icons"; +import { AlertBlock } from "@/components/shared/alert-block"; +import { DialogAction } from "@/components/shared/dialog-action"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; import { Card, CardContent, @@ -7,18 +13,110 @@ import { CardHeader, CardTitle, } from "@/components/ui/card"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Label } from "@/components/ui/label"; import { api } from "@/utils/api"; -import { ToggleLogManagement } from "../servers/actions/toggle-log-management"; + +type Status = "running" | "stopped" | "unknown"; + +const statusBadge = (status: Status) => { + if (status === "running") { + return Running; + } + if (status === "stopped") { + return Not deployed; + } + return Unreachable; +}; export const ShowLogManagementServers = () => { - const { data: providers, isPending: isPendingProviders } = - api.logProvider.all.useQuery(); - const { data: isCloud } = api.settings.isCloud.useQuery(); - const { data: servers, isPending: isPendingServers } = - api.server.all.useQuery(); + const utils = api.useUtils(); + const [selection, setSelection] = useState>({}); + const [pendingTarget, setPendingTarget] = useState(null); + const [errors, setErrors] = useState>({}); - const hasAnyProvider = (providers?.length ?? 0) > 0; - const isPending = isPendingProviders || isPendingServers; + const { data: providers } = api.logProvider.all.useQuery(); + const { data: targets, isPending } = api.logProvider.serverStatus.useQuery( + undefined, + { + refetchOnWindowFocus: false, + staleTime: 30_000, + trpc: { context: { skipBatch: true } }, + }, + ); + + const { mutateAsync: deployOnServer } = + api.logProvider.deployOnServer.useMutation(); + const { mutateAsync: removeOnServer } = + api.logProvider.removeOnServer.useMutation(); + + const keyOf = (serverId: string | null) => serverId ?? "local"; + + const idsFor = (serverId: string | null, saved: string[]) => + selection[keyOf(serverId)] ?? saved; + + const toggleProvider = ( + serverId: string | null, + saved: string[], + logProviderId: string, + ) => { + const key = keyOf(serverId); + const current = selection[key] ?? saved; + setSelection({ + ...selection, + [key]: current.includes(logProviderId) + ? current.filter((id) => id !== logProviderId) + : [...current, logProviderId], + }); + }; + + const setError = (serverId: string | null, message?: string) => + setErrors((prev) => { + const next = { ...prev }; + if (message) { + next[keyOf(serverId)] = message; + } else { + delete next[keyOf(serverId)]; + } + return next; + }); + + const handleDeploy = async (serverId: string | null, ids: string[]) => { + setPendingTarget(keyOf(serverId)); + setError(serverId); + await deployOnServer({ serverId, logProviderIds: ids }) + .then(() => { + toast.success("Vector agent deployed"); + utils.logProvider.serverStatus.invalidate(); + }) + .catch((error) => { + setError( + serverId, + error instanceof Error ? error.message : "Failed to deploy the agent", + ); + }) + .finally(() => setPendingTarget(null)); + }; + + const handleRemove = async (serverId: string | null) => { + setPendingTarget(keyOf(serverId)); + setError(serverId); + await removeOnServer({ serverId }) + .then(() => { + toast.success("Vector agent removed"); + setSelection((prev) => ({ ...prev, [keyOf(serverId)]: [] })); + utils.logProvider.serverStatus.invalidate(); + }) + .catch((error) => { + setError( + serverId, + error instanceof Error ? error.message : "Failed to remove the agent", + ); + }) + .finally(() => setPendingTarget(null)); + }; + + const hasProviders = (providers?.length ?? 0) > 0; return (
@@ -30,17 +128,18 @@ export const ShowLogManagementServers = () => { Servers - Pick which servers ship their container logs to the providers - above. Each one runs a Vector agent while it's enabled. + Pick which providers each server ships to, then deploy its Vector + agent. Changing a provider only takes effect on a server after you + redeploy it. {isPending ? (
- Loading... + Checking servers...
- ) : !hasAnyProvider ? ( + ) : !hasProviders ? (
@@ -49,51 +148,158 @@ export const ShowLogManagementServers = () => {
) : (
- {!isCloud && ( -
-
-
- Web Server - - The machine running Dokploy - -
- -
-
- )} + {targets?.map((target) => { + const key = keyOf(target.serverId); + const ids = idsFor(target.serverId, target.logProviderIds); + const isBusy = pendingTarget === key; + const isDeployed = target.status === "running"; + const hasEnabledSelected = ids.some( + (id) => + providers?.find((p) => p.logProviderId === id)?.enabled, + ); - {servers?.map((server) => ( -
-
-
- - {server.name} - - - {server.ipAddress} - + return ( +
+
+
+ + {target.name} + + {target.ipAddress && ( + + {target.ipAddress} + + )} +
+
+ {statusBadge(target.status as Status)} + {isDeployed && ( + handleRemove(target.serverId)} + > + + + )} +
- -
-
- ))} - {isCloud && servers?.length === 0 && ( +
+ + Log providers + +
+ {providers?.map((provider) => { + const ProviderIcon = + logProviderIcons[ + provider.providerType as keyof typeof logProviderIcons + ]; + return ( +
+ + toggleProvider( + target.serverId, + target.logProviderIds, + provider.logProviderId, + ) + } + /> + {ProviderIcon && ( + + )} + + {!provider.enabled && ( + Disabled + )} +
+ ); + })} +
+
+ + {errors[key] && ( + +
+ + Deploy failed — the config was not applied, this + server keeps shipping with its previous one. + +
+															{errors[key]}
+														
+ +
+
+ )} + +
+ {ids.length > 0 && !hasEnabledSelected && ( + + Every selected provider is disabled — nothing would + ship. + + )} + +
+
+ ); + })} + + {targets?.length === 0 && (
You don't have any server yet - - Go to Servers -
)}
diff --git a/apps/dokploy/components/dashboard/settings/log-management/show-log-providers.tsx b/apps/dokploy/components/dashboard/settings/log-management/show-log-providers.tsx index d513a759c..6f22dd445 100644 --- a/apps/dokploy/components/dashboard/settings/log-management/show-log-providers.tsx +++ b/apps/dokploy/components/dashboard/settings/log-management/show-log-providers.tsx @@ -1,10 +1,4 @@ -import { - AlertTriangle, - CheckCircle2, - Loader2, - ScrollText, - Trash2, -} from "lucide-react"; +import { Loader2, ScrollText, Trash2 } from "lucide-react"; import { toast } from "sonner"; import { logProviderIcons } from "@/components/icons/log-provider-icons"; import { DialogAction } from "@/components/shared/dialog-action"; @@ -44,9 +38,6 @@ const LogProviderRow = ({ }: LogProviderRowProps) => { const { mutateAsync, isPending: isRemoving } = api.logProvider.remove.useMutation(); - const { mutateAsync: testConnectionById, isPending: isTesting } = - api.logProvider.testConnectionById.useMutation(); - const ProviderIcon = logProviderIcons[provider.providerType as keyof typeof logProviderIcons]; @@ -67,35 +58,6 @@ const LogProviderRow = ({
- {canEdit && ( - - )} {canEdit && ( )} @@ -109,13 +71,8 @@ const LogProviderRow = ({ await mutateAsync({ logProviderId: provider.logProviderId, }) - .then((result) => { + .then(() => { toast.success("Log provider deleted successfully"); - if (result.syncErrors && result.syncErrors.length > 0) { - toast.error( - `Failed to sync ${result.syncErrors.length} server(s) — they may still be shipping with the old config`, - ); - } onDeleted(); }) .catch(() => { @@ -144,21 +101,10 @@ export const ShowLogProviders = () => { const { data, isPending, refetch } = api.logProvider.all.useQuery(); const { data: availableTypes } = api.logProvider.availableTypes.useQuery(); const { data: permissions } = api.user.getPermissions.useQuery(); - const { data: webServerSettings } = - api.settings.getWebServerSettings.useQuery(); - const { data: servers } = api.server.all.useQuery(); const providerListLabel = availableTypes?.length ? ` (${availableTypes.map((t) => t.label).join(", ")})` : ""; - const hasAnyProvider = (data?.length ?? 0) > 0; - const knowsAboutServers = servers !== undefined; - const hasActiveTarget = - !!webServerSettings?.enableLogManagement || - !!servers?.some((s) => s.enableLogManagement); - const showNoActiveTargetBanner = - hasAnyProvider && knowsAboutServers && !hasActiveTarget; - return (
@@ -169,21 +115,10 @@ export const ShowLogProviders = () => { Log Management - {`Ship container logs to an external provider${providerListLabel}. Needs at least one provider here and Log Management turned on for the servers below.`} + {`Ship container logs to an external provider${providerListLabel}. Add one here, then deploy the Vector agent on the servers below.`} - {showNoActiveTargetBanner && ( -
- -
- - Nothing will ship yet — turn on Log Management for at least - one server below. - -
-
- )} {isPending ? (
Loading... diff --git a/apps/dokploy/components/dashboard/settings/servers/actions/toggle-log-management.tsx b/apps/dokploy/components/dashboard/settings/servers/actions/toggle-log-management.tsx deleted file mode 100644 index 0ef88e4d2..000000000 --- a/apps/dokploy/components/dashboard/settings/servers/actions/toggle-log-management.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { HelpCircle, Loader2 } from "lucide-react"; -import { toast } from "sonner"; -import { Label } from "@/components/ui/label"; -import { Switch } from "@/components/ui/switch"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { api } from "@/utils/api"; - -interface Props { - serverId?: string; -} - -export const ToggleLogManagement = ({ serverId }: Props) => { - const utils = api.useUtils(); - const { data: server } = api.server.one.useQuery( - { serverId: serverId || "" }, - { enabled: !!serverId }, - ); - const { data: webServerSettings } = - api.settings.getWebServerSettings.useQuery(undefined, { - enabled: !serverId, - }); - const { mutateAsync: updateServer, isPending: isServerPending } = - api.server.updateLogManagement.useMutation(); - const { mutateAsync: updateLocal, isPending: isLocalPending } = - api.settings.updateLogManagement.useMutation(); - - const isPending = serverId ? isServerPending : isLocalPending; - const enabled = serverId - ? !!server?.enableLogManagement - : !!webServerSettings?.enableLogManagement; - - const handleToggle = async (checked: boolean) => { - if (serverId) { - await updateServer({ serverId, enableLogManagement: checked }) - .then((result) => { - utils.server.one.setData({ serverId }, (old) => - old - ? { ...old, enableLogManagement: result.enableLogManagement } - : old, - ); - if (checked && !result.installed) { - toast.message( - "Log Management enabled, but no log provider is configured yet — add one under Settings > Log Management.", - ); - } else { - toast.success("Log Management updated"); - } - }) - .catch((e) => { - toast.error( - e instanceof Error ? e.message : "Error updating Log Management", - ); - }); - return; - } - - await updateLocal({ enableLogManagement: checked }) - .then((result) => { - utils.settings.getWebServerSettings.setData(undefined, (old) => - old - ? { ...old, enableLogManagement: result.enableLogManagement } - : old, - ); - if (checked && !result.installed) { - toast.message( - "Log Management enabled, but no log provider is configured yet — add one under Settings > Log Management.", - ); - } else { - toast.success("Log Management updated"); - } - }) - .catch((e) => { - toast.error( - e instanceof Error ? e.message : "Error updating Log Management", - ); - }); - }; - - return ( -
- - {isPending && ( - - )} - - - - - - -

- Ships {serverId ? "this server's" : "this machine's"} container - logs to the log providers configured under Settings > Log - Management, via a Vector agent. May take a few seconds to install - or remove. -

-

- Has no effect (and installs nothing) unless at least one log - provider is enabled for this organization. -

- {!serverId && ( -

- Ships every container on this machine, not just this - organization's — if another organization on this instance also - deploys here, its logs ship too (unscoped, no project/app tags). -

- )} -
-
-
-
- ); -}; diff --git a/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx b/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx index 7dfb62897..b1c8138ce 100644 --- a/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/handle-servers.tsx @@ -126,13 +126,10 @@ export const HandleServers = ({ serverId, asButton = false }: Props) => { enableDockerCleanup: data.enableDockerCleanup, serverId: serverId || "", }) - .then(async (data) => { + .then(async () => { await utils.server.all.invalidate(); refetchServer(); toast.success(serverId ? "Server Updated" : "Server Created"); - if ("vectorAgentWarning" in data && data.vectorAgentWarning) { - toast.error(data.vectorAgentWarning); - } setIsOpen(false); }) .catch(() => { diff --git a/apps/dokploy/drizzle/0198_kind_hemingway.sql b/apps/dokploy/drizzle/0198_kind_hemingway.sql new file mode 100644 index 000000000..57d23ca9e --- /dev/null +++ b/apps/dokploy/drizzle/0198_kind_hemingway.sql @@ -0,0 +1,4 @@ +ALTER TABLE "server" ADD COLUMN "logProviderIds" text[] DEFAULT ARRAY[]::text[] NOT NULL;--> statement-breakpoint +ALTER TABLE "webServerSettings" ADD COLUMN "logProviderIds" text[] DEFAULT ARRAY[]::text[] NOT NULL;--> statement-breakpoint +ALTER TABLE "server" DROP COLUMN "enableLogManagement";--> statement-breakpoint +ALTER TABLE "webServerSettings" DROP COLUMN "enableLogManagement"; \ No newline at end of file diff --git a/apps/dokploy/drizzle/meta/0198_snapshot.json b/apps/dokploy/drizzle/meta/0198_snapshot.json new file mode 100644 index 000000000..7a9bca5aa --- /dev/null +++ b/apps/dokploy/drizzle/meta/0198_snapshot.json @@ -0,0 +1,9305 @@ +{ + "id": "51944e9e-7f2f-4c61-9300-da7cf9eaa09a", + "prevId": "04d812fc-56cf-48bf-92a4-8afdf426b380", + "version": "7", + "dialect": "postgresql", + "tables": { + "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": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.apikey": { + "name": "apikey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start": { + "name": "start", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "config_id": { + "name": "config_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'default'" + }, + "reference_id": { + "name": "reference_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_reference_id_user_id_fk": { + "name": "apikey_reference_id_user_id_fk", + "tableFrom": "apikey", + "tableTo": "user", + "columnsFrom": [ + "reference_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invitation": { + "name": "invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "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_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": [ + "inviter_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.member": { + "name": "member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateProjects": { + "name": "canCreateProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToSSHKeys": { + "name": "canAccessToSSHKeys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateServices": { + "name": "canCreateServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteProjects": { + "name": "canDeleteProjects", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteServices": { + "name": "canDeleteServices", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToDocker": { + "name": "canAccessToDocker", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToAPI": { + "name": "canAccessToAPI", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToGitProviders": { + "name": "canAccessToGitProviders", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canAccessToTraefikFiles": { + "name": "canAccessToTraefikFiles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canDeleteEnvironments": { + "name": "canDeleteEnvironments", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "canCreateEnvironments": { + "name": "canCreateEnvironments", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "accesedProjects": { + "name": "accesedProjects", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accessedEnvironments": { + "name": "accessedEnvironments", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accesedServices": { + "name": "accesedServices", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accessedGitProviders": { + "name": "accessedGitProviders", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "accessedServers": { + "name": "accessedServers", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + } + }, + "indexes": {}, + "foreignKeys": { + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "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 + }, + "default_role": { + "name": "default_role", + "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": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_role": { + "name": "organization_role", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "organizationRole_organizationId_idx": { + "name": "organizationRole_organizationId_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "organizationRole_role_idx": { + "name": "organizationRole_role_idx", + "columns": [ + { + "expression": "role", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "organization_role_organization_id_organization_id_fk": { + "name": "organization_role_organization_id_organization_id_fk", + "tableFrom": "organization_role", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.passkey": { + "name": "passkey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "counter": { + "name": "counter", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "device_type": { + "name": "device_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "backed_up": { + "name": "backed_up", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "transports": { + "name": "transports", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "aaguid": { + "name": "aaguid", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "passkey_userId_idx": { + "name": "passkey_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "passkey_credentialID_idx": { + "name": "passkey_credentialID_idx", + "columns": [ + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "passkey_user_id_user_id_fk": { + "name": "passkey_user_id_user_id_fk", + "tableFrom": "passkey", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "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 + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "failed_verification_count": { + "name": "failed_verification_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "locked_until": { + "name": "locked_until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "two_factor_user_id_user_id_fk": { + "name": "two_factor_user_id_user_id_fk", + "tableFrom": "two_factor", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ai": { + "name": "ai", + "schema": "", + "columns": { + "aiId": { + "name": "aiId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "apiUrl": { + "name": "apiUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isEnabled": { + "name": "isEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "ai_organizationId_organization_id_fk": { + "name": "ai_organizationId_organization_id_fk", + "tableFrom": "ai", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.application": { + "name": "application", + "schema": "", + "columns": { + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewEnv": { + "name": "previewEnv", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "watchPaths": { + "name": "watchPaths", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "previewBuildArgs": { + "name": "previewBuildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewBuildSecrets": { + "name": "previewBuildSecrets", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewLabels": { + "name": "previewLabels", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "previewWildcard": { + "name": "previewWildcard", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewPort": { + "name": "previewPort", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3000 + }, + "previewHttps": { + "name": "previewHttps", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "previewPath": { + "name": "previewPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "previewCustomCertResolver": { + "name": "previewCustomCertResolver", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewLimit": { + "name": "previewLimit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "isPreviewDeploymentsActive": { + "name": "isPreviewDeploymentsActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewRequireCollaboratorPermissions": { + "name": "previewRequireCollaboratorPermissions", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "rollbackActive": { + "name": "rollbackActive", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "buildArgs": { + "name": "buildArgs", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildSecrets": { + "name": "buildSecrets", + "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 + }, + "args": { + "name": "args", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refreshToken": { + "name": "refreshToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sourceType": { + "name": "sourceType", + "type": "sourceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "cleanCache": { + "name": "cleanCache", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "repository": { + "name": "repository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner": { + "name": "owner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "branch": { + "name": "branch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildPath": { + "name": "buildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "triggerType": { + "name": "triggerType", + "type": "triggerType", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'push'" + }, + "autoDeploy": { + "name": "autoDeploy", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "gitlabProjectId": { + "name": "gitlabProjectId", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "gitlabRepository": { + "name": "gitlabRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabOwner": { + "name": "gitlabOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBranch": { + "name": "gitlabBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabBuildPath": { + "name": "gitlabBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "gitlabPathNamespace": { + "name": "gitlabPathNamespace", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaRepository": { + "name": "giteaRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaOwner": { + "name": "giteaOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaBranch": { + "name": "giteaBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaBuildPath": { + "name": "giteaBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "bitbucketRepository": { + "name": "bitbucketRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketRepositorySlug": { + "name": "bitbucketRepositorySlug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBuildPath": { + "name": "bitbucketBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerImage": { + "name": "dockerImage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registryUrl": { + "name": "registryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBuildPath": { + "name": "customGitBuildPath", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableSubmodules": { + "name": "enableSubmodules", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dockerfile": { + "name": "dockerfile", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Dockerfile'" + }, + "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 + }, + "stopGracePeriodSwarm": { + "name": "stopGracePeriodSwarm", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "endpointSpecSwarm": { + "name": "endpointSpecSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "ulimitsSwarm": { + "name": "ulimitsSwarm", + "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'" + }, + "railpackVersion": { + "name": "railpackVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'0.15.4'" + }, + "herokuVersion": { + "name": "herokuVersion", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'24'" + }, + "publishDirectory": { + "name": "publishDirectory", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isStaticSpa": { + "name": "isStaticSpa", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "createEnvFile": { + "name": "createEnvFile", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registryId": { + "name": "registryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "rollbackRegistryId": { + "name": "rollbackRegistryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "environmentId": { + "name": "environmentId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaId": { + "name": "giteaId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildServerId": { + "name": "buildServerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildRegistryId": { + "name": "buildRegistryId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "networkIds": { + "name": "networkIds", + "type": "text[]", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "detachDokployNetwork": { + "name": "detachDokployNetwork", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": 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_rollbackRegistryId_registry_registryId_fk": { + "name": "application_rollbackRegistryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "rollbackRegistryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_environmentId_environment_environmentId_fk": { + "name": "application_environmentId_environment_environmentId_fk", + "tableFrom": "application", + "tableTo": "environment", + "columnsFrom": [ + "environmentId" + ], + "columnsTo": [ + "environmentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_githubId_github_githubId_fk": { + "name": "application_githubId_github_githubId_fk", + "tableFrom": "application", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_gitlabId_gitlab_gitlabId_fk": { + "name": "application_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "application", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_giteaId_gitea_giteaId_fk": { + "name": "application_giteaId_gitea_giteaId_fk", + "tableFrom": "application", + "tableTo": "gitea", + "columnsFrom": [ + "giteaId" + ], + "columnsTo": [ + "giteaId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "application_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "application", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_serverId_server_serverId_fk": { + "name": "application_serverId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "application_buildServerId_server_serverId_fk": { + "name": "application_buildServerId_server_serverId_fk", + "tableFrom": "application", + "tableTo": "server", + "columnsFrom": [ + "buildServerId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "application_buildRegistryId_registry_registryId_fk": { + "name": "application_buildRegistryId_registry_registryId_fk", + "tableFrom": "application", + "tableTo": "registry", + "columnsFrom": [ + "buildRegistryId" + ], + "columnsTo": [ + "registryId" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "application_appName_unique": { + "name": "application_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_log": { + "name": "audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_email": { + "name": "user_email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_role": { + "name": "user_role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resource_name": { + "name": "resource_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "auditLog_organizationId_idx": { + "name": "auditLog_organizationId_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "auditLog_userId_idx": { + "name": "auditLog_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "auditLog_createdAt_idx": { + "name": "auditLog_createdAt_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_log_organization_id_organization_id_fk": { + "name": "audit_log_organization_id_organization_id_fk", + "tableFrom": "audit_log", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_log_user_id_user_id_fk": { + "name": "audit_log_user_id_user_id_fk", + "tableFrom": "audit_log", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup": { + "name": "backup", + "schema": "", + "columns": { + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "database": { + "name": "database", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keepLatestCount": { + "name": "keepLatestCount", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "includeEncryptionKey": { + "name": "includeEncryptionKey", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "backupType": { + "name": "backupType", + "type": "backupType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'database'" + }, + "databaseType": { + "name": "databaseType", + "type": "databaseType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "libsqlId": { + "name": "libsqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_destinationId_destination_destinationId_fk": { + "name": "backup_destinationId_destination_destinationId_fk", + "tableFrom": "backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_composeId_compose_composeId_fk": { + "name": "backup_composeId_compose_composeId_fk", + "tableFrom": "backup", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_postgresId_postgres_postgresId_fk": { + "name": "backup_postgresId_postgres_postgresId_fk", + "tableFrom": "backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mariadbId_mariadb_mariadbId_fk": { + "name": "backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mysqlId_mysql_mysqlId_fk": { + "name": "backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_mongoId_mongo_mongoId_fk": { + "name": "backup_mongoId_mongo_mongoId_fk", + "tableFrom": "backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_libsqlId_libsql_libsqlId_fk": { + "name": "backup_libsqlId_libsql_libsqlId_fk", + "tableFrom": "backup", + "tableTo": "libsql", + "columnsFrom": [ + "libsqlId" + ], + "columnsTo": [ + "libsqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_userId_user_id_fk": { + "name": "backup_userId_user_id_fk", + "tableFrom": "backup", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "backup_appName_unique": { + "name": "backup_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bitbucket": { + "name": "bitbucket", + "schema": "", + "columns": { + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "bitbucketUsername": { + "name": "bitbucketUsername", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketEmail": { + "name": "bitbucketEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "appPassword": { + "name": "appPassword", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "apiToken": { + "name": "apiToken", + "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.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.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 + }, + "bitbucketRepositorySlug": { + "name": "bitbucketRepositorySlug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketOwner": { + "name": "bitbucketOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketBranch": { + "name": "bitbucketBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaRepository": { + "name": "giteaRepository", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaOwner": { + "name": "giteaOwner", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaBranch": { + "name": "giteaBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitUrl": { + "name": "customGitUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitBranch": { + "name": "customGitBranch", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customGitSSHKeyId": { + "name": "customGitSSHKeyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "createEnvFile": { + "name": "createEnvFile", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enableSubmodules": { + "name": "enableSubmodules", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "composePath": { + "name": "composePath", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'./docker-compose.yml'" + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "randomize": { + "name": "randomize", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeployment": { + "name": "isolatedDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isolatedDeploymentsVolume": { + "name": "isolatedDeploymentsVolume", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "pullImages": { + "name": "pullImages", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "triggerType": { + "name": "triggerType", + "type": "triggerType", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'push'" + }, + "composeStatus": { + "name": "composeStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "environmentId": { + "name": "environmentId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "watchPaths": { + "name": "watchPaths", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "githubId": { + "name": "githubId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitlabId": { + "name": "gitlabId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bitbucketId": { + "name": "bitbucketId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "giteaId": { + "name": "giteaId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serviceNetworks": { + "name": "serviceNetworks", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + } + }, + "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_environmentId_environment_environmentId_fk": { + "name": "compose_environmentId_environment_environmentId_fk", + "tableFrom": "compose", + "tableTo": "environment", + "columnsFrom": [ + "environmentId" + ], + "columnsTo": [ + "environmentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "compose_githubId_github_githubId_fk": { + "name": "compose_githubId_github_githubId_fk", + "tableFrom": "compose", + "tableTo": "github", + "columnsFrom": [ + "githubId" + ], + "columnsTo": [ + "githubId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_gitlabId_gitlab_gitlabId_fk": { + "name": "compose_gitlabId_gitlab_gitlabId_fk", + "tableFrom": "compose", + "tableTo": "gitlab", + "columnsFrom": [ + "gitlabId" + ], + "columnsTo": [ + "gitlabId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_bitbucketId_bitbucket_bitbucketId_fk": { + "name": "compose_bitbucketId_bitbucket_bitbucketId_fk", + "tableFrom": "compose", + "tableTo": "bitbucket", + "columnsFrom": [ + "bitbucketId" + ], + "columnsTo": [ + "bitbucketId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_giteaId_gitea_giteaId_fk": { + "name": "compose_giteaId_gitea_giteaId_fk", + "tableFrom": "compose", + "tableTo": "gitea", + "columnsFrom": [ + "giteaId" + ], + "columnsTo": [ + "giteaId" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "compose_serverId_server_serverId_fk": { + "name": "compose_serverId_server_serverId_fk", + "tableFrom": "compose", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deployment": { + "name": "deployment", + "schema": "", + "columns": { + "deploymentId": { + "name": "deploymentId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "deploymentStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'running'" + }, + "logPath": { + "name": "logPath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pid": { + "name": "pid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isPreviewDeployment": { + "name": "isPreviewDeployment", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "startedAt": { + "name": "startedAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "finishedAt": { + "name": "finishedAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "errorMessage": { + "name": "errorMessage", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scheduleId": { + "name": "scheduleId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "backupId": { + "name": "backupId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "rollbackId": { + "name": "rollbackId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "volumeBackupId": { + "name": "volumeBackupId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buildServerId": { + "name": "buildServerId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "deployment_applicationId_application_applicationId_fk": { + "name": "deployment_applicationId_application_applicationId_fk", + "tableFrom": "deployment", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_composeId_compose_composeId_fk": { + "name": "deployment_composeId_compose_composeId_fk", + "tableFrom": "deployment", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_serverId_server_serverId_fk": { + "name": "deployment_serverId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk": { + "name": "deployment_previewDeploymentId_preview_deployments_previewDeploymentId_fk", + "tableFrom": "deployment", + "tableTo": "preview_deployments", + "columnsFrom": [ + "previewDeploymentId" + ], + "columnsTo": [ + "previewDeploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_scheduleId_schedule_scheduleId_fk": { + "name": "deployment_scheduleId_schedule_scheduleId_fk", + "tableFrom": "deployment", + "tableTo": "schedule", + "columnsFrom": [ + "scheduleId" + ], + "columnsTo": [ + "scheduleId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_backupId_backup_backupId_fk": { + "name": "deployment_backupId_backup_backupId_fk", + "tableFrom": "deployment", + "tableTo": "backup", + "columnsFrom": [ + "backupId" + ], + "columnsTo": [ + "backupId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_rollbackId_rollback_rollbackId_fk": { + "name": "deployment_rollbackId_rollback_rollbackId_fk", + "tableFrom": "deployment", + "tableTo": "rollback", + "columnsFrom": [ + "rollbackId" + ], + "columnsTo": [ + "rollbackId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_volumeBackupId_volume_backup_volumeBackupId_fk": { + "name": "deployment_volumeBackupId_volume_backup_volumeBackupId_fk", + "tableFrom": "deployment", + "tableTo": "volume_backup", + "columnsFrom": [ + "volumeBackupId" + ], + "columnsTo": [ + "volumeBackupId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployment_buildServerId_server_serverId_fk": { + "name": "deployment_buildServerId_server_serverId_fk", + "tableFrom": "deployment", + "tableTo": "server", + "columnsFrom": [ + "buildServerId" + ], + "columnsTo": [ + "serverId" + ], + "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 + }, + "additionalFlags": { + "name": "additionalFlags", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "destination_organizationId_organization_id_fk": { + "name": "destination_organizationId_organization_id_fk", + "tableFrom": "destination", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.dns_provider": { + "name": "dns_provider", + "schema": "", + "columns": { + "dnsProviderId": { + "name": "dnsProviderId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerType": { + "name": "providerType", + "type": "DnsProviderType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "dns_provider_org_name_idx": { + "name": "dns_provider_org_name_idx", + "columns": [ + { + "expression": "organizationId", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "dns_provider_organizationId_organization_id_fk": { + "name": "dns_provider_organizationId_organization_id_fk", + "tableFrom": "dns_provider", + "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 + }, + "customEntrypoint": { + "name": "customEntrypoint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domainType": { + "name": "domainType", + "type": "domainType", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'application'" + }, + "uniqueConfigKey": { + "name": "uniqueConfigKey", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customCertResolver": { + "name": "customCertResolver", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "previewDeploymentId": { + "name": "previewDeploymentId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "internalPath": { + "name": "internalPath", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/'" + }, + "stripPath": { + "name": "stripPath", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "middlewares": { + "name": "middlewares", + "type": "text[]", + "primaryKey": false, + "notNull": false, + "default": "ARRAY[]::text[]" + }, + "forwardAuthEnabled": { + "name": "forwardAuthEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "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.environment": { + "name": "environment", + "schema": "", + "columns": { + "environmentId": { + "name": "environmentId", + "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 + }, + "env": { + "name": "env", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "isDefault": { + "name": "isDefault", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "environment_projectId_project_projectId_fk": { + "name": "environment_projectId_project_projectId_fk", + "tableFrom": "environment", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.forward_auth_settings": { + "name": "forward_auth_settings", + "schema": "", + "columns": { + "forwardAuthSettingsId": { + "name": "forwardAuthSettingsId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "authDomain": { + "name": "authDomain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "baseDomain": { + "name": "baseDomain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "https": { + "name": "https", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "certificateType": { + "name": "certificateType", + "type": "certificateType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'letsencrypt'" + }, + "customCertResolver": { + "name": "customCertResolver", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "providerId": { + "name": "providerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "forward_auth_settings_providerId_sso_provider_provider_id_fk": { + "name": "forward_auth_settings_providerId_sso_provider_provider_id_fk", + "tableFrom": "forward_auth_settings", + "tableTo": "sso_provider", + "columnsFrom": [ + "providerId" + ], + "columnsTo": [ + "provider_id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "forward_auth_settings_serverId_server_serverId_fk": { + "name": "forward_auth_settings_serverId_server_serverId_fk", + "tableFrom": "forward_auth_settings", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "forward_auth_settings_serverId_unique": { + "name": "forward_auth_settings_serverId_unique", + "nullsNotDistinct": false, + "columns": [ + "serverId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.git_provider": { + "name": "git_provider", + "schema": "", + "columns": { + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerType": { + "name": "providerType", + "type": "gitProviderType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'github'" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sharedWithOrganization": { + "name": "sharedWithOrganization", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "git_provider_organizationId_organization_id_fk": { + "name": "git_provider_organizationId_organization_id_fk", + "tableFrom": "git_provider", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "git_provider_userId_user_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.gitea": { + "name": "gitea", + "schema": "", + "columns": { + "giteaId": { + "name": "giteaId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "giteaUrl": { + "name": "giteaUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'https://gitea.com'" + }, + "giteaInternalUrl": { + "name": "giteaInternalUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_secret": { + "name": "client_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gitProviderId": { + "name": "gitProviderId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'repo,repo:status,read:user,read:org'" + }, + "last_authenticated_at": { + "name": "last_authenticated_at", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "gitea_gitProviderId_git_provider_gitProviderId_fk": { + "name": "gitea_gitProviderId_git_provider_gitProviderId_fk", + "tableFrom": "gitea", + "tableTo": "git_provider", + "columnsFrom": [ + "gitProviderId" + ], + "columnsTo": [ + "gitProviderId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.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 + }, + "githubUrl": { + "name": "githubUrl", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'https://github.com'" + }, + "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'" + }, + "gitlabInternalUrl": { + "name": "gitlabInternalUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "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.libsql": { + "name": "libsql", + "schema": "", + "columns": { + "libsqlId": { + "name": "libsqlId", + "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 + }, + "sqldNode": { + "name": "sqldNode", + "type": "sqldNode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'primary'" + }, + "sqldPrimaryUrl": { + "name": "sqldPrimaryUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableNamespaces": { + "name": "enableNamespaces", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": 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 + }, + "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 + }, + "externalGRPCPort": { + "name": "externalGRPCPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "externalAdminPort": { + "name": "externalAdminPort", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "applicationStatus": { + "name": "applicationStatus", + "type": "applicationStatus", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "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 + }, + "stopGracePeriodSwarm": { + "name": "stopGracePeriodSwarm", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "endpointSpecSwarm": { + "name": "endpointSpecSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "networkIds": { + "name": "networkIds", + "type": "text[]", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "detachDokployNetwork": { + "name": "detachDokployNetwork", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environmentId": { + "name": "environmentId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "libsql_environmentId_environment_environmentId_fk": { + "name": "libsql_environmentId_environment_environmentId_fk", + "tableFrom": "libsql", + "tableTo": "environment", + "columnsFrom": [ + "environmentId" + ], + "columnsTo": [ + "environmentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "libsql_serverId_server_serverId_fk": { + "name": "libsql_serverId_server_serverId_fk", + "tableFrom": "libsql", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "libsql_appName_unique": { + "name": "libsql_appName_unique", + "nullsNotDistinct": false, + "columns": [ + "appName" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.logProvider": { + "name": "logProvider", + "schema": "", + "columns": { + "logProviderId": { + "name": "logProviderId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerType": { + "name": "providerType", + "type": "LogProviderType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "apiKey": { + "name": "apiKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "apiSecret": { + "name": "apiSecret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "extraConfig": { + "name": "extraConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "logProvider_organizationId_organization_id_fk": { + "name": "logProvider_organizationId_organization_id_fk", + "tableFrom": "logProvider", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "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 + }, + "args": { + "name": "args", + "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'" + }, + "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 + }, + "stopGracePeriodSwarm": { + "name": "stopGracePeriodSwarm", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "endpointSpecSwarm": { + "name": "endpointSpecSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "ulimitsSwarm": { + "name": "ulimitsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environmentId": { + "name": "environmentId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "networkIds": { + "name": "networkIds", + "type": "text[]", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "detachDokployNetwork": { + "name": "detachDokployNetwork", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mariadb_environmentId_environment_environmentId_fk": { + "name": "mariadb_environmentId_environment_environmentId_fk", + "tableFrom": "mariadb", + "tableTo": "environment", + "columnsFrom": [ + "environmentId" + ], + "columnsTo": [ + "environmentId" + ], + "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, + "default": "'mongo:8'" + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "args": { + "name": "args", + "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'" + }, + "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 + }, + "stopGracePeriodSwarm": { + "name": "stopGracePeriodSwarm", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "endpointSpecSwarm": { + "name": "endpointSpecSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "ulimitsSwarm": { + "name": "ulimitsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environmentId": { + "name": "environmentId", + "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 + }, + "networkIds": { + "name": "networkIds", + "type": "text[]", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "detachDokployNetwork": { + "name": "detachDokployNetwork", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mongo_environmentId_environment_environmentId_fk": { + "name": "mongo_environmentId_environment_environmentId_fk", + "tableFrom": "mongo", + "tableTo": "environment", + "columnsFrom": [ + "environmentId" + ], + "columnsTo": [ + "environmentId" + ], + "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.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 + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "libsqlId": { + "name": "libsqlId", + "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 + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "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_composeId_compose_composeId_fk": { + "name": "mount_composeId_compose_composeId_fk", + "tableFrom": "mount", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mount_libsqlId_libsql_libsqlId_fk": { + "name": "mount_libsqlId_libsql_libsqlId_fk", + "tableFrom": "mount", + "tableTo": "libsql", + "columnsFrom": [ + "libsqlId" + ], + "columnsTo": [ + "libsqlId" + ], + "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_postgresId_postgres_postgresId_fk": { + "name": "mount_postgresId_postgres_postgresId_fk", + "tableFrom": "mount", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "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" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "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 + }, + "args": { + "name": "args", + "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'" + }, + "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 + }, + "stopGracePeriodSwarm": { + "name": "stopGracePeriodSwarm", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "endpointSpecSwarm": { + "name": "endpointSpecSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "ulimitsSwarm": { + "name": "ulimitsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environmentId": { + "name": "environmentId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "networkIds": { + "name": "networkIds", + "type": "text[]", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "detachDokployNetwork": { + "name": "detachDokployNetwork", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "mysql_environmentId_environment_environmentId_fk": { + "name": "mysql_environmentId_environment_environmentId_fk", + "tableFrom": "mysql", + "tableTo": "environment", + "columnsFrom": [ + "environmentId" + ], + "columnsTo": [ + "environmentId" + ], + "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.network": { + "name": "network", + "schema": "", + "columns": { + "networkId": { + "name": "networkId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dockerId": { + "name": "dockerId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "driver": { + "name": "driver", + "type": "networkDriver", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'bridge'" + }, + "internal": { + "name": "internal", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "attachable": { + "name": "attachable", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableIPv4": { + "name": "enableIPv4", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enableIPv6": { + "name": "enableIPv6", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "mtu": { + "name": "mtu", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "ipam": { + "name": "ipam", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "network_organizationId_organization_id_fk": { + "name": "network_organizationId_organization_id_fk", + "tableFrom": "network", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "network_serverId_server_serverId_fk": { + "name": "network_serverId_server_serverId_fk", + "tableFrom": "network", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom": { + "name": "custom", + "schema": "", + "columns": { + "customId": { + "name": "customId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "headers": { + "name": "headers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "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.lark": { + "name": "lark", + "schema": "", + "columns": { + "larkId": { + "name": "larkId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mattermost": { + "name": "mattermost", + "schema": "", + "columns": { + "mattermostId": { + "name": "mattermostId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel": { + "name": "channel", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "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 + }, + "volumeBackup": { + "name": "volumeBackup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dokployRestart": { + "name": "dokployRestart", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "dokployBackup": { + "name": "dokployBackup", + "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 + }, + "resendId": { + "name": "resendId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gotifyId": { + "name": "gotifyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ntfyId": { + "name": "ntfyId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mattermostId": { + "name": "mattermostId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customId": { + "name": "customId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "larkId": { + "name": "larkId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pushoverId": { + "name": "pushoverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "teamsId": { + "name": "teamsId", + "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_resendId_resend_resendId_fk": { + "name": "notification_resendId_resend_resendId_fk", + "tableFrom": "notification", + "tableTo": "resend", + "columnsFrom": [ + "resendId" + ], + "columnsTo": [ + "resendId" + ], + "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_ntfyId_ntfy_ntfyId_fk": { + "name": "notification_ntfyId_ntfy_ntfyId_fk", + "tableFrom": "notification", + "tableTo": "ntfy", + "columnsFrom": [ + "ntfyId" + ], + "columnsTo": [ + "ntfyId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_mattermostId_mattermost_mattermostId_fk": { + "name": "notification_mattermostId_mattermost_mattermostId_fk", + "tableFrom": "notification", + "tableTo": "mattermost", + "columnsFrom": [ + "mattermostId" + ], + "columnsTo": [ + "mattermostId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_customId_custom_customId_fk": { + "name": "notification_customId_custom_customId_fk", + "tableFrom": "notification", + "tableTo": "custom", + "columnsFrom": [ + "customId" + ], + "columnsTo": [ + "customId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_larkId_lark_larkId_fk": { + "name": "notification_larkId_lark_larkId_fk", + "tableFrom": "notification", + "tableTo": "lark", + "columnsFrom": [ + "larkId" + ], + "columnsTo": [ + "larkId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_pushoverId_pushover_pushoverId_fk": { + "name": "notification_pushoverId_pushover_pushoverId_fk", + "tableFrom": "notification", + "tableTo": "pushover", + "columnsFrom": [ + "pushoverId" + ], + "columnsTo": [ + "pushoverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_teamsId_teams_teamsId_fk": { + "name": "notification_teamsId_teams_teamsId_fk", + "tableFrom": "notification", + "tableTo": "teams", + "columnsFrom": [ + "teamsId" + ], + "columnsTo": [ + "teamsId" + ], + "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.ntfy": { + "name": "ntfy", + "schema": "", + "columns": { + "ntfyId": { + "name": "ntfyId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "serverUrl": { + "name": "serverUrl", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "topic": { + "name": "topic", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "accessToken": { + "name": "accessToken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pushover": { + "name": "pushover", + "schema": "", + "columns": { + "pushoverId": { + "name": "pushoverId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userKey": { + "name": "userKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "apiToken": { + "name": "apiToken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "retry": { + "name": "retry", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "expire": { + "name": "expire", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.resend": { + "name": "resend", + "schema": "", + "columns": { + "resendId": { + "name": "resendId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "apiKey": { + "name": "apiKey", + "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.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.teams": { + "name": "teams", + "schema": "", + "columns": { + "teamsId": { + "name": "teamsId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "webhookUrl": { + "name": "webhookUrl", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.telegram": { + "name": "telegram", + "schema": "", + "columns": { + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "botToken": { + "name": "botToken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chatId": { + "name": "chatId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "messageThreadId": { + "name": "messageThreadId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.patch": { + "name": "patch", + "schema": "", + "columns": { + "patchId": { + "name": "patchId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "patchType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'update'" + }, + "filePath": { + "name": "filePath", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updatedAt": { + "name": "updatedAt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "patch_applicationId_application_applicationId_fk": { + "name": "patch_applicationId_application_applicationId_fk", + "tableFrom": "patch", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "patch_composeId_compose_composeId_fk": { + "name": "patch_composeId_compose_composeId_fk", + "tableFrom": "patch", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "patch_filepath_application_unique": { + "name": "patch_filepath_application_unique", + "nullsNotDistinct": false, + "columns": [ + "filePath", + "applicationId" + ] + }, + "patch_filepath_compose_unique": { + "name": "patch_filepath_compose_unique", + "nullsNotDistinct": false, + "columns": [ + "filePath", + "composeId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.port": { + "name": "port", + "schema": "", + "columns": { + "portId": { + "name": "portId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "publishedPort": { + "name": "publishedPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "publishMode": { + "name": "publishMode", + "type": "publishModeType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'host'" + }, + "targetPort": { + "name": "targetPort", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "protocol": { + "name": "protocol", + "type": "protocolType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "port_applicationId_application_applicationId_fk": { + "name": "port_applicationId_application_applicationId_fk", + "tableFrom": "port", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.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 + }, + "args": { + "name": "args", + "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'" + }, + "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 + }, + "stopGracePeriodSwarm": { + "name": "stopGracePeriodSwarm", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "endpointSpecSwarm": { + "name": "endpointSpecSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "ulimitsSwarm": { + "name": "ulimitsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environmentId": { + "name": "environmentId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "networkIds": { + "name": "networkIds", + "type": "text[]", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "detachDokployNetwork": { + "name": "detachDokployNetwork", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "postgres_environmentId_environment_environmentId_fk": { + "name": "postgres_environmentId_environment_environmentId_fk", + "tableFrom": "postgres", + "tableTo": "environment", + "columnsFrom": [ + "environmentId" + ], + "columnsTo": [ + "environmentId" + ], + "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.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.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.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.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 + }, + "args": { + "name": "args", + "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'" + }, + "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 + }, + "stopGracePeriodSwarm": { + "name": "stopGracePeriodSwarm", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "endpointSpecSwarm": { + "name": "endpointSpecSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "ulimitsSwarm": { + "name": "ulimitsSwarm", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "replicas": { + "name": "replicas", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "environmentId": { + "name": "environmentId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "networkIds": { + "name": "networkIds", + "type": "text[]", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "detachDokployNetwork": { + "name": "detachDokployNetwork", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "redis_environmentId_environment_environmentId_fk": { + "name": "redis_environmentId_environment_environmentId_fk", + "tableFrom": "redis", + "tableTo": "environment", + "columnsFrom": [ + "environmentId" + ], + "columnsTo": [ + "environmentId" + ], + "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.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.rollback": { + "name": "rollback", + "schema": "", + "columns": { + "rollbackId": { + "name": "rollbackId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "deploymentId": { + "name": "deploymentId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fullContext": { + "name": "fullContext", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "rollback_deploymentId_deployment_deploymentId_fk": { + "name": "rollback_deploymentId_deployment_deploymentId_fk", + "tableFrom": "rollback", + "tableTo": "deployment", + "columnsFrom": [ + "deploymentId" + ], + "columnsTo": [ + "deploymentId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.schedule": { + "name": "schedule", + "schema": "", + "columns": { + "scheduleId": { + "name": "scheduleId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cronExpression": { + "name": "cronExpression", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "shellType": { + "name": "shellType", + "type": "shellType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'bash'" + }, + "scheduleType": { + "name": "scheduleType", + "type": "scheduleType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "script": { + "name": "script", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serverId": { + "name": "serverId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "schedule_applicationId_application_applicationId_fk": { + "name": "schedule_applicationId_application_applicationId_fk", + "tableFrom": "schedule", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "schedule_composeId_compose_composeId_fk": { + "name": "schedule_composeId_compose_composeId_fk", + "tableFrom": "schedule", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "schedule_serverId_server_serverId_fk": { + "name": "schedule_serverId_server_serverId_fk", + "tableFrom": "schedule", + "tableTo": "server", + "columnsFrom": [ + "serverId" + ], + "columnsTo": [ + "serverId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "schedule_organizationId_organization_id_fk": { + "name": "schedule_organizationId_organization_id_fk", + "tableFrom": "schedule", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_provider": { + "name": "scim_provider", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scim_token": { + "name": "scim_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "scim_provider_organization_id_organization_id_fk": { + "name": "scim_provider_organization_id_organization_id_fk", + "tableFrom": "scim_provider", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "scim_provider_provider_id_unique": { + "name": "scim_provider_provider_id_unique", + "nullsNotDistinct": false, + "columns": [ + "provider_id" + ] + }, + "scim_provider_scim_token_unique": { + "name": "scim_provider_scim_token_unique", + "nullsNotDistinct": false, + "columns": [ + "scim_token" + ] + } + }, + "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.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 + }, + "logProviderIds": { + "name": "logProviderIds", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "buildsConcurrency": { + "name": "buildsConcurrency", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "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'" + }, + "serverType": { + "name": "serverType", + "type": "serverType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'deploy'" + }, + "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.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": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "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.sso_provider": { + "name": "sso_provider", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "issuer": { + "name": "issuer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "oidc_config": { + "name": "oidc_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "saml_config": { + "name": "saml_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain_verified": { + "name": "domain_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sso_provider_user_id_user_id_fk": { + "name": "sso_provider_user_id_user_id_fk", + "tableFrom": "sso_provider", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "sso_provider_organization_id_organization_id_fk": { + "name": "sso_provider_organization_id_organization_id_fk", + "tableFrom": "sso_provider", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "sso_provider_provider_id_unique": { + "name": "sso_provider_provider_id_unique", + "nullsNotDistinct": false, + "columns": [ + "provider_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_tag": { + "name": "project_tag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "projectId": { + "name": "projectId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tagId": { + "name": "tagId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "project_tag_projectId_project_projectId_fk": { + "name": "project_tag_projectId_project_projectId_fk", + "tableFrom": "project_tag", + "tableTo": "project", + "columnsFrom": [ + "projectId" + ], + "columnsTo": [ + "projectId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "project_tag_tagId_tag_tagId_fk": { + "name": "project_tag_tagId_tag_tagId_fk", + "tableFrom": "project_tag", + "tableTo": "tag", + "columnsFrom": [ + "tagId" + ], + "columnsTo": [ + "tagId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unique_project_tag": { + "name": "unique_project_tag", + "nullsNotDistinct": false, + "columns": [ + "projectId", + "tagId" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tag": { + "name": "tag", + "schema": "", + "columns": { + "tagId": { + "name": "tagId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "tag_organizationId_organization_id_fk": { + "name": "tag_organizationId_organization_id_fk", + "tableFrom": "tag", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unique_org_tag_name": { + "name": "unique_org_tag_name", + "nullsNotDistinct": false, + "columns": [ + "organizationId", + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "firstName": { + "name": "firstName", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "lastName": { + "name": "lastName", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "isRegistered": { + "name": "isRegistered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expirationDate": { + "name": "expirationDate", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "banned": { + "name": "banned", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'user'" + }, + "enablePaidFeatures": { + "name": "enablePaidFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "allowImpersonation": { + "name": "allowImpersonation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enableEnterpriseFeatures": { + "name": "enableEnterpriseFeatures", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "licenseKey": { + "name": "licenseKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isValidEnterpriseLicense": { + "name": "isValidEnterpriseLicense", + "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 + }, + "sendInvoiceNotifications": { + "name": "sendInvoiceNotifications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isEnterpriseCloud": { + "name": "isEnterpriseCloud", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "trustedOrigins": { + "name": "trustedOrigins", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "bookmarkedTemplates": { + "name": "bookmarkedTemplates", + "type": "text[]", + "primaryKey": false, + "notNull": false, + "default": "ARRAY[]::text[]" + }, + "onboardingCompletedAt": { + "name": "onboardingCompletedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.vault_provider": { + "name": "vault_provider", + "schema": "", + "columns": { + "vaultProviderId": { + "name": "vaultProviderId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerType": { + "name": "providerType", + "type": "VaultProviderType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "assignments": { + "name": "assignments", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "organizationId": { + "name": "organizationId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "vault_provider_org_name_idx": { + "name": "vault_provider_org_name_idx", + "columns": [ + { + "expression": "organizationId", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "vault_provider_organizationId_organization_id_fk": { + "name": "vault_provider_organizationId_organization_id_fk", + "tableFrom": "vault_provider", + "tableTo": "organization", + "columnsFrom": [ + "organizationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.volume_backup": { + "name": "volume_backup", + "schema": "", + "columns": { + "volumeBackupId": { + "name": "volumeBackupId", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "volumeName": { + "name": "volumeName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serviceType": { + "name": "serviceType", + "type": "serviceType", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'application'" + }, + "appName": { + "name": "appName", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "serviceName": { + "name": "serviceName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "turnOff": { + "name": "turnOff", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cronExpression": { + "name": "cronExpression", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keepLatestCount": { + "name": "keepLatestCount", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "applicationId": { + "name": "applicationId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postgresId": { + "name": "postgresId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mariadbId": { + "name": "mariadbId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mongoId": { + "name": "mongoId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mysqlId": { + "name": "mysqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redisId": { + "name": "redisId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "libsqlId": { + "name": "libsqlId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "composeId": { + "name": "composeId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destinationId": { + "name": "destinationId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "volume_backup_applicationId_application_applicationId_fk": { + "name": "volume_backup_applicationId_application_applicationId_fk", + "tableFrom": "volume_backup", + "tableTo": "application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "applicationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_postgresId_postgres_postgresId_fk": { + "name": "volume_backup_postgresId_postgres_postgresId_fk", + "tableFrom": "volume_backup", + "tableTo": "postgres", + "columnsFrom": [ + "postgresId" + ], + "columnsTo": [ + "postgresId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_mariadbId_mariadb_mariadbId_fk": { + "name": "volume_backup_mariadbId_mariadb_mariadbId_fk", + "tableFrom": "volume_backup", + "tableTo": "mariadb", + "columnsFrom": [ + "mariadbId" + ], + "columnsTo": [ + "mariadbId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_mongoId_mongo_mongoId_fk": { + "name": "volume_backup_mongoId_mongo_mongoId_fk", + "tableFrom": "volume_backup", + "tableTo": "mongo", + "columnsFrom": [ + "mongoId" + ], + "columnsTo": [ + "mongoId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_mysqlId_mysql_mysqlId_fk": { + "name": "volume_backup_mysqlId_mysql_mysqlId_fk", + "tableFrom": "volume_backup", + "tableTo": "mysql", + "columnsFrom": [ + "mysqlId" + ], + "columnsTo": [ + "mysqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_redisId_redis_redisId_fk": { + "name": "volume_backup_redisId_redis_redisId_fk", + "tableFrom": "volume_backup", + "tableTo": "redis", + "columnsFrom": [ + "redisId" + ], + "columnsTo": [ + "redisId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_libsqlId_libsql_libsqlId_fk": { + "name": "volume_backup_libsqlId_libsql_libsqlId_fk", + "tableFrom": "volume_backup", + "tableTo": "libsql", + "columnsFrom": [ + "libsqlId" + ], + "columnsTo": [ + "libsqlId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_composeId_compose_composeId_fk": { + "name": "volume_backup_composeId_compose_composeId_fk", + "tableFrom": "volume_backup", + "tableTo": "compose", + "columnsFrom": [ + "composeId" + ], + "columnsTo": [ + "composeId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "volume_backup_destinationId_destination_destinationId_fk": { + "name": "volume_backup_destinationId_destination_destinationId_fk", + "tableFrom": "volume_backup", + "tableTo": "destination", + "columnsFrom": [ + "destinationId" + ], + "columnsTo": [ + "destinationId" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.webServerSettings": { + "name": "webServerSettings", + "schema": "", + "columns": { + "id": { + "name": "id", + "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'" + }, + "https": { + "name": "https", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "letsEncryptEmail": { + "name": "letsEncryptEmail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sshPrivateKey": { + "name": "sshPrivateKey", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enableDockerCleanup": { + "name": "enableDockerCleanup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "logCleanupCron": { + "name": "logCleanupCron", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'0 0 * * *'" + }, + "logProviderIds": { + "name": "logProviderIds", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "logManagementOrganizationId": { + "name": "logManagementOrganizationId", + "type": "text", + "primaryKey": false, + "notNull": 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" + }, + "whitelabelingConfig": { + "name": "whitelabelingConfig", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{\"appName\":null,\"appDescription\":null,\"logoUrl\":null,\"faviconUrl\":null,\"customCss\":null,\"loginLogoUrl\":null,\"supportUrl\":null,\"docsUrl\":null,\"errorPageTitle\":null,\"errorPageDescription\":null,\"footerText\":null,\"ogImageUrl\":null}'::jsonb" + }, + "remoteServersOnly": { + "name": "remoteServersOnly", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "buildsConcurrency": { + "name": "buildsConcurrency", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "enforceSSO": { + "name": "enforceSSO", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "webServerSettings_logManagementOrganizationId_organization_id_fk": { + "name": "webServerSettings_logManagementOrganizationId_organization_id_fk", + "tableFrom": "webServerSettings", + "tableTo": "organization", + "columnsFrom": [ + "logManagementOrganizationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.buildType": { + "name": "buildType", + "schema": "public", + "values": [ + "dockerfile", + "heroku_buildpacks", + "paketo_buildpacks", + "nixpacks", + "static", + "railpack" + ] + }, + "public.sourceType": { + "name": "sourceType", + "schema": "public", + "values": [ + "docker", + "git", + "github", + "gitlab", + "bitbucket", + "gitea", + "drop" + ] + }, + "public.backupType": { + "name": "backupType", + "schema": "public", + "values": [ + "database", + "compose" + ] + }, + "public.databaseType": { + "name": "databaseType", + "schema": "public", + "values": [ + "postgres", + "mariadb", + "mysql", + "mongo", + "web-server", + "libsql" + ] + }, + "public.composeType": { + "name": "composeType", + "schema": "public", + "values": [ + "docker-compose", + "stack" + ] + }, + "public.sourceTypeCompose": { + "name": "sourceTypeCompose", + "schema": "public", + "values": [ + "git", + "github", + "gitlab", + "bitbucket", + "gitea", + "raw" + ] + }, + "public.deploymentStatus": { + "name": "deploymentStatus", + "schema": "public", + "values": [ + "running", + "done", + "error", + "cancelled" + ] + }, + "public.DnsProviderType": { + "name": "DnsProviderType", + "schema": "public", + "values": [ + "cloudflare", + "route53", + "porkbun", + "infomaniak", + "ovh" + ] + }, + "public.domainType": { + "name": "domainType", + "schema": "public", + "values": [ + "compose", + "application", + "preview" + ] + }, + "public.gitProviderType": { + "name": "gitProviderType", + "schema": "public", + "values": [ + "github", + "gitlab", + "bitbucket", + "gitea" + ] + }, + "public.LogProviderType": { + "name": "LogProviderType", + "schema": "public", + "values": [ + "loki", + "datadog", + "betterstack", + "elasticsearch", + "splunk_hec", + "aws_cloudwatch" + ] + }, + "public.mountType": { + "name": "mountType", + "schema": "public", + "values": [ + "bind", + "volume", + "file" + ] + }, + "public.serviceType": { + "name": "serviceType", + "schema": "public", + "values": [ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose", + "libsql" + ] + }, + "public.networkDriver": { + "name": "networkDriver", + "schema": "public", + "values": [ + "bridge", + "overlay" + ] + }, + "public.notificationType": { + "name": "notificationType", + "schema": "public", + "values": [ + "slack", + "telegram", + "discord", + "email", + "resend", + "gotify", + "ntfy", + "mattermost", + "pushover", + "custom", + "lark", + "teams" + ] + }, + "public.patchType": { + "name": "patchType", + "schema": "public", + "values": [ + "create", + "update", + "delete" + ] + }, + "public.protocolType": { + "name": "protocolType", + "schema": "public", + "values": [ + "tcp", + "udp" + ] + }, + "public.publishModeType": { + "name": "publishModeType", + "schema": "public", + "values": [ + "ingress", + "host" + ] + }, + "public.RegistryType": { + "name": "RegistryType", + "schema": "public", + "values": [ + "selfHosted", + "cloud" + ] + }, + "public.scheduleType": { + "name": "scheduleType", + "schema": "public", + "values": [ + "application", + "compose", + "server", + "dokploy-server" + ] + }, + "public.shellType": { + "name": "shellType", + "schema": "public", + "values": [ + "bash", + "sh" + ] + }, + "public.serverStatus": { + "name": "serverStatus", + "schema": "public", + "values": [ + "active", + "inactive" + ] + }, + "public.serverType": { + "name": "serverType", + "schema": "public", + "values": [ + "deploy", + "build" + ] + }, + "public.applicationStatus": { + "name": "applicationStatus", + "schema": "public", + "values": [ + "idle", + "running", + "done", + "error" + ] + }, + "public.certificateType": { + "name": "certificateType", + "schema": "public", + "values": [ + "letsencrypt", + "none", + "custom" + ] + }, + "public.sqldNode": { + "name": "sqldNode", + "schema": "public", + "values": [ + "primary", + "replica" + ] + }, + "public.triggerType": { + "name": "triggerType", + "schema": "public", + "values": [ + "push", + "tag" + ] + }, + "public.VaultProviderType": { + "name": "VaultProviderType", + "schema": "public", + "values": [ + "hashicorp", + "infisical", + "aws", + "aws-parameter-store", + "doppler", + "azure", + "scaleway", + "phase" + ] + } + }, + "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 5be52175e..962fba287 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -1387,6 +1387,13 @@ "when": 1789042957674, "tag": "0197_past_omega_red", "breakpoints": true + }, + { + "idx": 198, + "version": "7", + "when": 1790203407320, + "tag": "0198_kind_hemingway", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/server/api/routers/log-provider.ts b/apps/dokploy/server/api/routers/log-provider.ts index f49c3eb07..9a2ce8204 100644 --- a/apps/dokploy/server/api/routers/log-provider.ts +++ b/apps/dokploy/server/api/routers/log-provider.ts @@ -1,14 +1,21 @@ import { + claimWebServerLogManagement, createLogProvider, findLogProviderById, findLogProvidersByOrganization, + findServerById, + getLogManagementServerStatus, logProviderAdapters, removeLogProvider, + removeVectorAgent, sanitizeLogProvider, + setupVectorAgent, testLogProviderConnection, updateLogProvider, + updateServerLogProviders, } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; +import { z } from "zod"; import { audit } from "@/server/api/utils/audit"; import { apiCreateLogProvider, @@ -17,9 +24,46 @@ import { apiTestLogProvider, apiUpdateLogProvider, } from "@/server/db/schema"; -import { safeSyncVectorAgentsForOrganization } from "@/server/utils/vector-resync"; import { createTRPCRouter, protectedProcedure, withPermission } from "../trpc"; +const assertServerBelongsToOrg = async ( + serverId: string | undefined, + organizationId: string, +) => { + if (!serverId) return; + const server = await findServerById(serverId); + if (server.organizationId !== organizationId) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not authorized to access this server", + }); + } +}; + +const assertLogProvidersBelongToOrg = async ( + logProviderIds: string[], + organizationId: string, +) => { + const providers = await findLogProvidersByOrganization(organizationId); + const byId = new Map(providers.map((p) => [p.logProviderId, p])); + for (const id of logProviderIds) { + if (!byId.has(id)) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: + "One of the selected log providers is not in this organization", + }); + } + } + if (!logProviderIds.some((id) => byId.get(id)?.enabled)) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: + "Select at least one enabled log provider — a disabled one ships nothing.", + }); + } +}; + export const logProviderRouter = createTRPCRouter({ create: withPermission("logProvider", "create") .input(apiCreateLogProvider) @@ -34,10 +78,7 @@ export const logProviderRouter = createTRPCRouter({ resourceId: provider.logProviderId, resourceName: provider.name, }); - const syncErrors = await safeSyncVectorAgentsForOrganization( - ctx.session.activeOrganizationId, - ); - return { ...sanitizeLogProvider(provider), syncErrors }; + return sanitizeLogProvider(provider); }), update: withPermission("logProvider", "create") .input(apiUpdateLogProvider) @@ -57,10 +98,7 @@ export const logProviderRouter = createTRPCRouter({ resourceId: logProviderId, resourceName: provider.name, }); - const syncErrors = await safeSyncVectorAgentsForOrganization( - ctx.session.activeOrganizationId, - ); - return { ...sanitizeLogProvider(updated), syncErrors }; + return sanitizeLogProvider(updated); }), remove: withPermission("logProvider", "delete") .input(apiRemoveLogProvider) @@ -79,10 +117,7 @@ export const logProviderRouter = createTRPCRouter({ resourceId: provider.logProviderId, resourceName: provider.name, }); - const syncErrors = await safeSyncVectorAgentsForOrganization( - ctx.session.activeOrganizationId, - ); - return { ...sanitizeLogProvider(removed), syncErrors }; + return sanitizeLogProvider(removed); }), all: withPermission("logProvider", "read").query(async ({ ctx }) => { return await findLogProvidersByOrganization( @@ -130,6 +165,68 @@ export const logProviderRouter = createTRPCRouter({ logProviderId: input.logProviderId, }); }), + serverStatus: withPermission("logProvider", "read").query(({ ctx }) => + getLogManagementServerStatus(ctx.session.activeOrganizationId), + ), + deployOnServer: withPermission("logProvider", "create") + .input( + z.object({ + serverId: z.string().nullable().optional(), + logProviderIds: z.array(z.string()).min(1), + }), + ) + .mutation(async ({ ctx, input }) => { + const organizationId = ctx.session.activeOrganizationId; + const serverId = input.serverId ?? undefined; + await assertServerBelongsToOrg(serverId, organizationId); + await assertLogProvidersBelongToOrg(input.logProviderIds, organizationId); + + if (serverId) { + await updateServerLogProviders(serverId, input.logProviderIds); + } else { + const claimed = await claimWebServerLogManagement( + organizationId, + input.logProviderIds, + ); + if (!claimed) { + throw new TRPCError({ + code: "CONFLICT", + message: + "The local Vector agent is already claimed by another organization", + }); + } + } + + await setupVectorAgent(organizationId, serverId, input.logProviderIds); + await audit(ctx, { + action: "create", + resourceType: "server", + resourceId: input.serverId ?? "local", + resourceName: "log-management", + }); + return { installed: true }; + }), + removeOnServer: withPermission("logProvider", "create") + .input(z.object({ serverId: z.string().nullable().optional() })) + .mutation(async ({ ctx, input }) => { + const organizationId = ctx.session.activeOrganizationId; + const serverId = input.serverId ?? undefined; + await assertServerBelongsToOrg(serverId, organizationId); + + await removeVectorAgent(serverId); + if (serverId) { + await updateServerLogProviders(serverId, []); + } else { + await claimWebServerLogManagement(organizationId, []); + } + await audit(ctx, { + action: "delete", + resourceType: "server", + resourceId: input.serverId ?? "local", + resourceName: "log-management", + }); + return { installed: false }; + }), availableTypes: protectedProcedure.query(() => { return Object.values(logProviderAdapters).map((adapter) => ({ type: adapter.type, diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts index a334c4afe..6a7740238 100644 --- a/apps/dokploy/server/api/routers/organization.ts +++ b/apps/dokploy/server/api/routers/organization.ts @@ -1,5 +1,6 @@ import { db } from "@dokploy/server/db"; import { + deleteOrganization, hasValidLicense, IS_CLOUD, sendInvitationEmail, @@ -20,7 +21,6 @@ import { organizationRole, user, } from "@/server/db/schema"; -import { teardownVectorForOrganizationDeletion } from "@/server/utils/vector-resync"; import { createTRPCRouter, protectedProcedure, withPermission } from "../trpc"; export const organizationRouter = createTRPCRouter({ create: protectedProcedure @@ -286,11 +286,7 @@ export const organizationRouter = createTRPCRouter({ }); } - await teardownVectorForOrganizationDeletion(input.organizationId); - - const result = await db - .delete(organization) - .where(eq(organization.id, input.organizationId)); + const result = await deleteOrganization(input.organizationId); await audit(ctx, { action: "delete", diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts index fd2321d1a..b74e233d4 100644 --- a/apps/dokploy/server/api/routers/server.ts +++ b/apps/dokploy/server/api/routers/server.ts @@ -51,10 +51,6 @@ import { server, } from "@/server/db/schema"; import { applyDockerCleanupSchedule } from "@/server/utils/docker-cleanup"; -import { - applyVectorResyncSchedule, - syncVectorAgentAndSchedule, -} from "@/server/utils/vector-resync"; export const serverRouter = createTRPCRouter({ create: withPermission("server", "create") @@ -458,73 +454,6 @@ export const serverRouter = createTRPCRouter({ throw error; } }), - setupLogManagement: withPermission("server", "create") - .input(apiFindOneServer) - .mutation(async ({ input, ctx }) => { - const server = await findServerById(input.serverId); - if (server.organizationId !== ctx.session.activeOrganizationId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to setup this server", - }); - } - const result = await syncVectorAgentAndSchedule(input.serverId); - await audit(ctx, { - action: "update", - resourceType: "server", - resourceId: input.serverId, - resourceName: server.name, - }); - return result; - }), - updateLogManagement: withPermission("server", "create") - .input( - z.object({ - serverId: z.string().min(1), - enableLogManagement: z.boolean(), - }), - ) - .mutation(async ({ input, ctx }) => { - const server = await findServerById(input.serverId); - if (server.organizationId !== ctx.session.activeOrganizationId) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not authorized to update this server", - }); - } - await updateServerById(input.serverId, { - enableLogManagement: input.enableLogManagement, - }); - try { - const result = await syncVectorAgentAndSchedule(input.serverId); - await audit(ctx, { - action: "update", - resourceType: "server", - resourceId: input.serverId, - resourceName: server.name, - }); - return { ...result, enableLogManagement: input.enableLogManagement }; - } catch (error) { - await updateServerById(input.serverId, { - enableLogManagement: server.enableLogManagement, - }); - await syncVectorAgentAndSchedule(input.serverId).catch( - (teardownError) => { - console.error( - `[Vector] Failed to tear down agent for server ${input.serverId} after a failed sync — it may still be running:`, - teardownError, - ); - }, - ); - throw new TRPCError({ - code: "BAD_REQUEST", - message: - error instanceof Error - ? `Failed to sync Vector agent: ${error.message}` - : "Failed to sync Vector agent", - }); - } - }), remove: withPermission("server", "delete") .input(apiRemoveServer) .mutation(async ({ input, ctx }) => { @@ -546,18 +475,15 @@ export const serverRouter = createTRPCRouter({ }); } let vectorAgentRemovalWarning: string | undefined; - if (currentServer.enableLogManagement) { - await removeVectorAgent({ serverId: input.serverId }).catch( - (error) => { - vectorAgentRemovalWarning = - error instanceof Error ? error.message : String(error); - console.error( - `[Vector] Failed to remove agent for server ${input.serverId} before deletion:`, - error, - ); - }, - ); - await applyVectorResyncSchedule(input.serverId, false); + if ((currentServer.logProviderIds?.length ?? 0) > 0) { + await removeVectorAgent(input.serverId).catch((error) => { + vectorAgentRemovalWarning = + error instanceof Error ? error.message : String(error); + console.error( + `[Vector] Failed to remove agent for server ${input.serverId} before deletion:`, + error, + ); + }); } await audit(ctx, { action: "delete", @@ -604,33 +530,7 @@ export const serverRouter = createTRPCRouter({ }); } - const connectionChanged = - server.ipAddress !== input.ipAddress || - server.port !== input.port || - server.username !== input.username || - server.sshKeyId !== input.sshKeyId; - - let vectorAgentWarning: string | undefined; - const recordVectorWarning = (prefix: string, error: unknown) => { - const message = `${prefix}: ${error instanceof Error ? error.message : String(error)}`; - vectorAgentWarning = vectorAgentWarning - ? `${vectorAgentWarning} ${message}` - : message; - console.error(`[Vector] ${message}`); - }; - - if (connectionChanged && server.enableLogManagement) { - await removeVectorAgent({ serverId: input.serverId }).catch( - (error) => { - recordVectorWarning( - "Failed to remove the agent from the old host", - error, - ); - }, - ); - } - - let currentServer = await updateServerById(input.serverId, { + const currentServer = await updateServerById(input.serverId, { ...input, }); @@ -640,37 +540,13 @@ export const serverRouter = createTRPCRouter({ input.enableDockerCleanup, ); - if (connectionChanged && server.enableLogManagement) { - try { - await syncVectorAgentAndSchedule(input.serverId); - } catch (error) { - currentServer = - (await updateServerById(input.serverId, { - enableLogManagement: false, - })) ?? currentServer; - await syncVectorAgentAndSchedule(input.serverId).catch( - (teardownError) => { - console.error( - `[Vector] Failed to tear down agent for server ${input.serverId} after a failed sync — it may still be running:`, - teardownError, - ); - }, - ); - recordVectorWarning( - "Failed to install the agent on the new host, log management has been turned off for this server", - error, - ); - } - } - await audit(ctx, { action: "update", resourceType: "server", resourceId: input.serverId, resourceName: server.name, - ...(vectorAgentWarning ? { metadata: { vectorAgentWarning } } : {}), }); - return { ...currentServer, vectorAgentWarning }; + return currentServer; } catch (error) { throw error; } diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index 5caeae96e..db2951ae4 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -4,7 +4,6 @@ import { checkPortInUse, checkPostgresHealth, checkTraefikHealth, - claimWebServerLogManagement, cleanupAll, cleanupAllBackground, cleanupBuilders, @@ -72,7 +71,6 @@ import { } from "@/server/db/schema"; import { cleanAllDeploymentQueue } from "@/server/queues/queueSetup"; import { removeJob, schedule } from "@/server/utils/backup"; -import { syncWebVectorAgentAndSchedule } from "@/server/utils/vector-resync"; import packageInfo from "../../../package.json"; import { appRouter } from "../root"; import { @@ -412,75 +410,6 @@ export const settingsRouter = createTRPCRouter({ return true; }), - updateLogManagement: adminProcedure - .input(z.object({ enableLogManagement: z.boolean() })) - .mutation(async ({ input, ctx }) => { - if (IS_CLOUD) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "This feature is only available for self-hosted instances", - }); - } - - const activeOrganizationId = ctx.session.activeOrganizationId; - const current = await getWebServerSettings(); - const currentOwner = current?.logManagementOrganizationId ?? null; - - if (currentOwner && currentOwner !== activeOrganizationId) { - throw new TRPCError({ - code: "FORBIDDEN", - message: input.enableLogManagement - ? "The local Vector agent is already used by another organization on this instance — disable it there first." - : "You are not authorized to disable the local Vector agent — it belongs to another organization.", - }); - } - - const previous = { - enableLogManagement: !!current?.enableLogManagement, - logManagementOrganizationId: currentOwner, - }; - - const claimed = await claimWebServerLogManagement( - activeOrganizationId, - input.enableLogManagement, - ); - if (!claimed) { - throw new TRPCError({ - code: "FORBIDDEN", - message: - "The local Vector agent was just claimed by another organization — try again.", - }); - } - - try { - const result = - await syncWebVectorAgentAndSchedule(activeOrganizationId); - await audit(ctx, { - action: "update", - resourceType: "settings", - resourceName: "log-management", - }); - return { ...result, enableLogManagement: input.enableLogManagement }; - } catch (error) { - await updateWebServerSettings(previous); - await syncWebVectorAgentAndSchedule(activeOrganizationId).catch( - (teardownError) => { - console.error( - "[Vector] Failed to reconcile local agent after a failed sync:", - teardownError, - ); - }, - ); - throw new TRPCError({ - code: "BAD_REQUEST", - message: - error instanceof Error - ? `Failed to sync local Vector agent: ${error.message}` - : "Failed to sync local Vector agent", - }); - } - }), - updateRemoteServersOnly: enterpriseProcedure .input(z.object({ remoteServersOnly: z.boolean() })) .mutation(async ({ input, ctx }) => { diff --git a/apps/dokploy/server/server.ts b/apps/dokploy/server/server.ts index f57c2264c..7f4f3d407 100644 --- a/apps/dokploy/server/server.ts +++ b/apps/dokploy/server/server.ts @@ -16,7 +16,6 @@ import { import { config } from "dotenv"; import next from "next"; import packageInfo from "../package.json"; -import { initVectorResyncSchedules } from "./utils/vector-resync"; import { setupDockerContainerLogsWebSocketServer } from "./wss/docker-container-logs"; import { setupDockerContainerTerminalWebSocketServer } from "./wss/docker-container-terminal"; import { setupDockerStatsMonitoringSocketServer } from "./wss/docker-stats"; @@ -66,10 +65,8 @@ void app.prepare().then(async () => { await initSchedules(); await initCancelDeployments(); await initVolumeBackupsCronJobs(); - await initVectorResyncSchedules(); await sendDokployRestartNotifications(); } else if (IS_CLOUD) { - await initVectorResyncSchedules(); } await initEnterpriseBackupCronJobs(); diff --git a/apps/dokploy/server/utils/vector-resync.ts b/apps/dokploy/server/utils/vector-resync.ts deleted file mode 100644 index 4668e1699..000000000 --- a/apps/dokploy/server/utils/vector-resync.ts +++ /dev/null @@ -1,249 +0,0 @@ -import { - findAllServersWithLogManagementEnabled, - findServersWithLogManagementEnabled, - getWebServerSettings, - hasEnabledLogProvider, - IS_CLOUD, - loadVectorOrgData, - removeVectorAgent, - removeWebVectorAgent, - syncVectorAgent, - syncVectorConfig, - syncWebVectorAgent, - syncWebVectorConfig, - updateWebServerSettings, - VECTOR_RESYNC_CRON_JOB, - type VectorOrgData, -} from "@dokploy/server"; -import { TRPCError } from "@trpc/server"; -import { scheduledJobs, scheduleJob } from "node-schedule"; - -export const applyVectorResyncSchedule = async ( - serverId: string, - enable: boolean, -) => { - const jobName = `vector-resync:${serverId}`; - if (IS_CLOUD) { - console.warn( - `[Vector] Periodic resync for server ${serverId} is running in-process, not via the Cloud Jobs service (no handler for "vector-resync" yet).`, - ); - } - if (enable) { - scheduleJob(jobName, VECTOR_RESYNC_CRON_JOB, async () => { - try { - await syncVectorConfig({ serverId }); - } catch (error) { - console.error(`[Vector] Resync failed for server ${serverId}:`, error); - if (error instanceof TRPCError && error.code === "NOT_FOUND") { - scheduledJobs[jobName]?.cancel(); - } - } - }); - } else { - scheduledJobs[jobName]?.cancel(); - } -}; - -const WEB_VECTOR_RESYNC_JOB_NAME = "vector-resync-web"; - -export const applyWebVectorResyncSchedule = async ( - organizationId: string, - enable: boolean, -) => { - if (enable) { - scheduleJob( - WEB_VECTOR_RESYNC_JOB_NAME, - VECTOR_RESYNC_CRON_JOB, - async () => { - try { - await syncWebVectorConfig(organizationId); - } catch (error) { - console.error("[Vector] Local resync failed:", error); - } - }, - ); - } else { - scheduledJobs[WEB_VECTOR_RESYNC_JOB_NAME]?.cancel(); - } -}; - -export const initVectorResyncSchedules = async () => { - let servers: Awaited< - ReturnType - >; - try { - servers = await findAllServersWithLogManagementEnabled(); - } catch (error) { - console.error( - "[Vector] Failed to load servers for resync schedules:", - error, - ); - return; - } - const hasProviderByOrg = new Map< - string, - ReturnType - >(); - const hasProviderCached = (organizationId: string) => { - let result = hasProviderByOrg.get(organizationId); - if (!result) { - result = hasEnabledLogProvider(organizationId); - hasProviderByOrg.set(organizationId, result); - } - return result; - }; - - await Promise.all( - servers.map(async (s) => { - try { - if (await hasProviderCached(s.organizationId)) { - await applyVectorResyncSchedule(s.serverId, true); - } - } catch (error) { - console.error( - `[Vector] Failed to re-register resync schedule for server ${s.serverId}:`, - error, - ); - } - }), - ); - - if (!IS_CLOUD) { - try { - const settings = await getWebServerSettings(); - const organizationId = settings?.logManagementOrganizationId; - if ( - settings?.enableLogManagement && - organizationId && - (await hasEnabledLogProvider(organizationId)) - ) { - await applyWebVectorResyncSchedule(organizationId, true); - } - } catch (error) { - console.error( - "[Vector] Failed to re-register local resync schedule:", - error, - ); - } - } -}; - -export const syncVectorAgentAndSchedule = async ( - serverId: string, - preloaded?: VectorOrgData, -) => { - const { installed } = await syncVectorAgent({ serverId, preloaded }); - await applyVectorResyncSchedule(serverId, installed); - return { installed }; -}; - -export const syncWebVectorAgentAndSchedule = async ( - organizationId: string, - preloaded?: VectorOrgData, -) => { - const { installed } = await syncWebVectorAgent(preloaded); - await applyWebVectorResyncSchedule(organizationId, installed); - return { installed }; -}; - -export const syncVectorAgentsForOrganization = async ( - organizationId: string, -): Promise> => { - const servers = await findServersWithLogManagementEnabled(organizationId); - const webOwnsThisOrg = - !IS_CLOUD && - (await getWebServerSettings())?.logManagementOrganizationId === - organizationId; - - if (servers.length === 0 && !webOwnsThisOrg) { - return []; - } - - const preloaded = await loadVectorOrgData(organizationId); - - const targets: Array<{ - id: string; - run: () => Promise<{ installed: boolean }>; - }> = [ - ...servers.map((s) => ({ - id: s.serverId, - run: () => syncVectorAgentAndSchedule(s.serverId, preloaded), - })), - ...(webOwnsThisOrg - ? [ - { - id: "web", - run: () => syncWebVectorAgentAndSchedule(organizationId, preloaded), - }, - ] - : []), - ]; - - const results = await Promise.allSettled(targets.map((t) => t.run())); - - const errors: Array<{ serverId: string; error: string }> = []; - results.forEach((result, index) => { - if (result.status === "rejected") { - const target = targets[index]; - if (target) { - errors.push({ - serverId: target.id, - error: - result.reason instanceof Error - ? result.reason.message - : String(result.reason), - }); - } - } - }); - return errors; -}; - -export const safeSyncVectorAgentsForOrganization = async ( - organizationId: string, -) => { - try { - return await syncVectorAgentsForOrganization(organizationId); - } catch (error) { - return [ - { - serverId: "unknown", - error: error instanceof Error ? error.message : String(error), - }, - ]; - } -}; - -export const teardownVectorForOrganizationDeletion = async ( - organizationId: string, -): Promise => { - const servers = await findServersWithLogManagementEnabled(organizationId); - await Promise.all( - servers.map(async (s) => { - await removeVectorAgent({ serverId: s.serverId }).catch((error) => { - console.error( - `[Vector] Failed to remove agent for server ${s.serverId} before deleting organization ${organizationId}:`, - error, - ); - }); - await applyVectorResyncSchedule(s.serverId, false); - }), - ); - - if (!IS_CLOUD) { - const settings = await getWebServerSettings(); - if (settings?.logManagementOrganizationId === organizationId) { - await removeWebVectorAgent().catch((error) => { - console.error( - `[Vector] Failed to remove local agent before deleting organization ${organizationId}:`, - error, - ); - }); - await applyWebVectorResyncSchedule(organizationId, false); - await updateWebServerSettings({ - enableLogManagement: false, - logManagementOrganizationId: null, - }); - } - } -}; diff --git a/apps/dokploy/utils/api.ts b/apps/dokploy/utils/api.ts index d7f165f6a..94e5c5a59 100644 --- a/apps/dokploy/utils/api.ts +++ b/apps/dokploy/utils/api.ts @@ -52,7 +52,8 @@ const links = transformer: superjson, }), false: splitLink({ - condition: (op) => op.input instanceof FormData, + condition: (op) => + op.input instanceof FormData || op.context.skipBatch === true, true: httpLink({ url: `${getBaseUrl()}/api/trpc`, transformer: superjson, diff --git a/packages/server/src/constants/index.ts b/packages/server/src/constants/index.ts index 8f8de52f9..ea084e2f4 100644 --- a/packages/server/src/constants/index.ts +++ b/packages/server/src/constants/index.ts @@ -13,8 +13,6 @@ export const DOKPLOY_DOCKER_PORT = process.env.DOKPLOY_DOCKER_PORT export const CLEANUP_CRON_JOB = "50 23 * * *"; -export const VECTOR_RESYNC_CRON_JOB = "*/15 * * * *"; - // Body size limits for the OpenAPI catch-all route (pages/api/[...trpc].ts). const parseByteSize = (envVar: string, fallback: number): number => { const raw = process.env[envVar]; diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index aa5209631..c58162b39 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -1,4 +1,4 @@ -import { relations } from "drizzle-orm"; +import { relations, sql } from "drizzle-orm"; import { boolean, integer, @@ -42,7 +42,10 @@ export const server = pgTable("server", { .notNull() .$defaultFn(() => generateAppName("server")), enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false), - enableLogManagement: boolean("enableLogManagement").notNull().default(false), + logProviderIds: text("logProviderIds") + .array() + .notNull() + .default(sql`ARRAY[]::text[]`), buildsConcurrency: integer("buildsConcurrency").notNull().default(1), createdAt: text("createdAt").notNull(), organizationId: text("organizationId") diff --git a/packages/server/src/db/schema/web-server-settings.ts b/packages/server/src/db/schema/web-server-settings.ts index ac63844c5..e04920e26 100644 --- a/packages/server/src/db/schema/web-server-settings.ts +++ b/packages/server/src/db/schema/web-server-settings.ts @@ -1,4 +1,4 @@ -import { relations } from "drizzle-orm"; +import { relations, sql } from "drizzle-orm"; import { boolean, integer, @@ -27,7 +27,10 @@ export const webServerSettings = pgTable("webServerSettings", { sshPrivateKey: text("sshPrivateKey"), enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(true), logCleanupCron: text("logCleanupCron").default("0 0 * * *"), - enableLogManagement: boolean("enableLogManagement").notNull().default(false), + logProviderIds: text("logProviderIds") + .array() + .notNull() + .default(sql`ARRAY[]::text[]`), logManagementOrganizationId: text("logManagementOrganizationId").references( () => organization.id, { onDelete: "set null" }, diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 7b31ade95..5cf969e26 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -36,6 +36,7 @@ export * from "./services/mount"; export * from "./services/mysql"; export * from "./services/network"; export * from "./services/notification"; +export * from "./services/organization"; export * from "./services/overview"; export * from "./services/patch"; export * from "./services/patch-repo"; diff --git a/packages/server/src/services/log-management/providers/elasticsearch.ts b/packages/server/src/services/log-management/providers/elasticsearch.ts index 274c14ec7..61b39ee0c 100644 --- a/packages/server/src/services/log-management/providers/elasticsearch.ts +++ b/packages/server/src/services/log-management/providers/elasticsearch.ts @@ -117,6 +117,7 @@ export const elasticsearchAdapter: LogProviderAdapter = { type: "elasticsearch", inputs: [inputId], endpoints: [normalizeEndpointUrl(config.endpoint ?? "")], + api_version: "v8", ...(typeof index === "string" && index.length > 0 ? { bulk: { index } } : {}), diff --git a/packages/server/src/services/organization.ts b/packages/server/src/services/organization.ts new file mode 100644 index 000000000..114bda287 --- /dev/null +++ b/packages/server/src/services/organization.ts @@ -0,0 +1,26 @@ +import { db } from "@dokploy/server/db"; +import { organization } from "@dokploy/server/db/schema"; +import { findServersWithLogManagementEnabled } from "@dokploy/server/services/server"; +import { removeVectorAgent } from "@dokploy/server/setup/vector-setup"; +import { eq } from "drizzle-orm"; + +const removeVectorAgents = async (organizationId: string) => { + const servers = await findServersWithLogManagementEnabled(organizationId); + await Promise.all( + servers.map((server) => + removeVectorAgent(server.serverId).catch((error) => { + console.error( + `[Vector] Failed to remove the agent on server ${server.serverId} before deleting organization ${organizationId}:`, + error, + ); + }), + ), + ); +}; + +export const deleteOrganization = async (organizationId: string) => { + await removeVectorAgents(organizationId); + return await db + .delete(organization) + .where(eq(organization.id, organizationId)); +}; diff --git a/packages/server/src/services/server.ts b/packages/server/src/services/server.ts index a7c56c5c3..443f8a01c 100644 --- a/packages/server/src/services/server.ts +++ b/packages/server/src/services/server.ts @@ -7,7 +7,7 @@ import { } from "@dokploy/server/db/schema"; import { hasValidLicense } from "@dokploy/server/services/proprietary/license-key"; import { TRPCError } from "@trpc/server"; -import { and, eq } from "drizzle-orm"; +import { and, desc, eq, isNotNull, sql } from "drizzle-orm"; import type { z } from "zod"; export type Server = typeof server.$inferSelect; @@ -93,19 +93,43 @@ export const findServersWithLogManagementEnabled = async ( return await db.query.server.findMany({ where: and( eq(server.organizationId, organizationId), - eq(server.enableLogManagement, true), + sql`array_length(${server.logProviderIds}, 1) > 0`, ), columns: { serverId: true }, }); }; -export const findAllServersWithLogManagementEnabled = async () => { +export const findServersByOrganizationForLogManagement = async ( + organizationId: string, +) => { return await db.query.server.findMany({ - where: eq(server.enableLogManagement, true), - columns: { serverId: true, organizationId: true }, + where: and( + eq(server.organizationId, organizationId), + isNotNull(server.sshKeyId), + eq(server.serverType, "deploy"), + ), + columns: { + serverId: true, + name: true, + ipAddress: true, + logProviderIds: true, + }, + orderBy: [desc(server.createdAt)], }); }; +export const updateServerLogProviders = async ( + serverId: string, + logProviderIds: string[], +) => { + const [updated] = await db + .update(server) + .set({ logProviderIds }) + .where(eq(server.serverId, serverId)) + .returning(); + return updated ?? null; +}; + export const deleteServer = async (serverId: string) => { const currentServer = await db .delete(server) diff --git a/packages/server/src/services/web-server-settings.ts b/packages/server/src/services/web-server-settings.ts index bce77983b..7a2f83cdd 100644 --- a/packages/server/src/services/web-server-settings.ts +++ b/packages/server/src/services/web-server-settings.ts @@ -45,7 +45,7 @@ export const updateWebServerSettings = async ( export const claimWebServerLogManagement = async ( organizationId: string, - enableLogManagement: boolean, + logProviderIds: string[], ) => { const current = await getWebServerSettings(); if (!current) { @@ -55,8 +55,9 @@ export const claimWebServerLogManagement = async ( const [updated] = await db .update(webServerSettings) .set({ - enableLogManagement, - logManagementOrganizationId: enableLogManagement ? organizationId : null, + logProviderIds, + logManagementOrganizationId: + logProviderIds.length > 0 ? organizationId : null, updatedAt: new Date(), }) .where( diff --git a/packages/server/src/setup/vector-setup.ts b/packages/server/src/setup/vector-setup.ts index 55effe56a..d31b3c163 100644 --- a/packages/server/src/setup/vector-setup.ts +++ b/packages/server/src/setup/vector-setup.ts @@ -1,33 +1,24 @@ -import { - chmodSync as fsChmodSync, - mkdirSync, - renameSync, - rmSync, - writeFileSync, -} from "node:fs"; -import { paths } from "@dokploy/server/constants"; -import { db } from "@dokploy/server/db"; -import { dbUrl } from "@dokploy/server/db/constants"; -import { projects } from "@dokploy/server/db/schema"; +import { IS_CLOUD, paths } from "@dokploy/server/constants"; import { findEnabledLogProvidersByOrganization, - hasEnabledLogProvider, type LogProvider, toRuntimeConfig, } from "@dokploy/server/services/log-management/service"; -import { findServerById } from "@dokploy/server/services/server"; +import { + findServerById, + findServersByOrganizationForLogManagement, +} from "@dokploy/server/services/server"; import { getWebServerSettings } from "@dokploy/server/services/web-server-settings"; -import { pullImage, pullRemoteImage } from "@dokploy/server/utils/docker/utils"; +import { encodeBase64 } from "@dokploy/server/utils/docker/utils"; import { ExecError } from "@dokploy/server/utils/process/ExecError"; import { execAsync, execAsyncRemote, - writeFileRemote, } from "@dokploy/server/utils/process/execAsync"; import { getRemoteDocker } from "@dokploy/server/utils/servers/remote-docker"; import type { CreateServiceOptions } from "dockerode"; -import { eq } from "drizzle-orm"; -import postgres from "postgres"; +import { nanoid } from "nanoid"; +import { quote } from "shell-quote"; import { stringify } from "yaml"; import { getLogProviderAdapter } from "../services/log-management/providers/registry"; import type { @@ -41,124 +32,17 @@ const VECTOR_CONFIG_CONTAINER_DIR = "/etc/vector"; const VECTOR_CONFIG_CONTAINER_PATH = `${VECTOR_CONFIG_CONTAINER_DIR}/vector.yaml`; const VECTOR_DATA_DIR_CONTAINER = "/var/lib/vector"; -interface AppNameLookupEntry { - projectId: string; - projectName: string; - environmentId: string; - environmentName: string; - applicationId: string; - applicationName: string; -} - -const escapeVrlString = (value: string): string => - value - .replace(/\\/g, "\\\\") - .replace(/"/g, '\\"') - // biome-ignore lint/suspicious/noControlCharactersInRegex: replacing them is the point - .replace(/[\u0000-\u001f\u007f]/g, " "); - -const buildAppNameLookup = async ( - organizationId: string, -): Promise> => { - const projectRows = await db.query.projects.findMany({ - where: eq(projects.organizationId, organizationId), - columns: { projectId: true, name: true }, - with: { - environments: { - columns: { environmentId: true, name: true }, - with: { - applications: { - columns: { applicationId: true, appName: true, name: true }, - }, - compose: { - columns: { composeId: true, appName: true, name: true }, - }, - }, - }, - }, - }); - - const lookup: Record = {}; - for (const project of projectRows) { - for (const environment of project.environments) { - for (const application of environment.applications) { - lookup[application.appName] = { - projectId: project.projectId, - projectName: project.name, - environmentId: environment.environmentId, - environmentName: environment.name, - applicationId: application.applicationId, - applicationName: application.name, - }; - } - for (const composeService of environment.compose) { - lookup[composeService.appName] = { - projectId: project.projectId, - projectName: project.name, - environmentId: environment.environmentId, - environmentName: environment.name, - applicationId: composeService.composeId, - applicationName: composeService.name, - }; - } - } - } - return lookup; -}; - -const buildScopeTransformSource = ( - organizationId: string, - lookup: Record, -): string => { - const lines: string[] = [ - `.dokploy_organization = "${escapeVrlString(organizationId)}"`, - '.dokploy_project = ""', - '.dokploy_project_id = ""', - '.dokploy_environment = ""', - '.dokploy_environment_id = ""', - '.dokploy_application = ""', - '.dokploy_application_id = ""', - ]; - - const entries = Object.entries(lookup); - if (entries.length === 0) { - return lines.join("\n"); - } - - lines.push('app_name = .label."com.docker.compose.project"'); - lines.push("if app_name == null {"); - lines.push(' app_name = .label."com.docker.stack.namespace"'); - lines.push("}"); - lines.push("if app_name == null {"); - lines.push(' app_name = .label."com.docker.swarm.service.name"'); - lines.push("}"); - lines.push("if app_name != null {"); - entries.forEach(([appName, entry], index) => { - const branch = index === 0 ? " if" : " } else if"; - lines.push(`${branch} app_name == "${escapeVrlString(appName)}" {`); - lines.push( - ` .dokploy_project = "${escapeVrlString(entry.projectName)}"`, - ); - lines.push( - ` .dokploy_project_id = "${escapeVrlString(entry.projectId)}"`, - ); - lines.push( - ` .dokploy_environment = "${escapeVrlString(entry.environmentName)}"`, - ); - lines.push( - ` .dokploy_environment_id = "${escapeVrlString(entry.environmentId)}"`, - ); - lines.push( - ` .dokploy_application = "${escapeVrlString(entry.applicationName)}"`, - ); - lines.push( - ` .dokploy_application_id = "${escapeVrlString(entry.applicationId)}"`, - ); - }); - lines.push(" }"); - lines.push("}"); - return lines.join("\n"); -}; +const buildScopeTransformSource = (): string => + [ + '.dokploy_organization = .label."dokploy.organization.id" || ""', + '.dokploy_project = .label."dokploy.project" || ""', + '.dokploy_project_id = .label."dokploy.project.id" || ""', + '.dokploy_environment = .label."dokploy.environment" || ""', + '.dokploy_environment_id = .label."dokploy.environment.id" || ""', + '.dokploy_application = .label."dokploy.application" || ""', + '.dokploy_application_id = .label."dokploy.application.id" || ""', + '.dokploy_service = .label."dokploy.service" || ""', + ].join("\n"); const buildSinksAndTransforms = ( providers: Array, @@ -206,28 +90,22 @@ const buildSinksAndTransforms = ( return { sinks, transforms }; }; -export interface VectorOrgData { - providers: Array; - lookup: Record; -} - -export const loadVectorOrgData = async ( +const loadEnabledLogProviders = async ( organizationId: string, -): Promise => { - const [providers, lookup] = await Promise.all([ - findEnabledLogProvidersByOrganization(organizationId), - buildAppNameLookup(organizationId), - ]); - return { providers, lookup }; + logProviderIds?: string[], +): Promise> => { + const providers = await findEnabledLogProvidersByOrganization(organizationId); + return logProviderIds + ? providers.filter((provider) => + logProviderIds.includes(provider.logProviderId), + ) + : providers; }; export const buildVectorConfigYaml = async ( - organizationId: string, - preloaded?: VectorOrgData, + providers: Array, options?: { dropUnmatched?: boolean }, ) => { - const { providers, lookup } = - preloaded ?? (await loadVectorOrgData(organizationId)); const baseTransformId = options?.dropUnmatched ? "dokploy_scope_local_only" : "dokploy_scope"; @@ -248,7 +126,7 @@ export const buildVectorConfigYaml = async ( dokploy_scope: { type: "remap", inputs: ["docker_logs_source"], - source: buildScopeTransformSource(organizationId, lookup), + source: buildScopeTransformSource(), }, ...(options?.dropUnmatched ? { @@ -290,138 +168,89 @@ export const redactSecrets = (text: string, secrets: string[]): string => { return redacted; }; -const VECTOR_CONFIG_LOCK_NAMESPACE = 87_234_501; - -const hashServerIdToInt32 = (serverId: string): number => { - let hash = 0; - for (let i = 0; i < serverId.length; i++) { - hash = (Math.imul(31, hash) + serverId.charCodeAt(i)) | 0; - } - return hash; -}; - -let lockPool: ReturnType | undefined; -const getLockPool = () => { - if (!lockPool) { - lockPool = postgres(dbUrl, { max: 10 }); - } - return lockPool; -}; - -const LOCK_RETRY_ATTEMPTS = 3; -const LOCK_RETRY_DELAY_MS = 1000; - -const configWriteLocks = new Map>(); - -export const withConfigWriteLock = async ( - serverId: string, - fn: () => Promise, -): Promise => { - const previous = configWriteLocks.get(serverId) ?? Promise.resolve(); - let release: () => void = () => {}; - const current = new Promise((resolve) => { - release = resolve; - }); - configWriteLocks.set( - serverId, - previous.then(() => current), - ); - await previous; - try { - return await runWithCrossProcessLock(serverId, fn); - } finally { - release(); - } -}; - -const runWithCrossProcessLock = async ( - serverId: string, - fn: () => Promise, -): Promise => { - const key1 = VECTOR_CONFIG_LOCK_NAMESPACE; - const key2 = hashServerIdToInt32(serverId); - for (let attempt = 1; attempt <= LOCK_RETRY_ATTEMPTS; attempt++) { - const reserved = await getLockPool().reserve(); - try { - const rows = - await reserved`select pg_try_advisory_lock(${key1}, ${key2}) as locked`; - if (rows[0]?.locked) { - try { - return await fn(); - } finally { - await reserved`select pg_advisory_unlock(${key1}, ${key2})`; - } - } - } finally { - reserved.release(); - } - if (attempt < LOCK_RETRY_ATTEMPTS) { - await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_DELAY_MS)); - } - } - throw new Error( - `Vector config sync for server ${serverId} is already in progress on another Dokploy instance, skipped`, - ); -}; - -export const syncVectorConfig = async ({ - serverId, - preloaded, -}: { - serverId: string; - preloaded?: VectorOrgData; -}) => - withConfigWriteLock(serverId, async () => { +const getServerLogProviderIds = async ( + serverId?: string, +): Promise => { + if (serverId) { const server = await findServerById(serverId); - const { VECTOR_PATH } = paths(true); - const configPath = `${VECTOR_PATH}/vector.yaml`; - const candidatePath = `${VECTOR_PATH}/vector.yaml.candidate`; - const orgData = - preloaded ?? (await loadVectorOrgData(server.organizationId)); - const yamlStr = await buildVectorConfigYaml(server.organizationId, orgData); + return server.logProviderIds ?? []; + } + const settings = await getWebServerSettings(); + return settings?.logProviderIds ?? []; +}; - await execAsyncRemote(serverId, `mkdir -p ${VECTOR_PATH}/data`); - await writeFileRemote(serverId, candidatePath, yamlStr); - await execAsyncRemote( - serverId, - `chmod 600 ${candidatePath} && chmod 700 ${VECTOR_PATH} && chmod 700 ${VECTOR_PATH}/data`, - ); - try { - await execAsyncRemote( - serverId, - `docker run --rm -v /var/run/docker.sock:/var/run/docker.sock:ro -v ${candidatePath}:/etc/vector/vector.yaml:ro ${VECTOR_IMAGE} validate --skip-healthchecks /etc/vector/vector.yaml`, - ); - } catch (error) { - const detail = - error instanceof ExecError - ? error.stderr || error.stdout || error.message - : error instanceof Error - ? error.message - : String(error); - const sanitizedDetail = redactSecrets( - detail, - collectSecretValues(orgData.providers), - ); - await execAsyncRemote(serverId, `rm -f ${candidatePath}`).catch( - (cleanupError) => { - console.error( - `[Vector] Failed to remove invalid config candidate ${candidatePath} on server ${serverId}:`, - cleanupError, - ); - }, - ); - throw new Error( - `Generated Vector config failed validation, not applying it: ${sanitizedDetail}`, - ); - } - await execAsyncRemote(serverId, `mv ${candidatePath} ${configPath}`); +const syncVectorConfig = async ( + organizationId: string, + serverId?: string, + logProviderIds?: string[], +) => { + const { VECTOR_PATH } = paths(!!serverId); + const configPath = `${VECTOR_PATH}/vector.yaml`; + const candidatePath = `${VECTOR_PATH}/vector.yaml.candidate.${nanoid(10)}`; + const ids = logProviderIds ?? (await getServerLogProviderIds(serverId)); + const providers = await loadEnabledLogProviders(organizationId, ids); + const yamlStr = await buildVectorConfigYaml(providers, { + dropUnmatched: !serverId, }); -export const buildServiceSettings = ( - vectorPath: string, -): CreateServiceOptions => { - const VECTOR_PATH = vectorPath; - return { + const writeCommand = `umask 077 && mkdir -p ${quote([`${VECTOR_PATH}/data`])} && chmod 700 ${quote([VECTOR_PATH])} ${quote([`${VECTOR_PATH}/data`])} && echo "${encodeBase64(yamlStr)}" | base64 -d > ${quote([candidatePath])}`; + if (serverId) { + await execAsyncRemote(serverId, writeCommand); + } else { + await execAsync(writeCommand); + } + + const validateCommand = `docker run --rm -v /var/run/docker.sock:/var/run/docker.sock:ro -v ${quote([`${candidatePath}:/etc/vector/vector.yaml:ro`])} ${VECTOR_IMAGE} validate --skip-healthchecks /etc/vector/vector.yaml`; + try { + if (serverId) { + await execAsyncRemote(serverId, validateCommand); + } else { + await execAsync(validateCommand); + } + } catch (error) { + const detail = + error instanceof ExecError + ? error.stderr || error.stdout || error.message + : error instanceof Error + ? error.message + : String(error); + const sanitizedDetail = redactSecrets( + detail, + collectSecretValues(providers), + ); + const cleanupCommand = `rm -f ${quote([candidatePath])}`; + try { + if (serverId) { + await execAsyncRemote(serverId, cleanupCommand); + } else { + await execAsync(cleanupCommand); + } + } catch (cleanupError) { + console.error( + `[Vector] Failed to remove invalid config candidate ${candidatePath}${ + serverId ? ` on server ${serverId}` : "" + }:`, + cleanupError, + ); + } + throw new Error( + `Generated Vector config failed validation, not applying it: ${sanitizedDetail}`, + ); + } + + const applyCommand = `mv ${quote([candidatePath])} ${quote([configPath])}`; + if (serverId) { + await execAsyncRemote(serverId, applyCommand); + } else { + await execAsync(applyCommand); + } +}; + +const deployVectorService = async (serverId?: string) => { + const { VECTOR_PATH } = paths(!!serverId); + const docker = await getRemoteDocker(serverId); + + const settings: CreateServiceOptions = { Name: VECTOR_SERVICE_NAME, TaskTemplate: { ContainerSpec: { @@ -456,40 +285,10 @@ export const buildServiceSettings = ( }, }, }; -}; -export const stripImageDigest = (image: string): string => - image.split("@")[0] ?? image; - -export const vectorServiceSpecUnchanged = ( - inspect: { Spec: { TaskTemplate: any; Mode?: unknown } }, - settings: CreateServiceOptions, -): boolean => { - const desiredTaskTemplate = settings.TaskTemplate as any; - const existing = inspect.Spec.TaskTemplate?.ContainerSpec ?? {}; - const desired = desiredTaskTemplate?.ContainerSpec ?? {}; - return ( - stripImageDigest(existing.Image ?? "") === - stripImageDigest(desired.Image ?? "") && - JSON.stringify(existing.Args ?? []) === - JSON.stringify(desired.Args ?? []) && - JSON.stringify(existing.Mounts ?? []) === - JSON.stringify(desired.Mounts ?? []) && - JSON.stringify(inspect.Spec.Mode ?? {}) === - JSON.stringify(settings.Mode ?? {}) - ); -}; - -const deployVectorService = async ( - docker: Awaited>, - settings: CreateServiceOptions, -) => { try { const service = docker.getService(VECTOR_SERVICE_NAME); const inspect = await service.inspect(); - if (vectorServiceSpecUnchanged(inspect, settings)) { - return; - } await service.update({ version: Number.parseInt(inspect.Version.Index, 10), ...settings, @@ -498,130 +297,31 @@ const deployVectorService = async ( ForceUpdate: (inspect.Spec.TaskTemplate.ForceUpdate ?? 0) + 1, }, }); - } catch (error: any) { - if (error?.statusCode !== 404) { - throw error; - } - await docker.createService(settings); - } -}; - -export const setupVectorAgent = async ({ - serverId, - preloaded, -}: { - serverId: string; - preloaded?: VectorOrgData; -}) => { - await syncVectorConfig({ serverId, preloaded }); - const { VECTOR_PATH } = paths(true); - - await pullRemoteImage(VECTOR_IMAGE, serverId); - const docker = await getRemoteDocker(serverId); - await deployVectorService(docker, buildServiceSettings(VECTOR_PATH)); -}; - -export const removeVectorAgent = async ({ serverId }: { serverId: string }) => { - const server = await findServerById(serverId); - if (!server.sshKeyId) { - throw new Error(`No SSH key configured for server ${serverId}`); - } - const docker = await getRemoteDocker(serverId); - try { - await docker.getService(VECTOR_SERVICE_NAME).remove(); - } catch (error: any) { - if (error?.statusCode !== 404) { - throw error; - } - } - const { VECTOR_PATH } = paths(true); - await execAsyncRemote(serverId, `rm -rf ${VECTOR_PATH}`); -}; - -export const syncVectorAgent = async ({ - serverId, - preloaded, -}: { - serverId: string; - preloaded?: VectorOrgData; -}): Promise<{ installed: boolean }> => { - const server = await findServerById(serverId); - const hasProvider = preloaded - ? preloaded.providers.length > 0 - : await hasEnabledLogProvider(server.organizationId); - const shouldRun = server.enableLogManagement && hasProvider; - - if (shouldRun) { - await setupVectorAgent({ serverId, preloaded }); - } else { - await removeVectorAgent({ serverId }); - } - - return { installed: shouldRun }; -}; - -export const syncWebVectorConfig = async ( - organizationId: string, - preloaded?: VectorOrgData, -) => - withConfigWriteLock("web", async () => { - const { VECTOR_PATH } = paths(); - const configPath = `${VECTOR_PATH}/vector.yaml`; - const candidatePath = `${VECTOR_PATH}/vector.yaml.candidate`; - const orgData = preloaded ?? (await loadVectorOrgData(organizationId)); - const yamlStr = await buildVectorConfigYaml(organizationId, orgData, { - dropUnmatched: true, - }); - - mkdirSync(`${VECTOR_PATH}/data`, { recursive: true }); - writeFileSync(candidatePath, yamlStr, "utf8"); - fsChmodSync(candidatePath, 0o600); - fsChmodSync(VECTOR_PATH, 0o700); - fsChmodSync(`${VECTOR_PATH}/data`, 0o700); + console.log("Vector Updated ✅"); + } catch (_) { try { - await execAsync( - `docker run --rm -v /var/run/docker.sock:/var/run/docker.sock:ro -v ${candidatePath}:/etc/vector/vector.yaml:ro ${VECTOR_IMAGE} validate --skip-healthchecks /etc/vector/vector.yaml`, - ); - } catch (error) { - const detail = - error instanceof ExecError - ? error.stderr || error.stdout || error.message - : error instanceof Error - ? error.message - : String(error); - const sanitizedDetail = redactSecrets( - detail, - collectSecretValues(orgData.providers), - ); - try { - rmSync(candidatePath, { force: true }); - } catch (cleanupError) { - console.error( - `[Vector] Failed to remove invalid local config candidate ${candidatePath}:`, - cleanupError, - ); + await docker.createService(settings); + console.log("Vector Started ✅"); + } catch (error: any) { + if (error?.statusCode !== 409) { + throw error; } - throw new Error( - `Generated Vector config failed validation, not applying it: ${sanitizedDetail}`, - ); + console.log("Vector service already exists, continuing..."); } - renameSync(candidatePath, configPath); - }); - -export const setupWebVectorAgent = async ( - organizationId: string, - preloaded?: VectorOrgData, -) => { - await syncWebVectorConfig(organizationId, preloaded); - const { VECTOR_PATH } = paths(); - - await pullImage(VECTOR_IMAGE); - const docker = await getRemoteDocker(); - await deployVectorService(docker, buildServiceSettings(VECTOR_PATH)); + } }; -export const removeWebVectorAgent = async () => { - const docker = await getRemoteDocker(); +export const setupVectorAgent = async ( + organizationId: string, + serverId?: string, + logProviderIds?: string[], +) => { + await syncVectorConfig(organizationId, serverId, logProviderIds); + await deployVectorService(serverId); +}; + +export const removeVectorAgent = async (serverId?: string) => { + const docker = await getRemoteDocker(serverId); try { await docker.getService(VECTOR_SERVICE_NAME).remove(); } catch (error: any) { @@ -629,28 +329,82 @@ export const removeWebVectorAgent = async () => { throw error; } } - const { VECTOR_PATH } = paths(); - rmSync(VECTOR_PATH, { recursive: true, force: true }); -}; - -export const syncWebVectorAgent = async ( - preloaded?: VectorOrgData, -): Promise<{ installed: boolean }> => { - const settings = await getWebServerSettings(); - const organizationId = settings?.logManagementOrganizationId ?? null; - const hasProvider = organizationId - ? preloaded - ? preloaded.providers.length > 0 - : await hasEnabledLogProvider(organizationId) - : false; - const shouldRun = - !!settings?.enableLogManagement && !!organizationId && hasProvider; - - if (shouldRun && organizationId) { - await setupWebVectorAgent(organizationId, preloaded); + const { VECTOR_PATH } = paths(!!serverId); + const cleanupCommand = `rm -rf ${quote([VECTOR_PATH])}`; + if (serverId) { + await execAsyncRemote(serverId, cleanupCommand); } else { - await removeWebVectorAgent(); + await execAsync(cleanupCommand); } - - return { installed: shouldRun }; +}; + +const isVectorRunning = async (serverId?: string): Promise => { + const docker = await getRemoteDocker(serverId); + try { + await docker.getService(VECTOR_SERVICE_NAME).inspect(); + return true; + } catch { + return false; + } +}; + +const VECTOR_CHECK_TIMEOUT_MS = 5000; + +const vectorStatus = async ( + serverId: string | null, +): Promise<"running" | "stopped" | "unknown"> => { + try { + const running = await Promise.race([ + isVectorRunning(serverId ?? undefined), + new Promise((_, reject) => + setTimeout(() => reject(new Error("timeout")), VECTOR_CHECK_TIMEOUT_MS), + ), + ]); + return running ? "running" : "stopped"; + } catch { + return "unknown"; + } +}; + +export const getLogManagementServerStatus = async (organizationId: string) => { + const [servers, settings] = await Promise.all([ + findServersByOrganizationForLogManagement(organizationId), + IS_CLOUD ? Promise.resolve(null) : getWebServerSettings(), + ]); + + const webOwnsThisOrg = + !!settings && + (settings.logManagementOrganizationId === null || + settings.logManagementOrganizationId === organizationId); + + const targets: Array<{ + serverId: string | null; + name: string; + ipAddress: string | null; + logProviderIds: string[]; + }> = [ + ...(settings && webOwnsThisOrg + ? [ + { + serverId: null, + name: "Dokploy Server (local)", + ipAddress: null, + logProviderIds: settings.logProviderIds ?? [], + }, + ] + : []), + ...servers.map((s) => ({ + serverId: s.serverId, + name: s.name, + ipAddress: s.ipAddress, + logProviderIds: s.logProviderIds ?? [], + })), + ]; + + return Promise.all( + targets.map(async (target) => ({ + ...target, + status: await vectorStatus(target.serverId), + })), + ); }; diff --git a/packages/server/src/utils/builders/index.ts b/packages/server/src/utils/builders/index.ts index 6c8448000..e21203df0 100644 --- a/packages/server/src/utils/builders/index.ts +++ b/packages/server/src/utils/builders/index.ts @@ -3,6 +3,7 @@ import { findRegistryByIdWithCredentials } from "@dokploy/server/services/regist import type { InferResultType } from "@dokploy/server/types/with"; import type { CreateServiceOptions } from "dockerode"; import { getRegistryTag, uploadImageRemoteCommand } from "../cluster/upload"; +import { buildDokployLabels } from "../docker/dokploy-labels"; import { calculateResources, generateBindMounts, @@ -150,7 +151,18 @@ export const mechanizeDockerContainer = async ( Args: args, }), ...(Ulimits && { Ulimits }), - Labels, + Labels: { + ...Labels, + ...buildDokployLabels({ + organizationId: application.environment.project.organizationId, + projectId: application.environment.projectId, + projectName: application.environment.project.name, + environmentId: application.environmentId, + environmentName: application.environment.name, + applicationId: application.applicationId, + applicationName: application.name, + }), + }, }, Networks: resolvedNetworks, RestartPolicy, diff --git a/packages/server/src/utils/docker/dokploy-labels.ts b/packages/server/src/utils/docker/dokploy-labels.ts new file mode 100644 index 000000000..bcc93cdb4 --- /dev/null +++ b/packages/server/src/utils/docker/dokploy-labels.ts @@ -0,0 +1,34 @@ +export interface DokployResourceMetadata { + organizationId: string; + projectId: string; + projectName: string; + environmentId: string; + environmentName: string; + applicationId: string; + applicationName: string; + serviceName?: string; +} + +export const DOKPLOY_LABEL_PREFIX = "dokploy"; + +export const buildDokployLabels = ( + metadata: DokployResourceMetadata, +): Record => ({ + [`${DOKPLOY_LABEL_PREFIX}.organization.id`]: metadata.organizationId, + [`${DOKPLOY_LABEL_PREFIX}.project.id`]: metadata.projectId, + [`${DOKPLOY_LABEL_PREFIX}.project`]: metadata.projectName, + [`${DOKPLOY_LABEL_PREFIX}.environment.id`]: metadata.environmentId, + [`${DOKPLOY_LABEL_PREFIX}.environment`]: metadata.environmentName, + [`${DOKPLOY_LABEL_PREFIX}.application.id`]: metadata.applicationId, + [`${DOKPLOY_LABEL_PREFIX}.application`]: metadata.applicationName, + ...(metadata.serviceName + ? { [`${DOKPLOY_LABEL_PREFIX}.service`]: metadata.serviceName } + : {}), +}); + +export const dokployLabelsAsList = ( + metadata: DokployResourceMetadata, +): string[] => + Object.entries(buildDokployLabels(metadata)).map( + ([key, value]) => `${key}=${value}`, + ); diff --git a/packages/server/src/utils/docker/domain.ts b/packages/server/src/utils/docker/domain.ts index 0d83d4a48..8c94e9494 100644 --- a/packages/server/src/utils/docker/domain.ts +++ b/packages/server/src/utils/docker/domain.ts @@ -17,6 +17,7 @@ import { cloneGitlabRepository } from "../providers/gitlab"; import { getCreateComposeFileCommand } from "../providers/raw"; import { randomizeDeployableSpecificationFile } from "./collision"; import { randomizeSpecificationFile } from "./compose"; +import { buildDokployLabels } from "./dokploy-labels"; import type { ComposeSpecification, DefinitionsService, @@ -111,7 +112,7 @@ export const readComposeFile = async (compose: Compose) => { }; export const writeDomainsToCompose = async ( - compose: Compose, + compose: ComposeWithMetadata, domains: Domain[], ) => { try { @@ -196,8 +197,66 @@ const removeDomainLabels = ( return labels; }; +type ComposeWithMetadata = Compose & { + environment?: { + environmentId: string; + name: string; + projectId: string; + project?: { name: string; organizationId: string }; + }; +}; + +const applyDokployLabelsToCompose = ( + result: ComposeSpecification, + compose: ComposeWithMetadata, +) => { + const { environment } = compose; + if (!environment?.project) return; + + for (const [serviceName, service] of Object.entries(result.services ?? {})) { + if (!service) continue; + const dokployLabels = buildDokployLabels({ + organizationId: environment.project.organizationId, + projectId: environment.projectId, + projectName: environment.project.name, + environmentId: environment.environmentId, + environmentName: environment.name, + applicationId: compose.composeId, + applicationName: compose.name, + serviceName, + }); + + if (compose.composeType === "docker-compose") { + service.labels = mergeDokployLabels(service.labels, dokployLabels); + continue; + } + if (!service.deploy) { + service.deploy = {}; + } + service.deploy.labels = mergeDokployLabels( + service.deploy.labels, + dokployLabels, + ); + } +}; + +const mergeDokployLabels = ( + current: DefinitionsService["labels"], + dokployLabels: Record, +): DefinitionsService["labels"] => { + if (current && !Array.isArray(current)) { + return { ...current, ...dokployLabels }; + } + const entries = Object.entries(dokployLabels); + const keys = new Set(entries.map(([key]) => key)); + const kept = (current ?? []).filter( + (label) => !keys.has(label.slice(0, label.indexOf("="))), + ); + return [...kept, ...entries.map(([key, value]) => `${key}=${value}`)]; +}; + export const addDomainToCompose = async ( - compose: Compose, + compose: ComposeWithMetadata, domains: Domain[], ) => { const { appName } = compose; @@ -326,6 +385,8 @@ export const addDomainToCompose = async ( } } + applyDokployLabelsToCompose(result, compose); + const injectedNetworkNames = await applyServiceNetworks(result, compose); if (!compose.isolatedDeployment) {