FAQ pro Mandant statt fest codiertem AOK-Inhalt

faq.php zeigte bislang fuer jeden Mandanten denselben, komplett
AOK-spezifischen Inhalt (Kaffeemaschinen-Bedienung, interner
Ansprechpartner) - fuer andere Kunden unbrauchbar und inhaltlich falsch.

- Neue Tabelle faq_entries (tenant-scoped, Soft-Delete, sort_order).
- Migration uebernimmt die bisherigen AOK-Inhalte einmalig als FAQ des
  migrierten Default-Mandanten; andere Mandanten sehen sie nicht.
- Neue Mandanten bekommen bei der Registrierung automatisch eine kurze
  generische Starter-FAQ (faq_seed_default_entries), frei editierbar.
- faq.php: lesbar fuer alle angemeldeten Mitglieder eines Mandanten,
  Anlegen/Bearbeiten/Entfernen auf owner/admin beschraenkt.
- Landingpage verweist nicht mehr auf faq.php (jetzt interner,
  mandantengebundener Inhalt statt oeffentlicher Marketing-Seite).

Live getestet: AOK-Carry-over fuer Default-Mandant, frisch registrierter
Test-Mandant bekam isolierte generische Starter-FAQ, Anlegen mit
HTML-Payload (korrekt escaped), Bearbeiten und Soft-Delete geprueft.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 23:18:09 +02:00
co-authored by Claude Sonnet 5
parent d176619e1d
commit 8b0dcd2c70
7 changed files with 311 additions and 72 deletions
+137 -65
View File
@@ -1,12 +1,14 @@
<?php
include "functions.php";
require_once __DIR__ . "/app/ledger.php";
require_once __DIR__ . "/app/faq.php";
require_once __DIR__ . "/app/audit.php";
app_require_csrf();
include "header.php";
include "headerline.php";
include "nav.php";
?>
@@ -17,74 +19,144 @@ include "nav.php";
<?php
echo "<h2>FAQ - Kaffeeliste</h2>";
echo "<br>";
$pdo = app_db_pdo();
$saasUser = saas_current_user($pdo);
$tenantId = 0;
$hasAccess = false;
$kannVerwalten = false;
if ($saasUser !== null) {
$tenantId = (int)$saasUser['tenant_id'];
$hasAccess = true;
$kannVerwalten = saas_user_has_role(['owner', 'admin'], $saasUser);
}
if (!$hasAccess && $saasUser === null && checkKaffeelisteAccess($conn, $mailadress)) {
$tenant = ledger_fetch_default_tenant($pdo);
if ($tenant !== null) {
$tenantId = (int)$tenant['id'];
$hasAccess = true;
$kannVerwalten = checkKaffeelisteAdmin($conn, $mailadress);
}
}
if (!$hasAccess) {
echo "<h2>Kein Zugriff</h2>";
include "footer.php";
exit;
}
$meldung = null;
$fehler = null;
$bearbeitenId = null;
if ($kannVerwalten && $_SERVER['REQUEST_METHOD'] === 'POST') {
$aktion = $_POST['aktion'] ?? '';
$actorUserId = $saasUser['user_id'] ?? null;
if ($aktion === 'anlegen') {
if (faq_create($pdo, $tenantId, (string)($_POST['question'] ?? ''), (string)($_POST['answer'] ?? ''))) {
app_audit_log($pdo, $tenantId, $actorUserId, 'faq.created', 'faq_entry', null);
$meldung = 'Frage wurde hinzugefügt.';
} else {
$fehler = 'Bitte Frage und Antwort ausfüllen.';
}
} elseif ($aktion === 'bearbeiten') {
$bearbeitenId = (int)($_POST['id'] ?? 0);
} elseif ($aktion === 'speichern') {
$id = (int)($_POST['id'] ?? 0);
if (faq_update($pdo, $tenantId, $id, (string)($_POST['question'] ?? ''), (string)($_POST['answer'] ?? ''))) {
app_audit_log($pdo, $tenantId, $actorUserId, 'faq.updated', 'faq_entry', $id);
$meldung = 'Frage wurde aktualisiert.';
} else {
$fehler = 'Bitte Frage und Antwort ausfüllen.';
$bearbeitenId = $id;
}
} elseif ($aktion === 'loeschen') {
$id = (int)($_POST['id'] ?? 0);
if (faq_soft_delete($pdo, $tenantId, $id)) {
app_audit_log($pdo, $tenantId, $actorUserId, 'faq.deleted', 'faq_entry', $id);
$meldung = 'Frage wurde entfernt.';
}
}
}
$eintraege = faq_fetch_all($pdo, $tenantId);
$bearbeitenEintrag = null;
if ($bearbeitenId !== null) {
foreach ($eintraege as $eintrag) {
if ($eintrag['id'] === $bearbeitenId) {
$bearbeitenEintrag = $eintrag;
break;
}
}
}
?>
<p><b>Wie werde ich Mitglied der Kaffeeliste?</b>
</b></p><p>Neumitglieder können sich einfach in diese Liste eintragen und zahlen aktuell keine Aufnahmegebühr. Es ist keine weitere Rücksprache nötig.
Schon mal ausgetretene Mitglieder können erst nach einem Jahr wiederaufgenommen werden. Die Kaffeeliste behält sich vor Mitglieder von der Liste streichen zu können.
<p><b>Wo finde ich Milch, Zucker und Kaffee?
</b></p><p>Milch findet ihr im Kühlschrank (XXX auf dem Deckel), Zucker und Süßstoff steht neben der Kaffeemaschine. Nachschub findet Ihr im Schrank über der Maschine.
Sollte dort nichts mehr vorhanden sein, schaut bitte auf der Webseite https://kaffeeliste.arge.aok nach ob es einen Hinweis gibt. Sollte kein Hinweis erscheinen, informiert bitte den Ansprechpartner der Kaffeeliste. <br>
Dieser bestellt im Laufe einer Woche die Verbrauchsgüter nach. Sollte dieses nicht ausreichen, dann können in diesem Ausnahmefall auch selbst die Verbrauchsgüter besorgt werden.
Die Unkosten werden gegen Vorlage des Bon (z.B. per Mail) der einreichenden Person auf der Kaffeeliste gutgeschrieben.
<p><b>Welche Arten von Kaffee bekomme ich an der Kaffeemaschine?
</b></p><p>Es gibt für euch nur noch vier Tasten mit jeweils einem Bild.<br>
<b>Espresso</b> Ausgabe von ca. 100ml Kaffee<br>
<b>Coffee</b> Ausgabe von ca. 150ml Kaffee<br>
<b>Hot Water</b> Ausgabe von ca. 200ml warmen Wasser (extra Ausgabe)<br>
<b>Americano</b> Ausgabe von ca. 300ml (150ml Kaffee + 150ml warmes Wasser)<br>
<br>
Eine persönliche Einstellung der Kaffeemenge ist nicht mehr möglich.
Die Stärke muss durch die Menge des Wassers definiert werden.
Alle Kaffeespezialitäten bekommen aktuell ca. 11g Kaffee.
Durch den automatischen Doppelbezug und die verschiedenen Mengen sollten aber die meisten Wünsche erfüllt werden können.
</p>
<p><b>Wie nutze ich die Kaffeemaschine?
</b></p><p>Mit einem Klick auf das jeweilige Symbol bekommt ihr eine Tasse (1 Strich auf der Kaffeeliste).
Mit zweimaligem Drücken auf die jeweilige Taste bekommt ihr zwei Tassen (2 Strich auf der Kaffeeliste).
Läuft das Programm könnt ihr mit einem weiteren Klick auf das jeweilige Symbol den Vorgang vorzeitig beenden.
<p><b>Wie viel kostet ein Kaffee?
</b></p><p>Den aktuellen Preis pro Strich steht immer oben rechts auf der Kaffeeliste. Somit kann ein einfacher Kaffee ein oder auch zwei Striche kosten.
<p><b>Wie erfolgt die Abrechnung?
</b></p><p>Je nach dem was du an der Maschine bezogen hast, machst du die entsprechenden Striche auf der Liste. Also: ein Klick = ein Strich und zwei Klicks = zwei Striche.
Etwa ein Mal im Monat wird die Liste aktualisiert. In diesem Fall bekommst eine E-Mail, wenn du bezahlen musst.
<p><b>Wie kann ich bezahlen?
</b></p><p>Aktuell kann nur per Paypal bezahlt werden. Du erhältst einen entsprechenden Link per Mail.<br>
Bezahle immer über die Freunde Funktion von Paypal. Ansonsten stellen wir 20% des Betrags als Gebühr in Rechnung.
<p><b>Muss ich bei der Bezahlung per PayPal gesondert bestätigen oder jemand benachrichtigen?
</b></p><p>Nein, du musst die Bezahlung nicht gesondert bestätigen. Deine Zahlungen von PayPal werden verrechnet und du siehst dieses auf der nächsten Kaffeeliste. Nach der Verarbeitung deiner Einzahlung bekommst du eine schriftliche Bestätigung per Mail.
<p><b>Ich habe einen negativen Wert auf der Kaffeeliste?
</b></p><p>Ein negativer Betrag in der Spalte "offen" stellen deine Schulden dar. Ein positiver Betrag ist ein Guthaben.
<p><b>Ich habe eine rote Markierung in der Liste. Was bedeutet das?
</b></p><p>Du hast einen höheren offenen Betrag. Bitte bezahle deinen ausstehenden Betrag per PayPal.
<p><b>Ich habe bezahlt und der rote Eintrag in der Liste verschwindet nicht!
</b></p><p>Die Liste wird etwa ein Mal im Monat aktualisiert. Bis zur Aktualisierung der Liste bleibt dein Betrag vom letzten Mal auf der Liste stehen.
<p><b>Was passiert, wenn ich die Striche auf der Liste zu undeutlich oder nicht in Fünferblocks mache?
</b></p><p>Nicht klar erkennbare Stiche führen ohne weitere Vorwarnung zu einer pauschalen Strafe von 10 Strichen bei der Auswertung der Liste. <br>
Sollten die Striche nicht im Quinärsystem - also nach vier Strichen ein Querstrich über diese - (Beispiel: <a href="https://de.wikipedia.org/wiki/Strichliste" >Strichliste</a>) gemacht werden, führt dieses ohne weitere Vorwarnung zu einer pauschalen Strafe von 10 Strichen bei der Auswertung der Liste.
<p><b>Ich habe das Gefühl mein Betrag/Guthaben passt nicht. Was soll ich machen?
</b></p><p>Fehler können leider auch in der Kaffeeliste passieren. Melde dich einfach per Mail und wir schauen uns einmal die Abrechnung an. In der Regel findet sich dann der Fehler oder eine Lösung.
<p><b>Wie erfolgt die Wartung der Maschine?
</b></p><p>Die Wartung der Maschine (Reinigung und Entkalkung) erfolgt etwa einmal im Monaten. Bei jeder Entkalkung findet auch ein Wechsel des Wasserfilters statt.
</p>
<p><b>Wie kann ich mich einbringen?
</b></p><p>Zunächst ist ein freundliches Miteinander wichtig! <br>
Schaut gerne immer mal nach, ob die Verbrauchsmaterialen noch entsprechend vorhanden sind.
Wenn du dich weitere Punkte wie Wartung oder ähnliches kümmern möchtest, melde dich gerne beim Ansprechpartner der Kaffeeliste.
<p><b>Ich habe eine Frage und diese steht hier nicht!
</b></p><p>Dann wenden dich gerne an den Ansprechpartner der Kaffeeliste (kaffeelistesb3@nds.aok.de). Dieser wird dir sicherlich weiterhelfen.
<h2>FAQ - Kaffeeliste</h2>
<?php if ($meldung !== null): ?>
<div class="hint-box success"><p><?php echo saas_html($meldung); ?></p></div>
<?php endif; ?>
<?php if ($fehler !== null): ?>
<div class="hint-box error"><p><?php echo saas_html($fehler); ?></p></div>
<?php endif; ?>
<?php if ($eintraege === []): ?>
<p>Für dieses Team wurden noch keine Fragen hinterlegt.</p>
<?php endif; ?>
<?php foreach ($eintraege as $eintrag): ?>
<div class="faq-entry">
<?php if ($kannVerwalten && $bearbeitenEintrag !== null && $bearbeitenEintrag['id'] === $eintrag['id']): ?>
<form method="post" action="faq.php">
<?php echo app_csrf_field(); ?>
<input type="hidden" name="aktion" value="speichern">
<input type="hidden" name="id" value="<?php echo (int)$eintrag['id']; ?>">
<label>Frage:</label><br>
<input type="text" name="question" value="<?php echo saas_html($eintrag['question']); ?>" required style="width:100%"><br><br>
<label>Antwort:</label><br>
<textarea name="answer" required style="width:100%"><?php echo saas_html($eintrag['answer']); ?></textarea><br><br>
<button type="submit">Speichern</button>
<a href="faq.php" class="button">Abbrechen</a>
</form>
<?php else: ?>
<p><b><?php echo saas_html($eintrag['question']); ?></b></p>
<p><?php echo nl2br(saas_html($eintrag['answer'])); ?></p>
<?php if ($kannVerwalten): ?>
<form method="post" action="faq.php" style="display:inline">
<?php echo app_csrf_field(); ?>
<input type="hidden" name="aktion" value="bearbeiten">
<input type="hidden" name="id" value="<?php echo (int)$eintrag['id']; ?>">
<button type="submit">Bearbeiten</button>
</form>
<form method="post" action="faq.php" style="display:inline" onsubmit="return confirm('Diese Frage wirklich entfernen?');">
<?php echo app_csrf_field(); ?>
<input type="hidden" name="aktion" value="loeschen">
<input type="hidden" name="id" value="<?php echo (int)$eintrag['id']; ?>">
<button type="submit">Entfernen</button>
</form>
<?php endif; ?>
<?php endif; ?>
</div>
<br>
<?php endforeach; ?>
</div>
<?php if ($kannVerwalten): ?>
<h3>Neue Frage hinzufügen</h3>
<form method="post" action="faq.php">
<?php echo app_csrf_field(); ?>
<input type="hidden" name="aktion" value="anlegen">
<label>Frage:</label><br>
<input type="text" name="question" required style="width:100%"><br><br>
<label>Antwort:</label><br>
<textarea name="answer" required style="width:100%"></textarea><br><br>
<button type="submit">Frage hinzufügen</button>
</form>
<?php endif; ?>
</div>
</section>
<?php include "footer.php";
?>
<?php include "footer.php"; ?>