content: replace scaffolding with bilingual pages and case studies

Ship the final German and English copy, compose every route from shared page primitives, and cover claims, parity and contact briefing in tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-25 17:34:04 +02:00
parent 9ea2885c7b
commit d954361724
95 changed files with 4161 additions and 419 deletions

View File

@@ -0,0 +1,82 @@
import { APP_LOCALES } from '../i18n/locale';
import {
CASE_STUDY_IDS,
type CaseStudyCopy,
type MetricCopy,
type OfferingCopy,
type SiteContent,
} from './content.contracts';
import { SITE_CONTENT_DATA } from './site-content';
const DELIVERED_OFFER_WORDING =
/für kunden umgesetzt|im kundeneinsatz|in production for clients|delivered for clients|langjährige erfahrung mit rag|years of rag/i;
function allMetrics(site: SiteContent): readonly MetricCopy[] {
return [...site.home.metrics, ...CASE_STUDY_IDS.flatMap((id) => site.cases[id].metrics)];
}
function allOfferings(site: SiteContent): readonly OfferingCopy[] {
return Object.values(site.services).flatMap((page) => page.offerings);
}
function caseText(caseStudy: CaseStudyCopy): string {
return [
caseStudy.summary,
caseStudy.responsibility,
caseStudy.situation,
...caseStudy.approach,
...caseStudy.outcome,
...caseStudy.metrics.map((metric) => `${metric.value} ${metric.label} ${metric.note ?? ''}`),
].join('\n');
}
describe('content claims and attribution', () => {
it('keeps the four public cases and attributes verified facts to the right ones', () => {
for (const locale of APP_LOCALES) {
const site = SITE_CONTENT_DATA[locale];
expect(Object.keys(site.cases)).toEqual([...CASE_STUDY_IDS]);
expect(CASE_STUDY_IDS).toEqual(['innofocus', 'roesterei', 'myspa', 'hdi']);
const runtimeMetrics = allMetrics(site).filter(
(metric) => /8/.test(metric.value) && /90/.test(metric.value),
);
expect(runtimeMetrics).toHaveLength(1);
expect(runtimeMetrics[0]?.caseId).toBe('innofocus');
const leadershipMetrics = allMetrics(site).filter(
(metric) =>
metric.caseId === 'myspa' &&
/4/.test(`${metric.value} ${metric.label}`) &&
/2/.test(`${metric.value} ${metric.label}`),
);
expect(leadershipMetrics.length).toBeGreaterThan(0);
const hdiText = caseText(site.cases.hdi);
expect(hdiText).toMatch(/Azure AKS/);
expect(hdiText).toMatch(/Azure App Services/);
for (const caseId of CASE_STUDY_IDS.filter((id) => id !== 'hdi')) {
expect(caseText(site.cases[caseId])).not.toMatch(/Azure App Services/);
}
}
});
it('keeps AI delivery claims limited to the two Rösterei tools', () => {
for (const locale of APP_LOCALES) {
const site = SITE_CONTENT_DATA[locale];
const aiOfferings = site.services.servicesAi.offerings;
const delivered = aiOfferings.filter((offering) => offering.status === 'delivered');
expect(delivered).toHaveLength(2);
expect(delivered.every((offering) => offering.referenceCaseId === 'roesterei')).toBe(true);
const otherOfferings = allOfferings(site).filter((offering) => !delivered.includes(offering));
expect(otherOfferings.every((offering) => offering.status === 'offer')).toBe(true);
expect(
otherOfferings.some((offering) =>
DELIVERED_OFFER_WORDING.test(`${offering.title} ${offering.body}`),
),
).toBe(false);
}
});
});