require('dotenv').config(); const express = require('express'); const { Pool } = require('pg'); const cors = require('cors'); const app = express(); const port = process.env.PORT || 80; // Database Connection const pool = new Pool({ host: process.env.DB_HOST, port: process.env.DB_PORT, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000, }); pool.on('error', (err) => { console.error('Unexpected error on idle client', err); }); // Middleware app.use(cors()); app.use(express.json({ limit: '50mb' })); app.use(express.static(__dirname)); // Helper to run the schema isolation command async function setSchema(client) { const schema = process.env.DB_SCHEMA || 'wind_projekt_bwscheddebrock'; await client.query(`SET search_path TO "${schema}", public;`); } // Database Initial Setup / Migration Logic Removed // (Now treating existing tables as the read-only 'Source of Truth') // --- API Routes --- app.get('/api/health', (req, res) => { res.json({ status: 'OK', schema: process.env.DB_SCHEMA, time: new Date().toISOString() }); }); // 1. Get Owner Data app.get('/api/owners', async (req, res) => { const client = await pool.connect(); try { await setSchema(client); // Using exact quoted names to preserve case-sensitivity const query = ` SELECT "id", "Nachname", "Vorname", "Ort", "Flur", "Flurstueck", "Gemarkung", "status" as "status", "notiz" as "notiz", "Str_HNr", ST_AsGeoJSON(ST_Transform("geom", 4326)) as geometry FROM "eigentuemerdaten" `; const result = await client.query(query); const geojson = { type: "FeatureCollection", features: result.rows.map(row => { const { geometry, ...properties } = row; return { type: "Feature", id: row.id, geometry: JSON.parse(geometry), properties: properties }; }) }; res.json(geojson); } catch (err) { console.error("Owner Fetch Error:", err); res.status(500).json({ error: 'Failed to fetch owner data' }); } finally { client.release(); } }); // 2. Get Usage Data (Nutzung) app.get('/api/usage', async (req, res) => { const client = await pool.connect(); try { await setSchema(client); const query = ` SELECT "id", "nutzart" as "nutzart", ST_AsGeoJSON(ST_Transform("geom", 4326)) as geometry FROM "nutzung" `; const result = await client.query(query); const geojson = { type: "FeatureCollection", features: result.rows.map(row => { const { geometry, ...properties } = row; return { type: "Feature", geometry: JSON.parse(geometry), properties: properties }; }) }; res.json(geojson); } catch (err) { console.error("Usage Fetch Error:", err); res.status(500).json({ error: 'Failed to fetch usage data' }); } finally { client.release(); } }); // 2.5 Get WEA Data app.get('/api/wea', async (req, res) => { const client = await pool.connect(); try { await setSchema(client); const query = ` SELECT "id", "Name", ST_AsGeoJSON(ST_Transform("geom", 4326)) as geometry FROM "wea" `; const result = await client.query(query); const geojson = { type: "FeatureCollection", features: result.rows.map(row => { const { geometry, ...properties } = row; return { type: "Feature", geometry: JSON.parse(geometry), properties: properties }; }) }; res.json(geojson); } catch (err) { res.json({ type: "FeatureCollection", features: [] }); } finally { client.release(); } }); // 2.7 Get Infrastructure Data app.get('/api/infrastructure', async (req, res) => { const client = await pool.connect(); try { await setSchema(client); const query = ` SELECT "id", ST_AsGeoJSON(ST_Transform("geom", 4326)) as geometry FROM "infrastruktur" `; const result = await client.query(query); const geojson = { type: "FeatureCollection", features: result.rows.map(row => { const { geometry, ...properties } = row; return { type: "Feature", geometry: JSON.parse(geometry), properties: properties }; }) }; res.json(geojson); } catch (err) { res.json({ type: "FeatureCollection", features: [] }); } finally { client.release(); } }); // 3. Get Variants (Kabeltrasse) app.get('/api/variants', async (req, res) => { const client = await pool.connect(); try { await setSchema(client); const query = ` SELECT "id", "name", "Variante", ST_AsGeoJSON(ST_Transform(ST_SetSRID("geom", 25832), 4326)) as geometry FROM "kabeltrasse" ORDER BY "id" DESC `; const result = await client.query(query); const featureCollection = { type: "FeatureCollection", features: result.rows.map(row => { return { type: "Feature", id: row.id, geometry: JSON.parse(row.geometry || 'null'), properties: { id: row.id, name: row.name || (row.Variante ? `Variante ${row.Variante}` : 'Neue Trasse'), Variante: row.Variante } }; }) }; res.json(featureCollection); } catch (err) { console.error("Variants Fetch Error:", err); res.status(500).json({ error: 'Failed to fetch variants' }); } finally { client.release(); } }); // 4. Save/Update Variant app.post('/api/variants', async (req, res) => { const { geometry, properties } = req.body; const client = await pool.connect(); try { await setSchema(client); const routeName = properties.name || 'Neue Trasse'; const varianteValue = properties.Variante || (properties.name ? properties.name.replace('Variante ', '') : 'A'); const geoJsonStr = JSON.stringify(geometry); // Using exact quoted column names for the UPSERT const upsertQuery = ` INSERT INTO "kabeltrasse" ("geom", "name", "Variante") VALUES ( ST_MakeValid(ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON($1), 4326), 25832)), $2, $3 ) ON CONFLICT ("Variante") DO UPDATE SET "geom" = EXCLUDED."geom", "name" = EXCLUDED."name" RETURNING "id" `; const upsertRes = await client.query(upsertQuery, [geoJsonStr, routeName, varianteValue]); res.json({ success: true, id: upsertRes.rows[0].id }); } catch (err) { console.error("SQL-FEHLER (SAVE):", err.message); res.status(500).json({ error: 'Failed to save variant' }); } finally { client.release(); } }); // 5. Update Owner Note/Status app.patch('/api/owners/:id', async (req, res) => { const { id } = req.params; const { status, notiz } = req.body; const client = await pool.connect(); try { await setSchema(client); const query = ` UPDATE "eigentuemerdaten" SET "status" = $1, "notiz" = $2 WHERE "id" = $3 RETURNING "id"; `; const result = await client.query(query, [status, notiz, id]); if (result.rowCount === 0) return res.status(404).json({ error: 'Owner not found' }); res.json({ success: true, id: result.rows[0].id }); } catch (err) { console.error("Update Owner Error:", err); res.status(500).json({ error: 'Failed to update owner' }); } finally { client.release(); } }); app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); });