/** * QA-1: Seed-Daten für den Mock-Modus — geformt exakt nach dem DATA-2-Vertrag * (camelCase-DTOs, Gridify-paged Listen). Datensatz angelehnt an Kellys * FEAT-4-Verifikationsdaten (mehrgenerationiger Stammbaum inkl. gemeinsamem * Vorfahren Anton), erweitert um Becken/Kontakte/Gesundheit/Gewicht für die * FEAT-2/FEAT-6-Flüsse. */ import type { Contact, Enclosure, Gerbil, Litter } from '../src/api/types' import type { InboxRequest } from '../src/api/requests' export interface HealthRecordRow { id: string gerbilId: string date: string type: string description: string veterinarian: string | null createdAt: string } export interface WeightRecordRow { id: string gerbilId: string date: string weightGrams: number notes: string | null } /** WEB-0b: CMS-Block (data ist das typ-spezifische JSON-Objekt). */ export interface MockBlock { id: string order: number type: string data: Record } /** WEB-0b: CMS-Seite der öffentlichen Webseite. */ export interface MockPage { id: string slug: string title: string seoDescription: string | null status: 'Draft' | 'Published' blocks: MockBlock[] } /** ABGABE: Abgabevertrag (mirrors SaleContract in src/api/contracts.ts). */ export interface MockContract { id: string contactId: string price: number handoverDate: string contractDate: string fileName: string createdAt: string gerbilIds: string[] url: string } export interface MockDb { gerbils: Gerbil[] litters: Litter[] enclosures: Enclosure[] contacts: Contact[] colorVarieties: { id: string; name: string; canonicalGenotype: string | null; sortOrder: number }[] healthRecords: HealthRecordRow[] weightRecords: WeightRecordRow[] pages: MockPage[] // INBOX-1: Anfragen-Posteingang. Die Flags steuern die Fehlerpfade des Mocks // (Specs können sie pro Test umlegen): KI-Entwurf 503 / Sync+Send Mail-Fehler. requests: InboxRequest[] aiConfigured: boolean mailConfigured: boolean // ABGABE: Verträge + KI-Inserat-Flag contracts: MockContract[] saleAdConfigured: boolean // FEAT-NAMEGEN: Namensvorschläge — false = 503 NamesKeyMissing simulieren namesConfigured: boolean } function gerbil( id: string, name: string, gender: 'male' | 'female', dateOfBirth: string, litterId: string | null, colorVarietyId: string | null, genotype: string | null = null, ): Gerbil { return { id, name, gender, status: 'Active', dateOfBirth, dateOfDeath: null, causeOfDeath: null, goHomeDate: null, litterId, enclosureId: null, colorVarietyId, originContactId: null, receiverContactId: null, originBreeder: null, // SEARCH-2b: backend stores a normalized name (lowercase, [\s._-] stripped). nameSearch: name.toLowerCase().replace(/[\s._-]/g, ''), genotype, notes: null, // BESTAND-FILTER: default = eigener Bestand; einzelne externe Ahnen unten gesetzt. isResident: true, } } /** Frischer, unabhängiger Datenbestand pro Test. */ export function seedDb(): MockDb { const gerbils: Gerbil[] = [ { ...gerbil('kruemel', 'Krümel', 'female', '2025-03-12', 'w-kruemel', 'cv-agouti', 'Aa CC DD EE GG Pp spsp rere'), enclosureId: 'enc-gross', originContactId: 'con-meier', originBreeder: 'Clan-Kleine-Chaoten', }, { ...gerbil('fridolin', 'Fridolin', 'male', '2023-05-01', 'w-fridolin', 'cv-schwarz', 'aa CC DD EE GG PP spsp rere'), enclosureId: 'enc-gross', originBreeder: 'Zoohandlung Meier' }, gerbil('luna', 'Luna', 'female', '2023-08-15', 'w-luna', 'cv-gold', 'AA CC DD EE GG pp spsp rere'), gerbil('balu', 'Balu', 'male', '2021-04-20', 'w-balu', 'cv-agouti'), gerbil('maja', 'Maja', 'female', '2021-06-11', null, 'cv-schwarz-schecke', 'aa CC DD EE GG PP Spsp rere'), gerbil('karlsson', 'Karlsson', 'male', '2022-02-02', 'w-karlsson', 'cv-blau'), gerbil('smilla', 'Smilla', 'female', '2022-09-30', null, 'cv-himalaya'), gerbil('anton', 'Anton', 'male', '2019-07-07', 'w-anton', 'cv-agouti'), gerbil('greta', 'Greta', 'female', '2019-05-23', null, 'cv-schwarz'), gerbil('frieda', 'Frieda', 'female', '2020-01-18', null, 'cv-gold'), gerbil('emil', 'Emil', 'male', '2017-03-03', 'w-emil', 'cv-agouti'), // BESTAND-FILTER: externe Ahnen (Gründertiere fremder Zuchten, nur für den Stammbaum). { ...gerbil('hilde', 'Hilde', 'female', '2017-11-11', null, 'cv-schwarz'), isResident: false, originBreeder: 'Zoohandlung Meier' }, { ...gerbil('max', 'Max', 'male', '2015-08-08', null, 'cv-agouti'), isResident: false, originBreeder: 'Zoohandlung Meier' }, // Statistik: Verstorbene + Abgegebene für Verluste/Bestandskurve { ...gerbil('willi', 'Willi', 'male', '2019-09-09', null, 'cv-schwarz'), status: 'Deceased', dateOfDeath: '2022-04-04' }, { ...gerbil('rosa', 'Rosa', 'female', '2020-02-02', null, 'cv-gold'), status: 'Deceased', dateOfDeath: '2023-08-15' }, { ...gerbil('pauli', 'Pauli', 'male', '2023-05-01', null, 'cv-himalaya'), status: 'GivenAway', goHomeDate: '2023-07-15', receiverContactId: 'con-huber' }, // ABGABE: zwei Tiere zur Abgabe im Quarantänebecken (enc-leer ist leer, kein Konflikt // mit dem Becken-Belegungstest der Großbecken-2-Tiere-Assertion). { ...gerbil('sale-balu', 'Balu Abgabe', 'male', '2024-03-12', null, 'cv-agouti'), status: 'ForSale' as const, enclosureId: 'enc-leer', notes: 'ruhig, nimmt Leckerlis aus der Hand', }, { ...gerbil('sale-benny', 'Benny Abgabe', 'male', '2024-03-12', null, 'cv-schwarz-schecke'), status: 'ForSale' as const, enclosureId: 'enc-leer', notes: 'neugieriger Entdecker', }, // UI-POLISH-1: Import-Stub ohne Namen — testet den '(ohne Namen)'-Platzhalter in Liste + Detail. gerbil('nameless-stub', '', 'male', '2023-01-01', null, null), ] const litters: Litter[] = [ { id: 'w-kruemel', name: 'Wurf K', date: '2025-03-12', totalBorn: 5, expectedGoHomeDate: '2025-04-16', notes: null, fatherId: 'fridolin', motherId: 'luna' }, { id: 'w-fridolin', name: 'Wurf F', date: '2023-05-01', totalBorn: 4, expectedGoHomeDate: null, notes: null, fatherId: 'balu', motherId: 'maja' }, { id: 'w-luna', name: 'Wurf L', date: '2023-08-15', totalBorn: 6, expectedGoHomeDate: null, notes: null, fatherId: 'karlsson', motherId: 'smilla' }, { id: 'w-balu', name: 'Wurf B', date: '2021-04-20', totalBorn: 3, expectedGoHomeDate: null, notes: null, fatherId: 'anton', motherId: 'greta' }, // Anton ist auch Karlssons Vater -> gemeinsamer Vorfahre (Inzucht-Demo) { id: 'w-karlsson', name: 'Wurf C', date: '2022-02-02', totalBorn: 5, expectedGoHomeDate: null, notes: null, fatherId: 'anton', motherId: 'frieda' }, { id: 'w-anton', name: 'Wurf A', date: '2019-07-07', totalBorn: 4, expectedGoHomeDate: null, notes: null, fatherId: 'emil', motherId: 'hilde' }, { id: 'w-emil', name: 'Wurf E', date: '2017-03-03', totalBorn: 2, expectedGoHomeDate: null, notes: null, fatherId: 'max', motherId: null }, ] const enclosures: Enclosure[] = [ { id: 'enc-gross', name: 'Großbecken', notes: '120×50 cm' }, { id: 'enc-leer', name: 'Quarantänebecken', notes: null }, ] // FEAT-13: contactInfo (Freitext) wurde durch strukturierte Felder ersetzt. const contacts: Contact[] = [ { id: 'con-meier', name: 'Zoohandlung Meier', email: 'meier@example.de', phone: null, address: 'Hauptstraße 1, 12345 Musterstadt', notes: null }, { id: 'con-huber', name: 'Familie Huber', email: null, phone: '0151 2345678', address: null, notes: null }, { id: 'con-frei', name: 'Züchterin Frei', email: null, phone: null, address: null, notes: 'unverknüpft' }, ] const colorVarieties = [ { id: 'cv-agouti', name: 'Agouti', canonicalGenotype: 'AA CC DD EE GG PP spsp rere', sortOrder: 1 }, { id: 'cv-schwarz', name: 'Schwarz', canonicalGenotype: 'aa CC DD EE GG PP spsp rere', sortOrder: 2 }, { id: 'cv-gold', name: 'Gold', canonicalGenotype: 'AA CC DD EE GG pp spsp rere', sortOrder: 3 }, { id: 'cv-blau', name: 'Blau', canonicalGenotype: 'aa CC dd EE GG PP spsp rere', sortOrder: 4 }, { id: 'cv-himalaya', name: 'Himalaya', canonicalGenotype: 'AA chch DD EE GG PP spsp rere', sortOrder: 5 }, { id: 'cv-schwarz-schecke', name: 'Schwarz Schecke', canonicalGenotype: 'aa CC DD EE GG PP Spsp rere', sortOrder: 6 }, ] const healthRecords: HealthRecordRow[] = [ { id: 'hr-1', gerbilId: 'kruemel', date: '2026-01-15', type: 'Vaccination', description: 'Jahresimpfung', veterinarian: 'Dr. Vogel', createdAt: '2026-01-15T10:00:00Z', }, ] const weightRecords: WeightRecordRow[] = [ { id: 'wr-1', gerbilId: 'kruemel', date: '2026-05-01', weightGrams: 78, notes: null }, { id: 'wr-2', gerbilId: 'kruemel', date: '2026-05-20', weightGrams: 82, notes: null }, ] // WEB-0b: die 6 Webseiten-Seiten (wie vom Backend geseedet), mit ein paar Blöcken. const pages: MockPage[] = [ { id: 'page-start', slug: 'start', title: 'Startseite', seoDescription: 'Willkommen bei unserer Rennmauszucht.', status: 'Published', blocks: [ { id: 'blk-start-1', order: 0, type: 'Heading', data: { text: 'Willkommen', level: 2 } }, { id: 'blk-start-2', order: 1, type: 'RichText', data: { markdown: 'Schön, dass du da bist.' } }, ], }, { id: 'page-zucht', slug: 'ueber-die-zucht', title: 'Über die Zucht', seoDescription: null, status: 'Draft', blocks: [] }, { id: 'page-abgabe', slug: 'abgabetiere', title: 'Abgabetiere', seoDescription: null, status: 'Published', blocks: [ { id: 'blk-abgabe-1', order: 0, type: 'AbgabetiereList', data: { mode: 'auto', intro: 'Diese Tiere suchen ein Zuhause.' } }, ], }, { id: 'page-bedingungen', slug: 'abgabebedingungen', title: 'Abgabebedingungen', seoDescription: null, status: 'Draft', blocks: [] }, { id: 'page-farben', slug: 'farben-genetik', title: 'Farben & Genetik', seoDescription: null, status: 'Draft', blocks: [] }, { id: 'page-kontakt', slug: 'kontakt', title: 'Kontakt', seoDescription: null, status: 'Draft', blocks: [] }, ] // INBOX-1: Anfragen (neueste zuerst nach receivedAt sortierbar) const requests: InboxRequest[] = [ { id: 'req-anna', gmailMessageId: '', threadId: 'thr-1', fromAddress: 'anna@example.de', fromName: 'Anna Albrecht', subject: 'Anfrage: Pärchen zur Abgabe?', bodyText: 'Hallo,\n\nich habe euer Inserat gesehen — sind die beiden Agouti-Jungs noch zu haben?\n\nViele Grüße\nAnna', receivedAt: '2026-06-05T18:30:00Z', status: 'New', assignedContactId: null, draftReply: null, answeredAt: null, }, { id: 'req-ben', gmailMessageId: '', threadId: 'thr-2', fromAddress: 'ben@example.org', fromName: 'Ben Berger', subject: 'Frage zur Haltung', bodyText: 'Guten Tag, was für ein Becken empfehlt ihr für zwei Rennmäuse?', receivedAt: '2026-06-04T09:00:00Z', status: 'InProgress', assignedContactId: null, draftReply: 'Hallo Ben, wir empfehlen mindestens 100×50 cm …', answeredAt: null, }, { id: 'req-clara', gmailMessageId: '', threadId: null, fromAddress: 'clara@example.com', fromName: null, subject: 'Danke!', bodyText: 'Die beiden sind super angekommen — danke nochmal!', receivedAt: '2026-06-01T12:00:00Z', status: 'Answered', assignedContactId: 'con-meier', draftReply: null, answeredAt: '2026-06-02T08:00:00Z', }, ] return { gerbils, litters, enclosures, contacts, colorVarieties, healthRecords, weightRecords, pages, requests, aiConfigured: true, mailConfigured: true, contracts: [], saleAdConfigured: true, namesConfigured: true, } }