Funktionen: Register config.features mit News- und Termine-Eintrag
config.features (news, termine) als reine Daten in config.js, config.ustHinweis, config.funktionen als Alias mit Gettern auf features.news. Neu featureRegistry.js (featureConfig, featureKeys, featureHaken mit Ueberschreib-Regel, oeffentlicheAnsicht); FEATURE_KEYS, FEATURE_LABELS und DISABLED_MESSAGE in siteFeatures.js kommen aus dem Register, Werte unveraendert. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e2f50407a0
commit
c584d220c8
4 files changed
+512
-13
No files matched your search
+136
-5
@@ -130,6 +130,131 @@ export function resolveEnableBankingApiBase(value) {
|
||||
return ENABLE_BANKING_API_BASE
|
||||
}
|
||||
|
||||
// Pflichthinweis zum Preis (Kleinunternehmer); die Funktionen-Register-Texte und die Preisangaben nutzen ihn
|
||||
const ustHinweis = 'ohne Umsatzsteuer gemäß § 19 UStG'
|
||||
|
||||
const ticketProjektName = (project) => project?.projectName || project?.subdomain || ''
|
||||
|
||||
/**
|
||||
* Register der kaufbaren Funktionen (News-Pinnwand, Terminplaner): Preis, Zustimmungen, Rechtsunterlagen,
|
||||
* Ticket- und Mail-Texte je Funktion; reine Daten, config.js importiert keine Dienste. Die Helfer (featureConfig,
|
||||
* featureHaken, oeffentlicheAnsicht) stehen in server/services/featureRegistry.js. Haken (verfuegbar,
|
||||
* bestellpruefung, unterlagenBereit, belehrung, freischaltbar) gehoeren nicht hierher: wer sie in Tests auf dem
|
||||
* Eintrag setzt, ueberschreibt den Standard aus featureRegistry.js.
|
||||
* ticket.topic(project) liefert den Ticket-Betreff, ticket.details(ctx) den Text des Einrichtungs-Tickets
|
||||
* (ctx = { feature, doc, project, customer }: Register-Eintrag, portalFeatures-, websiteProjects- und Kunden-Dokument).
|
||||
*/
|
||||
const features = {
|
||||
news: {
|
||||
key: 'news',
|
||||
product: 'newsSetup',
|
||||
label: { name: 'News-Pinnwand', kurz: 'News', keine: 'keine News-Pinnwand' },
|
||||
priceLabel: '30 €',
|
||||
setupEstimate: 'meist innerhalb von 1–2 Wochen',
|
||||
// Wortlaut der Zustimmung; wird mit Zeitstempel am Feature-Dokument gespeichert (Widerruf, § 356 Abs. 4 BGB)
|
||||
consent: {
|
||||
version: '2026-09-30',
|
||||
knopf: 'Zahlungspflichtig bestellen · 30 €',
|
||||
items: [
|
||||
{
|
||||
id: 'beginn',
|
||||
haken: true,
|
||||
text: 'Ich verlange ausdrücklich, dass WEBklar vor Ablauf der Widerrufsfrist mit dem Einbau beginnt. Mir ist bekannt, dass mein Widerrufsrecht erlischt, sobald der Einbau vollständig erbracht ist (§ 356 Abs. 4 BGB).',
|
||||
},
|
||||
],
|
||||
},
|
||||
leistungsbeschreibung: { version: '2026-09-30', url: '/vertragsunterlagen/funktionen-leistungsbeschreibung.html' },
|
||||
avv: null,
|
||||
widerruf: null,
|
||||
returnHash: 'news',
|
||||
returnProjekt: false,
|
||||
ticket: {
|
||||
topic: (project) => `News-Pinnwand einbauen – ${ticketProjektName(project)}`.trim(),
|
||||
details: async (ctx) => {
|
||||
const { feature, doc, project } = ctx || {}
|
||||
const siteKey = doc?.siteKey || ''
|
||||
const domain = project?.liveDomain || project?.previewUrl || project?.subdomain || ''
|
||||
return [
|
||||
`Funktion: ${feature?.key || 'news'}`,
|
||||
`Projekt: ${ticketProjektName(project)}`,
|
||||
`Domain: ${domain}`,
|
||||
`siteKey: ${siteKey}`,
|
||||
`Einbau: <div data-webklar-news="${siteKey}"></div> + https://project.webklar.com/embed/news.js`,
|
||||
'Anleitung: docs/funktionen/news-einbau.md (Repo Webklar-Kundenbereich)',
|
||||
].join('\n')
|
||||
},
|
||||
},
|
||||
mails: {
|
||||
funktion: 'News-Pinnwand',
|
||||
formen: { dein: 'Deine News-Pinnwand', nom: 'die News-Pinnwand', akk: 'die News-Pinnwand', gen: 'der News-Pinnwand', pron: 'sie' },
|
||||
knopf: 'Beitrag schreiben',
|
||||
danach: 'Danach kannst Du Beiträge im Portal schreiben.',
|
||||
bereit: 'Du kannst ab sofort Beiträge schreiben, sie erscheinen direkt bei Dir auf der Seite.',
|
||||
preisHinweis: 'brutto, einmalig; die Nutzung ist kostenlos, es läuft kein Abo',
|
||||
anleitung: false,
|
||||
},
|
||||
requiresWartungsAbo: false,
|
||||
ticketFreischaltung: true,
|
||||
disabledMessage:
|
||||
'Die News-Pinnwand wurde für diese Website abgeschaltet. Schreib uns im Chat, wenn du sie wieder möchtest.',
|
||||
orderedConflictMessage: 'Die News-Pinnwand ist für dieses Projekt schon bestellt.',
|
||||
},
|
||||
termine: {
|
||||
key: 'termine',
|
||||
product: 'termineSetup',
|
||||
label: { name: 'Terminplaner', kurz: 'Termine', keine: 'keinen Terminplaner' },
|
||||
priceLabel: '149 €',
|
||||
setupEstimate: 'meist innerhalb von 1–2 Wochen',
|
||||
// Platzhalter bis Block F (Rechtsrunde): Struktur und IDs stehen, Texte und Fassung ersetzt Block F
|
||||
consent: {
|
||||
version: 'ENTWURF-2026-10-03',
|
||||
knopf: 'Zahlungspflichtig bestellen · 149 €',
|
||||
items: [
|
||||
{ id: 'unterlagen', haken: true, text: 'ENTWURF (Block F): Zustimmung zu Leistungsbeschreibung und Auftragsverarbeitungsvertrag (AVV) Terminplaner.' },
|
||||
{ id: 'gesundheit', haken: true, text: 'ENTWURF (Block F): Bestätigung, dass der Terminplaner nicht im Gesundheitsbereich eingesetzt wird.' },
|
||||
{
|
||||
id: 'beginn',
|
||||
haken: true,
|
||||
text: 'ENTWURF (Block F): Ausdrückliches Verlangen, dass vor Ablauf der Widerrufsfrist mit dem Einbau begonnen wird, mit Hinweis auf das Erlöschen des Widerrufsrechts und den Wertersatz.',
|
||||
},
|
||||
{
|
||||
id: 'information',
|
||||
haken: true,
|
||||
text: 'ENTWURF (Block F): Pflichtinformationen zu Leistung, Gesamtpreis, Ende mit dem Wartungs-Abo und Einrichtungsdauer.',
|
||||
},
|
||||
],
|
||||
},
|
||||
leistungsbeschreibung: { version: 'ENTWURF', url: '' },
|
||||
avv: { version: 'ENTWURF', url: '' },
|
||||
widerruf: null,
|
||||
returnHash: 'termine',
|
||||
returnProjekt: true,
|
||||
ticket: {
|
||||
topic: (project) => `Terminplaner einbauen – ${ticketProjektName(project)}`,
|
||||
// Dienst erst beim Aufruf laden: config.js importiert keine Dienste statisch
|
||||
details: async (ctx) => {
|
||||
const { termineTicketDetails } = await import('./services/termine/ticketDetails.js')
|
||||
return termineTicketDetails(ctx)
|
||||
},
|
||||
},
|
||||
mails: {
|
||||
funktion: 'Terminplaner',
|
||||
formen: { dein: 'Dein Terminplaner', nom: 'der Terminplaner', akk: 'den Terminplaner', gen: 'des Terminplaners', pron: 'ihn' },
|
||||
knopf: 'Termine öffnen',
|
||||
// Platzhalter: den Wortlaut schreibt der Inhaber in seiner Mailrunde
|
||||
danach: 'ENTWURF (Mailrunde): Danach kannst Du im Portal Termine und Einstellungen verwalten.',
|
||||
bereit: 'ENTWURF (Mailrunde): Du kannst ab sofort Termine online buchen lassen.',
|
||||
preisHinweis: `einmalig, ${ustHinweis}; der Terminplaner läuft, solange Dein Wartungs-Abo läuft`,
|
||||
anleitung: true,
|
||||
},
|
||||
requiresWartungsAbo: true,
|
||||
ticketFreischaltung: true,
|
||||
disabledMessage: 'Der Terminplaner ist für diese Website abgeschaltet. Schreib uns im Chat, wenn Du ihn wieder möchtest.',
|
||||
orderedConflictMessage: 'Der Terminplaner ist für dieses Projekt schon bestellt.',
|
||||
unavailableMessage: 'Der Terminplaner ist noch nicht verfügbar.',
|
||||
},
|
||||
}
|
||||
|
||||
export const config = {
|
||||
port: Number(process.env.PORT) || 3000,
|
||||
sessionSecret: process.env.SESSION_SECRET || '',
|
||||
@@ -188,12 +313,18 @@ export const config = {
|
||||
products,
|
||||
mailStorage,
|
||||
newsSetup,
|
||||
// Funktionen-Tab (News-Pinnwand): Zeiteinschaetzung auf der Buchungsseite und Wortlaut der Zustimmung,
|
||||
// der mit Zeitstempel am Feature-Dokument gespeichert wird (Widerruf, § 356 Abs. 4 BGB)
|
||||
ustHinweis,
|
||||
// Register der kaufbaren Funktionen (siehe oben)
|
||||
features,
|
||||
// Funktionen-Tab (News-Pinnwand): Alias auf den News-Eintrag des Registers, Zeiteinschaetzung auf der
|
||||
// Buchungsseite und Wortlaut der Zustimmung (die Getter folgen config.features.news zur Laufzeit)
|
||||
funktionen: {
|
||||
setupEstimate: 'meist innerhalb von 1–2 Wochen',
|
||||
consentText:
|
||||
'Ich verlange ausdrücklich, dass WEBklar vor Ablauf der Widerrufsfrist mit dem Einbau beginnt. Mir ist bekannt, dass mein Widerrufsrecht erlischt, sobald der Einbau vollständig erbracht ist (§ 356 Abs. 4 BGB).',
|
||||
get setupEstimate() {
|
||||
return config.features.news.setupEstimate
|
||||
},
|
||||
get consentText() {
|
||||
return config.features.news.consent.items[0].text
|
||||
},
|
||||
},
|
||||
|
||||
// Wartungs-Abo (Stripe Billing). Preis/Produkt legt der Server per lookup_key selbst an.
|
||||
|
||||
Reference in new issue
Block a user