TP2 Abschlussprüfung: Rechtstexte (AVV, 6c, News-LB-Archiv, Livegang-Checkliste)
- AVV Vorbemerkung (2): K16 der Textform-Aktivierung trägt nur Leistungsbeschreibung und AVV als PDF - AVV Nr. 9 Abs. 6, Anlage (Löschung), LB Nr. 8 Abs. 3 und Datenschutz 6c: das Einrichtungs-Ticket bleibt mit einer Kurzfassung der Einstellungen als Arbeitsnachweis (keine Daten von Gästen) - AVV Nr. 8 Abs. 2: "Gastdaten löschen" löscht nur wartende E-Mails; fehlgeschlagene behalten Adresse und Inhalt bis Nr. 9 Abs. 4 - Datenschutz § 7: Frist für Bestellungen ohne Abo (drei Jahre nach Ablauf des Jahres der Bestellung) - News-Leistungsbeschreibung vom 30.09.2026 unverändert archiviert (SHA-256-Pin), die geltende Datei verweist darauf - Kanzlei-Paket: Zitate, Q4/Q9/Q23, Livegang-Checkliste (Abschnitt 7.6/7.7), K23-Hinweis - build-legal-html: Rückwärtsschrägstrich in Navigationsadressen abgelehnt; TP1-Spezifikation E2 (ohne USt) - HTML, PDFs und Prüfsummen neu erzeugt (Terminplaner-Unterlagen und Datenschutzerklärung) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5f99f08a39
commit
bea07e73b1
22 files changed
+299
-33
No files matched your search
@@ -505,6 +505,79 @@ test('paket_konsistenz_abo_ende: LB Nr. 8, AVV Nr. 9, 6c und K22 nennen 30 Tage
|
||||
assert.ok(drei.includes('30 Tage') && drei.includes('Rückkehr') && drei.includes('spätestens am folgenden Tag'))
|
||||
})
|
||||
|
||||
test('paket_checkliste_livegang: Abschnitt 7.6 nennt die Schritte vor, bei und nach dem Deploy in fester Reihenfolge; Skripte, Indizes und Fristen stimmen mit dem Code überein', () => {
|
||||
const sieben = abschnitt(7)
|
||||
const [, ab76] = sieben.split('### 7.6 ')
|
||||
assert.ok(ab76, 'Abschnitt 7.6')
|
||||
const [livegang, nachher] = ab76.split('### 7.7 ')
|
||||
assert.ok(nachher, 'Abschnitt 7.7')
|
||||
const punkte = (text) => text.split('\n').filter((z) => z.startsWith('- [ ] '))
|
||||
const l = punkte(livegang)
|
||||
const folge = [
|
||||
'scripts/termine-setup.mjs', // (a) Schema des Terminplaners vor dem Code-Deploy
|
||||
'scripts/feature-setup.mjs', // (b) Schema der Funktionen vor dem Code-Deploy
|
||||
'scripts/build-legal-pdfs.sh datenschutz', // (c) nur das PDF der Datenschutzerklärung
|
||||
'ruhigen Zeit', // (d) Deploy bei wenig Verkehr
|
||||
'Uploads in WOMS', // Uploads nach dem Deploy
|
||||
'scripts/feature-consent-felder-leeren.mjs', // (f) mit Freigabe des Inhabers
|
||||
'TERMINE_ENABLED=on', // (e) als allerletzter Schritt
|
||||
]
|
||||
assert.equal(l.length, folge.length, 'sieben Schritte')
|
||||
folge.forEach((wort, i) => assert.ok(l[i].includes(wort), `Schritt ${i + 1} nennt „${wort}“: ${l[i].slice(0, 80)}`))
|
||||
assert.ok(l[0].includes('--check') && l[1].includes('--check'), 'beide Schema-Skripte erst mit --check')
|
||||
assert.ok(l[1].includes('Code-Deploy, nicht erst der erste Löschlauf'), '(b) Zeitpunkt: vor dem Code-Deploy')
|
||||
assert.ok(!PAKET.includes('vor dem ersten Löschlauf der Aufbewahrungsfristen ausführen'), 'der alte Zeitpunkt steht nirgends mehr')
|
||||
assert.ok(l[2].includes('nicht mit `all`'), '(c) nicht all')
|
||||
assert.ok(l[3].includes('Fassung der Gästetexte, die der Server beim Speichern hat'), '(d) der Nachweis speichert die Fassung des Servers')
|
||||
assert.ok(l[5].includes('nur mit Freigabe des Inhabers') && l[5].includes('Probelauf') && l[5].includes('--dry-run') && l[5].includes('--apply'), '(f) Probelauf, dann --apply, mit Freigabe')
|
||||
assert.ok(l[6].startsWith('- [ ] Als allerletzten Schritt `TERMINE_ENABLED=on`'), '(e) TERMINE_ENABLED=on zuletzt')
|
||||
assert.ok(sieben.indexOf('TERMINE_ENABLED=on') > sieben.indexOf('scripts/feature-consent-felder-leeren.mjs'), 'on nach allen anderen Schritten')
|
||||
assert.equal(sieben.split('TERMINE_ENABLED=on').length - 1, 1, 'on wird nur an dieser Stelle gesetzt')
|
||||
|
||||
// (a) die genannten Spalten und Indizes stehen im Schema; (b)/(f) die Skripte gibt es und sagen dasselbe wie die Checkliste
|
||||
const schema = lies('server/services/termine/schema.js')
|
||||
assert.match(schema, /str\('fragebogen', 20000\)/)
|
||||
for (const index of ['idx_status_ends', 'idx_status_updated', 'idx_booking']) {
|
||||
assert.ok(schema.includes(`'${index}'`), `${index} im Schema`)
|
||||
assert.ok(l[0].includes(`\`${index}\``), `Schritt 1 nennt ${index}`)
|
||||
}
|
||||
assert.ok(l[0].includes('`fragebogen`') && l[0].includes('`termineConfig`') && l[0].includes('`termineBookings`') && l[0].includes('`termineOutbox`'))
|
||||
assert.match(lies('scripts/feature-setup.mjs'), /Vor dem Code-Deploy ausfuehren/)
|
||||
assert.match(lies('scripts/termine-setup.mjs'), /--check/)
|
||||
const pdfs = lies('scripts/build-legal-pdfs.sh')
|
||||
assert.ok(pdfs.includes('\ndatenschutz)\n') && pdfs.includes('\nall)\n'), 'build-legal-pdfs.sh kennt datenschutz und all')
|
||||
const leeren = lies('scripts/feature-consent-felder-leeren.mjs')
|
||||
assert.ok(leeren.includes('--dry-run') && leeren.includes('--apply') && leeren.includes('Standard ist der Probelauf'))
|
||||
|
||||
// (g) Kunden ohne Abo: der Löschlauf erfasst sie heute nicht, die Datenschutzerklärung nennt die Frist; die erste Frist läuft Ende 2029 ab
|
||||
const g = punkte(nachher)
|
||||
assert.equal(g.length, 1)
|
||||
assert.ok(g[0].includes('31.12.2029') && g[0].includes('`findDueDeletions`') && g[0].includes('ohne Abo'))
|
||||
assert.match(lies('server/services/retention.js'), /Kunden ohne Abo, zum Beispiel nur mit News, sind nie faellig/, 'steht das nicht mehr im Code, ist die Löschung umgesetzt: Punkt 7.7 und Q23 anpassen')
|
||||
assert.ok(mailText('public/datenschutz.html').includes('Bestellen Sie ohne Abo (zum Beispiel nur die News-Pinnwand), löschen wir diese Angaben spätestens drei Jahre nach Ablauf des Jahres der Bestellung.'))
|
||||
assert.ok(abschnitt(4).includes('Für Bestellungen ohne Abo (nur News) nennt die Erklärung eine eigene Frist') && abschnitt(4).includes('(31.12.2029)'))
|
||||
|
||||
// (h) K23 verspricht „unverändert da“; der Löschlauf löscht auch bei abgeschaltetem Terminplaner Termine nach ihren Fristen
|
||||
const vier = punkte(abschnitt(7).split('### 7.4 ')[1].split('### 7.5 ')[0])
|
||||
assert.ok(vier.some((z) => z.includes('K23') && z.includes('unverändert da') && z.includes('abschwächen')), '(h) K23 in 7.4')
|
||||
assert.ok(mailText('server/mail-templates/K23 Terminplaner laeuft wieder.html').includes('Deine Termine und Einstellungen sind unverändert da'))
|
||||
assert.match(lies('server/services/termine/jobs.js'), /portalFeatures featureKey termine, active oder disabled/)
|
||||
|
||||
// 7.5 verweist auf 7.6
|
||||
assert.ok(abschnitt(7).split('### 7.5 ')[1].split('### 7.6 ')[0].includes('Abschnitt 7.6'))
|
||||
})
|
||||
|
||||
test('paket_ausnahme_einrichtungs_ticket_und_archiv: Q4, Q9 und Abschnitt 2.3 nennen das archivierte News-Dokument und die Ausnahme der Löschung', () => {
|
||||
const alle = abschnitt(4)
|
||||
const q4 = alle.split('### Q4: ')[1].split('### Q5: ')[0]
|
||||
assert.ok(q4.includes('`public/vertragsunterlagen/funktionen-leistungsbeschreibung-2026-09-30.html`'))
|
||||
assert.ok(existsSync(new URL('../public/vertragsunterlagen/funktionen-leistungsbeschreibung-2026-09-30.html', import.meta.url)))
|
||||
assert.ok(q4.includes('unveränderte Kopie des Standes 3a0b008') && q4.includes('Prüfsumme'))
|
||||
const q9 = alle.split('### Q9: ')[1].split('### Q10: ')[0]
|
||||
assert.ok(q9.includes('(g) Das Einrichtungs-Ticket') && q9.includes('Leistungsbeschreibung Nr. 8 Abs. 3 und AVV Nr. 9 Abs. 6'))
|
||||
assert.ok(abschnitt(2).split('### 2.3 ')[1].split('### 2.4 ')[0].includes('das Einrichtungs-Ticket des Teams bleibt als Arbeitsnachweis'))
|
||||
})
|
||||
|
||||
// ------------------------------------------------------------------------------------------------ Fragen Q1 bis Q26 (Task F15b)
|
||||
|
||||
const FRAGE_TEILE = ['**Frage.**', '**Fundstelle im Text.**', '**Unsere Annahme.**', '**Alternative.**']
|
||||
|
||||
Reference in new issue
Block a user