bwscheddebrock_trassenplaner/server.js

289 lines
7.6 KiB
JavaScript

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);
// Strict Case-Sensitivity Mapping based on server structure
const query = `
SELECT
id,
nachname AS "Nachname",
vorname AS "Vorname",
ort AS "Ort",
"Flur" AS "Flur",
"FlSt" AS "Flurstueck",
"Gema" AS "Gemarkung",
"PLZ" AS "PLZ",
"Land" AS "Land",
"AFlaeche" AS "AFlaeche",
status as "status",
notiz as "notiz",
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" AS "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" AS "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);
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}`);
});