feat(web-server): migrate user-related functionality to web server model

- Refactored components and API routes to utilize the new web server schema, replacing user references with web server data.
- Updated the dashboard settings to fetch and manage web server domains, IPs, and configurations.
- Introduced a new web server router to handle related API requests, enhancing the overall architecture and data management.
- Added SQL migration for the new web server table and adjusted the database schema accordingly.
This commit is contained in:
Mauricio Siu
2025-07-12 22:57:36 -06:00
parent 733777eeb1
commit 2ec4868a09
27 changed files with 7366 additions and 364 deletions

View File

@@ -8,6 +8,7 @@ import {
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { IS_CLOUD } from "../constants";
import { findWebServer } from "./web-server";
export const findUserById = async (userId: string) => {
const user = await db.query.users.findFirst({
@@ -108,10 +109,10 @@ export const getDokployUrl = async () => {
if (IS_CLOUD) {
return "https://app.dokploy.com";
}
const owner = await findOwner();
const webServer = await findWebServer();
if (owner.user.host) {
return `https://${owner.user.host}`;
if (webServer.host) {
return `https://${webServer.host}`;
}
return `http://${owner.user.serverIp}:${process.env.PORT}`;
return `http://${webServer.serverIp}:${process.env.PORT}`;
};

View File

@@ -6,8 +6,8 @@ import { generateObject } from "ai";
import { desc, eq } from "drizzle-orm";
import { z } from "zod";
import { IS_CLOUD } from "../constants";
import { findOrganizationById } from "./admin";
import { findServerById } from "./server";
import { findWebServer } from "./web-server";
export const getAiSettingsByOrganizationId = async (organizationId: string) => {
const aiSettings = await db.query.ai.findMany({
@@ -53,18 +53,12 @@ export const deleteAiSettings = async (aiId: string) => {
};
interface Props {
organizationId: string;
aiId: string;
input: string;
serverId?: string | undefined;
}
export const suggestVariants = async ({
organizationId,
aiId,
input,
serverId,
}: Props) => {
export const suggestVariants = async ({ aiId, input, serverId }: Props) => {
try {
const aiSettings = await getAiSettingById(aiId);
if (!aiSettings || !aiSettings.isEnabled) {
@@ -79,8 +73,8 @@ export const suggestVariants = async ({
let ip = "";
if (!IS_CLOUD) {
const organization = await findOrganizationById(organizationId);
ip = organization?.owner.serverIp || "";
const webServer = await findWebServer();
ip = webServer?.serverIp || "";
}
if (serverId) {

View File

@@ -6,10 +6,10 @@ import { manageDomain } from "@dokploy/server/utils/traefik/domain";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { type apiCreateDomain, domains } from "../db/schema";
import { findUserById } from "./admin";
import { findApplicationById } from "./application";
import { detectCDNProvider } from "./cdn";
import { findServerById } from "./server";
import { findWebServer } from "./web-server";
export type Domain = typeof domains.$inferSelect;
@@ -43,7 +43,6 @@ export const createDomain = async (input: typeof apiCreateDomain._type) => {
export const generateTraefikMeDomain = async (
appName: string,
userId: string,
serverId?: string,
) => {
if (serverId) {
@@ -60,9 +59,9 @@ export const generateTraefikMeDomain = async (
projectName: appName,
});
}
const admin = await findUserById(userId);
const webServer = await findWebServer();
return generateRandomDomain({
serverIp: admin?.serverIp || "",
serverIp: webServer?.serverIp || "",
projectName: appName,
});
};

View File

@@ -2,7 +2,6 @@ import { db } from "@dokploy/server/db";
import {
type apiCreatePreviewDeployment,
deployments,
organization,
previewDeployments,
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
@@ -13,11 +12,11 @@ import { removeDirectoryCode } from "../utils/filesystem/directory";
import { authGithub } from "../utils/providers/github";
import { removeTraefikConfig } from "../utils/traefik/application";
import { manageDomain } from "../utils/traefik/domain";
import { findUserById } from "./admin";
import { findApplicationById } from "./application";
import { removeDeploymentsByPreviewDeploymentId } from "./deployment";
import { createDomain } from "./domain";
import { type Github, getIssueComment } from "./github";
import { findWebServer } from "./web-server";
export type PreviewDeployment = typeof previewDeployments.$inferSelect;
@@ -156,14 +155,10 @@ export const createPreviewDeployment = async (
const application = await findApplicationById(schema.applicationId);
const appName = `preview-${application.appName}-${generatePassword(6)}`;
const org = await db.query.organization.findFirst({
where: eq(organization.id, application.project.organizationId),
});
const generateDomain = await generateWildcardDomain(
application.previewWildcard || "*.traefik.me",
appName,
application.server?.ipAddress || "",
org?.ownerId || "",
);
const octokit = authGithub(application?.github as Github);
@@ -256,7 +251,6 @@ const generateWildcardDomain = async (
baseDomain: string,
appName: string,
serverIp: string,
userId: string,
): Promise<string> => {
if (!baseDomain.startsWith("*.")) {
throw new Error('The base domain must start with "*."');
@@ -274,8 +268,8 @@ const generateWildcardDomain = async (
}
if (!ip) {
const admin = await findUserById(userId);
ip = admin?.serverIp || "";
const webServer = await findWebServer();
ip = webServer?.serverIp || "";
}
const slugIp = ip.replaceAll(".", "-");

View File

@@ -0,0 +1,42 @@
import { webServer, type updateWebServerSchema } from "../db/schema";
import { db } from "../db";
import type { z } from "zod";
import { TRPCError } from "@trpc/server";
export const createWebServer = async () => {
const exists = await findWebServer();
if (exists) {
return exists;
}
const server = await db?.insert(webServer).values({});
return server;
};
export const findWebServer = async () => {
const server = await db?.query.webServer.findFirst();
if (!server) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Web server not found",
});
}
return server;
};
export const updateWebServer = async (
input: z.infer<typeof updateWebServerSchema>,
) => {
const server = await findWebServer();
if (!server) {
await createWebServer();
}
const updated = await db
.update(webServer)
.set({
...input,
})
.returning()
.then(([updated]) => updated);
return updated;
};