Replace entire codebase with homarr-labs/homarr

This commit is contained in:
Thomas Camlong
2026-01-15 21:54:44 +01:00
parent c5bc3b1559
commit 4fdd1fe351
4666 changed files with 409577 additions and 147434 deletions

83
packages/db/collection.ts Normal file
View File

@@ -0,0 +1,83 @@
import type { InferInsertModel } from "drizzle-orm";
import { objectEntries } from "@homarr/common";
import { dbEnv } from "@homarr/core/infrastructure/db/env";
import type { HomarrDatabase, HomarrDatabaseMysql, HomarrDatabasePostgresql } from "./driver";
import * as schema from "./schema";
type TableKey = {
[K in keyof typeof schema]: (typeof schema)[K] extends { _: { brand: "Table" } } ? K : never;
}[keyof typeof schema];
export function isMysql(): boolean {
return dbEnv.DRIVER === "mysql2";
}
export function isPostgresql(): boolean {
return dbEnv.DRIVER === "node-postgres";
}
export const createDbInsertCollectionForTransaction = <TTableKey extends TableKey>(
tablesInInsertOrder: TTableKey[],
) => {
const context = tablesInInsertOrder.reduce(
(acc, key) => {
acc[key] = [];
return acc;
},
{} as { [K in TTableKey]: InferInsertModel<(typeof schema)[K]>[] },
);
return {
...context,
insertAll: (db: HomarrDatabase) => {
db.transaction((transaction) => {
for (const [key, values] of objectEntries(context)) {
if (values.length >= 1) {
transaction
.insert(schema[key])
.values(values as never)
.run();
}
}
});
},
// We allow any database that supports async passed here but then fallback to mysql to prevent typescript errors
insertAllAsync: async (db: HomarrDatabaseMysql | HomarrDatabasePostgresql) => {
const innerDb = db as HomarrDatabaseMysql;
await innerDb.transaction(async (transaction) => {
for (const [key, values] of objectEntries(context)) {
if (values.length >= 1) {
// Below is actually the mysqlSchema when the driver is mysql
await transaction.insert(schema[key] as never).values(values as never);
}
}
});
},
};
};
export const createDbInsertCollectionWithoutTransaction = <TTableKey extends TableKey>(
tablesInInsertOrder: TTableKey[],
) => {
const { insertAll, insertAllAsync, ...collection } = createDbInsertCollectionForTransaction(tablesInInsertOrder);
return {
...collection,
insertAllAsync: async (db: HomarrDatabase) => {
switch (dbEnv.DRIVER) {
case "mysql2":
case "node-postgres":
// For mysql2 and node-postgres, we can use the async insertAllAsync method
await insertAllAsync(db as unknown as HomarrDatabaseMysql | HomarrDatabasePostgresql);
return;
default:
// For better-sqlite3, we need to use the synchronous insertAll method
// default assumes better-sqlite3. It's original implementation.
insertAll(db);
break;
}
},
};
};

View File

@@ -0,0 +1,20 @@
import type { Config } from "drizzle-kit";
import { DB_CASING } from "@homarr/core/infrastructure/db/constants";
import { dbEnv } from "@homarr/core/infrastructure/db/env";
export default {
dialect: "mysql",
schema: "./schema",
casing: DB_CASING,
dbCredentials: dbEnv.URL
? { url: dbEnv.URL }
: {
host: dbEnv.HOST,
port: dbEnv.PORT,
database: dbEnv.NAME,
user: dbEnv.USER,
password: dbEnv.PASSWORD,
},
out: "./migrations/mysql",
} satisfies Config;

View File

@@ -0,0 +1,21 @@
import type { Config } from "drizzle-kit";
import { DB_CASING } from "@homarr/core/infrastructure/db/constants";
import { dbEnv } from "@homarr/core/infrastructure/db/env";
export default {
dialect: "postgresql",
schema: "./schema",
casing: DB_CASING,
dbCredentials: dbEnv.URL
? { url: dbEnv.URL }
: {
host: dbEnv.HOST,
port: dbEnv.PORT,
database: dbEnv.NAME,
user: dbEnv.USER,
password: dbEnv.PASSWORD,
},
out: "./migrations/postgresql",
} satisfies Config;

View File

@@ -0,0 +1,12 @@
import type { Config } from "drizzle-kit";
import { DB_CASING } from "@homarr/core/infrastructure/db/constants";
import { dbEnv } from "@homarr/core/infrastructure/db/env";
export default {
dialect: "sqlite",
schema: "./schema",
casing: DB_CASING,
dbCredentials: { url: dbEnv.URL },
out: "./migrations/sqlite",
} satisfies Config;

11
packages/db/driver.ts Normal file
View File

@@ -0,0 +1,11 @@
import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3";
import type { MySql2Database } from "drizzle-orm/mysql2";
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
import type * as mysqlSchema from "./schema/mysql";
import type * as pgSchema from "./schema/postgresql";
import type * as sqliteSchema from "./schema/sqlite";
export type HomarrDatabase = BetterSQLite3Database<typeof sqliteSchema>;
export type HomarrDatabaseMysql = MySql2Database<typeof mysqlSchema>;
export type HomarrDatabasePostgresql = NodePgDatabase<typeof pgSchema>;

View File

@@ -0,0 +1,4 @@
import baseConfig from "@homarr/eslint-config/base";
/** @type {import('typescript-eslint').Config} */
export default [...baseConfig];

12
packages/db/index.ts Normal file
View File

@@ -0,0 +1,12 @@
import { createDb } from "@homarr/core/infrastructure/db";
import { schema } from "./schema";
export * from "drizzle-orm";
export type { HomarrDatabaseMysql, HomarrDatabasePostgresql } from "./driver";
export const db = createDb(schema);
export type Database = typeof db;
export { handleDiffrentDbDriverOperationsAsync as handleTransactionsAsync } from "./transactions";

View File

@@ -0,0 +1,72 @@
import SuperJSON from "superjson";
import { createId } from "@homarr/common";
import type { IntegrationKind } from "@homarr/definitions";
import { getIntegrationKindsByCategory } from "@homarr/definitions";
import { eq } from "../..";
import type { Database } from "../..";
import { items } from "../../schema";
export async function migrateReleaseWidgetProviderToOptionsAsync(db: Database) {
const existingItems = await db.query.items.findMany({
where: (items, { eq }) => eq(items.kind, "releases"),
});
const integrationKinds = getIntegrationKindsByCategory("releasesProvider");
const providerIntegrations = await db.query.integrations.findMany({
where: (integrations, { inArray }) => inArray(integrations.kind, integrationKinds),
columns: {
id: true,
kind: true,
},
});
const providerIntegrationMap = new Map<IntegrationKind, string>(
providerIntegrations.map((integration) => [integration.kind, integration.id]),
);
const updates: {
id: string;
options: object;
}[] = [];
for (const item of existingItems) {
const options = SuperJSON.parse<object>(item.options);
if (!("repositories" in options)) continue;
if (!Array.isArray(options.repositories)) continue;
if (options.repositories.length === 0) continue;
if (!options.repositories.some((repository) => "providerKey" in repository)) continue;
const updatedRepositories = options.repositories.map(
({ providerKey, ...otherFields }: { providerKey: string; [key: string]: unknown }) => {
// Ensure providerKey is camelCase
const provider = providerKey.charAt(0).toLowerCase() + providerKey.slice(1);
return {
id: createId(),
providerIntegrationId: providerIntegrationMap.get(provider as IntegrationKind) ?? null,
...otherFields,
};
},
);
updates.push({
id: item.id,
options: {
...options,
repositories: updatedRepositories,
},
});
}
for (const update of updates) {
await db
.update(items)
.set({
options: SuperJSON.stringify(update.options),
})
.where(eq(items.id, update.id));
}
console.log(`Migrated release widget providers to integrations count="${updates.length}"`);
}

View File

@@ -0,0 +1,52 @@
import type { Database } from "../..";
import { and, eq } from "../..";
import { integrationSecrets } from "../../schema";
/**
* Previously the credentials for OPNsense were stored as username and password.
* However it should have been the api key and secret.
* For more information see:
* https://docs.opnsense.org/development/how-tos/api.html#creating-keys
*/
export async function migrateOpnsenseCredentialsAsync(db: Database) {
const existingIntegrations = await db.query.integrations.findMany({
where: (table, { eq }) => eq(table.kind, "opnsense"),
with: {
secrets: true,
},
});
await Promise.all(
existingIntegrations.map(async (integration) => {
const username = integration.secrets.find((secret) => secret.kind === "username");
if (!username) return;
await db
.update(integrationSecrets)
.set({
kind: "opnsenseApiKey",
})
.where(
and(eq(integrationSecrets.integrationId, username.integrationId), eq(integrationSecrets.kind, "username")),
);
}),
);
await Promise.all(
existingIntegrations.map(async (integration) => {
const password = integration.secrets.find((secret) => secret.kind === "password");
if (!password) return;
await db
.update(integrationSecrets)
.set({
kind: "opnsenseApiSecret",
})
.where(
and(eq(integrationSecrets.integrationId, password.integrationId), eq(integrationSecrets.kind, "password")),
);
}),
);
if (existingIntegrations.length > 0) {
console.log(`Migrated OPNsense credentials count="${existingIntegrations.length}"`);
}
}

View File

@@ -0,0 +1,43 @@
import SuperJSON from "superjson";
import { eq } from "../..";
import type { Database } from "../..";
import { items } from "../../schema";
/**
* To support showing the description in the widget itself we replaced
* the tooltip show option with display mode.
*/
export async function migrateAppWidgetShowDescriptionTooltipToDisplayModeAsync(db: Database) {
const existingAppItems = await db.query.items.findMany({
where: (table, { eq }) => eq(table.kind, "app"),
});
const itemsToUpdate = existingAppItems
.map((item) => ({
id: item.id,
options: SuperJSON.parse<{ showDescriptionTooltip?: boolean }>(item.options),
}))
.filter((item) => item.options.showDescriptionTooltip !== undefined);
console.log(
`Migrating app items with showDescriptionTooltip to descriptionDisplayMode count=${itemsToUpdate.length}`,
);
await Promise.all(
itemsToUpdate.map(async (item) => {
const { showDescriptionTooltip, ...options } = item.options;
await db
.update(items)
.set({
options: SuperJSON.stringify({
...options,
descriptionDisplayMode: showDescriptionTooltip ? "tooltip" : "hidden",
}),
})
.where(eq(items.id, item.id));
}),
);
console.log(`Migrated app items with showDescriptionTooltip to descriptionDisplayMode count=${itemsToUpdate.length}`);
}

View File

@@ -0,0 +1,10 @@
import type { Database } from "../..";
import { migrateReleaseWidgetProviderToOptionsAsync } from "./0000_release_widget_provider_to_options";
import { migrateOpnsenseCredentialsAsync } from "./0001_opnsense_credentials";
import { migrateAppWidgetShowDescriptionTooltipToDisplayModeAsync } from "./0002_app_widget_show_description_tooltip_to_display_mode";
export const applyCustomMigrationsAsync = async (db: Database) => {
await migrateReleaseWidgetProviderToOptionsAsync(db);
await migrateOpnsenseCredentialsAsync(db);
await migrateAppWidgetShowDescriptionTooltipToDisplayModeAsync(db);
};

View File

@@ -0,0 +1,12 @@
import { applyCustomMigrationsAsync } from ".";
import { db } from "../..";
applyCustomMigrationsAsync(db)
.then(() => {
console.log("Custom migrations applied successfully");
process.exit(0);
})
.catch((err) => {
console.log("Failed to apply custom migrations\n\t", err);
process.exit(1);
});

View File

@@ -0,0 +1,193 @@
CREATE TABLE `account` (
`userId` varchar(64) NOT NULL,
`type` text NOT NULL,
`provider` varchar(64) NOT NULL,
`providerAccountId` varchar(64) NOT NULL,
`refresh_token` text,
`access_token` text,
`expires_at` int,
`token_type` text,
`scope` text,
`id_token` text,
`session_state` text,
CONSTRAINT `account_provider_providerAccountId_pk` PRIMARY KEY(`provider`,`providerAccountId`)
);
--> statement-breakpoint
CREATE TABLE `app` (
`id` varchar(64) NOT NULL,
`name` text NOT NULL,
`description` text,
`icon_url` text NOT NULL,
`href` text,
CONSTRAINT `app_id` PRIMARY KEY(`id`)
);
--> statement-breakpoint
CREATE TABLE `boardGroupPermission` (
`board_id` varchar(64) NOT NULL,
`group_id` varchar(64) NOT NULL,
`permission` varchar(128) NOT NULL,
CONSTRAINT `boardGroupPermission_board_id_group_id_permission_pk` PRIMARY KEY(`board_id`,`group_id`,`permission`)
);
--> statement-breakpoint
CREATE TABLE `boardUserPermission` (
`board_id` varchar(64) NOT NULL,
`user_id` varchar(64) NOT NULL,
`permission` varchar(128) NOT NULL,
CONSTRAINT `boardUserPermission_board_id_user_id_permission_pk` PRIMARY KEY(`board_id`,`user_id`,`permission`)
);
--> statement-breakpoint
CREATE TABLE `board` (
`id` varchar(64) NOT NULL,
`name` varchar(256) NOT NULL,
`is_public` boolean NOT NULL DEFAULT false,
`creator_id` varchar(64),
`page_title` text,
`meta_title` text,
`logo_image_url` text,
`favicon_image_url` text,
`background_image_url` text,
`background_image_attachment` text NOT NULL DEFAULT ('fixed'),
`background_image_repeat` text NOT NULL DEFAULT ('no-repeat'),
`background_image_size` text NOT NULL DEFAULT ('cover'),
`primary_color` text NOT NULL DEFAULT ('#fa5252'),
`secondary_color` text NOT NULL DEFAULT ('#fd7e14'),
`opacity` int NOT NULL DEFAULT 100,
`custom_css` text,
`column_count` int NOT NULL DEFAULT 10,
CONSTRAINT `board_id` PRIMARY KEY(`id`),
CONSTRAINT `board_name_unique` UNIQUE(`name`)
);
--> statement-breakpoint
CREATE TABLE `groupMember` (
`groupId` varchar(64) NOT NULL,
`userId` varchar(64) NOT NULL,
CONSTRAINT `groupMember_groupId_userId_pk` PRIMARY KEY(`groupId`,`userId`)
);
--> statement-breakpoint
CREATE TABLE `groupPermission` (
`groupId` varchar(64) NOT NULL,
`permission` text NOT NULL
);
--> statement-breakpoint
CREATE TABLE `group` (
`id` varchar(64) NOT NULL,
`name` varchar(64) NOT NULL,
`owner_id` varchar(64),
CONSTRAINT `group_id` PRIMARY KEY(`id`)
);
--> statement-breakpoint
CREATE TABLE `iconRepository` (
`iconRepository_id` varchar(64) NOT NULL,
`iconRepository_slug` varchar(150) NOT NULL,
CONSTRAINT `iconRepository_iconRepository_id` PRIMARY KEY(`iconRepository_id`)
);
--> statement-breakpoint
CREATE TABLE `icon` (
`icon_id` varchar(64) NOT NULL,
`icon_name` varchar(250) NOT NULL,
`icon_url` text NOT NULL,
`icon_checksum` text NOT NULL,
`iconRepository_id` varchar(64) NOT NULL,
CONSTRAINT `icon_icon_id` PRIMARY KEY(`icon_id`)
);
--> statement-breakpoint
CREATE TABLE `integration_item` (
`item_id` varchar(64) NOT NULL,
`integration_id` varchar(64) NOT NULL,
CONSTRAINT `integration_item_item_id_integration_id_pk` PRIMARY KEY(`item_id`,`integration_id`)
);
--> statement-breakpoint
CREATE TABLE `integrationSecret` (
`kind` varchar(16) NOT NULL,
`value` text NOT NULL,
`updated_at` timestamp NOT NULL,
`integration_id` varchar(64) NOT NULL,
CONSTRAINT `integrationSecret_integration_id_kind_pk` PRIMARY KEY(`integration_id`,`kind`)
);
--> statement-breakpoint
CREATE TABLE `integration` (
`id` varchar(64) NOT NULL,
`name` text NOT NULL,
`url` text NOT NULL,
`kind` varchar(128) NOT NULL,
CONSTRAINT `integration_id` PRIMARY KEY(`id`)
);
--> statement-breakpoint
CREATE TABLE `invite` (
`id` varchar(64) NOT NULL,
`token` varchar(512) NOT NULL,
`expiration_date` timestamp NOT NULL,
`creator_id` varchar(64) NOT NULL,
CONSTRAINT `invite_id` PRIMARY KEY(`id`),
CONSTRAINT `invite_token_unique` UNIQUE(`token`)
);
--> statement-breakpoint
CREATE TABLE `item` (
`id` varchar(64) NOT NULL,
`section_id` varchar(64) NOT NULL,
`kind` text NOT NULL,
`x_offset` int NOT NULL,
`y_offset` int NOT NULL,
`width` int NOT NULL,
`height` int NOT NULL,
`options` text NOT NULL DEFAULT ('{"json": {}}'),
CONSTRAINT `item_id` PRIMARY KEY(`id`)
);
--> statement-breakpoint
CREATE TABLE `section` (
`id` varchar(64) NOT NULL,
`board_id` varchar(64) NOT NULL,
`kind` text NOT NULL,
`position` int NOT NULL,
`name` text,
CONSTRAINT `section_id` PRIMARY KEY(`id`)
);
--> statement-breakpoint
CREATE TABLE `session` (
`sessionToken` varchar(512) NOT NULL,
`userId` varchar(64) NOT NULL,
`expires` timestamp NOT NULL,
CONSTRAINT `session_sessionToken` PRIMARY KEY(`sessionToken`)
);
--> statement-breakpoint
CREATE TABLE `user` (
`id` varchar(64) NOT NULL,
`name` text,
`email` text,
`emailVerified` timestamp,
`image` text,
`password` text,
`salt` text,
CONSTRAINT `user_id` PRIMARY KEY(`id`)
);
--> statement-breakpoint
CREATE TABLE `verificationToken` (
`identifier` varchar(64) NOT NULL,
`token` varchar(512) NOT NULL,
`expires` timestamp NOT NULL,
CONSTRAINT `verificationToken_identifier_token_pk` PRIMARY KEY(`identifier`,`token`)
);
--> statement-breakpoint
ALTER TABLE `account` ADD CONSTRAINT `account_userId_user_id_fk` FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `boardGroupPermission` ADD CONSTRAINT `boardGroupPermission_board_id_board_id_fk` FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `boardGroupPermission` ADD CONSTRAINT `boardGroupPermission_group_id_group_id_fk` FOREIGN KEY (`group_id`) REFERENCES `group`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `boardUserPermission` ADD CONSTRAINT `boardUserPermission_board_id_board_id_fk` FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `boardUserPermission` ADD CONSTRAINT `boardUserPermission_user_id_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `board` ADD CONSTRAINT `board_creator_id_user_id_fk` FOREIGN KEY (`creator_id`) REFERENCES `user`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `groupMember` ADD CONSTRAINT `groupMember_groupId_group_id_fk` FOREIGN KEY (`groupId`) REFERENCES `group`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `groupMember` ADD CONSTRAINT `groupMember_userId_user_id_fk` FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `groupPermission` ADD CONSTRAINT `groupPermission_groupId_group_id_fk` FOREIGN KEY (`groupId`) REFERENCES `group`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `group` ADD CONSTRAINT `group_owner_id_user_id_fk` FOREIGN KEY (`owner_id`) REFERENCES `user`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `icon` ADD CONSTRAINT `icon_iconRepository_id_iconRepository_iconRepository_id_fk` FOREIGN KEY (`iconRepository_id`) REFERENCES `iconRepository`(`iconRepository_id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `integration_item` ADD CONSTRAINT `integration_item_item_id_item_id_fk` FOREIGN KEY (`item_id`) REFERENCES `item`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `integration_item` ADD CONSTRAINT `integration_item_integration_id_integration_id_fk` FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `integrationSecret` ADD CONSTRAINT `integrationSecret_integration_id_integration_id_fk` FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `invite` ADD CONSTRAINT `invite_creator_id_user_id_fk` FOREIGN KEY (`creator_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `item` ADD CONSTRAINT `item_section_id_section_id_fk` FOREIGN KEY (`section_id`) REFERENCES `section`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `section` ADD CONSTRAINT `section_board_id_board_id_fk` FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `session` ADD CONSTRAINT `session_userId_user_id_fk` FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX `userId_idx` ON `account` (`userId`);--> statement-breakpoint
CREATE INDEX `integration_secret__kind_idx` ON `integrationSecret` (`kind`);--> statement-breakpoint
CREATE INDEX `integration_secret__updated_at_idx` ON `integrationSecret` (`updated_at`);--> statement-breakpoint
CREATE INDEX `integration__kind_idx` ON `integration` (`kind`);--> statement-breakpoint
CREATE INDEX `user_id_idx` ON `session` (`userId`);

View File

@@ -0,0 +1,2 @@
ALTER TABLE `user` ADD `homeBoardId` varchar(64);--> statement-breakpoint
ALTER TABLE `user` ADD CONSTRAINT `user_homeBoardId_board_id_fk` FOREIGN KEY (`homeBoardId`) REFERENCES `board`(`id`) ON DELETE set null ON UPDATE no action;

View File

@@ -0,0 +1 @@
ALTER TABLE `item` ADD `advanced_options` text DEFAULT ('{"json": {}}') NOT NULL;

View File

@@ -0,0 +1,6 @@
CREATE TABLE `serverSetting` (
`key` varchar(64) NOT NULL,
`value` text NOT NULL DEFAULT ('{"json": {}}'),
CONSTRAINT `serverSetting_key` PRIMARY KEY(`key`),
CONSTRAINT `serverSetting_key_unique` UNIQUE(`key`)
);

View File

@@ -0,0 +1,18 @@
CREATE TABLE `integrationGroupPermissions` (
`integration_id` varchar(64) NOT NULL,
`group_id` varchar(64) NOT NULL,
`permission` varchar(128) NOT NULL,
CONSTRAINT `integration_group_permission__pk` PRIMARY KEY(`integration_id`,`group_id`,`permission`)
);
--> statement-breakpoint
CREATE TABLE `integrationUserPermission` (
`integration_id` varchar(64) NOT NULL,
`user_id` varchar(64) NOT NULL,
`permission` varchar(128) NOT NULL,
CONSTRAINT `integrationUserPermission_integration_id_user_id_permission_pk` PRIMARY KEY(`integration_id`,`user_id`,`permission`)
);
--> statement-breakpoint
ALTER TABLE `integrationGroupPermissions` ADD CONSTRAINT `integrationGroupPermissions_integration_id_integration_id_fk` FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `integrationGroupPermissions` ADD CONSTRAINT `integrationGroupPermissions_group_id_group_id_fk` FOREIGN KEY (`group_id`) REFERENCES `group`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `integrationUserPermission` ADD CONSTRAINT `integrationUserPermission_integration_id_integration_id_fk` FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `integrationUserPermission` ADD CONSTRAINT `integrationUserPermission_user_id_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;

View File

@@ -0,0 +1 @@
ALTER TABLE `user` ADD `provider` varchar(64) DEFAULT 'credentials' NOT NULL;

View File

@@ -0,0 +1,6 @@
ALTER TABLE `section` RENAME COLUMN `position` TO `y_offset`;--> statement-breakpoint
ALTER TABLE `section` ADD `x_offset` int NOT NULL;--> statement-breakpoint
ALTER TABLE `section` ADD `width` int;--> statement-breakpoint
ALTER TABLE `section` ADD `height` int;--> statement-breakpoint
ALTER TABLE `section` ADD `parent_section_id` varchar(64);--> statement-breakpoint
ALTER TABLE `section` ADD CONSTRAINT `section_parent_section_id_section_id_fk` FOREIGN KEY (`parent_section_id`) REFERENCES `section`(`id`) ON DELETE cascade ON UPDATE no action;

View File

@@ -0,0 +1 @@
ALTER TABLE `user` ADD `colorScheme` varchar(5) DEFAULT 'auto' NOT NULL;

View File

@@ -0,0 +1,9 @@
CREATE TABLE `search_engine` (
`id` varchar(64) NOT NULL,
`icon_url` text NOT NULL,
`name` varchar(64) NOT NULL,
`short` varchar(8) NOT NULL,
`description` text,
`url_template` text NOT NULL,
CONSTRAINT `search_engine_id` PRIMARY KEY(`id`)
);

View File

@@ -0,0 +1,9 @@
CREATE TABLE `apiKey` (
`id` varchar(64) NOT NULL,
`apiKey` text NOT NULL,
`salt` text NOT NULL,
`userId` varchar(64) NOT NULL,
CONSTRAINT `apiKey_id` PRIMARY KEY(`id`)
);
--> statement-breakpoint
ALTER TABLE `apiKey` ADD CONSTRAINT `apiKey_userId_user_id_fk` FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;

View File

@@ -0,0 +1 @@
ALTER TABLE `user` ADD `firstDayOfWeek` tinyint DEFAULT 1 NOT NULL;

View File

@@ -0,0 +1 @@
ALTER TABLE `user` ADD `pingIconsEnabled` boolean DEFAULT false NOT NULL;

View File

@@ -0,0 +1 @@
ALTER TABLE `user` MODIFY COLUMN `colorScheme` varchar(5) NOT NULL DEFAULT 'dark';

View File

@@ -0,0 +1 @@
ALTER TABLE `group` ADD CONSTRAINT `group_name_unique` UNIQUE(`name`);

View File

@@ -0,0 +1,12 @@
CREATE TABLE `media` (
`id` varchar(64) NOT NULL,
`name` varchar(512) NOT NULL,
`content` BLOB NOT NULL,
`content_type` text NOT NULL,
`size` int NOT NULL,
`created_at` timestamp NOT NULL DEFAULT (now()),
`creator_id` varchar(64),
CONSTRAINT `media_id` PRIMARY KEY(`id`)
);
--> statement-breakpoint
ALTER TABLE `media` ADD CONSTRAINT `media_creator_id_user_id_fk` FOREIGN KEY (`creator_id`) REFERENCES `user`(`id`) ON DELETE set null ON UPDATE no action;

View File

@@ -0,0 +1,4 @@
ALTER TABLE `search_engine` MODIFY COLUMN `url_template` text;--> statement-breakpoint
ALTER TABLE `search_engine` ADD `type` varchar(64) DEFAULT 'generic' NOT NULL;--> statement-breakpoint
ALTER TABLE `search_engine` ADD `integration_id` varchar(64);--> statement-breakpoint
ALTER TABLE `search_engine` ADD CONSTRAINT `search_engine_integration_id_integration_id_fk` FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON DELETE cascade ON UPDATE no action;

View File

@@ -0,0 +1,64 @@
ALTER TABLE `account` RENAME COLUMN `userId` TO `user_id`;--> statement-breakpoint
ALTER TABLE `account` RENAME COLUMN `providerAccountId` TO `provider_account_id`;--> statement-breakpoint
ALTER TABLE `apiKey` RENAME COLUMN `apiKey` TO `api_key`;--> statement-breakpoint
ALTER TABLE `apiKey` RENAME COLUMN `userId` TO `user_id`;--> statement-breakpoint
ALTER TABLE `groupMember` RENAME COLUMN `groupId` TO `group_id`;--> statement-breakpoint
ALTER TABLE `groupMember` RENAME COLUMN `userId` TO `user_id`;--> statement-breakpoint
ALTER TABLE `groupPermission` RENAME COLUMN `groupId` TO `group_id`;--> statement-breakpoint
ALTER TABLE `iconRepository` RENAME COLUMN `iconRepository_id` TO `id`;--> statement-breakpoint
ALTER TABLE `iconRepository` RENAME COLUMN `iconRepository_slug` TO `slug`;--> statement-breakpoint
ALTER TABLE `icon` RENAME COLUMN `icon_id` TO `id`;--> statement-breakpoint
ALTER TABLE `icon` RENAME COLUMN `icon_name` TO `name`;--> statement-breakpoint
ALTER TABLE `icon` RENAME COLUMN `icon_url` TO `url`;--> statement-breakpoint
ALTER TABLE `icon` RENAME COLUMN `icon_checksum` TO `checksum`;--> statement-breakpoint
ALTER TABLE `icon` RENAME COLUMN `iconRepository_id` TO `icon_repository_id`;--> statement-breakpoint
ALTER TABLE `serverSetting` RENAME COLUMN `key` TO `setting_key`;--> statement-breakpoint
ALTER TABLE `session` RENAME COLUMN `sessionToken` TO `session_token`;--> statement-breakpoint
ALTER TABLE `session` RENAME COLUMN `userId` TO `user_id`;--> statement-breakpoint
ALTER TABLE `user` RENAME COLUMN `emailVerified` TO `email_verified`;--> statement-breakpoint
ALTER TABLE `user` RENAME COLUMN `homeBoardId` TO `home_board_id`;--> statement-breakpoint
ALTER TABLE `user` RENAME COLUMN `colorScheme` TO `color_scheme`;--> statement-breakpoint
ALTER TABLE `user` RENAME COLUMN `firstDayOfWeek` TO `first_day_of_week`;--> statement-breakpoint
ALTER TABLE `user` RENAME COLUMN `pingIconsEnabled` TO `ping_icons_enabled`;--> statement-breakpoint
ALTER TABLE `serverSetting` DROP INDEX `serverSetting_key_unique`;--> statement-breakpoint
ALTER TABLE `account` DROP FOREIGN KEY `account_userId_user_id_fk`;
--> statement-breakpoint
ALTER TABLE `apiKey` DROP FOREIGN KEY `apiKey_userId_user_id_fk`;
--> statement-breakpoint
ALTER TABLE `groupMember` DROP FOREIGN KEY `groupMember_groupId_group_id_fk`;
--> statement-breakpoint
ALTER TABLE `groupMember` DROP FOREIGN KEY `groupMember_userId_user_id_fk`;
--> statement-breakpoint
ALTER TABLE `groupPermission` DROP FOREIGN KEY `groupPermission_groupId_group_id_fk`;
--> statement-breakpoint
ALTER TABLE `icon` DROP FOREIGN KEY `icon_iconRepository_id_iconRepository_iconRepository_id_fk`;
--> statement-breakpoint
ALTER TABLE `session` DROP FOREIGN KEY `session_userId_user_id_fk`;
--> statement-breakpoint
ALTER TABLE `user` DROP FOREIGN KEY `user_homeBoardId_board_id_fk`;
--> statement-breakpoint
DROP INDEX `userId_idx` ON `account`;--> statement-breakpoint
DROP INDEX `user_id_idx` ON `session`;--> statement-breakpoint
ALTER TABLE `account` DROP PRIMARY KEY;--> statement-breakpoint
ALTER TABLE `groupMember` DROP PRIMARY KEY;--> statement-breakpoint
ALTER TABLE `iconRepository` DROP PRIMARY KEY;--> statement-breakpoint
ALTER TABLE `icon` DROP PRIMARY KEY;--> statement-breakpoint
ALTER TABLE `serverSetting` DROP PRIMARY KEY;--> statement-breakpoint
ALTER TABLE `session` DROP PRIMARY KEY;--> statement-breakpoint
ALTER TABLE `account` ADD PRIMARY KEY(`provider`,`provider_account_id`);--> statement-breakpoint
ALTER TABLE `groupMember` ADD PRIMARY KEY(`group_id`,`user_id`);--> statement-breakpoint
ALTER TABLE `iconRepository` ADD PRIMARY KEY(`id`);--> statement-breakpoint
ALTER TABLE `icon` ADD PRIMARY KEY(`id`);--> statement-breakpoint
ALTER TABLE `serverSetting` ADD PRIMARY KEY(`setting_key`);--> statement-breakpoint
ALTER TABLE `session` ADD PRIMARY KEY(`session_token`);--> statement-breakpoint
ALTER TABLE `serverSetting` ADD CONSTRAINT `serverSetting_settingKey_unique` UNIQUE(`setting_key`);--> statement-breakpoint
ALTER TABLE `account` ADD CONSTRAINT `account_user_id_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `apiKey` ADD CONSTRAINT `apiKey_user_id_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `groupMember` ADD CONSTRAINT `groupMember_group_id_group_id_fk` FOREIGN KEY (`group_id`) REFERENCES `group`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `groupMember` ADD CONSTRAINT `groupMember_user_id_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `groupPermission` ADD CONSTRAINT `groupPermission_group_id_group_id_fk` FOREIGN KEY (`group_id`) REFERENCES `group`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `icon` ADD CONSTRAINT `icon_icon_repository_id_iconRepository_id_fk` FOREIGN KEY (`icon_repository_id`) REFERENCES `iconRepository`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `session` ADD CONSTRAINT `session_user_id_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `user` ADD CONSTRAINT `user_home_board_id_board_id_fk` FOREIGN KEY (`home_board_id`) REFERENCES `board`(`id`) ON DELETE set null ON UPDATE no action;--> statement-breakpoint
CREATE INDEX `userId_idx` ON `account` (`user_id`);--> statement-breakpoint
CREATE INDEX `user_id_idx` ON `session` (`user_id`);

View File

@@ -0,0 +1,6 @@
CREATE TABLE `onboarding` (
`id` varchar(64) NOT NULL,
`step` varchar(64) NOT NULL,
`previous_step` varchar(64),
CONSTRAINT `onboarding_id` PRIMARY KEY(`id`)
);

View File

@@ -0,0 +1 @@
ALTER TABLE `search_engine` ADD CONSTRAINT `search_engine_short_unique` UNIQUE(`short`);

View File

@@ -0,0 +1,2 @@
ALTER TABLE `user` ADD `default_search_engine_id` varchar(64);--> statement-breakpoint
ALTER TABLE `user` ADD CONSTRAINT `user_default_search_engine_id_search_engine_id_fk` FOREIGN KEY (`default_search_engine_id`) REFERENCES `search_engine`(`id`) ON DELETE set null ON UPDATE no action;

View File

@@ -0,0 +1,2 @@
ALTER TABLE `user` ADD `mobile_home_board_id` varchar(64);--> statement-breakpoint
ALTER TABLE `user` ADD CONSTRAINT `user_mobile_home_board_id_board_id_fk` FOREIGN KEY (`mobile_home_board_id`) REFERENCES `board`(`id`) ON DELETE set null ON UPDATE no action;

View File

@@ -0,0 +1 @@
ALTER TABLE `user` ADD `open_search_in_new_tab` boolean DEFAULT false NOT NULL;

View File

@@ -0,0 +1,9 @@
CREATE TABLE `section_collapse_state` (
`user_id` varchar(64) NOT NULL,
`section_id` varchar(64) NOT NULL,
`collapsed` boolean NOT NULL DEFAULT false,
CONSTRAINT `section_collapse_state_user_id_section_id_pk` PRIMARY KEY(`user_id`,`section_id`)
);
--> statement-breakpoint
ALTER TABLE `section_collapse_state` ADD CONSTRAINT `section_collapse_state_user_id_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE `section_collapse_state` ADD CONSTRAINT `section_collapse_state_section_id_section_id_fk` FOREIGN KEY (`section_id`) REFERENCES `section`(`id`) ON DELETE cascade ON UPDATE no action;

View File

@@ -0,0 +1,2 @@
-- Custom SQL migration file, put your code below! --
-- This file is empty as there was a bug in the migration script of sqlite, missing on delete actions. See https://github.com/homarr-labs/homarr/pull/2211 --

View File

@@ -0,0 +1 @@
ALTER TABLE `board` ADD `disable_status` boolean DEFAULT false NOT NULL;

View File

@@ -0,0 +1,25 @@
ALTER TABLE `group` ADD `home_board_id` varchar(64);
--> statement-breakpoint
ALTER TABLE `group` ADD `mobile_home_board_id` varchar(64);
--> statement-breakpoint
ALTER TABLE `group` ADD `position` smallint;
--> statement-breakpoint
CREATE TABLE `temp_group` (
`id` varchar(64) NOT NULL,
`name` varchar(255) NOT NULL,
`position` smallint NOT NULL
);
--> statement-breakpoint
INSERT INTO `temp_group`(`id`, `name`, `position`) SELECT `id`, `name`, ROW_NUMBER() OVER(ORDER BY `name`) FROM `group` WHERE `name` != 'everyone';
--> statement-breakpoint
UPDATE `group` SET `position`=(SELECT `position` FROM `temp_group` WHERE `temp_group`.`id`=`group`.`id`);
--> statement-breakpoint
DROP TABLE `temp_group`;
--> statement-breakpoint
UPDATE `group` SET `position` = -1 WHERE `name` = 'everyone';
--> statement-breakpoint
ALTER TABLE `group` MODIFY `position` smallint NOT NULL;
--> statement-breakpoint
ALTER TABLE `group` ADD CONSTRAINT `group_home_board_id_board_id_fk` FOREIGN KEY (`home_board_id`) REFERENCES `board`(`id`) ON DELETE set null ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `group` ADD CONSTRAINT `group_mobile_home_board_id_board_id_fk` FOREIGN KEY (`mobile_home_board_id`) REFERENCES `board`(`id`) ON DELETE set null ON UPDATE no action;

View File

@@ -0,0 +1 @@
ALTER TABLE `board` ADD `item_radius` text DEFAULT ('lg') NOT NULL;

View File

@@ -0,0 +1 @@
ALTER TABLE `board` ADD `icon_color` text;

View File

@@ -0,0 +1 @@
ALTER TABLE `app` ADD `ping_url` text;

View File

@@ -0,0 +1,50 @@
CREATE TABLE `item_layout` (
`item_id` varchar(64) NOT NULL,
`section_id` varchar(64) NOT NULL,
`layout_id` varchar(64) NOT NULL,
`x_offset` int NOT NULL,
`y_offset` int NOT NULL,
`width` int NOT NULL,
`height` int NOT NULL,
CONSTRAINT `item_layout_item_id_section_id_layout_id_pk` PRIMARY KEY(`item_id`,`section_id`,`layout_id`)
);
--> statement-breakpoint
CREATE TABLE `layout` (
`id` varchar(64) NOT NULL,
`name` varchar(32) NOT NULL,
`board_id` varchar(64) NOT NULL,
`column_count` tinyint NOT NULL,
`breakpoint` smallint NOT NULL DEFAULT 0,
CONSTRAINT `layout_id` PRIMARY KEY(`id`)
);
--> statement-breakpoint
CREATE TABLE `section_layout` (
`section_id` varchar(64) NOT NULL,
`layout_id` varchar(64) NOT NULL,
`parent_section_id` varchar(64),
`x_offset` int NOT NULL,
`y_offset` int NOT NULL,
`width` int NOT NULL,
`height` int NOT NULL,
CONSTRAINT `section_layout_section_id_layout_id_pk` PRIMARY KEY(`section_id`,`layout_id`)
);
--> statement-breakpoint
ALTER TABLE `item_layout` ADD CONSTRAINT `item_layout_item_id_item_id_fk` FOREIGN KEY (`item_id`) REFERENCES `item`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `item_layout` ADD CONSTRAINT `item_layout_section_id_section_id_fk` FOREIGN KEY (`section_id`) REFERENCES `section`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `item_layout` ADD CONSTRAINT `item_layout_layout_id_layout_id_fk` FOREIGN KEY (`layout_id`) REFERENCES `layout`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `layout` ADD CONSTRAINT `layout_board_id_board_id_fk` FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `section_layout` ADD CONSTRAINT `section_layout_section_id_section_id_fk` FOREIGN KEY (`section_id`) REFERENCES `section`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `section_layout` ADD CONSTRAINT `section_layout_layout_id_layout_id_fk` FOREIGN KEY (`layout_id`) REFERENCES `layout`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE `section_layout` ADD CONSTRAINT `section_layout_parent_section_id_section_id_fk` FOREIGN KEY (`parent_section_id`) REFERENCES `section`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
INSERT INTO `layout`(`id`, `name`, `board_id`, `column_count`) SELECT `id`, 'Base', `id`, `column_count` FROM `board`;
--> statement-breakpoint
INSERT INTO `item_layout`(`item_id`, `section_id`, `layout_id`, `x_offset`, `y_offset`, `width`, `height`) SELECT `item`.`id`, `section`.`id`, `board`.`id`, `item`.`x_offset`, `item`.`y_offset`, `item`.`width`, `item`.`height` FROM `board` LEFT JOIN `section` ON `section`.`board_id`=`board`.`id` LEFT JOIN `item` ON `item`.`section_id`=`section`.`id` WHERE `item`.`id` IS NOT NULL;
--> statement-breakpoint
INSERT INTO `section_layout`(`section_id`, `layout_id`, `parent_section_id`, `x_offset`, `y_offset`, `width`, `height`) SELECT `section`.`id`, `board`.`id`, `section`.`parent_section_id`, `section`.`x_offset`, `section`.`y_offset`, `section`.`width`, `section`.`height` FROM `board` LEFT JOIN `section` ON `section`.`board_id`=`board`.`id` WHERE `section`.`id` IS NOT NULL AND `section`.`kind` = 'dynamic';

View File

@@ -0,0 +1,36 @@
-- Custom SQL migration file, put your code below! --
ALTER TABLE `item` DROP FOREIGN KEY `item_section_id_section_id_fk`;
--> statement-breakpoint
ALTER TABLE `section` DROP FOREIGN KEY `section_parent_section_id_section_id_fk`;
--> statement-breakpoint
ALTER TABLE `section` MODIFY COLUMN `x_offset` int;
--> statement-breakpoint
ALTER TABLE `section` MODIFY COLUMN `y_offset` int;
--> statement-breakpoint
ALTER TABLE `item` ADD `board_id` varchar(64);
--> statement-breakpoint
ALTER TABLE `item` ADD CONSTRAINT `item_board_id_board_id_fk` FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
UPDATE `item` JOIN `section` ON `item`.`section_id`=`section`.`id` SET `item`.`board_id` = `section`.`board_id`;
--> statement-breakpoint
ALTER TABLE `item` MODIFY COLUMN `board_id` varchar(64) NOT NULL;
--> statement-breakpoint
ALTER TABLE `board` DROP COLUMN `column_count`;
--> statement-breakpoint
ALTER TABLE `item` DROP COLUMN `section_id`;
--> statement-breakpoint
ALTER TABLE `item` DROP COLUMN `x_offset`;
--> statement-breakpoint
ALTER TABLE `item` DROP COLUMN `y_offset`;
--> statement-breakpoint
ALTER TABLE `item` DROP COLUMN `width`;
--> statement-breakpoint
ALTER TABLE `item` DROP COLUMN `height`;
--> statement-breakpoint
ALTER TABLE `section` DROP COLUMN `width`;
--> statement-breakpoint
ALTER TABLE `section` DROP COLUMN `height`;
--> statement-breakpoint
ALTER TABLE `section` DROP COLUMN `parent_section_id`;
--> statement-breakpoint
UPDATE `section` SET `x_offset` = NULL, `y_offset` = NULL WHERE `kind` = 'dynamic';

View File

@@ -0,0 +1 @@
ALTER TABLE `section` ADD `options` text DEFAULT ('{"json": {}}');

View File

@@ -0,0 +1,6 @@
CREATE TABLE `trusted_certificate_hostname` (
`hostname` varchar(256) NOT NULL,
`thumbprint` varchar(128) NOT NULL,
`certificate` text NOT NULL,
CONSTRAINT `trusted_certificate_hostname_hostname_thumbprint_pk` PRIMARY KEY(`hostname`,`thumbprint`)
);

View File

@@ -0,0 +1,6 @@
CREATE TABLE `cron_job_configuration` (
`name` varchar(256) NOT NULL,
`cron_expression` varchar(32) NOT NULL,
`is_enabled` boolean NOT NULL DEFAULT true,
CONSTRAINT `cron_job_configuration_name` PRIMARY KEY(`name`)
);

View File

@@ -0,0 +1 @@
ALTER TABLE `media` MODIFY COLUMN `content` LONGBLOB NOT NULL;

View File

@@ -0,0 +1 @@
ALTER TABLE `integrationSecret` MODIFY COLUMN `kind` varchar(64) NOT NULL;

View File

@@ -0,0 +1,2 @@
ALTER TABLE `integration` ADD `app_id` varchar(128);--> statement-breakpoint
ALTER TABLE `integration` ADD CONSTRAINT `integration_app_id_app_id_fk` FOREIGN KEY (`app_id`) REFERENCES `app`(`id`) ON DELETE set null ON UPDATE no action;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,265 @@
{
"version": "6",
"dialect": "mysql",
"entries": [
{
"idx": 0,
"version": "5",
"when": 1715334452118,
"tag": "0000_harsh_photon",
"breakpoints": true
},
{
"idx": 1,
"version": "5",
"when": 1715885855801,
"tag": "0001_wild_alex_wilder",
"breakpoints": true
},
{
"idx": 2,
"version": "5",
"when": 1715980459023,
"tag": "0002_flimsy_deathbird",
"breakpoints": true
},
{
"idx": 3,
"version": "5",
"when": 1716148439439,
"tag": "0003_freezing_black_panther",
"breakpoints": true
},
{
"idx": 4,
"version": "5",
"when": 1720113913876,
"tag": "0004_noisy_giant_girl",
"breakpoints": true
},
{
"idx": 5,
"version": "5",
"when": 1722068832607,
"tag": "0005_soft_microbe",
"breakpoints": true
},
{
"idx": 6,
"version": "5",
"when": 1722517058725,
"tag": "0006_young_micromax",
"breakpoints": true
},
{
"idx": 7,
"version": "5",
"when": 1723749320706,
"tag": "0007_boring_nocturne",
"breakpoints": true
},
{
"idx": 8,
"version": "5",
"when": 1727532165317,
"tag": "0008_far_lifeguard",
"breakpoints": true
},
{
"idx": 9,
"version": "5",
"when": 1728074730696,
"tag": "0009_wakeful_tenebrous",
"breakpoints": true
},
{
"idx": 10,
"version": "5",
"when": 1728142597094,
"tag": "0010_melted_pestilence",
"breakpoints": true
},
{
"idx": 11,
"version": "5",
"when": 1728490046896,
"tag": "0011_freezing_banshee",
"breakpoints": true
},
{
"idx": 12,
"version": "5",
"when": 1729348221072,
"tag": "0012_abnormal_wendell_vaughn",
"breakpoints": true
},
{
"idx": 13,
"version": "5",
"when": 1729369383739,
"tag": "0013_youthful_vulture",
"breakpoints": true
},
{
"idx": 14,
"version": "5",
"when": 1729524382483,
"tag": "0014_bizarre_red_shift",
"breakpoints": true
},
{
"idx": 15,
"version": "5",
"when": 1730653393442,
"tag": "0015_unknown_firedrake",
"breakpoints": true
},
{
"idx": 16,
"version": "5",
"when": 1732212709518,
"tag": "0016_change_all_to_snake_case",
"breakpoints": true
},
{
"idx": 17,
"version": "5",
"when": 1733777544067,
"tag": "0017_tired_penance",
"breakpoints": true
},
{
"idx": 18,
"version": "5",
"when": 1735593853768,
"tag": "0018_mighty_shaman",
"breakpoints": true
},
{
"idx": 19,
"version": "5",
"when": 1735651231818,
"tag": "0019_crazy_marvel_zombies",
"breakpoints": true
},
{
"idx": 20,
"version": "5",
"when": 1736514409126,
"tag": "0020_salty_doorman",
"breakpoints": true
},
{
"idx": 21,
"version": "5",
"when": 1737883744729,
"tag": "0021_fluffy_jocasta",
"breakpoints": true
},
{
"idx": 22,
"version": "5",
"when": 1737927618711,
"tag": "0022_famous_otto_octavius",
"breakpoints": true
},
{
"idx": 23,
"version": "5",
"when": 1738687012272,
"tag": "0023_fix_on_delete_actions",
"breakpoints": true
},
{
"idx": 24,
"version": "5",
"when": 1738961147412,
"tag": "0024_mean_vin_gonzales",
"breakpoints": true
},
{
"idx": 25,
"version": "5",
"when": 1739469710187,
"tag": "0025_add-group-home-board-settings",
"breakpoints": true
},
{
"idx": 26,
"version": "5",
"when": 1739907771355,
"tag": "0026_add-border-radius",
"breakpoints": true
},
{
"idx": 27,
"version": "5",
"when": 1739915526818,
"tag": "0027_acoustic_karma",
"breakpoints": true
},
{
"idx": 28,
"version": "5",
"when": 1740086765989,
"tag": "0028_add_app_ping_url",
"breakpoints": true
},
{
"idx": 29,
"version": "5",
"when": 1740255915876,
"tag": "0029_add_layouts",
"breakpoints": true
},
{
"idx": 30,
"version": "5",
"when": 1740256006328,
"tag": "0030_migrate_item_and_section_for_layouts",
"breakpoints": true
},
{
"idx": 31,
"version": "5",
"when": 1740784837957,
"tag": "0031_add_dynamic_section_options",
"breakpoints": true
},
{
"idx": 32,
"version": "5",
"when": 1746821770071,
"tag": "0032_add_trusted_certificate_hostnames",
"breakpoints": true
},
{
"idx": 33,
"version": "5",
"when": 1750013953833,
"tag": "0033_add_cron_job_configuration",
"breakpoints": true
},
{
"idx": 34,
"version": "5",
"when": 1754929897145,
"tag": "0034_increase-blob-size",
"breakpoints": true
},
{
"idx": 35,
"version": "5",
"when": 1756701556908,
"tag": "0035_increase-secret-kind-length",
"breakpoints": true
},
{
"idx": 36,
"version": "5",
"when": 1760968518445,
"tag": "0036_add_app_reference_to_integration",
"breakpoints": true
}
]
}

View File

@@ -0,0 +1,29 @@
import { migrate } from "drizzle-orm/mysql2/migrator";
import { createMysqlDb, createSharedDbConfig } from "@homarr/core/infrastructure/db";
import type { Database } from "../..";
import * as mysqlSchema from "../../schema/mysql";
import { applyCustomMigrationsAsync } from "../custom";
import { seedDataAsync } from "../seed";
const migrationsFolder = process.argv[2] ?? ".";
const migrateAsync = async () => {
const config = createSharedDbConfig(mysqlSchema);
const db = createMysqlDb(config);
await migrate(db, { migrationsFolder });
await seedDataAsync(db as unknown as Database);
await applyCustomMigrationsAsync(db as unknown as Database);
};
migrateAsync()
.then(() => {
console.log("Migration complete");
process.exit(0);
})
.catch((err) => {
console.log("Migration failed", err);
process.exit(1);
});

View File

@@ -0,0 +1,322 @@
CREATE TABLE "account" (
"user_id" varchar(64) NOT NULL,
"type" text NOT NULL,
"provider" varchar(64) NOT NULL,
"provider_account_id" varchar(64) NOT NULL,
"refresh_token" text,
"access_token" text,
"expires_at" integer,
"token_type" text,
"scope" text,
"id_token" text,
"session_state" text,
CONSTRAINT "account_provider_provider_account_id_pk" PRIMARY KEY("provider","provider_account_id")
);
--> statement-breakpoint
CREATE TABLE "apiKey" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"api_key" text NOT NULL,
"salt" text NOT NULL,
"user_id" varchar(64) NOT NULL
);
--> statement-breakpoint
CREATE TABLE "app" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"name" text NOT NULL,
"description" text,
"icon_url" text NOT NULL,
"href" text,
"ping_url" text
);
--> statement-breakpoint
CREATE TABLE "boardGroupPermission" (
"board_id" varchar(64) NOT NULL,
"group_id" varchar(64) NOT NULL,
"permission" varchar(128) NOT NULL,
CONSTRAINT "boardGroupPermission_board_id_group_id_permission_pk" PRIMARY KEY("board_id","group_id","permission")
);
--> statement-breakpoint
CREATE TABLE "boardUserPermission" (
"board_id" varchar(64) NOT NULL,
"user_id" varchar(64) NOT NULL,
"permission" varchar(128) NOT NULL,
CONSTRAINT "boardUserPermission_board_id_user_id_permission_pk" PRIMARY KEY("board_id","user_id","permission")
);
--> statement-breakpoint
CREATE TABLE "board" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"name" varchar(256) NOT NULL,
"is_public" boolean DEFAULT false NOT NULL,
"creator_id" varchar(64),
"page_title" text,
"meta_title" text,
"logo_image_url" text,
"favicon_image_url" text,
"background_image_url" text,
"background_image_attachment" text DEFAULT 'fixed' NOT NULL,
"background_image_repeat" text DEFAULT 'no-repeat' NOT NULL,
"background_image_size" text DEFAULT 'cover' NOT NULL,
"primary_color" text DEFAULT '#fa5252' NOT NULL,
"secondary_color" text DEFAULT '#fd7e14' NOT NULL,
"opacity" integer DEFAULT 100 NOT NULL,
"custom_css" text,
"icon_color" text,
"item_radius" text DEFAULT 'lg' NOT NULL,
"disable_status" boolean DEFAULT false NOT NULL,
CONSTRAINT "board_name_unique" UNIQUE("name")
);
--> statement-breakpoint
CREATE TABLE "cron_job_configuration" (
"name" varchar(256) PRIMARY KEY NOT NULL,
"cron_expression" varchar(32) NOT NULL,
"is_enabled" boolean DEFAULT true NOT NULL
);
--> statement-breakpoint
CREATE TABLE "groupMember" (
"group_id" varchar(64) NOT NULL,
"user_id" varchar(64) NOT NULL,
CONSTRAINT "groupMember_group_id_user_id_pk" PRIMARY KEY("group_id","user_id")
);
--> statement-breakpoint
CREATE TABLE "groupPermission" (
"group_id" varchar(64) NOT NULL,
"permission" text NOT NULL
);
--> statement-breakpoint
CREATE TABLE "group" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"name" varchar(64) NOT NULL,
"owner_id" varchar(64),
"home_board_id" varchar(64),
"mobile_home_board_id" varchar(64),
"position" smallint NOT NULL,
CONSTRAINT "group_name_unique" UNIQUE("name")
);
--> statement-breakpoint
CREATE TABLE "iconRepository" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"slug" varchar(150) NOT NULL
);
--> statement-breakpoint
CREATE TABLE "icon" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"name" varchar(250) NOT NULL,
"url" text NOT NULL,
"checksum" text NOT NULL,
"icon_repository_id" varchar(64) NOT NULL
);
--> statement-breakpoint
CREATE TABLE "integrationGroupPermissions" (
"integration_id" varchar(64) NOT NULL,
"group_id" varchar(64) NOT NULL,
"permission" varchar(128) NOT NULL,
CONSTRAINT "integration_group_permission__pk" PRIMARY KEY("integration_id","group_id","permission")
);
--> statement-breakpoint
CREATE TABLE "integration_item" (
"item_id" varchar(64) NOT NULL,
"integration_id" varchar(64) NOT NULL,
CONSTRAINT "integration_item_item_id_integration_id_pk" PRIMARY KEY("item_id","integration_id")
);
--> statement-breakpoint
CREATE TABLE "integrationSecret" (
"kind" varchar(16) NOT NULL,
"value" text NOT NULL,
"updated_at" timestamp NOT NULL,
"integration_id" varchar(64) NOT NULL,
CONSTRAINT "integrationSecret_integration_id_kind_pk" PRIMARY KEY("integration_id","kind")
);
--> statement-breakpoint
CREATE TABLE "integrationUserPermission" (
"integration_id" varchar(64) NOT NULL,
"user_id" varchar(64) NOT NULL,
"permission" varchar(128) NOT NULL,
CONSTRAINT "integrationUserPermission_integration_id_user_id_permission_pk" PRIMARY KEY("integration_id","user_id","permission")
);
--> statement-breakpoint
CREATE TABLE "integration" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"name" text NOT NULL,
"url" text NOT NULL,
"kind" varchar(128) NOT NULL
);
--> statement-breakpoint
CREATE TABLE "invite" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"token" varchar(512) NOT NULL,
"expiration_date" timestamp NOT NULL,
"creator_id" varchar(64) NOT NULL,
CONSTRAINT "invite_token_unique" UNIQUE("token")
);
--> statement-breakpoint
CREATE TABLE "item_layout" (
"item_id" varchar(64) NOT NULL,
"section_id" varchar(64) NOT NULL,
"layout_id" varchar(64) NOT NULL,
"x_offset" integer NOT NULL,
"y_offset" integer NOT NULL,
"width" integer NOT NULL,
"height" integer NOT NULL,
CONSTRAINT "item_layout_item_id_section_id_layout_id_pk" PRIMARY KEY("item_id","section_id","layout_id")
);
--> statement-breakpoint
CREATE TABLE "item" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"board_id" varchar(64) NOT NULL,
"kind" text NOT NULL,
"options" text DEFAULT '{"json": {}}' NOT NULL,
"advanced_options" text DEFAULT '{"json": {}}' NOT NULL
);
--> statement-breakpoint
CREATE TABLE "layout" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"name" varchar(32) NOT NULL,
"board_id" varchar(64) NOT NULL,
"column_count" smallint NOT NULL,
"breakpoint" smallint DEFAULT 0 NOT NULL
);
--> statement-breakpoint
CREATE TABLE "media" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"name" varchar(512) NOT NULL,
"content" "bytea" NOT NULL,
"content_type" text NOT NULL,
"size" integer NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"creator_id" varchar(64)
);
--> statement-breakpoint
CREATE TABLE "onboarding" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"step" varchar(64) NOT NULL,
"previous_step" varchar(64)
);
--> statement-breakpoint
CREATE TABLE "search_engine" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"icon_url" text NOT NULL,
"name" varchar(64) NOT NULL,
"short" varchar(8) NOT NULL,
"description" text,
"url_template" text,
"type" varchar(64) DEFAULT 'generic' NOT NULL,
"integration_id" varchar(64),
CONSTRAINT "search_engine_short_unique" UNIQUE("short")
);
--> statement-breakpoint
CREATE TABLE "section_collapse_state" (
"user_id" varchar(64) NOT NULL,
"section_id" varchar(64) NOT NULL,
"collapsed" boolean DEFAULT false NOT NULL,
CONSTRAINT "section_collapse_state_user_id_section_id_pk" PRIMARY KEY("user_id","section_id")
);
--> statement-breakpoint
CREATE TABLE "section_layout" (
"section_id" varchar(64) NOT NULL,
"layout_id" varchar(64) NOT NULL,
"parent_section_id" varchar(64),
"x_offset" integer NOT NULL,
"y_offset" integer NOT NULL,
"width" integer NOT NULL,
"height" integer NOT NULL,
CONSTRAINT "section_layout_section_id_layout_id_pk" PRIMARY KEY("section_id","layout_id")
);
--> statement-breakpoint
CREATE TABLE "section" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"board_id" varchar(64) NOT NULL,
"kind" text NOT NULL,
"x_offset" integer,
"y_offset" integer,
"name" text,
"options" text DEFAULT '{"json": {}}'
);
--> statement-breakpoint
CREATE TABLE "serverSetting" (
"setting_key" varchar(64) PRIMARY KEY NOT NULL,
"value" text DEFAULT '{"json": {}}' NOT NULL,
CONSTRAINT "serverSetting_settingKey_unique" UNIQUE("setting_key")
);
--> statement-breakpoint
CREATE TABLE "session" (
"session_token" varchar(512) PRIMARY KEY NOT NULL,
"user_id" varchar(64) NOT NULL,
"expires" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE "trusted_certificate_hostname" (
"hostname" varchar(256) NOT NULL,
"thumbprint" varchar(128) NOT NULL,
"certificate" text NOT NULL,
CONSTRAINT "trusted_certificate_hostname_hostname_thumbprint_pk" PRIMARY KEY("hostname","thumbprint")
);
--> statement-breakpoint
CREATE TABLE "user" (
"id" varchar(64) PRIMARY KEY NOT NULL,
"name" text,
"email" text,
"email_verified" timestamp,
"image" text,
"password" text,
"salt" text,
"provider" varchar(64) DEFAULT 'credentials' NOT NULL,
"home_board_id" varchar(64),
"mobile_home_board_id" varchar(64),
"default_search_engine_id" varchar(64),
"open_search_in_new_tab" boolean DEFAULT false NOT NULL,
"color_scheme" varchar(5) DEFAULT 'dark' NOT NULL,
"first_day_of_week" smallint DEFAULT 1 NOT NULL,
"ping_icons_enabled" boolean DEFAULT false NOT NULL
);
--> statement-breakpoint
CREATE TABLE "verificationToken" (
"identifier" varchar(64) NOT NULL,
"token" varchar(512) NOT NULL,
"expires" timestamp NOT NULL,
CONSTRAINT "verificationToken_identifier_token_pk" PRIMARY KEY("identifier","token")
);
--> statement-breakpoint
ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "apiKey" ADD CONSTRAINT "apiKey_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "boardGroupPermission" ADD CONSTRAINT "boardGroupPermission_board_id_board_id_fk" FOREIGN KEY ("board_id") REFERENCES "public"."board"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "boardGroupPermission" ADD CONSTRAINT "boardGroupPermission_group_id_group_id_fk" FOREIGN KEY ("group_id") REFERENCES "public"."group"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "boardUserPermission" ADD CONSTRAINT "boardUserPermission_board_id_board_id_fk" FOREIGN KEY ("board_id") REFERENCES "public"."board"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "boardUserPermission" ADD CONSTRAINT "boardUserPermission_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "board" ADD CONSTRAINT "board_creator_id_user_id_fk" FOREIGN KEY ("creator_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "groupMember" ADD CONSTRAINT "groupMember_group_id_group_id_fk" FOREIGN KEY ("group_id") REFERENCES "public"."group"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "groupMember" ADD CONSTRAINT "groupMember_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "groupPermission" ADD CONSTRAINT "groupPermission_group_id_group_id_fk" FOREIGN KEY ("group_id") REFERENCES "public"."group"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "group" ADD CONSTRAINT "group_owner_id_user_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "group" ADD CONSTRAINT "group_home_board_id_board_id_fk" FOREIGN KEY ("home_board_id") REFERENCES "public"."board"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "group" ADD CONSTRAINT "group_mobile_home_board_id_board_id_fk" FOREIGN KEY ("mobile_home_board_id") REFERENCES "public"."board"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "icon" ADD CONSTRAINT "icon_icon_repository_id_iconRepository_id_fk" FOREIGN KEY ("icon_repository_id") REFERENCES "public"."iconRepository"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "integrationGroupPermissions" ADD CONSTRAINT "integrationGroupPermissions_integration_id_integration_id_fk" FOREIGN KEY ("integration_id") REFERENCES "public"."integration"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "integrationGroupPermissions" ADD CONSTRAINT "integrationGroupPermissions_group_id_group_id_fk" FOREIGN KEY ("group_id") REFERENCES "public"."group"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "integration_item" ADD CONSTRAINT "integration_item_item_id_item_id_fk" FOREIGN KEY ("item_id") REFERENCES "public"."item"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "integration_item" ADD CONSTRAINT "integration_item_integration_id_integration_id_fk" FOREIGN KEY ("integration_id") REFERENCES "public"."integration"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "integrationSecret" ADD CONSTRAINT "integrationSecret_integration_id_integration_id_fk" FOREIGN KEY ("integration_id") REFERENCES "public"."integration"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "integrationUserPermission" ADD CONSTRAINT "integrationUserPermission_integration_id_integration_id_fk" FOREIGN KEY ("integration_id") REFERENCES "public"."integration"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "integrationUserPermission" ADD CONSTRAINT "integrationUserPermission_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invite" ADD CONSTRAINT "invite_creator_id_user_id_fk" FOREIGN KEY ("creator_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "item_layout" ADD CONSTRAINT "item_layout_item_id_item_id_fk" FOREIGN KEY ("item_id") REFERENCES "public"."item"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "item_layout" ADD CONSTRAINT "item_layout_section_id_section_id_fk" FOREIGN KEY ("section_id") REFERENCES "public"."section"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "item_layout" ADD CONSTRAINT "item_layout_layout_id_layout_id_fk" FOREIGN KEY ("layout_id") REFERENCES "public"."layout"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "item" ADD CONSTRAINT "item_board_id_board_id_fk" FOREIGN KEY ("board_id") REFERENCES "public"."board"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "layout" ADD CONSTRAINT "layout_board_id_board_id_fk" FOREIGN KEY ("board_id") REFERENCES "public"."board"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "media" ADD CONSTRAINT "media_creator_id_user_id_fk" FOREIGN KEY ("creator_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "search_engine" ADD CONSTRAINT "search_engine_integration_id_integration_id_fk" FOREIGN KEY ("integration_id") REFERENCES "public"."integration"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "section_collapse_state" ADD CONSTRAINT "section_collapse_state_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "section_collapse_state" ADD CONSTRAINT "section_collapse_state_section_id_section_id_fk" FOREIGN KEY ("section_id") REFERENCES "public"."section"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "section_layout" ADD CONSTRAINT "section_layout_section_id_section_id_fk" FOREIGN KEY ("section_id") REFERENCES "public"."section"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "section_layout" ADD CONSTRAINT "section_layout_layout_id_layout_id_fk" FOREIGN KEY ("layout_id") REFERENCES "public"."layout"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "section_layout" ADD CONSTRAINT "section_layout_parent_section_id_section_id_fk" FOREIGN KEY ("parent_section_id") REFERENCES "public"."section"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "section" ADD CONSTRAINT "section_board_id_board_id_fk" FOREIGN KEY ("board_id") REFERENCES "public"."board"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "user" ADD CONSTRAINT "user_home_board_id_board_id_fk" FOREIGN KEY ("home_board_id") REFERENCES "public"."board"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "user" ADD CONSTRAINT "user_mobile_home_board_id_board_id_fk" FOREIGN KEY ("mobile_home_board_id") REFERENCES "public"."board"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "user" ADD CONSTRAINT "user_default_search_engine_id_search_engine_id_fk" FOREIGN KEY ("default_search_engine_id") REFERENCES "public"."search_engine"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "userId_idx" ON "account" USING btree ("user_id");--> statement-breakpoint
CREATE INDEX "integration_secret__kind_idx" ON "integrationSecret" USING btree ("kind");--> statement-breakpoint
CREATE INDEX "integration_secret__updated_at_idx" ON "integrationSecret" USING btree ("updated_at");--> statement-breakpoint
CREATE INDEX "integration__kind_idx" ON "integration" USING btree ("kind");--> statement-breakpoint
CREATE INDEX "user_id_idx" ON "session" USING btree ("user_id");

View File

@@ -0,0 +1 @@
ALTER TABLE "integrationSecret" ALTER COLUMN "kind" SET DATA TYPE varchar(64);

View File

@@ -0,0 +1,2 @@
ALTER TABLE "integration" ADD COLUMN "app_id" varchar(128);--> statement-breakpoint
ALTER TABLE "integration" ADD CONSTRAINT "integration_app_id_app_id_fk" FOREIGN KEY ("app_id") REFERENCES "public"."app"("id") ON DELETE set null ON UPDATE no action;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1754853510707,
"tag": "0000_initial",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1756701573101,
"tag": "0001_increase-secret-kind-length",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1760968530084,
"tag": "0002_add_app_reference_to_integration",
"breakpoints": true
}
]
}

View File

@@ -0,0 +1,29 @@
import { migrate } from "drizzle-orm/node-postgres/migrator";
import { createPostgresDb, createSharedDbConfig } from "@homarr/core/infrastructure/db";
import type { Database } from "../..";
import * as pgSchema from "../../schema/postgresql";
import { applyCustomMigrationsAsync } from "../custom";
import { seedDataAsync } from "../seed";
const migrationsFolder = process.argv[2] ?? ".";
const migrateAsync = async () => {
const config = createSharedDbConfig(pgSchema);
const db = createPostgresDb(config);
await migrate(db, { migrationsFolder });
await seedDataAsync(db as unknown as Database);
await applyCustomMigrationsAsync(db as unknown as Database);
};
migrateAsync()
.then(() => {
console.log("Migration complete");
process.exit(0);
})
.catch((err) => {
console.log("Migration failed", err);
process.exit(1);
});

View File

@@ -0,0 +1,12 @@
import { db } from "..";
import { seedDataAsync } from "./seed";
seedDataAsync(db)
.then(() => {
console.log("Seed complete");
process.exit(0);
})
.catch((err) => {
console.log("Seed failed\n\t", err);
process.exit(1);
});

View File

@@ -0,0 +1,191 @@
import { createId, objectKeys } from "@homarr/common";
import {
createDocumentationLink,
everyoneGroup,
getIntegrationDefaultUrl,
getIntegrationName,
integrationKinds,
} from "@homarr/definitions";
import { defaultServerSettings, defaultServerSettingsKeys } from "@homarr/server-settings";
import type { Database } from "..";
import { eq } from "..";
import {
getServerSettingByKeyAsync,
insertServerSettingByKeyAsync,
updateServerSettingByKeyAsync,
} from "../queries/server-setting";
import { groups, integrations, onboarding, searchEngines } from "../schema";
import type { Integration } from "../schema";
export const seedDataAsync = async (db: Database) => {
await seedEveryoneGroupAsync(db);
await seedOnboardingAsync(db);
await seedServerSettingsAsync(db);
await seedDefaultSearchEnginesAsync(db);
await seedDefaultIntegrationsAsync(db);
};
const seedEveryoneGroupAsync = async (db: Database) => {
const group = await db.query.groups.findFirst({
where: eq(groups.name, everyoneGroup),
});
if (group) {
console.log("Skipping seeding of group 'everyone' as it already exists");
return;
}
await db.insert(groups).values({
id: createId(),
name: everyoneGroup,
position: -1,
});
console.log("Created group 'everyone' through seed");
};
const seedOnboardingAsync = async (db: Database) => {
const existing = await db.query.onboarding.findFirst();
if (existing) {
console.log("Skipping seeding of onboarding as it already exists");
return;
}
await db.insert(onboarding).values({
id: createId(),
step: "start",
});
console.log("Created onboarding step through seed");
};
const seedDefaultSearchEnginesAsync = async (db: Database) => {
const existingSearchEngines = await db.$count(searchEngines);
if (existingSearchEngines > 0) {
console.log("Skipping seeding of default search engines as some already exists");
return;
}
const homarrId = createId();
const defaultSearchEngines = [
{
id: createId(),
name: "Google",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/google.svg",
short: "g",
description: "Search the web with Google",
urlTemplate: "https://www.google.com/search?q=%s",
type: "generic" as const,
integrationId: null,
},
{
id: createId(),
name: "YouTube",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/youtube.svg",
short: "yt",
description: "Search for videos on YouTube",
urlTemplate: "https://www.youtube.com/results?search_query=%s",
type: "generic" as const,
integrationId: null,
},
{
id: homarrId,
name: "Homarr Docs",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/homarr.svg",
short: "docs",
description: "Search the Homarr documentation",
urlTemplate: createDocumentationLink("/search", undefined, { q: "%s" }),
type: "generic" as const,
integrationId: null,
},
];
await db.insert(searchEngines).values(defaultSearchEngines);
console.log(`Created ${defaultSearchEngines.length} default search engines through seeding process`);
// Set Homarr docs as the default search engine in server settings
const searchSettings = await getServerSettingByKeyAsync(db, "search");
await updateServerSettingByKeyAsync(db, "search", {
...searchSettings,
defaultSearchEngineId: homarrId,
});
console.log("Set Homarr docs as the default search engine");
};
const seedServerSettingsAsync = async (db: Database) => {
const serverSettingsData = await db.query.serverSettings.findMany();
for (const settingsKey of defaultServerSettingsKeys) {
const currentDbEntry = serverSettingsData.find((setting) => setting.settingKey === settingsKey);
if (!currentDbEntry) {
await insertServerSettingByKeyAsync(db, settingsKey, defaultServerSettings[settingsKey]);
console.log(`Created serverSetting through seed key=${settingsKey}`);
continue;
}
const currentSettings = await getServerSettingByKeyAsync(db, settingsKey);
const defaultSettings = defaultServerSettings[settingsKey];
const missingKeys = objectKeys(defaultSettings).filter((key) => !(key in currentSettings));
if (missingKeys.length === 0) {
console.info(`Skipping seeding for serverSetting as it already exists key=${settingsKey}`);
continue;
}
await updateServerSettingByKeyAsync(db, settingsKey, { ...defaultSettings, ...currentSettings });
console.log(`Updated serverSetting through seed key=${settingsKey}`);
}
};
const seedDefaultIntegrationsAsync = async (db: Database) => {
const defaultIntegrations = integrationKinds.reduce<Integration[]>((acc, kind) => {
const name = getIntegrationName(kind);
const defaultUrl = getIntegrationDefaultUrl(kind);
if (defaultUrl !== undefined) {
acc.push({
id: "new",
name: `${name} Default`,
url: defaultUrl,
kind,
appId: null,
});
}
return acc;
}, []);
if (defaultIntegrations.length === 0) {
console.warn("No default integrations found to seed");
return;
}
let createdCount = 0;
await Promise.all(
defaultIntegrations.map(async (integration) => {
const existingKind = await db.$count(integrations, eq(integrations.kind, integration.kind));
if (existingKind > 0) {
console.log(`Skipping seeding of default ${integration.kind} integration as one already exists`);
return;
}
const newIntegration = {
...integration,
id: createId(),
};
await db.insert(integrations).values(newIntegration);
createdCount++;
}),
);
if (createdCount === 0) {
console.log("No default integrations were created as they already exist");
return;
}
console.log(`Created ${createdCount} default integrations through seeding process`);
};

View File

@@ -0,0 +1,182 @@
CREATE TABLE `account` (
`userId` text NOT NULL,
`type` text NOT NULL,
`provider` text NOT NULL,
`providerAccountId` text NOT NULL,
`refresh_token` text,
`access_token` text,
`expires_at` integer,
`token_type` text,
`scope` text,
`id_token` text,
`session_state` text,
PRIMARY KEY(`provider`, `providerAccountId`),
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `app` (
`id` text PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`description` text,
`icon_url` text NOT NULL,
`href` text
);
--> statement-breakpoint
CREATE TABLE `boardGroupPermission` (
`board_id` text NOT NULL,
`group_id` text NOT NULL,
`permission` text NOT NULL,
PRIMARY KEY(`board_id`, `group_id`, `permission`),
FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`group_id`) REFERENCES `group`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `boardUserPermission` (
`board_id` text NOT NULL,
`user_id` text NOT NULL,
`permission` text NOT NULL,
PRIMARY KEY(`board_id`, `permission`, `user_id`),
FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `board` (
`id` text PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`is_public` integer DEFAULT false NOT NULL,
`creator_id` text,
`page_title` text,
`meta_title` text,
`logo_image_url` text,
`favicon_image_url` text,
`background_image_url` text,
`background_image_attachment` text DEFAULT 'fixed' NOT NULL,
`background_image_repeat` text DEFAULT 'no-repeat' NOT NULL,
`background_image_size` text DEFAULT 'cover' NOT NULL,
`primary_color` text DEFAULT '#fa5252' NOT NULL,
`secondary_color` text DEFAULT '#fd7e14' NOT NULL,
`opacity` integer DEFAULT 100 NOT NULL,
`custom_css` text,
`column_count` integer DEFAULT 10 NOT NULL,
FOREIGN KEY (`creator_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE set null
);
--> statement-breakpoint
CREATE TABLE `groupMember` (
`groupId` text NOT NULL,
`userId` text NOT NULL,
PRIMARY KEY(`groupId`, `userId`),
FOREIGN KEY (`groupId`) REFERENCES `group`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `groupPermission` (
`groupId` text NOT NULL,
`permission` text NOT NULL,
FOREIGN KEY (`groupId`) REFERENCES `group`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `group` (
`id` text PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`owner_id` text,
FOREIGN KEY (`owner_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE set null
);
--> statement-breakpoint
CREATE TABLE `iconRepository` (
`iconRepository_id` text PRIMARY KEY NOT NULL,
`iconRepository_slug` text NOT NULL
);
--> statement-breakpoint
CREATE TABLE `icon` (
`icon_id` text PRIMARY KEY NOT NULL,
`icon_name` text NOT NULL,
`icon_url` text NOT NULL,
`icon_checksum` text NOT NULL,
`iconRepository_id` text NOT NULL,
FOREIGN KEY (`iconRepository_id`) REFERENCES `iconRepository`(`iconRepository_id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `integration_item` (
`item_id` text NOT NULL,
`integration_id` text NOT NULL,
PRIMARY KEY(`integration_id`, `item_id`),
FOREIGN KEY (`item_id`) REFERENCES `item`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `integrationSecret` (
`kind` text NOT NULL,
`value` text NOT NULL,
`updated_at` integer NOT NULL,
`integration_id` text NOT NULL,
PRIMARY KEY(`integration_id`, `kind`),
FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `integration` (
`id` text PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`url` text NOT NULL,
`kind` text NOT NULL
);
--> statement-breakpoint
CREATE TABLE `invite` (
`id` text PRIMARY KEY NOT NULL,
`token` text NOT NULL,
`expiration_date` integer NOT NULL,
`creator_id` text NOT NULL,
FOREIGN KEY (`creator_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `item` (
`id` text PRIMARY KEY NOT NULL,
`section_id` text NOT NULL,
`kind` text NOT NULL,
`x_offset` integer NOT NULL,
`y_offset` integer NOT NULL,
`width` integer NOT NULL,
`height` integer NOT NULL,
`options` text DEFAULT '{"json": {}}' NOT NULL,
FOREIGN KEY (`section_id`) REFERENCES `section`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `section` (
`id` text PRIMARY KEY NOT NULL,
`board_id` text NOT NULL,
`kind` text NOT NULL,
`position` integer NOT NULL,
`name` text,
FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `session` (
`sessionToken` text PRIMARY KEY NOT NULL,
`userId` text NOT NULL,
`expires` integer NOT NULL,
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `user` (
`id` text PRIMARY KEY NOT NULL,
`name` text,
`email` text,
`emailVerified` integer,
`image` text,
`password` text,
`salt` text
);
--> statement-breakpoint
CREATE TABLE `verificationToken` (
`identifier` text NOT NULL,
`token` text NOT NULL,
`expires` integer NOT NULL,
PRIMARY KEY(`identifier`, `token`)
);
--> statement-breakpoint
CREATE INDEX `userId_idx` ON `account` (`userId`);--> statement-breakpoint
CREATE UNIQUE INDEX `board_name_unique` ON `board` (`name`);--> statement-breakpoint
CREATE INDEX `integration_secret__kind_idx` ON `integrationSecret` (`kind`);--> statement-breakpoint
CREATE INDEX `integration_secret__updated_at_idx` ON `integrationSecret` (`updated_at`);--> statement-breakpoint
CREATE INDEX `integration__kind_idx` ON `integration` (`kind`);--> statement-breakpoint
CREATE UNIQUE INDEX `invite_token_unique` ON `invite` (`token`);--> statement-breakpoint
CREATE INDEX `user_id_idx` ON `session` (`userId`);

View File

@@ -0,0 +1,33 @@
COMMIT TRANSACTION;
--> statement-breakpoint
PRAGMA foreign_keys = OFF;
--> statement-breakpoint
BEGIN TRANSACTION;
--> statement-breakpoint
ALTER TABLE `user` RENAME TO `__user_old`;
--> statement-breakpoint
CREATE TABLE `user` (
`id` text PRIMARY KEY NOT NULL,
`name` text,
`email` text,
`emailVerified` integer,
`image` text,
`password` text,
`salt` text,
`homeBoardId` text,
FOREIGN KEY (`homeBoardId`) REFERENCES `board`(`id`) ON UPDATE no action ON DELETE set null
);
--> statement-breakpoint
INSERT INTO `user` SELECT `id`, `name`, `email`, `emailVerified`, `image`, `password`, `salt`, null FROM `__user_old`;
--> statement-breakpoint
DROP TABLE `__user_old`;
--> statement-breakpoint
ALTER TABLE `user` RENAME TO `__user_old`;
--> statement-breakpoint
ALTER TABLE `__user_old` RENAME TO `user`;
--> statement-breakpoint
COMMIT TRANSACTION;
--> statement-breakpoint
PRAGMA foreign_keys = ON;
--> statement-breakpoint
BEGIN TRANSACTION;

Some files were not shown because too many files have changed in this diff Show More