CNR-Handwerker-Plus
Gesamtdokumentation · Sprint 1 bis Sprint 7
Datenbankentwurf
Konzeptionelles, logisches und physisches Datenmodell · Normalisierung · Sicherheitskonzept
Im Rahmen des Projekts wurde für CNR-Handwerker-Plus eine relationale Datenbank entwickelt. Ziel ist die strukturierte Verwaltung aller relevanten Geschäftsprozesse eines Handwerksbetriebs.
Datenbank dient als zentrale Quelle für:
- Kundenverwaltung
- Mitarbeiterverwaltung
- Auftragsverwaltung
- Terminplanung
- Angebots- und Rechnungsverwaltung
Entwicklungsprinzipien:
- Datenkonsistenz
- Erweiterbarkeit
- Normalisierung bis 3NF
- Klare Tabellenbeziehungen
Die Modellierung orientiert sich an den Anforderungen der IHK für Fachinformatiker Anwendungsentwicklung.
Konzeptionelles Datenmodell
Die Entität Kunde wurde bewusst weiter unterteilt, um Privat- und Firmenkunden sauber zu trennen:
| Beziehung | Kardinalität | Bedeutung |
|---|---|---|
| Kunde – Auftrag | 1 : N | Ein Kunde kann mehrere Aufträge besitzen |
| Auftrag – Position | 1 : N | Ein Auftrag enthält mehrere Positionen |
| Auftrag – Termin | 1 : N | Ein Auftrag kann mehrere Termine besitzen |
| Mitarbeiter – Termin | 1 : N | Ein Mitarbeiter kann mehrere Termine durchführen |
| Auftrag – Rechnung | 1 : 0..1 | Ein Auftrag kann optional eine Rechnung erzeugen |
| Auftrag – Material | N : M | Aufgelöst über Verknüpfungstabelle auftrag_material |
Logisches Datenmodell — Tabellen
kunden (Haupttabelle)
kunden_idPKtyp— privat / firmaist_stammkunde— BOOLEANerstellt_amnotizen
kunden_person
kunden_idPK FKvornamenachname
kunden_firma
kunden_idPK FKfirmennameansprechpartnerust_id
kunden_adressen
adress_idPKkunden_idFKstrasse,hausnummerplz,orttyp
kunden_kontakt
kontakt_idPKkunden_idFKtyp— Telefon, Email, Mobil…wert
mitarbeiter_idPKvorname,nachnameemailUNIQUEpassword_hash— Argon2ID / bcryptrolle— admin, meister, geselle, azubi, bueroaktiv— BOOLEANletzte_login— DATETIME
auftrag_idPKkunden_idFKauftrag_nrUNIQUE — auto-generierttitel,beschreibungstatus— neu, geplant, aktiv, abgeschlossen, abgerechnet, storniertprioritaet— niedrig, normal, dringend, notfallnotiz_intern,kunden_kommentarabgeschlossen_am,erstellt_am
termin_idPKauftrag_idFKmitarbeiter_idFKstart_datetime,end_datetimestatus- CHECK: end_datetime > start_datetime
rechnung_idPKauftrag_idFKkunden_idFKrechnungs_datumfaellig_amstatus— entwurf, gesendet, bezahlt, überfälliggesamtbetragDECIMAL(10,2)
material_idPKnamebeschreibungeinheit— m, Stk, Pkg…lagerbestandpreis_pro_einheitDECIMAL(10,2)
Physisches Datenmodell
Verwendete Datentypen
| Datentyp | Verwendung |
|---|---|
INT | Primärschlüssel, IDs |
VARCHAR | Textfelder (Namen, E-Mail) |
TEXT | Beschreibungen, Notizen |
DECIMAL(10,2) | Preiswerte (exakt, kein Float!) |
DECIMAL(10,3) | Mengen (z.B. 0,5 Stunden) |
DATE / DATETIME | Kalenderdaten / Zeitstempel |
BOOLEAN | Ja/Nein-Felder |
ENUM | Statusfelder, Typen, Rollen |
Verwendete Constraints
| Constraint | Zweck |
|---|---|
PRIMARY KEY | Eindeutige Identifikation |
FOREIGN KEY | Tabellenverknüpfung |
NOT NULL | Pflichtfelder erzwingen |
AUTO_INCREMENT | Automatische ID-Generierung |
UNIQUE | Duplikate verhindern (Email, Nr) |
CHECK | Logikwächter (Preis ≥ 0, Datum) |
Normalisierung
Die Datenbank wurde bis zur 3. Normalform (3NF) normalisiert.
1. Normalform
Alle Attribute sind atomar — keine Mehrfachwerte in einem Feld.
2. Normalform
Alle Nicht-Schlüsselattribute hängen vollständig vom Primärschlüssel ab.
3. Normalform
Keine transitiven Abhängigkeiten — Kundendaten in separate Tabellen ausgelagert.
Bewusste Denormalisierungen (begründet)
- Preishistorisierung in
auftrag_positionundrechnung_position: Der Preis wird zum Zeitpunkt der Bestellung kopiert. Preisänderungen in der Zukunft dürfen bestehende Rechnungen nicht rückwirkend verändern (GoBD-konform). - MwSt-Satz direkt in Positionstabellen gespeichert: Sichert korrekte Berechnung bei gesetzlichen Steuersatzänderungen.
netto_summeinangebot: Bewusste Denormalisierung als Performance-Cache. Verhindert rechenintensive Aggregationen bei jedem Seitenaufruf.auftrag_material: Löst N:M-Beziehung auf und verhindert Materialkosten-Redundanz.
Sicherheitskonzept & Datenintegrität
- Fremdschlüsselbeziehungen mit
ON DELETE CASCADE/SET NULL - NOT NULL Constraints an Pflichtfeldern
- ENUM-Werte für kontrollierte Eingaben
- AUTO_INCREMENT Schlüssel
- UNIQUE auf E-Mail und Auftragsnummern
- Passwortspeicherung als Hash (Argon2ID / bcrypt)
- Login-Protokollierung in
login_log - Rollenbasierte Zugriffskontrolle (admin → meister → geselle → azubi → buero)
- Pflichtfelder bei Kundenerstellung
- Validierung von Datumswerten
- Trennung von Benutzer- und Kundendaten
Technische Datenbankdokumentation
Datentypen · Constraints · Installationsanleitung
❌ FLOAT / DOUBLE
Binäre Gleitkommazahlen → Rundungsfehler bei kaufmännischen Berechnungen.
// Klassisches Problem: 0.1 + 0.2 = 0.300000000004
✅ DECIMAL(10,2)
Exakte Festkommazahlen → keine Cent-Abweichungen bei Rechnungen.
// Verwendung in CNR-Handwerker-Plus: DECIMAL(10,2) ← Preise, Summen, MwSt DECIMAL(10,3) ← Mengen (0,5 Std, 1,255 kg)
Für ein Handwerker-System, in dem Rechnungen rechtssicher erstellt werden müssen, ist DECIMAL zwingend erforderlich.
| Datentyp | Einsatz in CNR-Handwerker-Plus | Begründung |
|---|---|---|
ENUM |
status, rolle, typ | Stellt sicher, dass nur vordefinierte Werte eingetragen werden (z.B. Rolle kann nicht "Chef" sein) |
BOOLEAN |
ist_stammkunde, aktiv | Intern TINYINT(1) — ideal für Ja/Nein-Werte |
DATETIME |
Login-Log, Erstellung, Termine | Für Protokolle mit genauem Zeitpunkt |
DATE |
Rechnungsdatum, Fälligkeitsdatum | Für reine Kalendertage ohne Uhrzeit |
Erklärung der wichtigsten Constraints
Constraints sichern die Datenintegrität. Ohne sie würde die Datenbank schnell inkonsistent.
| Constraint | Wirkung |
|---|---|
PRIMARY KEY | Identifiziert Datensatz eindeutig, verhindert Dubletten |
FOREIGN KEY | Verknüpft Tabellen, verhindert Waisen-Datensätze |
ON DELETE CASCADE | Löscht automatisch Adressen/Kontakte wenn Kunde gelöscht wird |
ON DELETE SET NULL | login_log bleibt erhalten, mitarbeiter_id wird NULL (Historie) |
CHECK | Logikwächter: netto_summe ≥ 0, end_datetime > start_datetime |
UNIQUE | Email, auftrag_nr darf systemweit nur einmal vorkommen |
-- Beispiel: Fremdschlüssel mit Cascade ALTER TABLE kunden_adressen ADD CONSTRAINT fk_adr_kunde FOREIGN KEY (kunden_id) REFERENCES kunden(kunden_id) ON DELETE CASCADE; -- CHECK Constraint CHECK (end_datetime > start_datetime) CHECK (netto_summe >= 0)
Installation der Datenbank
Voraussetzungen
MySQL-Server (z.B. via XAMPP, MariaDB oder Docker) + ein DB-Client (phpMyAdmin, MySQL Workbench, DBeaver oder Konsole).
Datenbankstruktur erstellen
-- Zuerst: Struktur anlegen SOURCE create_db.sql;
Testdaten einspielen
-- Danach: Testdaten einfügen SOURCE test_data.sql;
Verbindung prüfen (Konsole)
mysql -u dein_benutzer -p USE handwerkerpro_db; SHOW TABLES; SELECT * FROM mitarbeiter;
Erfolgskontrolle
Wenn folgende Abfrage 10 Einträge mit verschiedenen Status-Werten liefert, war die Installation erfolgreich:
SELECT * FROM auftrag; -- Erwartung: 10 Einträge
Views & Query-Dokumentation
Tagesgeschäft · Wochenplanung · Monatsreporting · Material & Lager
1. Tagesgeschäft — schneller Überblick
Was: Alle Anfragen mit Status neu, sortiert nach Wartezeit. Wofür: Schnelle Reaktion auf Neukunden.
| kunden_id | kunde | anfrage_titel | erstellt_am | tage_warten |
|---|---|---|---|---|
| 7 | Bauhaus AG | Industrie-Wartung Q1 | 2026-02-15 | 15 |
| 6 | Dieter Bohlen | Leitung verstopft | 2026-02-10 | 20 |
Was: Offene Rechnungen über dem Fälligkeitsdatum. Wofür: Liquiditätskontrolle und Mahnwesen.
| rechnung_id | faellig_am | tage_verzug | brutto_betrag |
|---|---|---|---|
| 4 | 2026-03-01 | 1 | 214,20 € |
| 10 | 2026-02-24 | 6 | 450,00 € |
Was: Alle Termine für den heutigen Tag. Wofür: Einsatzplanung.
| mitarbeiter | start_datetime | end_datetime | auftrag | prioritaet |
|---|---|---|---|---|
| Max Mustermann | 11:00:00 | 14:00:00 | Leitung verstopft | normal |
| Lena Zimmer | 09:00:00 | 17:00:00 | Industrie-Wartung | dringend |
2. Wochenplanung — Ressourcen & Material
Alle Aufträge, die diese Woche aktiv bearbeitet werden.
| auftrag_nr | titel | status | prioritaet |
|---|---|---|---|
| AUF-011 | Leitung verstopft | neu | normal |
| AUF-012 | Industrie-Wartung | neu | dringend |
Geplante Stunden pro Mitarbeiter für die aktuelle KW.
| vorname | nachname | geplante_stunden |
|---|---|---|
| Lena | Zimmer | 38 h |
| Klaus | Bauer | 12 h |
Benötigtes Material vs. aktueller Lagerbestand für die Woche — ermöglicht vorausschauende Beschaffung.
| name | benoetigte_menge | aktueller_bestand | einheit |
|---|---|---|---|
| Kupferrohr 15mm | 10.00 | 100 | Meter |
| Heizungspumpe | 1.00 | 4 | Stück |
3. Monatsreporting — Erfolgskontrolle
Was: Netto-Umsatz pro Mitarbeiter für den laufenden Monat. Wofür: Faire Leistungsbewertung und Provisionsberechnung.
SELECT DISTINCT mitarbeiter_id, auftrag_id wird sichergestellt, dass ein Auftrag dem Mitarbeiter nur einmal zugerechnet wird, auch wenn er mehrfach vor Ort war. Verhindert künstliche Aufblähung der Umsatzzahlen.
| vorname | nachname | monats_umsatz |
|---|---|---|
| Lena | Zimmer | 1.450,00 € |
| Klaus | Bauer | 1.100,00 € |
| Max | Mustermann | 920,00 € |
Mittlere Dauer in Tagen von Anfrage bis abgeschlossen_am.
| avg_tage_bis_abschluss |
|---|
| 6.45 |
Das Feld abgeschlossen_am wurde explizit eingeführt um präzise Messung zu ermöglichen.
Wertvollste Kunden mit Klarnamen nach Gesamtumsatz.
| kunden_name | gesamt_umsatz |
|---|---|
| Berger Bau GmbH | 4.250,00 € |
| Bauhaus AG | 2.100,00 € |
4. Material & Lager-Views
Artikel unter 5 Einheiten Lagerbestand.
| name | lagerbestand | einheit |
|---|---|---|
| Heizungspumpe | 4 | Stück |
| Siphon flexibel | 2 | Stück |
Ranking nach Gesamtverbrauch über alle Aufträge.
| name | gesamt_verbrauch |
|---|---|
| Dichtungssatz | 54.00 |
| Kupferrohr 15mm | 45.00 |
Doppelzählungen eliminiert
Kombination aus Subquery (GROUP BY r.auftrag_id) und SELECT DISTINCT mitarbeiter_id, auftrag_id — ein Umsatz wird pro Mitarbeiter und Auftrag exakt einmal gewertet.
Performance-Indizes
idx_termin_start und idx_rechnung_faellig stellen sicher dass Joins und Filter auch bei großen Datensätzen performant bleiben.
Datenintegrität 100%
Feld abgeschlossen_am ermöglicht präzise Bearbeitungszeitenmessung — nicht verfälschbar durch nachträgliche Notizen.
Struktur & Benennung
Alle Views sprechend benannt (view_...), logisch gegliedert und durchgehend kommentiert. Modularer Aufbau erleichtert zukünftige Dashboard-Erweiterungen.
Automatisierung & Integrität
Stored Procedures · Trigger · Transaktionen · Performance · Abnahmetests
1. Stored Procedures
Stored Procedures kapseln komplexe Abläufe in einfache Befehle und validieren Eingaben. Alle kritischen Prozeduren sind mit TRANSACTION + EXIT HANDLER abgesichert.
Erstellt einen neuen Auftrag. Prüft vorab ob kunden_id vorhanden ist.
CALL sp_neuer_auftrag( KundenID, 'Titel', 'Priorität' );
Verknüpft Material mit Auftrag. Prüft: Menge positiv + genug Lagerbestand vorhanden.
CALL sp_material_zuordnen( AuftragID, MaterialID, Menge );
Markiert eine Rechnung als bezahlt und aktualisiert den Zeitstempel. Wird auch von REST-API aufgerufen.
Setzt Status auf abgeschlossen und trägt Datum in abgeschlossen_am ein. Löst indirekt den Trigger zur automatischen Rechnungserstellung aus.
Erhöht Lagerbestand. Stellt sicher dass keine negativen Mengen nachbestellt werden (Validierung).
CALL sp_material_nachbestellen(
MaterialID,
Menge -- muss > 0 sein
);Prüft alle offenen Rechnungen. Wenn faellig_am mehr als 30 Tage zurückliegt → Status automatisch auf überfällig. Für Cron-Job geeignet.
2. Trigger
Trigger reagieren in Echtzeit auf Datenbankänderungen — vollautomatisch, ohne Benutzereingriff.
| # | Trigger-Name | Ereignis | Automatische Aktion |
|---|---|---|---|
| A | tr_auftrag_nummer_gen |
BEFORE INSERT Auftrag | Erzeugt automatisch Auftragsnummer wie 2026-001 via LPAD(MAX()+1, 4) |
| B | tr_lager_abbuchen |
AFTER INSERT Materialzuordnung | Reduziert sofort den Lagerbestand um die verbrauchte Menge |
| C | tr_kunden_loeschschutz |
BEFORE DELETE Kunden | Blockiert Löschen wenn Kunde noch aktive (nicht abgeschlossene) Aufträge hat |
| D | tr_rechnung_status_logtr_auftrag_status_log |
AFTER UPDATE Rechnung/Auftrag | Schreibt jede Statusänderung automatisch in status_log Tabelle |
| E | tr_auto_rechnung_erstellen |
AFTER UPDATE Auftrag | Erstellt sofort neue Rechnung wenn Auftrag auf abgeschlossen gesetzt wird |
| F | tr_lager_rueckgabe_delete |
AFTER DELETE Auftrag_Material | Material aus Auftrag entfernt → Lagerbestand wird automatisch erhöht |
| G | tr_lager_anpassung_update |
AFTER UPDATE Auftrag_Material | Mengenänderung → Differenz wird automatisch im Lagerbestand korrigiert |
| H | tr_kunden_archivieren |
BEFORE DELETE Kunden | Kopiert Kundendaten unmittelbar vor dem Löschen in kunden_archiv |
3. Transaktionen
Kritische Operationen werden durch Transaktionen gesichert. Bei Fehler werden alle Teilschritte rückgängig gemacht (Rollback).
Beispiel: Auftrag stornieren
- Status wird auf
storniertgesetzt - Material wird dem Lager wieder gutgeschrieben
BEGIN; -- 1. Status setzen UPDATE auftrag SET status = 'storniert' WHERE auftrag_id = ?; -- 2. Material zurückbuchen UPDATE material SET lagerbestand = lagerbestand + ? WHERE material_id = ?; COMMIT; -- Bei Fehler: ROLLBACK;
4. Performance-Optimierung (Indizes)
| Index | Tabelle/Spalte | Optimiert | Sprint |
|---|---|---|---|
idx_auftrag_status | auftrag.status | Suche nach abgeschlossenen/offenen Projekten | Sprint 3 |
idx_termin_start | termin.start_datetime | Tages-/Wochenplan Joins | Sprint 3 |
idx_rechnung_faellig | rechnung.faellig_am | 30-Tage-Überfälligkeitscheck | Sprint 3 |
idx_rechnung_datum | rechnung.rechnungs_datum | Datumsbasierte Filterungen | Sprint 4 |
idx_mat_bestand | material.lagerbestand | Schnelle Bestandsprüfung vor Materialzuordnung | Sprint 4 |
idx_log_zeit | status_log.erstellt_am | Zeitbasierte Abfragen auf der Log-Tabelle | Sprint 4 |
5. Abnahmetests — Systemvalidierung
Ein stabiles System muss nicht nur unter Normalbedingungen, sondern auch in Grenzfällen (Edge Cases) die Datenintegrität wahren.
Szenario 1Überprüfung des Lagerbestands (Negativtest)
Vorgang: CALL sp_material_zuordnen(1, [id], 10) bei einem Material mit Bestand = 5
Erwartung: SIGNAL SQLSTATE mit Meldung "Nicht genügend Lagerbestand!" — kein neuer Datensatz in auftrag_material (Rollback-Nachweis)
Szenario 2Kettenreaktion und Fehlerbehandlung
Vorbereitung: NOT NULL Spalte zur rechnung Tabelle hinzufügen, die Trigger nicht bedient.
Vorgang: CALL sp_auftrag_abschliessen(1) — Erwartung: EXIT HANDLER verhindert Statusänderung, Rollback auf ursprünglichen Zustand.
Szenario 3Dublettenprüfung und MAX()-Logik
Vorgang: Manuell Auftrag mit Nummer 2026-999 einfügen, dann sp_neuer_auftrag aufrufen.
Erwartung: Neuer Auftrag erhält Nummer 2026-1000 — beweist Stabilität der MAX()-Logik gegenüber COUNT()-Logik.
Szenario 4Kundenschutz (Referenzielle Integrität)
Vorgang: DELETE FROM kunden WHERE kunden_id = 1 bei Kunde mit offenen Aufträgen.
Erwartung: Trigger tr_kunden_loeschschutz verhindert Löschung und gibt Fehlermeldung aus.
Szenario 5Zeitbasierte Automatisierung (Mahnwesen)
Vorbereitung: faellig_am auf 35 Tage in der Vergangenheit setzen, Status = gesendet.
Erwartung: CALL sp_update_ueberfaellige_rechnungen() setzt nur diese Rechnung auf überfällig. Statusänderung wird in status_log dokumentiert.
Szenario 6Atomarität und Fehlerbehandlung (Rollback-Test)
Vorgang: sp_material_zuordnen mit nicht existierender auftrag_id aufrufen.
Erwartung: Fehlermeldung + kein Lagerbestandsabzug (keine halben Datenbankzustände).
Szenario 7Kontrolle von multiplen Materialien und Gesamtbetrag
Szenario: Zwei Materialien zu unterschiedlichen Preisen einem Auftrag hinzufügen.
Erwartung: Rechnungsbetrag = (Menge1 × Preis1) + (Menge2 × Preis2) — exakt.
Szenario 8Rückgabe an Lagerbestand nach Stornierung
Ablauf: Material zuweisen → Lagerbestandsabzug prüfen → Auftrag stornieren.
Erwartung: Lagerbestand wird vollständig auf den ursprünglichen Wert zurückgesetzt.
Szenario 9Korrektheit der Archivierung
Ablauf: Kunden ohne Aufträge löschen.
Erwartung: Nicht mehr in kunden — aber vollständig mit allen Daten in kunden_archiv vorhanden.
REST API — Slim Framework 4
PHP 8.1 · PDO Prepared Statements · Argon2ID · CORS · 22 Endpoints
Basis-URL
http://localhost/api
Alle Antworten:
Content-Type: application/json; charset=UTF-8
Technologie-Stack
| Framework | Slim Framework 4 |
| Sprache | PHP 8.1+ |
| DB-Zugriff | PDO (Prepared Statements, kein String-Concat!) |
| Passwort | Argon2ID / bcrypt |
| Webserver | Apache + mod_rewrite |
✅ Erfolg:
{
"status": "success",
"message": "Beschreibung",
"data": { ... }
}❌ Fehler:
{
"status": "error",
"message": "...",
"details": { ... }
}HTTP-Codes:
201 Created
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
409 Conflict
422 Unprocessable
500 Server Error
Pagination
GET /api/kunden?page=2&limit=10
// Antwort enthält: total, page, limit, pagesInstallation (Slim Framework)
Dateien platzieren
C:\xampp\htdocs\
└── slim-api\
├── composer.json
├── config\ ← database.php, settings.php
├── public\ ← Apache DocumentRoot
└── src\ ← Controllers, Middleware, ModelsAbhängigkeiten installieren
cd C:\xampp\htdocs\slim-api
composer install
// Installiert: slim/slim, slim/psr7, php-di/php-di, monologApache konfigurieren (httpd-vhosts.conf)
<VirtualHost *:80>
DocumentRoot "C:/xampp/htdocs/slim-api/public"
ServerName localhost
<Directory "C:/xampp/htdocs/slim-api/public">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>Datenbank-Zugangsdaten anpassen (config/database.php)
return [ 'host' => 'localhost', 'name' => 'handwerkerpro_db', 'user' => 'root', 'pass' => '', ];
Apache restarten → testen
http://localhost/api http://localhost/docs/testclient.html
Authentifizierung & Rollensystem
Methode 1: API-Key Header
X-API-Key: admin-key-12345
// oder:
Authorization: Bearer admin-key-12345Methode 2: Session-Login
POST /api/auth/login
{
"email": "...",
"password": "demo123"
}Demo API-Keys
| API-Key | Rolle | Berechtigungen |
|---|---|---|
admin-key-12345 | admin | Vollzugriff inkl. Material löschen |
meister-key-67890 | meister | Alles außer Material löschen |
geselle-key-11111 | geselle | Lesen, Erstellen, Bearbeiten |
// Rollenhierarchie (höher = mehr Rechte):
admin (5) > meister (4) > geselle (3) > azubi (2) > buero (1)
GET → alle Rollen
POST → geselle+
PUT → geselle+
DELETE → meister+ (kunden/auftraege), admin (material)Sicherheit
Prepared Statements
PDO mit ATTR_EMULATE_PREPARES=false. String-Concatenation für SQL ist vollständig verboten.
Passwort-Hashing
Argon2ID via password_hash() und password_verify(). Niemals Klartext-Passwörter.
Input-Sanitizing
Alle Eingaben via strip_tags() + trim() (XSS-Schutz). ENUM-Werte per Whitelist validiert.
CORS-Header
CorsMiddleware setzt alle nötigen Header. OPTIONS Preflight wird sofort beantwortet.
Fehlerbehandlung & Validierung
Validierungsregeln
- Pflichtfelder fehlen → 422
- ENUM-Wert nicht erlaubt → 422
- Datum ungültig (YYYY-MM-DD) → 422
- Preis/Menge ≤ 0 → 422
- E-Mail invalid → 422
- Ressource nicht gefunden → 404
- DB-Trigger blockiert (offene Aufträge) → 409
// 422 mit Details: { "status": "error", "message": "Pflichtfelder fehlen.", "details": { "fehlende_felder": [ "vorname", "nachname" ] } }
Endpoints: Auth
curl -X POST http://localhost/api/auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "password": "demo123" }'
// Antwort 200: { "mitarbeiter_id": 1, "rolle": "admin", "session_aktiv": true }
curl http://localhost/api/auth/me -H "X-API-Key: admin-key-12345"curl -X POST http://localhost/api/auth/logout -H "X-API-Key: admin-key-12345"Endpoints: Dashboard
KPIs, heutige Termine, Notfall-Aufträge, kritische Lagerbestände, Mitarbeiterauslastung.
curl http://localhost/api/dashboard -H "X-API-Key: admin-key-12345"Endpoints: Kunden
Filter: typ (privat/firma), stammkunde (bool), search, page, limit
curl "http://localhost/api/kunden?typ=firma&stammkunde=true" \
-H "X-API-Key: admin-key-12345"Vollständiger Datensatz inkl. Kontakte, Adressen, Personen/Firmen-Details.
curl http://localhost/api/kunden/1 -H "X-API-Key: admin-key-12345"curl http://localhost/api/kunden/1/auftraege -H "X-API-Key: admin-key-12345"Privatkunde:
{ "typ": "privat", "vorname": "Hans",
"nachname": "Maier",
"kontakt_typ": "Mobil",
"kontakt_wert": "0170-1234567" }Firmenkunde:
{ "typ": "firma",
"firmenname": "Muster GmbH",
"ansprechpartner": "Herr Koch",
"ust_id": "DE123456789" }curl -X PUT http://localhost/api/kunden/1 \ -H "X-API-Key: admin-key-12345" \ -d '{ "ist_stammkunde": true, "notizen": "VIP-Kunde" }'
Trigger tr_kunden_loeschschutz blockiert bei offenen Aufträgen → 409
curl -X DELETE http://localhost/api/kunden/5 -H "X-API-Key: meister-key-67890"Endpoints: Aufträge
Filter: status (kommagetrennt), prioritaet, kunden_id, datum_von, datum_bis, search, sort, dir
curl "http://localhost/api/auftraege?status=neu,aktiv&prioritaet=notfall" \
-H "X-API-Key: admin-key-12345"Via sp_neuer_auftrag. Auftragsnummer automatisch via Trigger. Pflicht: kunden_id, titel (3–150 Zeichen).
curl -X POST http://localhost/api/auftraege \ -H "X-API-Key: geselle-key-11111" \ -d '{ "kunden_id": 1, "titel": "Heizungsreparatur Keller", "prioritaet": "dringend" }'
Spezialverhalten: abgeschlossen → ruft sp_auftrag_abschliessen auf → Rechnung wird automatisch erstellt. storniert → sp_auftrag_stornieren → Material zurückgebucht.
curl -X PUT http://localhost/api/auftraege/3/status \ -H "X-API-Key: admin-key-12345" \ -d '{ "status": "abgeschlossen" }'
Abgerechnete Aufträge können nicht gelöscht werden → 409
curl -X DELETE http://localhost/api/auftraege/15 -H "X-API-Key: meister-key-67890"Endpoints: Rechnungen
Filter: status, kunden_id, ueberfaellig=true, datum_von, datum_bis
curl "http://localhost/api/rechnungen?ueberfaellig=true" \
-H "X-API-Key: admin-key-12345"Via sp_rechnung_bezahlen. Bereits bezahlte Rechnung → 409
curl -X POST http://localhost/api/rechnungen/2/bezahlen \
-H "X-API-Key: admin-key-12345"Aktualisierbar: status, faellig_am (Format: YYYY-MM-DD)
curl -X PUT http://localhost/api/rechnungen/2 \
-d '{ "status": "gesendet", "faellig_am": "2026-04-01" }'Endpoints: Material
Filter: search, niedrig_bestand, bestellliste, nachbestellen, meistverwendet
curl "http://localhost/api/material?niedrig_bestand=1" \ -H "X-API-Key: admin-key-12345" curl "http://localhost/api/material?bestellliste=1" \ -H "X-API-Key: admin-key-12345"
Pflicht: name, preis_pro_einheit (>0). Lagerbestand darf nicht negativ sein.
curl -X POST http://localhost/api/material \ -H "X-API-Key: meister-key-67890" \ -d '{ "name": "Kupferrohr 22mm", "einheit": "Meter", "lagerbestand": 50, "preis_pro_einheit": 15.90 }'
Via sp_material_nachbestellen. Menge muss > 0 sein.
curl -X POST http://localhost/api/material/4/nachbestellen \
-d '{ "menge": 20 }'Schlägt fehl wenn Material in Aufträgen verwendet wird → 409
curl -X DELETE http://localhost/api/material/6 -H "X-API-Key: admin-key-12345"A. PDF - B. E-Mail - C. Export-Funktionen - D. Reporting & Statistiken - E. Automatisierung
PDF-Generierung
TCPDF · Rechnung · Angebot · Monatsreport · Professionelles Layout
Dateistruktur
slim-api/ ├── composer.json ← tecnickcom/tcpdf hinzugefügt └── src/ ├── Pdf/ │ ├── BasePdf.php ← TCPDF-Basisklasse (Header, Footer, Stile) │ ├── RechnungPdf.php ← Rechnungs-PDF │ ├── AngebotPdf.php ← Angebots-PDF │ └── MonatsreportPdf.php ← Monatsreport (2 Seiten) └── Controllers/ └── PdfController.php ← 3 neue Endpoints
Technologie
| PDF-Bibliothek | TCPDF 6.7 |
| Composer-Paket | tecnickcom/tcpdf |
| Ausgabeformat | A4, Portrait |
| Schrift | Helvetica (built-in) |
| Sprache | Deutsch (UTF-8) |
BasePdf — einheitlicher Header, Footer und Tabellenstil.
Installation
Neue Dateien ins Projekt kopieren
Folgende Dateien in die bestehende Slim-Struktur einfügen:
src\Pdf\BasePdf.php → neu anlegen src\Pdf\RechnungPdf.php → neu anlegen src\Pdf\AngebotPdf.php → neu anlegen src\Pdf\MonatsreportPdf.php → neu anlegen src\Controllers\PdfController.php → neu anlegen public\index.php → bestehende Datei ersetzen composer.json → bestehende Datei ersetzen
TCPDF installieren
Im slim-api Ordner einmalig ausführen:
cd C:\xampp\htdocs\slim-api composer update
Composer lädt tecnickcom/tcpdf automatisch in den vendor/ Ordner. Kein weiterer Konfigurationsaufwand nötig.
Apache neu starten & testen
XAMPP Control Panel → Apache → Restart, dann im Browser:
# Rechnung als PDF herunterladen: http://localhost/api/rechnungen/1/pdf # Im Browser anzeigen (nicht herunterladen): http://localhost/api/rechnungen/1/pdf?inline # Monatsreport März 2026: http://localhost/api/reports/monat/2026/3
Wenn der Browser ein PDF öffnet oder herunterlädt, ist die Installation erfolgreich.
Rechnungs-PDF — Aufbau
Header
- Blauer Balken mit Firmenname
- Absenderzeile (klein, über Anschrift)
- Empfängeranschrift
- Info-Box rechts: Rechnungsnr., Datum, Fälligkeitsdatum, Kundennr.
Body
- Titel "Rechnung" + Auftragsbezug
- Positionstabelle: Pos., Beschreibung, Typ, Menge, Einzelpreis, Gesamtpreis
- Arbeitszeit-Kosten (Std.)
- Material-Kosten (Stk.)
- Zwischensumme (netto)
- Mehrwertsteuer 19%
- Gesamtbetrag (brutto) — blau hervorgehoben
Footer
- Zahlungshinweis-Box mit IBAN, BIC, Frist
- Grußformel
- Dreispaltig: Bankverbindung · Kontakt · Steuerdaten
- Seitenzahl
Angebots-PDF — Aufbau
Gleiche Struktur wie Rechnungs-PDF, mit angebotsspezifischen Unterschieden:
| Element | Inhalt |
|---|---|
| Info-Box | Angebotsnr., Datum, Gültig bis, Kundennr. |
| Summenblock | Nettobetrag · MwSt 19% · Angebotssumme (brutto) |
| Abschluss | Gültigkeitshinweis + AGB-Hinweis |
| Standardgültigkeit | 30 Tage ab Ausstellungsdatum |
// Angebot-PDF abrufen: GET /api/angebote/1/pdf // Im Browser öffnen: GET /api/angebote/1/pdf?inline
Monatsreport-PDF — Aufbau
Zweiseitiger Management-Report. Alle Daten werden per DB-Abfrage für den gewählten Monat aggregiert.
Seite 1
- 6 KPI-Kacheln: Gesamtumsatz, abgeschlossene Aufträge, offene Aufträge, unbezahlte Rechnungen, offener Betrag, neue Kunden
- Top 5 Kunden nach Umsatz mit Auftragsanzahl
- Mitarbeiter-Auslastung: Geplante Stunden, Auftragsanzahl, Monatsumsatz
Seite 2
- Offene Aufträge mit Status, Priorität und Wert
- Unbezahlte Rechnungen — überfällige Zeilen rot hervorgehoben
- Materialverbrauch Top 10 mit Gesamtmenge und Wert
- Erstellungszeitstempel im Footer
// Monatsreport März 2026: GET /api/reports/monat/2026/3 // Im Browser öffnen: GET /api/reports/monat/2026/3?inline
Neue Endpoints (Sprint 6)
Generiert eine Rechnung als PDF. Query-Parameter ?inline zeigt das PDF im Browser an, ohne ?inline wird es heruntergeladen.
curl http://localhost/api/rechnungen/1/pdf \
-H "X-API-Key: $API_KEY_ADMIN" \
--output Rechnung_R-2026-0001.pdfGeneriert ein Angebot als PDF inkl. Gültigkeitsdatum und AGB-Hinweis.
curl http://localhost/api/angebote/1/pdf \
-H "X-API-Key: $API_KEY_ADMIN" \
--output Angebot_ANG-2026-0001.pdfGeneriert den Monatsreport als zweiseitiges PDF. Jahr: 2020–2099, Monat: 1–12.
curl http://localhost/api/reports/monat/2026/3 \ -H "X-API-Key: $API_KEY_ADMIN" \ --output Monatsreport_2026_03.pdf # Im Browser öffnen: http://localhost/api/reports/monat/2026/3?inline
E-Mail-Versand
PHPMailer · SMTP · HTML-Templates · PDF-Anhang · Mahnwesen · Benachrichtigungen
Dateistruktur
slim-api/ ├── composer.json ← phpmailer/phpmailer hinzugefügt ├── .env ← SMTP-Zugangsdaten (neu) ├── config/ │ └── settings.php ← mail[] Konfigurationsblock (neu) └── src/ ├── Mail/ │ ├── Mailer.php ← PHPMailer Wrapper (SMTP, Anhänge) │ └── MailTemplates.php ← 4 HTML-E-Mail-Vorlagen └── Controllers/ └── MailController.php ← 4 neue Endpoints
Technologie
| Bibliothek | PHPMailer 6.9 |
| Composer-Paket | phpmailer/phpmailer |
| Protokoll | SMTP (TLS / SSL) |
| Format | HTML + Plaintext Fallback |
| Anhang | PDF (base64, kein temp-File) |
| Test-Tool | Mailtrap.io (kostenlos) |
Rechnung · Mahnung (3 Stufen) · Auftrag-Status · SMTP-Test
Installation & SMTP-Konfiguration
Neue Dateien ins Projekt kopieren
src\Mail\Mailer.php → neu anlegen src\Mail\MailTemplates.php → neu anlegen src\Controllers\MailController.php → neu anlegen config\settings.php → bestehende Datei ersetzen (mail[] Block neu) public\index.php → bestehende Datei ersetzen (neue Routes) composer.json → bestehende Datei ersetzen
PHPMailer installieren
cd C:\xampp\htdocs\slim-api composer update
Composer lädt phpmailer/phpmailer automatisch in den vendor/ Ordner.
SMTP-Zugangsdaten in .env eintragen
Für die Entwicklung empfehlen wir Mailtrap.io (kostenlos, fängt alle E-Mails ab ohne echten Versand):
# Mailtrap — Entwicklung (https://mailtrap.io) MAIL_SMTP_HOST=sandbox.smtp.mailtrap.io MAIL_SMTP_PORT=587 MAIL_SMTP_USER=dein-mailtrap-user MAIL_SMTP_PASS=dein-mailtrap-pass MAIL_SMTP_SECURE=tls [email protected] MAIL_FROM_NAME=Klaus Meier GmbH MAIL_DEBUG=false # Produktion — z.B. eigener Mailserver MAIL_SMTP_HOST=mail.klausmeier-gmbh.de MAIL_SMTP_PORT=465 MAIL_SMTP_SECURE=ssl
SMTP-Verbindung testen
curl -X POST http://localhost/api/mail/test \ -H "X-API-Key: $API_KEY_ADMIN" \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]" }'
Bei Erfolg erscheint die Test-Mail im Mailtrap-Postfach.
E-Mail-Templates
Professionelle HTML-E-Mail mit PDF-Anhang.
- Rechnungsnummer, Datum, Fälligkeitsdatum
- Gesamtbetrag farbig hervorgehoben (blau)
- Positionstabelle (optional)
- Bankverbindungshinweis
- PDF automatisch generiert & angehängt
Farbcodierte Mahnung nach Eskalationsstufe.
- Stufe 1 — Zahlungserinnerung (orange)
- Stufe 2 — 1. Mahnung (rot)
- Stufe 3 — 2. Mahnung / Letzte Aufforderung (dunkelrot)
- Verzug in Tagen und offener Betrag
Statusänderung automatisch an Kunden melden.
- ● Geplant · ● In Bearbeitung
- ● Abgeschlossen · ● Storniert
- Status-Badge farbig im Mail-Body
- Kontaktdaten der Firma im Footer
Prüft ob SMTP-Konfiguration korrekt ist.
- Grüne Bestätigungs-Box
- Erstellungszeitstempel
- Nur für Meister+ zugänglich
Neue Endpoints (Sprint 6B)
Generiert die Rechnung als PDF und versendet sie per E-Mail. Empfänger-Adresse aus DB oder aus Request-Body.
| Feld | Typ | Beschreibung | |
|---|---|---|---|
email | string | Optional | Überschreibt die E-Mail aus der Kundendatenbank |
curl -X POST http://localhost/api/rechnungen/1/email \ -H "X-API-Key: $API_KEY_ADMIN" \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]" }' // Antwort 200: { "rechnung_id": 1, "empfaenger": "[email protected]", "betreff": "Rechnung R-2026-0001 von Klaus Meier GmbH", "pdf_angehängt": "Rechnung_R-2026-0001.pdf", "gesendet_am": "2026-03-10T14:23:00+01:00" }
Sendet Mahnungen an alle überfälligen Rechnungen. Mit Sicherheitslimit und Mahnstufen-Auswahl.
| Feld | Typ | Beschreibung | |
|---|---|---|---|
mahnstufe | int | Optional | 1 = Erinnerung · 2 = 1. Mahnung · 3 = 2. Mahnung (Standard: 1) |
min_tage_verzug | int | Optional | Nur Rechnungen mit mindestens X Tagen Verzug (Standard: 1) |
max_anzahl | int | Optional | Maximale Anzahl Mahnungen pro Aufruf (Standard: 50) |
curl -X POST http://localhost/api/rechnungen/mahnungen \ -H "X-API-Key: $API_KEY_ADMIN" \ -d '{ "mahnstufe": 1, "min_tage_verzug": 7 }' // Antwort 200: { "gesendet": 3, "fehler": 1, "details": [ { "rechnung_id": 4, "empfaenger": "...", "tage_verzug": 12, "status": "gesendet" }, { "rechnung_id": 7, "status": "fehler", "grund": "Keine E-Mail hinterlegt" } ] }
Sendet dem Kunden eine HTML-Benachrichtigung über den aktuellen Auftragsstatus.
curl -X POST http://localhost/api/notifications/auftrag/3 \ -H "X-API-Key: $API_KEY_ADMIN" \ -d '{ "email": "[email protected]" }'
Sendet eine Test-E-Mail zur Überprüfung der SMTP-Konfiguration.
| Feld | Typ | Beschreibung | |
|---|---|---|---|
email | string | Pflicht | Ziel-Adresse für die Test-Mail |
curl -X POST http://localhost/api/mail/test \ -H "X-API-Key: $API_KEY_ADMIN" \ -d '{ "email": "[email protected]" }'
CSV-Export & Backup
UTF-8 · Excel-kompatibel · Semikolon-Trennung · ZIP-Komplett-Backup
Dateistruktur
slim-api/ ├── public/ │ └── index.php ← aktualisiert └── src/ └── Controllers/ └── ExportController.php ← neu (6 Endpoints)
Keine neuen Abhängigkeiten — ZipArchive ist in PHP 8 standardmäßig enthalten.
Technologie
| Format | CSV (RFC 4180) |
| Encoding | UTF-8 mit BOM |
| Trennzeichen | Semikolon (;) |
| Zeilenumbruch | CRLF (Windows) |
| Backup-Format | ZIP (alle CSVs) |
| Berechtigung | meister+ |
Installation
Neue Datei ins Projekt kopieren
src\Controllers\ExportController.php → neu anlegen
Keine weiteren Abhängigkeiten. ZipArchive ist in PHP 8 standardmäßig aktiv.
index.php ersetzen (neue Routes)
public\index.php → bestehende Datei ersetzenDie neuen /api/export/* Routes werden eingetragen. Alle bestehenden Routes bleiben unverändert.
Apache neu starten & testen
# Kunden als CSV herunterladen: curl http://localhost/api/export/kunden \ -H "X-API-Key: $API_KEY_ADMIN" \ --output kunden.csv # Kompletter Backup als ZIP: curl http://localhost/api/export/backup \ -H "X-API-Key: $API_KEY_ADMIN" \ --output backup.zip
CSV-Format & Excel-Kompatibilität
Formatdetails
| Encoding | UTF-8 mit BOM (EF BB BF) |
| Trennzeichen | Semikolon ; — Deutsches Excel-Standard |
| Zeilenumbruch | CRLF \r\n — Windows-kompatibel |
| Dezimalzahl | Komma 19,99 — Kein Punkt |
| Datumsformat | TT.MM.JJJJ — z.B. 15.03.2026 |
| Textfelder | In "Anführungszeichen" bei Sonderzeichen |
| Nullwerte | Leere Zelle (nicht NULL) |
Exportierte Tabellen
| Endpoint | Inhalt | Spalten |
|---|---|---|
/export/kunden | Alle Kunden | 16 |
/export/auftraege | Alle Aufträge + Summen | 12 |
/export/rechnungen | Rechnungen + Verzug | 9 |
/export/material | Lager + Verbrauch | 8 |
/export/mitarbeiter | Personal + Termine | 8 |
/export/backup | Alle 5 als ZIP | — |
LIES_MICH.txt mit Encoding-Hinweisen und Erstellungszeitstempel.
Beispiel — kunden_export.csv
Kunden-ID;Typ;Vorname;Nachname;Firmenname;Ansprechpartner;... 1;privat;Hans;Müller;;;;Ja;[email protected];0201-123456;... 2;firma;;;Beispiel GmbH;Herr Schmidt;DE123456789;Ja;...
Neue Endpoints (Sprint 7)
Jeder Endpoint exportiert die jeweilige Tabelle als UTF-8 CSV-Datei. Der Download startet automatisch im Browser.
# Kunden exportieren: curl http://localhost/api/export/kunden \ -H "X-API-Key: $API_KEY_ADMIN" \ --output kunden_export_20260310.csv # Aufträge exportieren: curl http://localhost/api/export/auftraege \ -H "X-API-Key: $API_KEY_ADMIN" \ --output auftraege_export_20260310.csv
Dateiname: Automatisch mit Datum — z.B. kunden_export_20260310.csv
Generiert alle 5 CSV-Dateien und verpackt sie in einem ZIP-Archiv. Ideal für tägliche Datensicherung.
# Kompletter Backup als ZIP: curl http://localhost/api/export/backup \ -H "X-API-Key: $API_KEY_ADMIN" \ --output handwerkerpro_backup_20260310.zip // ZIP-Inhalt: handwerkerpro_backup_20260310.zip ├── kunden_export_10.03.2026.csv ├── auftraege_export_10.03.2026.csv ├── rechnungen_export_10.03.2026.csv ├── material_export_10.03.2026.csv ├── mitarbeiter_export_10.03.2026.csv └── LIES_MICH.txt
Reporting & Statistiken
Interaktives Dashboard · Chart.js · Umsatzstatistik · Mitarbeiterauslastung · Top Kunden
Dateistruktur
slim-api/ ├── public/ │ └── docs/ │ └── dashboard.html ← Interaktives Reporting-Dashboard └── src/ └── Controllers/ └── ReportingController.php ← 4 neue Endpoints
Technologie
| Chart-Bibliothek | Chart.js 4.4 |
| Diagrammtypen | Bar · Line · Doughnut |
| Berechtigung | alle Rollen |
| Filter | Jahr · Monat · API-Key |
Monat · Trend · Jahrestotal
Monatlich + Vorjahresvergleich
Stunden gestapelt pro Monat
Donut + Tabelle mit Anteil %
Installation
Neue Dateien ins Projekt kopieren
src\Controllers\ReportingController.php → neu anlegen
public\docs\dashboard.html → neu anlegen
public\index.php → bestehende Datei ersetzen (neue Routes)Keine neuen Composer-Pakete nötig. Chart.js wird per CDN geladen.
Dashboard im Browser öffnen
http://localhost/docs/dashboard.html
API-Key und Jahr/Monat oben einstellen → Aktualisieren klicken. Alle Daten kommen live aus der Datenbank.
Neue Endpoints (Sprint 6D)
KPI-Übersicht: Monatswerte, Jahreswerte, Trend ggü. Vormonat und offene Posten.
| Parameter | Typ | Beschreibung | |
|---|---|---|---|
jahr | int | Optional | Jahr (Standard: aktuelles Jahr) |
monat | int | Optional | Monat 1–12 (Standard: aktueller Monat) |
curl "http://localhost/api/reporting/kennzahlen?jahr=2026&monat=3" \
-H "X-API-Key: $API_KEY_ADMIN"Umsatz nach Zeit. Ohne monat: 12 Monatswerte + Vorjahr. Mit monat: Tageswerte für diesen Monat.
# Jahresübersicht mit Vorjahresvergleich: curl "http://localhost/api/reporting/umsatz?jahr=2026" \ -H "X-API-Key: $API_KEY_ADMIN" # Tageswerte März 2026: curl "http://localhost/api/reporting/umsatz?jahr=2026&monat=3" \ -H "X-API-Key: $API_KEY_ADMIN"
Arbeitsstunden pro Mitarbeiter aufgeteilt nach Monat. Ideal für gestapelte Balkendiagramme.
curl "http://localhost/api/reporting/mitarbeiter/auslastung?jahr=2026" \
-H "X-API-Key: $API_KEY_ADMIN"Top Kunden nach Umsatz mit Anteil in Prozent. Max. 50 Einträge.
| Parameter | Typ | Beschreibung | |
|---|---|---|---|
limit | int | Optional | Anzahl Kunden (Standard: 10, max: 50) |
jahr | int | Optional | Jahr (Standard: aktuelles Jahr) |
curl "http://localhost/api/reporting/top-kunden?limit=10&jahr=2026" \
-H "X-API-Key: $API_KEY_ADMIN"Automatisierung
Cronjobs · Backups
Dateistruktur
slim-api/ ├── bin/ ← [NEU] Für PHP-Befehlszeilen-Skripte (CLI) │ └── cron-tasks.php ← neu anlegen ├── scripts/ ← [NEU] Für Python- oder Shell-Skripte │ └── backup.py ← neu anlegen ├── logs/ ← [NEU] Für Fehlerprotokolle ├── backup.log ← Automatisch erstellt (Sicherungsprotokoll) └── cron.log ← Automatisch erstellt (PHP-Jobs-Protokoll)
Technische Spezifikation
| Backup-Archivierung | ZIP-Kompression |
| Aufbewahrungsfrist | 7 Tage Rotation (automatisches Purging) |
| Umgebung | CLI-Modus für PHP & Python |
| Berechtigung | meister+ |
Systembeschreibung
Dieses Skript läuft auf Systemebene und erstellt eine vollständige Kopie der Datenbank mithilfe des mysqldump-Befehls.
Logik des Skripts:
- Datenbankverbindung: Baut eine Verbindung zur MariaDB-Instanz auf.
- SQL-Dump: Erstellt eine .sql-Datei mit einem Zeitstempel im Dateinamen.
- Die Datei wird zur Speicherplatzoptimierung mit gzip komprimiert.
- Backups, die älter als 7 Tage sind, werden automatisch gelöscht, um eine Überfüllung des Speichers zu vermeiden.
Dieses Skript wird unabhängig von der API über das Terminal ausgeführt und nutzt das bestehende Database.php-Modell.
Logik des Skripts:
- Rechnungsprüfung: Rechnungen, deren Fälligkeitsdatum überschritten ist und die sich noch im Status "ausstehend" befinden, werden automatisch auf den Status "überfällig" gesetzt.
- Terminerinnerung: Das System identifiziert Kunden mit Terminen am Folgetag und versendet automatisch Erinnerungs-E-Mails über das in Sprint 6-b implementierte PHPMailer-System.
Cronjob-Einrichtung
Neue Datei ins Projekt kopieren
bin\cron-tasks.php → neu anlegen
scripts\backup.py.php → neu anlegen
slim-api\logs → Neuen Ordner anlegen!!!
Auszuführen
Um diese Skripte zeitgesteuert auszuführen, müssen sie in die crontab eingetragen werden. Öffnen Sie das Terminal, geben Sie crontab -e ein und fügen Sie folgende Zeilen am Ende hinzu:
# Täglich um 02:00 Uhr: Datenbank-Backup (Python)0 2 * * * /usr/bin/python3 /var/www/html/slim-api/scripts/backup.py >> /var/www/html/slim-api/logs/backup.log 2>&1
# Täglich um 08:00 Uhr: Rechnungs- & Termincheck (PHP)0 8 * * * /usr/bin/php /var/www/html/slim-api/bin/cron-tasks.php >> /var/www/html/slim-api/logs/cron.log 2>&1
Wichtige Hinweise zur Beachtung
- Berechtigungen (Permissions): Die Dateien in den Verzeichnissen scripts/ und bin/ müssen ausführbar sein. Führen Sie dazu folgenden Befehl im Terminal aus:
chmod +x /var/www/html/slim-api/scripts/backup.py
- Log-Verzeichnis: Stellen Sie sicher, dass das Verzeichnis /logs/ Schreibrechte besitzt, da andernfalls keine Fehlerprotokolle erstellt werden können.
- Python-Bibliotheken: Falls das Python-Skript zusätzliche Bibliotheken verwendet, müssen diese auf dem Server installiert sein (in der Regel sind die Standard-Bibliotheken ausreichend).