diff --git a/README.md b/README.md
index 9117cba..267a2b5 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,36 @@
-# Legacy App Archiv
+# Kaffeeliste
-Dieses Verzeichnis enthält den bisherigen PHP-Bestand der Kaffeeliste.
+Dieses Repository enthält den laufenden Umbau der Kaffeelisten-App von einer
+Windows/IIS/LDAP-gebundenen Legacy-App zu einer mehrkundenfähigen SaaS-
+Anwendung. Der Umbau erfolgt schrittweise im selben Repository, nicht in
+einem getrennten Zielverzeichnis: Legacy-Seiten und neue SaaS-Bausteine
+liegen nebeneinander, bis eine Seite vollständig auf das neue Modell
+umgestellt ist.
-Es bleibt aus drei Gründen im Repository:
+Den vollständigen Plan mit Zielbild, Datenmodell, Rollenmodell und
+Meilensteinen beschreibt `docs/saas-umstrukturierungsplan.md`. Der
+Fortschritt je Meilenstein steht in `docs/m2-technical-foundation.md` bis
+`docs/m5-app-kern.md`.
-- als Referenz für die bestehende Fachlogik
-- als Quelle für Datenmigrationen in die SaaS-Version
-- als Rückfalloption während der Übergangsphase
+## Struktur
-## Wichtige Legacy-Bereiche
+- Legacy- und SaaS-Seiten liegen als flache PHP-Dateien im Webroot, zum
+ Beispiel `index.php`, `stricheintragen.php`, `kaffeeliste.php`,
+ `mitarbeiterverwalten.php`.
+- `app/`: zentrale Bausteine für Bootstrap, DB-Zugriff, Auth, Mail und das
+ neue Ledger-Modell (`app/ledger.php`).
+- `database/migrations/`: versionierte Schemaänderungen, anzuwenden über
+ `scripts/migrate.php`.
+- `scripts/`: Migrations-, Backfill- und Prüfskripte (Golden Master,
+ HTTP-Smoke, M3/M4-Checks).
+- `docs/`: Planungs- und Meilensteindokumentation.
-- `index.php`: persönliches Dashboard
-- `stricheintragen.php`: Sammelerfassung für Kaffee-Striche
-- `einzahlung.php`: Sammelerfassung für Einzahlungen
-- `kaffeeliste.php`: operative Gesamtübersicht
-- `mitarbeiterverwalten.php`: Mitglieder- und Rollenpflege
-- `letzteneintraege.php`: Korrektur letzter Buchungen
-- `hinweise.php`: Banner/Hinweise
+## Umgang mit Legacy-Seiten
-## Umgang Mit Dem Archiv
-
-- Keine neuen Produktfunktionen mehr hier entwickeln.
-- Nur noch für Referenz, Datenabgleich oder Notfallbetrieb verwenden.
-- Neue Arbeit findet ausschließlich in `../saas-app/` und `../docs/` statt.
+- Seiten, die noch direkt auf `kl_*`-Tabellen schreiben, werden schrittweise
+ auf tenant-sicheres Lesen/Schreiben über `app/ledger.php` und
+ `app/saas-auth.php` umgestellt; siehe die Meilensteindokumente für den
+ aktuellen Stand je Seite.
+- Neue Produktfunktionen entstehen gegen das neue Modell (Tenants, Users,
+ Participants, Ledger), nicht mehr direkt gegen die `kl_*`-Tabellen.
+- Lokale Entwicklung gegen MySQL ist in `docs/dev-mysql.md` beschrieben.
diff --git a/app/ledger.php b/app/ledger.php
index 5868954..e6d8b86 100644
--- a/app/ledger.php
+++ b/app/ledger.php
@@ -319,6 +319,74 @@ function ledger_mirror_legacy_consumption(PDO $pdo, int $tenantId, int $legacyCo
}
}
+function ledger_mirror_legacy_payment(PDO $pdo, int $tenantId, int $legacyPaymentId): void
+{
+ $stmt = $pdo->prepare(
+ "INSERT INTO ledger_entries
+ (tenant_id, participant_id, type, amount_cents, marks_count,
+ unit_price_cents, booked_at, source, note, legacy_table, legacy_id)
+ SELECT
+ p.tenant_id,
+ p.id,
+ 'payment',
+ CAST(ROUND(e.Betrag * 100) AS SIGNED),
+ NULL,
+ NULL,
+ e.Datum,
+ 'legacy_payment',
+ NULL,
+ 'kl_Einzahlungen',
+ e.EinzahlungsID
+ FROM kl_Einzahlungen e
+ JOIN participants p
+ ON p.tenant_id = ?
+ AND p.legacy_mitarbeiter_id = e.MitarbeiterID
+ WHERE e.EinzahlungsID = ?
+ ON DUPLICATE KEY UPDATE
+ participant_id = VALUES(participant_id),
+ type = VALUES(type),
+ amount_cents = VALUES(amount_cents),
+ marks_count = VALUES(marks_count),
+ unit_price_cents = VALUES(unit_price_cents),
+ booked_at = VALUES(booked_at),
+ source = VALUES(source),
+ note = VALUES(note)"
+ );
+ $stmt->execute([$tenantId, $legacyPaymentId]);
+
+ $check = $pdo->prepare(
+ "SELECT COUNT(*)
+ FROM ledger_entries
+ WHERE tenant_id = ?
+ AND legacy_table = 'kl_Einzahlungen'
+ AND legacy_id = ?"
+ );
+ $check->execute([$tenantId, $legacyPaymentId]);
+ if ((int)$check->fetchColumn() !== 1) {
+ throw new RuntimeException('Die Legacy-Einzahlung konnte nicht ins Ledger gespiegelt werden.');
+ }
+}
+
+/**
+ * Marks the ledger entry mirrored from a legacy row as voided instead of
+ * deleting it, so corrections stay auditable. Idempotent: voiding an
+ * already-voided or missing entry is a no-op and returns false.
+ */
+function ledger_void_entry_by_legacy_id(PDO $pdo, int $tenantId, string $legacyTable, int $legacyId): bool
+{
+ $stmt = $pdo->prepare(
+ "UPDATE ledger_entries
+ SET voided_at = NOW()
+ WHERE tenant_id = ?
+ AND legacy_table = ?
+ AND legacy_id = ?
+ AND voided_at IS NULL"
+ );
+ $stmt->execute([$tenantId, $legacyTable, $legacyId]);
+
+ return $stmt->rowCount() > 0;
+}
+
/**
* Options:
* - participant_id: int
diff --git a/docs/m5-app-kern.md b/docs/m5-app-kern.md
index 5c9038d..caafb00 100644
--- a/docs/m5-app-kern.md
+++ b/docs/m5-app-kern.md
@@ -1,6 +1,6 @@
# M5 App-Kern
-Stand: 2026-07-14
+Stand: 2026-07-14 (fortgeführt)
M5 stellt die operativen App-Seiten schrittweise auf das neue tenant-sichere
Modell um. Der Start erfolgt bewusst read-only, damit Summen, Links und
@@ -67,15 +67,80 @@ Umgesetzter Umfang `index.php`:
- Eigene Web-Striche bleiben mit dem bestehenden Legacy-Datensatz kompatibel
und werden direkt ins Ledger gespiegelt.
+## Fortsetzung: Schreibseiten und Storno
+
+Umgesetzte Dateien:
+
+```text
+stricheintragen.php
+einzahlung.php
+letzteneintraege.php
+app/ledger.php
+scripts/check-m4-ledger-migration.php
+```
+
+Umgesetzter Umfang `stricheintragen.php` und `einzahlung.php`:
+
+- Beide Sammelerfassungsseiten waren zuvor ohne jede Zugriffsprüfung
+ erreichbar (nur CSRF-Schutz, kein `checkKaffeelisteAdmin`- oder Rollen-Check).
+ Das ist jetzt behoben: Zugriff erfordert SaaS-Rolle `owner`, `admin` oder
+ `treasurer`, oder im Legacy-/Dev-Fallback `checkKaffeelisteAdmin` mit dem
+ Default-Tenant.
+- Jede eingetragene Legacy-Zeile (`kl_Kaffeeverbrauch` beziehungsweise
+ `kl_Einzahlungen`) wird innerhalb derselben Transaktion sofort über
+ `ledger_mirror_legacy_consumption()` beziehungsweise die neue
+ `ledger_mirror_legacy_payment()` ins Ledger gespiegelt. Schlägt die
+ Spiegelung fehl, wird die gesamte Sammelerfassung zurückgerollt statt
+ teilweise gespeichert zu werden.
+- Ein vorbestehender Bug wurde nebenbei behoben: Bei einer POST-Anfrage blieb
+ `$sqlMitarbeiter` unbelegt, was einen PHP-Warning erzeugte und die
+ Mitarbeiterliste nach dem Speichern leer ließ.
+
+Umgesetzter Umfang `letzteneintraege.php`:
+
+- Der Seitenzugriff nutzte bisher ausschließlich den Legacy-Check
+ `checkKaffeelisteAdmin`, wodurch neu registrierte SaaS-Mandanten (ohne
+ Legacy-`kl_Mitarbeiter`-Zeile) die Seite nie hätten nutzen können. Jetzt gilt
+ dieselbe Rollen-/Fallback-Logik wie in `kaffeeliste.php`.
+- Löschen erzeugt keinen harten Delete im Ledger mehr. Neue Funktion
+ `ledger_void_entry_by_legacy_id()` setzt `voided_at` auf dem gespiegelten
+ Ledger-Eintrag, bevor die Legacy-Zeile aus `kl_Einzahlungen` oder
+ `kl_Kaffeeverbrauch` entfernt wird (in einer Transaktion). Der Ledger-Eintrag
+ bleibt damit für die Revision erhalten; alle Lesepfade filtern bereits
+ konsistent auf `voided_at IS NULL`.
+- Zwei nie aufgerufene Funktionen (`berechneGesamtausgabe`,
+ `berechneGesamtstriche`, `berechneGesamteinzahlungen`) wurden als toten Code
+ entfernt.
+
+Angepasstes Check-Skript:
+
+- `scripts/check-m4-ledger-migration.php` ging bisher davon aus, dass jeder
+ gespiegelte Ledger-Eintrag eine noch existierende Legacy-Zeile hat. Das ist
+ durch das Storno-Modell nicht mehr korrekt: Ein stornierter Eintrag hat
+ absichtlich keine Legacy-Zeile mehr, bleibt aber im Ledger stehen. Die
+ Prüfungen filtern jetzt zusätzlich auf `voided_at IS NULL`, sodass echte
+ Dateninkonsistenzen weiterhin erkannt werden, stornierte Einträge aber nicht
+ mehr als Fehler zählen.
+
+Alle drei Flows wurden gegen die Remote-Dev-Datenbank live per HTTP getestet
+(Sammeleintrag Striche, Sammeleinzahlung, Storno beider Buchungsarten über
+`letzteneintraege.php`) und anschließend wieder auf den Ausgangsstand
+zurückgesetzt.
+
## Noch offen
-- Schreibseiten `stricheintragen.php` und `einzahlung.php` erst danach mit
- Storno-/Reversal-Strategie vorbereiten.
+- Eigene PayPal-/Zahlungsbereich als eigenständiger App-Screen (aktuell nur im
+ Dashboard integriert).
+- Mitgliederverwaltung tenant- und rollenbasiert umsetzen
+ (`mitarbeiterverwalten.php` ist noch nicht angefasst).
+- Hinweise als tenant-spezifische Notices umsetzen.
- Export, Mail und Jahresprozesse bleiben M6-Themen.
## Aktueller Prüfstatus
-- M4 Ledger-Migration: grün mit 73 Assertions.
+- M4 Ledger-Migration: grün mit 73 Assertions (Storno-fähig).
- M4 Ledger-Service: grün mit 115 Assertions.
- Golden Master: grün mit 104 Assertions.
- HTTP-Smoke: grün mit 23 geprüften Seiten.
+- Live-Test der Schreibflows gegen die Dev-DB: Sammelstriche, Sammeleinzahlung
+ und Storno beider Buchungsarten erfolgreich geprüft.
diff --git a/einzahlung.php b/einzahlung.php
index 9d5eab0..9b46969 100644
--- a/einzahlung.php
+++ b/einzahlung.php
@@ -1,6 +1,7 @@
Kein Zugriff";
+ include "footer.php";
+ exit;
+}
// Verarbeitung des Formulars, wenn es gesendet wurde
if ($_SERVER["REQUEST_METHOD"] == "POST" ) {
- // Iteriere über alle Mitarbeiter
- foreach ($_POST["anzahlBetrag"] as $mitarbeiterID => $anzahlBetrag) {
- // Validierung könnte hier hinzugefügt werden
- #$anzahlBetrag = $anzahlBetrag;
- $anzahlBetrag = floatval($anzahlBetrag);
-
- if($anzahlBetrag != 0){
- $datum = date("Y-m-d H:i:s"); // Das aktuelle Datum verwenden
+ $datum = date("Y-m-d H:i:s"); // Das aktuelle Datum verwenden
+ $eingetragen = 0;
+ $fehlgeschlagen = false;
- // SQL-Abfrage zum Einfügen der Daten
- $sql = "INSERT INTO kl_Einzahlungen (MitarbeiterID, Betrag, Datum) VALUES (?, ?, ?)";
- $params = array($mitarbeiterID, $anzahlBetrag, $datum);
+ try {
+ $pdo->beginTransaction();
+ $insert = $pdo->prepare(
+ "INSERT INTO kl_Einzahlungen (MitarbeiterID, Betrag, Datum) VALUES (?, ?, ?)"
+ );
- $stmt = sqlsrv_query($conn, $sql, $params);
-
- if ($stmt === false) {
- die(print_r(sqlsrv_errors(), true));
+ foreach ($_POST["anzahlBetrag"] ?? [] as $mitarbeiterID => $anzahlBetrag) {
+ $mitarbeiterID = (int)$mitarbeiterID;
+ $anzahlBetrag = floatval($anzahlBetrag);
+ if ($mitarbeiterID <= 0 || $anzahlBetrag == 0.0) {
+ continue;
}
- }
- }
- echo "Einträge erfolgreich hinzugefügt.";
+ $insert->execute([$mitarbeiterID, $anzahlBetrag, $datum]);
+ $legacyPaymentId = (int)$pdo->lastInsertId();
+ ledger_mirror_legacy_payment($pdo, $tenantId, $legacyPaymentId);
+ $eingetragen++;
+ }
+
+ $pdo->commit();
+ } catch (Throwable $e) {
+ if ($pdo->inTransaction()) {
+ $pdo->rollBack();
+ }
+ $fehlgeschlagen = true;
+ }
+
+ if ($fehlgeschlagen) {
+ echo "Die Einzahlungen konnten nicht gespeichert werden.";
+ } else {
+ echo $eingetragen . " Einträge erfolgreich hinzugefügt.";
+ }
+
+ // Mitarbeiter aus der Datenbank abrufen und nach Namen sortieren
+ $sqlMitarbeiter = "SELECT MitarbeiterID, Name FROM kl_Mitarbeiter WHERE aktiv = 1 ORDER BY Name";
}elseif($_SERVER["REQUEST_METHOD"] == "GET" AND isset($_GET["action"])){
if($_GET["action"] == "vorderseite"){
diff --git a/letzteneintraege.php b/letzteneintraege.php
index 5e7082a..fc48ca6 100644
--- a/letzteneintraege.php
+++ b/letzteneintraege.php
@@ -1,6 +1,7 @@
beginTransaction();
- $stmt = sqlsrv_query($conn, $sql, $params);
+ ledger_void_entry_by_legacy_id($pdo, $tenantId, 'kl_Einzahlungen', $einzahlungID);
- if ($stmt === false) {
- throw new Exception(print_r(sqlsrv_errors(), true));
- }
+ $stmt = $pdo->prepare('DELETE FROM kl_Einzahlungen WHERE EinzahlungsID = ?');
+ $stmt->execute([$einzahlungID]);
+
+ $pdo->commit();
return true; // Erfolgreich gelöscht
- } catch (Exception $e) {
- return $e->getMessage(); // Fehlermeldung zurückgeben
+ } catch (Throwable $e) {
+ if ($pdo->inTransaction()) {
+ $pdo->rollBack();
+ }
+
+ return 'Die Einzahlung konnte nicht gelöscht werden.';
}
}
// Überprüfen, ob ein Löschvorgang angefordert wurde
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["aktion"]) && $_POST["aktion"] == "loescheneinzahlung") {
- $einzahlungID = $_POST["einzahlungID"];
+ $einzahlungID = (int)$_POST["einzahlungID"];
- $ergebnis = loescheEinzahlung($einzahlungID, $conn);
+ $ergebnis = loescheEinzahlung($einzahlungID, $pdo, $tenantId);
if ($ergebnis === true) {
echo "Einzahlung erfolgreich gelöscht.";
@@ -136,29 +127,34 @@ $stmtEinzahlungen = sqlsrv_query($conn, $sqlEinzahlungen);
beginTransaction();
- $stmt = sqlsrv_query($conn, $sql, $params);
+ ledger_void_entry_by_legacy_id($pdo, $tenantId, 'kl_Kaffeeverbrauch', $strichID);
- if ($stmt === false) {
- throw new Exception(print_r(sqlsrv_errors(), true));
- }
+ $stmt = $pdo->prepare('DELETE FROM kl_Kaffeeverbrauch WHERE VerbrauchID = ?');
+ $stmt->execute([$strichID]);
+
+ $pdo->commit();
return true; // Erfolgreich gelöscht
- } catch (Exception $e) {
- return $e->getMessage(); // Fehlermeldung zurückgeben
+ } catch (Throwable $e) {
+ if ($pdo->inTransaction()) {
+ $pdo->rollBack();
+ }
+
+ return 'Der Strich-Eintrag konnte nicht gelöscht werden.';
}
}
// Überprüfen, ob ein Löschvorgang angefordert wurde
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["aktion"]) && $_POST["aktion"] == "loeschen") {
- $strichID = $_POST["strichID"];
+ $strichID = (int)$_POST["strichID"];
- $ergebnis = loescheStrichEintrag($strichID, $conn);
+ $ergebnis = loescheStrichEintrag($strichID, $pdo, $tenantId);
if ($ergebnis === true) {
echo "Strich-Eintrag erfolgreich gelöscht.";
diff --git a/scripts/check-m4-ledger-migration.php b/scripts/check-m4-ledger-migration.php
index b2aab59..b06d644 100644
--- a/scripts/check-m4-ledger-migration.php
+++ b/scripts/check-m4-ledger-migration.php
@@ -101,12 +101,13 @@ $stmt = $pdo->prepare(
"SELECT COUNT(*)
FROM ledger_entries
WHERE tenant_id = ?
- AND legacy_table IN ('kl_Einzahlungen', 'kl_Kaffeeverbrauch')"
+ AND legacy_table IN ('kl_Einzahlungen', 'kl_Kaffeeverbrauch')
+ AND voided_at IS NULL"
);
$stmt->execute([$tenantId]);
$ledgerLegacyCount = (int)$stmt->fetchColumn();
m4_check_assert_equal(
- 'legacy ledger row count matches source rows',
+ 'active legacy ledger row count matches source rows',
$legacyPaymentCount + $legacyConsumptionCount,
$ledgerLegacyCount,
$failures,
@@ -131,16 +132,20 @@ m4_check_assert_equal(
$passes
);
+// Ledger rows without a matching legacy row are only expected when they were
+// voided through the storno flow in letzteneintraege.php. A missing legacy row
+// on a non-voided ledger entry indicates real drift between the tables.
$stmt = $pdo->prepare(
"SELECT COUNT(*)
FROM ledger_entries le
LEFT JOIN kl_Einzahlungen e ON e.EinzahlungsID = le.legacy_id
WHERE le.tenant_id = ?
AND le.legacy_table = 'kl_Einzahlungen'
+ AND le.voided_at IS NULL
AND e.EinzahlungsID IS NULL"
);
$stmt->execute([$tenantId]);
-m4_check_assert_equal('no stale payment ledger rows', 0, (int)$stmt->fetchColumn(), $failures, $passes);
+m4_check_assert_equal('no stale non-voided payment ledger rows', 0, (int)$stmt->fetchColumn(), $failures, $passes);
$stmt = $pdo->prepare(
"SELECT COUNT(*)
@@ -148,10 +153,11 @@ $stmt = $pdo->prepare(
LEFT JOIN kl_Kaffeeverbrauch v ON v.VerbrauchID = le.legacy_id
WHERE le.tenant_id = ?
AND le.legacy_table = 'kl_Kaffeeverbrauch'
+ AND le.voided_at IS NULL
AND v.VerbrauchID IS NULL"
);
$stmt->execute([$tenantId]);
-m4_check_assert_equal('no stale consumption ledger rows', 0, (int)$stmt->fetchColumn(), $failures, $passes);
+m4_check_assert_equal('no stale non-voided consumption ledger rows', 0, (int)$stmt->fetchColumn(), $failures, $passes);
$stmt = $pdo->prepare("SELECT COUNT(*) FROM ledger_entries WHERE tenant_id = ? AND type = 'payment' AND amount_cents <= 0");
$stmt->execute([$tenantId]);
diff --git a/stricheintragen.php b/stricheintragen.php
index 6792707..ccb4f37 100644
--- a/stricheintragen.php
+++ b/stricheintragen.php
@@ -1,6 +1,7 @@
Kein Zugriff";
+ include "footer.php";
+ exit;
+}
// Verarbeitung des Formulars, wenn es gesendet wurde
if ($_SERVER["REQUEST_METHOD"] == "POST") {
- // Kosten pro Strich übernehmen:
- $kostenproStrich = $_POST["kostenproStrich"];
-
- // Iteriere über alle Mitarbeiter
- foreach ($_POST["anzahlStriche"] as $mitarbeiterID => $anzahlStriche) {
- // Validierung könnte hier hinzugefügt werden
- $anzahlStriche = (int)$anzahlStriche;
- $kostenproStrich = floatval($kostenproStrich);
- $kosten = floatval($anzahlStriche * $kostenproStrich);
- $datum = date("Y-m-d H:i:s"); // Das aktuelle Datum verwenden
- if($anzahlStriche != 0){
- // SQL-Abfrage zum Einfügen der Daten
- $sql = "INSERT INTO kl_Kaffeeverbrauch (MitarbeiterID, AnzahlStriche, Kosten, KostenproStrich, Datum) VALUES (?, ?, ?, ?, ?)";
- $params = array($mitarbeiterID, $anzahlStriche, $kosten, $kostenproStrich, $datum);
+ $kostenproStrich = floatval($_POST["kostenproStrich"] ?? 0);
+ $datum = date("Y-m-d H:i:s"); // Das aktuelle Datum verwenden
+ $eingetragen = 0;
+ $fehlgeschlagen = false;
- $stmt = sqlsrv_query($conn, $sql, $params);
+ try {
+ $pdo->beginTransaction();
+ $insert = $pdo->prepare(
+ "INSERT INTO kl_Kaffeeverbrauch (MitarbeiterID, AnzahlStriche, Kosten, KostenproStrich, Datum) VALUES (?, ?, ?, ?, ?)"
+ );
- if ($stmt === false) {
- die(print_r(sqlsrv_errors(), true));
+ foreach ($_POST["anzahlStriche"] ?? [] as $mitarbeiterID => $anzahlStriche) {
+ $mitarbeiterID = (int)$mitarbeiterID;
+ $anzahlStriche = (int)$anzahlStriche;
+ if ($mitarbeiterID <= 0 || $anzahlStriche === 0) {
+ continue;
}
- }
- }
- echo "Einträge erfolgreich hinzugefügt.";
+ $kosten = $anzahlStriche * $kostenproStrich;
+ $insert->execute([$mitarbeiterID, $anzahlStriche, $kosten, $kostenproStrich, $datum]);
+ $legacyConsumptionId = (int)$pdo->lastInsertId();
+ ledger_mirror_legacy_consumption($pdo, $tenantId, $legacyConsumptionId);
+ $eingetragen++;
+ }
+
+ $pdo->commit();
+ } catch (Throwable $e) {
+ if ($pdo->inTransaction()) {
+ $pdo->rollBack();
+ }
+ $fehlgeschlagen = true;
+ }
+
+ if ($fehlgeschlagen) {
+ echo "Die Einträge konnten nicht gespeichert werden.";
+ } else {
+ echo $eingetragen . " Einträge erfolgreich hinzugefügt.";
+ }
+
+ // Mitarbeiter aus der Datenbank abrufen und nach Namen sortieren
+ $sqlMitarbeiter = "SELECT MitarbeiterID, Name FROM kl_Mitarbeiter WHERE aktiv = 1 ORDER BY Name";
}elseif($_SERVER["REQUEST_METHOD"] == "GET" AND isset($_GET["action"])){
if($_GET["action"] == "vorderseite"){