diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 6812170..6d62101 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -31,7 +31,7 @@ jobs: echo "DB_USER=${{ secrets.USER }}" >> .env echo "DB_PASSWORD='${{ secrets.PASSWORD }}'" >> .env echo "DB_NAME=${{ secrets.NAME }}" >> .env - echo "DB_SCHEMA=bw_scheddebrock" >> .env + echo "DB_SCHEMA=wind_projekt_bwscheddebrock" >> .env docker compose up -d --build --force-recreate docker image prune -f diff --git a/docker-compose.yml b/docker-compose.yml index 216dd7b..8bb6747 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ services: - DB_USER=authentik - DB_PASSWORD=WX1t1cgP1qK09 - DB_NAME=authentik - - DB_SCHEMA=bw_scheddebrock + - DB_SCHEMA=wind_projekt_bwscheddebrock networks: - proxy labels: diff --git a/index.html b/index.html index d54459b..d018046 100644 --- a/index.html +++ b/index.html @@ -6,15 +6,15 @@
Keine Daten oder Trasse vorhanden
'; return; } try { - const nested = getNestedCoords(variant.routes); - if (nested.length === 0) return; - - const lines = nested.filter(s => s.length >= 2).map(s => turf.lineString(s.map(ll => [ll.lng, ll.lat]))); - if (lines.length === 0) return; - - const multiLine = lines.length === 1 ? lines[0] : turf.multiLineString(lines.map(l => l.geometry.coordinates)); - const lineBbox = turf.bbox(multiLine); + const line = turf.lineString(latLngs.map(ll => [ll.lng, ll.lat])); + const lineBbox = turf.bbox(line); const intersectingPlots = state.owners.features.filter(f => { try { @@ -2151,7 +2160,7 @@ if (lineBbox[0] > obsBbox[2] || lineBbox[2] < obsBbox[0] || lineBbox[1] > obsBbox[3] || lineBbox[3] < obsBbox[1]) return false; - return turf.booleanIntersects(multiLine, f); + return turf.booleanIntersects(line, f); } catch (e) { return false; } }); @@ -2206,6 +2215,10 @@ // --- Variant Management UI --- window.startNewPath = (id) => { if (map.editTools) { + const v = state.variants.find(v => v.id == id); + if (v && !v.visible) { + toggleVariantVisibility(v.id, true); + } state.isDrawing = true; state.isMeasuring = false; updateToolCursors(); @@ -2281,7 +2294,6 @@ - @@ -2344,7 +2356,7 @@ if (newName && newName.trim()) { v.name = newName.trim(); renderVariants(); - if (activeV) saveVariantToDB(activeV); + if (v) saveVariantToDB(v); } }; @@ -2519,6 +2531,7 @@ // Global Map Click for generous vertex insertion ("Click anywhere near the line") const handleVertexInsertion = (e) => { + if (isClickOnUI(e)) return; if (state.isMeasuring) return; // VERY IMPORTANT: Don't interfere if we are actively drawing a path if (map.editTools && map.editTools.drawing()) return; @@ -2529,24 +2542,14 @@ const layer = routeLayers[variant.id]; if (!layer) return; - // If the variant is empty, we don't return here anymore, - // but we only attempt insertion if we have at least one segment (2 points). - const latlngs = getFlattenedCoords(layer.getLatLngs()); - - // If drawing and clicking far away, we let startPolyline/continueForward handle it - if (latlngs.length < 2) return; - - if (!layer.editor) { - layer.enableEdit(); - } - + const allPoints = (variant.routes || []).map(ll => L.latLng(ll)); let minIdx = -1; let minDist = Infinity; const pt = map.latLngToLayerPoint(e.latlng); - for (let i = 0; i < latlngs.length - 1; i++) { - const p1 = map.latLngToLayerPoint(latlngs[i]); - const p2 = map.latLngToLayerPoint(latlngs[i + 1]); + for (let i = 0; i < allPoints.length - 1; i++) { + const p1 = map.latLngToLayerPoint(allPoints[i]); + const p2 = map.latLngToLayerPoint(allPoints[i + 1]); const dist = L.LineUtil.pointToSegmentDistance(pt, p1, p2); if (dist < minDist) { minDist = dist; @@ -2554,29 +2557,27 @@ } } - // CRITICAL FIX: Check if we are clicking directly on or very near an existing vertex - // If we are closer than 10 pixels to any vertex, we assume the user wants - // to move the point, not insert a new one. - const isNearVertex = latlngs.some(ll => map.latLngToLayerPoint(ll).distanceTo(pt) < 12); + const isNearVertex = allPoints.some(ll => map.latLngToLayerPoint(ll).distanceTo(pt) < 12); if (isNearVertex) return; - // High tolerance hit-testing: 35 pixels (approx. the width of a finger/mouse inaccuracy) + // High tolerance hit-testing: 35 pixels const tolerance = state.isDrawing ? 15 : 35; if (minIdx !== -1 && minDist < tolerance) { - latlngs.splice(minIdx + 1, 0, e.latlng); - layer.setLatLngs(latlngs); + allPoints.splice(minIdx + 1, 0, e.latlng); + variant.routes = allPoints; + layer.setLatLngs(allPoints); - if (layer.editor && layer.editor.reset) { - layer.editor.reset(); + // FORCE REFRESH of editor markers + if (layer.editor) { + layer.disableEdit(); + layer.enableEdit(); } - // Force synchronization - variant.routes = getFlattenedCoords(layer.getLatLngs()); calculateStats(variant); updateVariantStatsUI(variant); renderVariants(); - const _activeV = state.variants.find(v => v.active); if (_activeV) saveVariantToDB(_activeV); + saveVariantToDB(variant); } }; @@ -2691,46 +2692,37 @@ } async function saveVariantToDB(variantDef) { + if (!variantDef) return; + const indicator = document.getElementById('db-status-indicator'); + if (indicator) indicator.classList.add('active'); + try { - // Identify the true state variant regardless of what parameter was passed - const v = variantDef.id ? variantDef : state.variants.find(vx => routeLayers[vx.id] === variantDef); + // Ensure we have a valid variant object and points + const v = variantDef.id ? variantDef : state.variants.find(vx => vx.id === variantDef.id); if (!v) { - console.warn("Save skipped: Could not map to a valid variant."); - return; - } - - const name = v.name || "Neue Trasse"; - let rawRoutes = v.routes || []; - - // Fallback attempt if routes is somehow empty but layer exists - if (rawRoutes.length === 0 && routeLayers[v.id] && typeof routeLayers[v.id].getLatLngs === 'function') { - rawRoutes = routeLayers[v.id].getLatLngs(); + if (indicator) indicator.classList.remove('active'); + return; } - if (!rawRoutes || rawRoutes.length === 0) { - console.warn("Save skipped: No route data available."); + // Simple flat coordinates from LineString + const latLngs = (v.routes || []).map(ll => { + try { return L.latLng(ll); } catch(e) { return null; } + }).filter(p => !!p && typeof p.lat === 'number'); + + if (latLngs.length < 2) { + if (indicator) indicator.classList.remove('active'); return; } - // Leaflet-Punkte in GeoJSON-Format umwandeln [lng, lat] - let geoJsonCoords = []; - const isMulti = routeLayers[v.id] && Array.isArray(rawRoutes[0]); - - if (isMulti || Array.isArray(rawRoutes[0])) { - geoJsonCoords = rawRoutes.map(line => line.map(p => [p.lng, p.lat])); - } else { - geoJsonCoords = rawRoutes.map(p => [p.lng, p.lat]); - } - - const geomType = (isMulti || Array.isArray(rawRoutes[0])) ? "MultiLineString" : "LineString"; - - const payload = { id: v.id, geometry: { - type: geoJsonCoords.length ? geomType : "LineString", - coordinates: geoJsonCoords + const payload = { + id: v.id, + geometry: { + type: "LineString", + coordinates: latLngs.map(p => [p.lng, p.lat]) }, properties: { - name: name, - Variante: name.replace('Variante ', '') + name: v.name, + Variante: v.name.replace('Variante ', '') } }; @@ -2748,113 +2740,98 @@ throw new Error('Server-Fehler: ' + errorText); } + const result = await response.json(); + if (result.success && result.id) { + v.id = result.id; // Sync the database ID back to the state + } console.log("Speichern in Datenbank erfolgreich!"); } catch (err) { console.error("DB Save failed:", err.message); - // alert("Fehler beim Speichern: " + err.message); // Commented to prevent spam during map moves + } finally { + if (indicator) indicator.classList.remove('active'); } } async function loadFromDatabase() { - if (isLoading) return; - isLoading = true; + const indicator = document.getElementById('db-status-indicator'); + if (indicator) indicator.classList.add('active'); + console.log("[V3-Sync] Starte Daten-Abruf vom Server..."); + + const sanitize = (gj) => { + if (!gj || !gj.features) return { type: "FeatureCollection", features: [] }; + return gj; + }; + + // 1. Varianten (JETZT ALS ERSTES) try { - console.log("Starte Daten-Abruf vom Server..."); - - const isVal = (c) => Array.isArray(c) && c.length >= 2 && !isNaN(c[0]) && !isNaN(c[1]) && c[0] !== null && c[1] !== null; - const sanitize = (gj) => { - if (!gj || !gj.features) return { type: "FeatureCollection", features: [] }; - return { - ...gj, - features: gj.features.filter(f => { - if (!f || !f.geometry || !f.geometry.coordinates) return false; - // Recursive coordinate check for simple structures - if (f.geometry.type === 'Point') return isVal(f.geometry.coordinates); - return true; // Polygons are harder to check deeply, but usually safer - }) - }; - }; + const res = await fetch(`${API_BASE}/variants`); + if (res.ok) { + const rawData = await res.json(); + let features = Array.isArray(rawData) ? rawData.map(item => ({ + type: "Feature", + id: item.id, + geometry: { + type: "LineString", + coordinates: (Array.isArray(item.routes[0]) ? item.routes[0] : item.routes) + .map(p => [(p.lng || p[0]), (p.lat || p[1])]) + }, + properties: { Variante: item.name ? item.name.replace('Variante ', '') : 'A', name: item.name } + })) : (rawData.features || []); - // 1. Eigentümer - try { - const res = await fetch(`${API_BASE}/owners`); - if (res.ok) { - let gj = sanitize(await res.json()); - if (gj.features.length > 0) { - // Check for UTM transform - const c = gj.features[0].geometry.coordinates; - const test = Array.isArray(c[0]) ? (Array.isArray(c[0][0]) ? c[0][0][0] : c[0][0]) : c[0]; - if (Math.abs(test) > 1000) gj = transformGeoJSON(gj, "EPSG:25832", "EPSG:4326"); + console.log(`[V3-Sync] ${features.length} Trassen geladen.`); + + features.forEach(f => { + const p = f.properties || {}; + const varName = p.Variante ? `Variante ${p.Variante}` : (p.name || "Variante A"); + const slot = state.variants.find(lv => lv.name === varName); + if (slot && f.geometry && f.geometry.coordinates) { + slot.id = f.id || p.id || slot.id; + slot.routes = f.geometry.coordinates.map(c => ({ lat: c[1], lng: c[0] })); + console.log(`[V3-Sync] ${slot.name} erfolgreich gemappt.`); } - state.owners = gj; - updateOwnerLayer(); - if (layers.owners.getBounds().isValid()) map.fitBounds(layers.owners.getBounds()); - } - } catch (e) { console.error("Owners load error:", e); } + }); - // 2. Varianten - try { - const res = await fetch(`${API_BASE}/variants`); - if (res.ok) { - const v = await res.json(); - v.forEach(sv => { - const l = state.variants.find(lv => lv.id === sv.id); - if (l) { l.routes = sv.routes || []; l.name = sv.name || l.name; } - }); - updateRouteLayers(); - } - } catch (e) { console.error("Variants load error:", e); } + state.variants.forEach(v => { calculateStats(v); updateVariantStatsUI(v); }); + const varA = state.variants.find(v => v.name === "Variante A"); + if (varA) setActiveVariant(varA.id); + renderVariants(); + updateRouteLayers(); + } + } catch (e) { console.error("[V3-Sync] Variants Error:", e); } - // 3. Nutzungen - try { - const res = await fetch(`${API_BASE}/usage`); - if (res.ok) { - let gj = sanitize(await res.json()); - // Transform usage if UTM - if (gj.features.length > 0) { - const c = gj.features[0].geometry.coordinates; - const test = Array.isArray(c[0]) ? (Array.isArray(c[0][0]) ? c[0][0][0] : c[0][0]) : c[0]; - if (Math.abs(test) > 1000) gj = transformGeoJSON(gj, "EPSG:25832", "EPSG:4326"); - } - state.usage = gj; - updateUsageLayer(); + // 2. Eigentümer (SCHWERER LAYER) + try { + const res = await fetch(`${API_BASE}/owners`); + if (res.ok) { + let gj = sanitize(await res.json()); + if (gj.features.length > 0) { + const c = gj.features[0].geometry.coordinates; + if (Math.abs(Array.isArray(c[0]) ? c[0][0] : c[0]) > 1000) gj = transformGeoJSON(gj, "EPSG:25832", "EPSG:4326"); } - } catch (e) { console.error("Usage load error:", e); } + state.owners = gj; + updateOwnerLayer(); + } + } catch (e) { console.error("[V3-Sync] Owners Error:", e); } - // 4. WEA - try { - const res = await fetch(`${API_BASE}/wea`); - if (res.ok) { - let gj = sanitize(await res.json()); - if (gj.features.length > 0) { - if (Math.abs(gj.features[0].geometry.coordinates[0]) > 1000) gj = transformGeoJSON(gj, "EPSG:25832", "EPSG:4326"); - } - state.wea = gj; - updateWEALayer(); + // 3. Nutzungen + try { + const res = await fetch(`${API_BASE}/usage`); + if (res.ok) { + let gj = sanitize(await res.json()); + if (gj.features.length > 0) { + const c = gj.features[0].geometry.coordinates; + if (Math.abs(Array.isArray(c[0]) ? c[0][0] : c[0]) > 1000) gj = transformGeoJSON(gj, "EPSG:25832", "EPSG:4326"); } - } catch (e) { console.error("WEA load error:", e); } + updateUsageLayer(gj); + } + } catch (e) { console.error("[V3-Sync] Usage Error:", e); } - // 5. Infrastruktur - try { - const res = await fetch(`${API_BASE}/infrastructure`); - if (res.ok) { - let gj = sanitize(await res.json()); - if (gj.features.length > 0) { - if (Math.abs(gj.features[0].geometry.coordinates[0]) > 1000) gj = transformGeoJSON(gj, "EPSG:25832", "EPSG:4326"); - } - state.infrastructure = gj; - updateInfrastructureLayer(); - } - } catch (e) { console.error("Infra load error:", e); } - - console.log("Daten-Ladevorgang abgeschlossen."); - } catch (err) { - console.error("Kritischer Fehler beim Laden der Datenbank:", err); - } finally { - isLoading = false; - renderVariants(); - } + console.log("[V3-Sync] Daten-Ladevorgang abgeschlossen."); + if (indicator) indicator.classList.remove('active'); + isLoading = false; + renderVariants(); } + let isSaving = false; async function saveToFolder() { if (isSaving || !state.directoryHandle) return; @@ -3117,6 +3094,26 @@ input.click(); }); + window.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + if (map.editTools) { + if (map.editTools.drawing()) { + map.editTools.stopDrawing(); + } + state.isDrawing = false; + state.isMeasuring = false; + updateToolCursors(); + renderVariants(); + + const activeV = state.variants.find(v => v.active); + if (activeV && routeLayers[activeV.id]) { + routeLayers[activeV.id].enableEdit(); + saveVariantToDB(activeV); + } + } + } + }); + window.addEventListener('load', async () => { try { initApp(); diff --git a/server.js b/server.js index bd4a500..85cfec8 100644 --- a/server.js +++ b/server.js @@ -28,32 +28,33 @@ app.use(express.static(__dirname)); // Helper to run the schema isolation command async function setSchema(client) { - await client.query(`SET search_path TO ${process.env.DB_SCHEMA}, public;`); + const schema = process.env.DB_SCHEMA || 'wind_projekt_bwscheddebrock'; + await client.query(`SET search_path TO "${schema}", public;`); } -// Routes +// 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', time: new Date().toISOString() }); + res.json({ status: 'OK', schema: process.env.DB_SCHEMA, time: new Date().toISOString() }); }); // 1. Get Owner Data app.get('/api/owners', async (req, res) => { - console.log("Anfrage erhalten: /api/owners"); const client = await pool.connect(); try { await setSchema(client); - // 1. Log actual count in DB - const countRes = await client.query('SELECT count(*) FROM bw_scheddebrock."Eigentuemerdaten"'); - console.log(`Datenbank-Check: ${countRes.rows[0].count} Eigentümer in bw_scheddebrock."Eigentuemerdaten" gefunden.`); + const countRes = await client.query('SELECT count(*) FROM "Eigentuemerdaten"'); + console.log(`Datenbank-Check: ${countRes.rows[0].count} Einträge in "Eigentuemerdaten".`); const query = ` SELECT *, ST_AsGeoJSON(ST_Transform(geom, 4326)) as geometry - FROM bw_scheddebrock."Eigentuemerdaten" + FROM "Eigentuemerdaten" `; const result = await client.query(query); - console.log(`Abfrage erfolgreich: ${result.rowCount} Zeilen für Frontend geladen.`); const geojson = { type: "FeatureCollection", @@ -62,7 +63,7 @@ app.get('/api/owners', async (req, res) => { const geomObj = typeof geometry === 'string' ? JSON.parse(geometry) : geometry; return { type: "Feature", - id: row.id || row.id_0, + id: row.id, geometry: geomObj, properties: properties }; @@ -82,18 +83,13 @@ app.get('/api/usage', async (req, res) => { const client = await pool.connect(); try { await setSchema(client); - // 1. Log actual count in DB - const countRes = await client.query('SELECT count(*) FROM bw_scheddebrock."Nutzung"'); - console.log(`Datenbank-Check: ${countRes.rows[0].count} Nutzungs-Flächen in bw_scheddebrock."Nutzung" gefunden.`); - const query = ` SELECT *, ST_AsGeoJSON(ST_Transform(geom, 4326)) as geometry - FROM bw_scheddebrock."Nutzung" + FROM "Nutzung" `; const result = await client.query(query); - console.log(`Abfrage erfolgreich: ${result.rowCount} Zeilen für Frontend geladen.`); const geojson = { type: "FeatureCollection", @@ -116,7 +112,7 @@ app.get('/api/usage', async (req, res) => { } }); -// 2.5 Get WEA Data (Windturbinen) +// 2.5 Get WEA Data app.get('/api/wea', async (req, res) => { const client = await pool.connect(); try { @@ -127,10 +123,9 @@ app.get('/api/wea', async (req, res) => { SELECT *, ST_AsGeoJSON(ST_Transform(geom, 4326)) as geometry - FROM bw_scheddebrock."WEA" + FROM "WEA" `); } catch (dbErr) { - console.log("WEA Tabelle fehlt oder nicht abrufbar."); result = { rows: [], rowCount: 0 }; } @@ -155,7 +150,7 @@ app.get('/api/wea', async (req, res) => { } }); -// 2.7 Get Infrastructure Data (UW, etc) +// 2.7 Get Infrastructure Data app.get('/api/infrastructure', async (req, res) => { const client = await pool.connect(); try { @@ -166,10 +161,9 @@ app.get('/api/infrastructure', async (req, res) => { SELECT *, ST_AsGeoJSON(ST_Transform(geom, 4326)) as geometry - FROM bw_scheddebrock."Infrastruktur" + FROM "Infrastruktur" `); } catch (dbErr) { - console.log("Infrastruktur Tabelle fehlt oder nicht abrufbar."); result = { rows: [], rowCount: 0 }; } @@ -199,41 +193,32 @@ app.get('/api/variants', async (req, res) => { const client = await pool.connect(); try { await setSchema(client); - - // Log count - const countRes = await client.query('SELECT count(*) FROM bw_scheddebrock."Kabeltrasse"'); - console.log(`Datenbank-Check: ${countRes.rows[0].count} Kabeltrassen in bw_scheddebrock."Kabeltrasse" gefunden.`); - const query = ` SELECT - id_0 as id, name, "Variante", + id, name, "Variante", ST_AsGeoJSON(ST_Transform(ST_SetSRID(geom, 25832), 4326)) as geometry - FROM bw_scheddebrock."Kabeltrasse" - ORDER BY id_0 DESC + FROM "Kabeltrasse" + ORDER BY id DESC `; const result = await client.query(query); - console.log(`Abfrage erfolgreich: ${result.rowCount} Trassen geladen.`); - const variants = result.rows.map(row => { - let routes = []; - const geomObj = typeof row.geometry === 'string' ? JSON.parse(row.geometry) : row.geometry; - if (geomObj && geomObj.coordinates) { - if (geomObj.type === 'MultiLineString') { - routes = geomObj.coordinates.map(line => line.map(c => ({ lat: c[1], lng: c[0] }))); - } else if (geomObj.type === 'LineString') { - routes = geomObj.coordinates.map(c => ({ lat: c[1], lng: c[0] })); - } - } - return { - id: row.id, - name: row.name || row.Variante || 'Trasse', - active: false, - visible: true, - stats: { total: 0, drilling: 0, open: 0, muffen: 0 }, - routes: routes - }; - }); - res.json(variants); + const featureCollection = { + type: "FeatureCollection", + features: result.rows.map(row => { + const geomObj = JSON.parse(row.geometry || 'null'); + return { + type: "Feature", + id: row.id, + geometry: geomObj, + properties: { + id: row.id, + name: row.name || (row.Variante ? `Variante ${row.Variante}` : 'Neue Trasse'), + Variante: row.Variante + } + }; + }) + }; + res.json(featureCollection); } catch (err) { console.error(err); res.status(500).json({ error: 'Failed to fetch variants' }); @@ -244,52 +229,36 @@ app.get('/api/variants', async (req, res) => { // 4. Save/Update Variant app.post('/api/variants', async (req, res) => { - console.log("Empfangene Daten (Payload):", JSON.stringify(req.body).substring(0, 200) + "..."); const { geometry, properties } = req.body; const client = await pool.connect(); try { await setSchema(client); - console.log("Starte PostgreSQL-Query..."); - - // Clean UPSERT by Database ID. - const routeId = req.body.id; const routeName = properties.name || 'Neue Trasse'; - const variante = properties.Variante || properties.name || 'A'; + const variante = 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 + `; - // Check if the passed ID is a valid database ID (small int) vs a frontend dummy Date.now() timestamp - // Or try to match it initially just in case it's a known database row. - const existing = await client.query('SELECT id_0 FROM bw_scheddebrock."Kabeltrasse" WHERE id_0 = $1', [Number(routeId) || 0]); + const upsertRes = await client.query(upsertQuery, [geoJsonStr, routeName, variante]); + const finalId = upsertRes.rows[0].id; - let result; - if (existing.rowCount > 0) { - // EXACT match found physically in DB, do an UPDATE - const updateQuery = ` - UPDATE bw_scheddebrock."Kabeltrasse" - SET geom = ST_MakeValid(ST_SetSRID(ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON($1), 4326), 25832), 25832)), - name = $2, - "Variante" = $3 - WHERE id_0 = $4 - RETURNING id_0 as id; - `; - result = await client.query(updateQuery, [geoJsonStr, routeName, variante, existing.rows[0].id_0]); - console.log(`PostgreSQL-Ergebnis: Zeile ${existing.rows[0].id_0} aktualisiert (Variante: ${routeName})!`); - } else { - // INSERT new - const insertQuery = ` - INSERT INTO bw_scheddebrock."Kabeltrasse" (geom, name, "Variante") - VALUES (ST_MakeValid(ST_SetSRID(ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON($1), 4326), 25832), 25832)), $2, $3) - RETURNING id_0 as id; - `; - result = await client.query(insertQuery, [geoJsonStr, routeName, variante]); - console.log(`PostgreSQL-Ergebnis: Zeile eingefügt! ID: ${result.rows[0].id}`); - } - - res.json({ success: true, id: result.rows[0].id }); + res.json({ success: true, id: finalId }); } catch (err) { - console.error("KRITISCHER SQL-FEHLER:", err.message); - res.status(500).json({ error: 'Failed to save variant: ' + err.message }); + console.error("SQL-FEHLER (SAVE):", err.message); + res.status(500).json({ error: 'Failed to save variant' }); } finally { client.release(); } @@ -303,18 +272,18 @@ app.patch('/api/owners/:id', async (req, res) => { try { await setSchema(client); const query = ` - UPDATE bw_scheddebrock."Eigentuemerdaten" + 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 in database' }); + return res.status(404).json({ error: 'Owner not found' }); } res.json({ success: true, id: result.rows[0].id }); } catch (err) { - console.error("Owner Update Error:", err); + console.error(err); res.status(500).json({ error: 'Failed to update owner' }); } finally { client.release();