diff --git a/.dockerignore b/.dockerignore index 80054d0..69951f8 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,8 +1,8 @@ .git +.agents +.codex .next +data dist node_modules -data -*.db -.env -.env.* +npm-debug.log* diff --git a/Dockerfile b/Dockerfile index 41a08fd..70e7761 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,12 @@ -FROM node:22 +FROM node:22-bookworm-slim + WORKDIR /app -COPY package*.json ./ +ENV NEXT_TELEMETRY_DISABLED=1 + +COPY package.json package-lock.json ./ RUN npm ci COPY . . -RUN npm run build:api && npm run build:web -RUN mkdir -p data && chmod +x scripts/docker-start.sh - -EXPOSE 3001 - -CMD ["sh", "scripts/docker-start.sh"] +EXPOSE 3000 3001 diff --git a/scripts/docker-start.sh b/scripts/docker-start.sh deleted file mode 100644 index bf0d856..0000000 --- a/scripts/docker-start.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -set -e - -echo "Running migrations..." -node scripts/run-migrations.js - -echo "Starting API server on :3000..." -node dist/server/index.js & - -echo "Waiting for API..." -until node -e "require('http').get('http://localhost:3000/health', r => process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))" 2>/dev/null; do - sleep 1 -done - -echo "Starting Next.js on :3001..." -exec node_modules/.bin/next start -p 3001 diff --git a/scripts/run-migrations.js b/scripts/run-migrations.js deleted file mode 100644 index ebbed8a..0000000 --- a/scripts/run-migrations.js +++ /dev/null @@ -1,16 +0,0 @@ -const { migrate } = require('drizzle-orm/better-sqlite3/migrator'); -const { drizzle } = require('drizzle-orm/better-sqlite3'); -const Database = require('better-sqlite3'); -const fs = require('node:fs'); -const path = require('node:path'); - -const dataDir = path.resolve('data'); -if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true }); - -const sqlite = new Database(path.join(dataDir, 'leistungsbilanz.db')); -const db = drizzle(sqlite); - -migrate(db, { migrationsFolder: path.resolve('src/db/migrations') }); -sqlite.close(); - -console.log('Migrations applied'); diff --git a/src/app/globals.css b/src/app/globals.css index 22da5df..c73e0f8 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1396,68 +1396,3 @@ a.kpi:hover { max-height: calc(100vh - 5.5rem); } } - -/* ── Seitenleiste: eingeklappter Zustand ─────────────────────────────── */ - -.app-shell { - transition: grid-template-columns 0.18s ease; -} - -.app-shell-collapsed { - grid-template-columns: 64px 1fr; -} - -.sidebar { - transition: padding 0.18s ease; -} - -.sidebar-brand { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 8px; -} - -.sidebar-toggle { - background: rgba(255, 255, 255, 0.08); - border: 0; - border-radius: 6px; - color: #fff; - cursor: pointer; - display: inline-flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - font-size: 0.8rem; - line-height: 1; - width: 26px; - height: 26px; -} - -.sidebar-toggle:hover { - background: rgba(255, 255, 255, 0.18); -} - -.sidebar-collapsed .sidebar-brand { - padding: 16px 10px; - flex-direction: column; - align-items: center; -} - -.sidebar-collapsed .sidebar-brand-text { - display: none; -} - -.sidebar-collapsed .sidebar-nav { - padding: 12px 8px; -} - -.sidebar-collapsed .sidebar-link { - justify-content: center; - padding: 10px; -} - -.sidebar-collapsed .sidebar-section-label, -.sidebar-collapsed .sidebar-label { - display: none; -} diff --git a/src/app/projects/page.tsx b/src/app/projects/page.tsx index 21409fd..93a2d14 100644 --- a/src/app/projects/page.tsx +++ b/src/app/projects/page.tsx @@ -14,7 +14,6 @@ import type { CreateGlobalDeviceInput, GlobalDeviceDto, } from "../../frontend/types"; -import { GzfPickerModal } from "../../frontend/components/gzf-picker-modal"; const PROJECTS_CHANGED_EVENT = "leistungsbilanz:projects-changed"; @@ -68,7 +67,6 @@ export default function ProjectsPage() { id: string; name: string; } | null>(null); - const [isGzfPickerOpen, setIsGzfPickerOpen] = useState(false); async function loadData() { setError(null); @@ -382,28 +380,18 @@ export default function ProjectsPage() { } /> -
-
- - setGlobalDeviceForm((current) => ({ ...current, demandFactor: event.target.value })) - } - /> - -
+
+ + setGlobalDeviceForm((current) => ({ ...current, demandFactor: event.target.value })) + } + />
update("simultaneityFactor", event.target.value)} - step="0.01" - type="number" - value={values.simultaneityFactor} - /> - -
-
+ update("simultaneityFactor", value)} + step="0.01" + value={values.simultaneityFactor} + /> - {isGzfPickerOpen ? ( - setIsGzfPickerOpen(false)} - onSelect={(value) => { - update("simultaneityFactor", String(value)); - setIsGzfPickerOpen(false); - }} - /> - ) : null} - ); } diff --git a/src/shared/constants/amev-gzf.ts b/src/shared/constants/amev-gzf.ts deleted file mode 100644 index 0833091..0000000 --- a/src/shared/constants/amev-gzf.ts +++ /dev/null @@ -1,38 +0,0 @@ -export interface AmevGzfEntry { - group: string; - range: string; - mean: number; - overallRange?: string; -} - -// Quelle: AMEV „Planungshilfe für elektrische Leistungsbilanzen" (rev. 4), -// Tabelle 3 – Gleichzeitigkeitsfaktoren für Verbrauchergruppen. -export const AMEV_GZF_TABLE: AmevGzfEntry[] = [ - { group: "Absaugung, Digestorien", range: "0,7", mean: 0.7 }, - { group: "Aufzüge/Rolltreppen", range: "0,2 – 0,7", mean: 0.5, overallRange: "0,2" }, - { group: "Beleuchtungsanlagen", range: "0,7 – 0,8", mean: 0.75, overallRange: "0,4" }, - { group: "Beleuchtungsanlagen in innenliegenden Räumen", range: "0,7 – 0,9", mean: 0.8 }, - { group: "IuK-Anlagen", range: "1", mean: 1, overallRange: "1" }, - { group: "Experimentieranlagen", range: "0,2 – 0,4", mean: 0.3 }, - { group: "Heizung", range: "0,7 – 1", mean: 0.85 }, - { group: "Kälteanlagen", range: "0,8 – 1", mean: 0.9, overallRange: "0,4 – 0,5" }, - { group: "Küchen elektrisch ohne Energieoptimierung", range: "0,3 – 0,7", mean: 0.6 }, - { group: "Küchen elektrisch mit Energieoptimierung", range: "0,2 – 0,6", mean: 0.4 }, - { group: "Lastenaufzüge, Krananlagen", range: "0,2", mean: 0.2 }, - { - group: "Lüftungsanlagen, kontrollierte Lüftung", - range: "0,7", - mean: 0.7, - overallRange: "0,4 – 0,5", - }, - { - group: "Steckdosen 230 V allg. Verbraucher (100 W/Steckdose)", - range: "0,1 – 0,3", - mean: 0.2, - }, - { group: "Steckdosen 230 V für IuK (100 W/Steckdose)", range: "0,7 – 0,9", mean: 0.8 }, - { group: "Steckdosen 400 V (1000 W/Steckdose)", range: "0,1 – 0,5", mean: 0.35 }, - { group: "Schmutz-, Warmwasserpumpen", range: "0,2 – 0,4", mean: 0.3 }, - { group: "Umwälzpumpen", range: "0,6 – 1", mean: 0.8 }, - { group: "Werkstätten", range: "0,2 – 0,4", mean: 0.3 }, -];