Directus als Daten-/Auth-Schicht + Backend-Anbindung
Directus (Postgres, hinter NPM) wird die zentrale Datenquelle für Kunden, Aufträge, Produkte, Preise und Gutscheine; das skrift-backend bleibt reine Generierungs-Engine. - Docker/directus: docker-compose (Directus 11 + Postgres), Bootstrap-Skript legt Collections, Rollen/Policies/Rechte und Seed idempotent an. - Extension skrift-auth: passwortloser Login per E-Mail-Code (Codes nur als Hash, Ablauf, Versuchslimit) sowie Kontoanlage aus dem Checkout. - Extension skrift-orders: kontrollierter Bestell-Endpunkt für Gäste und eingeloggte Kunden; Preis wird immer serverseitig berechnet (editierbare Formel via sicherem Interpreter, Werte aus price_items). - skrift-backend: neuer Endpunkt /api/order/from-directus erzeugt SVGs aus einem Directus-Auftrag und schreibt Status + artifact_path zurück. Dafür wurde die Kernlogik aus generateOrder als runGeneration herausgelöst (Verhalten unverändert); generateOrder ist jetzt ein HTTP-Wrapper. - compose: NPM-Netz ergänzt, API_TOKEN/DIRECTUS_* werden durchgereicht. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
80
Docker/skrift-backend/src/services/directus-service.js
Normal file
80
Docker/skrift-backend/src/services/directus-service.js
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Directus-Client für das Backend.
|
||||
*
|
||||
* Directus ist die Datenquelle für Aufträge; dieses Backend bleibt die reine
|
||||
* Generierungs-Engine. Zugriff über einen Service-Token (Rolle "Service").
|
||||
*/
|
||||
|
||||
const config = require('../config');
|
||||
|
||||
function requireConfig() {
|
||||
if (!config.directus.url || !config.directus.token) {
|
||||
const e = new Error('DIRECTUS_URL und DIRECTUS_TOKEN müssen gesetzt sein.');
|
||||
e.status = 500;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function directusFetch(path, options = {}) {
|
||||
requireConfig();
|
||||
const res = await fetch(config.directus.url.replace(/\/$/, '') + path, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${config.directus.token}`,
|
||||
...(options.headers || {}),
|
||||
},
|
||||
});
|
||||
const text = await res.text();
|
||||
let data = null;
|
||||
try { data = text ? JSON.parse(text) : null; } catch { /* ignore */ }
|
||||
if (!res.ok) {
|
||||
const msg = data?.errors?.[0]?.message || text || res.statusText;
|
||||
const e = new Error(`Directus ${options.method || 'GET'} ${path}: ${msg}`);
|
||||
e.status = res.status === 404 ? 404 : 502;
|
||||
throw e;
|
||||
}
|
||||
return data?.data ?? data;
|
||||
}
|
||||
|
||||
/** Lädt einen Auftrag inkl. Empfängerzeilen, Produkt und Format. */
|
||||
async function fetchOrder(orderId) {
|
||||
const fields = [
|
||||
'id', 'order_number', 'customer_email', 'font', 'status',
|
||||
'needs_envelope', 'envelope_labeling', 'envelope_format',
|
||||
'text_template', 'motif_mode', 'own_cards', 'entries_count',
|
||||
'product.key', 'product.type', 'format.key',
|
||||
].join(',');
|
||||
|
||||
const order = await directusFetch(`/items/orders/${encodeURIComponent(orderId)}?fields=${fields}`);
|
||||
if (!order) {
|
||||
const e = new Error(`Auftrag ${orderId} nicht gefunden.`);
|
||||
e.status = 404;
|
||||
throw e;
|
||||
}
|
||||
|
||||
const entries = await directusFetch(
|
||||
`/items/order_entries?filter[order][_eq]=${encodeURIComponent(orderId)}` +
|
||||
`&sort=letter_number&limit=-1&fields=*`
|
||||
);
|
||||
|
||||
return { order, entries: entries || [] };
|
||||
}
|
||||
|
||||
/** Schreibt Status und Artefakt-Pfad zurück. */
|
||||
async function updateOrder(orderId, patch) {
|
||||
return directusFetch(`/items/orders/${encodeURIComponent(orderId)}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(patch),
|
||||
});
|
||||
}
|
||||
|
||||
/** Protokolliert einen Statuswechsel in der Timeline. */
|
||||
async function addStatusHistory(orderId, status, note) {
|
||||
return directusFetch('/items/status_history', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ order: orderId, status, note }),
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { fetchOrder, updateOrder, addStatusHistory };
|
||||
Reference in New Issue
Block a user