Files
breakpilot-lehrer/website/lib/content.ts
Benjamin Boenisch 5a31f52310 Initial commit: breakpilot-lehrer - Lehrer KI Platform
Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website,
Klausur-Service, School-Service, Voice-Service, Geo-Service,
BreakPilot Drive, Agent-Core

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:47:26 +01:00

285 lines
8.6 KiB
TypeScript

/**
* Website Content Management (Server-only)
*
* Laedt Website-Texte aus JSON-Dateien.
* Admin kann Texte ueber /admin bearbeiten.
*
* WICHTIG: Diese Datei darf nur in Server Components verwendet werden!
* Fuer Client Components verwende @/lib/content-types
*/
import { readFileSync, writeFileSync, existsSync, mkdirSync, accessSync, constants } from 'fs'
import { join, dirname } from 'path'
// Re-export types from content-types for backward compatibility
export type {
HeroContent,
FeatureContent,
FAQItem,
PricingPlan,
WebsiteContent,
} from './content-types'
import type { WebsiteContent } from './content-types'
// Content-Verzeichnis - nutze Umgebungsvariable oder relativen Pfad
function getContentDir(): string {
// Prüfe Umgebungsvariable zuerst
if (process.env.CONTENT_DIR) {
return process.env.CONTENT_DIR
}
// Versuche verschiedene mögliche Pfade
const possiblePaths = [
join(process.cwd(), 'content'), // Standard: CWD/content
join(process.cwd(), 'website', 'content'), // Falls CWD das Projekt-Root ist
'/app/content', // Docker-Container
join(dirname(__filename), '..', 'content'), // Relativ zu dieser Datei
]
// Prüfe ob einer der Pfade existiert und beschreibbar ist
for (const path of possiblePaths) {
try {
if (existsSync(path)) {
accessSync(path, constants.W_OK)
return path
}
} catch {
// Pfad nicht beschreibbar, versuche nächsten
}
}
// Fallback: Erstelle im CWD
const fallbackPath = join(process.cwd(), 'content')
try {
mkdirSync(fallbackPath, { recursive: true, mode: 0o755 })
console.log(`[Content] Created content directory at: ${fallbackPath}`)
} catch (err) {
console.error(`[Content] Failed to create content directory: ${err}`)
}
return fallbackPath
}
const CONTENT_DIR = getContentDir()
// Default Content
const defaultContent: WebsiteContent = {
hero: {
badge: 'Entwickelt fuer deutsche Lehrkraefte',
title: 'Korrigieren Sie',
titleHighlight1: 'schneller',
titleHighlight2: 'besser',
subtitle: 'BreakPilot unterstuetzt Lehrkraefte mit intelligenter KI bei der Bewertung von Aufgaben. Sparen Sie bis zu 50% Ihrer Korrekturzeit und geben Sie besseres Feedback.',
ctaPrimary: '7 Tage kostenlos testen',
ctaSecondary: 'Mehr erfahren',
ctaHint: 'Keine Kreditkarte fuer den Start erforderlich',
},
features: [
{
id: 'ai-correction',
icon: '✍️',
title: 'KI-gestuetzte Korrektur',
description: 'Intelligente Analyse von Schuelerantworten mit Verbesserungsvorschlaegen und automatischer Bewertung nach Ihren Kriterien.',
},
{
id: 'templates',
icon: '📋',
title: 'Dokumentvorlagen',
description: 'Erstellen und verwalten Sie Ihre eigenen Arbeitsblatt-Vorlagen. Wiederverwendbar fuer verschiedene Klassen und Jahrgaenge.',
},
{
id: 'analytics',
icon: '📊',
title: 'Fortschrittsanalyse',
description: 'Verfolgen Sie die Entwicklung Ihrer Schueler ueber Zeit. Erkennen Sie Staerken und Schwaechen fruehzeitig.',
},
{
id: 'gdpr',
icon: '🔒',
title: 'DSGVO-konform',
description: 'Hosting in Deutschland, volle Datenschutzkonformitaet. Ihre Daten und die Ihrer Schueler sind sicher.',
},
{
id: 'team',
icon: '👥',
title: 'Team-Funktionen',
description: 'Arbeiten Sie im Fachbereich zusammen. Teilen Sie Vorlagen, Bewertungskriterien und Best Practices.',
},
{
id: 'mobile',
icon: '📱',
title: 'Ueberall verfuegbar',
description: 'Browserbasiert und responsive. Funktioniert auf Desktop, Tablet und Smartphone - ohne Installation.',
},
],
faq: [
{
question: 'Was ist bei Breakpilot eine „Aufgabe"?',
answer: [
'Eine Aufgabe ist ein abgeschlossener Arbeitsauftrag, den du mit Breakpilot erledigst.',
'Typische Beispiele:',
'• eine Klassenarbeit korrigieren (egal wie viele Seiten)',
'• mehrere Klassenarbeiten in einer Serie korrigieren',
'• einen Elternbrief erstellen',
'Wichtig: Die Anzahl der Seiten, Dateien oder Uploads spielt dabei keine Rolle.',
],
},
{
question: 'Kann ich Breakpilot kostenlos testen?',
answer: [
'Ja.',
'• Du kannst Breakpilot 7 Tage kostenlos testen',
'• Dafuer ist eine Kreditkarte erforderlich',
'• Wenn du innerhalb der Testphase kuendigst, entstehen keine Kosten',
],
},
{
question: 'Werden meine Daten fuer KI-Training verwendet?',
answer: [
'Nein.',
'• Deine Inhalte werden nicht fuer das Training oeffentlicher KI-Modelle genutzt',
'• Die Verarbeitung erfolgt DSGVO-konform',
'• Deine Daten bleiben unter deiner Kontrolle',
],
},
{
question: 'Kann ich meinen Tarif jederzeit aendern oder kuendigen?',
answer: [
'Ja.',
'• Upgrades sind jederzeit moeglich',
'• Downgrades greifen zum naechsten Abrechnungszeitraum',
'• Kuendigungen sind jederzeit moeglich',
],
},
],
pricing: [
{
id: 'basic',
name: 'Basic',
description: 'Perfekt fuer den Einstieg',
price: 9.90,
currency: 'EUR',
interval: 'Monat',
features: {
tasks: '30 Aufgaben',
taskDescription: 'pro Monat',
included: [
'KI-gestuetzte Korrektur',
'Basis-Dokumentvorlagen',
'E-Mail Support',
],
},
},
{
id: 'standard',
name: 'Standard',
description: 'Fuer regelmaessige Nutzer',
price: 19.90,
currency: 'EUR',
interval: 'Monat',
popular: true,
features: {
tasks: '100 Aufgaben',
taskDescription: 'pro Monat',
included: [
'Alles aus Basic',
'Eigene Vorlagen erstellen',
'Batch-Verarbeitung',
'Bis zu 3 Teammitglieder',
'Prioritaets-Support',
],
},
},
{
id: 'premium',
name: 'Premium',
description: 'Sorglos-Tarif fuer Vielnutzer',
price: 39.90,
currency: 'EUR',
interval: 'Monat',
features: {
tasks: 'Unbegrenzt',
taskDescription: 'Fair Use',
included: [
'Alles aus Standard',
'Unbegrenzte Aufgaben (Fair Use)',
'Bis zu 10 Teammitglieder',
'Admin-Panel & Audit-Log',
'API-Zugang',
'Eigenes Branding',
'Dedizierter Support',
],
},
},
],
trust: {
item1: { value: 'DSGVO', label: 'Konform & sicher' },
item2: { value: '7 Tage', label: 'Kostenlos testen' },
item3: { value: '100%', label: 'Made in Germany' },
},
testimonial: {
quote: 'BreakPilot hat meine Korrekturzeit halbiert. Ich habe endlich wieder Zeit fuer das Wesentliche: meine Schueler.',
author: 'Maria S.',
role: 'Deutschlehrerin, Gymnasium',
},
}
/**
* Laedt Content aus JSON-Datei oder gibt Default zurueck
*/
export function getContent(): WebsiteContent {
const contentPath = join(CONTENT_DIR, 'website.json')
try {
if (existsSync(contentPath)) {
const fileContent = readFileSync(contentPath, 'utf-8')
return JSON.parse(fileContent) as WebsiteContent
}
} catch (error) {
console.error('Error loading content:', error)
}
return defaultContent
}
/**
* Speichert Content in JSON-Datei
* @returns Objekt mit success-Status und optionaler Fehlermeldung
*/
export function saveContent(content: WebsiteContent): { success: boolean; error?: string } {
const contentPath = join(CONTENT_DIR, 'website.json')
try {
// Stelle sicher, dass Verzeichnis existiert
if (!existsSync(CONTENT_DIR)) {
console.log(`[Content] Creating directory: ${CONTENT_DIR}`)
mkdirSync(CONTENT_DIR, { recursive: true, mode: 0o755 })
}
// Prüfe Schreibrechte
try {
accessSync(CONTENT_DIR, constants.W_OK)
} catch {
const error = `Verzeichnis nicht beschreibbar: ${CONTENT_DIR}`
console.error(`[Content] ${error}`)
return { success: false, error }
}
// Schreibe Datei
writeFileSync(contentPath, JSON.stringify(content, null, 2), 'utf-8')
console.log(`[Content] Saved successfully to: ${contentPath}`)
return { success: true }
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler'
console.error(`[Content] Error saving: ${errorMessage}`)
return { success: false, error: errorMessage }
}
}
/**
* Gibt Default Content zurueck (fuer Reset)
*/
export function getDefaultContent(): WebsiteContent {
return defaultContent
}