From 086db10f74a6ae697ca30e11077227c931a1a7d0 Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Sat, 27 Dec 2025 18:00:57 +0000 Subject: [PATCH] refactor: modularize default data seeding --- .../nextjs/src/lib/db/database-admin/index.ts | 2 +- .../app/default-app-config.ts | 14 ++ .../seed-default-data/app/seed-app-config.ts | 10 + .../seed-default-data/app/seed-users.ts | 37 ++++ .../css/build-css-classes.ts | 87 ++++++++ .../seed-default-data/css/css-class-utils.ts | 4 + .../css/default-css-categories.ts} | 203 +----------------- .../css/seed-css-categories.ts | 10 + .../dropdowns/default-dropdown-configs.ts | 36 ++++ .../dropdowns/seed-dropdown-configs.ts | 10 + .../database-admin/seed-default-data/index.ts | 21 ++ 11 files changed, 235 insertions(+), 199 deletions(-) create mode 100644 frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/default-app-config.ts create mode 100644 frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/seed-app-config.ts create mode 100644 frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/seed-users.ts create mode 100644 frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/build-css-classes.ts create mode 100644 frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/css-class-utils.ts rename frontends/nextjs/src/lib/db/database-admin/{seed-default-data.ts => seed-default-data/css/default-css-categories.ts} (51%) create mode 100644 frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/seed-css-categories.ts create mode 100644 frontends/nextjs/src/lib/db/database-admin/seed-default-data/dropdowns/default-dropdown-configs.ts create mode 100644 frontends/nextjs/src/lib/db/database-admin/seed-default-data/dropdowns/seed-dropdown-configs.ts create mode 100644 frontends/nextjs/src/lib/db/database-admin/seed-default-data/index.ts diff --git a/frontends/nextjs/src/lib/db/database-admin/index.ts b/frontends/nextjs/src/lib/db/database-admin/index.ts index 23fedd11b..f02ba56a7 100644 --- a/frontends/nextjs/src/lib/db/database-admin/index.ts +++ b/frontends/nextjs/src/lib/db/database-admin/index.ts @@ -1,4 +1,4 @@ export { clearDatabase } from './clear-database' export { exportDatabase } from './export-database' export { importDatabase } from './import-database' -export { seedDefaultData } from './seed-default-data' +export { seedDefaultData, defaultDataBuilders } from './seed-default-data' diff --git a/frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/default-app-config.ts b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/default-app-config.ts new file mode 100644 index 000000000..d81042d35 --- /dev/null +++ b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/default-app-config.ts @@ -0,0 +1,14 @@ +import type { AppConfiguration } from '../../../types/level-types' + +export const buildDefaultAppConfig = (): AppConfiguration => ({ + id: 'app_001', + name: 'MetaBuilder App', + schemas: [], + workflows: [], + luaScripts: [], + pages: [], + theme: { + colors: {}, + fonts: {}, + }, +}) diff --git a/frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/seed-app-config.ts b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/seed-app-config.ts new file mode 100644 index 000000000..b20c8b8cf --- /dev/null +++ b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/seed-app-config.ts @@ -0,0 +1,10 @@ +import { getAppConfig, setAppConfig } from '../../../app-config' +import { buildDefaultAppConfig } from './default-app-config' + +export const seedAppConfig = async () => { + const appConfig = await getAppConfig() + + if (!appConfig) { + await setAppConfig(buildDefaultAppConfig()) + } +} diff --git a/frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/seed-users.ts b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/seed-users.ts new file mode 100644 index 000000000..0e5ceaa8d --- /dev/null +++ b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/app/seed-users.ts @@ -0,0 +1,37 @@ +import { setCredential } from '../../../credentials' +import { hashPassword } from '../../../password/hash-password' +import { getUsers, setUsers } from '../../../users' +import type { User } from '../../../types/level-types' + +const buildDefaultUsers = (): User[] => [ + { + id: 'user_supergod', + username: 'supergod', + email: 'supergod@system.local', + role: 'supergod', + createdAt: Date.now(), + isInstanceOwner: true, + }, + { + id: 'user_god', + username: 'god', + email: 'god@system.local', + role: 'god', + createdAt: Date.now(), + isInstanceOwner: false, + }, +] + +export const seedUsers = async () => { + const users = await getUsers({ scope: 'all' }) + + if (users.length === 0) { + const defaultUsers = buildDefaultUsers() + await setUsers(defaultUsers) + + for (const user of defaultUsers) { + const hash = await hashPassword(user.username) + await setCredential(user.username, hash) + } + } +} diff --git a/frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/build-css-classes.ts b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/build-css-classes.ts new file mode 100644 index 000000000..02aa50757 --- /dev/null +++ b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/build-css-classes.ts @@ -0,0 +1,87 @@ +import { buildScaleClasses, uniqueClasses } from './css-class-utils' + +const spacingScale = ['0', '0.5', '1', '1.5', '2', '3', '4', '5', '6', '8', '10', '12', '16'] +const sizeScale = ['0', '1', '2', '3', '4', '5', '6', '8', '10', '12', '16', '20', '24', '32', '40', '48', '56', '64'] + +export const buildSpacingClasses = () => + uniqueClasses([ + ...buildScaleClasses( + ['p', 'px', 'py', 'pt', 'pr', 'pb', 'pl', 'm', 'mx', 'my', 'mt', 'mr', 'mb', 'ml'], + spacingScale + ), + ...buildScaleClasses(['gap', 'gap-x', 'gap-y'], ['0', '1', '2', '3', '4', '6', '8', '10', '12', '16']), + ...buildScaleClasses(['space-x', 'space-y'], ['0', '1', '2', '3', '4', '6', '8', '10', '12', '16']), + ]) + +export const buildSizingClasses = () => + uniqueClasses([ + ...buildScaleClasses(['w', 'h'], sizeScale), + 'w-auto', + 'w-full', + 'w-screen', + 'w-min', + 'w-max', + 'w-fit', + 'h-auto', + 'h-full', + 'h-screen', + 'h-min', + 'h-max', + 'h-fit', + 'min-w-0', + 'min-w-full', + 'min-w-min', + 'min-w-max', + 'min-w-fit', + 'min-h-0', + 'min-h-full', + 'min-h-screen', + 'min-h-min', + 'min-h-max', + 'min-h-fit', + 'max-w-none', + 'max-w-xs', + 'max-w-sm', + 'max-w-md', + 'max-w-lg', + 'max-w-xl', + 'max-w-2xl', + 'max-w-3xl', + 'max-w-4xl', + 'max-w-5xl', + 'max-w-6xl', + 'max-w-7xl', + 'max-w-full', + 'max-w-screen-sm', + 'max-w-screen-md', + 'max-w-screen-lg', + 'max-w-screen-xl', + 'max-h-none', + 'max-h-full', + 'max-h-screen', + 'w-1/2', + 'w-1/3', + 'w-2/3', + 'w-1/4', + 'w-2/4', + 'w-3/4', + 'w-1/5', + 'w-2/5', + 'w-3/5', + 'w-4/5', + 'w-1/6', + 'w-2/6', + 'w-3/6', + 'w-4/6', + 'w-5/6', + 'h-1/2', + 'h-1/3', + 'h-2/3', + 'h-1/4', + 'h-2/4', + 'h-3/4', + 'h-1/5', + 'h-2/5', + 'h-3/5', + 'h-4/5', + ]) diff --git a/frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/css-class-utils.ts b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/css-class-utils.ts new file mode 100644 index 000000000..e32868e06 --- /dev/null +++ b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/css-class-utils.ts @@ -0,0 +1,4 @@ +export const uniqueClasses = (classes: string[]) => Array.from(new Set(classes)) + +export const buildScaleClasses = (prefixes: string[], scale: string[]) => + prefixes.flatMap((prefix) => scale.map((value) => `${prefix}-${value}`)) diff --git a/frontends/nextjs/src/lib/db/database-admin/seed-default-data.ts b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/default-css-categories.ts similarity index 51% rename from frontends/nextjs/src/lib/db/database-admin/seed-default-data.ts rename to frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/default-css-categories.ts index 69487d1cb..772760517 100644 --- a/frontends/nextjs/src/lib/db/database-admin/seed-default-data.ts +++ b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/default-css-categories.ts @@ -1,100 +1,7 @@ -import { getUsers, setUsers } from '../users' -import { setCredential } from '../credentials' -import { getAppConfig, setAppConfig } from '../app-config' -import { getCssClasses, setCssClasses } from '../css-classes' -import { getDropdownConfigs, setDropdownConfigs } from '../dropdown-configs' -import { hashPassword } from '../password/hash-password' -import type { CssCategory, DropdownConfig } from '../types' -import type { User, AppConfiguration } from '../../types/level-types' +import type { CssCategory } from '../../../core/types' +import { buildSizingClasses, buildSpacingClasses } from './build-css-classes' -const uniqueClasses = (classes: string[]) => Array.from(new Set(classes)) -const buildScaleClasses = (prefixes: string[], scale: string[]) => - prefixes.flatMap((prefix) => scale.map((value) => `${prefix}-${value}`)) - -const spacingScale = ['0', '0.5', '1', '1.5', '2', '3', '4', '5', '6', '8', '10', '12', '16'] -const spacingClasses = uniqueClasses([ - ...buildScaleClasses( - ['p', 'px', 'py', 'pt', 'pr', 'pb', 'pl', 'm', 'mx', 'my', 'mt', 'mr', 'mb', 'ml'], - spacingScale - ), - ...buildScaleClasses(['gap', 'gap-x', 'gap-y'], ['0', '1', '2', '3', '4', '6', '8', '10', '12', '16']), - ...buildScaleClasses(['space-x', 'space-y'], ['0', '1', '2', '3', '4', '6', '8', '10', '12', '16']), -]) - -const sizeScale = ['0', '1', '2', '3', '4', '5', '6', '8', '10', '12', '16', '20', '24', '32', '40', '48', '56', '64'] -const sizingClasses = uniqueClasses([ - ...buildScaleClasses(['w', 'h'], sizeScale), - 'w-auto', - 'w-full', - 'w-screen', - 'w-min', - 'w-max', - 'w-fit', - 'h-auto', - 'h-full', - 'h-screen', - 'h-min', - 'h-max', - 'h-fit', - 'min-w-0', - 'min-w-full', - 'min-w-min', - 'min-w-max', - 'min-w-fit', - 'min-h-0', - 'min-h-full', - 'min-h-screen', - 'min-h-min', - 'min-h-max', - 'min-h-fit', - 'max-w-none', - 'max-w-xs', - 'max-w-sm', - 'max-w-md', - 'max-w-lg', - 'max-w-xl', - 'max-w-2xl', - 'max-w-3xl', - 'max-w-4xl', - 'max-w-5xl', - 'max-w-6xl', - 'max-w-7xl', - 'max-w-full', - 'max-w-screen-sm', - 'max-w-screen-md', - 'max-w-screen-lg', - 'max-w-screen-xl', - 'max-h-none', - 'max-h-full', - 'max-h-screen', - 'w-1/2', - 'w-1/3', - 'w-2/3', - 'w-1/4', - 'w-2/4', - 'w-3/4', - 'w-1/5', - 'w-2/5', - 'w-3/5', - 'w-4/5', - 'w-1/6', - 'w-2/6', - 'w-3/6', - 'w-4/6', - 'w-5/6', - 'h-1/2', - 'h-1/3', - 'h-2/3', - 'h-1/4', - 'h-2/4', - 'h-3/4', - 'h-1/5', - 'h-2/5', - 'h-3/5', - 'h-4/5', -]) - -const DEFAULT_CSS_CLASSES: CssCategory[] = [ +export const buildDefaultCssCategories = (): CssCategory[] => [ { name: 'Layout', classes: [ @@ -118,11 +25,11 @@ const DEFAULT_CSS_CLASSES: CssCategory[] = [ }, { name: 'Spacing', - classes: spacingClasses, + classes: buildSpacingClasses(), }, { name: 'Sizing', - classes: sizingClasses, + classes: buildSizingClasses(), }, { name: 'Typography', @@ -369,103 +276,3 @@ const DEFAULT_CSS_CLASSES: CssCategory[] = [ ], }, ] - -const DEFAULT_DROPDOWN_CONFIGS: DropdownConfig[] = [ - { - id: 'dropdown_status', - name: 'status_options', - label: 'Status', - options: [ - { value: 'draft', label: 'Draft' }, - { value: 'published', label: 'Published' }, - { value: 'archived', label: 'Archived' }, - ], - }, - { - id: 'dropdown_priority', - name: 'priority_options', - label: 'Priority', - options: [ - { value: 'low', label: 'Low' }, - { value: 'medium', label: 'Medium' }, - { value: 'high', label: 'High' }, - { value: 'urgent', label: 'Urgent' }, - ], - }, - { - id: 'dropdown_category', - name: 'category_options', - label: 'Category', - options: [ - { value: 'general', label: 'General' }, - { value: 'technical', label: 'Technical' }, - { value: 'business', label: 'Business' }, - { value: 'personal', label: 'Personal' }, - ], - }, -] - -/** - * Seed database with default data - */ -export async function seedDefaultData(): Promise { - // Create default users if none exist - const users = await getUsers({ scope: 'all' }) - if (users.length === 0) { - const defaultUsers: User[] = [ - { - id: 'user_supergod', - username: 'supergod', - email: 'supergod@system.local', - role: 'supergod', - createdAt: Date.now(), - isInstanceOwner: true, - }, - { - id: 'user_god', - username: 'god', - email: 'god@system.local', - role: 'god', - createdAt: Date.now(), - isInstanceOwner: false, - }, - ] - await setUsers(defaultUsers) - - // Set default passwords - for (const user of defaultUsers) { - const hash = await hashPassword(user.username) - await setCredential(user.username, hash) - } - } - - // Create default app config if none exists - const appConfig = await getAppConfig() - if (!appConfig) { - const defaultConfig: AppConfiguration = { - id: 'app_001', - name: 'MetaBuilder App', - schemas: [], - workflows: [], - luaScripts: [], - pages: [], - theme: { - colors: {}, - fonts: {}, - }, - } - await setAppConfig(defaultConfig) - } - - // Create default CSS classes if none exist - const cssClasses = await getCssClasses() - if (cssClasses.length === 0) { - await setCssClasses(DEFAULT_CSS_CLASSES) - } - - // Create default dropdown configs if none exist - const dropdowns = await getDropdownConfigs() - if (dropdowns.length === 0) { - await setDropdownConfigs(DEFAULT_DROPDOWN_CONFIGS) - } -} diff --git a/frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/seed-css-categories.ts b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/seed-css-categories.ts new file mode 100644 index 000000000..970466d4d --- /dev/null +++ b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/css/seed-css-categories.ts @@ -0,0 +1,10 @@ +import { getCssClasses, setCssClasses } from '../../../css-classes' +import { buildDefaultCssCategories } from './default-css-categories' + +export const seedCssCategories = async () => { + const cssClasses = await getCssClasses() + + if (cssClasses.length === 0) { + await setCssClasses(buildDefaultCssCategories()) + } +} diff --git a/frontends/nextjs/src/lib/db/database-admin/seed-default-data/dropdowns/default-dropdown-configs.ts b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/dropdowns/default-dropdown-configs.ts new file mode 100644 index 000000000..8e9fcd4a5 --- /dev/null +++ b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/dropdowns/default-dropdown-configs.ts @@ -0,0 +1,36 @@ +import type { DropdownConfig } from '../../../core/types' + +export const buildDefaultDropdownConfigs = (): DropdownConfig[] => [ + { + id: 'dropdown_status', + name: 'status_options', + label: 'Status', + options: [ + { value: 'draft', label: 'Draft' }, + { value: 'published', label: 'Published' }, + { value: 'archived', label: 'Archived' }, + ], + }, + { + id: 'dropdown_priority', + name: 'priority_options', + label: 'Priority', + options: [ + { value: 'low', label: 'Low' }, + { value: 'medium', label: 'Medium' }, + { value: 'high', label: 'High' }, + { value: 'urgent', label: 'Urgent' }, + ], + }, + { + id: 'dropdown_category', + name: 'category_options', + label: 'Category', + options: [ + { value: 'general', label: 'General' }, + { value: 'technical', label: 'Technical' }, + { value: 'business', label: 'Business' }, + { value: 'personal', label: 'Personal' }, + ], + }, +] diff --git a/frontends/nextjs/src/lib/db/database-admin/seed-default-data/dropdowns/seed-dropdown-configs.ts b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/dropdowns/seed-dropdown-configs.ts new file mode 100644 index 000000000..ef13a3296 --- /dev/null +++ b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/dropdowns/seed-dropdown-configs.ts @@ -0,0 +1,10 @@ +import { getDropdownConfigs, setDropdownConfigs } from '../../../dropdown-configs' +import { buildDefaultDropdownConfigs } from './default-dropdown-configs' + +export const seedDropdownConfigs = async () => { + const dropdowns = await getDropdownConfigs() + + if (dropdowns.length === 0) { + await setDropdownConfigs(buildDefaultDropdownConfigs()) + } +} diff --git a/frontends/nextjs/src/lib/db/database-admin/seed-default-data/index.ts b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/index.ts new file mode 100644 index 000000000..ec9bb2c05 --- /dev/null +++ b/frontends/nextjs/src/lib/db/database-admin/seed-default-data/index.ts @@ -0,0 +1,21 @@ +import { seedAppConfig } from './app/seed-app-config' +import { seedUsers } from './app/seed-users' +import { seedCssCategories } from './css/seed-css-categories' +import { seedDropdownConfigs } from './dropdowns/seed-dropdown-configs' + +/** + * Seed database with default data + */ +export const seedDefaultData = async (): Promise => { + await seedUsers() + await seedAppConfig() + await seedCssCategories() + await seedDropdownConfigs() +} + +export const defaultDataBuilders = { + seedUsers, + seedAppConfig, + seedCssCategories, + seedDropdownConfigs, +}