feat: implement DB-driven architecture with SQLite persistence and file-generator compilation service
All checks were successful
Production Build & Deploy / build-and-deploy (push) Successful in 50s

This commit is contained in:
Daniel S
2026-08-10 00:09:10 +02:00
parent 950497311c
commit db2f607e5a
12 changed files with 375 additions and 306 deletions

View File

@@ -1,40 +1,24 @@
import type { APIRoute } from 'astro';
import fs from 'node:fs/promises';
import path from 'node:path';
import { getDb } from '../../../db/index';
import { generateDraftConfig } from '../../../services/file-generator';
export const prerender = false;
const DATA_DIR = process.env.DATA_DIR || path.join(process.cwd(), 'app', 'data');
// Vordefinierte Standard-Templates für neue Sektionen
// Standard-Templates
const SECTION_TEMPLATES: Record<string, any> = {
HeroSection: {
type: 'HeroSection',
settings: {
title: 'Neue Überschrift',
subtitle: 'Beschreibungstext hier eingeben.',
cta_text: 'Jetzt anfragen',
cta_url: '#contact'
}
title: 'Neue Überschrift',
subtitle: 'Beschreibungstext hier eingeben.',
ctaPrimaryText: 'Jetzt anfragen',
ctaPrimaryLink: '#contact'
},
BentoGrid: {
type: 'BentoGrid',
settings: {
title: 'Unsere Highlights',
columns: 3,
items: [
{ title: 'Feature 1', description: 'Beschreibung 1' },
{ title: 'Feature 2', description: 'Beschreibung 2' },
{ title: 'Feature 3', description: 'Beschreibung 3' }
]
}
sectionTitle: 'Unsere Highlights',
sectionSubtitle: 'Modernste Features im Überblick'
},
ContactSection: {
type: 'ContactSection',
settings: {
title: 'Kontaktieren Sie uns',
email_recipient: 'info@kunden-domain.de'
}
title: 'Kontaktieren Sie uns',
subtitle: 'Wir antworten innerhalb von 24 Stunden.'
}
};
@@ -42,40 +26,32 @@ export const POST: APIRoute = async ({ request }) => {
try {
const { page_id, section_type } = await request.json();
if (!page_id || !section_type || !SECTION_TEMPLATES[section_type]) {
if (!page_id || !section_type) {
return new Response(JSON.stringify({ error: 'Gültige page_id und section_type erforderlich' }), { status: 400 });
}
const draftPath = path.join(DATA_DIR, 'site.config.draft.json');
const livePath = path.join(DATA_DIR, 'site.config.json');
const db = getDb();
const secId = `sec_${section_type.toLowerCase()}_${Date.now()}`;
const defaultContent = JSON.stringify(SECTION_TEMPLATES[section_type] || {});
let configRaw: string;
try {
configRaw = await fs.readFile(draftPath, 'utf-8');
} catch {
configRaw = await fs.readFile(livePath, 'utf-8');
}
// Aktuellen max order_index ermitteln
const maxOrderRow = db.prepare('SELECT MAX(order_index) as max_idx FROM page_sections WHERE page_id = ?').get(page_id) as { max_idx: number | null };
const nextIdx = (maxOrderRow?.max_idx ?? -1) + 1;
const config = JSON.parse(configRaw);
const targetPage = config.pages?.find((p: any) => p.id === page_id);
db.prepare('INSERT INTO page_sections (id, page_id, section_type, order_index, content_draft_json, content_published_json, styles_json) VALUES (?, ?, ?, ?, ?, ?, ?)').run(
secId,
page_id,
section_type,
nextIdx,
defaultContent,
defaultContent,
JSON.stringify({})
);
if (!targetPage) {
return new Response(JSON.stringify({ error: 'Seite nicht gefunden' }), { status: 404 });
}
// Draft-Config via File-Generator neu kompilieren
await generateDraftConfig();
// Neue Sektion mit eindeutiger ID anfügen
const newSection = {
id: `sec_${section_type.toLowerCase()}_${Date.now()}`,
...SECTION_TEMPLATES[section_type]
};
targetPage.sections = targetPage.sections || [];
targetPage.sections.push(newSection);
await fs.mkdir(DATA_DIR, { recursive: true });
await fs.writeFile(draftPath, JSON.stringify(config, null, 2), 'utf-8');
return new Response(JSON.stringify({ success: true, section: newSection }), { status: 201 });
return new Response(JSON.stringify({ success: true, section_id: secId }), { status: 201 });
} catch (error) {
return new Response(JSON.stringify({ error: 'Fehler beim Hinzufügen der Sektion' }), { status: 500 });
}