diff --git a/backend-node/src/app.ts b/backend-node/src/app.ts index ae10a6fe..0d7e0e15 100644 --- a/backend-node/src/app.ts +++ b/backend-node/src/app.ts @@ -231,6 +231,14 @@ app.listen(PORT, HOST, async () => { logger.info(`๐ Health check: http://${HOST}:${PORT}/health`); logger.info(`๐ External access: http://39.117.244.52:${PORT}/health`); + // ๋์๋ณด๋ ๋ง์ด๊ทธ๋ ์ด์ ์คํ + try { + const { runDashboardMigration } = await import('./database/runMigration'); + await runDashboardMigration(); + } catch (error) { + logger.error(`โ ๋์๋ณด๋ ๋ง์ด๊ทธ๋ ์ด์ ์คํจ:`, error); + } + // ๋ฐฐ์น ์ค์ผ์ค๋ฌ ์ด๊ธฐํ try { await BatchSchedulerService.initialize(); diff --git a/backend-node/src/database/runMigration.ts b/backend-node/src/database/runMigration.ts new file mode 100644 index 00000000..61b98241 --- /dev/null +++ b/backend-node/src/database/runMigration.ts @@ -0,0 +1,42 @@ +import { PostgreSQLService } from './PostgreSQLService'; + +/** + * ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ง์ด๊ทธ๋ ์ด์ ์คํ + * dashboard_elements ํ ์ด๋ธ์ custom_title, show_header ์ปฌ๋ผ ์ถ๊ฐ + */ +export async function runDashboardMigration() { + try { + console.log('๐ ๋์๋ณด๋ ๋ง์ด๊ทธ๋ ์ด์ ์์...'); + + // custom_title ์ปฌ๋ผ ์ถ๊ฐ + await PostgreSQLService.query(` + ALTER TABLE dashboard_elements + ADD COLUMN IF NOT EXISTS custom_title VARCHAR(255) + `); + console.log('โ custom_title ์ปฌ๋ผ ์ถ๊ฐ ์๋ฃ'); + + // show_header ์ปฌ๋ผ ์ถ๊ฐ + await PostgreSQLService.query(` + ALTER TABLE dashboard_elements + ADD COLUMN IF NOT EXISTS show_header BOOLEAN DEFAULT true + `); + console.log('โ show_header ์ปฌ๋ผ ์ถ๊ฐ ์๋ฃ'); + + // ๊ธฐ์กด ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ + await PostgreSQLService.query(` + UPDATE dashboard_elements + SET show_header = true + WHERE show_header IS NULL + `); + console.log('โ ๊ธฐ์กด ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ ์๋ฃ'); + + console.log('โ ๋์๋ณด๋ ๋ง์ด๊ทธ๋ ์ด์ ์๋ฃ!'); + } catch (error) { + console.error('โ ๋์๋ณด๋ ๋ง์ด๊ทธ๋ ์ด์ ์คํจ:', error); + // ์ด๋ฏธ ์ปฌ๋ผ์ด ์๋ ๊ฒฝ์ฐ๋ ๋ฌด์ + if (error instanceof Error && error.message.includes('already exists')) { + console.log('โน๏ธ ์ปฌ๋ผ์ด ์ด๋ฏธ ์กด์ฌํฉ๋๋ค.'); + } + } +} + diff --git a/backend-node/src/services/DashboardService.ts b/backend-node/src/services/DashboardService.ts index d7245ce0..f8816555 100644 --- a/backend-node/src/services/DashboardService.ts +++ b/backend-node/src/services/DashboardService.ts @@ -60,9 +60,9 @@ export class DashboardService { INSERT INTO dashboard_elements ( id, dashboard_id, element_type, element_subtype, position_x, position_y, width, height, - title, content, data_source_config, chart_config, + title, custom_title, show_header, content, data_source_config, chart_config, display_order, created_at, updated_at - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) `, [ elementId, @@ -74,6 +74,8 @@ export class DashboardService { element.size.width, element.size.height, element.title, + element.customTitle || null, + element.showHeader !== false, // ๊ธฐ๋ณธ๊ฐ true element.content || null, JSON.stringify(element.dataSource || {}), JSON.stringify(element.chartConfig || {}), @@ -335,6 +337,8 @@ export class DashboardService { height: row.height, }, title: row.title, + customTitle: row.custom_title || undefined, + showHeader: row.show_header !== false, // ๊ธฐ๋ณธ๊ฐ true content: row.content, dataSource: JSON.parse(row.data_source_config || "{}"), chartConfig: JSON.parse(row.chart_config || "{}"), @@ -460,9 +464,9 @@ export class DashboardService { INSERT INTO dashboard_elements ( id, dashboard_id, element_type, element_subtype, position_x, position_y, width, height, - title, content, data_source_config, chart_config, + title, custom_title, show_header, content, data_source_config, chart_config, display_order, created_at, updated_at - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) `, [ elementId, @@ -474,6 +478,8 @@ export class DashboardService { element.size.width, element.size.height, element.title, + element.customTitle || null, + element.showHeader !== false, // ๊ธฐ๋ณธ๊ฐ true element.content || null, JSON.stringify(element.dataSource || {}), JSON.stringify(element.chartConfig || {}), diff --git a/backend-node/src/types/dashboard.ts b/backend-node/src/types/dashboard.ts index f40ee768..789adda3 100644 --- a/backend-node/src/types/dashboard.ts +++ b/backend-node/src/types/dashboard.ts @@ -15,6 +15,8 @@ export interface DashboardElement { height: number; }; title: string; + customTitle?: string; // ์ฌ์ฉ์ ์ ์ ์ ๋ชฉ (์ต์ ) + showHeader?: boolean; // ํค๋ ํ์ ์ฌ๋ถ (๊ธฐ๋ณธ๊ฐ: true) content?: string; dataSource?: { type: "api" | "database" | "static"; diff --git a/frontend/components/admin/dashboard/CanvasElement.tsx b/frontend/components/admin/dashboard/CanvasElement.tsx index c1a682d3..7050b1f2 100644 --- a/frontend/components/admin/dashboard/CanvasElement.tsx +++ b/frontend/components/admin/dashboard/CanvasElement.tsx @@ -455,7 +455,7 @@ export function CanvasElement({ > {/* ํค๋ */}