refactor: Remove numerical prefixes from pricing calculator position titles.
Some checks failed
Build & Deploy Mintel Blog / build-and-deploy (push) Failing after 28s

This commit is contained in:
2026-02-05 10:42:47 +01:00
parent c5ad6108ee
commit 190720ad92
5 changed files with 74 additions and 74 deletions

View File

@@ -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', {

View File

@@ -36,52 +36,52 @@ export const TransparenzModule = ({ pricing }: any) => (
<PDFView style={styles.section}>
<PDFView style={styles.pricingGrid}>
<PDFView style={styles.pricingRow}>
<PDFText style={styles.pricingTitle}>1. Fundament</PDFText>
<PDFText style={styles.pricingTitle}>Fundament</PDFText>
<PDFText style={styles.pricingDesc}>Setup, Infrastruktur, Hosting, SEO-Basics, Staging & Live-Umgebungen.</PDFText>
<PDFText style={styles.pricingTag}>{pricing.BASE_WEBSITE?.toLocaleString('de-DE')} </PDFText>
</PDFView>
<PDFView style={styles.pricingRow}>
<PDFText style={styles.pricingTitle}>2. Seiten</PDFText>
<PDFText style={styles.pricingTitle}>Seiten</PDFText>
<PDFText style={styles.pricingDesc}>Layout & Umsetzung individueller Seiten. Responsive Design / Cross-Browser.</PDFText>
<PDFText style={styles.pricingTag}>{pricing.PAGE?.toLocaleString('de-DE')} / Stk</PDFText>
</PDFView>
<PDFView style={styles.pricingRow}>
<PDFText style={styles.pricingTitle}>3. Features</PDFText>
<PDFText style={styles.pricingTitle}>Features</PDFText>
<PDFText style={styles.pricingDesc}>Abgeschlossene Systeme (z. B. Blog, Jobs, Produkte) inkl. Datenstruktur.</PDFText>
<PDFText style={styles.pricingTag}>{pricing.FEATURE?.toLocaleString('de-DE')} / Stk</PDFText>
</PDFView>
<PDFView style={styles.pricingRow}>
<PDFText style={styles.pricingTitle}>4. Funktionen</PDFText>
<PDFText style={styles.pricingTitle}>Funktionen</PDFText>
<PDFText style={styles.pricingDesc}>Logik-Einheiten wie Filter, Suchen oder Kontakt-Schnittstellen.</PDFText>
<PDFText style={styles.pricingTag}>{pricing.FUNCTION?.toLocaleString('de-DE')} / Stk</PDFText>
</PDFView>
<PDFView style={styles.pricingRow}>
<PDFText style={styles.pricingTitle}>5. Schnittstellen</PDFText>
<PDFText style={styles.pricingTitle}>Schnittstellen</PDFText>
<PDFText style={styles.pricingDesc}>Anbindung externer Systeme (CRM, ERP, Payment) zur Synchronisation.</PDFText>
<PDFText style={styles.pricingTag}>ab {pricing.API_INTEGRATION?.toLocaleString('de-DE')} / Stk</PDFText>
</PDFView>
<PDFView style={styles.pricingRow}>
<PDFText style={styles.pricingTitle}>6. CMS Setup</PDFText>
<PDFText style={styles.pricingTitle}>CMS Setup</PDFText>
<PDFText style={styles.pricingDesc}>Konfiguration Headless CMS zur unabhängigen Datenpflege aller Module.</PDFText>
<PDFText style={pricing.CMS_SETUP ? styles.pricingTag : [styles.pricingTag, { color: COLORS.TEXT_LIGHT }]}>{pricing.CMS_SETUP?.toLocaleString('de-DE')} </PDFText>
</PDFView>
<PDFView style={styles.pricingRow}>
<PDFText style={styles.pricingTitle}>7. Inszenierung</PDFText>
<PDFText style={styles.pricingTitle}>Inszenierung</PDFText>
<PDFText style={styles.pricingDesc}>Interaktions-Mechanismen, Konfiguratoren oder visuelles Storytelling.</PDFText>
<PDFText style={styles.pricingTag}>ab {pricing.VISUAL_STAGING?.toLocaleString('de-DE')} </PDFText>
</PDFView>
<PDFView style={styles.pricingRow}>
<PDFText style={styles.pricingTitle}>8. Sprachen</PDFText>
<PDFText style={styles.pricingTitle}>Sprachen</PDFText>
<PDFText style={styles.pricingDesc}>Skalierung der System-Architektur auf zusätzliche Sprachversionen.</PDFText>
<PDFText style={styles.pricingTag}>+20% / Sprache</PDFText>
</PDFView>
<PDFView style={styles.pricingRow}>
<PDFText style={styles.pricingTitle}>9. Initial-Pflege</PDFText>
<PDFText style={styles.pricingTitle}>Initial-Pflege</PDFText>
<PDFText style={styles.pricingDesc}>Manuelle Aufbereitung & Übernahme von Datensätzen in das Zielsystem.</PDFText>
<PDFText style={styles.pricingTag}>{pricing.NEW_DATASET?.toLocaleString('de-DE')} / Stk</PDFText>
</PDFView>
<PDFView style={styles.pricingRow}>
<PDFText style={styles.pricingTitle}>10. Sorglos-Paket</PDFText>
<PDFText style={styles.pricingTitle}>Sorglos-Paket</PDFText>
<PDFText style={styles.pricingDesc}>Betrieb, Hosting, Updates & Monitoring gemäß AGB Punkt 7a.</PDFText>
<PDFText style={styles.pricingTag}>Inklusive 1 Jahr</PDFText>
</PDFView>

View File

@@ -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

View File

@@ -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": {},

View File

@@ -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