From ab52ef6c27ee06d628d6614edf406d818af5e5bc Mon Sep 17 00:00:00 2001 From: Charles GTE Date: Sun, 17 May 2026 10:41:36 +0200 Subject: [PATCH 1/6] fix: logger.ts (#288) * fix: release.yml * fix: S3ChannelConfigSchema type port mismatch * chore: package.json * fix: refactoring logs and adding pino logger for production and dev. * fix: trusted url error due to better auth update. * fix: logger.ts --------- Co-authored-by: charlesgauthereau Co-authored-by: killianlarcher --- src/lib/logger.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lib/logger.ts b/src/lib/logger.ts index 829d20fe..9337e144 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -1,9 +1,8 @@ import pino, { type Logger } from "pino"; -import {env} from "@/env.mjs"; -const isProd = env.NODE_ENV === "production"; +const isProd = process.env.NODE_ENV === "production"; const defaultLevel = isProd ? "info" : "debug"; -const level = (env.LOG_LEVEL ?? defaultLevel) as pino.Level; +const level = (process.env.LOG_LEVEL ?? defaultLevel) as pino.Level; function getLocalTimestamp() { const date = new Date(); @@ -22,9 +21,8 @@ function getLocalTimestamp() { } export const logger: Logger = pino({ - level, + level: level, base: null, - ...(isProd ? { timestamp: getLocalTimestamp, From 332540488d34ed2f99d78a9f662d92865d884db2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 17 May 2026 08:42:07 +0000 Subject: [PATCH 2/6] chore: release 1.15.1 --- CITATION.cff | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index d24a66e6..9e621318 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -33,5 +33,5 @@ keywords: - web-ui - agent license: Apache-2.0 -version: 1.15.0 +version: 1.15.1 date-released: '2026-03-02' diff --git a/package.json b/package.json index ffd9e979..53032d7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "portabase", - "version": "1.15.0", + "version": "1.15.1", "private": true, "scripts": { "dev": "next dev --turbopack -p 8887", From 7d463d7da817d4fa09b3815b90eccd87a1497f6a Mon Sep 17 00:00:00 2001 From: Charles GTE Date: Thu, 21 May 2026 07:28:05 +0200 Subject: [PATCH 3/6] fix: default user from init .env variables (#293) * fix: default user from init en .env variables * fix: .env.example --------- Co-authored-by: charles-gauthereau --- .env.example | 9 + .../dashboard/(admin)/admin/users/page.tsx | 8 +- package.json | 2 +- .../dashboard/admin/users/user.action.ts | 1 + src/db/services/user.ts | 4 + src/env.mjs | 261 +++++++++--------- src/types/auth.ts | 4 +- src/utils/init.ts | 146 ---------- src/utils/init/cron.ts | 14 + src/utils/init/index.ts | 50 ++++ src/utils/init/organization.ts | 27 ++ src/utils/init/setting.ts | 70 +++++ src/utils/init/user.ts | 71 +++++ src/utils/password.ts | 57 ++++ 14 files changed, 445 insertions(+), 279 deletions(-) delete mode 100644 src/utils/init.ts create mode 100644 src/utils/init/cron.ts create mode 100644 src/utils/init/index.ts create mode 100644 src/utils/init/organization.ts create mode 100644 src/utils/init/setting.ts create mode 100644 src/utils/init/user.ts diff --git a/.env.example b/.env.example index 21888ecb..4008667e 100644 --- a/.env.example +++ b/.env.example @@ -15,6 +15,15 @@ PROJECT_NAME="Portabase" PROJECT_URL=http://localhost:8887 PROJECT_SECRET= +AUTH_DEFAULT_USER_NAME="Portabase Admin" +AUTH_DEFAULT_USER=user@example.com +# Password must contain at least 8 characters +# Password must contain at least 1 number +# Password must contain at least 1 lowercase letter +# Password must contain at least 1 uppercase letter +# Password must contain at least 1 special character +AUTH_DEFAULT_PASSWORD=testPASS123456! + # SMTP (email) SMTP_HOST= SMTP_PORT= diff --git a/app/(customer)/dashboard/(admin)/admin/users/page.tsx b/app/(customer)/dashboard/(admin)/admin/users/page.tsx index ec7f8feb..899e7f4c 100644 --- a/app/(customer)/dashboard/(admin)/admin/users/page.tsx +++ b/app/(customer)/dashboard/(admin)/admin/users/page.tsx @@ -30,9 +30,11 @@ export default async function RoutePage(props: PageParams<{}>) {
Active users - - - + {isPasswordAuthEnabled && ( + + + + )}
diff --git a/package.json b/package.json index 53032d7d..5aa8d6da 100644 --- a/package.json +++ b/package.json @@ -136,5 +136,5 @@ "typescript": "^5.9.3", "zenstack": "2.14.2" }, - "packageManager": "pnpm@11.1.2+sha512.415a1cc25974731e75455c1468371be74c5aa5fb7621b50d4056d222451609f11412f23fd602e6169f1e060466641f798597e1be961a10688836a67b16569499" + "packageManager": "pnpm@11.1.3" } diff --git a/src/components/wrappers/dashboard/admin/users/user.action.ts b/src/components/wrappers/dashboard/admin/users/user.action.ts index 23b136b8..f2d18cb1 100644 --- a/src/components/wrappers/dashboard/admin/users/user.action.ts +++ b/src/components/wrappers/dashboard/admin/users/user.action.ts @@ -35,6 +35,7 @@ export const createUserAction = userAction email: parsedInput.email, theme: "dark", role: "user", + password: "" }; if (isPasswordAuthEnabled) { diff --git a/src/db/services/user.ts b/src/db/services/user.ts index a230b310..f847e15d 100644 --- a/src/db/services/user.ts +++ b/src/db/services/user.ts @@ -3,13 +3,17 @@ import {hashPassword} from "better-auth/crypto"; import {db} from "@/db"; import * as drizzleDb from "@/db"; import {User, UserThemeEnum} from "@/db/schema/02_user"; +import {assertValidPassword} from "@/utils/password"; export async function createUserDb(data: SignUpUser): Promise { + assertValidPassword(data.password); + const now = new Date(); const userId = crypto.randomUUID(); const [newUser] = await db.insert(drizzleDb.schemas.user).values({ + ...data, id: userId, name: data.name, email: data.email, diff --git a/src/env.mjs b/src/env.mjs index 6a5d926a..e27ac90e 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -1,167 +1,174 @@ -import { createEnv } from "@t3-oss/env-nextjs"; +import {createEnv} from "@t3-oss/env-nextjs"; import path from "path"; -import { z } from "zod"; -import packageJson from "../package.json" with { type: "json" }; +import {z} from "zod"; +import packageJson from "../package.json" with {type: "json"}; -const { version } = packageJson; +const {version} = packageJson; export const env = createEnv({ - server: { - NEXT_PUBLIC_PROJECT_VERSION: z.string().optional(), + server: { + NEXT_PUBLIC_PROJECT_VERSION: z.string().optional(), - NODE_ENV: z.enum(["development", "production"]).optional(), - LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"), + NODE_ENV: z.enum(["development", "production"]).optional(), + LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"), - DATABASE_URL: z.string().url().optional(), + DATABASE_URL: z.url().optional(), - PROJECT_NAME: z.string().optional(), - PROJECT_DESCRIPTION: z.string().optional(), - PROJECT_URL: z - .string() - .regex(/^https?:\/\//, "URL must start with http:// or https://"), - PROJECT_SECRET: z.string(), + PROJECT_NAME: z.string().optional(), + PROJECT_DESCRIPTION: z.string().optional(), + PROJECT_URL: z + .string() + .regex(/^https?:\/\//, "URL must start with http:// or https://"), + PROJECT_SECRET: z.string(), - TRUSTED_DOMAINS: z.string().optional(), + TRUSTED_DOMAINS: z.string().optional(), - SMTP_PASSWORD: z.string().optional(), - SMTP_FROM: z.string().optional(), - SMTP_HOST: z.string().optional(), - SMTP_PORT: z.string().optional(), - SMTP_USER: z.string().optional(), + SMTP_PASSWORD: z.string().optional(), + SMTP_FROM: z.string().optional(), + SMTP_HOST: z.string().optional(), + SMTP_PORT: z.string().optional(), + SMTP_USER: z.string().optional(), + + AUTH_DEFAULT_USER_NAME: z.string().optional(), + AUTH_DEFAULT_USER: z.string().optional(), + AUTH_DEFAULT_PASSWORD: z.string().optional(), - SMTP_SECURE: z - .enum(["true", "false"]) - .transform((val) => val === "true") - .default("true"), + SMTP_SECURE: z + .enum(["true", "false"]) + .transform((val) => val === "true") + .default("true"), - AUTH_GOOGLE_ID: z.string().optional(), - AUTH_GOOGLE_SECRET: z.string().optional(), + AUTH_GOOGLE_ID: z.string().optional(), + AUTH_GOOGLE_SECRET: z.string().optional(), - AUTH_GITHUB_ID: z.string().optional(), - AUTH_GITHUB_SECRET: z.string().optional(), + AUTH_GITHUB_ID: z.string().optional(), + AUTH_GITHUB_SECRET: z.string().optional(), - RETENTION_CRON: z - .string() - .default( - process.env.NODE_ENV === "production" ? "0 7 * * *" : "* * * * *", - ), + RETENTION_CRON: z + .string() + .default( + process.env.NODE_ENV === "production" ? "0 7 * * *" : "* * * * *", + ), - CLEANING_HEALTHCHECK_LOGS_CRON: z - .string() - .default( - process.env.NODE_ENV === "production" ? "0 * * * *" : "* * * * *", - ), + CLEANING_HEALTHCHECK_LOGS_CRON: z + .string() + .default( + process.env.NODE_ENV === "production" ? "0 * * * *" : "* * * * *", + ), - HEALTHCHECK_CRON: z - .string() - .default( - process.env.NODE_ENV === "production" ? "0 * * * *" : "* * * * *", - ), + HEALTHCHECK_CRON: z + .string() + .default( + process.env.NODE_ENV === "production" ? "0 * * * *" : "* * * * *", + ), + AUTH_OIDC_ID: z.string().optional().default("oidc"), + AUTH_OIDC_TITLE: z.string().optional(), + AUTH_OIDC_DESC: z.string().optional(), + AUTH_OIDC_ICON: z.string().optional(), + AUTH_OIDC_CLIENT: z.string().optional(), + AUTH_OIDC_SECRET: z.string().optional(), + AUTH_OIDC_ISSUER_URL: z.string().optional(), + AUTH_OIDC_HOST: z.string().optional(), + AUTH_OIDC_SCOPES: z.string().optional(), + AUTH_OIDC_DISCOVERY_ENDPOINT: z.string().optional(), + AUTH_OIDC_JWKS_ENDPOINT: z.string().optional(), + AUTH_OIDC_PKCE: z.string().optional(), - AUTH_OIDC_ID: z.string().optional().default("oidc"), - AUTH_OIDC_TITLE: z.string().optional(), - AUTH_OIDC_DESC: z.string().optional(), - AUTH_OIDC_ICON: z.string().optional(), - AUTH_OIDC_CLIENT: z.string().optional(), - AUTH_OIDC_SECRET: z.string().optional(), - AUTH_OIDC_ISSUER_URL: z.string().optional(), - AUTH_OIDC_HOST: z.string().optional(), - AUTH_OIDC_SCOPES: z.string().optional(), - AUTH_OIDC_DISCOVERY_ENDPOINT: z.string().optional(), - AUTH_OIDC_JWKS_ENDPOINT: z.string().optional(), - AUTH_OIDC_PKCE: z.string().optional(), + AUTH_SOCIAL_ID: z.string().optional().default("social"), + AUTH_SOCIAL_TITLE: z.string().optional(), + AUTH_SOCIAL_DESC: z.string().optional(), + AUTH_SOCIAL_ICON: z.string().optional(), + AUTH_SOCIAL_CLIENT: z.string().optional(), + AUTH_SOCIAL_SECRET: z.string().optional(), + AUTH_SOCIAL_APPLE_APP_BUNDLE_IDENTIFIER: z.string().optional(), - AUTH_SOCIAL_ID: z.string().optional().default("social"), - AUTH_SOCIAL_TITLE: z.string().optional(), - AUTH_SOCIAL_DESC: z.string().optional(), - AUTH_SOCIAL_ICON: z.string().optional(), - AUTH_SOCIAL_CLIENT: z.string().optional(), - AUTH_SOCIAL_SECRET: z.string().optional(), - AUTH_SOCIAL_APPLE_APP_BUNDLE_IDENTIFIER: z.string().optional(), + ALLOWED_GROUP: z.string().optional(), - ALLOWED_GROUP: z.string().optional(), + AUTH_EMAIL_PASSWORD_ENABLED: z.string().optional().default("true"), + AUTH_SIGNUP_ENABLED: z.string().optional().default("true"), + AUTH_PASSKEY_ENABLED: z.string().optional().default("false"), - AUTH_EMAIL_PASSWORD_ENABLED: z.string().optional().default("true"), - AUTH_SIGNUP_ENABLED: z.string().optional().default("true"), - AUTH_PASSKEY_ENABLED: z.string().optional().default("false"), + AUTH_SYNC_OIDC_ROLES_ON_LOGIN: z.enum(["true", "false"]).default("true"), + AUTH_ROLE_MAP: z.string().optional(), + AUTH_DEFAULT_ROLE: z.string().optional().default("pending"), + AUTH_ALLOW_LINKING: z.enum(["true", "false"]).default("true"), + AUTH_ALLOW_UNLINKING: z.enum(["true", "false"]).default("true"), - AUTH_SYNC_OIDC_ROLES_ON_LOGIN: z.enum(["true", "false"]).default("true"), - AUTH_ROLE_MAP: z.string().optional(), - AUTH_DEFAULT_ROLE: z.string().optional().default("pending"), - AUTH_ALLOW_LINKING: z.enum(["true", "false"]).default("true"), - AUTH_ALLOW_UNLINKING: z.enum(["true", "false"]).default("true"), + PRIVATE_PATH: z.string().optional(), + }, + client: { + NEXT_PUBLIC_PROJECT_VERSION: z.string().optional(), + }, + runtimeEnv: { + NEXT_PUBLIC_PROJECT_VERSION: version || "Unknown Version", + LOG_LEVEL: process.env.LOG_LEVEL, - PRIVATE_PATH: z.string().optional(), - }, - client: { - NEXT_PUBLIC_PROJECT_VERSION: z.string().optional(), - }, - runtimeEnv: { - NEXT_PUBLIC_PROJECT_VERSION: version || "Unknown Version", - LOG_LEVEL: process.env.LOG_LEVEL, + PROJECT_NAME: process.env.PROJECT_NAME, + PROJECT_DESCRIPTION: process.env.PROJECT_DESCRIPTION, + PROJECT_URL: process.env.PROJECT_URL, + PROJECT_SECRET: process.env.PROJECT_SECRET, - PROJECT_NAME: process.env.PROJECT_NAME, - PROJECT_DESCRIPTION: process.env.PROJECT_DESCRIPTION, - PROJECT_URL: process.env.PROJECT_URL, - PROJECT_SECRET: process.env.PROJECT_SECRET, + DATABASE_URL: process.env.DATABASE_URL, - DATABASE_URL: process.env.DATABASE_URL, + TRUSTED_DOMAINS: process.env.TRUSTED_DOMAINS, - TRUSTED_DOMAINS: process.env.TRUSTED_DOMAINS, + SMTP_PASSWORD: process.env.SMTP_PASSWORD, + SMTP_FROM: process.env.SMTP_FROM, + SMTP_HOST: process.env.SMTP_HOST, + SMTP_PORT: process.env.SMTP_PORT, + SMTP_USER: process.env.SMTP_USER, + SMTP_SECURE: process.env.SMTP_SECURE, - SMTP_PASSWORD: process.env.SMTP_PASSWORD, - SMTP_FROM: process.env.SMTP_FROM, - SMTP_HOST: process.env.SMTP_HOST, - SMTP_PORT: process.env.SMTP_PORT, - SMTP_USER: process.env.SMTP_USER, - SMTP_SECURE: process.env.SMTP_SECURE, + RETENTION_CRON: process.env.RETENTION_CRON, + CLEANING_HEALTHCHECK_LOGS_CRON: process.env.CLEANING_HEALTHCHECK_LOGS_CRON, - RETENTION_CRON: process.env.RETENTION_CRON, - CLEANING_HEALTHCHECK_LOGS_CRON: process.env.CLEANING_HEALTHCHECK_LOGS_CRON, + AUTH_OIDC_ID: process.env.AUTH_OIDC_ID, + AUTH_OIDC_TITLE: process.env.AUTH_OIDC_TITLE, + AUTH_OIDC_DESC: process.env.AUTH_OIDC_DESC, + AUTH_OIDC_ICON: process.env.AUTH_OIDC_ICON, + AUTH_OIDC_CLIENT: process.env.AUTH_OIDC_CLIENT, + AUTH_OIDC_SECRET: process.env.AUTH_OIDC_SECRET, + AUTH_OIDC_ISSUER_URL: process.env.AUTH_OIDC_ISSUER_URL, + AUTH_OIDC_HOST: process.env.AUTH_OIDC_HOST, + AUTH_OIDC_SCOPES: process.env.AUTH_OIDC_SCOPES, + AUTH_OIDC_DISCOVERY_ENDPOINT: process.env.AUTH_OIDC_DISCOVERY_ENDPOINT, + AUTH_OIDC_JWKS_ENDPOINT: process.env.AUTH_OIDC_JWKS_ENDPOINT, + AUTH_OIDC_PKCE: process.env.AUTH_OIDC_PKCE, - AUTH_OIDC_ID: process.env.AUTH_OIDC_ID, - AUTH_OIDC_TITLE: process.env.AUTH_OIDC_TITLE, - AUTH_OIDC_DESC: process.env.AUTH_OIDC_DESC, - AUTH_OIDC_ICON: process.env.AUTH_OIDC_ICON, - AUTH_OIDC_CLIENT: process.env.AUTH_OIDC_CLIENT, - AUTH_OIDC_SECRET: process.env.AUTH_OIDC_SECRET, - AUTH_OIDC_ISSUER_URL: process.env.AUTH_OIDC_ISSUER_URL, - AUTH_OIDC_HOST: process.env.AUTH_OIDC_HOST, - AUTH_OIDC_SCOPES: process.env.AUTH_OIDC_SCOPES, - AUTH_OIDC_DISCOVERY_ENDPOINT: process.env.AUTH_OIDC_DISCOVERY_ENDPOINT, - AUTH_OIDC_JWKS_ENDPOINT: process.env.AUTH_OIDC_JWKS_ENDPOINT, - AUTH_OIDC_PKCE: process.env.AUTH_OIDC_PKCE, + AUTH_GOOGLE_ID: process.env.AUTH_GOOGLE_ID, + AUTH_GOOGLE_SECRET: process.env.AUTH_GOOGLE_SECRET, - AUTH_GOOGLE_ID: process.env.AUTH_GOOGLE_ID, - AUTH_GOOGLE_SECRET: process.env.AUTH_GOOGLE_SECRET, + AUTH_GITHUB_ID: process.env.AUTH_GITHUB_ID, + AUTH_GITHUB_SECRET: process.env.AUTH_GITHUB_SECRET, - AUTH_GITHUB_ID: process.env.AUTH_GITHUB_ID, - AUTH_GITHUB_SECRET: process.env.AUTH_GITHUB_SECRET, + AUTH_SOCIAL_ID: process.env.AUTH_SOCIAL_ID, + AUTH_SOCIAL_TITLE: process.env.AUTH_SOCIAL_TITLE, + AUTH_SOCIAL_DESC: process.env.AUTH_SOCIAL_DESC, + AUTH_SOCIAL_ICON: process.env.AUTH_SOCIAL_ICON, + AUTH_SOCIAL_CLIENT: process.env.AUTH_SOCIAL_CLIENT, + AUTH_SOCIAL_SECRET: process.env.AUTH_SOCIAL_SECRET, - AUTH_SOCIAL_ID: process.env.AUTH_SOCIAL_ID, - AUTH_SOCIAL_TITLE: process.env.AUTH_SOCIAL_TITLE, - AUTH_SOCIAL_DESC: process.env.AUTH_SOCIAL_DESC, - AUTH_SOCIAL_ICON: process.env.AUTH_SOCIAL_ICON, - AUTH_SOCIAL_CLIENT: process.env.AUTH_SOCIAL_CLIENT, - AUTH_SOCIAL_SECRET: process.env.AUTH_SOCIAL_SECRET, + ALLOWED_GROUP: process.env.ALLOWED_GROUP, - ALLOWED_GROUP: process.env.ALLOWED_GROUP, + AUTH_EMAIL_PASSWORD_ENABLED: process.env.AUTH_EMAIL_PASSWORD_ENABLED, + AUTH_SIGNUP_ENABLED: process.env.AUTH_SIGNUP_ENABLED, + AUTH_PASSKEY_ENABLED: process.env.AUTH_PASSKEY_ENABLED, - AUTH_EMAIL_PASSWORD_ENABLED: process.env.AUTH_EMAIL_PASSWORD_ENABLED, - AUTH_SIGNUP_ENABLED: process.env.AUTH_SIGNUP_ENABLED, - AUTH_PASSKEY_ENABLED: process.env.AUTH_PASSKEY_ENABLED, + AUTH_SYNC_OIDC_ROLES_ON_LOGIN: process.env.AUTH_SYNC_OIDC_ROLES_ON_LOGIN, - AUTH_SYNC_OIDC_ROLES_ON_LOGIN: process.env.AUTH_SYNC_OIDC_ROLES_ON_LOGIN, + AUTH_ROLE_MAP: process.env.AUTH_ROLE_MAP, - AUTH_ROLE_MAP: process.env.AUTH_ROLE_MAP, + AUTH_ALLOW_LINKING: process.env.AUTH_ALLOW_LINKING, + AUTH_ALLOW_UNLINKING: process.env.AUTH_ALLOW_UNLINKING, - AUTH_ALLOW_LINKING: process.env.AUTH_ALLOW_LINKING, - AUTH_ALLOW_UNLINKING: process.env.AUTH_ALLOW_UNLINKING, + PRIVATE_PATH: + process.env.PRIVATE_PATH || path.join(process.cwd(), "private"), - PRIVATE_PATH: - process.env.PRIVATE_PATH || path.join(process.cwd(), "private"), - }, + AUTH_DEFAULT_USER_NAME: process.env.AUTH_DEFAULT_USER_NAME, + AUTH_DEFAULT_USER: process.env.AUTH_DEFAULT_USER, + AUTH_DEFAULT_PASSWORD: process.env.AUTH_DEFAULT_PASSWORD, + }, }); diff --git a/src/types/auth.ts b/src/types/auth.ts index 41139d71..d3727eef 100644 --- a/src/types/auth.ts +++ b/src/types/auth.ts @@ -1,11 +1,11 @@ - export type SignUpUser = { name: string email: string - password?: string + password: string callbackURL?: string role?: string theme: string + emailVerified?: boolean } diff --git a/src/utils/init.ts b/src/utils/init.ts deleted file mode 100644 index d3bc859e..00000000 --- a/src/utils/init.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { env } from "@/env.mjs"; -import { db, makeMigration } from "@/db"; -import { eq } from "drizzle-orm"; -import * as drizzleDb from "@/db"; -import {cleaningHealthcheckLogsJob, cleaningJob, healthcheckAgentAndDatabaseJob, retentionJob} from "@/lib/tasks"; -import { generateRSAKeys, getOrCreateMasterKey } from "@/utils/rsa-keys"; -import { StorageProviderKind } from "@/features/storages/types"; -import {logger} from "@/lib/logger"; -import {withUpdatedAt} from "@/db/utils"; - -const log = logger.child({module: "init"}); - -export async function init() { - consoleAscii(); - - log.info("====Init Functions===="); - await getOrCreateMasterKey(); - await generateRSAKeys(); - await makeMigration(); - await createDefaultOrganization(); - await createSettingsIfNotExist(); - log.info("====Initialization completed===="); - await setupCronJobs(); - - if ( - (env.AUTH_GOOGLE_ID && env.AUTH_GOOGLE_SECRET) || - (env.AUTH_GITHUB_ID && env.AUTH_GITHUB_SECRET) - ) { - log.warn( - { - deprecated: true, - provider: "oauth_env", - message: "You have set up OAuth credentials in your environment variables, but the format is now different. Please update your environment variables to use the new format. For example, if you were using AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET, you should now use AUTH_SOCIAL_GOOGLE_CLIENT and AUTH_SOCIAL_GOOGLE_SECRET. Please refer to the documentation for more details. (https://portabase.io/docs/dashboard/auth/oauth2/setup#dynamic-providers)" - }, - "Deprecated OAuth environment variables detected", - ); - } -} - -async function setupCronJobs() { - - log.info("==== Setting up Cron Jobs ===="); - retentionJob.start(); - cleaningJob.start(); - cleaningHealthcheckLogsJob.start(); - healthcheckAgentAndDatabaseJob.start(); - log.info("==== Cron jobs started ===="); -} - -async function createSettingsIfNotExist() { - await db.transaction(async (tx) => { - - const systemSettingsValues = { - name: "system", - smtpPassword: env.SMTP_PASSWORD ?? null, - smtpFrom: env.SMTP_FROM ?? null, - smtpHost: env.SMTP_HOST ?? null, - smtpPort: env.SMTP_PORT ?? null, - smtpUser: env.SMTP_USER ?? null, - smtpSecure: env.SMTP_SECURE ?? false, - }; - - const [systemSetting] = await tx - .select() - .from(drizzleDb.schemas.setting) - .where(eq(drizzleDb.schemas.setting.name, "system")) - .limit(1); - - const [finalSystemSetting] = systemSetting - ? await tx - .update(drizzleDb.schemas.setting) - .set(systemSettingsValues) - .where(eq(drizzleDb.schemas.setting.name, "system")) - .returning() - : await tx - .insert(drizzleDb.schemas.setting) - .values(systemSettingsValues) - .returning(); - - const localStorageValues = { - provider: "local" as StorageProviderKind, - enabled: true, - name: "System", - config: {}, - }; - - const [existingLocalStorage] = await tx - .select() - .from(drizzleDb.schemas.storageChannel) - .where(eq(drizzleDb.schemas.storageChannel.provider, "local")) - .limit(1); - - const [localStorage] = existingLocalStorage - ? await tx - .update(drizzleDb.schemas.storageChannel) - .set(localStorageValues) - .where(eq(drizzleDb.schemas.storageChannel.provider, "local")) - .returning() - : await tx - .insert(drizzleDb.schemas.storageChannel) - .values(localStorageValues) - .returning(); - - if (!finalSystemSetting.defaultStorageChannelId) { - await tx - .update(drizzleDb.schemas.setting) - .set(withUpdatedAt({ defaultStorageChannelId: localStorage.id })) - .where(eq(drizzleDb.schemas.setting.id, finalSystemSetting.id)); - } - }); -} - -async function createDefaultOrganization() { - const defaultOrganizationConf = { - slug: "default", - name: "Default Organization", - createdAt: new Date(), - }; - - const [existing] = await db - .select() - .from(drizzleDb.schemas.organization) - .where(eq(drizzleDb.schemas.organization.slug, "default")) - .limit(1); - - if (!existing) { - log.info("==== Creating default Organization... ===="); - await db - .insert(drizzleDb.schemas.organization) - .values(defaultOrganizationConf); - } -} - -function consoleAscii() { - console.log( - " \n" + - " ____ __ __ \n" + - " / __ \\____ _____/ /_____ _/ /_ ____ _________ \n" + - " / /_/ / __ \\/ ___/ __/ __ / __ \\/ __ / ___/ _ \\ \n" + - " / ____/ /_/ / / / /_/ /_/ / /_/ / /_/ (__ ) __/ \n" + - " /_/ \\____/_/ \\__/\\__,_/_.___/\\__,_/____/\\___/ \n" + - " \n" + - ` Community Edition v${env.NEXT_PUBLIC_PROJECT_VERSION} \n ` + - " \n", - ); -} diff --git a/src/utils/init/cron.ts b/src/utils/init/cron.ts new file mode 100644 index 00000000..7db2077f --- /dev/null +++ b/src/utils/init/cron.ts @@ -0,0 +1,14 @@ +import {cleaningHealthcheckLogsJob, cleaningJob, healthcheckAgentAndDatabaseJob, retentionJob} from "@/lib/tasks"; +import {logger} from "@/lib/logger"; + +const log = logger.child({module: "init/cron"}); + + +export async function setupCronJobs() { + log.info("==== Setting up Cron Jobs ===="); + retentionJob.start(); + cleaningJob.start(); + cleaningHealthcheckLogsJob.start(); + healthcheckAgentAndDatabaseJob.start(); + log.info("==== Cron jobs started ===="); +} \ No newline at end of file diff --git a/src/utils/init/index.ts b/src/utils/init/index.ts new file mode 100644 index 00000000..9108fb8e --- /dev/null +++ b/src/utils/init/index.ts @@ -0,0 +1,50 @@ +import { env } from "@/env.mjs"; +import { makeMigration } from "@/db"; +import { generateRSAKeys, getOrCreateMasterKey } from "@/utils/rsa-keys"; +import {logger} from "@/lib/logger"; +import {setupCronJobs} from "@/utils/init/cron"; +import {createSettingsIfNotExist} from "@/utils/init/setting"; +import {createDefaultOrganization} from "@/utils/init/organization"; +import {createDefaultUser} from "@/utils/init/user"; + +const log = logger.child({module: "init"}); + +export async function init() { + consoleAscii(); + log.info("====Init Functions===="); + await getOrCreateMasterKey(); + await generateRSAKeys(); + await makeMigration(); + await createDefaultOrganization(); + await createSettingsIfNotExist(); + await createDefaultUser(); + log.info("====Initialization completed===="); + await setupCronJobs(); + if ( + (env.AUTH_GOOGLE_ID && env.AUTH_GOOGLE_SECRET) || + (env.AUTH_GITHUB_ID && env.AUTH_GITHUB_SECRET) + ) { + log.warn( + { + deprecated: true, + provider: "oauth_env", + message: "You have set up OAuth credentials in your environment variables, but the format is now different. Please update your environment variables to use the new format. For example, if you were using AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET, you should now use AUTH_SOCIAL_GOOGLE_CLIENT and AUTH_SOCIAL_GOOGLE_SECRET. Please refer to the documentation for more details. (https://portabase.io/docs/dashboard/auth/oauth2/setup#dynamic-providers)" + }, + "Deprecated OAuth environment variables detected", + ); + } +} + +function consoleAscii() { + console.log( + " \n" + + " ____ __ __ \n" + + " / __ \\____ _____/ /_____ _/ /_ ____ _________ \n" + + " / /_/ / __ \\/ ___/ __/ __ / __ \\/ __ / ___/ _ \\ \n" + + " / ____/ /_/ / / / /_/ /_/ / /_/ / /_/ (__ ) __/ \n" + + " /_/ \\____/_/ \\__/\\__,_/_.___/\\__,_/____/\\___/ \n" + + " \n" + + ` Community Edition v${env.NEXT_PUBLIC_PROJECT_VERSION} \n ` + + " \n", + ); +} diff --git a/src/utils/init/organization.ts b/src/utils/init/organization.ts new file mode 100644 index 00000000..1058cd24 --- /dev/null +++ b/src/utils/init/organization.ts @@ -0,0 +1,27 @@ +import {db} from "@/db"; +import * as drizzleDb from "@/db"; +import {eq} from "drizzle-orm"; +import {logger} from "@/lib/logger"; + +const log = logger.child({module: "init/organization"}); + +export async function createDefaultOrganization() { + const defaultOrganizationConf = { + slug: "default", + name: "Default Organization", + createdAt: new Date(), + }; + + const [existing] = await db + .select() + .from(drizzleDb.schemas.organization) + .where(eq(drizzleDb.schemas.organization.slug, "default")) + .limit(1); + + if (!existing) { + log.info("==== Creating default Organization... ===="); + await db + .insert(drizzleDb.schemas.organization) + .values(defaultOrganizationConf); + } +} \ No newline at end of file diff --git a/src/utils/init/setting.ts b/src/utils/init/setting.ts new file mode 100644 index 00000000..04b095d3 --- /dev/null +++ b/src/utils/init/setting.ts @@ -0,0 +1,70 @@ +import {db} from "@/db"; +import {env} from "@/env.mjs"; +import * as drizzleDb from "@/db"; +import {eq} from "drizzle-orm"; +import {StorageProviderKind} from "@/features/storages/types"; +import {withUpdatedAt} from "@/db/utils"; + + +export async function createSettingsIfNotExist() { + await db.transaction(async (tx) => { + + const systemSettingsValues = { + name: "system", + smtpPassword: env.SMTP_PASSWORD ?? null, + smtpFrom: env.SMTP_FROM ?? null, + smtpHost: env.SMTP_HOST ?? null, + smtpPort: env.SMTP_PORT ?? null, + smtpUser: env.SMTP_USER ?? null, + smtpSecure: env.SMTP_SECURE ?? false, + }; + + const [systemSetting] = await tx + .select() + .from(drizzleDb.schemas.setting) + .where(eq(drizzleDb.schemas.setting.name, "system")) + .limit(1); + + const [finalSystemSetting] = systemSetting + ? await tx + .update(drizzleDb.schemas.setting) + .set(systemSettingsValues) + .where(eq(drizzleDb.schemas.setting.name, "system")) + .returning() + : await tx + .insert(drizzleDb.schemas.setting) + .values(systemSettingsValues) + .returning(); + + const localStorageValues = { + provider: "local" as StorageProviderKind, + enabled: true, + name: "System", + config: {}, + }; + + const [existingLocalStorage] = await tx + .select() + .from(drizzleDb.schemas.storageChannel) + .where(eq(drizzleDb.schemas.storageChannel.provider, "local")) + .limit(1); + + const [localStorage] = existingLocalStorage + ? await tx + .update(drizzleDb.schemas.storageChannel) + .set(localStorageValues) + .where(eq(drizzleDb.schemas.storageChannel.provider, "local")) + .returning() + : await tx + .insert(drizzleDb.schemas.storageChannel) + .values(localStorageValues) + .returning(); + + if (!finalSystemSetting.defaultStorageChannelId) { + await tx + .update(drizzleDb.schemas.setting) + .set(withUpdatedAt({ defaultStorageChannelId: localStorage.id })) + .where(eq(drizzleDb.schemas.setting.id, finalSystemSetting.id)); + } + }); +} \ No newline at end of file diff --git a/src/utils/init/user.ts b/src/utils/init/user.ts new file mode 100644 index 00000000..d5c653e5 --- /dev/null +++ b/src/utils/init/user.ts @@ -0,0 +1,71 @@ +import {db} from "@/db"; +import * as drizzleDb from "@/db"; +import {count, eq} from "drizzle-orm"; +import {logger} from "@/lib/logger"; +import type { SignUpUser } from "@/types/auth"; +import {env} from "@/env.mjs"; +import {createUserDb} from "@/db/services/user"; + +const log = logger.child({module: "init/user"}); + +export async function createDefaultUser() { + + const hasRequiredEnv = + env.AUTH_DEFAULT_USER && + env.AUTH_DEFAULT_PASSWORD && + env.AUTH_DEFAULT_USER_NAME; + + if (!hasRequiredEnv) { + log.info( + "Default admin creation skipped: missing environment variables.", + ); + return; + } + + log.info("Checking default super admin..."); + + const existingSuperAdmin = await db.query.user.findFirst({ + where: eq(drizzleDb.schemas.user.role, "superadmin"), + }); + + if (existingSuperAdmin) { + log.info( + `CreateDefaultUser skipped: a superadmin already exists (${existingSuperAdmin.email}).`, + ); + return; + } + + const userData: SignUpUser = { + name: env.AUTH_DEFAULT_USER_NAME!, + email: env.AUTH_DEFAULT_USER!, + password: env.AUTH_DEFAULT_PASSWORD!, + theme: "system", + role: "superadmin", + emailVerified: true, + }; + + + const newUser = await createUserDb(userData); + + if (newUser) { + log.info(`Default super admin created (${userData.email}).`); + + const defaultOrgSlug = "default"; + const defaultOrg = await db.query.organization.findFirst({ + where: eq(drizzleDb.schemas.organization.slug, defaultOrgSlug), + }); + + if (defaultOrg) { + await db.insert(drizzleDb.schemas.member).values({ + userId: newUser.id, + organizationId: defaultOrg.id, + role: "owner", + }); + } else { + log.warn( + "Default organization not found. Cannot assign member.", + ); + } + + } +} diff --git a/src/utils/password.ts b/src/utils/password.ts index 53b07108..f88fe7e4 100644 --- a/src/utils/password.ts +++ b/src/utils/password.ts @@ -24,4 +24,61 @@ export function generateValidPassword(length = 12) { } return passwordChars.join(''); +} + + +export interface PasswordValidationResult { + valid: boolean; + errors: string[]; + score: number; +} + +const PASSWORD_RULES = [ + { + key: "minLength", + regex: /.{8,}/, + message: "Password must contain at least 8 characters", + }, + { + key: "number", + regex: /[0-9]/, + message: "Password must contain at least 1 number", + }, + { + key: "lowercase", + regex: /[a-z]/, + message: "Password must contain at least 1 lowercase letter", + }, + { + key: "uppercase", + regex: /[A-Z]/, + message: "Password must contain at least 1 uppercase letter", + }, + { + key: "specialChar", + regex: /[^a-zA-Z0-9]/, + message: "Password must contain at least 1 special character", + }, +]; + +export function validatePassword( + password: string, +): PasswordValidationResult { + const failedRules = PASSWORD_RULES.filter( + (rule) => !rule.regex.test(password), + ); + + return { + valid: failedRules.length === 0, + errors: failedRules.map((r) => r.message), + score: PASSWORD_RULES.length - failedRules.length, + }; +} + +export function assertValidPassword(password: string) { + const result = validatePassword(password); + + if (!result.valid) { + throw new Error(result.errors.join(", ")); + } } \ No newline at end of file From 27f6b746e0427fd7e060e094ee23f7f6fd07c0d0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 21 May 2026 05:28:56 +0000 Subject: [PATCH 4/6] chore: release 1.15.2 --- CITATION.cff | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 9e621318..94b2e28e 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -33,5 +33,5 @@ keywords: - web-ui - agent license: Apache-2.0 -version: 1.15.1 +version: 1.15.2 date-released: '2026-03-02' diff --git a/package.json b/package.json index 5aa8d6da..cce5ea5a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "portabase", - "version": "1.15.1", + "version": "1.15.2", "private": true, "scripts": { "dev": "next dev --turbopack -p 8887", From 965b2152244ee8f41ad320c073d7a5782df25c7d Mon Sep 17 00:00:00 2001 From: Charles GTE Date: Thu, 21 May 2026 07:51:08 +0200 Subject: [PATCH 5/6] fix: replace integer column with bigint for size (#295) Co-authored-by: charles-gauthereau --- .../0055_yielding_justin_hammer.sql | 2 + src/db/migrations/meta/0055_snapshot.json | 2662 +++++++++++++++++ src/db/migrations/meta/_journal.json | 7 + src/db/schema/07_database.ts | 4 +- src/db/schema/14_storage-backup.ts | 4 +- 5 files changed, 2675 insertions(+), 4 deletions(-) create mode 100644 src/db/migrations/0055_yielding_justin_hammer.sql create mode 100644 src/db/migrations/meta/0055_snapshot.json diff --git a/src/db/migrations/0055_yielding_justin_hammer.sql b/src/db/migrations/0055_yielding_justin_hammer.sql new file mode 100644 index 00000000..ebba3b08 --- /dev/null +++ b/src/db/migrations/0055_yielding_justin_hammer.sql @@ -0,0 +1,2 @@ +ALTER TABLE "backups" ALTER COLUMN "file_size" SET DATA TYPE bigint;--> statement-breakpoint +ALTER TABLE "backup_storage" ALTER COLUMN "size" SET DATA TYPE bigint; \ No newline at end of file diff --git a/src/db/migrations/meta/0055_snapshot.json b/src/db/migrations/meta/0055_snapshot.json new file mode 100644 index 00000000..3c734bac --- /dev/null +++ b/src/db/migrations/meta/0055_snapshot.json @@ -0,0 +1,2662 @@ +{ + "id": "da218fef-3968-4e1c-bdb0-343e993551f5", + "prevId": "fd6127d5-7918-47c3-b070-7a272fddc2b9", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.settings": { + "name": "settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "smtp_password": { + "name": "smtp_password", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "smtp_from": { + "name": "smtp_from", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "smtp_host": { + "name": "smtp_host", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "smtp_port": { + "name": "smtp_port", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "smtp_user": { + "name": "smtp_user", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "smtp_secure": { + "name": "smtp_secure", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "default_notification_channel_id": { + "name": "default_notification_channel_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "default_storage_channel_id": { + "name": "default_storage_channel_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "encryption": { + "name": "encryption", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "settings_default_notification_channel_id_notification_channel_id_fk": { + "name": "settings_default_notification_channel_id_notification_channel_id_fk", + "tableFrom": "settings", + "tableTo": "notification_channel", + "columnsFrom": [ + "default_notification_channel_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "settings_default_storage_channel_id_storage_channel_id_fk": { + "name": "settings_default_storage_channel_id_storage_channel_id_fk", + "tableFrom": "settings", + "tableTo": "storage_channel", + "columnsFrom": [ + "default_storage_channel_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "settings_name_unique": { + "name": "settings_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "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": "uuid", + "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 + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "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.passkey": { + "name": "passkey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "publicKey": { + "name": "publicKey", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "credentialID": { + "name": "credentialID", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "counter": { + "name": "counter", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "deviceType": { + "name": "deviceType", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "backedUp": { + "name": "backedUp", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "transports": { + "name": "transports", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "aaguid": { + "name": "aaguid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "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.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "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": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "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.sso_provider": { + "name": "sso_provider", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "issuer": { + "name": "issuer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "oidc_config": { + "name": "oidc_config", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "saml_config": { + "name": "saml_config", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "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": "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.two_factor": { + "name": "two_factor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "backup_codes": { + "name": "backup_codes", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "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.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "theme": { + "name": "theme", + "type": "user_themes", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'light'" + }, + "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 + }, + "lastConnectedAt": { + "name": "lastConnectedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "lastChangedPasswordAt": { + "name": "lastChangedPasswordAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "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.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "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 + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization": { + "name": "organization", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.member": { + "name": "member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "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.invitation": { + "name": "invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "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": "uuid", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "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.projects": { + "name": "projects", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_archived": { + "name": "is_archived", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "projects_organization_id_organization_id_fk": { + "name": "projects_organization_id_organization_id_fk", + "tableFrom": "projects", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "projects_slug_unique": { + "name": "projects_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backups": { + "name": "backups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "status": { + "name": "status", + "type": "status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'waiting'" + }, + "file": { + "name": "file", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_size": { + "name": "file_size", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "database_id": { + "name": "database_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "imported": { + "name": "imported", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "migrated": { + "name": "migrated", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backups_database_id_databases_id_fk": { + "name": "backups_database_id_databases_id_fk", + "tableFrom": "backups", + "tableTo": "databases", + "columnsFrom": [ + "database_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.databases": { + "name": "databases", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "agent_database_id": { + "name": "agent_database_id", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dbms": { + "name": "dbms", + "type": "dbms_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "backup_policy": { + "name": "backup_policy", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_waiting_for_backup": { + "name": "is_waiting_for_backup", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "backup_to_restore": { + "name": "backup_to_restore", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "health_error_count": { + "name": "health_error_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "last_contact": { + "name": "last_contact", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "databases_agent_id_agents_id_fk": { + "name": "databases_agent_id_agents_id_fk", + "tableFrom": "databases", + "tableTo": "agents", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "databases_project_id_projects_id_fk": { + "name": "databases_project_id_projects_id_fk", + "tableFrom": "databases", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.restorations": { + "name": "restorations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "status": { + "name": "status", + "type": "status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'waiting'" + }, + "backup_storage_id": { + "name": "backup_storage_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "backup_id": { + "name": "backup_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "database_id": { + "name": "database_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "restorations_backup_storage_id_backup_storage_id_fk": { + "name": "restorations_backup_storage_id_backup_storage_id_fk", + "tableFrom": "restorations", + "tableTo": "backup_storage", + "columnsFrom": [ + "backup_storage_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "restorations_backup_id_backups_id_fk": { + "name": "restorations_backup_id_backups_id_fk", + "tableFrom": "restorations", + "tableTo": "backups", + "columnsFrom": [ + "backup_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "restorations_database_id_databases_id_fk": { + "name": "restorations_database_id_databases_id_fk", + "tableFrom": "restorations", + "tableTo": "databases", + "columnsFrom": [ + "database_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.retention_policies": { + "name": "retention_policies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "database_id": { + "name": "database_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "retention_policy_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "count": { + "name": "count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 7 + }, + "days": { + "name": "days", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 30 + }, + "gfs_daily": { + "name": "gfs_daily", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 7 + }, + "gfs_weekly": { + "name": "gfs_weekly", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 4 + }, + "gfs_monthly": { + "name": "gfs_monthly", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 12 + }, + "gfs_yearly": { + "name": "gfs_yearly", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "retention_policies_database_id_databases_id_fk": { + "name": "retention_policies_database_id_databases_id_fk", + "tableFrom": "retention_policies", + "tableTo": "databases", + "columnsFrom": [ + "database_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.agents": { + "name": "agents", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "health_error_count": { + "name": "health_error_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_archived": { + "name": "is_archived", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "last_contact": { + "name": "last_contact", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "agents_organization_id_organization_id_fk": { + "name": "agents_organization_id_organization_id_fk", + "tableFrom": "agents", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "agents_slug_unique": { + "name": "agents_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_agents": { + "name": "organization_agents", + "schema": "", + "columns": { + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "organization_agents_organization_id_organization_id_fk": { + "name": "organization_agents_organization_id_organization_id_fk", + "tableFrom": "organization_agents", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_agents_agent_id_agents_id_fk": { + "name": "organization_agents_agent_id_agents_id_fk", + "tableFrom": "organization_agents", + "tableTo": "agents", + "columnsFrom": [ + "agent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_agents_organization_id_agent_id_unique": { + "name": "organization_agents_organization_id_agent_id_unique", + "nullsNotDistinct": false, + "columns": [ + "organization_id", + "agent_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notification_channel": { + "name": "notification_channel", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "provider": { + "name": "provider", + "type": "provider_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "notification_channel_organization_id_organization_id_fk": { + "name": "notification_channel_organization_id_organization_id_fk", + "tableFrom": "notification_channel", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_notification_channels": { + "name": "organization_notification_channels", + "schema": "", + "columns": { + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "notification_channel_id": { + "name": "notification_channel_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "organization_notification_channels_organization_id_organization_id_fk": { + "name": "organization_notification_channels_organization_id_organization_id_fk", + "tableFrom": "organization_notification_channels", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_notification_channels_notification_channel_id_notification_channel_id_fk": { + "name": "organization_notification_channels_notification_channel_id_notification_channel_id_fk", + "tableFrom": "organization_notification_channels", + "tableTo": "notification_channel", + "columnsFrom": [ + "notification_channel_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_notification_channels_organization_id_notification_channel_id_unique": { + "name": "organization_notification_channels_organization_id_notification_channel_id_unique", + "nullsNotDistinct": false, + "columns": [ + "organization_id", + "notification_channel_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.alert_policy": { + "name": "alert_policy", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "notification_channel_id": { + "name": "notification_channel_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_kind": { + "name": "event_kind", + "type": "event_kind[]", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "database_id": { + "name": "database_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "alert_policy_notification_channel_id_notification_channel_id_fk": { + "name": "alert_policy_notification_channel_id_notification_channel_id_fk", + "tableFrom": "alert_policy", + "tableTo": "notification_channel", + "columnsFrom": [ + "notification_channel_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "alert_policy_database_id_databases_id_fk": { + "name": "alert_policy_database_id_databases_id_fk", + "tableFrom": "alert_policy", + "tableTo": "databases", + "columnsFrom": [ + "database_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notification_log": { + "name": "notification_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "channel_id": { + "name": "channel_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "policy_id": { + "name": "policy_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "event": { + "name": "event", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_name": { + "name": "provider_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "level", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "success": { + "name": "success", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_response": { + "name": "provider_response", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "sent_at": { + "name": "sent_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_storage_channels": { + "name": "organization_storage_channels", + "schema": "", + "columns": { + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "storage_channel_id": { + "name": "storage_channel_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "organization_storage_channels_organization_id_organization_id_fk": { + "name": "organization_storage_channels_organization_id_organization_id_fk", + "tableFrom": "organization_storage_channels", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_storage_channels_storage_channel_id_storage_channel_id_fk": { + "name": "organization_storage_channels_storage_channel_id_storage_channel_id_fk", + "tableFrom": "organization_storage_channels", + "tableTo": "storage_channel", + "columnsFrom": [ + "storage_channel_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_storage_channels_organization_id_storage_channel_id_unique": { + "name": "organization_storage_channels_organization_id_storage_channel_id_unique", + "nullsNotDistinct": false, + "columns": [ + "organization_id", + "storage_channel_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.storage_channel": { + "name": "storage_channel", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "provider_storage_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "storage_channel_organization_id_organization_id_fk": { + "name": "storage_channel_organization_id_organization_id_fk", + "tableFrom": "storage_channel", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.storage_policy": { + "name": "storage_policy", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "storage_channel_id": { + "name": "storage_channel_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "database_id": { + "name": "database_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "storage_policy_storage_channel_id_storage_channel_id_fk": { + "name": "storage_policy_storage_channel_id_storage_channel_id_fk", + "tableFrom": "storage_policy", + "tableTo": "storage_channel", + "columnsFrom": [ + "storage_channel_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "storage_policy_database_id_databases_id_fk": { + "name": "storage_policy_database_id_databases_id_fk", + "tableFrom": "storage_policy", + "tableTo": "databases", + "columnsFrom": [ + "database_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.backup_storage": { + "name": "backup_storage", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "backup_id": { + "name": "backup_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "storage_channel_id": { + "name": "storage_channel_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "backup_storage_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "size": { + "name": "size", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "backup_storage_backup_id_backups_id_fk": { + "name": "backup_storage_backup_id_backups_id_fk", + "tableFrom": "backup_storage", + "tableTo": "backups", + "columnsFrom": [ + "backup_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "backup_storage_storage_channel_id_storage_channel_id_fk": { + "name": "backup_storage_storage_channel_id_storage_channel_id_fk", + "tableFrom": "backup_storage", + "tableTo": "storage_channel", + "columnsFrom": [ + "storage_channel_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.healthcheck_log": { + "name": "healthcheck_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "kind": { + "name": "kind", + "type": "healthcheck_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "healthcheck_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "object_id": { + "name": "object_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.user_themes": { + "name": "user_themes", + "schema": "public", + "values": [ + "light", + "dark", + "system" + ] + }, + "public.retention_policy_type": { + "name": "retention_policy_type", + "schema": "public", + "values": [ + "count", + "days", + "gfs" + ] + }, + "public.provider_kind": { + "name": "provider_kind", + "schema": "public", + "values": [ + "slack", + "smtp", + "discord", + "telegram", + "gotify", + "ntfy", + "webhook" + ] + }, + "public.event_kind": { + "name": "event_kind", + "schema": "public", + "values": [ + "error_backup", + "error_restore", + "success_restore", + "success_backup", + "weekly_report", + "error_health_agent", + "error_health_database" + ] + }, + "public.level": { + "name": "level", + "schema": "public", + "values": [ + "critical", + "warning", + "info" + ] + }, + "public.provider_storage_kind": { + "name": "provider_storage_kind", + "schema": "public", + "values": [ + "local", + "s3", + "google-drive" + ] + }, + "public.backup_storage_status": { + "name": "backup_storage_status", + "schema": "public", + "values": [ + "pending", + "success", + "failed" + ] + }, + "public.healthcheck_status": { + "name": "healthcheck_status", + "schema": "public", + "values": [ + "success", + "failed" + ] + }, + "public.healthcheck_kind": { + "name": "healthcheck_kind", + "schema": "public", + "values": [ + "database", + "agent" + ] + }, + "public.dbms_status": { + "name": "dbms_status", + "schema": "public", + "values": [ + "postgresql", + "mysql", + "mariadb", + "mongodb", + "sqlite", + "redis", + "valkey", + "firebird", + "mssql" + ] + }, + "public.status": { + "name": "status", + "schema": "public", + "values": [ + "waiting", + "ongoing", + "failed", + "success" + ] + }, + "public.type_storage": { + "name": "type_storage", + "schema": "public", + "values": [ + "local", + "s3" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/src/db/migrations/meta/_journal.json b/src/db/migrations/meta/_journal.json index 50d888f5..1c8d639a 100644 --- a/src/db/migrations/meta/_journal.json +++ b/src/db/migrations/meta/_journal.json @@ -386,6 +386,13 @@ "when": 1778523056918, "tag": "0054_hesitant_darkhawk", "breakpoints": true + }, + { + "idx": 55, + "version": "7", + "when": 1779342014802, + "tag": "0055_yielding_justin_hammer", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/db/schema/07_database.ts b/src/db/schema/07_database.ts index d4cc6aff..83735337 100644 --- a/src/db/schema/07_database.ts +++ b/src/db/schema/07_database.ts @@ -1,4 +1,4 @@ -import {pgTable, text, boolean, timestamp, uuid, integer, pgEnum} from "drizzle-orm/pg-core"; +import {pgTable, text, boolean, timestamp, uuid, integer, pgEnum, bigint} from "drizzle-orm/pg-core"; import {Agent, agent, AgentWith} from "./08_agent"; import {Project, project} from "./06_project"; import {relations} from "drizzle-orm"; @@ -37,7 +37,7 @@ export const backup = pgTable( id: uuid("id").primaryKey().defaultRandom(), status: statusEnum("status").default("waiting").notNull(), file: text("file"), - fileSize: integer("file_size"), + fileSize: bigint("file_size", { mode: "number" }), databaseId: uuid("database_id") .notNull() .references(() => database.id, {onDelete: "cascade"}), diff --git a/src/db/schema/14_storage-backup.ts b/src/db/schema/14_storage-backup.ts index e7dbfb22..1c9754de 100644 --- a/src/db/schema/14_storage-backup.ts +++ b/src/db/schema/14_storage-backup.ts @@ -1,4 +1,4 @@ -import { pgTable, uuid, text, integer, pgEnum } from "drizzle-orm/pg-core"; +import {pgTable, uuid, text, integer, pgEnum, bigint} from "drizzle-orm/pg-core"; import { timestamps } from "@/db/schema/00_common"; import {StorageChannel, storageChannel} from "@/db/schema/12_storage-channel"; import {Backup, backup, Restoration} from "@/db/schema/07_database"; @@ -22,7 +22,7 @@ export const backupStorage = pgTable("backup_storage", { .references(() => storageChannel.id, { onDelete: "cascade" }), status: backupStorageStatusEnum("status").notNull().default("pending"), path: text("path"), - size: integer("size"), + size: bigint("size", { mode: "number" }), checksum: text("checksum"), ...timestamps, }); From 2cd5bda41691103fbb95ddc94c3403e2978f150b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 21 May 2026 05:51:50 +0000 Subject: [PATCH 6/6] chore: release 1.15.3 --- CITATION.cff | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 94b2e28e..cf9e1878 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -33,5 +33,5 @@ keywords: - web-ui - agent license: Apache-2.0 -version: 1.15.2 +version: 1.15.3 date-released: '2026-03-02' diff --git a/package.json b/package.json index cce5ea5a..02447bd9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "portabase", - "version": "1.15.2", + "version": "1.15.3", "private": true, "scripts": { "dev": "next dev --turbopack -p 8887",