StiftOS FörderPortal
Vollständiges Benutzerhandbuch für Installation, Konfiguration und täglichen Betrieb des PHP-basierten Förder- und Spendenmanagement-Portals für Stiftungen und gemeinnützige Organisationen.
Das StiftOS FörderPortal ist eine selbst gehostete Webanwendung, die Stiftungen, Bürgerstiftungen und NGOs dabei unterstützt, Förderanträge digital zu verwalten, Spenden zu erfassen und Zuwendungsbestätigungen automatisiert zu erstellen. Das System ist als White-Label-Lösung konzipiert und kann vollständig an das Corporate Design Ihrer Organisation angepasst werden.
1 Installation & Ersteinrichtung
Systemvoraussetzungen
Bevor Sie mit der Installation beginnen, stellen Sie sicher, dass Ihr Server die folgenden Mindestanforderungen erfüllt:
| Komponente | Minimum | Empfohlen | Hinweis |
|---|---|---|---|
| PHP | 8.2 | 8.3 oder 8.4 | Getestet bis PHP 8.5 |
| PHP Extension: pdo_sqlite | Pflicht | – | Für SQLite-Datenbankzugriff |
| PHP Extension: mbstring | Pflicht | – | Multibyte-Zeichenketten |
| PHP Extension: json | Pflicht | – | API & Konfiguration |
| PHP Extension: openssl | Pflicht | – | SMTP-Verschlüsselung, TOTP |
| Webserver | Apache 2.4 + mod_rewrite | – | Oder Nginx mit location-Block |
| Festplatte | 50 MB | 500 MB+ | Wächst mit PDF-Archiv |
| RAM | 128 MB PHP limit | 256 MB+ | PDF-Generierung ist speicherintensiv |
php -m | grep -E "pdo_sqlite|mbstring|json|openssl" auf der Kommandozeile oder über phpinfo() im Browser.Download & Dateistruktur
Nach dem Entpacken des Archivs finden Sie folgende Verzeichnisstruktur im Hauptordner foerderportal/:
foerderportal/
├── index.php # Einziger Einstiegspunkt (Single Entry Point)
├── setup.php # Ersteinrichtungsassistent (danach absichern!)
├── .htaccess # Apache URL-Rewriting + Sicherheitsregeln
├── nginx-security.conf # Nginx-Konfigurationsblock zum Einbinden
│
├── includes/ # PHP-Kernlogik
│ ├── database.php # PDO/SQLite-Singleton mit Hilfsmethoden
│ ├── auth.php # Session-Auth + TOTP 2FA
│ ├── functions.php # XSS-Schutz e(), CSRF, sendSMTPEmail()
│ ├── admin.php # Adminbereich-Controller (~800 Zeilen)
│ ├── frontend.php # Öffentliche Routen
│ ├── pdf_generator.php # Antrags-PDF (FPDF)
│ ├── bescheid_generator.php # Förderbescheid-PDF
│ └── receipt_generator.php # Zuwendungsbestätigung-PDF
│
├── templates/ # PHP-HTML-Templates
│ ├── admin/ # Admin-Oberfläche
│ └── frontend/ # Öffentliche Seiten
│
├── api/
│ └── handler.php # REST-API-Endpunkte
│
├── cron/
│ └── run.php # Cron-Job für E-Mail-Automatisierung
│
├── assets/ # CSS, JS, Bilder
│
├── data/ # Datenbankdatei + Uploads (Schreibrecht nötig!)
│ ├── database.sqlite # SQLite-Datenbank (nach Setup erstellt)
│ ├── logo.png / logo.jpg
│ └── unterschrift_1.png … unterschrift_5.png
│
└── config/
└── config.php # Auto-generiert durch Setup (NICHT einchecken!)
Dateirechte setzen
Die Verzeichnisse config/ und data/ müssen vom Webserver beschreibbar sein. Setzen Sie die Berechtigungen nach dem Upload:
# Verzeichnisse für Webserver-Benutzer schreibbar machen
chmod 755 config/ data/
# Falls nötig: Besitzer auf Webserver-User setzen (z.B. www-data bei Apache/Ubuntu)
chown -R www-data:www-data config/ data/
# Alternativ mit ACL (empfohlen auf Shared Hosting)
setfacl -R -m u:www-data:rwx config/ data/
data/ enthält die gesamte Datenbank und sollte nicht öffentlich zugänglich sein. Stellen Sie sicher, dass Ihr Webserver-Block direkten Zugriff auf /data/ und /config/ verbietet.Setup-Assistent (setup.php)
Der einmalige Setup-Assistent initialisiert die SQLite-Datenbank und legt den ersten Administrator-Account an. Rufen Sie nach dem Upload die folgende URL im Browser auf:
https://ihre-domain.de/setup.php
Der Assistent prüft automatisch alle PHP-Extensions und Dateirechte. Fehlende Voraussetzungen werden rot markiert — beheben Sie diese vor dem Fortfahren.
Das System erstellt die SQLite-Datei unter data/database.sqlite und legt alle Tabellen mit korrektem Schema an. Dieser Vorgang dauert wenige Sekunden.
Geben Sie Benutzername, E-Mail-Adresse und ein sicheres Passwort (min. 12 Zeichen, Groß-/Kleinbuchstaben, Ziffern) für den ersten Admin-Account ein.
Tragen Sie den Namen Ihrer Organisation (site_name), das Kürzel (site_abbrev) und die E-Mail-Adresse für ausgehende Mails ein.
Nach erfolgreichem Abschluss wird setup.php automatisch umbenannt oder gesperrt. Stellen Sie zusätzlich sicher, dass die Datei auf dem Server nicht mehr erreichbar ist (z.B. via .htaccess deny).
setup.php unmittelbar nach der Ersteinrichtung. Eine erneut aufrufbare Setup-Seite auf einem Produktivsystem ist ein kritisches Sicherheitsrisiko.TOTP 2FA einrichten
Beim ersten Login nach dem Setup wird der Administrator automatisch zur Einrichtung der Zwei-Faktor-Authentifizierung (2FA) weitergeleitet. Das System verwendet TOTP (Time-based One-Time Password) nach RFC 6238 – kompatibel mit Google Authenticator, Microsoft Authenticator und allen gängigen TOTP-Apps.
Installieren Sie Google Authenticator (iOS/Android) oder Microsoft Authenticator auf Ihrem Smartphone. Alternativ funktioniert auch Authy oder jede andere TOTP-kompatible App.
Das Portal zeigt einen QR-Code an. Öffnen Sie Ihre Authenticator-App, tippen Sie auf „+" oder „Konto hinzufügen" und scannen Sie den QR-Code. Alternativ können Sie den angezeigten geheimen Schlüssel manuell eingeben.
Geben Sie den aktuell in der App angezeigten 6-stelligen Code ein, um die Einrichtung zu bestätigen. Der Code wechselt alle 30 Sekunden. Das System akzeptiert Codes aus einem Zeitfenster von ±30 Sekunden für Uhrabweichungen.
Notieren Sie den angezeigten geheimen TOTP-Schlüssel an einem sicheren Ort. Bei Verlust des Smartphones ist dieser Schlüssel die einzige Möglichkeit, den Account ohne Datenbankzugriff wiederherzustellen.
totp_secret der Tabelle users gespeichert. Bei Verlust kann ein Datenbankadministrator den Wert auf NULL setzen – beim nächsten Login wird dann ein neues TOTP eingerichtet.Hosting-Konfiguration
Apache VirtualHost
Erstellen Sie eine neue VirtualHost-Konfiguration unter /etc/apache2/sites-available/foerderportal.conf:
<VirtualHost *:443>
ServerName portal.ihre-stiftung.de
DocumentRoot /var/www/foerderportal
<Directory /var/www/foerderportal>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# Zugriff auf sensitive Verzeichnisse sperren
<Directory /var/www/foerderportal/data>
Require all denied
</Directory>
<Directory /var/www/foerderportal/config>
Require all denied
</Directory>
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/portal.ihre-stiftung.de/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/portal.ihre-stiftung.de/privkey.pem
</VirtualHost>
# HTTP → HTTPS Weiterleitung
<VirtualHost *:80>
ServerName portal.ihre-stiftung.de
Redirect permanent / https://portal.ihre-stiftung.de/
</VirtualHost>
Aktivieren Sie den VirtualHost und starten Sie Apache neu:
a2ensite foerderportal.conf
a2enmod rewrite ssl
systemctl restart apache2
Nginx Konfiguration
Binden Sie die mitgelieferte Datei nginx-security.conf in Ihren Server-Block ein:
server {
listen 443 ssl;
server_name portal.ihre-stiftung.de;
root /var/www/foerderportal;
index index.php;
# Sicherheitskonfiguration einbinden
include /var/www/foerderportal/nginx-security.conf;
# URL-Rewriting für Single-Entry-Point
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Sensitive Verzeichnisse sperren
location ~* ^/(data|config)/ {
deny all;
return 403;
}
# PHP-FPM
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
ssl_certificate /etc/letsencrypt/live/portal.ihre-stiftung.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/portal.ihre-stiftung.de/privkey.pem;
}
2 Einstellungen
Die Einstellungen sind im Adminbereich unter Einstellungen in sechs Tabs gegliedert. Alle Werte werden in der Tabelle settings als Schlüssel-Wert-Paare gespeichert und sofort wirksam.
E-Mail & SMTP konfigurieren
Das System versendet E-Mails über SMTP (empfohlen) oder als Fallback über die PHP-Funktion mail(). Konfigurieren Sie SMTP unter Einstellungen → E-Mail:
| Feld | Beispielwert | Beschreibung |
|---|---|---|
| SMTP-Host | smtp.strato.de | Hostname des ausgehenden Mailservers |
| SMTP-Port | 587 | 587 (STARTTLS, empfohlen) oder 465 (SSL) |
| Verschlüsselung | tls | tls für STARTTLS, ssl für direktes SSL |
| SMTP-Benutzername | portal@stiftung.de | Meist identisch mit der Absender-E-Mail |
| SMTP-Passwort | •••••••• | Wird verschlüsselt in der Datenbank gespeichert |
| Absender-E-Mail | portal@stiftung.de | From-Adresse aller ausgehenden E-Mails |
| Absender-Name | Bürgerstiftung Lohne | Anzeigename im E-Mail-Client des Empfängers |
E-Mail-Vorlagen & Platzhalter
Unter Einstellungen → E-Mail-Vorlagen können Sie die automatisch versendeten E-Mails individuell anpassen. Jede Vorlage hat einen Betreff und einen HTML/Text-Körper. Folgende Platzhalter werden beim Versand durch die echten Werte ersetzt:
| Platzhalter | Ersetzt durch | Verfügbar in |
|---|---|---|
{{name}} | Vor- und Nachname des Antragstellers | Alle Vorlagen |
{{vorname}} | Nur Vorname | Alle Vorlagen |
{{nachname}} | Nur Nachname | Alle Vorlagen |
{{organisation}} | Name der antragstellenden Organisation | Alle Vorlagen |
{{projekt}} | Kurzbeschreibung des Projekts | Antrags-Vorlagen |
{{betrag}} | Bewilligter Förderbetrag (formatiert, z.B. „2.500,00 €") | Bewilligungs-Vorlage |
{{antragsnummer}} | Eindeutige Antrags-ID (z.B. DEMO-2025-001234) | Alle Vorlagen |
{{projektstart}} | Geplanter Projektbeginn (formatiert) | Antrags-Vorlagen |
{{projektende}} | Geplantes Projektende (formatiert) | Antrags-Vorlagen |
{{gesamtkosten}} | Gesamtkosten des Projekts | Antrags-Vorlagen |
{{foerderbetrag}} | Beantragter Förderbetrag | Eingangsbestätigung |
Beispiel: Bewilligungsmail
Betreff: Ihr Förderantrag {{antragsnummer}} wurde bewilligt
Sehr geehrte/r {{name}},
wir freuen uns, Ihnen mitteilen zu können, dass Ihr Förderantrag
für das Projekt „{{projekt}}" in unserer Vorstandssitzung positiv
beschieden wurde.
Bewilligter Förderbetrag: {{betrag}}
Antragsnummer: {{antragsnummer}}
Projektzeitraum: {{projektstart}} bis {{projektende}}
Den offiziellen Förderbescheid finden Sie im Anhang dieser E-Mail.
Mit freundlichen Grüßen
Ihr Team der {{organisation}}
Automatisierung & Cron-Jobs
Das System sendet automatische Erinnerungs-E-Mails vor Projektbeginn und nach Projektende. Diese Funktion erfordert einen eingerichteten Cron-Job.
Option 1: Server-Crontab (empfohlen)
# Crontab bearbeiten:
crontab -e
# Täglich um 08:00 Uhr ausführen:
0 8 * * * php /var/www/foerderportal/cron/run.php >> /var/log/foerderportal-cron.log 2>&1
Option 2: Web-Trigger (für Shared Hosting)
Falls kein SSH-Zugriff verfügbar ist, kann der Cron-Job über eine URL ausgelöst werden. Der Sicherheitsschlüssel wird unter Einstellungen → Automatisierung → Cron-Key angezeigt:
GET https://ihre-domain.de/index.php?page=cron&key=IHR_CRON_KEY
Option 3: Manuell über das Dashboard
Unter Dashboard → Automatisierung finden Sie einen Button zum manuellen Auslösen des Cron-Laufs. Dies ist nützlich zum Testen und für ad-hoc Benachrichtigungen.
Dokumente-Tab
Im Reiter Dokumente konfigurieren Sie die Texte und Signaturen für automatisch generierte PDFs:
Förderbescheid-Texte
Passen Sie den Einleitungstext, die Bewilligungsformulierung, Bedingungen und die Schlussformel des Förderbescheids individuell an. Diese Texte werden 1:1 im PDF ausgegeben — Zeilenumbrüche werden berücksichtigt.
Unterschriften hochladen
Das System unterstützt bis zu 5 Unterschriften für Förderbescheide und Zuwendungsbestätigungen. Hochgeladene Bilder werden unter data/unterschrift_1.png bis data/unterschrift_5.png gespeichert.
- Empfohlenes Format: PNG mit transparentem Hintergrund, 300 DPI
- Empfohlene Größe: ca. 400 × 150 Pixel
- Maximale Dateigröße: 2 MB pro Unterschrift
- Zugelassene Formate: PNG, JPG
Integration & API
Unter Einstellungen → Integration verwalten Sie die Schnittstellen zu externen Diensten.
API-Zugangsdaten
Generieren Sie unter diesem Tab einen API-Key und API-Secret für die Nutzung der REST-Schnittstelle. Diese Zugangsdaten werden ausschließlich als HTTP-Header übertragen:
X-API-Key: ihr_api_key
X-API-Secret: ihr_api_secret
?api_key=...) — diese Version des Systems hat diese Sicherheitslücke bereits geschlossen.Rate Limiting
Die API ist auf 60 Anfragen pro Minute pro IP-Adresse begrenzt. Bei Überschreitung antwortet die API mit HTTP 429 (Too Many Requests). Zähler werden in der Tabelle rate_limit gespeichert und minütlich zurückgesetzt.
Design & Branding
Unter Einstellungen → Design passen Sie das Erscheinungsbild des Portals an Ihre Organisation an. Alle Änderungen werden als CSS-Variablen zur Laufzeit injiziert — kein Neustart erforderlich.
| Einstellung | Setting-Key | Beschreibung |
|---|---|---|
| Portal-Name | site_name | Ersetzt „LBS FörderPortal" im gesamten System |
| Tagline | site_tagline | Untertitel auf der öffentlichen Startseite |
| Kürzel | site_abbrev | Kurzes Kürzel für Antragsnummern (z.B. „LBS") |
| Primärfarbe | color_primary | Hauptfarbe (CSS-Variable --primary) |
| Primärfarbe dunkel | color_primary_dark | Dunklere Variante für Header etc. |
| Akzentfarbe | color_accent | Highlights, Buttons, Badges |
| Footer-Text | footer_text | HTML-Fußzeile (Impressum, Datenschutz etc.) |
| Logo | – | Upload: wird als data/logo.png gespeichert |
System & Lizenz
Lizenz aktivieren
Nach dem Lizenzkauf erhalten Sie per E-Mail einen Lizenzschlüssel im Format STIFTOS-XXXX-XXXX-XXXX-XXXX.
Navigieren Sie zu Einstellungen → System → Lizenz und tragen Sie Ihren Schlüssel ein. Klicken Sie auf „Lizenz aktivieren".
Das System kontaktiert den Lizenzserver und bestätigt die Aktivierung. Der Status wird täglich per Cron überprüft. Bei fehlgeschlagener Überprüfung werden bestimmte White-Label-Funktionen gesperrt.
Rollen & Rechte
👑 admin
- Vollzugriff auf alle Funktionen
- Systemkonfiguration & Einstellungen
- Benutzerverwaltung
- Lizenz-Management
- Alle Berichte & Exporte
🏛️ vorstand
- Förderanträge einsehen
- Anträge bewilligen/ablehnen
- Vorstandssitzungen verwalten
- Bescheide erstellen
- Keine Systemeinstellungen
💰 schatzmeister
- Zahlungen erfassen & buchen
- Spendenverwaltung
- Zuwendungsbestätigungen
- Finanzberichte
- Keine Beschlüsse
👁️ beirat
- Nur-Lese-Zugriff
- Anträge einsehen
- Berichte lesen
- Keine Aktionen
- Keine Einstellungen
3 Arbeitsprozesse
Förderanträge – Workflow
Der Lebenszyklus eines Förderantrags durchläuft definierte Status-Stufen. Der aktuelle Status bestimmt, welche Aktionen verfügbar sind und welche E-Mails automatisch versendet werden.
| Status | Anzeige | Bedeutung | Nächste Schritte |
|---|---|---|---|
neu | 🔵 Neu | Antrag eingegangen, noch nicht geprüft | Prüfen, einer Sitzung zuweisen |
in_bearbeitung | 🟡 In Bearbeitung | Prüfung läuft, ggf. Rückfragen | Vorstandssitzung, Bescheid erstellen |
bewilligt | 🟢 Bewilligt | Förderung beschlossen & Bescheid versandt | Zahlung buchen, Projektnachweise sammeln |
abgelehnt | 🔴 Abgelehnt | Antrag abgelehnt, Bescheid versandt | Archivierung |
hinfällig | ⚫ Hinfällig | Antrag hat sich erledigt (z.B. Projektabsage) | Archivierung |
abgebrochen | 🟠 Abgebrochen | Vom Antragsteller zurückgezogen | Archivierung |
Typischer Workflow
Antrag wird über das öffentliche Formular oder die API importiert. Automatische Eingangsbestätigung per E-Mail. Admin erhält Benachrichtigung.
Sachbearbeiter sichtet den Antrag, prüft Vollständigkeit und setzt Status auf „in Bearbeitung". Ggf. Rückfragen an Antragsteller per E-Mail aus dem System.
Antrag wird einer Vorstandssitzung zugewiesen. In der Sitzung wird abgestimmt. Ergebnis und Begründung werden im System dokumentiert.
Förderbescheid (PDF) wird automatisch generiert und per E-Mail an den Antragsteller versandt. Status wechselt zu „bewilligt" oder „abgelehnt".
Nach Projektbeginn wird die Zahlung durch den Schatzmeister gebucht. Der Cron-Job sendet automatische Erinnerungen vor Projektende für Nachweispflichten.
Digitale Signatur (OTP-Link)
Für bestimmte Fördertypen kann eine digitale Bestätigung durch den Antragsteller angefordert werden. Das System versendet einen signierten E-Mail-Link mit einem Einmal-OTP. Nach Klick und Bestätigung wird die Signatur mit Zeitstempel in der Datenbank gespeichert.
Vorstandssitzungen
Vorstandssitzungen bündeln mehrere Förderanträge für gemeinsame Beratung und Beschlussfassung.
Unter Sitzungen → Neue Sitzung tragen Sie Datum, Ort und ggf. eine Beschreibung ein.
Aus der Antragsliste können Anträge mit Status „neu" oder „in_bearbeitung" der Sitzung zugewiesen werden. Mehrfachauswahl möglich.
Für jeden Antrag in der Sitzung wird das Abstimmungsergebnis (bewilligt/abgelehnt/vertagt) und optional eine Begründung erfasst.
Nach Abschluss der Sitzung können alle Bescheide mit einem Klick generiert und per E-Mail versandt werden.
Spendenverwaltung
Das Spendenmodul verwaltet einmalige und wiederkehrende Spenden mit optionalem SEPA-Lastschriftmandat.
Spende erfassen
| Feld | Pflichtfeld | Beschreibung |
|---|---|---|
| Spendername | Ja | Vor- und Nachname oder Organisation |
| E-Mail-Adresse | Für Quittung | Empfänger der Zuwendungsbestätigung |
| Betrag | Ja | In Euro, mit Centangabe (z.B. 150,00) |
| Turnus | Ja | einmalig, monatlich, vierteljaehrlich, jaehrlich |
| Datum | Ja | Datum des Zahlungseingangs |
| Zweck | Nein | Spendenzweck für die Bestätigung |
| SEPA-Mandat | Nein | Mandatsnummer, IBAN, BIC für Lastschrift |
Zahlungen buchen
Wiederkehrende Spenden erzeugen automatisch Zahlungserwartungen (in der Tabelle donation_payments). Der Schatzmeister bucht eingegangene Zahlungen als „bezahlt" und kann ausbleibende Zahlungen als „fehlgeschlagen" markieren.
Zuwendungsbestätigung (Zuwendungsbescheinigung)
Das System generiert steuerlich anerkannte Zuwendungsbestätigungen nach amtlichem Muster als PDF-Dokument.
Wählen Sie eine Spende aus und klicken Sie auf „Zuwendungsbestätigung erstellen". Das System prüft, ob alle Pflichtfelder vorhanden sind.
Das FPDF-Bibliothekssystem generiert das PDF mit amtlichem Muster, Vereinsdaten, Spenderbetrag und Unterschrift. Die Generierung dauert typischerweise <2 Sekunden.
Das PDF wird als Anhang per SMTP an die hinterlegte Spender-E-Mail versandt. Eine Kopie landet im E-Mail-Log. Der Versand wird im Audit-Log protokolliert.
Ein Token-gesicherter Download-Link wird generiert. Der Spender kann die Bestätigung auch über das öffentliche Spendenportal herunterladen. Links sind via SHA256-Token gegen Manipulation geschützt.
Statistiken & Berichte
Das Dashboard bietet interaktive Diagramme über Chart.js:
- Antragsstatistik: Neue Anträge pro Monat, Status-Verteilung, Bewilligungsquote
- Finanzübersicht: Bewilligte Förderbeträge nach Monat/Jahr, Gesamtvolumen
- Spendenstatistik: Spendeneingang nach Turnus und Zeitraum, Neugewinnung vs. Bestandsspender
- E-Mail-Status: Zustellquote, Fehler im E-Mail-Log
4 Technische Referenz
API-Referenz
Die REST-API ermöglicht die Integration mit externen Formularsystemen (FluentForms), Automatisierungsplattformen (z.B. n8n) und eigenen Anwendungen. Die Basis-URL lautet: https://ihre-domain.de/index.php
X-API-Key und X-API-Secret. URL-Parameter für Credentials werden nicht akzeptiert und führen zu einer 401-Antwort.Importiert einen neuen Förderantrag aus FluentForms oder einer anderen Quelle. Erstellt einen neuen Eintrag in der applications-Tabelle mit Status neu.
curl -X POST https://ihre-domain.de/index.php?page=api&action=import \
-H "X-API-Key: ihr_api_key" \
-H "X-API-Secret: ihr_api_secret" \
-H "Content-Type: application/json" \
-d '{
"input_organisation": "Sportverein Musterstadt e.V.",
"first_name": "Maria",
"last_name": "Muster",
"email": "maria@sportverein.de",
"address_line_1": "Sportplatzweg 1",
"city": "Musterstadt",
"zip": "12345",
"description_projekt": "Neubau Jugendraum",
"projektdauer": "2025-04-01",
"projektdauer_1": "2025-09-30",
"numeric_field_gesamtkosten": "15000",
"numeric_field_foerderbetrag": "5000",
"dropdown": "Ja",
"input_text_kontoinhaber": "Sportverein Musterstadt e.V.",
"input_mask_IBAN": "DE89370400440532013000",
"input_mask_bic": "COBADEFFXXX",
"input_text_institut": "Commerzbank"
}'
Erfolgreiche Antwort (HTTP 201):
{
"success": true,
"id": 42,
"antragsnummer": "DEMO-2025-000042",
"message": "Antrag erfolgreich importiert"
}
Gibt den Status eines Antrags zurück. Wird vom öffentlichen Statusportal genutzt. Parameter: id (Antrags-ID) oder antragsnummer.
curl "https://ihre-domain.de/index.php?page=api&action=status&antragsnummer=DEMO-2025-000042"
Listet alle Förderanträge auf. Unterstützt optionale Filter-Parameter: status, year, limit, offset.
curl "https://ihre-domain.de/index.php?page=api&action=applications&status=bewilligt&year=2025" \
-H "X-API-Key: ihr_api_key" \
-H "X-API-Secret: ihr_api_secret"
Empfängt Webhook-Benachrichtigungen für Statusupdates von externen Systemen (z.B. Zahlungsdienstleister). Der Payload enthält antragsnummer und event.
curl -X POST "https://ihre-domain.de/index.php?page=api&action=webhook" \
-H "X-API-Key: ihr_api_key" \
-H "X-API-Secret: ihr_api_secret" \
-H "Content-Type: application/json" \
-d '{"antragsnummer": "DEMO-2025-000042", "event": "payment_confirmed", "amount": 5000}'
Externe Formular- & Webhook-Integration
Die empfohlene Integrationsarchitektur: FluentForms (WordPress) → Automatisierungsplattform (z.B. n8n) (Webhook/HTTP Request Node) → StiftOS API.
Erstellen Sie in FluentForms ein Formular mit allen benötigten Feldern. Verwenden Sie die unten aufgeführten Feldnamen für korrektes Mapping.
Unter Formular → Integrationen → Webhook tragen Sie die Webhook-URL Ihrer Automatisierungsplattform ein. Aktivieren Sie „JSON payload" für alle Felder.
In Ihrem Automatisierungs-Workflow: Webhook-Trigger-Node empfängt die Daten → HTTP-Request-Schritt Ihrer Automatisierungsplattform mappt und sendet die Felder an POST ?page=api&action=import mit den korrekten Headern.
Stellen Sie in Ihrem HTTP-Client sicher, dass die FluentForms-Felder korrekt auf die API-Parameter gemappt sind (siehe Tabelle unten).
| FluentForms Feldname | API Parameter | Pflicht |
|---|---|---|
input_organisation | input_organisation | Ja |
names.first_name | first_name | Ja |
names.last_name | last_name | Ja |
address_1.address_line_1 | address_line_1 | Ja |
address_1.city | city | Ja |
address_1.zip | zip | Ja |
description_projekt | description_projekt | Ja |
projektdauer | projektdauer (Start) | Ja |
projektdauer_1 | projektdauer_1 (Ende) | Ja |
numeric_field_gesamtkosten | numeric_field_gesamtkosten | Ja |
numeric_field_foerderbetrag | numeric_field_foerderbetrag | Ja |
dropdown | dropdown (Bankkonto: Ja/Nein) | Nein |
input_text_kontoinhaber | input_text_kontoinhaber | Nein |
input_mask_IBAN | input_mask_IBAN | Nein |
input_mask_bic | input_mask_bic | Nein |
input_text_institut | input_text_institut | Nein |
| (manuell hinzufügen) | email | Empfohlen |
Cron-Job Referenz
Das Cron-Skript cron/run.php übernimmt folgende Aufgaben:
- Erinnerungs-E-Mails vor Projektbeginn (konfigurierbare Tage vorab)
- Erinnerungs-E-Mails nach Projektende (für Nachweispflichten)
- Lizenz-Revalidierung (tägliche Lizenzprüfung)
- Rate-Limit-Tabelle aufräumen (alte Einträge löschen)
# Manuelle Ausführung (mit Ausgabe)
php /var/www/foerderportal/cron/run.php
# Crontab-Eintrag: täglich 08:00 Uhr, Ausgabe in Logdatei
0 8 * * * php /var/www/foerderportal/cron/run.php >> /var/log/foerderportal.log 2>&1
# Web-Trigger mit Sicherheitsschlüssel (für Shared Hosting)
# GET https://ihre-domain.de/index.php?page=cron&key=SHA256_KEY
PDF-System (FPDF)
Das System nutzt die FPDF-Bibliothek für die PDF-Generierung. FPDF wird beim ersten Bedarf automatisch von fpdf.org heruntergeladen und mit einem SHA-256-Prüfwert verifiziert. Kein manueller Download erforderlich.
| PDF-Typ | Generator-Datei | Route |
|---|---|---|
| Förderantrag | includes/pdf_generator.php | ?page=pdf&action=antrag&token=SHA256 |
| Förderbescheid | includes/bescheid_generator.php | ?page=pdf&action=bescheid&token=SHA256 |
| Zuwendungsbestätigung | includes/receipt_generator.php | ?page=pdf&action=zuwendung&token=SHA256 |
Download-Links werden mit hash_equals() für timing-sicheren SHA256-Token-Vergleich verifiziert. Dies verhindert Timing-Angriffe bei der Token-Validierung.
includes/fpdf/fpdf.php. Prüfen Sie den SHA-256-Hash in pdf_generator.php.Datenbankstruktur
Die SQLite-Datenbank liegt unter data/database.sqlite. Das Schema wird beim Setup automatisch erstellt — es gibt kein separates Migrations-Tooling.
| Tabelle | Primärschlüssel | Zweck | Wichtige Spalten |
|---|---|---|---|
| applications | id |
Kernentität: Förderanträge | antragsnummer, status, email, foerderbetrag, created_at |
| users | id |
Admin-Accounts & Rollen | username, email, role, totp_secret, password_hash |
| meetings | id |
Vorstandssitzungen | title, meeting_date, status, notes |
| donations | id |
Spendenstammdaten | donor_name, amount, turnus, sepa_mandate |
| donation_payments | id |
Einzelne Zahlungsbuchungen | donation_id, amount, due_date, paid_at, status |
| email_log | id |
Alle versendeten E-Mails | recipient, subject, status, error_message, sent_at |
| audit_log | id |
Sicherheits- & Aktions-Protokoll | user_id, action, details, ip_address, created_at |
| settings | key |
Systemkonfiguration (Key-Value) | key, value |
| rate_limit | id |
IP-basiertes Rate-Limiting | ip_address, endpoint, requests, window_start |
Sicherheitsarchitektur
| Mechanismus | Implementierung | Beschreibung |
|---|---|---|
| XSS-Schutz | e() in functions.php | Alle Nutzerausgaben über htmlspecialchars() geleitet. Niemals rohes echo in Templates. |
| CSRF-Schutz | verifyCSRFToken() | Alle POST-Formulare enthalten ein CSRF-Token, das serverseitig validiert wird. |
| SQL Injection | PDO Prepared Statements | Alle Datenbankabfragen ausnahmslos über Parameter-Binding. Kein String-Concatenation in SQL. |
| TOTP 2FA | RFC 6238 TOTP | Pflicht für alle Admin-Logins. Kompatibel mit Google/Microsoft Authenticator. |
| Rate Limiting | rate_limit-Tabelle | 60 Anfragen/Minute pro IP für API-Endpunkte. |
| Token-Validierung | hash_equals() | Timing-sicherer Vergleich bei PDF-Download-Token-Prüfung. |
| API-Credentials | HTTP-Header only | API-Key & Secret ausschließlich via X-API-Key/X-API-Secret Header. |
| Redirect-Sicherheit | Whitelist-Validierung | Weiterleitungsziele aus sicheren Konstanten, nie aus $_SERVER['REQUEST_URI']. |
insert(), update() und delete() in database.php interpolieren Tabellennamen als String. Übergeben Sie daher ausschließlich hartcodierte Tabellennamen-Strings — niemals Benutzereingaben als Tabellennamen.Backup & Wiederherstellung
Das gesamte System lässt sich mit zwei Pfaden vollständig sichern:
# Backup: SQLite-Datenbank + Uploads sichern
DATUM=$(date +%Y%m%d_%H%M%S)
cp /var/www/foerderportal/data/database.sqlite /backup/foerderportal-db-$DATUM.sqlite
tar -czf /backup/foerderportal-data-$DATUM.tar.gz /var/www/foerderportal/data/
# Vollständiges Backup (inkl. Code)
tar -czf /backup/foerderportal-full-$DATUM.tar.gz /var/www/foerderportal/
# Wiederherstellung
cp /backup/foerderportal-db-20250101_080000.sqlite /var/www/foerderportal/data/database.sqlite
chown www-data:www-data /var/www/foerderportal/data/database.sqlite
sqlite3 database.sqlite ".backup /backup/backup.sqlite".Troubleshooting & FAQ
1. Setup.php zeigt „PDO SQLite Extension nicht gefunden"
Ursache: Die PHP-Extension pdo_sqlite ist nicht geladen.
Lösung: Führen Sie php -m | grep pdo_sqlite aus. Falls leer, installieren Sie die Extension: apt install php8.3-sqlite3 (Ubuntu) oder aktivieren Sie extension=pdo_sqlite in der php.ini.
2. E-Mails werden nicht versandt / SMTP-Fehler
Ursache: Falsche SMTP-Einstellungen, Firewall blockiert Port 587, oder SSL-Zertifikat-Problem.
Lösung: Prüfen Sie die Einstellungen über Test-E-Mail senden. Schauen Sie in den E-Mail-Log unter Protokolle → E-Mail für genaue Fehlermeldungen. Stellen Sie sicher, dass Ihr Server ausgehende Verbindungen auf Port 587/465 erlaubt.
3. PDF-Generierung schlägt fehl (Blank Page / Error)
Ursache: FPDF konnte nicht heruntergeladen werden, oder Schreibrecht auf temp-Verzeichnis fehlt.
Lösung: Prüfen Sie, ob allow_url_fopen = On in der php.ini gesetzt ist. Laden Sie FPDF manuell herunter und platzieren Sie es unter includes/fpdf/fpdf.php. Prüfen Sie sys_get_temp_dir() auf Schreibbarkeit.
4. TOTP-Code wird nicht akzeptiert
Ursache: Serverzeit weicht stark von der Smartphone-Zeit ab (TOTP ist zeitbasiert).
Lösung: Synchronisieren Sie die Serverzeit: ntpdate -u pool.ntp.org oder aktivieren Sie systemd-timesyncd. Abweichungen bis ±30 Sekunden werden toleriert.
5. API antwortet mit „401 Unauthorized"
Ursache: API-Key oder Secret fehlt, oder wurde als URL-Parameter statt Header übergeben.
Lösung: Stellen Sie sicher, dass X-API-Key und X-API-Secret als HTTP-Request-Header gesetzt sind. URL-Parameter werden aus Sicherheitsgründen nicht akzeptiert.
6. „403 Forbidden" beim Zugriff auf /data/ oder /config/
Ursache: Diese Verzeichnisse sind bewusst gesperrt — das ist korrekt.
Lösung: Der direkte Webzugriff auf diese Verzeichnisse ist aus Sicherheitsgründen geblockt. Greifen Sie auf die Daten ausschließlich über die Anwendung zu.
7. Cron-Job sendet keine E-Mails
Ursache: PHP-Pfad in der Crontab falsch, oder fehlende Berechtigungen.
Lösung: Testen Sie manuell: php /var/www/foerderportal/cron/run.php. Prüfen Sie den PHP-Pfad mit which php. Führen Sie den Cron-Job als denselben User aus wie den Webserver (z.B. www-data).
8. Datenbank wächst sehr schnell
Ursache: Der E-Mail-Log und Audit-Log akkumulieren über Zeit viele Einträge.
Lösung: Führen Sie regelmäßig sqlite3 data/database.sqlite "DELETE FROM email_log WHERE sent_at < datetime('now', '-365 days')" aus. Komprimieren Sie danach mit VACUUM.
9. „Weiße Seite" nach Update
Ursache: PHP-Fehler bei Syntaxfehler in aktualisierten Dateien, oder fehlende Extension.
Lösung: Aktivieren Sie temporär Fehlerausgabe: display_errors = On in php.ini. Prüfen Sie das PHP-Error-Log (error_log-Pfad in phpinfo). Testen Sie Syntax: php -l includes/admin.php.
10. Lizenzaktivierung schlägt fehl
Ursache: Keine Internetverbindung vom Server, falscher Lizenzschlüssel, oder Lizenz bereits auf anderem Server aktiviert.
Lösung: Prüfen Sie, ob der Server ausgehende HTTPS-Anfragen stellen kann: . Kontaktieren Sie den Support mit Ihrer Bestellnummer, wenn die Lizenz auf einem anderen Server deaktiviert werden soll.
11. Förderantrag aus FluentForms wird nicht importiert
Ursache: Mapping in der Automatisierungsplattform falsch konfiguriert, oder falsche Content-Type-Header.
Lösung: Aktivieren Sie das Execution-Log in Ihrer Automatisierungsplattform (z.B. n8n) und prüfen Sie den genauen Request-Body. Stellen Sie sicher, dass Content-Type: application/json gesetzt ist. Testen Sie mit dem curl-Beispiel aus dieser Dokumentation.
12. .htaccess Fehler / 500 Internal Server Error
Ursache: Apache-Modul mod_rewrite ist nicht aktiviert, oder AllowOverride All fehlt.
Lösung: Aktivieren Sie mod_rewrite: a2enmod rewrite && systemctl restart apache2. Stellen Sie in der VirtualHost-Konfiguration AllowOverride All für das Dokumenten-Verzeichnis sicher.