Files
Webklar-Kundenbereich/server/config.js
T
ClaudeandClaude Opus 5.5 9b563482ff Wartungs-Abo v3: Mindestlaufzeit 12 Monate
- Bedingungen § 8: 12 Monate ab Leistungsbeginn, Kuendigung zum Ende bis
  1 Monat vorher, danach monatlich; Sonderkuendigung bei Geschaeftsaufgabe
  (1 Monat Frist), einvernehmliche Beendigung jederzeit; gilt beidseitig
- Kuendigungslogik computeCancellationDate (Mindestlaufzeit, verpasste
  Frist, Wunschtermin, Geschaeftsaufgabe, Monatsende) + cancelAt gespiegelt
- Stripe-Kundenportal: Kuendigung aus (Stripe kennt keine Mindestlaufzeit)
- Bestellseite, Abo-Karte, Vertragsbestaetigung, Checkout-Text, PDF,
  Leitfaden angepasst; termsVersion 2026-09-25-v3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 17:59:49 +00:00

154 lines
6.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dotenv/config'
/** Einzige erlaubte Datenbank (Ticketsystem). Keine separate Portal-DB mehr. */
export const WOMS_DATABASE_ID = 'woms-database'
const DEPRECATED_DATABASE_IDS = new Set([
'6943bf0e0003291f8c35', // frühere Portal-/Legacy-DB
])
function resolveDatabaseId() {
const fromEnv = (process.env.APPWRITE_DATABASE_ID || '').trim()
if (!fromEnv || fromEnv === WOMS_DATABASE_ID) return WOMS_DATABASE_ID
if (DEPRECATED_DATABASE_IDS.has(fromEnv)) {
console.warn(
`[config] Veraltete APPWRITE_DATABASE_ID "${fromEnv}" – es wird nur ${WOMS_DATABASE_ID} verwendet.`
)
return WOMS_DATABASE_ID
}
console.warn(
`[config] APPWRITE_DATABASE_ID="${fromEnv}" ignoriert – Portal nutzt ausschließlich ${WOMS_DATABASE_ID}.`
)
return WOMS_DATABASE_ID
}
export const config = {
port: Number(process.env.PORT) || 3000,
sessionSecret: process.env.SESSION_SECRET || '',
cookieName: process.env.SESSION_COOKIE_NAME || 'webklar_portal_session',
allowedCustomerStatuses: (process.env.ALLOWED_CUSTOMER_STATUSES || 'active')
.split(',')
.map((s) => s.trim())
.filter(Boolean),
appwrite: {
endpoint: process.env.APPWRITE_ENDPOINT || 'https://ticket.webklar.com/v1',
projectId: process.env.APPWRITE_PROJECT_ID || '6a1058610003c5a13a05',
databaseId: resolveDatabaseId(),
apiKey: process.env.APPWRITE_API_KEY || '',
},
collections: {
customers: process.env.APPWRITE_COLLECTION_CUSTOMERS || 'customers',
customerPortalAccess: process.env.APPWRITE_COLLECTION_CUSTOMER_PORTAL_ACCESS || 'customerPortalAccess',
websiteProjects: process.env.APPWRITE_COLLECTION_WEBSITE_PROJECTS || 'websiteProjects',
portalFeatures: process.env.APPWRITE_COLLECTION_PORTAL_FEATURES || 'portalFeatures',
workorders: process.env.APPWRITE_COLLECTION_WORKORDERS || 'workorders',
worksheets: process.env.APPWRITE_COLLECTION_WORKSHEETS || 'worksheets',
employees: process.env.APPWRITE_COLLECTION_EMPLOYEES || 'employees',
portalMessages: process.env.APPWRITE_COLLECTION_PORTAL_MESSAGES || 'portalMessages',
subscriptions: process.env.APPWRITE_COLLECTION_SUBSCRIPTIONS || 'subscriptions',
hourCredits: process.env.APPWRITE_COLLECTION_HOUR_CREDITS || 'hourCredits',
},
publicBaseUrl: (process.env.PORTAL_PUBLIC_URL || 'https://project.webklar.com').replace(/\/$/, ''),
// Wartungs-Abo (Stripe Billing). Preis/Produkt legt der Server per lookup_key selbst an.
stripe: {
secretKey: process.env.STRIPE_SECRET_KEY || '',
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET || '',
priceLookupKey: process.env.STRIPE_ABO_PRICE_LOOKUP_KEY || 'webklar_wartung_monatlich_5000',
priceAmountCents: 5000,
productName: 'WEBklar Wartungs-Abo',
productDescription:
'Betrieb und Pflege Ihrer Website bzw. Web-Anwendung auf unserem Server in Deutschland (Sicherheitsupdates, SSL, tägliche Datensicherung, Überwachung der Erreichbarkeit), 1 Domain inklusive Verwaltung, 1 E-Mail-Postfach (5 GB) und 1 Stunde Arbeitszeit pro Monat (12 Monate nutzbar). Mindestlaufzeit 12 Monate, danach monatlich kündbar. Gemäß § 19 UStG ohne Umsatzsteuer.',
statementDescriptor: 'WEBKLAR WARTUNG',
productImage: 'https://project.webklar.com/img/wartungs-abo-produkt.png',
// Kleinunternehmer: Pflichthinweis auf jeder Stripe-Rechnung
invoiceFooter:
process.env.STRIPE_INVOICE_FOOTER ||
'Gemäß § 19 UStG wird keine Umsatzsteuer berechnet (Kleinunternehmerregelung). WEBklar GbR, Am Schwimmbad 10, 67722 Winnweiler',
},
abo: {
// Bei jeder Textaenderung an Bedingungen oder Bestellseite hochziehen (wird mit der Zustimmung gespeichert)
termsVersion: '2026-09-25-v3',
// Mindestlaufzeit ab Leistungsbeginn; Kuendigung zum Ende bis 1 Monat vorher, danach monatlich
minTermMonths: 12,
minutesPerMonth: 60,
creditValidityMonths: 12,
usageRoundingMinutes: 15,
withdrawalDays: 14,
// "Beginn nach Ablauf der Widerrufsfrist": 15 Tage Probezeit ohne Leistung und ohne Abbuchung
lateStartTrialDays: 15,
// Pilotbetrieb: nur diese Kunden-E-Mails duerfen bestellen (leer = alle)
pilotEmails: (process.env.ABO_PILOT_EMAILS || '')
.split(',')
.map((s) => s.trim().toLowerCase())
.filter(Boolean),
// Testkonten zahlen nur den Stripe-Mindestbetrag (0,50 €) ueber einen Rabatt auf den echten Preis
testEmails: (process.env.ABO_TEST_EMAILS || '')
.split(',')
.map((s) => s.trim().toLowerCase())
.filter(Boolean),
testCouponId: 'WEBKLAR-TEST-050',
},
smtp: {
host: process.env.SMTP_HOST || '',
port: Number(process.env.SMTP_PORT) || 587,
secure: (process.env.SMTP_SECURE || 'false') === 'true',
user: process.env.SMTP_USERNAME || '',
pass: process.env.SMTP_PASSWORD || '',
from: process.env.SMTP_FROM || process.env.SMTP_USERNAME || '',
},
chatNotify: {
emails: (process.env.CHAT_NOTIFY_EMAILS || 'kenso@webklar.com,andrej@webklar.com')
.split(',')
.map((s) => s.trim())
.filter(Boolean),
throttleMin: Number(process.env.CHAT_NOTIFY_THROTTLE_MIN) || 15,
},
gitea: {
webhookToken: process.env.GITEA_WEBHOOK_TOKEN || '',
baseUrl: process.env.GITEA_BASE_URL || 'https://git.webklar.com',
apiToken: process.env.GITEA_API_TOKEN || '',
templateOwner: process.env.GITEA_TEMPLATE_OWNER || 'knso',
templateRepo: process.env.GITEA_TEMPLATE_REPO || 'webklar-preview-template',
defaultOwner: process.env.GITEA_DEFAULT_OWNER || 'knso',
},
cors: {
allowedOrigins: (process.env.ADMIN_CORS_ORIGINS || 'https://ticket.webklar.com,http://localhost:5173')
.split(',')
.map((s) => s.trim())
.filter(Boolean),
},
preview: {
baseHost: process.env.PREVIEW_BASE_HOST || 'project.webklar.com',
deployRoot: process.env.PREVIEW_DEPLOY_ROOT || '',
traefikDynamicDir: process.env.TRAEFIK_DYNAMIC_DIR || '',
sessionSecret:
process.env.PREVIEW_SESSION_SECRET || process.env.SESSION_SECRET || '',
cookieDomain: process.env.PREVIEW_COOKIE_DOMAIN || '.project.webklar.com',
sessionMaxAge: Number(process.env.PREVIEW_SESSION_MAX_AGE || 60 * 60 * 24 * 7),
},
invoiceNinja: {
url: (process.env.INVOICE_NINJA_URL || 'https://invoice.webklar.com').replace(/\/$/, ''),
apiToken: process.env.INVOICE_NINJA_API_TOKEN || '',
},
}
export function assertServerConfig() {
if (!config.sessionSecret || config.sessionSecret.length < 32) {
console.warn('[config] SESSION_SECRET fehlt oder ist zu kurz (min. 32 Zeichen).')
}
if (!config.appwrite.apiKey) {
console.warn('[config] APPWRITE_API_KEY fehlt – DB-Zugriff und Webhook schlagen fehl.')
}
}