This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/admin-v2/lib/content.ts
BreakPilot Dev 19855efacc
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
feat: BreakPilot PWA - Full codebase (clean push without large binaries)
All services: admin-v2, studio-v2, website, ai-compliance-sdk,
consent-service, klausur-service, voice-service, and infrastructure.
Large PDFs and compiled binaries excluded via .gitignore.
2026-02-11 13:25:58 +01:00

285 lines
8.5 KiB
TypeScript

/**
* Website Content Management (Server-only)
*
* Loads website texts from JSON files.
* Admin can edit texts via /development/content
*
* IMPORTANT: This file may only be used in Server Components!
* For Client Components use @/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 directory - use environment variable or relative path
function getContentDir(): string {
// Check environment variable first
if (process.env.CONTENT_DIR) {
return process.env.CONTENT_DIR
}
// Try various possible paths
const possiblePaths = [
join(process.cwd(), 'content'), // Standard: CWD/content
join(process.cwd(), 'admin-v2', 'content'), // If CWD is project root
'/app/content', // Docker container
join(dirname(__filename), '..', 'content'), // Relative to this file
]
// Check if any path exists and is writable
for (const path of possiblePaths) {
try {
if (existsSync(path)) {
accessSync(path, constants.W_OK)
return path
}
} catch {
// Path not writable, try next
}
}
// Fallback: Create in 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',
},
}
/**
* Loads content from JSON file or returns default
*/
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
}
/**
* Saves content to JSON file
* @returns Object with success status and optional error message
*/
export function saveContent(content: WebsiteContent): { success: boolean; error?: string } {
const contentPath = join(CONTENT_DIR, 'website.json')
try {
// Ensure directory exists
if (!existsSync(CONTENT_DIR)) {
console.log(`[Content] Creating directory: ${CONTENT_DIR}`)
mkdirSync(CONTENT_DIR, { recursive: true, mode: 0o755 })
}
// Check write permissions
try {
accessSync(CONTENT_DIR, constants.W_OK)
} catch {
const error = `Directory not writable: ${CONTENT_DIR}`
console.error(`[Content] ${error}`)
return { success: false, error }
}
// Write file
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 : 'Unknown error'
console.error(`[Content] Error saving: ${errorMessage}`)
return { success: false, error: errorMessage }
}
}
/**
* Returns default content (for reset)
*/
export function getDefaultContent(): WebsiteContent {
return defaultContent
}