mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
559 lines
15 KiB
TypeScript
559 lines
15 KiB
TypeScript
import { relations } from "drizzle-orm";
|
|
import {
|
|
boolean,
|
|
integer,
|
|
json,
|
|
pgEnum,
|
|
pgTable,
|
|
text,
|
|
} from "drizzle-orm/pg-core";
|
|
import { createInsertSchema } from "drizzle-zod";
|
|
import { nanoid } from "nanoid";
|
|
import { z } from "zod";
|
|
import { bitbucket } from "./bitbucket";
|
|
import { deployments } from "./deployment";
|
|
import { domains } from "./domain";
|
|
import { github } from "./github";
|
|
import { gitlab } from "./gitlab";
|
|
import { gitea } from "./gitea";
|
|
import { mounts } from "./mount";
|
|
import { ports } from "./port";
|
|
import { previewDeployments } from "./preview-deployments";
|
|
import { projects } from "./project";
|
|
import { redirects } from "./redirects";
|
|
import { registry } from "./registry";
|
|
import { security } from "./security";
|
|
import { server } from "./server";
|
|
import { applicationStatus, certificateType } from "./shared";
|
|
import { sshKeys } from "./ssh-key";
|
|
import { generateAppName } from "./utils";
|
|
|
|
export const sourceType = pgEnum("sourceType", [
|
|
"docker",
|
|
"git",
|
|
"github",
|
|
"gitlab",
|
|
"bitbucket",
|
|
"gitea",
|
|
"drop",
|
|
]);
|
|
|
|
export const buildType = pgEnum("buildType", [
|
|
"dockerfile",
|
|
"heroku_buildpacks",
|
|
"paketo_buildpacks",
|
|
"nixpacks",
|
|
"static",
|
|
"railpack",
|
|
]);
|
|
|
|
export interface HealthCheckSwarm {
|
|
Test?: string[] | undefined;
|
|
Interval?: number | undefined;
|
|
Timeout?: number | undefined;
|
|
StartPeriod?: number | undefined;
|
|
Retries?: number | undefined;
|
|
}
|
|
|
|
export interface RestartPolicySwarm {
|
|
Condition?: string | undefined;
|
|
Delay?: number | undefined;
|
|
MaxAttempts?: number | undefined;
|
|
Window?: number | undefined;
|
|
}
|
|
|
|
export interface PlacementSwarm {
|
|
Constraints?: string[] | undefined;
|
|
Preferences?: Array<{ Spread: { SpreadDescriptor: string } }> | undefined;
|
|
MaxReplicas?: number | undefined;
|
|
Platforms?:
|
|
| Array<{
|
|
Architecture: string;
|
|
OS: string;
|
|
}>
|
|
| undefined;
|
|
}
|
|
|
|
export interface UpdateConfigSwarm {
|
|
Parallelism: number;
|
|
Delay?: number | undefined;
|
|
FailureAction?: string | undefined;
|
|
Monitor?: number | undefined;
|
|
MaxFailureRatio?: number | undefined;
|
|
Order: string;
|
|
}
|
|
|
|
export interface ServiceModeSwarm {
|
|
Replicated?: { Replicas?: number | undefined } | undefined;
|
|
Global?: {} | undefined;
|
|
ReplicatedJob?:
|
|
| {
|
|
MaxConcurrent?: number | undefined;
|
|
TotalCompletions?: number | undefined;
|
|
}
|
|
| undefined;
|
|
GlobalJob?: {} | undefined;
|
|
}
|
|
|
|
export interface NetworkSwarm {
|
|
Target?: string | undefined;
|
|
Aliases?: string[] | undefined;
|
|
DriverOpts?: { [key: string]: string } | undefined;
|
|
}
|
|
|
|
export interface LabelsSwarm {
|
|
[name: string]: string;
|
|
}
|
|
|
|
export const applications = pgTable("application", {
|
|
applicationId: text("applicationId")
|
|
.notNull()
|
|
.primaryKey()
|
|
.$defaultFn(() => nanoid()),
|
|
name: text("name").notNull(),
|
|
appName: text("appName")
|
|
.notNull()
|
|
.$defaultFn(() => generateAppName("app"))
|
|
.unique(),
|
|
description: text("description"),
|
|
env: text("env"),
|
|
previewEnv: text("previewEnv"),
|
|
watchPaths: text("watchPaths").array(),
|
|
previewBuildArgs: text("previewBuildArgs"),
|
|
previewWildcard: text("previewWildcard"),
|
|
previewPort: integer("previewPort").default(3000),
|
|
previewHttps: boolean("previewHttps").notNull().default(false),
|
|
previewPath: text("previewPath").default("/"),
|
|
previewCertificateType: certificateType("certificateType")
|
|
.notNull()
|
|
.default("none"),
|
|
previewCustomCertResolver: text("previewCustomCertResolver"),
|
|
previewLimit: integer("previewLimit").default(3),
|
|
isPreviewDeploymentsActive: boolean("isPreviewDeploymentsActive").default(
|
|
false,
|
|
),
|
|
buildArgs: text("buildArgs"),
|
|
memoryReservation: text("memoryReservation"),
|
|
memoryLimit: text("memoryLimit"),
|
|
cpuReservation: text("cpuReservation"),
|
|
cpuLimit: text("cpuLimit"),
|
|
title: text("title"),
|
|
enabled: boolean("enabled"),
|
|
subtitle: text("subtitle"),
|
|
command: text("command"),
|
|
refreshToken: text("refreshToken").$defaultFn(() => nanoid()),
|
|
sourceType: sourceType("sourceType").notNull().default("github"),
|
|
cleanCache: boolean("cleanCache").default(false),
|
|
// Github
|
|
repository: text("repository"),
|
|
owner: text("owner"),
|
|
branch: text("branch"),
|
|
buildPath: text("buildPath").default("/"),
|
|
autoDeploy: boolean("autoDeploy").$defaultFn(() => true),
|
|
// Gitlab
|
|
gitlabProjectId: integer("gitlabProjectId"),
|
|
gitlabRepository: text("gitlabRepository"),
|
|
gitlabOwner: text("gitlabOwner"),
|
|
gitlabBranch: text("gitlabBranch"),
|
|
gitlabBuildPath: text("gitlabBuildPath").default("/"),
|
|
gitlabPathNamespace: text("gitlabPathNamespace"),
|
|
// Gitea
|
|
giteaProjectId: integer("giteaProjectId"),
|
|
giteaRepository: text("giteaRepository"),
|
|
giteaOwner: text("giteaOwner"),
|
|
giteaBranch: text("giteaBranch"),
|
|
giteaBuildPath: text("giteaBuildPath").default("/"),
|
|
giteaPathNamespace: text("giteaPathNamespace"),
|
|
// Bitbucket
|
|
bitbucketRepository: text("bitbucketRepository"),
|
|
bitbucketOwner: text("bitbucketOwner"),
|
|
bitbucketBranch: text("bitbucketBranch"),
|
|
bitbucketBuildPath: text("bitbucketBuildPath").default("/"),
|
|
// Docker
|
|
username: text("username"),
|
|
password: text("password"),
|
|
dockerImage: text("dockerImage"),
|
|
registryUrl: text("registryUrl"),
|
|
// Git
|
|
customGitUrl: text("customGitUrl"),
|
|
customGitBranch: text("customGitBranch"),
|
|
customGitBuildPath: text("customGitBuildPath"),
|
|
customGitSSHKeyId: text("customGitSSHKeyId").references(
|
|
() => sshKeys.sshKeyId,
|
|
{
|
|
onDelete: "set null",
|
|
},
|
|
),
|
|
dockerfile: text("dockerfile"),
|
|
dockerContextPath: text("dockerContextPath"),
|
|
dockerBuildStage: text("dockerBuildStage"),
|
|
// Drop
|
|
dropBuildPath: text("dropBuildPath"),
|
|
// Docker swarm json
|
|
healthCheckSwarm: json("healthCheckSwarm").$type<HealthCheckSwarm>(),
|
|
restartPolicySwarm: json("restartPolicySwarm").$type<RestartPolicySwarm>(),
|
|
placementSwarm: json("placementSwarm").$type<PlacementSwarm>(),
|
|
updateConfigSwarm: json("updateConfigSwarm").$type<UpdateConfigSwarm>(),
|
|
rollbackConfigSwarm: json("rollbackConfigSwarm").$type<UpdateConfigSwarm>(),
|
|
modeSwarm: json("modeSwarm").$type<ServiceModeSwarm>(),
|
|
labelsSwarm: json("labelsSwarm").$type<LabelsSwarm>(),
|
|
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
|
//
|
|
replicas: integer("replicas").default(1).notNull(),
|
|
applicationStatus: applicationStatus("applicationStatus")
|
|
.notNull()
|
|
.default("idle"),
|
|
buildType: buildType("buildType").notNull().default("nixpacks"),
|
|
herokuVersion: text("herokuVersion").default("24"),
|
|
publishDirectory: text("publishDirectory"),
|
|
createdAt: text("createdAt")
|
|
.notNull()
|
|
.$defaultFn(() => new Date().toISOString()),
|
|
registryId: text("registryId").references(() => registry.registryId, {
|
|
onDelete: "set null",
|
|
}),
|
|
projectId: text("projectId")
|
|
.notNull()
|
|
.references(() => projects.projectId, { onDelete: "cascade" }),
|
|
githubId: text("githubId").references(() => github.githubId, {
|
|
onDelete: "set null",
|
|
}),
|
|
gitlabId: text("gitlabId").references(() => gitlab.gitlabId, {
|
|
onDelete: "set null",
|
|
}),
|
|
giteaId: text("giteaId").references(() => gitea.giteaId, {
|
|
onDelete: "set null",
|
|
}),
|
|
bitbucketId: text("bitbucketId").references(() => bitbucket.bitbucketId, {
|
|
onDelete: "set null",
|
|
}),
|
|
serverId: text("serverId").references(() => server.serverId, {
|
|
onDelete: "cascade",
|
|
}),
|
|
});
|
|
|
|
export const applicationsRelations = relations(
|
|
applications,
|
|
({ one, many }) => ({
|
|
project: one(projects, {
|
|
fields: [applications.projectId],
|
|
references: [projects.projectId],
|
|
}),
|
|
deployments: many(deployments),
|
|
customGitSSHKey: one(sshKeys, {
|
|
fields: [applications.customGitSSHKeyId],
|
|
references: [sshKeys.sshKeyId],
|
|
}),
|
|
domains: many(domains),
|
|
mounts: many(mounts),
|
|
redirects: many(redirects),
|
|
security: many(security),
|
|
ports: many(ports),
|
|
registry: one(registry, {
|
|
fields: [applications.registryId],
|
|
references: [registry.registryId],
|
|
}),
|
|
github: one(github, {
|
|
fields: [applications.githubId],
|
|
references: [github.githubId],
|
|
}),
|
|
gitlab: one(gitlab, {
|
|
fields: [applications.gitlabId],
|
|
references: [gitlab.gitlabId],
|
|
}),
|
|
gitea: one(gitea, {
|
|
fields: [applications.giteaId],
|
|
references: [gitea.giteaId],
|
|
}),
|
|
bitbucket: one(bitbucket, {
|
|
fields: [applications.bitbucketId],
|
|
references: [bitbucket.bitbucketId],
|
|
}),
|
|
server: one(server, {
|
|
fields: [applications.serverId],
|
|
references: [server.serverId],
|
|
}),
|
|
previewDeployments: many(previewDeployments),
|
|
}),
|
|
);
|
|
|
|
const HealthCheckSwarmSchema = z
|
|
.object({
|
|
Test: z.array(z.string()).optional(),
|
|
Interval: z.number().optional(),
|
|
Timeout: z.number().optional(),
|
|
StartPeriod: z.number().optional(),
|
|
Retries: z.number().optional(),
|
|
})
|
|
.strict();
|
|
|
|
const RestartPolicySwarmSchema = z
|
|
.object({
|
|
Condition: z.string().optional(),
|
|
Delay: z.number().optional(),
|
|
MaxAttempts: z.number().optional(),
|
|
Window: z.number().optional(),
|
|
})
|
|
.strict();
|
|
|
|
const PreferenceSchema = z
|
|
.object({
|
|
Spread: z.object({
|
|
SpreadDescriptor: z.string(),
|
|
}),
|
|
})
|
|
.strict();
|
|
|
|
const PlatformSchema = z
|
|
.object({
|
|
Architecture: z.string(),
|
|
OS: z.string(),
|
|
})
|
|
.strict();
|
|
|
|
const PlacementSwarmSchema = z
|
|
.object({
|
|
Constraints: z.array(z.string()).optional(),
|
|
Preferences: z.array(PreferenceSchema).optional(),
|
|
MaxReplicas: z.number().optional(),
|
|
Platforms: z.array(PlatformSchema).optional(),
|
|
})
|
|
.strict();
|
|
|
|
const UpdateConfigSwarmSchema = z
|
|
.object({
|
|
Parallelism: z.number(),
|
|
Delay: z.number().optional(),
|
|
FailureAction: z.string().optional(),
|
|
Monitor: z.number().optional(),
|
|
MaxFailureRatio: z.number().optional(),
|
|
Order: z.string(),
|
|
})
|
|
.strict();
|
|
|
|
const ReplicatedSchema = z
|
|
.object({
|
|
Replicas: z.number().optional(),
|
|
})
|
|
.strict();
|
|
|
|
const ReplicatedJobSchema = z
|
|
.object({
|
|
MaxConcurrent: z.number().optional(),
|
|
TotalCompletions: z.number().optional(),
|
|
})
|
|
.strict();
|
|
|
|
const ServiceModeSwarmSchema = z
|
|
.object({
|
|
Replicated: ReplicatedSchema.optional(),
|
|
Global: z.object({}).optional(),
|
|
ReplicatedJob: ReplicatedJobSchema.optional(),
|
|
GlobalJob: z.object({}).optional(),
|
|
})
|
|
.strict();
|
|
|
|
const NetworkSwarmSchema = z.array(
|
|
z
|
|
.object({
|
|
Target: z.string().optional(),
|
|
Aliases: z.array(z.string()).optional(),
|
|
DriverOpts: z.object({}).optional(),
|
|
})
|
|
.strict(),
|
|
);
|
|
|
|
const LabelsSwarmSchema = z.record(z.string());
|
|
|
|
const createSchema = createInsertSchema(applications, {
|
|
appName: z.string(),
|
|
createdAt: z.string(),
|
|
applicationId: z.string(),
|
|
autoDeploy: z.boolean(),
|
|
env: z.string().optional(),
|
|
buildArgs: z.string().optional(),
|
|
name: z.string().min(1),
|
|
description: z.string().optional(),
|
|
memoryReservation: z.string().optional(),
|
|
memoryLimit: z.string().optional(),
|
|
cpuReservation: z.string().optional(),
|
|
cpuLimit: z.string().optional(),
|
|
title: z.string().optional(),
|
|
enabled: z.boolean().optional(),
|
|
subtitle: z.string().optional(),
|
|
dockerImage: z.string().optional(),
|
|
username: z.string().optional(),
|
|
isPreviewDeploymentsActive: z.boolean().optional(),
|
|
password: z.string().optional(),
|
|
registryUrl: z.string().optional(),
|
|
customGitSSHKeyId: z.string().optional(),
|
|
repository: z.string().optional(),
|
|
dockerfile: z.string().optional(),
|
|
branch: z.string().optional(),
|
|
customGitBranch: z.string().optional(),
|
|
customGitBuildPath: z.string().optional(),
|
|
customGitUrl: z.string().optional(),
|
|
buildPath: z.string().optional(),
|
|
projectId: z.string(),
|
|
sourceType: z.enum(["github", "docker", "git", "gitlab", "bitbucket", "gitea", "drop"]).optional(),
|
|
applicationStatus: z.enum(["idle", "running", "done", "error"]),
|
|
buildType: z.enum([
|
|
"dockerfile",
|
|
"heroku_buildpacks",
|
|
"paketo_buildpacks",
|
|
"nixpacks",
|
|
"static",
|
|
"railpack",
|
|
]),
|
|
herokuVersion: z.string().optional(),
|
|
publishDirectory: z.string().optional(),
|
|
owner: z.string(),
|
|
healthCheckSwarm: HealthCheckSwarmSchema.nullable(),
|
|
restartPolicySwarm: RestartPolicySwarmSchema.nullable(),
|
|
placementSwarm: PlacementSwarmSchema.nullable(),
|
|
updateConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
|
rollbackConfigSwarm: UpdateConfigSwarmSchema.nullable(),
|
|
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
|
labelsSwarm: LabelsSwarmSchema.nullable(),
|
|
networkSwarm: NetworkSwarmSchema.nullable(),
|
|
previewPort: z.number().optional(),
|
|
previewEnv: z.string().optional(),
|
|
previewBuildArgs: z.string().optional(),
|
|
previewWildcard: z.string().optional(),
|
|
previewLimit: z.number().optional(),
|
|
previewHttps: z.boolean().optional(),
|
|
previewPath: z.string().optional(),
|
|
previewCertificateType: z.enum(["letsencrypt", "none", "custom"]).optional(),
|
|
watchPaths: z.array(z.string()).optional(),
|
|
cleanCache: z.boolean().optional(),
|
|
});
|
|
|
|
export const apiCreateApplication = createSchema.pick({
|
|
name: true,
|
|
appName: true,
|
|
description: true,
|
|
projectId: true,
|
|
serverId: true,
|
|
});
|
|
|
|
export const apiFindOneApplication = createSchema
|
|
.pick({
|
|
applicationId: true,
|
|
})
|
|
.required();
|
|
|
|
export const apiReloadApplication = createSchema
|
|
.pick({
|
|
appName: true,
|
|
applicationId: true,
|
|
})
|
|
.required();
|
|
|
|
export const apiSaveBuildType = createSchema
|
|
.pick({
|
|
applicationId: true,
|
|
buildType: true,
|
|
dockerfile: true,
|
|
dockerContextPath: true,
|
|
dockerBuildStage: true,
|
|
herokuVersion: true,
|
|
})
|
|
.required()
|
|
.merge(createSchema.pick({ publishDirectory: true }));
|
|
|
|
export const apiSaveGithubProvider = createSchema
|
|
.pick({
|
|
applicationId: true,
|
|
repository: true,
|
|
branch: true,
|
|
owner: true,
|
|
buildPath: true,
|
|
githubId: true,
|
|
watchPaths: true,
|
|
})
|
|
.required();
|
|
|
|
export const apiSaveGitlabProvider = createSchema
|
|
.pick({
|
|
applicationId: true,
|
|
gitlabBranch: true,
|
|
gitlabBuildPath: true,
|
|
gitlabOwner: true,
|
|
gitlabRepository: true,
|
|
gitlabId: true,
|
|
gitlabProjectId: true,
|
|
gitlabPathNamespace: true,
|
|
watchPaths: true,
|
|
})
|
|
.required();
|
|
|
|
export const apiSaveBitbucketProvider = createSchema
|
|
.pick({
|
|
bitbucketBranch: true,
|
|
bitbucketBuildPath: true,
|
|
bitbucketOwner: true,
|
|
bitbucketRepository: true,
|
|
bitbucketId: true,
|
|
applicationId: true,
|
|
watchPaths: true,
|
|
})
|
|
.required();
|
|
|
|
export const apiSaveGiteaProvider = createSchema
|
|
.pick({
|
|
applicationId: true,
|
|
giteaBranch: true,
|
|
giteaBuildPath: true,
|
|
giteaOwner: true,
|
|
giteaRepository: true,
|
|
giteaId: true,
|
|
giteaProjectId: true,
|
|
giteaPathNamespace: true,
|
|
})
|
|
.required();
|
|
|
|
export const apiSaveDockerProvider = createSchema
|
|
.pick({
|
|
dockerImage: true,
|
|
applicationId: true,
|
|
username: true,
|
|
password: true,
|
|
registryUrl: true,
|
|
})
|
|
.required();
|
|
|
|
export const apiSaveGitProvider = createSchema
|
|
.pick({
|
|
customGitBranch: true,
|
|
applicationId: true,
|
|
customGitBuildPath: true,
|
|
customGitUrl: true,
|
|
watchPaths: true,
|
|
})
|
|
.required()
|
|
.merge(
|
|
createSchema.pick({
|
|
customGitSSHKeyId: true,
|
|
}),
|
|
);
|
|
|
|
export const apiSaveEnvironmentVariables = createSchema
|
|
.pick({
|
|
applicationId: true,
|
|
env: true,
|
|
buildArgs: true,
|
|
})
|
|
.required();
|
|
|
|
export const apiFindMonitoringStats = createSchema
|
|
.pick({
|
|
appName: true,
|
|
})
|
|
.required();
|
|
|
|
export const apiUpdateApplication = createSchema
|
|
.partial()
|
|
.extend({
|
|
applicationId: z.string().min(1),
|
|
})
|
|
.omit({ serverId: true }); |