From 49c13dfd801cb685dbc87c1dea49260d9086d5a8 Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Sun, 23 Aug 2026 02:47:01 +0200 Subject: [PATCH] big --- .gitea/workflows/deploy.yml | 6 +- .gitignore | 7 + .gitlab-ci.yml | 7 +- Internal/db/schema.sql | 3 +- Internal/de/PROJECT_CONTEXT.md | 5 +- Internal/de/PROJECT_STRUCTURE.md | 4 + Internal/de/README.md | 1 + Internal/en/PROJECT_CONTEXT.md | 5 +- Internal/en/PROJECT_STRUCTURE.md | 4 + Internal/en/README.md | 1 + README.md | 5 + config/.htaccess | 7 + config/config.php | 6 + config/secrets.local.php.example | 13 ++ partials/landing/account/dashboard.php | 73 +++++++- src/App/AccountPages.php | 75 +++++++- src/App/ListingCatalog.php | 107 ++++++++++- src/App/PlaceProviderLookup.php | 248 +++++++++++++++++++++++++ src/App/SystemSettings.php | 2 + 19 files changed, 555 insertions(+), 24 deletions(-) create mode 100644 .gitignore create mode 100644 config/.htaccess create mode 100644 config/secrets.local.php.example create mode 100644 src/App/PlaceProviderLookup.php diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 577e2ca..d216b84 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -95,6 +95,8 @@ jobs: [ -f "$f" ] && cp "$f" .ci_config_deploy/ done + [ -f "${CONFIG_BASE_DIR}/.htaccess" ] && cp "${CONFIG_BASE_DIR}/.htaccess" .ci_config_deploy/ + cp -R ${CONFIG_ENV_DIR}/. .ci_config_deploy/ echo "🔁 config → ${TARGET_PATH}${CONFIG_BASE_DIR}/" @@ -105,11 +107,11 @@ jobs: set ftp:ssl-protect-data true; set ssl:verify-certificate no; lcd .ci_config_deploy; - mirror -R --delete --exclude .gitkeep ./ ${TARGET_PATH}${CONFIG_BASE_DIR}/; + mirror -R --delete --exclude secrets.local.php --exclude .gitkeep ./ ${TARGET_PATH}${CONFIG_BASE_DIR}/; bye " || exit 1 else echo "⚠️ Config-Deploy übersprungen: ${CONFIG_BASE_DIR} oder ${CONFIG_ENV_DIR} fehlt" fi - echo "✅ Deploy abgeschlossen" \ No newline at end of file + echo "✅ Deploy abgeschlossen" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2b101f8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# Local server secrets +/config/secrets.local.php + +# Local environment files +/.env +/.env.* +!/.env.example diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e812a15..97d46b3 100755 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -90,6 +90,7 @@ deploy:staging: cp "$f" .ci_config_deploy/ fi done + [ -f "${CONFIG_BASE_DIR}/.htaccess" ] && cp "${CONFIG_BASE_DIR}/.htaccess" .ci_config_deploy/ fi if [ -d "${CONFIG_ENV_DIR}" ]; then @@ -104,7 +105,7 @@ deploy:staging: set ftp:ssl-protect-data true; set ssl:verify-certificate no; lcd .ci_config_deploy; - mirror -R --delete --exclude .gitkeep ./ ${TARGET_PATH}${CONFIG_BASE_DIR}/; + mirror -R --delete --exclude secrets.local.php --exclude .gitkeep ./ ${TARGET_PATH}${CONFIG_BASE_DIR}/; bye " || { echo "❌ Upload für gemischtes Config-Verzeichnis fehlgeschlagen."; exit 1; } @@ -197,6 +198,7 @@ deploy:production: cp "$f" .ci_config_deploy/ fi done + [ -f "${CONFIG_BASE_DIR}/.htaccess" ] && cp "${CONFIG_BASE_DIR}/.htaccess" .ci_config_deploy/ fi if [ -d "${CONFIG_ENV_DIR}" ]; then @@ -211,7 +213,7 @@ deploy:production: set ftp:ssl-protect-data true; set ssl:verify-certificate no; lcd .ci_config_deploy; - mirror -R --delete --exclude .gitkeep ./ ${TARGET_PATH}${CONFIG_BASE_DIR}/; + mirror -R --delete --exclude secrets.local.php --exclude .gitkeep ./ ${TARGET_PATH}${CONFIG_BASE_DIR}/; bye " || { echo "❌ Upload für gemischtes Config-Verzeichnis fehlgeschlagen."; exit 1; } @@ -224,4 +226,3 @@ deploy:production: only: - main # when: manual - diff --git a/Internal/db/schema.sql b/Internal/db/schema.sql index 008cce9..0d87348 100755 --- a/Internal/db/schema.sql +++ b/Internal/db/schema.sql @@ -154,9 +154,10 @@ CREATE TABLE listing_places ( place_kind VARCHAR(80) NULL, opening_hours_note TEXT NULL, opening_hours_json LONGTEXT NULL, - provider_hint ENUM('manual','osm','google') NOT NULL DEFAULT 'manual', + provider_hint ENUM('manual','osm','google','azure') NOT NULL DEFAULT 'manual', external_place_id VARCHAR(190) NULL, google_place_id VARCHAR(190) NULL, + provider_links_json LONGTEXT NULL, rating_value DECIMAL(3,2) NULL, rating_count INT UNSIGNED NULL, status ENUM('draft','published','archived') NOT NULL DEFAULT 'published', diff --git a/Internal/de/PROJECT_CONTEXT.md b/Internal/de/PROJECT_CONTEXT.md index 2561be1..3e157d9 100644 --- a/Internal/de/PROJECT_CONTEXT.md +++ b/Internal/de/PROJECT_CONTEXT.md @@ -66,6 +66,7 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter. Kernbereiche sind l - Bestehende gespeicherte Community-Level erhalten diese beiden Rechte im Fallback automatisch ab 750 Punkten, solange sie nicht explizit anders gespeichert wurden. ## Technischer Rahmen +- Externe API-Schlüssel werden ausschließlich über Server-Umgebungsvariablen oder die lokale, nicht versionierte Datei `config/secrets.local.php` außerhalb des Webroots bereitgestellt. - eigener Front-Controller in `public/index.php` - Templates unter `partials/` - Geschäftslogik unter `src/App/` @@ -74,7 +75,9 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter. Kernbereiche sind l ## Neue Ausbaustufe: Termin-/Ort-System - Neue Tabellenbasis: `listing_places`, `listings`, `listing_occurrences`, `listing_prices`, `listing_benefits`, `listing_categories` - Ziel: spätere Unterscheidung zwischen eigenem Event, Partner-Angebot, allgemeinem Ort und redaktionellem Termin -- Google ist noch nicht aktiv integriert; das System wird nur vorbereitend über Settings und Datenfelder darauf ausgelegt +- In der Admin-Freigabe werden aktivierte Ortsanbieter serverseitig parallel durchsucht: OpenStreetMap/Nominatim, Google Places und Azure Maps. Ein Admin wählt einen Treffer gezielt aus; je Ort können Verknüpfungen mehrerer Anbieter gespeichert werden. Google-Gesamtwertung und Bewertungsanzahl werden erst nach der ausgewählten Google-Verknüpfung geladen. +- Die Admin-Ansicht für Orte und Veranstaltungen hat die Unterpunkte `Freigaben`, `Bestehende Ortsbearbeitung` mit Suchfeld und `Fehlende Angaben`. Letzterer filtert veröffentlichte Einträge nach Verknüpfungen, die bei mindestens einem aktuell aktivierten Anbieter fehlen. +- Eine manuelle Admin-Suche überträgt Name und Adressdaten des offenen Eintrags an die aktivierten Ortsanbieter; Datenschutz- und Consent-Hinweise müssen vor dem produktiven Aktivieren geprüft werden. ## Vorgemerkte To-dos - Kalender-Integration großer Anbieter soll später zusätzlich zum ICS-Feed kommen, zuerst vor allem für Google und Microsoft/Outlook. diff --git a/Internal/de/PROJECT_STRUCTURE.md b/Internal/de/PROJECT_STRUCTURE.md index 1c5cf1d..547ef59 100644 --- a/Internal/de/PROJECT_STRUCTURE.md +++ b/Internal/de/PROJECT_STRUCTURE.md @@ -4,6 +4,8 @@ Stand: 2026-08-10 ## Projektordner - `config/`: Konfigurationen, inklusive `prod/` und `staging/` +- `config/secrets.local.php`: lokale, nicht versionierte Server-Geheimnisse außerhalb des Webroots; Vorlage: `config/secrets.local.php.example` +- `config/.htaccess`: zusätzliche Webserver-Sperre für den gesamten Konfigurationsordner; beide Deployment-Workflows schließen `secrets.local.php` explizit vom synchronisierenden Löschen aus. - `partials/`: Templates, aufgeteilt in `landing/` und `structure/` - `public/`: Webroot mit Assets und Seiten-Entry-Points - `src/`: Backend-/Business-Logik und Kernklassen @@ -30,6 +32,8 @@ Stand: 2026-08-10 - Preis-, Bild- und Ortseingabe für Orte und Veranstaltungen sowie reduzierte Event-Maske: `partials/landing/account/dashboard.php` plus Speicherung in `src/App/ListingCatalog.php` - Freigaben sowie Änderungs- und Löschanfragen für Orte und Veranstaltungen: `src/App/ListingCatalog.php`, `src/App/AccountPages.php`, `partials/landing/account/dashboard.php` - Direktbearbeitung noch nicht veröffentlichter Orts- und Veranstaltungsvorschläge sowie Rechteauflösung für deren Freigabe: `src/App/CommunityAccess.php`, `src/App/AccountPages.php`, `src/App/ListingCatalog.php`, `partials/landing/account/dashboard.php` +- Server-seitige Ortsanbieter-Suche und sichere Trefferauswahl für die Admin-Freigabe: `src/App/PlaceProviderLookup.php`, `src/App/AccountPages.php`, `src/App/ListingCatalog.php`, `partials/landing/account/dashboard.php` +- Admin-Listen für bestehende Ortsbearbeitung und fehlende Anbieter-Verknüpfungen: `src/App/ListingCatalog.php`, `src/App/AccountPages.php`, `partials/landing/account/dashboard.php` - Rollenvergabe per Benutzersuche im User Management: `src/App/AccountPages.php`, `partials/landing/account/dashboard.php`, `src/App/CommunityAccess.php` - Legacy-Eigen-Events wurden erweitert in `src/App/AccountPages.php` und `Internal/db/schema.sql` um Kategorie- und Bildfelder - Kategorien-Prüfung und Zusammenführung für Seiten-Admins liegen ebenfalls in `partials/landing/account/dashboard.php` mit Logik in `src/App/ListingCatalog.php` diff --git a/Internal/de/README.md b/Internal/de/README.md index 202a584..40910e9 100644 --- a/Internal/de/README.md +++ b/Internal/de/README.md @@ -51,6 +51,7 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter mit Fokus auf lokale - neue Basisklassen: `src/App/SystemSettings.php`, `src/App/ListingCatalog.php` ## Datenschutz und Sicherheit +- Server-Geheimnisse können lokal über `config/secrets.local.php` außerhalb des Webroots geladen werden; die Datei wird nicht versioniert und bei Deployments nicht gelöscht. - Passwort-Hashes über Argon2id - Konto-E-Mails verschlüsselt plus separater HMAC-Lookup-Hash - persönliche Kalender-Feed-Tokens verschlüsselt plus separater SHA-256-Lookup-Hash diff --git a/Internal/en/PROJECT_CONTEXT.md b/Internal/en/PROJECT_CONTEXT.md index a754387..b3727f8 100644 --- a/Internal/en/PROJECT_CONTEXT.md +++ b/Internal/en/PROJECT_CONTEXT.md @@ -66,6 +66,7 @@ Papa-Kind-Treff is a PHP-based platform for fathers. Core areas are local events - Existing stored community levels receive these two rights automatically in the fallback from 750 points upward, unless they were explicitly saved differently. ## Technical Frame +- External API keys are provided only through server environment variables or the local, unversioned `config/secrets.local.php` file outside the webroot. - custom front controller in `public/index.php` - templates under `partials/` - business logic under `src/App/` @@ -74,7 +75,9 @@ Papa-Kind-Treff is a PHP-based platform for fathers. Core areas are local events ## New Expansion Stage: Listings and Places - New table base: `listing_places`, `listings`, `listing_occurrences`, `listing_prices`, `listing_benefits`, `listing_categories` - Goal: later distinguish between own event, partner offer, general place, and editorial event entry -- Google is not integrated productively yet; the system is only being prepared for it via settings and data fields +- In admin approvals, enabled place providers are searched server-side in parallel: OpenStreetMap/Nominatim, Google Places, and Azure Maps. An admin deliberately selects a match; links to multiple providers can be saved for one place. Google aggregate rating and rating count are loaded only after the selected Google link. +- The admin view for places and events has the sub-items `Approvals`, `Existing place editing` with a search field, and `Missing information`. The latter filters published entries by links missing from at least one currently enabled provider. +- A manual admin lookup sends the open entry's name and address data to enabled place providers; privacy and consent notices must be reviewed before enabling this in production. ## Deferred To-dos - Large calendar-provider integrations should be added later in addition to the ICS feed, starting primarily with Google and Microsoft/Outlook. diff --git a/Internal/en/PROJECT_STRUCTURE.md b/Internal/en/PROJECT_STRUCTURE.md index 8adb2a4..a94a0dc 100644 --- a/Internal/en/PROJECT_STRUCTURE.md +++ b/Internal/en/PROJECT_STRUCTURE.md @@ -4,6 +4,8 @@ Updated: 2026-08-10 ## Main Directories - `config/`: configuration, including `prod/` and `staging/` +- `config/secrets.local.php`: local, unversioned server secrets outside the webroot; template: `config/secrets.local.php.example` +- `config/.htaccess`: additional web-server protection for the entire configuration directory; both deployment workflows explicitly exclude `secrets.local.php` from synchronizing deletion. - `partials/`: templates split into `landing/` and `structure/` - `public/`: webroot, assets, and page entry points - `src/`: backend and business logic @@ -30,6 +32,8 @@ Updated: 2026-08-10 - pricing, image upload, and place/address input for places and event-style entries plus a reduced own-event form: `partials/landing/account/dashboard.php` with persistence in `src/App/ListingCatalog.php` - approvals as well as change and deletion requests for places and event-style entries: `src/App/ListingCatalog.php`, `src/App/AccountPages.php`, `partials/landing/account/dashboard.php` - direct editing for not-yet-published place and event-style suggestions plus approval-right resolution: `src/App/CommunityAccess.php`, `src/App/AccountPages.php`, `src/App/ListingCatalog.php`, `partials/landing/account/dashboard.php` +- server-side place-provider lookup and secure match selection for admin approvals: `src/App/PlaceProviderLookup.php`, `src/App/AccountPages.php`, `src/App/ListingCatalog.php`, `partials/landing/account/dashboard.php` +- admin lists for existing place editing and missing provider links: `src/App/ListingCatalog.php`, `src/App/AccountPages.php`, `partials/landing/account/dashboard.php` - role assignment via user search in User Management: `src/App/AccountPages.php`, `partials/landing/account/dashboard.php`, `src/App/CommunityAccess.php` - legacy own events were extended in `src/App/AccountPages.php` and `Internal/db/schema.sql` with category and image fields diff --git a/Internal/en/README.md b/Internal/en/README.md index c9e4f83..d7b1b4c 100644 --- a/Internal/en/README.md +++ b/Internal/en/README.md @@ -50,6 +50,7 @@ Papa-Kind-Treff is a PHP-based platform for fathers focused on local events, app - new base classes: `src/App/SystemSettings.php`, `src/App/ListingCatalog.php` ## Privacy and Security +- Server secrets can be loaded locally through `config/secrets.local.php` outside the webroot; the file is not versioned and is not deleted by deployments. - password hashes via Argon2id - account emails are encrypted and additionally addressed through a separate HMAC lookup hash - personal calendar-feed tokens are stored encrypted and additionally resolved through a separate SHA-256 lookup hash diff --git a/README.md b/README.md index 1f08ba9..dafd991 100644 --- a/README.md +++ b/README.md @@ -67,10 +67,15 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter mit Fokus auf: - Im Mitgliederbereich `Events` gibt es jetzt zusätzlich einen ICS-Download und einen persönlichen abonnierbaren Kalender-Feed für alle eigenen Events und Event-Teilnahmen - Der Bereich `Events` ist im Mitgliederbereich jetzt zusätzlich in die Tabs `Meine Events`, `Kalendersynchronisation` und `Abgelaufene Events` gegliedert - Vorschläge für neue Orte und Veranstaltungen werden schon vor der Freigabe als mögliche Ortsauswahl für Events berücksichtigt, solange sie nicht abgelehnt oder archiviert wurden +- In der Admin-Freigabe können berechtigte Nutzer offene Orte und Veranstaltungen serverseitig bei aktivierten Anbietern (OpenStreetMap, Google Places, Azure Maps) suchen und einen Treffer gezielt verknüpfen; Google-Gesamtwertung und Bewertungsanzahl werden erst nach einer bewussten Google-Verknüpfung geladen. +- Die Admin-Ansicht für Orte und Veranstaltungen gliedert sich in `Freigaben`, `Bestehende Ortsbearbeitung` mit Suchfeld und `Fehlende Angaben`; Letztere listet veröffentlichte Einträge ohne Verknüpfung zu mindestens einem aktuell aktivierten Anbieter. - Für später vorgemerkt: direkte Kalender-Anbindung großer Anbieter wie Google und Microsoft/Outlook per OAuth, zusätzlich zum bestehenden ICS-Feed - Interne Projektdateien und das Datenbankschema liegen nicht mehr im Root, sondern unter `Internal/` ## Datenschutz und Sicherheit +- Server-Geheimnisse werden optional aus `config/secrets.local.php` außerhalb des Webroots geladen; die Datei ist lokal, wird nicht versioniert und bei Deployments nicht gelöscht. +- Schlüssel für Ortsanbieter bleiben ausschließlich serverseitig. Die Auswahl von Suchtreffern erfolgt über kurzzeitig in der Server-Session abgelegte Treffer, nicht über vom Browser übermittelte Provider-IDs. +- Das Aktivieren von Ortsanbietern muss mit den Datenschutz- und Consent-Hinweisen abgeglichen werden, weil eine manuelle Admin-Suche Name und Adressdaten eines offenen Eintrags an den gewählten Anbieter überträgt. - sensible Profilfelder werden app-seitig verschlüsselt gespeichert - Konto-E-Mails werden verschlüsselt gespeichert und zusätzlich über einen separaten HMAC-Lookup-Hash adressiert - persönliche Kalender-Feed-Tokens werden verschlüsselt gespeichert und zusätzlich über einen separaten SHA-256-Lookup-Hash adressiert diff --git a/config/.htaccess b/config/.htaccess new file mode 100644 index 0000000..40ec0c6 --- /dev/null +++ b/config/.htaccess @@ -0,0 +1,7 @@ + + Require all denied + + + + Deny from all + diff --git a/config/config.php b/config/config.php index cdc97a2..fbc6d87 100755 --- a/config/config.php +++ b/config/config.php @@ -1,6 +1,12 @@
- +