M0 Einrichtung
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# M0 Baseline
|
||||
|
||||
Stand: 2026-07-11
|
||||
|
||||
M0 dokumentiert den aktuellen Legacy-Bestand, bevor die SaaS-Umstrukturierung
|
||||
beginnt. Ziel ist eine belastbare Ausgangsbasis fuer Migration, Sicherheit,
|
||||
Design-Erhalt und fachliche Vergleichstests.
|
||||
|
||||
## Status
|
||||
|
||||
| Bereich | Status | Ergebnis |
|
||||
| --- | --- | --- |
|
||||
| Code-Inventar | begonnen | Siehe `code-inventory.md` |
|
||||
| Prozesslandkarte | begonnen | In `code-inventory.md` enthalten |
|
||||
| Sicherheitsbaseline | begonnen | Siehe `security-baseline.md` |
|
||||
| DB-Schema-Export | vorbereitet | Siehe `schema-export.sql` |
|
||||
| Golden-Master-Auswertungen | vorbereitet | Siehe `golden-master-queries.sql` |
|
||||
| Design-/Screenshot-Referenz | vorbereitet | Siehe `screenshot-checklist.md` |
|
||||
|
||||
## Lokal abgeschlossen
|
||||
|
||||
- Legacy-Einstiegspunkte und Kernseiten identifiziert.
|
||||
- Fachliche Tabellen aus SQL-Strings abgeleitet.
|
||||
- Schreibende Aktionen und kritische Datenfluesse markiert.
|
||||
- Sicherheitsrisiken fuer M0 inventarisiert.
|
||||
- SQL-Vorlagen fuer Schema- und Golden-Master-Export angelegt.
|
||||
- Screenshot-Checkliste fuer Design-Erhalt angelegt.
|
||||
|
||||
## Lokale Einschraenkungen
|
||||
|
||||
- `php` ist in dieser Umgebung nicht im PATH, daher kein lokaler Syntaxcheck und
|
||||
kein lokaler App-Start.
|
||||
- `sqlcmd` ist in dieser Umgebung nicht im PATH, daher kein direkter
|
||||
SQL-Server-Export aus der Shell.
|
||||
- Die aktuelle M0-Auswertung ist deshalb statisch aus dem Code abgeleitet.
|
||||
|
||||
## Blockiert bis Input vorliegt
|
||||
|
||||
Diese Punkte kann ich ohne externe Informationen nicht abschliessen:
|
||||
|
||||
1. Live- oder Staging-DB-Schema exportieren.
|
||||
2. Tabellen, Spalten, Indizes, Constraints und Rowcounts verifizieren.
|
||||
3. Golden-Master-Ergebnisse gegen echte Daten berechnen.
|
||||
4. Screenshots der echten App-Zustaende aufnehmen, falls die App lokal nicht
|
||||
lauffaehig ist.
|
||||
5. Produktivumgebung dokumentieren: PHP-Version, Webserver, SQL-Server-Version,
|
||||
Auth-Setup, Cron/Job-Ausfuehrung.
|
||||
|
||||
## Was ich von dir brauche
|
||||
|
||||
Bitte stelle eines der folgenden Pakete bereit:
|
||||
|
||||
- Idealerweise: einen anonymisierten SQL-Server-Schemaexport plus Rowcounts.
|
||||
- Alternativ: Zugriffsdaten zu einer Test-/Staging-DB, nicht zu Produktion.
|
||||
- Alternativ: die Ergebnisse aus `schema-export.sql` als CSV/Excel/Markdown.
|
||||
|
||||
Zusaetzlich hilfreich:
|
||||
|
||||
- Ein erreichbarer Test-Link zur bestehenden App oder Screenshots der Seiten aus
|
||||
`screenshot-checklist.md`.
|
||||
- Beispiel-Accounts oder Rollen fuer Admin und normales Mitglied, nur fuer eine
|
||||
Testumgebung.
|
||||
- Info, ob hart codierte Zugangsdaten aus Legacy-Skripten bereits rotiert wurden.
|
||||
- Entscheidung, ob M1/M2 nativ in PHP oder mit Framework vorbereitet werden
|
||||
sollen.
|
||||
|
||||
Bitte keine Produktivpasswoerter oder echten personenbezogenen Exportdaten in
|
||||
das Repository legen.
|
||||
@@ -0,0 +1,192 @@
|
||||
# M0 Code- und Prozessinventar
|
||||
|
||||
Stand: 2026-07-11
|
||||
|
||||
Dieses Inventar basiert auf statischer Sichtung des Legacy-Codes im Repository.
|
||||
Das echte Datenbankschema muss noch mit `schema-export.sql` verifiziert werden.
|
||||
|
||||
## App-Struktur
|
||||
|
||||
| Datei | Rolle | Wichtige Beobachtung |
|
||||
| --- | --- | --- |
|
||||
| `config.php` | AD-/DB-Konfiguration | Erstellt globale SQL-Server-Verbindung `$conn` |
|
||||
| `functions.php` | Auth-/User-Helper | Liest `$_SERVER['AUTH_USER']`, inkludiert LDAP, prueft `kl_Mitarbeiter` |
|
||||
| `functionsLDAP.php` | LDAP-Mailauflösung | Ermittelt `$mailadress` aus AD |
|
||||
| `header.php` | HTML-Head und Hinweisbanner | Laedt `assets/css/main.css`, liest `kl_hinweise` |
|
||||
| `footer.php` | App-Sidebar und JS | Enthaelt die sichtbare Navigation und Admin-Menues |
|
||||
| `nav.php` | Navigation | Aktuell praktisch leer |
|
||||
| `headerline.php` | Headerfragment | Enthaelt NUL-Zeichen, fachlich unklar |
|
||||
| `assets/css/main.css` | Hauptdesign | HTML5-UP Editorial, gruener Akzent, Tabellen, Buttons, Sidebar |
|
||||
| `DataTables/` | Tabellen-Assets | Wird teilweise eingebunden, aber nicht konsequent initialisiert |
|
||||
| `PHPMailer/` | Mailversand | Fuer Rundmails/Jahresauswertung genutzt |
|
||||
| `TCPDF/` | PDF-Export | Fuer Kaffeelisten-Export genutzt |
|
||||
|
||||
## Fachliche Kernseiten
|
||||
|
||||
| Datei | Prozess | Tabellen |
|
||||
| --- | --- | --- |
|
||||
| `index.php` | Persoenliches Dashboard, Saldo, Jahreswerte, eigene Striche, PayPal-Links | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch`, `kl_config` |
|
||||
| `kaffeeliste.php` | Admin-Gesamtuebersicht mit Salden | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch` |
|
||||
| `stricheintragen.php` | Sammelerfassung von Strichen | `kl_Mitarbeiter`, `kl_Kaffeeverbrauch`, `kl_config` |
|
||||
| `einzahlung.php` | Sammelerfassung von Einzahlungen | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch` |
|
||||
| `mitarbeiterverwalten.php` | Mitglieder anlegen, bearbeiten, aktivieren, deaktivieren | `kl_Mitarbeiter` |
|
||||
| `namenanpassen.php` | Anzeigenamen aendern | `kl_Mitarbeiter` |
|
||||
| `letzteneintraege.php` | Letzte Buchungen anzeigen und loeschen | `kl_Einzahlungen`, `kl_Kaffeeverbrauch`, `kl_Mitarbeiter` |
|
||||
| `csvupload.php` | Zahlungs-CSV importieren | `kl_Mitarbeiter`, `kl_Einzahlungen` |
|
||||
| `exportKaffeeliste.php` | PDF-/Listenexport | `kl_Mitarbeiter`, `kl_Kaffeeverbrauch`, `kl_Einzahlungen`, `kl_config` |
|
||||
| `mailausgebe.php` | Mailausgabe/Adressliste | `kl_Mitarbeiter` |
|
||||
| `mailversenden.php` | Massenmail mit aktuellem Stand | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch` |
|
||||
| `hinweise.php` | Hinweise pflegen | `kl_hinweise` |
|
||||
| `faq.php` | FAQ | Keine fachlichen Schreibzugriffe |
|
||||
| `jahresauswertung.php` | Jahresgutschriften und Mailversand | `kl_Mitarbeiter`, `kl_Kaffeeverbrauch`, `kl_Einzahlungen` |
|
||||
| `umfrage.php` | Umfrage | `CoffeeSurveyVotedEmails`, `CoffeeSurveyResponses` |
|
||||
| `umfrageergebnisse.php` | Umfrageauswertung | `CoffeeSurveyVotedEmails`, `CoffeeSurveyResponses` |
|
||||
|
||||
## Abgeleitete Tabellen und Spalten
|
||||
|
||||
Diese Spalten sind aus dem Code abgeleitet und muessen mit dem echten DB-Schema
|
||||
abgeglichen werden.
|
||||
|
||||
| Tabelle | Abgeleitete Spalten |
|
||||
| --- | --- |
|
||||
| `kl_Mitarbeiter` | `MitarbeiterID`, `Name`, `Email`, `aktiv`, `admin`, `paypalname` |
|
||||
| `kl_Einzahlungen` | `EinzahlungsID`, `MitarbeiterID`, `Betrag`, `Datum` |
|
||||
| `kl_Kaffeeverbrauch` | `VerbrauchID`, `MitarbeiterID`, `AnzahlStriche`, `Kosten`, `KostenproStrich`, `Datum`, `Eintragsart` |
|
||||
| `kl_config` | `KostenproStrich`, `paypaluse`, `paypallink`, `strichperweb` |
|
||||
| `kl_hinweise` | `id`, `nachricht`, `gueltig_bis` |
|
||||
| `CoffeeSurveyVotedEmails` | `EmailNorm` |
|
||||
| `CoffeeSurveyResponses` | diverse `Q*_`-Antwortspalten, siehe Umfragecode |
|
||||
|
||||
## Prozesslandkarte
|
||||
|
||||
### Authentifizierung
|
||||
|
||||
1. Seite inkludiert `functions.php`.
|
||||
2. `functions.php` liest `$_SERVER['AUTH_USER']`.
|
||||
3. `functionsLDAP.php` ermittelt Mailadresse aus LDAP.
|
||||
4. Zugriff wird ueber `kl_Mitarbeiter.Email`, `aktiv` und `admin` geprueft.
|
||||
|
||||
M0-Feststellung:
|
||||
Login-Konto, Kaffee-Teilnehmer und Rolle sind im Legacy-Modell gekoppelt. Fuer
|
||||
SaaS muessen `users`, `participants` und `tenant_memberships` getrennt werden.
|
||||
|
||||
### Persoenliches Dashboard
|
||||
|
||||
Quelle: `index.php`.
|
||||
|
||||
Berechnungen:
|
||||
|
||||
- Mitarbeiter per E-Mail suchen.
|
||||
- Gesamteinzahlung: Summe `kl_Einzahlungen.Betrag`.
|
||||
- Gesamtausgabe: Summe `kl_Kaffeeverbrauch.Kosten`.
|
||||
- Gesamtstriche: Summe `kl_Kaffeeverbrauch.AnzahlStriche`.
|
||||
- Aktueller Stand: Einzahlungen minus Ausgaben.
|
||||
- Jahreswerte: dieselben Summen fuer aktuelles Jahr.
|
||||
- Bei aktivem `strichperweb`: eigener Strich-Eintrag.
|
||||
- Bei aktivem `paypaluse`: PayPal-Links anzeigen.
|
||||
|
||||
### Sammelerfassung Striche
|
||||
|
||||
Quelle: `stricheintragen.php`.
|
||||
|
||||
Berechnungen:
|
||||
|
||||
- Preis pro Strich aus `kl_config.KostenproStrich`.
|
||||
- Pro Mitarbeiter eine Anzahl erfassen.
|
||||
- Kosten = Anzahl Striche mal Kosten pro Strich.
|
||||
- Neue Zeile in `kl_Kaffeeverbrauch`.
|
||||
- Filter `vorderseite`/`rueckseite` anhand der letzten 100 Tage und mindestens
|
||||
10 Strichen.
|
||||
|
||||
### Sammelerfassung Einzahlungen
|
||||
|
||||
Quelle: `einzahlung.php`.
|
||||
|
||||
Berechnungen:
|
||||
|
||||
- Pro Mitarbeiter Betrag erfassen.
|
||||
- Neue Zeile in `kl_Einzahlungen`.
|
||||
- Filter `vorderseite`/`rueckseite` anhand der letzten 100 Tage und mindestens
|
||||
10 Strichen.
|
||||
|
||||
### Mitgliederverwaltung
|
||||
|
||||
Quelle: `mitarbeiterverwalten.php`.
|
||||
|
||||
Aktionen:
|
||||
|
||||
- Mitglied anlegen.
|
||||
- Name/E-Mail/aktiv/admin bearbeiten.
|
||||
- Mitglied aktivieren/deaktivieren.
|
||||
|
||||
M0-Feststellung:
|
||||
Das `admin`-Flag ist fachlich eine Rolleninformation und sollte in der SaaS-App
|
||||
in `tenant_memberships.role` wandern.
|
||||
|
||||
### Korrektur letzter Eintraege
|
||||
|
||||
Quelle: `letzteneintraege.php`.
|
||||
|
||||
Aktionen:
|
||||
|
||||
- Letzte 100 Einzahlungen anzeigen.
|
||||
- Einzahlung hart loeschen.
|
||||
- Letzte 100 Strich-Eintraege anzeigen.
|
||||
- Strich-Eintrag hart loeschen.
|
||||
|
||||
M0-Feststellung:
|
||||
Finanznahe Korrekturen sollten im Zielmodell nicht hart loeschen, sondern als
|
||||
Storno/Reversal mit Audit-Trail gespeichert werden.
|
||||
|
||||
### CSV-Import
|
||||
|
||||
Quelle: `csvupload.php`.
|
||||
|
||||
Ablauf:
|
||||
|
||||
- Datei hochladen.
|
||||
- CSV mit Komma-Trennung lesen.
|
||||
- Name aus Spalte 3, Betrag aus Spalte 7, Datum aus Spalte 0.
|
||||
- Mitarbeiter per Name oder `paypalname` finden.
|
||||
- Dublette anhand Mitarbeiter, Betrag und Datumstag pruefen.
|
||||
- Einzahlung einfuegen.
|
||||
- Ergebnis in Erfolg/Fehler klassifizieren.
|
||||
|
||||
### Jahresauswertung
|
||||
|
||||
Quelle: `jahresauswertung.php`.
|
||||
|
||||
Ablauf:
|
||||
|
||||
- Gesamtstriche des aktuellen Jahres je aktivem Mitarbeiter berechnen.
|
||||
- Konstante Anzahl neuer Striche/Gutschrift proportional verteilen.
|
||||
- Einzahlung je Mitarbeiter einfuegen.
|
||||
- Mail an Mitarbeiter senden.
|
||||
|
||||
M0-Feststellung:
|
||||
Das ist ein Job/Skript mit direktem Schreibzugriff und Mailversand. Fuer SaaS
|
||||
braucht es Dry-Run, Audit, Tenant-Scope und expliziten Operator.
|
||||
|
||||
## Offene Schemafragen
|
||||
|
||||
- Gibt es Primary Keys, Foreign Keys und Indizes fuer die `kl_`-Tabellen?
|
||||
- Sind Datentypen fuer Geldwerte `decimal`, `money`, `float` oder etwas anderes?
|
||||
- Gibt es historische Spalten, die im Code nicht sichtbar sind?
|
||||
- Gibt es Trigger oder Stored Procedures?
|
||||
- Gibt es weitere Jobs ausser `jahresauswertung.php`?
|
||||
- Sind Umfragetabellen produktiv relevant oder Archiv/Randmodul?
|
||||
|
||||
## Technische Legacy-Inkonsistenzen
|
||||
|
||||
- `csvupload.php` sucht in `getMitarbeiterID` nach `Name = ? or paypalname = ?`,
|
||||
uebergibt aber nur einen Parameter. Das sollte vor der Uebernahme des
|
||||
CSV-Flows verifiziert werden.
|
||||
- `einzahlung.php` prueft auf `$_GET["action"]`, die Buttons erzeugen aber
|
||||
URLs mit `aktion=...`. Der Vorderseite-/Rueckseite-Filter kann dadurch
|
||||
abweichend vom erwarteten Verhalten laufen.
|
||||
- `exportKaffeeliste.php` referenziert `tcpdf/tcpdf.php`, waehrend der Ordner im
|
||||
Repository `TCPDF/` heisst. Auf case-sensitiven Dateisystemen kann das
|
||||
brechen.
|
||||
- `headerline.php` ist fachlich leer beziehungsweise mit NUL-Zeichen gefuellt.
|
||||
Vor der neuen App-Shell sollte geklaert werden, ob die Datei entfernt werden
|
||||
kann.
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
M0 Golden-Master Queries
|
||||
|
||||
Ziel:
|
||||
- Fachliche Legacy-Ergebnisse exportieren, damit Migration und neue SaaS-App
|
||||
gegen denselben Stand verglichen werden koennen.
|
||||
|
||||
Ausfuehrung:
|
||||
- In der Legacy-Datenbank ausfuehren.
|
||||
- Ergebnisse je Query als CSV speichern.
|
||||
- Keine personenbezogenen Exporte ins Repo committen.
|
||||
*/
|
||||
|
||||
DECLARE @CurrentYear int = YEAR(GETDATE());
|
||||
|
||||
-- 1. Teilnehmer-Basisdaten
|
||||
SELECT
|
||||
m.MitarbeiterID,
|
||||
m.Name,
|
||||
m.Email,
|
||||
m.aktiv,
|
||||
m.admin
|
||||
FROM kl_Mitarbeiter m
|
||||
ORDER BY m.Name;
|
||||
|
||||
-- 2. Saldo je Teilnehmer
|
||||
WITH payments AS (
|
||||
SELECT
|
||||
MitarbeiterID,
|
||||
SUM(Betrag) AS total_payments
|
||||
FROM kl_Einzahlungen
|
||||
GROUP BY MitarbeiterID
|
||||
),
|
||||
consumption AS (
|
||||
SELECT
|
||||
MitarbeiterID,
|
||||
SUM(Kosten) AS total_costs,
|
||||
SUM(AnzahlStriche) AS total_marks
|
||||
FROM kl_Kaffeeverbrauch
|
||||
GROUP BY MitarbeiterID
|
||||
)
|
||||
SELECT
|
||||
m.MitarbeiterID,
|
||||
m.Name,
|
||||
m.Email,
|
||||
COALESCE(p.total_payments, 0) AS total_payments,
|
||||
COALESCE(c.total_costs, 0) AS total_costs,
|
||||
COALESCE(c.total_marks, 0) AS total_marks,
|
||||
COALESCE(p.total_payments, 0) - COALESCE(c.total_costs, 0) AS balance
|
||||
FROM kl_Mitarbeiter m
|
||||
LEFT JOIN payments p ON p.MitarbeiterID = m.MitarbeiterID
|
||||
LEFT JOIN consumption c ON c.MitarbeiterID = m.MitarbeiterID
|
||||
ORDER BY m.Name;
|
||||
|
||||
-- 3. Jahreswerte je Teilnehmer
|
||||
WITH year_payments AS (
|
||||
SELECT
|
||||
MitarbeiterID,
|
||||
SUM(Betrag) AS year_payments
|
||||
FROM kl_Einzahlungen
|
||||
WHERE YEAR(Datum) = @CurrentYear
|
||||
GROUP BY MitarbeiterID
|
||||
),
|
||||
year_consumption AS (
|
||||
SELECT
|
||||
MitarbeiterID,
|
||||
SUM(Kosten) AS year_costs,
|
||||
SUM(AnzahlStriche) AS year_marks
|
||||
FROM kl_Kaffeeverbrauch
|
||||
WHERE YEAR(Datum) = @CurrentYear
|
||||
GROUP BY MitarbeiterID
|
||||
)
|
||||
SELECT
|
||||
m.MitarbeiterID,
|
||||
m.Name,
|
||||
m.Email,
|
||||
COALESCE(yp.year_payments, 0) AS year_payments,
|
||||
COALESCE(yc.year_costs, 0) AS year_costs,
|
||||
COALESCE(yc.year_marks, 0) AS year_marks
|
||||
FROM kl_Mitarbeiter m
|
||||
LEFT JOIN year_payments yp ON yp.MitarbeiterID = m.MitarbeiterID
|
||||
LEFT JOIN year_consumption yc ON yc.MitarbeiterID = m.MitarbeiterID
|
||||
ORDER BY m.Name;
|
||||
|
||||
-- 4. Letzte Einzahlungen je Teilnehmer
|
||||
SELECT
|
||||
e.EinzahlungsID,
|
||||
e.MitarbeiterID,
|
||||
m.Name,
|
||||
m.Email,
|
||||
e.Betrag,
|
||||
e.Datum
|
||||
FROM kl_Einzahlungen e
|
||||
JOIN kl_Mitarbeiter m ON m.MitarbeiterID = e.MitarbeiterID
|
||||
ORDER BY e.Datum DESC, e.EinzahlungsID DESC;
|
||||
|
||||
-- 5. Letzte Strich-/Verbrauchseintraege je Teilnehmer
|
||||
SELECT
|
||||
v.VerbrauchID,
|
||||
v.MitarbeiterID,
|
||||
m.Name,
|
||||
m.Email,
|
||||
v.AnzahlStriche,
|
||||
v.Kosten,
|
||||
v.KostenproStrich,
|
||||
v.Datum,
|
||||
v.Eintragsart
|
||||
FROM kl_Kaffeeverbrauch v
|
||||
JOIN kl_Mitarbeiter m ON m.MitarbeiterID = v.MitarbeiterID
|
||||
ORDER BY v.Datum DESC, v.VerbrauchID DESC;
|
||||
|
||||
-- 6. Aktuelle Konfiguration
|
||||
SELECT
|
||||
*
|
||||
FROM kl_config;
|
||||
|
||||
-- 7. Aktuelle und historische Hinweise
|
||||
SELECT
|
||||
id,
|
||||
nachricht,
|
||||
gueltig_bis
|
||||
FROM kl_hinweise
|
||||
ORDER BY gueltig_bis DESC;
|
||||
|
||||
-- 8. 100-Tage-Vorderseite analog Legacy-Stricherfassung
|
||||
DECLARE @ReferenceDate date = (
|
||||
SELECT MAX(CAST(Datum AS date))
|
||||
FROM kl_Kaffeeverbrauch
|
||||
WHERE Datum < CAST(GETDATE() AS date)
|
||||
);
|
||||
|
||||
SELECT
|
||||
m.MitarbeiterID,
|
||||
m.Name,
|
||||
m.Email,
|
||||
SUM(v.AnzahlStriche) AS marks_in_window
|
||||
FROM kl_Mitarbeiter m
|
||||
JOIN kl_Kaffeeverbrauch v ON m.MitarbeiterID = v.MitarbeiterID
|
||||
WHERE v.Datum >= DATEADD(DAY, -100, @ReferenceDate)
|
||||
AND m.aktiv = 1
|
||||
GROUP BY m.MitarbeiterID, m.Name, m.Email
|
||||
HAVING SUM(v.AnzahlStriche) >= 10
|
||||
ORDER BY m.Name;
|
||||
|
||||
-- 9. 100-Tage-Rueckseite analog Legacy-Stricherfassung
|
||||
SELECT
|
||||
m.MitarbeiterID,
|
||||
m.Name,
|
||||
m.Email,
|
||||
COALESCE(SUM(v.AnzahlStriche), 0) AS marks_in_window
|
||||
FROM kl_Mitarbeiter m
|
||||
LEFT JOIN kl_Kaffeeverbrauch v
|
||||
ON m.MitarbeiterID = v.MitarbeiterID
|
||||
AND v.Datum >= DATEADD(DAY, -100, @ReferenceDate)
|
||||
WHERE m.aktiv = 1
|
||||
GROUP BY m.MitarbeiterID, m.Name, m.Email
|
||||
HAVING COALESCE(SUM(v.AnzahlStriche), 0) < 10
|
||||
ORDER BY m.Name;
|
||||
|
||||
-- 10. CSV-Import-Dublettenbasis
|
||||
SELECT
|
||||
e.MitarbeiterID,
|
||||
m.Name,
|
||||
e.Betrag,
|
||||
CONVERT(varchar, e.Datum, 23) AS booking_day,
|
||||
COUNT(*) AS duplicates_per_day
|
||||
FROM kl_Einzahlungen e
|
||||
JOIN kl_Mitarbeiter m ON m.MitarbeiterID = e.MitarbeiterID
|
||||
GROUP BY e.MitarbeiterID, m.Name, e.Betrag, CONVERT(varchar, e.Datum, 23)
|
||||
HAVING COUNT(*) > 1
|
||||
ORDER BY booking_day DESC, m.Name;
|
||||
|
||||
-- 11. Jahresauswertung: Gesamtstriche aktuelles Jahr
|
||||
SELECT
|
||||
m.MitarbeiterID,
|
||||
m.Name,
|
||||
m.Email,
|
||||
SUM(v.AnzahlStriche) AS GesamtStriche
|
||||
FROM kl_Kaffeeverbrauch v
|
||||
JOIN kl_Mitarbeiter m ON v.MitarbeiterID = m.MitarbeiterID
|
||||
WHERE YEAR(v.Datum) = @CurrentYear
|
||||
AND m.aktiv = 1
|
||||
GROUP BY m.MitarbeiterID, m.Name, m.Email
|
||||
ORDER BY GesamtStriche DESC, m.Name;
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
M0 SQL Server Schema Export
|
||||
|
||||
Ziel:
|
||||
- Tabellen, Spalten, Defaults, Primary Keys, Foreign Keys, Indizes und Rowcounts
|
||||
aus der Legacy-Datenbank exportieren.
|
||||
|
||||
Hinweise:
|
||||
- In der Ziel-Datenbank ausfuehren.
|
||||
- Ergebnisse als CSV/Excel speichern und nicht mit Produktiv-Secrets ins Repo
|
||||
legen.
|
||||
- Falls nur Kaffeelisten-Tabellen exportiert werden sollen, den WHERE-Block bei
|
||||
Bedarf auf kl_% und CoffeeSurvey% begrenzen.
|
||||
*/
|
||||
|
||||
-- 1. Tabellen und Spalten
|
||||
SELECT
|
||||
s.name AS schema_name,
|
||||
t.name AS table_name,
|
||||
c.column_id,
|
||||
c.name AS column_name,
|
||||
ty.name AS data_type,
|
||||
c.max_length,
|
||||
c.precision,
|
||||
c.scale,
|
||||
c.is_nullable,
|
||||
c.is_identity,
|
||||
dc.definition AS default_definition,
|
||||
ep.value AS column_description
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.columns c ON c.object_id = t.object_id
|
||||
JOIN sys.types ty ON ty.user_type_id = c.user_type_id
|
||||
LEFT JOIN sys.default_constraints dc
|
||||
ON dc.parent_object_id = t.object_id
|
||||
AND dc.parent_column_id = c.column_id
|
||||
LEFT JOIN sys.extended_properties ep
|
||||
ON ep.major_id = t.object_id
|
||||
AND ep.minor_id = c.column_id
|
||||
AND ep.name = 'MS_Description'
|
||||
WHERE t.is_ms_shipped = 0
|
||||
ORDER BY s.name, t.name, c.column_id;
|
||||
|
||||
-- 2. Primary Keys und Unique Constraints
|
||||
SELECT
|
||||
s.name AS schema_name,
|
||||
t.name AS table_name,
|
||||
kc.name AS constraint_name,
|
||||
kc.type_desc,
|
||||
ic.key_ordinal,
|
||||
c.name AS column_name
|
||||
FROM sys.key_constraints kc
|
||||
JOIN sys.tables t ON t.object_id = kc.parent_object_id
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.index_columns ic
|
||||
ON ic.object_id = kc.parent_object_id
|
||||
AND ic.index_id = kc.unique_index_id
|
||||
JOIN sys.columns c
|
||||
ON c.object_id = ic.object_id
|
||||
AND c.column_id = ic.column_id
|
||||
ORDER BY s.name, t.name, kc.name, ic.key_ordinal;
|
||||
|
||||
-- 3. Foreign Keys
|
||||
SELECT
|
||||
sch_parent.name AS parent_schema,
|
||||
parent_t.name AS parent_table,
|
||||
parent_c.name AS parent_column,
|
||||
fk.name AS foreign_key_name,
|
||||
sch_ref.name AS referenced_schema,
|
||||
ref_t.name AS referenced_table,
|
||||
ref_c.name AS referenced_column,
|
||||
fk.delete_referential_action_desc,
|
||||
fk.update_referential_action_desc
|
||||
FROM sys.foreign_keys fk
|
||||
JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
|
||||
JOIN sys.tables parent_t ON parent_t.object_id = fkc.parent_object_id
|
||||
JOIN sys.schemas sch_parent ON sch_parent.schema_id = parent_t.schema_id
|
||||
JOIN sys.columns parent_c
|
||||
ON parent_c.object_id = fkc.parent_object_id
|
||||
AND parent_c.column_id = fkc.parent_column_id
|
||||
JOIN sys.tables ref_t ON ref_t.object_id = fkc.referenced_object_id
|
||||
JOIN sys.schemas sch_ref ON sch_ref.schema_id = ref_t.schema_id
|
||||
JOIN sys.columns ref_c
|
||||
ON ref_c.object_id = fkc.referenced_object_id
|
||||
AND ref_c.column_id = fkc.referenced_column_id
|
||||
ORDER BY parent_schema, parent_table, foreign_key_name;
|
||||
|
||||
-- 4. Indizes
|
||||
SELECT
|
||||
s.name AS schema_name,
|
||||
t.name AS table_name,
|
||||
i.name AS index_name,
|
||||
i.type_desc,
|
||||
i.is_unique,
|
||||
i.is_primary_key,
|
||||
i.is_unique_constraint,
|
||||
ic.key_ordinal,
|
||||
ic.is_included_column,
|
||||
c.name AS column_name
|
||||
FROM sys.indexes i
|
||||
JOIN sys.tables t ON t.object_id = i.object_id
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.index_columns ic
|
||||
ON ic.object_id = i.object_id
|
||||
AND ic.index_id = i.index_id
|
||||
JOIN sys.columns c
|
||||
ON c.object_id = ic.object_id
|
||||
AND c.column_id = ic.column_id
|
||||
WHERE t.is_ms_shipped = 0
|
||||
AND i.name IS NOT NULL
|
||||
ORDER BY s.name, t.name, i.name, ic.key_ordinal, ic.index_column_id;
|
||||
|
||||
-- 5. Rowcounts
|
||||
SELECT
|
||||
s.name AS schema_name,
|
||||
t.name AS table_name,
|
||||
SUM(p.row_count) AS row_count
|
||||
FROM sys.tables t
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
JOIN sys.dm_db_partition_stats p ON p.object_id = t.object_id
|
||||
WHERE t.is_ms_shipped = 0
|
||||
AND p.index_id IN (0, 1)
|
||||
GROUP BY s.name, t.name
|
||||
ORDER BY s.name, t.name;
|
||||
|
||||
-- 6. Trigger
|
||||
SELECT
|
||||
s.name AS schema_name,
|
||||
t.name AS table_name,
|
||||
tr.name AS trigger_name,
|
||||
tr.is_disabled,
|
||||
OBJECT_DEFINITION(tr.object_id) AS trigger_definition
|
||||
FROM sys.triggers tr
|
||||
JOIN sys.tables t ON t.object_id = tr.parent_id
|
||||
JOIN sys.schemas s ON s.schema_id = t.schema_id
|
||||
ORDER BY s.name, t.name, tr.name;
|
||||
|
||||
-- 7. Stored Procedures und Funktionen mit Kaffeelisten-Bezug
|
||||
SELECT
|
||||
s.name AS schema_name,
|
||||
o.name AS object_name,
|
||||
o.type_desc,
|
||||
OBJECT_DEFINITION(o.object_id) AS object_definition
|
||||
FROM sys.objects o
|
||||
JOIN sys.schemas s ON s.schema_id = o.schema_id
|
||||
WHERE o.type IN ('P', 'FN', 'IF', 'TF')
|
||||
AND (
|
||||
OBJECT_DEFINITION(o.object_id) LIKE '%kl_%'
|
||||
OR OBJECT_DEFINITION(o.object_id) LIKE '%CoffeeSurvey%'
|
||||
)
|
||||
ORDER BY s.name, o.name;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# M0 Screenshot- und Designreferenz
|
||||
|
||||
Stand: 2026-07-11
|
||||
|
||||
Diese Checkliste friert die bestehende Optik ein, damit die SaaS-App vertraut
|
||||
bleibt. Wenn die Legacy-App lokal nicht laeuft, koennen Screenshots aus der
|
||||
aktuellen Umgebung geliefert werden.
|
||||
|
||||
## Allgemeine Vorgaben
|
||||
|
||||
- Je Seite Desktop mit ca. 1440 px Breite aufnehmen.
|
||||
- Je Kernseite mobile Ansicht mit ca. 390 px Breite aufnehmen.
|
||||
- Je relevanter Rolle aufnehmen: normales Mitglied und Admin.
|
||||
- Keine echten personenbezogenen Daten veroeffentlichen.
|
||||
- Dateinamen nach Muster `m0-<rolle>-<seite>-<viewport>.png`.
|
||||
|
||||
## Kernseiten
|
||||
|
||||
| Prioritaet | Seite | Rolle | Zweck |
|
||||
| --- | --- | --- | --- |
|
||||
| Hoch | `index.php` | Mitglied | Dashboard, Saldo, Jahreswerte, eigene Striche, PayPal |
|
||||
| Hoch | `index.php` | Admin | Dashboard mit Admin-Sidebar |
|
||||
| Hoch | `kaffeeliste.php` | Admin | Gesamtuebersicht und Aktionsleiste |
|
||||
| Hoch | `stricheintragen.php` | Admin | Sammelerfassung Striche |
|
||||
| Hoch | `einzahlung.php` | Admin | Sammelerfassung Einzahlungen |
|
||||
| Hoch | `mitarbeiterverwalten.php` | Admin | Mitgliederliste und Formular |
|
||||
| Hoch | `letzteneintraege.php` | Admin | Korrekturansicht mit Loeschaktionen |
|
||||
| Mittel | `csvupload.php` | Admin | CSV-Upload-Formular und Ergebniszustand |
|
||||
| Mittel | `hinweise.php` | Admin | Hinweise anlegen und Liste |
|
||||
| Mittel | `faq.php` | Mitglied | FAQ-Inhalte und Typografie |
|
||||
| Mittel | `namenanpassen.php` | Mitglied | Formular fuer Anzeigenamen |
|
||||
| Niedrig | `teilnehmerauswertung.php` | Admin | Detailauswertung pro Teilnehmer |
|
||||
| Niedrig | `mailausgebe.php` | Admin | Mail-/Adressausgabe |
|
||||
| Niedrig | `umfrage.php` | Mitglied | Randmodul, falls SaaS-relevant |
|
||||
| Niedrig | `umfrageergebnisse.php` | Admin | Randmodul, falls SaaS-relevant |
|
||||
|
||||
## Zustaende
|
||||
|
||||
Diese UI-Zustaende sollten, wenn moeglich, separat gesichert werden:
|
||||
|
||||
- Positiver Kontostand.
|
||||
- Negativer Kontostand.
|
||||
- Nullsaldo.
|
||||
- Nutzer ohne Zugriff.
|
||||
- Erfolgreiche Stricherfassung.
|
||||
- Erfolgreiche Einzahlung.
|
||||
- CSV-Import mit Erfolg, Dublette und unbekanntem Nutzer.
|
||||
- Hinweisbanner aktiv.
|
||||
- Leere Tabellen oder keine Daten.
|
||||
- Mobile Sidebar geoeffnet und geschlossen.
|
||||
|
||||
## Designmerkmale, die erhalten bleiben sollen
|
||||
|
||||
- Gruener Akzent fuer Links, Buttons und Linien.
|
||||
- Roboto-Slab-Ueberschriften.
|
||||
- Open-Sans-Fliesstext.
|
||||
- Weisse Hauptflaeche.
|
||||
- Graue Sidebar in der App.
|
||||
- Tabellen als zentrale Datenansicht.
|
||||
- Schlichte Formularfelder und Buttons.
|
||||
- Ruhige, arbeitsorientierte Darstellung.
|
||||
|
||||
## Ablage
|
||||
|
||||
Empfohlene lokale Ablage, falls Screenshots ins Repo sollen:
|
||||
|
||||
```text
|
||||
docs/m0/screenshots/
|
||||
```
|
||||
|
||||
Vor dem Commit sollten Screenshots anonymisiert sein. Wenn echte Namen,
|
||||
E-Mails, PayPal-Daten oder Salden sichtbar sind, besser ausserhalb des Repos
|
||||
ablegen und nur als Referenz verwenden.
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# M0 Sicherheitsbaseline
|
||||
|
||||
Stand: 2026-07-11
|
||||
|
||||
Diese Baseline ist eine statische Erstbewertung. Sie ersetzt kein Penetration
|
||||
Testing, markiert aber die wichtigsten Risiken fuer die SaaS-Umstrukturierung.
|
||||
|
||||
## Kritische Sofortthemen
|
||||
|
||||
| Risiko | Quelle | Auswirkung | Empfehlung |
|
||||
| --- | --- | --- | --- |
|
||||
| Hart codierte DB-Zugangsdaten | `jahresauswertung.php` Zeilen 4-8 | Secret-Leak, direkte Produktiv-DB-Gefahr | Zugangsdaten rotieren, Skript deaktivieren oder auf Env-Konfiguration umstellen |
|
||||
| Schreibende Seiten ohne eigene Rollenpruefung | `stricheintragen.php`, `einzahlung.php`, `mailversenden.php`, `exportKaffeeliste.php` | Direkter URL-Aufruf kann Aktionen erlauben | Jede Seite serverseitig mit `requireRole` absichern |
|
||||
| Keine CSRF-Token | nahezu alle POST-/Delete-Formulare | Ungewollte Buchungen, Loeschungen, Imports | CSRF fuer alle schreibenden Aktionen |
|
||||
| Harte Deletes fuer Buchungen | `letzteneintraege.php` | Audit-Historie und Revisionsfaehigkeit gehen verloren | Storno-/Reversal-Modell statt Delete |
|
||||
| Upload in Webroot | `csvupload.php` Zeilen 131-138 | Dateiablage kann missbraucht werden | Upload ausserhalb Webroot, Dateityp/MIME/Name pruefen |
|
||||
| Kein Tenant-Scope | alle fachlichen Queries | Zentrales SaaS-Leak-Risiko | `tenant_id` verpflichtend und Query-Schicht testen |
|
||||
|
||||
## Weitere Befunde
|
||||
|
||||
| Befund | Quelle | Empfehlung |
|
||||
| --- | --- | --- |
|
||||
| Direkte SQL-String-Verkettung mit Mailadresse | `functions.php` Zeilen 14, 25, 39, 55 | Parameterisierte Queries |
|
||||
| LDAP-Filter ohne Escaping | `functionsLDAP.php` LDAP-Suchen nach `samaccountname` | LDAP-Filter escapen |
|
||||
| Datumsformat `Y-d-m H:i:s` | `index.php`, `stricheintragen.php`, `einzahlung.php`, `hinweise.php` | ISO/DB-kompatibel `Y-m-d H:i:s` oder DB-Zeit verwenden |
|
||||
| Ausgabe von Namen/E-Mails teils unescaped | mehrere Tabellen, z.B. Mitgliederverwaltung | `htmlspecialchars` zentral erzwingen |
|
||||
| Fehlerausgabe mit `sqlsrv_errors()` an Nutzer | mehrere Dateien | Logging intern, neutrale Fehlermeldung extern |
|
||||
| CSV-Mitarbeitersuche mit mutmasslich falscher Parameteranzahl | `csvupload.php` `getMitarbeiterID` | Query pruefen und mit Tests abdecken |
|
||||
| Basis-Auth-Beispiel mit Platzhalter-Passwort | `umfrageergebnisse.php` Kommentarblock | Entfernen oder echte Auth-Middleware nutzen |
|
||||
| App-Navigation ist in `footer.php` | Layoutstruktur | Trennung in App-Shell und Public-Shell |
|
||||
| `headerline.php` enthaelt NUL-Zeichen | `headerline.php` | Datei pruefen/entfernen, wenn ungenutzt |
|
||||
| Massenmail ohne Versandlog | `mailversenden.php`, `jahresauswertung.php` | Job-Modell mit Dry-Run, Audit, Rate-Limit |
|
||||
|
||||
## Rollen- und Zugriffsrisiken
|
||||
|
||||
Aktuell gilt:
|
||||
|
||||
- Sichtbare Admin-Navigation wird in `footer.php` per `checkKaffeelisteAdmin`
|
||||
gesteuert.
|
||||
- Einige Admin-Zielseiten haben eigene Checks.
|
||||
- Einige schreibende oder sensible Dateien verlassen sich nicht durchgehend auf
|
||||
eine eigene Rollenpruefung.
|
||||
|
||||
Fuer SaaS gilt:
|
||||
|
||||
- Menue-Ausblendung ist keine Berechtigungspruefung.
|
||||
- Jede Route braucht serverseitige Auth- und Rollenpruefung.
|
||||
- Jede fachliche Route braucht Tenant-Kontext.
|
||||
- IDs aus Requests muessen zum aktuellen Tenant gehoeren.
|
||||
|
||||
## Empfohlene Reihenfolge fuer Sicherheitsarbeit
|
||||
|
||||
1. Secrets rotieren und aus dem Code entfernen.
|
||||
2. Legacy-Schreibseiten bis zum Umbau hinter explizite Admin-Pruefung setzen.
|
||||
3. CSRF-Schutz in der neuen App-Basis einplanen.
|
||||
4. Finanzdaten im Zielmodell nur noch stornieren, nicht loeschen.
|
||||
5. Uploads ausserhalb des Webroots modellieren.
|
||||
6. Einheitliche Escape-/View-Helfer einfuehren.
|
||||
7. Tenant-Isolation mit Tests gegen zwei Tenants absichern.
|
||||
|
||||
## Nicht im Repo speichern
|
||||
|
||||
- Produktivpasswoerter.
|
||||
- Echte Nutzerlisten.
|
||||
- Bank-/PayPal-Exportdaten mit Personenbezug.
|
||||
- AD-/LDAP-Service-Account-Daten.
|
||||
- Vollstaendige Produktiv-Dumps.
|
||||
Reference in New Issue
Block a user