5b01aa3d-f0b2-4a70-9e57-f4fd90682497
This commit is contained in:
1 parent
d4c3b0f5ca
commit
34bd721ab1
23 files changed
+1461
-3
No files matched your search
+162
-1
@@ -34,9 +34,10 @@ async function main() {
|
||||
{ id: 'licenses', enabled: true, version: '1.0.0' },
|
||||
{ id: 'contracts', enabled: true, version: '1.0.0' },
|
||||
{ id: 'expenses', enabled: true, version: '1.0.0' },
|
||||
{ id: 'estimates', enabled: true, version: '1.0.0' },
|
||||
{ id: 'support', enabled: true, version: '1.0.0' },
|
||||
{ id: 'sales-docs', enabled: false, version: '0.9.0' },
|
||||
{ id: 'finance', enabled: true, version: '1.0.0' },
|
||||
{ id: 'support', enabled: false, version: '0.5.0' },
|
||||
{ id: 'reporting', enabled: false, version: '0.5.0' },
|
||||
]
|
||||
for (const m of modules) {
|
||||
@@ -463,6 +464,166 @@ async function main() {
|
||||
await db.auditLog.create({ data: { actor: 'nora@nordlicht.digital', action: 'expense.record', entity: 'Expense', entityId: 'seed', after: '{"category":"reise","billable":true}', hash: 'sha256:' + Math.random().toString(36).slice(2) } })
|
||||
await db.auditLog.create({ data: { actor: 'nora@nordlicht.digital', action: 'expense.convert:invoice', entity: 'Expense', entityId: 'seed', after: '{"status":"invoiced"}', hash: 'sha256:' + Math.random().toString(36).slice(2) } })
|
||||
|
||||
// --- Support Tickets (with conversation threads) -------------------------
|
||||
const tickets = [
|
||||
{
|
||||
number: 'TKT-2026-0014', subject: 'WooCommerce Checkout lädt nicht nach Update', status: 'open', priority: 'urgent', categoryId: 'bug',
|
||||
company: 'HanseMöbel Manufaktur GmbH', projectId: null, assignee: 'Tom Becker', slaResponseHours: 4, slaResolveHours: 24,
|
||||
messages: [
|
||||
{ fromType: 'customer', fromName: 'Frank Hartmann', body: 'Hallo, nach dem WordPress-Update heute Morgen lädt der Checkout nicht mehr. Kunden können nicht bezahlen. Bitte dringend prüfen! Fehlermeldung im Console: "jQuery is not defined".', createdAt: daysFromNow(-0.1) },
|
||||
{ fromType: 'staff', fromName: 'Tom Becker', body: 'Hallo Herr Hartmann, danke für die Meldung. Ich prüfe das sofort und melde mich innerhalb von 4 Stunden mit einer Lösung. Vermutlich ein Plugin-Konflikt durch das WP-Update.', createdAt: daysFromNow(-0.08) },
|
||||
{ fromType: 'customer', fromName: 'Frank Hartmann', body: 'OK, danke. Wir haben aktuell Bestellungen die hängen bleiben.', createdAt: daysFromNow(-0.05) },
|
||||
],
|
||||
},
|
||||
{
|
||||
number: 'TKT-2026-0013', subject: 'Neue Landingpage für Herbstkampagne', status: 'pending', priority: 'normal', categoryId: 'aenderung',
|
||||
company: 'Ostsee Hotel & Spa AG', projectId: projectMap['Website-Redesign Konzept'], assignee: 'Aylin Demir', slaResponseHours: 8, slaResolveHours: 72,
|
||||
slaRespondedAt: daysFromNow(-2),
|
||||
messages: [
|
||||
{ fromType: 'customer', fromName: 'Henrik Olsen', body: 'Wir benötigen eine Landingpage für unsere Herbst-Aktionswochen (Oktober/November). Inhalte: Wellness-Pakete, Bilder, Buchungs-CTA. Können Sie das bis nächste Woche umsetzen?', createdAt: daysFromNow(-3) },
|
||||
{ fromType: 'staff', fromName: 'Aylin Demir', body: 'Hallo Herr Olsen, sehr gerne. Wir können das im Rahmen des Redesign-Projekts umsetzen. Ich erstelle ein kurzes Angebot mit 2 Entwürfen. Ist ein Budgetrahmen von 2.500 € i.O.?', createdAt: daysFromNow(-2.5) },
|
||||
{ fromType: 'customer', fromName: 'Henrik Olsen', body: 'Ja, das passt. Bitte auch mobile Optimierung beachten.', createdAt: daysFromNow(-2) },
|
||||
],
|
||||
},
|
||||
{
|
||||
number: 'TKT-2026-0012', subject: 'Rechnung RE-2026-0039 unklar', status: 'open', priority: 'normal', categoryId: 'rechnung',
|
||||
company: 'Nordwind Logistik GmbH', assignee: 'Nora Klein', slaResponseHours: 8, slaResolveHours: 48,
|
||||
messages: [
|
||||
{ fromType: 'customer', fromName: 'Petra Hahn', body: 'Hallo, auf der Rechnung RE-2026-0039 sehe ich einen Posten "Abschlagszahlung Projekt" mit 5.400 €. Können Sie mir sagen, auf welche Leistungsphase sich das bezieht?', createdAt: daysFromNow(-0.3) },
|
||||
],
|
||||
},
|
||||
{
|
||||
number: 'TKT-2026-0011', subject: 'Backup-Job fehlgeschlagen (Intranet)', status: 'resolved', priority: 'high', categoryId: 'hosting',
|
||||
company: 'Nordwind Logistik GmbH', projectId: projectMap['Intranet-Portal Q4'], assignee: 'Tom Becker', slaResponseHours: 4, slaResolveHours: 24,
|
||||
slaRespondedAt: daysFromNow(-5), slaResolvedAt: daysFromNow(-4),
|
||||
messages: [
|
||||
{ fromType: 'customer', fromName: 'Petra Hahn', body: 'Der nächtliche Backup-Job ist am 20.10. fehlgeschlagen. Log: "Permission denied /var/backups".', createdAt: daysFromNow(-5.5) },
|
||||
{ fromType: 'staff', fromName: 'Tom Becker', body: 'Danke fürs Melden. Ursache: Berechtigungen nach Server-Update zurückgesetzt. Habe die Rechte korrigiert und einen Test-Backup angestoßen — läuft erfolgreich.', createdAt: daysFromNow(-5) },
|
||||
{ fromType: 'customer', fromName: 'Petra Hahn', body: 'Perfekt, danke für die schnelle Lösung!', createdAt: daysFromNow(-4.5) },
|
||||
{ fromType: 'system', fromName: 'AOS System', body: 'Ticket automatisch auf "resolved" gesetzt — keine Antwort des Kunden seit 12 Stunden.', createdAt: daysFromNow(-4) },
|
||||
],
|
||||
},
|
||||
{
|
||||
number: 'TKT-2026-0010', subject: 'Zugangsdaten für neue Redakteurin', status: 'resolved', priority: 'low', categoryId: 'konto',
|
||||
company: 'Bauer Handwerk GmbH', assignee: 'Aylin Demir', slaResponseHours: 8, slaResolveHours: 48,
|
||||
slaRespondedAt: daysFromNow(-8), slaResolvedAt: daysFromNow(-7),
|
||||
messages: [
|
||||
{ fromType: 'customer', fromName: 'Sabine Bauer', body: 'Unsere neue Praktikantin Lisa benötigt CMS-Zugang für den Blog. Welche Daten braucht ihr dafür?', createdAt: daysFromNow(-8.5) },
|
||||
{ fromType: 'staff', fromName: 'Aylin Demir', body: 'Hallo Frau Bauer, gerne. Ich brauche: Vor- und Nachname, E-Mail-Adresse. Dann richte ich einen Redakteur-Account ohne Admin-Rechte ein (DSGVO-konform, minimal privilegiert).', createdAt: daysFromNow(-8) },
|
||||
{ fromType: 'customer', fromName: 'Sabine Bauer', body: 'Lisa Müller, lisa@bauer-handwerk.de', createdAt: daysFromNow(-7.5) },
|
||||
{ fromType: 'staff', fromName: 'Aylin Demir', body: 'Erledigt. Zugangsdaten wurden per sicherem Link verschickt (24 h gültig). Bitte beim ersten Login Passwort setzen.', createdAt: daysFromNow(-7) },
|
||||
],
|
||||
},
|
||||
{
|
||||
number: 'TKT-2026-0009', subject: 'DSGVO: Auskunft nach Art. 15', status: 'closed', priority: 'normal', categoryId: 'anfrage',
|
||||
company: 'TechStart UG (haftungsbeschränkt)', assignee: 'Lena Vogt', slaResponseHours: 24, slaResolveHours: 168,
|
||||
slaRespondedAt: daysFromNow(-12), slaResolvedAt: daysFromNow(-3),
|
||||
messages: [
|
||||
{ fromType: 'customer', fromName: 'Jonas Weiß', body: 'Gemäß Art. 15 DSGVO bitte ich um Auskunft über die zu meiner Person gespeicherten Daten.', createdAt: daysFromNow(-14) },
|
||||
{ fromType: 'staff', fromName: 'Lena Vogt', body: 'Hallo Herr Weiß, Ihre Anfrage wurde registriert (Art. 15 DSGVO, Frist 1 Monat). Ich erstelle einen Datenexport und eine Aufstellung aller Verarbeitungsvorgänge.', createdAt: daysFromNow(-12) },
|
||||
{ fromType: 'staff', fromName: 'Lena Vogt', body: 'Der Datenexport liegt vor: CRM-Kontakt, 2 Projekte, 3 Rechnungen, 1 Ticket-Verlauf. Alle Daten wurden im Rahmen der Auftragsabwicklung verarbeitet (Art. 6 Abs. 1 lit. b). Dokument anbei.', createdAt: daysFromNow(-3) },
|
||||
],
|
||||
},
|
||||
]
|
||||
for (const t of tickets) {
|
||||
const { company, messages, ...rest } = t
|
||||
const created = await db.ticket.create({ data: { ...rest, companyId: companyMap[company] } })
|
||||
for (const m of messages) {
|
||||
await db.ticketMessage.create({ data: { ...m, ticketId: created.id } })
|
||||
}
|
||||
}
|
||||
|
||||
// --- Estimates / Angebote ------------------------------------------------
|
||||
const estimates = [
|
||||
{
|
||||
number: 'AN-2026-0018', company: 'Ostsee Hotel & Spa AG', dealId: null, projectId: null,
|
||||
subject: 'Landingpage Herbstkampagne (Wellness-Pakete)', status: 'sent', validUntil: daysFromNow(14),
|
||||
issueDate: daysFromNow(-1), acceptedAt: null, acceptedBy: null,
|
||||
notes: 'Mobil-optimiert, 2 Entwürfe inkl. Revisionsschleife, Buchungs-CTA.',
|
||||
lines: [
|
||||
{ description: 'Konzeption & Wireframe Landingpage', quantity: 1, unitCents: CENTS(450) },
|
||||
{ description: 'Design-Entwürfe (2 Varianten)', quantity: 1, unitCents: CENTS(800) },
|
||||
{ description: 'Responsive Umsetzung (Astro)', quantity: 1, unitCents: CENTS(650) },
|
||||
{ description: 'Buchungs-CTA & Formular-Anbindung', quantity: 1, unitCents: CENTS(350) },
|
||||
{ description: 'Revisionsschleife (1 Runde)', quantity: 1, unitCents: CENTS(250) },
|
||||
],
|
||||
},
|
||||
{
|
||||
number: 'AN-2026-0017', company: 'Bauer Handwerk GmbH', dealId: null, projectId: null,
|
||||
subject: 'Corporate Website Relaunch (Werkvertrag)', status: 'sent', validUntil: daysFromNow(21),
|
||||
issueDate: daysFromNow(-3), acceptedAt: null, acceptedBy: null,
|
||||
notes: 'Inkl. Impressum, Datenschutz, DSGVO-Check, Schulung Redakteure.',
|
||||
lines: [
|
||||
{ description: 'Konzeption & Information Architecture', quantity: 1, unitCents: CENTS(1200) },
|
||||
{ description: 'UI/UX Design (inkl. 2 Revisionsschleifen)', quantity: 1, unitCents: CENTS(2400) },
|
||||
{ description: 'Frontend-Entwicklung (Astro + Tailwind)', quantity: 1, unitCents: CENTS(3200) },
|
||||
{ description: 'CMS-Integration (AOS-CMS, Headless)', quantity: 1, unitCents: CENTS(1500) },
|
||||
{ description: 'DSGVO/Impressum & BFSG-Accessibility', quantity: 1, unitCents: CENTS(500) },
|
||||
{ description: 'Schulung Redakteure (2 × 2 h)', quantity: 2, unitCents: CENTS(200) },
|
||||
{ description: 'Launch-Checkliste & Go-Live', quantity: 1, unitCents: CENTS(800) },
|
||||
],
|
||||
},
|
||||
{
|
||||
number: 'AN-2026-0016', company: 'Müller Bäckerei e.K.', dealId: null, projectId: null,
|
||||
subject: 'WooCommerce Online-Shop (Click & Collect)', status: 'accepted', validUntil: daysFromNow(-2),
|
||||
issueDate: daysFromNow(-18), acceptedAt: daysFromNow(-5), acceptedBy: 'Greta Müller',
|
||||
notes: 'Inkl. Altersprüfung, Click-&-Collect, Anbindung Kassensystem (offen).',
|
||||
lines: [
|
||||
{ description: 'Shop-Konzeption & Produktstruktur', quantity: 1, unitCents: CENTS(800) },
|
||||
{ description: 'WooCommerce Setup & Theme', quantity: 1, unitCents: CENTS(1800) },
|
||||
{ description: 'Click-&-Collect Modul (AOS-Plugin)', quantity: 1, unitCents: CENTS(900) },
|
||||
{ description: 'Zahlungsanbindung (Stripe)', quantity: 1, unitCents: CENTS(600) },
|
||||
{ description: 'Altersprüfung 18+ (juice/sharp)', quantity: 1, unitCents: CENTS(350) },
|
||||
{ description: 'Produktimport (200 Artikel)', quantity: 1, unitCents: CENTS(450) },
|
||||
{ description: 'Schulung & Handbuch', quantity: 1, unitCents: CENTS(300) },
|
||||
],
|
||||
},
|
||||
{
|
||||
number: 'AN-2026-0015', company: 'TechStart UG (haftungsbeschränkt)', dealId: null, projectId: projectMap['SaaS MVP — Auth & Billing'],
|
||||
subject: 'SaaS MVP — Erweiterung Auth & Billing (Phase 2)', status: 'accepted', validUntil: daysFromNow(5),
|
||||
issueDate: daysFromNow(-7), acceptedAt: daysFromNow(-3), acceptedBy: 'Jonas Weiß',
|
||||
notes: 'Aufbauend auf Phase 1. Stripe Billing, Team-Invites, Audit-Log.',
|
||||
lines: [
|
||||
{ description: 'Stripe Billing Integration (Subscriptions)', quantity: 1, unitCents: CENTS(3200) },
|
||||
{ description: 'Team-Management & Invites', quantity: 1, unitCents: CENTS(1800) },
|
||||
{ description: 'RBAC & Permissions Matrix', quantity: 1, unitCents: CENTS(1500) },
|
||||
{ description: 'Audit-Log (Hash-Kette)', quantity: 1, unitCents: CENTS(900) },
|
||||
],
|
||||
},
|
||||
{
|
||||
number: 'AN-2026-0014', company: 'Klinik am Park MV GmbH', dealId: null, projectId: projectMap['SEO-Optimierung & BFGG-Check'],
|
||||
subject: 'SEO-Optimierung & BFSG-Barrierefreiheit', status: 'rejected', validUntil: daysFromNow(-10),
|
||||
issueDate: daysFromNow(-25), acceptedAt: null, acceptedBy: null,
|
||||
notes: 'Kunde hat Budget gekürzt, scope reduziert. Neues Angebot folgt.',
|
||||
lines: [
|
||||
{ description: 'SEO-Audit & Keyword-Analyse', quantity: 1, unitCents: CENTS(1200) },
|
||||
{ description: 'Schema.org LocalBusiness Markup', quantity: 1, unitCents: CENTS(450) },
|
||||
{ description: 'BFSG Accessibility-Audit (axe)', quantity: 1, unitCents: CENTS(800) },
|
||||
{ description: 'Accessibility-Behebung (Kontrast, ARIA, Skip-Links)', quantity: 1, unitCents: CENTS(2200) },
|
||||
],
|
||||
},
|
||||
]
|
||||
for (const est of estimates) {
|
||||
const { company, lines, ...rest } = est
|
||||
const netCents = lines.reduce((s, l) => s + l.unitCents * l.quantity, 0)
|
||||
const taxBp = 1900
|
||||
const grossCents = Math.round(netCents * (1 + taxBp / 10000))
|
||||
const created = await db.estimate.create({
|
||||
data: { ...rest, companyId: companyMap[company], netCents, taxBp, grossCents },
|
||||
})
|
||||
for (const l of lines) {
|
||||
await db.estimateLine.create({
|
||||
data: { ...l, estimateId: created.id, totalCents: l.unitCents * l.quantity },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// audit entries for tickets + estimates
|
||||
await db.auditLog.create({ data: { actor: 'aylin@nordlicht.digital', action: 'ticket.reply', entity: 'Ticket', entityId: 'seed', after: '{"status":"pending"}', hash: 'sha256:' + Math.random().toString(36).slice(2) } })
|
||||
await db.auditLog.create({ data: { actor: 'system:llm', action: 'ai.ticket:summarize', entity: 'Ticket', entityId: 'seed', after: '{"model":"glm","length":340}', hash: 'sha256:' + Math.random().toString(36).slice(2) } })
|
||||
await db.auditLog.create({ data: { actor: 'sven@nordlicht.digital', action: 'estimate.send', entity: 'Estimate', entityId: 'seed', after: '{"status":"sent"}', hash: 'sha256:' + Math.random().toString(36).slice(2) } })
|
||||
await db.auditLog.create({ data: { actor: 'sven@nordlicht.digital', action: 'estimate.accept', entity: 'Estimate', entityId: 'seed', after: '{"status":"accepted","projectId":"created"}', hash: 'sha256:' + Math.random().toString(36).slice(2) } })
|
||||
|
||||
console.log('Seed complete.')
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user