From 5824b066f46508b47fc16c28fd0c0ce36b955b89 Mon Sep 17 00:00:00 2001 From: Clemens Creutzburg Date: Tue, 14 Jul 2026 19:01:57 +0200 Subject: [PATCH] Public-Auth-Seiten in Landingpage-Stil integrieren - gemeinsames Public-CSS fuer Landingpage und Auth-Seiten ergaenzen - Login, Registrierung und Passwort-/E-Mail-Seiten vom App-Layout trennen - App-Sidebar von Public-Login- und Registrierungslinks bereinigen - Webspace- und Subdomain-Strategie dokumentieren --- assets/css/public.css | 175 +++++++++++++++++++++++++++++ docs/m3-saas-basis-vorbereitung.md | 14 ++- docs/saas-umstrukturierungsplan.md | 36 +++++- email-verifizieren.php | 77 +++++++++---- footer.php | 5 - landing.php | 128 ++------------------- login.php | 108 +++++++++++------- passwort-vergessen.php | 110 +++++++++++------- passwort-zuruecksetzen.php | 125 +++++++++++++-------- register.php | 127 +++++++++++++-------- 10 files changed, 575 insertions(+), 330 deletions(-) create mode 100644 assets/css/public.css diff --git a/assets/css/public.css b/assets/css/public.css new file mode 100644 index 0000000..d5c8f51 --- /dev/null +++ b/assets/css/public.css @@ -0,0 +1,175 @@ +body.public-page { + background: #ffffff; +} + +.public-shell { + min-height: 100vh; + background: #ffffff; +} + +.public-hero { + min-height: 82vh; + background-image: url("../images/landing-hero.png"); + background-size: cover; + background-position: center right; + position: relative; + display: flex; + align-items: center; + padding: 4rem 6vw; +} + +.public-hero:before { + content: ""; + position: absolute; + inset: 0; + background: rgba(255, 255, 255, 0.68); +} + +.public-nav { + position: absolute; + top: 1.5rem; + left: 6vw; + right: 6vw; + z-index: 2; + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; +} + +.public-nav strong { + color: #3d4449; + font-family: "Roboto Slab", serif; + font-size: 1.1em; +} + +.public-nav strong a { + border-bottom: 0; + color: inherit; +} + +.public-nav .actions { + margin: 0; +} + +.public-hero-content { + position: relative; + max-width: 42rem; +} + +.public-hero h1 { + margin-bottom: 0.35em; +} + +.public-hero p { + color: #3d4449; + font-size: 1.15em; + max-width: 34rem; +} + +.public-section { + padding: 4rem 6vw; +} + +.public-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1.25rem; + max-width: 72rem; +} + +.public-feature, +.public-panel { + border: solid 1px rgba(210, 215, 217, 0.75); + border-radius: 8px; + padding: 1.5rem; + background: #ffffff; +} + +.public-feature h3 { + margin-bottom: 0.5rem; +} + +.public-feature p { + margin-bottom: 0; +} + +.public-auth { + min-height: 100vh; + background-image: url("../images/landing-hero.png"); + background-size: cover; + background-position: center right; + position: relative; + display: flex; + align-items: center; + padding: 6rem 6vw 4rem 6vw; +} + +.public-auth:before { + content: ""; + position: absolute; + inset: 0; + background: rgba(255, 255, 255, 0.72); +} + +.public-auth-grid { + position: relative; + display: grid; + grid-template-columns: minmax(18rem, 0.85fr) minmax(22rem, 1.15fr); + gap: 2rem; + align-items: start; + width: min(72rem, 100%); +} + +.public-auth-copy { + padding-top: 1.25rem; +} + +.public-auth-copy p { + color: #3d4449; + font-size: 1.05em; + max-width: 30rem; +} + +.public-panel { + box-shadow: 0 0.75rem 2.25rem rgba(61, 68, 73, 0.08); +} + +.public-panel h2 { + margin-bottom: 0.5rem; +} + +.public-panel form { + margin-bottom: 0; +} + +.public-panel .actions { + margin-bottom: 0; +} + +@media screen and (max-width: 980px) { + .public-hero { + min-height: 78vh; + padding: 5.5rem 2rem 3rem 2rem; + background-position: center right 30%; + } + + .public-auth { + padding: 5.5rem 2rem 3rem 2rem; + background-position: center right 30%; + } + + .public-nav { + left: 2rem; + right: 2rem; + } + + .public-grid, + .public-auth-grid { + grid-template-columns: 1fr; + } + + .public-section { + padding: 3rem 2rem; + } +} diff --git a/docs/m3-saas-basis-vorbereitung.md b/docs/m3-saas-basis-vorbereitung.md index b4659bf..021295a 100644 --- a/docs/m3-saas-basis-vorbereitung.md +++ b/docs/m3-saas-basis-vorbereitung.md @@ -138,6 +138,7 @@ email-verifikation-senden.php email-verifizieren.php landing.php assets/images/landing-hero.png +assets/css/public.css ``` Umgesetzter Umfang: @@ -153,8 +154,10 @@ Umgesetzter Umfang: - `konto.php` zeigt den aktuellen SaaS-Kontext fuer den angemeldeten User. - `functions.php` akzeptiert eine SaaS-Login-Session als erste Identitaetsquelle, laesst `DEV_AUTH_EMAIL` und `AUTH_USER` aber als Legacy-Fallback bestehen. -- `footer.php` ist fuer nicht angemeldete Public-Seiten sicher und zeigt Links - zu Login und Registrierung. +- `footer.php` bleibt App-Sidebar und zeigt keine Public-Login- oder + Registrierungslinks mehr. +- Login, Registrierung, Passwort-Reset und E-Mail-Verifikation nutzen das + Public-Layout im Stil der Landingpage. - Passwort-Reset erzeugt Single-Use-Tokens und speichert nur Token-Hashes. - E-Mail-Verifikation erzeugt Single-Use-Tokens und setzt `users.email_verified_at`. @@ -176,6 +179,7 @@ Umgesetzte Dateien: ```text landing.php assets/images/landing-hero.png +assets/css/public.css ``` Umgesetzter Umfang: @@ -183,6 +187,8 @@ Umgesetzter Umfang: - Oeffentliche Landingpage ohne Legacy-DB-Zugriff. - Hero mit generiertem Bild-Asset, bestehender Typografie und gruenem Akzent. - CTA zu Login und Registrierung. +- Login, Registrierung und oeffentliche Auth-Hilfsseiten sind optisch in den + Public-Bereich integriert. - Kurzabschnitt zu Stricherfassung, Mandantenfaehigkeit und Webspace-Betrieb. - Die geschuetzte App-Sidebar bleibt von der Public-Seite getrennt. @@ -192,6 +198,8 @@ Entscheidung fuer den Webspace-Betrieb: - Keine Wildcard-Subdomains im ersten Schritt. - Primaere App-Adresse ist eine zentrale App-Domain wie `app.kaffeeliste.de`. +- Die Public-Seite kann ueber `kaffeeliste.de` beziehungsweise + `www.kaffeeliste.de` laufen. - Der aktive Mandant wird nach Login ueber `tenant_memberships` und die PHP- Session gesetzt. - Bei genau einem Mandanten wird automatisch weitergeleitet. @@ -202,6 +210,8 @@ Entscheidung fuer den Webspace-Betrieb: Noch offen: - `APP_PRIMARY_HOST` in der Zielumgebung setzen. +- Optional `APP_PUBLIC_HOST` beziehungsweise Host-Rewrite fuer die Landingpage + in der Zielumgebung definieren. - Produktive Domain-/Zertifikatspruefung fuer einzelne feste Domains definieren. diff --git a/docs/saas-umstrukturierungsplan.md b/docs/saas-umstrukturierungsplan.md index 9ec9dea..b5d1644 100644 --- a/docs/saas-umstrukturierungsplan.md +++ b/docs/saas-umstrukturierungsplan.md @@ -83,9 +83,10 @@ Empfohlene Routen: - `/`: Landingpage. - `/preise` oder spaeter `/pricing`: optional, falls Tarife eingefuehrt werden. - `/faq`: oeffentliche FAQ oder FAQ-Auszug. -- `/registrieren`: Kundenregistrierung. -- `/login`: Login. -- `/passwort-vergessen`: Passwort-Reset. +- `/registrieren` beziehungsweise aktuell `register.php`: Kundenregistrierung. +- `/login` beziehungsweise aktuell `login.php`: Login. +- `/passwort-vergessen` beziehungsweise aktuell `passwort-vergessen.php`: + Passwort-Reset. Landingpage-Inhalte: @@ -121,6 +122,25 @@ Die App sollte eine Sidebar behalten, aber besser gruppiert werden: - Erfassung: Striche, Einzahlungen. - Auswertung: Kaffeeliste, Buchungen, Export. - Administration: Mitglieder, Hinweise, Einstellungen, Importe. +- Konto: Kundenkonto und Logout. Public-Links wie Login und Registrierung + gehoeren nicht in die App-Sidebar. + +### Webspace- und Host-Strategie + +Empfohlen fuer den Start: + +- `kaffeeliste.de` oder `www.kaffeeliste.de` fuer Landingpage, Registrierung + und Login. +- `app.kaffeeliste.de` fuer die geschuetzte App. +- Keine Wildcard-Subdomains fuer Kunden. +- Mandantenauswahl nach Login ueber Session und `tenant_memberships`. +- Kundeneigene feste Domains oder Subdomains erst spaeter gezielt einrichten, + wenn DNS und Zertifikat pro Domain sauber geprueft sind. + +Damit bleibt der Betrieb webspace-tauglich: Fuer den Start reichen zwei feste +Hosts mit normalen Let's-Encrypt-Zertifikaten. Die fachliche Tenant-Aufloesung +ist in M3 vorbereitet; produktive Host-Rewrites, Cookie-Domain und Zertifikats- +Details gehoeren zur M8-Betriebshaertung. ## Datenmodell @@ -287,7 +307,7 @@ Uebersicht: | M4 | Datenmigration | Gestartet: Ledger-Tabelle, Legacy-Backfill, Paritaetscheck und Ledger-Service sind umgesetzt | | M5 | App-Kern | Dashboard, Striche, Einzahlungen, Mitglieder und Liste laufen | | M6 | Betriebsflows | Import, Export, Mail und Jahresprozesse sind auditierbar | -| M7 | Landingpage | Erste werbliche Seite ist oeffentlich nutzbar; spaetere Ausbaustufen folgen | +| M7 | Landingpage | Public-Seite und Auth-Seiten sind im gemeinsamen Stil nutzbar; spaetere Ausbaustufen folgen | | M8 | Haertung | Betrieb, Datenschutz, Monitoring und Isolation sind geprueft | | M9 | Cutover | Produktivumstellung ist vorbereitet und Legacy ist read-only | @@ -427,6 +447,9 @@ Schritte: - Rollenpruefung zentralisieren: erster Owner/Admin-Check erledigt. - Erste Admin-/Owner-Seite fuer Grundeinstellungen: erledigt. - Erste Public-Landingpage mit CTA zu Login und Registrierung: erledigt. +- Login, Registrierung, Passwort-Reset und E-Mail-Verifikation im Public-Stil: + erledigt. +- App-Sidebar ohne Public-Login-/Registrierungslinks: erledigt. Ergebnis: @@ -529,10 +552,13 @@ zu verwischen. Schritte: - Public-Layout mit bestehender Typografie und gruenem Akzent bauen. Erster - Stand als `landing.php` erledigt. + Stand als `landing.php` und `assets/css/public.css` erledigt. - Landingpage-Inhalte erstellen. Erster Stand erledigt. - Demo-Screenshot oder Demo-Ansicht einbinden. - CTA zu Registrierung und Login. Erledigt. +- Login, Registrierung und Passwort-Reset in den Public-Stil integrieren. + Erledigt. +- App-Sidebar von Public-Links trennen. Erledigt. - FAQ-Auszug strukturieren. - Keine App-Sidebar im Public-Bereich. diff --git a/email-verifizieren.php b/email-verifizieren.php index 8c3e268..68cbe5d 100644 --- a/email-verifizieren.php +++ b/email-verifizieren.php @@ -8,31 +8,60 @@ $result = $token !== '' ? saas_verify_email_token($pdo, $token) : ['ok' => false, 'errors' => ['Der Link ist ungueltig oder abgelaufen.']]; -include 'header.php'; -include 'headerline.php'; -include 'nav.php'; ?> - +
+
+

E-Mail verifizieren

+

Bestaetige deine Adresse, damit dein Kundenkonto vollstaendig eingerichtet ist.

+
- +
+

Status

+ + +

Die E-Mail-Adresse wurde bestaetigt.

+ + +
+ +

+ +
+ + +
+
+ + + + + + + + + + diff --git a/footer.php b/footer.php index 33c0e78..2e8b833 100644 --- a/footer.php +++ b/footer.php @@ -54,11 +54,6 @@ if ($saasNavUser !== null) { ?>
  • Logout
  • -
  • Login
  • -
  • Registrierung
  • - diff --git a/landing.php b/landing.php index df5b9c1..06af1a8 100644 --- a/landing.php +++ b/landing.php @@ -5,125 +5,19 @@ - + - -
    -
    - - +
    +
    +

    Passwort zuruecksetzen

    +

    Setze ein neues Passwort fuer dein Kaffeeliste-Konto.

    +
    + +
    +

    Neues Passwort

    + + +

    Das Passwort wurde geaendert.

    + + + +
    + +

    + +
    + +

    Der Link ist ungueltig oder abgelaufen.

    + + + +
    + + +
    +
    + + +
    +
    + + +
    +
    +
      +
    • +
    +
    + + + + +
    +
    +
    +
    + + + + + + + + diff --git a/register.php b/register.php index 4d8c02e..23b0ede 100644 --- a/register.php +++ b/register.php @@ -39,57 +39,86 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $errors = $result['errors']; } -include 'header.php'; -include 'headerline.php'; -include 'nav.php'; ?> - + + + + + + + + +