paul.roost ca05e334a7 feat: Implement server-side API for categories, KPIs, and measurements
- Added Express server with SQLite database connection.
- Created API endpoints to fetch categories, KPIs, measurements, and statistics.
- Implemented error handling for database operations.

feat: Create ChartModal component for visualizing KPI data

- Developed ChartModal to display line charts for KPI measurements.
- Integrated Chart.js for rendering charts with responsive design.
- Added styling for modal and chart components.

feat: Add ExportModal component for exporting KPI data

- Implemented ExportModal to allow users to select data ranges for export.
- Included radio buttons for predefined time ranges (last week, month, year, all data).
- Styled modal for better user experience.

feat: Introduce RangeChartModal for dynamic range selection

- Created RangeChartModal to visualize KPI data over user-selected time ranges.
- Integrated radio buttons for selecting different time ranges.
- Enhanced chart rendering with Chart.js.

refactor: Create useSQLiteDatabase hook for data fetching

- Developed custom hook to manage fetching categories, KPIs, and measurements.
- Improved error handling and loading states for better user feedback.

style: Add CSS styles for modals and charts

- Created styles for ChartModal, ExportModal, and RangeChartModal.
- Ensured responsive design for various screen sizes.
2025-10-21 13:31:14 +02:00

84 lines
2.2 KiB
TypeScript

import sqlite3 from 'sqlite3';
import { open } from 'sqlite';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const DB_PATH = path.join(__dirname, '../../database/sqdc.db');
export async function initDB() {
const db = await open({
filename: DB_PATH,
driver: sqlite3.Database
});
await db.exec(`
CREATE TABLE IF NOT EXISTS categories (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
emoji TEXT,
description TEXT
);
CREATE TABLE IF NOT EXISTS kpis (
id INTEGER PRIMARY KEY,
category_id INTEGER NOT NULL,
name TEXT NOT NULL,
unit TEXT,
target REAL,
formula TEXT,
description TEXT,
frequency TEXT,
FOREIGN KEY(category_id) REFERENCES categories(id)
);
CREATE TABLE IF NOT EXISTS measurements (
id INTEGER PRIMARY KEY AUTOINCREMENT,
kpi_id INTEGER NOT NULL,
measurement_date DATETIME NOT NULL,
value REAL NOT NULL,
status TEXT,
FOREIGN KEY(kpi_id) REFERENCES kpis(id)
);
CREATE TABLE IF NOT EXISTS alerts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
kpi_id INTEGER NOT NULL,
alert_type TEXT,
severity TEXT,
message TEXT,
created_at DATETIME,
FOREIGN KEY(kpi_id) REFERENCES kpis(id)
);
CREATE INDEX IF NOT EXISTS idx_measurements_kpi ON measurements(kpi_id);
CREATE INDEX IF NOT EXISTS idx_measurements_date ON measurements(measurement_date);
CREATE INDEX IF NOT EXISTS idx_alerts_kpi ON alerts(kpi_id);
`);
return db;
}
export async function getKPIs(db) {
return await db.all('SELECT * FROM kpis');
}
export async function getMeasurements(db, kpiId, days = 30) {
const fromDate = new Date();
fromDate.setDate(fromDate.getDate() - days);
return await db.all(
'SELECT * FROM measurements WHERE kpi_id = ? AND measurement_date >= ? ORDER BY measurement_date ASC',
[kpiId, fromDate.toISOString()]
);
}
export async function getLatestMeasurement(db, kpiId) {
return await db.get(
'SELECT * FROM measurements WHERE kpi_id = ? ORDER BY measurement_date DESC LIMIT 1',
[kpiId]
);
}