feat: add domains

This commit is contained in:
Mauricio Siu
2025-01-18 22:55:35 -06:00
parent 08ab18eebf
commit 87546b4558
12 changed files with 406 additions and 361 deletions

View File

@@ -3,119 +3,119 @@ import { boolean, integer, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
import { ai } from "./ai";
import { auth } from "./auth";
import { certificates } from "./certificate";
import { registry } from "./registry";
import { certificateType } from "./shared";
import { sshKeys } from "./ssh-key";
import { users } from "./user";
import { ai } from "./ai";
export const admins = pgTable("admin", {
adminId: text("adminId")
.notNull()
.primaryKey()
.$defaultFn(() => nanoid()),
serverIp: text("serverIp"),
certificateType: certificateType("certificateType").notNull().default("none"),
host: text("host"),
letsEncryptEmail: text("letsEncryptEmail"),
sshPrivateKey: text("sshPrivateKey"),
enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false),
enableLogRotation: boolean("enableLogRotation").notNull().default(false),
authId: text("authId")
.notNull()
.references(() => auth.id, { onDelete: "cascade" }),
createdAt: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
stripeCustomerId: text("stripeCustomerId"),
stripeSubscriptionId: text("stripeSubscriptionId"),
serversQuantity: integer("serversQuantity").notNull().default(0),
adminId: text("adminId")
.notNull()
.primaryKey()
.$defaultFn(() => nanoid()),
serverIp: text("serverIp"),
certificateType: certificateType("certificateType").notNull().default("none"),
host: text("host"),
letsEncryptEmail: text("letsEncryptEmail"),
sshPrivateKey: text("sshPrivateKey"),
enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false),
enableLogRotation: boolean("enableLogRotation").notNull().default(false),
authId: text("authId")
.notNull()
.references(() => auth.id, { onDelete: "cascade" }),
createdAt: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
stripeCustomerId: text("stripeCustomerId"),
stripeSubscriptionId: text("stripeSubscriptionId"),
serversQuantity: integer("serversQuantity").notNull().default(0),
});
export const adminsRelations = relations(admins, ({ one, many }) => ({
auth: one(auth, {
fields: [admins.authId],
references: [auth.id],
}),
users: many(users),
registry: many(registry),
sshKeys: many(sshKeys),
certificates: many(certificates),
ai: many(ai),
auth: one(auth, {
fields: [admins.authId],
references: [auth.id],
}),
users: many(users),
registry: many(registry),
sshKeys: many(sshKeys),
certificates: many(certificates),
ai: many(ai),
}));
const createSchema = createInsertSchema(admins, {
adminId: z.string(),
enableDockerCleanup: z.boolean().optional(),
sshPrivateKey: z.string().optional(),
certificateType: z.enum(["letsencrypt", "none"]).default("none"),
serverIp: z.string().optional(),
letsEncryptEmail: z.string().optional(),
adminId: z.string(),
enableDockerCleanup: z.boolean().optional(),
sshPrivateKey: z.string().optional(),
certificateType: z.enum(["letsencrypt", "none"]).default("none"),
serverIp: z.string().optional(),
letsEncryptEmail: z.string().optional(),
});
export const apiUpdateAdmin = createSchema.partial();
export const apiSaveSSHKey = createSchema
.pick({
sshPrivateKey: true,
})
.required();
.pick({
sshPrivateKey: true,
})
.required();
export const apiAssignDomain = createSchema
.pick({
host: true,
certificateType: true,
letsEncryptEmail: true,
})
.required()
.partial({
letsEncryptEmail: true,
});
.pick({
host: true,
certificateType: true,
letsEncryptEmail: true,
})
.required()
.partial({
letsEncryptEmail: true,
});
export const apiUpdateDockerCleanup = createSchema
.pick({
enableDockerCleanup: true,
})
.required()
.extend({
serverId: z.string().optional(),
});
.pick({
enableDockerCleanup: true,
})
.required()
.extend({
serverId: z.string().optional(),
});
export const apiTraefikConfig = z.object({
traefikConfig: z.string().min(1),
traefikConfig: z.string().min(1),
});
export const apiModifyTraefikConfig = z.object({
path: z.string().min(1),
traefikConfig: z.string().min(1),
serverId: z.string().optional(),
path: z.string().min(1),
traefikConfig: z.string().min(1),
serverId: z.string().optional(),
});
export const apiReadTraefikConfig = z.object({
path: z.string().min(1),
serverId: z.string().optional(),
path: z.string().min(1),
serverId: z.string().optional(),
});
export const apiEnableDashboard = z.object({
enableDashboard: z.boolean().optional(),
serverId: z.string().optional(),
enableDashboard: z.boolean().optional(),
serverId: z.string().optional(),
});
export const apiServerSchema = z
.object({
serverId: z.string().optional(),
})
.optional();
.object({
serverId: z.string().optional(),
})
.optional();
export const apiReadStatsLogs = z.object({
page: z
.object({
pageIndex: z.number(),
pageSize: z.number(),
})
.optional(),
status: z.string().array().optional(),
search: z.string().optional(),
sort: z.object({ id: z.string(), desc: z.boolean() }).optional(),
page: z
.object({
pageIndex: z.number(),
pageSize: z.number(),
})
.optional(),
status: z.string().array().optional(),
search: z.string().optional(),
sort: z.object({ id: z.string(), desc: z.boolean() }).optional(),
});

View File

@@ -1,9 +1,9 @@
import { relations } from "drizzle-orm";
import { boolean, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
import { admins } from "./admin";
import { relations } from "drizzle-orm";
import { nanoid } from "nanoid";
export const ai = pgTable("ai", {
aiId: text("aiId")
@@ -63,4 +63,13 @@ export const deploySuggestionSchema = z.object({
serverId: z.string().optional(),
name: z.string().min(1),
description: z.string(),
domains: z
.array(
z.object({
host: z.string().min(1),
port: z.number().min(1),
serviceName: z.string().min(1),
})
)
.optional(),
});

View File

@@ -7,6 +7,7 @@ import { desc, eq } from "drizzle-orm";
import { z } from "zod";
import { IS_CLOUD } from "../constants";
import { findAdminById } from "./admin";
import { findServerById } from "./server";
export const getAiSettingsByAdminId = async (adminId: string) => {
const aiSettings = await db.query.ai.findMany({
@@ -51,11 +52,19 @@ export const deleteAiSettings = async (aiId: string) => {
return db.delete(ai).where(eq(ai.aiId, aiId));
};
export const suggestVariants = async (
adminId: string,
aiId: string,
input: string
) => {
interface Props {
adminId: string;
aiId: string;
input: string;
serverId?: string | undefined;
}
export const suggestVariants = async ({
adminId,
aiId,
input,
serverId,
}: Props) => {
try {
const aiSettings = await getAiSettingById(aiId);
if (!aiSettings || !aiSettings.isEnabled) {
@@ -74,6 +83,13 @@ export const suggestVariants = async (
ip = admin?.serverIp || "";
}
if (serverId) {
const server = await findServerById(serverId);
ip = server.ipAddress;
} else if (process.env.NODE_ENV === "development") {
ip = "127.0.0.1";
}
const { object } = await generateObject({
model,
output: "array",
@@ -122,13 +138,13 @@ export const suggestVariants = async (
2. Use complex values for passwords/secrets variables
3. Don't set container_name field in services
4. Don't set version field in the docker compose
5. Don't set ports like 'ports: 3000:3000', use 'ports: ["3000"]' instead
5. Don't set ports like 'ports: 3000:3000', use 'ports: "3000"' instead
6. Use dokploy-network in all services
7. Add dokploy-network at the end and mark it as external: true
For each service that needs to be exposed to the internet:
1. Define a domain configuration with:
- host: the domain name for the service
- host: the domain name for the service in format: {service-name}-{random-3-chars-hex}-${ip ? ip.replaceAll(".", "-") : ""}.traefik.me
- port: the internal port the service runs on
- serviceName: the name of the service in the docker-compose
2. Make sure the service is properly configured in the docker-compose to work with the specified port
@@ -145,7 +161,6 @@ export const suggestVariants = async (
}
} catch (error) {
console.error("Error in docker compose generation:", error);
console.error("Error details:", error.cause?.issues || error);
}
}
return result;