From 190720ad9265da64bd0ae17eea8abb0cd44e35f1 Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Thu, 5 Feb 2026 10:42:47 +0100 Subject: [PATCH] refactor: Remove numerical prefixes from pricing calculator position titles. --- scripts/ai-estimate.ts | 44 +++++++++---------- src/components/pdf/modules/CommonModules.tsx | 20 ++++----- src/logic/pricing/calculator.ts | 20 ++++----- .../default/SDK_CRAWLER_STATISTICS_0.json | 22 +++++----- .../default/SDK_SESSION_POOL_STATE.json | 42 +++++++++--------- 5 files changed, 74 insertions(+), 74 deletions(-) diff --git a/scripts/ai-estimate.ts b/scripts/ai-estimate.ts index f6549eb..f2ff233 100644 --- a/scripts/ai-estimate.ts +++ b/scripts/ai-estimate.ts @@ -533,16 +533,16 @@ ${JSON.stringify({ facts, strategy }, null, 2)} // Determine which positions are actually relevant to avoid hallucinations const requiredPositions = [ - "1. Das technische Fundament", - facts.selectedPages.length + facts.otherPages.length > 0 ? "2. Individuelle Seiten" : null, - facts.features.length > 0 ? "3. System-Module (Features)" : null, - facts.functions.length > 0 ? "4. Logik-Funktionen" : null, - facts.apiSystems.length > 0 ? "5. Schnittstellen (API)" : null, - facts.cmsSetup ? "6. Inhaltsverwaltung (CMS)" : null, - "7. Inszenierung & Interaktion", // Always include for high-end strategy - facts.multilang ? "8. Mehrsprachigkeit" : null, - "9. Inhaltliche Initial-Pflege", - "10. Sorglos-Paket (Betrieb & Pflege)" + "Das technische Fundament", + facts.selectedPages.length + facts.otherPages.length > 0 ? "Individuelle Seiten" : null, + facts.features.length > 0 ? "System-Module (Features)" : null, + facts.functions.length > 0 ? "Logik-Funktionen" : null, + facts.apiSystems.length > 0 ? "Schnittstellen (API)" : null, + facts.cmsSetup ? "Inhaltsverwaltung (CMS)" : null, + "Inszenierung & Interaktion", // Always include for high-end strategy + facts.multilang ? "Mehrsprachigkeit" : null, + "Inhaltliche Initial-Pflege", + "Sorglos-Paket (Betrieb & Pflege)" ].filter(Boolean); const pass5SystemPrompt = ` @@ -553,16 +553,16 @@ Each position in the quote must be perfectly justified and detailed using an obj ${requiredPositions.map(p => `"${p}"`).join(", ")} ### MAPPING RULES (STRICT): -- ** 1. Das technische Fundament **: Infrastructure, Hosting setup, SEO-Basics, Analytics, Environments. -- ** 2. Individuelle Seiten **: Layout / structure for specific pages. ** RULE **: If quantity is high (e.g. > 10), lead with "Umsetzung von [QTY] individuellen Einzelseiten...". -- ** 3. System-Module (Features) **: Functional systems like Blog, News, Products, Jobs, References. ** RULE **: Describe exactly 1 thing if qty is 1. If qty is 0, DO NOT DESCRIBE THIS. -- ** 4. Logik-Funktionen **: Logic modules like Search, Filter, Forms, PDF-Export. -- ** 5. Schnittstellen (API) **: Data Syncs with CRM, ERP, Payment systems. -- ** 6. Inhaltsverwaltung (CMS) **: Setup and mapping for CMS. -- ** 7. Inszenierung & Interaktion **: Hero-stories, visual effects, configurators. -- ** 8. Mehrsprachigkeit **: Architecture scaling for multiple languages. -- ** 9. Inhaltliche Initial-Pflege **: Manual data entry / cleanup. -- ** 10. Sorglos-Paket (Betrieb & Pflege) **: ** RULE **: Describe as "1 Jahr Sicherung des technischen Betriebs, Instandhaltung, Sicherheits-Updates und Inhalts-Aktualisierungen gemäß AGB Punkt 7a." +- ** Das technische Fundament **: Infrastructure, Hosting setup, SEO-Basics, Analytics, Environments. +- ** Individuelle Seiten **: Layout / structure for specific pages. ** RULE **: If quantity is high (e.g. > 10), lead with "Umsetzung von [QTY] individuellen Einzelseiten...". +- ** System-Module (Features) **: Functional systems like Blog, News, Products, Jobs, References. ** RULE **: Describe exactly 1 thing if qty is 1. If qty is 0, DO NOT DESCRIBE THIS. +- ** Logik-Funktionen **: Logic modules like Search, Filter, Forms, PDF-Export. +- ** Schnittstellen (API) **: Data Syncs with CRM, ERP, Payment systems. +- ** Inhaltsverwaltung (CMS) **: Setup and mapping for CMS. +- ** Inszenierung & Interaktion **: Hero-stories, visual effects, configurators. +- ** Mehrsprachigkeit **: Architecture scaling for multiple languages. +- ** Inhaltliche Initial-Pflege **: Manual data entry / cleanup. +- ** Sorglos-Paket (Betrieb & Pflege) **: ** RULE **: Describe as "1 Jahr Sicherung des technischen Betriebs, Instandhaltung, Sicherheits-Updates und Inhalts-Aktualisierungen gemäß AGB Punkt 7a." ### RULES FOR positionDescriptions(STRICT): 1. ** ABSOLUTE RULE: NO FIRST PERSON **: NEVER use "Ich", "Mein", "Wir" or "Unser". Lead with nouns or passive verbs. @@ -574,7 +574,7 @@ ${requiredPositions.map(p => `"${p}"`).join(", ")} 7. ** ITEMIZED SYNTHESIS **: Mention EVERY component selected in Pass 1. 8. ** HARD SPECIFICS **: If the briefing mentions "Glasfaser-Trassen" or "Schwerlast-Logistik", IT MUST BE IN THE DESCRIPTION. 9. ** INDUSTRIAL AMBITION **: Describe it as a high-end technical solution. Avoid "schöne Website" or marketing fluff. -10. ** PAGES **: For "2. Individuelle Seiten", list the pages. ** ABSOLUTE RULE **: Do NOT add implementation details or technical notes in parentheses (e.g. NO "(Matrix-Struktur)", NO "(Timeline-Modul)"). Use clean titles like "Startseite, Über uns, Leistungen". +10. ** PAGES **: For "Individuelle Seiten", list the pages. ** ABSOLUTE RULE **: Do NOT add implementation details or technical notes in parentheses (e.g. NO "(Matrix-Struktur)", NO "(Timeline-Modul)"). Use clean titles like "Startseite, Über uns, Leistungen". 11. ** LOGIC **: Describe the ACTUAL logic (e.g., "Volltextsuche mit Auto-Complete", not "eine Suche"). 12. ** KEYS **: Return EXACTLY the keys defined in "POSITION TITLES". 13. ** NO AGB **: NEVER mention "AGB" or "Geschäftsbedingungen". @@ -591,7 +591,7 @@ ${JSON.stringify({ facts, details, strategy, ia }, null, 2)} ### OUTPUT FORMAT(Strict JSON): { - "positionDescriptions": { "1. Das technische Fundament": string, ... } + "positionDescriptions": { "Das technische Fundament": string, ... } } `; const p5Resp = await axios.post('https://openrouter.ai/api/v1/chat/completions', { diff --git a/src/components/pdf/modules/CommonModules.tsx b/src/components/pdf/modules/CommonModules.tsx index 80b9218..381fb7c 100644 --- a/src/components/pdf/modules/CommonModules.tsx +++ b/src/components/pdf/modules/CommonModules.tsx @@ -36,52 +36,52 @@ export const TransparenzModule = ({ pricing }: any) => ( - 1. Fundament + Fundament Setup, Infrastruktur, Hosting, SEO-Basics, Staging & Live-Umgebungen. {pricing.BASE_WEBSITE?.toLocaleString('de-DE')} € - 2. Seiten + Seiten Layout & Umsetzung individueller Seiten. Responsive Design / Cross-Browser. {pricing.PAGE?.toLocaleString('de-DE')} € / Stk - 3. Features + Features Abgeschlossene Systeme (z. B. Blog, Jobs, Produkte) inkl. Datenstruktur. {pricing.FEATURE?.toLocaleString('de-DE')} € / Stk - 4. Funktionen + Funktionen Logik-Einheiten wie Filter, Suchen oder Kontakt-Schnittstellen. {pricing.FUNCTION?.toLocaleString('de-DE')} € / Stk - 5. Schnittstellen + Schnittstellen Anbindung externer Systeme (CRM, ERP, Payment) zur Synchronisation. ab {pricing.API_INTEGRATION?.toLocaleString('de-DE')} € / Stk - 6. CMS Setup + CMS Setup Konfiguration Headless CMS zur unabhängigen Datenpflege aller Module. {pricing.CMS_SETUP?.toLocaleString('de-DE')} € - 7. Inszenierung + Inszenierung Interaktions-Mechanismen, Konfiguratoren oder visuelles Storytelling. ab {pricing.VISUAL_STAGING?.toLocaleString('de-DE')} € - 8. Sprachen + Sprachen Skalierung der System-Architektur auf zusätzliche Sprachversionen. +20% / Sprache - 9. Initial-Pflege + Initial-Pflege Manuelle Aufbereitung & Übernahme von Datensätzen in das Zielsystem. {pricing.NEW_DATASET?.toLocaleString('de-DE')} € / Stk - 10. Sorglos-Paket + Sorglos-Paket Betrieb, Hosting, Updates & Monitoring gemäß AGB Punkt 7a. Inklusive 1 Jahr diff --git a/src/logic/pricing/calculator.ts b/src/logic/pricing/calculator.ts index c550691..512df8c 100644 --- a/src/logic/pricing/calculator.ts +++ b/src/logic/pricing/calculator.ts @@ -69,7 +69,7 @@ export function calculatePositions(state: FormState, pricing: any): Position[] { if (state.projectType === 'website') { positions.push({ pos: pos++, - title: '1. Das technische Fundament', + title: 'Das technische Fundament', desc: 'Projekt-Setup, Infrastruktur, Hosting-Bereitstellung, Grundstruktur & Design-Vorlage, technisches SEO-Basics, Analytics.', qty: 1, price: pricing.BASE_WEBSITE @@ -92,7 +92,7 @@ export function calculatePositions(state: FormState, pricing: any): Position[] { positions.push({ pos: pos++, - title: '2. Individuelle Seiten', + title: 'Individuelle Seiten', desc: `Gestaltung und Umsetzung von ${totalPagesCount} individuellen Seiten-Layouts (${uniquePages.join(', ')}).`, qty: totalPagesCount, price: totalPagesCount * pricing.PAGE @@ -102,7 +102,7 @@ export function calculatePositions(state: FormState, pricing: any): Position[] { const allFeatures = [...state.features.map((f: string) => FEATURE_LABELS[f] || f), ...(state.otherFeatures || [])]; positions.push({ pos: pos++, - title: '3. System-Module (Features)', + title: 'System-Module (Features)', desc: `Implementierung funktionaler Bereiche: ${allFeatures.join(', ')}. Inklusive Datenstruktur und Darstellung.`, qty: allFeatures.length, price: allFeatures.length * pricing.FEATURE @@ -113,7 +113,7 @@ export function calculatePositions(state: FormState, pricing: any): Position[] { const allFunctions = [...state.functions.map((f: string) => FUNCTION_LABELS[f] || f), ...(state.otherFunctions || [])]; positions.push({ pos: pos++, - title: '4. Logik-Funktionen', + title: 'Logik-Funktionen', desc: `Implementierung technischer Logik: ${allFunctions.join(', ')}.`, qty: allFunctions.length, price: allFunctions.length * pricing.FUNCTION @@ -124,7 +124,7 @@ export function calculatePositions(state: FormState, pricing: any): Position[] { const allApis = [...state.apiSystems.map((a: string) => API_LABELS[a] || a), ...(state.otherTech || [])]; positions.push({ pos: pos++, - title: '5. Schnittstellen (API)', + title: 'Schnittstellen (API)', desc: `Anbindung externer Systeme zur Datensynchronisation: ${allApis.join(', ')}.`, qty: allApis.length, price: allApis.length * pricing.API_INTEGRATION @@ -135,7 +135,7 @@ export function calculatePositions(state: FormState, pricing: any): Position[] { const totalFeatures = state.features.length + (state.otherFeatures?.length || 0) + (state.otherFeaturesCount || 0); positions.push({ pos: pos++, - title: '6. Inhaltsverwaltung (CMS)', + title: 'Inhaltsverwaltung (CMS)', desc: 'Einrichtung eines Systems zur eigenständigen Pflege von Inhalten und Datensätzen.', qty: 1, price: pricing.CMS_SETUP + totalFeatures * pricing.CMS_CONNECTION_PER_FEATURE @@ -145,7 +145,7 @@ export function calculatePositions(state: FormState, pricing: any): Position[] { if (state.newDatasets > 0) { positions.push({ pos: pos++, - title: '9. Inhaltliche Initial-Pflege', + title: 'Inhaltliche Initial-Pflege', desc: `Manuelle Übernahme und Aufbereitung von ${state.newDatasets} Datensätzen (Produkte, Artikel) in das Zielsystem.`, qty: state.newDatasets, price: state.newDatasets * pricing.NEW_DATASET @@ -159,7 +159,7 @@ export function calculatePositions(state: FormState, pricing: any): Position[] { positions.push({ pos: pos++, - title: '7. Inszenierung & Interaktion', + title: 'Inszenierung & Interaktion', desc: `Umsetzung von ${totalCount} speziellen Sektionen, Hero-Stories oder Konfiguratoren zur Steigerung der Conversion.`, qty: totalCount, price: (vsCount * pricing.VISUAL_STAGING) + (ciCount * pricing.COMPLEX_INTERACTION) @@ -173,7 +173,7 @@ export function calculatePositions(state: FormState, pricing: any): Position[] { positions.push({ pos: pos++, - title: '8. Mehrsprachigkeit', + title: 'Mehrsprachigkeit', desc: `Erweiterung des Systems auf ${languagesCount} Sprachen (Struktur & Logik).`, qty: languagesCount, price: Math.round(factorPrice) @@ -183,7 +183,7 @@ export function calculatePositions(state: FormState, pricing: any): Position[] { const monthlyRate = pricing.HOSTING_MONTHLY + (state.storageExpansion * pricing.STORAGE_EXPANSION_MONTHLY); positions.push({ pos: pos++, - title: '10. Sorglos-Paket (Betrieb & Pflege)', + title: 'Sorglos-Paket (Betrieb & Pflege)', desc: `1 Jahr Sicherung des technischen Betriebs, Instandhaltung, Sicherheits-Updates und Inhalts-Aktualisierungen gemäß AGB Punkt 7a.`, qty: 1, price: monthlyRate * 12 diff --git a/storage/key_value_stores/default/SDK_CRAWLER_STATISTICS_0.json b/storage/key_value_stores/default/SDK_CRAWLER_STATISTICS_0.json index c8f1fd5..01d274b 100644 --- a/storage/key_value_stores/default/SDK_CRAWLER_STATISTICS_0.json +++ b/storage/key_value_stores/default/SDK_CRAWLER_STATISTICS_0.json @@ -3,23 +3,23 @@ "requestsFailed": 0, "requestsRetries": 0, "requestsFailedPerMinute": 0, - "requestsFinishedPerMinute": 596, - "requestMinDurationMillis": 72, - "requestMaxDurationMillis": 503, + "requestsFinishedPerMinute": 542, + "requestMinDurationMillis": 73, + "requestMaxDurationMillis": 500, "requestTotalFailedDurationMillis": 0, - "requestTotalFinishedDurationMillis": 1167, - "crawlerStartedAt": "2026-02-05T00:44:22.537Z", - "crawlerFinishedAt": "2026-02-05T00:44:23.230Z", - "statsPersistedAt": "2026-02-05T00:44:23.230Z", - "crawlerRuntimeMillis": 705, - "crawlerLastStartTimestamp": 1770252262525, + "requestTotalFinishedDurationMillis": 1181, + "crawlerStartedAt": "2026-02-05T00:53:55.409Z", + "crawlerFinishedAt": "2026-02-05T00:53:56.171Z", + "statsPersistedAt": "2026-02-05T00:53:56.171Z", + "crawlerRuntimeMillis": 775, + "crawlerLastStartTimestamp": 1770252835396, "requestRetryHistogram": [ 7 ], "statsId": 0, "requestAvgFailedDurationMillis": null, - "requestAvgFinishedDurationMillis": 167, - "requestTotalDurationMillis": 1167, + "requestAvgFinishedDurationMillis": 169, + "requestTotalDurationMillis": 1181, "requestsTotal": 7, "requestsWithStatusCode": {}, "errors": {}, diff --git a/storage/key_value_stores/default/SDK_SESSION_POOL_STATE.json b/storage/key_value_stores/default/SDK_SESSION_POOL_STATE.json index 769857f..aec3b2c 100644 --- a/storage/key_value_stores/default/SDK_SESSION_POOL_STATE.json +++ b/storage/key_value_stores/default/SDK_SESSION_POOL_STATE.json @@ -3,7 +3,7 @@ "retiredSessionsCount": 0, "sessions": [ { - "id": "session_MKcXTj8jBY", + "id": "session_Uo8m4zZ2R9", "cookieJar": { "version": "tough-cookie@6.0.0", "storeType": "MemoryCookieStore", @@ -16,14 +16,14 @@ "userData": {}, "maxErrorScore": 3, "errorScoreDecrement": 0.5, - "expiresAt": "2026-02-05T01:34:22.574Z", - "createdAt": "2026-02-05T00:44:22.574Z", + "expiresAt": "2026-02-05T01:43:55.447Z", + "createdAt": "2026-02-05T00:53:55.447Z", "usageCount": 1, "maxUsageCount": 50, "errorScore": 0 }, { - "id": "session_CzBvH8k5d6", + "id": "session_giHbwcUnUR", "cookieJar": { "version": "tough-cookie@6.0.0", "storeType": "MemoryCookieStore", @@ -36,14 +36,14 @@ "userData": {}, "maxErrorScore": 3, "errorScoreDecrement": 0.5, - "expiresAt": "2026-02-05T01:34:23.083Z", - "createdAt": "2026-02-05T00:44:23.083Z", + "expiresAt": "2026-02-05T01:43:55.951Z", + "createdAt": "2026-02-05T00:53:55.951Z", "usageCount": 1, "maxUsageCount": 50, "errorScore": 0 }, { - "id": "session_6tYd3j1pzA", + "id": "session_a1xAz6qUbx", "cookieJar": { "version": "tough-cookie@6.0.0", "storeType": "MemoryCookieStore", @@ -56,14 +56,14 @@ "userData": {}, "maxErrorScore": 3, "errorScoreDecrement": 0.5, - "expiresAt": "2026-02-05T01:34:23.085Z", - "createdAt": "2026-02-05T00:44:23.085Z", + "expiresAt": "2026-02-05T01:43:55.952Z", + "createdAt": "2026-02-05T00:53:55.952Z", "usageCount": 1, "maxUsageCount": 50, "errorScore": 0 }, { - "id": "session_MahMPRKWfS", + "id": "session_a1nkjT4C2O", "cookieJar": { "version": "tough-cookie@6.0.0", "storeType": "MemoryCookieStore", @@ -76,14 +76,14 @@ "userData": {}, "maxErrorScore": 3, "errorScoreDecrement": 0.5, - "expiresAt": "2026-02-05T01:34:23.086Z", - "createdAt": "2026-02-05T00:44:23.086Z", + "expiresAt": "2026-02-05T01:43:55.954Z", + "createdAt": "2026-02-05T00:53:55.954Z", "usageCount": 1, "maxUsageCount": 50, "errorScore": 0 }, { - "id": "session_POCFcWGlXP", + "id": "session_K2iOQY8LPb", "cookieJar": { "version": "tough-cookie@6.0.0", "storeType": "MemoryCookieStore", @@ -96,14 +96,14 @@ "userData": {}, "maxErrorScore": 3, "errorScoreDecrement": 0.5, - "expiresAt": "2026-02-05T01:34:23.087Z", - "createdAt": "2026-02-05T00:44:23.087Z", + "expiresAt": "2026-02-05T01:43:55.956Z", + "createdAt": "2026-02-05T00:53:55.956Z", "usageCount": 1, "maxUsageCount": 50, "errorScore": 0 }, { - "id": "session_zra0Syci00", + "id": "session_NeZlnTbttx", "cookieJar": { "version": "tough-cookie@6.0.0", "storeType": "MemoryCookieStore", @@ -116,14 +116,14 @@ "userData": {}, "maxErrorScore": 3, "errorScoreDecrement": 0.5, - "expiresAt": "2026-02-05T01:34:23.088Z", - "createdAt": "2026-02-05T00:44:23.088Z", + "expiresAt": "2026-02-05T01:43:55.957Z", + "createdAt": "2026-02-05T00:53:55.957Z", "usageCount": 1, "maxUsageCount": 50, "errorScore": 0 }, { - "id": "session_JbCC8UIBHk", + "id": "session_NnTheV32tc", "cookieJar": { "version": "tough-cookie@6.0.0", "storeType": "MemoryCookieStore", @@ -136,8 +136,8 @@ "userData": {}, "maxErrorScore": 3, "errorScoreDecrement": 0.5, - "expiresAt": "2026-02-05T01:34:23.092Z", - "createdAt": "2026-02-05T00:44:23.092Z", + "expiresAt": "2026-02-05T01:43:55.961Z", + "createdAt": "2026-02-05T00:53:55.961Z", "usageCount": 1, "maxUsageCount": 50, "errorScore": 0