feat: add MSP and internal IT use-case pages (#402)

Implements website feature branch `407-msp-mittelstand-use-case-pages` into `website-dev`.

Summary:
- add German and English MSP and internal IT use-case landing pages
- expose localized buyer-path teasers from the homepage and platform page
- extend smoke coverage for the new routes, navigation links, metadata, and conservative claim checks
- include the aligned Spec Kit artifacts under `specs/407-msp-mittelstand-use-case-pages`

Validation:
- `cd apps/website && corepack pnpm build`
- `cd apps/website && corepack pnpm test -- tests/smoke/public-routes.spec.ts tests/smoke/interaction.spec.ts`

Follow-up integration path after merge:

`website-dev` -> `dev`.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #402
This commit is contained in:
ahmido 2026-05-27 22:02:42 +00:00
parent 09dc9988cb
commit 94cff6ca03
14 changed files with 3221 additions and 4 deletions

View File

@ -77,6 +77,51 @@ const copy = siteCopy[locale].home;
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.useCasesTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.useCasesSubtitle}
</p>
</div>
</div>
<div class="mt-8 grid gap-6 lg:grid-cols-2">
{
copy.useCases.map((useCase: any) => (
<article class="rounded-[2rem] border border-neutral-300 bg-linear-to-br from-neutral-100 to-yellow-100/60 p-6 shadow-xs dark:border-neutral-700 dark:from-neutral-900 dark:to-neutral-800">
<p class="text-xs font-semibold tracking-[0.22em] text-neutral-500 uppercase dark:text-neutral-400">
{useCase.eyebrow}
</p>
<h3 class="mt-4 text-2xl font-semibold text-balance text-neutral-800 dark:text-neutral-200">
{useCase.title}
</h3>
<p class="mt-4 max-w-prose text-pretty text-neutral-600 dark:text-neutral-400">
{useCase.content}
</p>
<div class="mt-6">
<SecondaryCTA
title={useCase.cta}
url={localizeHref(useCase.href, locale)}
/>
</div>
</article>
))
}
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>

View File

@ -4,6 +4,7 @@ import MainSection from '@components/ui/blocks/MainSection.astro';
import LeftSection from '@components/ui/blocks/LeftSection.astro';
import RightSection from '@components/ui/blocks/RightSection.astro';
import FeaturesStats from '@components/sections/features/FeaturesStats.astro';
import SecondaryCTA from '@components/ui/buttons/SecondaryCTA.astro';
import dashboard from '@images/tenantial-dashboard.avif';
import evidenceImage from '@images/tenantial-evidence-panel.avif';
import reviewImage from '@images/tenantial-drift-workflow.avif';
@ -57,12 +58,18 @@ const canonicalPath = localizedPath('/platform', locale);
btnURL={localizeHref('/contact', locale)}
/>
<section class="mx-auto max-w-[85rem] px-4 py-4 sm:px-6 lg:px-8 lg:py-8 2xl:max-w-full">
<section
class="mx-auto max-w-[85rem] px-4 py-4 sm:px-6 lg:px-8 lg:py-8 2xl:max-w-full"
>
<div class="max-w-(--breakpoint-md)">
<h2 class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.focusTitle}
</h2>
<p class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400">
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.focusSubtitle}
</p>
</div>
@ -83,6 +90,48 @@ const canonicalPath = localizedPath('/platform', locale);
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-4 sm:px-6 lg:px-8 lg:py-8 2xl:max-w-full"
>
<div
class="rounded-[2rem] border border-neutral-300 bg-neutral-100/80 p-6 md:p-10 dark:border-neutral-700 dark:bg-white/[0.05]"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.useCasesTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.useCasesSubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-2">
{
copy.useCases.map((useCase: any) => (
<article class="rounded-2xl bg-neutral-200/80 p-5 dark:bg-neutral-900/70">
<h3 class="text-base font-semibold text-neutral-800 dark:text-neutral-200">
{useCase.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{useCase.content}
</p>
<div class="mt-5">
<SecondaryCTA
title={useCase.cta}
url={localizeHref(useCase.href, locale)}
/>
</div>
</article>
))
}
</div>
</div>
</section>
<RightSection
title={copy.backupTitle}
subTitle={copy.backupSubtitle}

View File

@ -44,6 +44,8 @@ export const siteCopy: Record<Locale, any> = {
nav: [
{ name: 'Start', url: '/' },
{ name: 'Plattform', url: '/platform' },
{ name: 'MSPs', url: '/use-cases/msp' },
{ name: 'Interne IT', url: '/use-cases/mittelstand' },
{ name: 'Preise', url: '/pricing' },
{ name: 'Vertrauen', url: '/trust' },
{ name: 'Docs', url: '/welcome-to-docs/' },
@ -55,6 +57,8 @@ export const siteCopy: Record<Locale, any> = {
section: 'Produkt',
links: [
{ name: 'Plattform', url: '/platform' },
{ name: 'MSPs', url: '/use-cases/msp' },
{ name: 'Interne IT', url: '/use-cases/mittelstand' },
{ name: 'Preise', url: '/pricing' },
{ name: 'Vertrauen', url: '/trust' },
{ name: 'Docs', url: '/welcome-to-docs/' },
@ -117,6 +121,27 @@ export const siteCopy: Record<Locale, any> = {
'Evidence, Findings und Accepted Risks in prüfbare Review-Unterlagen überführen.',
},
],
useCasesTitle: 'Buyer-Pfade, die schneller zur richtigen Frage führen.',
useCasesSubtitle:
'Ob MSP oder interne IT: Tenantial verbindet Microsoft 365 Governance mit einem klaren Review-, Evidence- und Follow-up-Modell.',
useCases: [
{
eyebrow: 'Für MSPs',
title: 'Wiederholbare Governance-Services pro Kunde aufbauen',
content:
'Zeige MSPs, wie Tenantial Reviews, Evidence, Drift und Accepted Risks pro Kundenumgebung in einen wiederholbaren Ablauf bringt.',
cta: 'MSP-Use-Case ansehen',
href: '/use-cases/msp',
},
{
eyebrow: 'Für interne IT',
title: 'Kontrolle, Evidence und Audit-Kontext zusammenhalten',
content:
'Zeige internen Teams, wie Tenantial Policy-Drift, Change-Kontext, Backups und Review-Vorbereitung für Microsoft 365 lesbar macht.',
cta: 'Interne IT ansehen',
href: '/use-cases/mittelstand',
},
],
boundaryTitle: 'Gebaut für Governance. Nicht für blinde Automatisierung.',
boundarySubtitle:
'Tenantial ersetzt nicht das Microsoft Admin Center. Es ergänzt es um die Schicht, die Enterprise-Teams im Alltag fehlt: Versionierung, Evidence, Drift-Sichtbarkeit, Review-Kontext und auditierbare Entscheidungen.',
@ -154,6 +179,350 @@ export const siteCopy: Record<Locale, any> = {
finalSecondaryCta: 'Plattform ansehen',
faqTitle: 'Häufige<br />Fragen',
},
useCases: {
msp: {
pageTitle: 'MSP Governance Reviews | Tenantial',
metaDescription:
'Microsoft 365 Governance fuer MSPs mit wiederholbaren Reviews, Evidence, versionierten Backups, Accepted Risks und sauberem Follow-up.',
heroTitle:
'<span class="text-yellow-500 dark:text-yellow-400">Microsoft 365 Governance</span> fuer MSPs, die wiederholbare Reviews liefern wollen.',
heroSubtitle:
'Tenantial macht aus manuellen Tenant-Checks, Screenshots und Excel-Listen einen kontrollierten Governance-Ablauf fuer Kundenumgebungen.',
supportingLine:
'Mehr Microsoft 365 Governance pro Kunde - mit Review Packs, Evidence, Drift-Sichtbarkeit und sauberem Follow-up statt Einmalprojekten.',
primaryCta: 'MSP-Demo buchen',
secondaryCta: 'Plattform ansehen',
heroAlt: 'Statische Tenantial MSP Governance-Vorschau',
painTitle: 'Wo MSP-Governance heute stecken bleibt',
painSubtitle:
'MSPs brauchen keine weitere Admin-Oberflaeche. Sie brauchen einen Ablauf, mit dem Reviews, Evidence und Nachverfolgung pro Kunde wiederholbar werden.',
painCards: [
{
title: 'Manuelle Review-Schleifen',
content:
'Operatoren sammeln Screenshots, Export-Fragmente und Einzelnotizen, statt einen stabilen Governance-Review pro Kunde aufzubauen.',
},
{
title: 'Versteckter Policy-Drift',
content:
'Wenn Aenderungen zwischen Review-Terminen nicht sichtbar bleiben, werden Ausnahmen und Risiken erst spaet erkannt.',
},
{
title: 'Schwache Kunden-Evidence',
content:
'Ohne nachvollziehbare Evidence wird aus jeder Kundenbesprechung eine Diskussion ueber Quellen statt ueber Entscheidungen.',
},
{
title: 'Kein wiederholbares Service-Paket',
content:
'Governance bleibt Personenwissen, solange Follow-up, Accepted Risks und Review-Kontext nicht in denselben Ablauf fallen.',
},
],
outcomeTitle: 'Was das fuer das MSP-Modell veraendert',
outcomeSubtitle:
'Tenantial positioniert Governance als wiederholbaren Service-Layer fuer Microsoft 365 statt als lose Sammlung manueller Kundenchecks.',
outcomeCards: [
{
title: 'Review Packs pro Kunde',
content:
'Policy-Zustand, Evidence, Findings und Accepted Risks bleiben in einer lesbaren Review-Grundlage zusammen.',
},
{
title: 'Mehrere Kunden unter Kontrolle',
content:
'MSPs koennen Konfigurationsstaende, Drift und Nachverfolgung pro Kundenumgebung kontrollierter vorbereiten.',
},
{
title: 'Audit-faehige Evidence',
content:
'Reviews basieren auf nachvollziehbaren Konfigurations- und Entscheidungsdaten statt auf Einzel-Screenshots.',
},
{
title: 'Sauberes Follow-up',
content:
'Offene Findings, Accepted Risks und naechste Schritte bleiben sichtbar, bis sie bewusst geklaert sind.',
},
],
workflowTitle: 'Ein wiederholbarer Governance-Ablauf',
workflowSubtitle:
'Die Story fuer MSPs ist nicht Automatisierung um jeden Preis, sondern ein reproduzierbarer Review- und Evidence-Prozess fuer Kundenumgebungen.',
workflowSteps: [
{
step: '01',
title: 'Policy-Zustand sichern',
content:
'Versionierte Backups halten fest, welcher Konfigurationsstand fuer den naechsten Kundenreview relevant ist.',
},
{
step: '02',
title: 'Drift sichtbar machen',
content:
'Aenderungen zwischen bekannten Staenden werden lesbar, bevor sie in Kundenreviews uebersehen werden.',
},
{
step: '03',
title: 'Evidence buendeln',
content:
'Konfigurationsnachweise, Findings und Kontext werden in einer Review-Basis zusammengezogen.',
},
{
step: '04',
title: 'Risiken klassifizieren',
content:
'Accepted Risks und offene Fragen bleiben als bewusste Entscheidungen sichtbar statt in Tickets zu verschwinden.',
},
{
step: '05',
title: 'Review-Kontext vorbereiten',
content:
'Vor dem Kundentermin ist klar, was sich geaendert hat, was akzeptiert wurde und wo Follow-up noetig bleibt.',
},
{
step: '06',
title: 'Follow-up sichtbar halten',
content:
'Naechste Schritte bleiben an Evidence und Entscheidungen gekoppelt, bis der Governance-Zyklus geschlossen ist.',
},
],
capabilityTitle: 'Was Tenantial im MSP-Kontext liefert',
capabilitySubtitle:
'Die Plattform verkauft keine generische MSP-Suite. Sie liefert den Governance-Layer fuer Microsoft 365 Reviews, Evidence und Nachvollziehbarkeit.',
capabilityCards: [
{
title: 'Governance Reviews',
content:
'Wiederholbare Review-Strukturen fuer Kundenumgebungen mit sichtbaren Findings und Entscheidungsstand.',
},
{
title: 'Policy Backup & Versionierung',
content:
'Konfigurationsstaende bleiben historisch vergleichbar statt nur als letzte Momentaufnahme erhalten.',
},
{
title: 'Drift-Sichtbarkeit',
content:
'Drift wird als Review-Arbeit fuer MSP-Teams aufbereitet und nicht als unsichtbarer Seiteneffekt behandelt.',
},
{
title: 'Accepted-Risk-Transparenz',
content:
'Akzeptierte Risiken bleiben fuer Kunden, Operatoren und Review-Kontext nachvollziehbar.',
},
{
title: 'Audit-Evidence',
content:
'Evidence bleibt an Policy-Stand, Findings und Review-Entscheidungen gekoppelt.',
},
{
title: 'PSA-Handoff-Grenze',
content:
'Tenantial klaert Governance und Evidence. Das eigentliche Ticketing oder PSA-System bleibt bewusst ausserhalb.',
},
],
boundaryTitle: 'Klare Grenzen zur PSA- und Helpdesk-Welt',
boundarySubtitle:
'Tenantial ist kein PSA, kein Ticketing-System, keine generische Helpdesk-Suite und keine blinde Remediation-Engine.',
boundaryCards: [
{
title: 'Nicht die PSA ersetzen',
content:
'Tenantial dokumentiert Governance-Kontext, aber fuehrt keine komplette Service-Desk- oder Ticket-Organisation aus.',
},
{
title: 'Nicht blind remediieren',
content:
'Die Seite verspricht keine automatische Korrektur oder autonome Durchsetzung von Policies.',
},
{
title: 'Nicht Intune-only',
content:
'Intune ist der erste starke Policy-Fokus, aber die Story bleibt Microsoft 365 Governance und nicht nur ein Backup-Werkzeug.',
},
],
trustTeaserTitle: 'Trust-Fragen bleiben sauber anschlussfaehig',
trustTeaserSubtitle:
'Wenn Kunden nach Datenschutz, Security oder Dokumentenstatus fragen, bleibt die Antwort auf die bestehende Trust-Haltung verankert statt in Marketing-Uebertreibung abzudriften.',
trustTeaserCta: 'Trust-Haltung ansehen',
trustPoints: [
'Provider-Berechtigungen und Grenzen bleiben erklaert',
'DPA-, TOM- und Sicherheitsfragen bleiben ueber echte Handoffs anschlussfaehig',
'Keine Fake-Zertifikate, keine Fake-Proof-Downloads, keine ueberzogenen Compliance-Versprechen',
],
finalCtaTitle: 'Governance-Services statt Einmalprojekte verkaufen',
finalCtaSubtitle:
'In einer fokussierten Demo zeigt Tenantial, wie MSPs Reviews, Evidence, Backups und Follow-up pro Kunde strukturierter vorbereiten koennen.',
finalPrimaryCta: 'MSP-Demo buchen',
finalSecondaryCta: 'Plattform ansehen',
},
mittelstand: {
pageTitle:
'Microsoft 365 Governance fuer Mittelstand & Enterprise IT | Tenantial',
metaDescription:
'Microsoft 365 Governance fuer interne IT mit Policy-Drift, nachvollziehbaren Changes, Evidence, Backups, Reviews und kontrollierter Recovery-Vorbereitung.',
heroTitle:
'<span class="text-yellow-500 dark:text-yellow-400">Kontrolle und Evidence</span> fuer interne Microsoft 365 Teams.',
heroSubtitle:
'Tenantial hilft IT-Leitung, Security, Audit und Operations, Policy-Drift, Change-Kontext und Recovery-Fragen nachvollziehbar auf einer gemeinsamen Governance-Oberflaeche zu halten.',
supportingLine:
'Wenn interne Microsoft 365 Changes reviewfaehig bleiben muessen, reicht ein Admin Center allein nicht mehr aus.',
primaryCta: 'Governance-Demo buchen',
secondaryCta: 'Plattform ansehen',
heroAlt: 'Statische Tenantial Enterprise Governance-Vorschau',
painTitle: 'Wo interne Kontrolle heute Reibung erzeugt',
painSubtitle:
'Interne IT-Teams verlieren Zeit, wenn Change-Nachweise, Evidence und Recovery-Kontext zwischen Screenshots, Exporten und Einzelnotizen zerfallen.',
painCards: [
{
title: 'Undokumentierte Changes',
content:
'Aenderungen an Policies bleiben oft nur im Admin Center sichtbar und verlieren schnell ihren Entscheidungs- und Review-Kontext.',
},
{
title: 'Audit-Druck vor Reviews',
content:
'Kurz vor Audits oder internen Reviews muss Evidence hektisch aus mehreren Quellen zusammengesucht werden.',
},
{
title: 'Unsichere Recovery-Fragen',
content:
'Wenn Konfigurationsstaende fehlen oder nicht vergleichbar bleiben, wird jede Recovery-Entscheidung riskanter.',
},
{
title: 'Screenshot- und Export-Prozesse',
content:
'Governance wird unnoetig fragil, wenn die Grundlage fuer Entscheidungen aus verstreuten Exporten und Dateien besteht.',
},
],
outcomeTitle: 'Was interne Teams dadurch gewinnen',
outcomeSubtitle:
'Tenantial verkauft keine neue Admin-Oberflaeche, sondern den Governance-Layer fuer nachvollziehbare Changes, Evidence und Review-Kontext.',
outcomeCards: [
{
title: 'Policy-Drift sichtbar machen',
content:
'Teams erkennen frueher, welche Konfigurationen sich zwischen bekannten Staenden veraendert haben.',
},
{
title: 'Changes nachvollziehbar halten',
content:
'Aenderungen, Findings und Accepted Risks bleiben mit Entscheidungs- und Review-Kontext verknuepft.',
},
{
title: 'Evidence fuer Reviews vorbereiten',
content:
'Audit-faehige Nachweise bleiben lesbar, statt kurz vor Reviews manuell zusammengesucht zu werden.',
},
{
title: 'Recovery defensiv bewerten',
content:
'Backups und bekannte Konfigurationsstaende schaffen eine bessere Grundlage fuer kontrollierte Recovery-Vorbereitung.',
},
],
stakeholderTitle: 'Ein Surface fuer vier Blickwinkel',
stakeholderSubtitle:
'Die gleiche Governance-Oberflaeche unterstuetzt interne Rollen unterschiedlich, ohne in vier getrennte Tool-Stories zu zerfallen.',
stakeholderCards: [
{
title: 'IT Operations',
content:
'Braucht Klarheit ueber aktuelle Konfigurationsstaende, Drift und den naechsten sicheren Schritt.',
},
{
title: 'Security',
content:
'Will Evidence, Findings und Accepted Risks mit sichtbarer Begruendung statt Bauchgefuehl.',
},
{
title: 'IT-Leitung',
content:
'Benötigt nachvollziehbare Entscheidungslagen fuer Priorisierung, Rollout-Risiken und Governance-Reife.',
},
{
title: 'Audit / Datenschutz',
content:
'Braucht Review-konforme Nachweise, Status und belastbare Grenzen ohne ueberzogene Compliance-Versprechen.',
},
],
workflowTitle: 'Ein kontrollierter Ablauf fuer interne Governance',
workflowSubtitle:
'Tenantial fuehrt nicht autonom aus. Es schafft einen lesbaren Ablauf von Zustand, Drift, Evidence, Risiko und naechster Entscheidung.',
workflowSteps: [
{
step: '01',
title: 'Zustand sichern',
content:
'Bekannte Policy-Staende bleiben ueber versionierte Backups und Vergleichspunkte nachvollziehbar.',
},
{
step: '02',
title: 'Drift erkennen',
content:
'Abweichungen zwischen bekannten Konfigurationsstaenden werden lesbar, bevor sie im Tagesgeschaeft untergehen.',
},
{
step: '03',
title: 'Evidence vorbereiten',
content:
'Changes, Findings und Nachweise werden fuer Reviews und interne Abstimmung in einen gemeinsamen Kontext gebracht.',
},
{
step: '04',
title: 'Risiko bewerten',
content:
'Accepted Risks und offene Fragen bleiben bewusst dokumentiert, statt implizit akzeptiert zu werden.',
},
{
step: '05',
title: 'Recovery-Kontext pruefen',
content:
'Vor sensiblen Schritten bleibt sichtbar, welcher Stand abgesichert ist und welche Grenzen fuer Recovery gelten.',
},
{
step: '06',
title: 'Naechste Entscheidung festhalten',
content:
'Follow-up bleibt mit Evidence und Review-Kontext verbunden, bis die Entscheidung sauber abgeschlossen ist.',
},
],
differentiationTitle:
'Nicht noch ein Admin Center. Nicht noch ein Helpdesk.',
differentiationSubtitle:
'Tenantial sitzt oberhalb der operativen Microsoft-Oberflaechen und unterstuetzt Governance, Evidence und Auditierbarkeit, ohne eine generische Tool-Kategorie zu kopieren.',
differentiationCards: [
{
title: 'Governance-Layer ueber Admin-Surfaces',
content:
'Tenantial rahmt Policy-Zustand, Evidence und Review-Arbeit. Es ersetzt nicht die operativen Microsoft Admin-Oberflaechen.',
},
{
title: 'Kein Helpdesk, kein PSA, kein SIEM',
content:
'Die Story bleibt fokussiert auf Microsoft 365 Governance und nicht auf Ticketing, Service-Desk oder generische Security-Plattformen.',
},
{
title: 'Keine autonome Compliance-Automation',
content:
'Die Seite verspricht keine automatische Remediation, keine vollautomatisierte Recovery und keine pauschalen Compliance-Ergebnisse.',
},
],
trustTeaserTitle:
'Trust und Datenschutz bleiben Teil derselben Erzaehlung',
trustTeaserSubtitle:
'Interne Evaluatoren brauchen klare Aussagen zu Provider-Berechtigungen, Datenkategorien und Dokumentenstatus. Die Trust-Seite beantwortet genau diese Fragen konservativ weiter.',
trustTeaserCta: 'Trust-Haltung ansehen',
trustPoints: [
'Provider-Berechtigungen, Datenkategorien und Dokumentenstatus bleiben explizit',
'Keine Fake-Zertifikate oder pauschalen Compliance-Versprechen',
'Recovery-, Evidence- und Review-Sprache bleibt kontrolliert und anschlussfaehig',
],
finalCtaTitle:
'Kontrollierte Microsoft 365 Governance statt Review-Stress',
finalCtaSubtitle:
'In einer fokussierten Demo zeigt Tenantial, wie interne Teams Drift, Evidence, Backups und Recovery-Kontext fuer Microsoft 365 kontrollierter vorbereiten.',
finalPrimaryCta: 'Governance-Demo buchen',
finalSecondaryCta: 'Plattform ansehen',
},
},
platform: {
pageTitle: 'Plattform | Tenantial',
metaDescription:
@ -176,6 +545,25 @@ export const siteCopy: Record<Locale, any> = {
'Weitere Policy-Domänen können als Architektur- oder Roadmap-Richtung genannt werden, aber nicht als live unterstützte Integrationen oder verifizierte Workflows.',
},
],
useCasesTitle: 'Wer den Governance-Layer am schnellsten einordnen kann',
useCasesSubtitle:
'Die Plattformseite bleibt produktnah. Die kompakten Buyer-Pfade zeigen, wie sich derselbe Governance-Layer für MSPs und interne IT unterschiedlich übersetzt.',
useCases: [
{
title: 'MSPs',
content:
'Fokussiert auf wiederholbare Kundenreviews, Evidence und sichtbares Follow-up über mehrere Microsoft-365-Umgebungen.',
cta: 'MSP-Pfad ansehen',
href: '/use-cases/msp',
},
{
title: 'Interne IT',
content:
'Fokussiert auf interne Kontrolle, nachvollziehbare Changes, Audit-Kontext und defensive Recovery-Vorbereitung.',
cta: 'Interne IT ansehen',
href: '/use-cases/mittelstand',
},
],
backupTitle: 'Beobachteter Zustand und Policy-Evidence',
backupSubtitle:
'Teams brauchen einen reproduzierbaren Nachweis dessen, was beobachtet wurde, bevor entschieden wird, ob eine Änderung sicher ist. Tenantial rahmt Snapshots und Nachweise als Review-Evidence und nicht als versteckte Automation.',
@ -561,6 +949,8 @@ export const siteCopy: Record<Locale, any> = {
nav: [
{ name: 'Home', url: '/' },
{ name: 'Platform', url: '/platform' },
{ name: 'MSPs', url: '/use-cases/msp' },
{ name: 'Internal IT', url: '/use-cases/mittelstand' },
{ name: 'Pricing', url: '/pricing' },
{ name: 'Trust', url: '/trust' },
{ name: 'Docs', url: '/welcome-to-docs/' },
@ -572,6 +962,8 @@ export const siteCopy: Record<Locale, any> = {
section: 'Product',
links: [
{ name: 'Platform', url: '/platform' },
{ name: 'MSPs', url: '/use-cases/msp' },
{ name: 'Internal IT', url: '/use-cases/mittelstand' },
{ name: 'Pricing', url: '/pricing' },
{ name: 'Trust', url: '/trust' },
{ name: 'Docs', url: '/welcome-to-docs/' },
@ -634,6 +1026,27 @@ export const siteCopy: Record<Locale, any> = {
'Turn evidence, findings, and accepted risks into reviewable material.',
},
],
useCasesTitle: 'Buyer paths that lead to the right question faster.',
useCasesSubtitle:
'Whether the audience is an MSP or internal IT, Tenantial connects Microsoft 365 governance to a clear review, evidence, and follow-up model.',
useCases: [
{
eyebrow: 'For MSPs',
title: 'Build repeatable governance services per customer',
content:
'Show MSP teams how Tenantial turns reviews, evidence, drift, and accepted risks into a repeatable customer workflow.',
cta: 'Explore MSP use case',
href: '/use-cases/msp',
},
{
eyebrow: 'For internal IT',
title: 'Keep control, evidence, and audit context together',
content:
'Show internal teams how Tenantial makes policy drift, change context, backups, and review prep readable for Microsoft 365.',
cta: 'Explore internal IT use case',
href: '/use-cases/mittelstand',
},
],
boundaryTitle: 'Built for governance. Not blind automation.',
boundarySubtitle:
'Tenantial does not replace Microsoft Admin Center. It adds the layer enterprise teams miss in daily work: versioning, evidence, drift visibility, review context, and auditable decisions.',
@ -671,6 +1084,348 @@ export const siteCopy: Record<Locale, any> = {
finalSecondaryCta: 'View platform',
faqTitle: 'Frequently<br />asked questions',
},
useCases: {
msp: {
pageTitle: 'MSP Governance Reviews | Tenantial',
metaDescription:
'Microsoft 365 governance for MSPs with repeatable reviews, evidence, versioned backups, accepted risks, and clear follow-up.',
heroTitle:
'<span class="text-yellow-500 dark:text-yellow-400">Microsoft 365 governance</span> for MSPs that need repeatable customer reviews.',
heroSubtitle:
'Tenantial turns manual tenant checks, screenshots, and spreadsheets into a controlled governance workflow across customer environments.',
supportingLine:
'More Microsoft 365 governance per customer - with review packs, evidence, drift visibility, and clear follow-up instead of one-off projects.',
primaryCta: 'Book MSP demo',
secondaryCta: 'View platform',
heroAlt: 'Static Tenantial MSP governance preview',
painTitle: 'Where MSP governance gets stuck today',
painSubtitle:
'MSPs do not need another admin surface. They need an operating model that makes reviews, evidence, and follow-up repeatable per customer.',
painCards: [
{
title: 'Manual review loops',
content:
'Operators gather screenshots, export fragments, and side notes instead of running a stable governance review per customer.',
},
{
title: 'Hidden policy drift',
content:
'When changes stay invisible between review cycles, exceptions and risks surface too late.',
},
{
title: 'Weak customer evidence',
content:
'Without traceable evidence, customer meetings become debates about sources instead of decisions and priorities.',
},
{
title: 'No repeatable service package',
content:
'Governance remains tribal knowledge when follow-up, accepted risks, and review context do not live in one flow.',
},
],
outcomeTitle: 'What changes for the MSP model',
outcomeSubtitle:
'Tenantial positions governance as a repeatable Microsoft 365 service layer instead of a loose collection of manual customer checks.',
outcomeCards: [
{
title: 'Review packs per customer',
content:
'Policy state, evidence, findings, and accepted risks stay together in one readable review baseline.',
},
{
title: 'Control across multiple customers',
content:
'MSPs can prepare configuration state, drift, and follow-up in a more controlled way across customer environments.',
},
{
title: 'Audit-ready evidence',
content:
'Reviews stay grounded in traceable configuration and decision data instead of individual screenshots.',
},
{
title: 'Clear follow-up handling',
content:
'Open findings, accepted risks, and next decisions remain visible until they are deliberately resolved.',
},
],
workflowTitle: 'A repeatable governance workflow',
workflowSubtitle:
'The MSP story is not automation at any cost. It is a reproducible review and evidence process for Microsoft 365 customer environments.',
workflowSteps: [
{
step: '01',
title: 'Secure policy state',
content:
'Versioned backups keep the relevant configuration state available for the next customer review.',
},
{
step: '02',
title: 'Expose drift',
content:
'Changes between known states become readable before they are missed in customer conversations.',
},
{
step: '03',
title: 'Bundle evidence',
content:
'Configuration proof, findings, and context are assembled into one review baseline.',
},
{
step: '04',
title: 'Classify risk',
content:
'Accepted risks and open questions stay visible as deliberate decisions instead of disappearing into tickets.',
},
{
step: '05',
title: 'Prepare review context',
content:
'Before the customer call, the team knows what changed, what was accepted, and where follow-up still matters.',
},
{
step: '06',
title: 'Keep follow-up visible',
content:
'Next actions stay tied to evidence and decisions until the governance cycle is actually closed.',
},
],
capabilityTitle: 'What Tenantial delivers in the MSP context',
capabilitySubtitle:
'The platform is not a generic MSP suite. It is the governance layer for Microsoft 365 reviews, evidence, and traceability.',
capabilityCards: [
{
title: 'Governance reviews',
content:
'Repeatable review structures for customer environments with visible findings and decision status.',
},
{
title: 'Policy backup and versioning',
content:
'Configuration states remain historically comparable instead of existing only as the latest snapshot.',
},
{
title: 'Drift visibility',
content:
'Drift becomes review work for MSP teams instead of an invisible side effect between meetings.',
},
{
title: 'Accepted-risk visibility',
content:
'Accepted risks stay reviewable for customers, operators, and internal governance context.',
},
{
title: 'Audit evidence',
content:
'Evidence remains tied to policy state, findings, and review decisions.',
},
{
title: 'PSA handoff boundary',
content:
'Tenantial clarifies governance and evidence. Ticketing or PSA execution stays intentionally outside the product boundary.',
},
],
boundaryTitle: 'Clear boundary to PSA and helpdesk tooling',
boundarySubtitle:
'Tenantial is not a PSA, not a ticketing system, not a generic helpdesk suite, and not a blind remediation engine.',
boundaryCards: [
{
title: 'It does not replace the PSA',
content:
'Tenantial documents governance context, but it does not run a full service-desk or ticketing operation for the MSP.',
},
{
title: 'It does not remediate blindly',
content:
'The page does not promise automatic correction or autonomous enforcement of policy changes.',
},
{
title: 'It is not Intune-only',
content:
'Intune is the first strong policy focus, but the story stays Microsoft 365 governance rather than a narrow backup utility.',
},
],
trustTeaserTitle: 'Trust questions stay connected to a real posture',
trustTeaserSubtitle:
'When customers ask about privacy, security, or document status, the answer stays anchored in the existing trust surface instead of drifting into marketing overclaims.',
trustTeaserCta: 'Review trust posture',
trustPoints: [
'Provider permissions and boundaries remain explicit',
'DPA, TOM, and security questions still route through real trust handoffs',
'No fake certifications, no fake proof downloads, and no inflated compliance promises',
],
finalCtaTitle: 'Sell governance services instead of one-off projects',
finalCtaSubtitle:
'In a focused demo, Tenantial shows how MSPs can structure reviews, evidence, backups, and follow-up more cleanly per customer.',
finalPrimaryCta: 'Book MSP demo',
finalSecondaryCta: 'View platform',
},
mittelstand: {
pageTitle:
'Microsoft 365 Governance for Mittelstand & Enterprise IT | Tenantial',
metaDescription:
'Microsoft 365 governance for internal IT with policy drift, traceable changes, evidence, backups, reviews, and controlled recovery preparation.',
heroTitle:
'<span class="text-yellow-500 dark:text-yellow-400">Control and evidence</span> for internal Microsoft 365 teams.',
heroSubtitle:
'Tenantial helps IT leadership, security, audit, and operations keep policy drift, change context, and recovery questions visible on one shared governance surface.',
supportingLine:
'When internal Microsoft 365 changes need to stay reviewable, an admin center alone is not enough.',
primaryCta: 'Book governance demo',
secondaryCta: 'View platform',
heroAlt: 'Static Tenantial enterprise governance preview',
painTitle: 'Where internal control creates friction today',
painSubtitle:
'Internal IT teams lose time when change proof, evidence, and recovery context fragment across screenshots, exports, and side notes.',
painCards: [
{
title: 'Undocumented changes',
content:
'Policy changes often remain visible only in the admin center and quickly lose their decision and review context.',
},
{
title: 'Audit pressure before reviews',
content:
'Shortly before audits or internal reviews, evidence has to be reconstructed manually from multiple sources.',
},
{
title: 'Uncertain recovery questions',
content:
'When configuration states are missing or no longer comparable, every recovery decision becomes riskier.',
},
{
title: 'Screenshot and export workflows',
content:
'Governance becomes fragile when decision support depends on scattered exports and point-in-time files.',
},
],
outcomeTitle: 'What internal teams gain instead',
outcomeSubtitle:
'Tenantial does not sell another admin surface. It sells the governance layer for traceable changes, evidence, and review context.',
outcomeCards: [
{
title: 'Expose policy drift',
content:
'Teams see earlier which configurations changed between known states.',
},
{
title: 'Keep changes traceable',
content:
'Changes, findings, and accepted risks stay tied to decision and review context.',
},
{
title: 'Prepare evidence for reviews',
content:
'Audit-ready evidence remains readable instead of being rebuilt manually right before review time.',
},
{
title: 'Assess recovery defensively',
content:
'Backups and known configuration states create a stronger basis for controlled recovery preparation.',
},
],
stakeholderTitle: 'One surface for four stakeholder views',
stakeholderSubtitle:
'The same governance layer supports internal roles differently without breaking into four separate tool stories.',
stakeholderCards: [
{
title: 'IT Operations',
content:
'Needs clarity on current configuration state, drift, and the next safe operational step.',
},
{
title: 'Security',
content:
'Needs evidence, findings, and accepted risks with visible reasoning instead of gut feel.',
},
{
title: 'IT Leadership',
content:
'Needs traceable decision context for prioritization, rollout risk, and governance maturity.',
},
{
title: 'Audit / Privacy',
content:
'Needs review-ready evidence, status language, and bounded claims without inflated compliance promises.',
},
],
workflowTitle: 'A controlled internal-governance workflow',
workflowSubtitle:
'Tenantial does not act autonomously. It creates a readable sequence across state, drift, evidence, risk, and the next decision.',
workflowSteps: [
{
step: '01',
title: 'Secure state',
content:
'Known policy states stay traceable through versioned backups and comparison points.',
},
{
step: '02',
title: 'Detect drift',
content:
'Differences between known states become readable before they disappear in day-to-day operations.',
},
{
step: '03',
title: 'Prepare evidence',
content:
'Changes, findings, and proof are assembled into shared review context for internal alignment.',
},
{
step: '04',
title: 'Evaluate risk',
content:
'Accepted risks and open questions remain deliberately documented instead of silently tolerated.',
},
{
step: '05',
title: 'Review recovery context',
content:
'Before sensitive actions, the team can see which state is protected and which recovery limits matter.',
},
{
step: '06',
title: 'Record the next decision',
content:
'Follow-up stays tied to evidence and review context until the decision is actually closed.',
},
],
differentiationTitle: 'Not another admin center. Not another helpdesk.',
differentiationSubtitle:
'Tenantial sits above operational Microsoft surfaces and supports governance, evidence, and auditability without copying a generic tool category.',
differentiationCards: [
{
title: 'Governance layer above admin surfaces',
content:
'Tenantial frames policy state, evidence, and review work. It does not replace the operational Microsoft admin surfaces.',
},
{
title: 'Not a helpdesk, PSA, or SIEM',
content:
'The story stays focused on Microsoft 365 governance rather than ticketing, service-desk tooling, or generic security platforms.',
},
{
title: 'No autonomous compliance automation',
content:
'The page does not promise automatic remediation, fully automated recovery, or blanket compliance outcomes.',
},
],
trustTeaserTitle: 'Trust and privacy stay part of the same story',
trustTeaserSubtitle:
'Internal evaluators need clear statements about provider permissions, data categories, and document status. The trust page continues that conversation conservatively.',
trustTeaserCta: 'Review trust posture',
trustPoints: [
'Provider permissions, data categories, and document status remain explicit',
'No fake certifications or blanket compliance promises',
'Recovery, evidence, and review language stays controlled and reviewable',
],
finalCtaTitle:
'Controlled Microsoft 365 governance instead of review stress',
finalCtaSubtitle:
'In a focused demo, Tenantial shows how internal teams can prepare drift, evidence, backups, and recovery context for Microsoft 365 more deliberately.',
finalPrimaryCta: 'Book governance demo',
finalSecondaryCta: 'View platform',
},
},
platform: {
pageTitle: 'Platform | Tenantial',
metaDescription:
@ -693,6 +1448,25 @@ export const siteCopy: Record<Locale, any> = {
'Further policy domains may be referenced as architecture or roadmap direction, but not as live integrations or verified operating workflows.',
},
],
useCasesTitle: 'Who benefits fastest from the governance layer',
useCasesSubtitle:
'The platform page stays product-focused. These compact buyer paths show how the same governance layer translates differently for MSPs and internal IT.',
useCases: [
{
title: 'MSPs',
content:
'Focused on repeatable customer reviews, evidence, and visible follow-up across multiple Microsoft 365 environments.',
cta: 'See MSP path',
href: '/use-cases/msp',
},
{
title: 'Internal IT',
content:
'Focused on internal control, traceable changes, audit context, and defensive recovery preparation.',
cta: 'See internal IT path',
href: '/use-cases/mittelstand',
},
],
backupTitle: 'Observed state and policy evidence',
backupSubtitle:
'Teams need a reproducible record of what was observed before deciding whether a change is safe. Tenantial frames snapshots and supporting evidence as review input, not hidden automation.',

View File

@ -0,0 +1,292 @@
---
import MainLayout from '@/layouts/MainLayout.astro';
import HeroSection from '@components/sections/landing/HeroSection.astro';
import PrimaryCTA from '@components/ui/buttons/PrimaryCTA.astro';
import SecondaryCTA from '@components/ui/buttons/SecondaryCTA.astro';
import heroImage from '@images/tenantial-dashboard.avif';
import { SITE } from '@data/constants';
import { siteCopy } from '@data/site-copy';
import { localeHtmlLang, localizeHref, localizedPath } from '@/i18n';
const locale = 'en' as const;
const copy = siteCopy[locale].useCases.mittelstand;
const siteDescription = siteCopy[locale].site.description;
const canonicalPath = localizedPath('/use-cases/mittelstand', locale);
---
<MainLayout
lang={locale}
title={copy.pageTitle}
customDescription={copy.metaDescription}
customOgTitle={copy.pageTitle}
structuredData={{
'@context': 'https://schema.org',
'@type': 'WebPage',
'@id': `${SITE.url}${canonicalPath}`,
url: `${SITE.url}${canonicalPath}`,
name: copy.pageTitle,
description: copy.metaDescription,
isPartOf: {
'@type': 'WebSite',
url: SITE.url,
name: SITE.title,
description: siteDescription,
},
inLanguage: localeHtmlLang[locale],
}}
>
<HeroSection
title={copy.heroTitle}
subTitle={copy.heroSubtitle}
primaryBtn={copy.primaryCta}
primaryBtnURL={localizeHref('/contact', locale)}
secondaryBtn={copy.secondaryCta}
secondaryBtnURL={localizeHref('/platform', locale)}
withReview={false}
supportingLine={copy.supportingLine}
src={heroImage}
alt={copy.heroAlt}
/>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.painTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.painSubtitle}
</p>
</div>
<div class="mt-8 grid gap-6 md:grid-cols-2 xl:grid-cols-4">
{
copy.painCards.map((card: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/80 p-6 shadow-xs dark:border-neutral-700 dark:bg-white/[0.04]">
<h3 class="text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-pretty text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] border border-neutral-300 bg-linear-to-br from-neutral-100 to-yellow-100/70 p-6 md:p-10 dark:border-neutral-700 dark:from-neutral-900 dark:to-neutral-800"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.outcomeTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.outcomeSubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-2">
{
copy.outcomeCards.map((card: any) => (
<article class="rounded-2xl bg-white/80 p-5 dark:bg-neutral-950/60">
<h3 class="text-base font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.stakeholderTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.stakeholderSubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-2 xl:grid-cols-4">
{
copy.stakeholderCards.map((card: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/70 p-6 dark:border-neutral-700 dark:bg-white/[0.04]">
<h3 class="text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-pretty text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="grid gap-8 lg:grid-cols-[minmax(0,0.7fr)_minmax(0,1.3fr)] lg:items-start"
>
<div>
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.workflowTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.workflowSubtitle}
</p>
</div>
<div class="grid gap-4 md:grid-cols-2">
{
copy.workflowSteps.map((step: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/70 p-5 dark:border-neutral-700 dark:bg-white/[0.04]">
<span class="inline-flex rounded-full bg-yellow-400 px-3 py-1 text-xs font-semibold tracking-[0.18em] text-neutral-900 uppercase">
{step.step}
</span>
<h3 class="mt-4 text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{step.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{step.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] border border-neutral-300 bg-neutral-100/80 p-6 md:p-10 dark:border-neutral-700 dark:bg-white/[0.05]"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.differentiationTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.differentiationSubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-3">
{
copy.differentiationCards.map((card: any) => (
<article class="rounded-2xl bg-neutral-200/80 p-5 dark:bg-neutral-900/70">
<h3 class="text-base font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="grid gap-8 border-y border-neutral-300 py-10 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)] lg:items-center lg:py-14 dark:border-neutral-700"
>
<div>
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.trustTeaserTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.trustTeaserSubtitle}
</p>
<div class="mt-6">
<SecondaryCTA
title={copy.trustTeaserCta}
url={localizeHref('/trust', locale)}
/>
</div>
</div>
<ul class="grid gap-3">
{
copy.trustPoints.map((point: string) => (
<li class="rounded-2xl border border-neutral-300 bg-neutral-100/70 px-5 py-4 text-sm font-medium text-neutral-700 dark:border-neutral-700 dark:bg-white/[0.04] dark:text-neutral-300">
{point}
</li>
))
}
</ul>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 pb-10 sm:px-6 lg:px-8 lg:pb-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] bg-linear-to-r from-neutral-900 to-neutral-700 px-6 py-8 text-neutral-50 md:px-10 md:py-12 dark:from-neutral-100 dark:to-neutral-300 dark:text-neutral-900"
>
<div class="max-w-(--breakpoint-lg)">
<h2 class="text-2xl font-bold text-balance md:text-3xl">
{copy.finalCtaTitle}
</h2>
<p
class="mt-3 max-w-2xl text-pretty text-neutral-200 dark:text-neutral-700"
>
{copy.finalCtaSubtitle}
</p>
</div>
<div class="mt-6 flex flex-col gap-3 sm:flex-row">
<PrimaryCTA
title={copy.finalPrimaryCta}
url={localizeHref('/contact', locale)}
/>
<SecondaryCTA
title={copy.finalSecondaryCta}
url={localizeHref('/platform', locale)}
/>
</div>
</div>
</section>
</MainLayout>

View File

@ -0,0 +1,292 @@
---
import MainLayout from '@/layouts/MainLayout.astro';
import HeroSection from '@components/sections/landing/HeroSection.astro';
import PrimaryCTA from '@components/ui/buttons/PrimaryCTA.astro';
import SecondaryCTA from '@components/ui/buttons/SecondaryCTA.astro';
import heroImage from '@images/tenantial-review-board.avif';
import { SITE } from '@data/constants';
import { siteCopy } from '@data/site-copy';
import { localeHtmlLang, localizeHref, localizedPath } from '@/i18n';
const locale = 'en' as const;
const copy = siteCopy[locale].useCases.msp;
const siteDescription = siteCopy[locale].site.description;
const canonicalPath = localizedPath('/use-cases/msp', locale);
---
<MainLayout
lang={locale}
title={copy.pageTitle}
customDescription={copy.metaDescription}
customOgTitle={copy.pageTitle}
structuredData={{
'@context': 'https://schema.org',
'@type': 'WebPage',
'@id': `${SITE.url}${canonicalPath}`,
url: `${SITE.url}${canonicalPath}`,
name: copy.pageTitle,
description: copy.metaDescription,
isPartOf: {
'@type': 'WebSite',
url: SITE.url,
name: SITE.title,
description: siteDescription,
},
inLanguage: localeHtmlLang[locale],
}}
>
<HeroSection
title={copy.heroTitle}
subTitle={copy.heroSubtitle}
primaryBtn={copy.primaryCta}
primaryBtnURL={localizeHref('/contact', locale)}
secondaryBtn={copy.secondaryCta}
secondaryBtnURL={localizeHref('/platform', locale)}
withReview={false}
supportingLine={copy.supportingLine}
src={heroImage}
alt={copy.heroAlt}
/>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.painTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.painSubtitle}
</p>
</div>
<div class="mt-8 grid gap-6 md:grid-cols-2 xl:grid-cols-4">
{
copy.painCards.map((card: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/80 p-6 shadow-xs dark:border-neutral-700 dark:bg-white/[0.04]">
<h3 class="text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-pretty text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] border border-neutral-300 bg-linear-to-br from-neutral-100 to-yellow-100/70 p-6 md:p-10 dark:border-neutral-700 dark:from-neutral-900 dark:to-neutral-800"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.outcomeTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.outcomeSubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-2">
{
copy.outcomeCards.map((card: any) => (
<article class="rounded-2xl bg-white/80 p-5 dark:bg-neutral-950/60">
<h3 class="text-base font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="grid gap-8 lg:grid-cols-[minmax(0,0.7fr)_minmax(0,1.3fr)] lg:items-start"
>
<div>
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.workflowTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.workflowSubtitle}
</p>
</div>
<div class="grid gap-4 md:grid-cols-2">
{
copy.workflowSteps.map((step: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/70 p-5 dark:border-neutral-700 dark:bg-white/[0.04]">
<span class="inline-flex rounded-full bg-yellow-400 px-3 py-1 text-xs font-semibold tracking-[0.18em] text-neutral-900 uppercase">
{step.step}
</span>
<h3 class="mt-4 text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{step.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{step.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.capabilityTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.capabilitySubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-2 xl:grid-cols-3">
{
copy.capabilityCards.map((card: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/70 p-6 dark:border-neutral-700 dark:bg-white/[0.04]">
<h3 class="text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-pretty text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] border border-neutral-300 bg-neutral-100/80 p-6 md:p-10 dark:border-neutral-700 dark:bg-white/[0.05]"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.boundaryTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.boundarySubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-3">
{
copy.boundaryCards.map((card: any) => (
<article class="rounded-2xl bg-neutral-200/80 p-5 dark:bg-neutral-900/70">
<h3 class="text-base font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="grid gap-8 border-y border-neutral-300 py-10 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)] lg:items-center lg:py-14 dark:border-neutral-700"
>
<div>
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.trustTeaserTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.trustTeaserSubtitle}
</p>
<div class="mt-6">
<SecondaryCTA
title={copy.trustTeaserCta}
url={localizeHref('/trust', locale)}
/>
</div>
</div>
<ul class="grid gap-3">
{
copy.trustPoints.map((point: string) => (
<li class="rounded-2xl border border-neutral-300 bg-neutral-100/70 px-5 py-4 text-sm font-medium text-neutral-700 dark:border-neutral-700 dark:bg-white/[0.04] dark:text-neutral-300">
{point}
</li>
))
}
</ul>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 pb-10 sm:px-6 lg:px-8 lg:pb-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] bg-linear-to-r from-neutral-900 to-neutral-700 px-6 py-8 text-neutral-50 md:px-10 md:py-12 dark:from-neutral-100 dark:to-neutral-300 dark:text-neutral-900"
>
<div class="max-w-(--breakpoint-lg)">
<h2 class="text-2xl font-bold text-balance md:text-3xl">
{copy.finalCtaTitle}
</h2>
<p
class="mt-3 max-w-2xl text-pretty text-neutral-200 dark:text-neutral-700"
>
{copy.finalCtaSubtitle}
</p>
</div>
<div class="mt-6 flex flex-col gap-3 sm:flex-row">
<PrimaryCTA
title={copy.finalPrimaryCta}
url={localizeHref('/contact', locale)}
/>
<SecondaryCTA
title={copy.finalSecondaryCta}
url={localizeHref('/platform', locale)}
/>
</div>
</div>
</section>
</MainLayout>

View File

@ -0,0 +1,292 @@
---
import MainLayout from '@/layouts/MainLayout.astro';
import HeroSection from '@components/sections/landing/HeroSection.astro';
import PrimaryCTA from '@components/ui/buttons/PrimaryCTA.astro';
import SecondaryCTA from '@components/ui/buttons/SecondaryCTA.astro';
import heroImage from '@images/tenantial-dashboard.avif';
import { SITE } from '@data/constants';
import { siteCopy } from '@data/site-copy';
import { localeHtmlLang, localizeHref, localizedPath } from '@/i18n';
const locale = 'de' as const;
const copy = siteCopy[locale].useCases.mittelstand;
const siteDescription = siteCopy[locale].site.description;
const canonicalPath = localizedPath('/use-cases/mittelstand', locale);
---
<MainLayout
lang={locale}
title={copy.pageTitle}
customDescription={copy.metaDescription}
customOgTitle={copy.pageTitle}
structuredData={{
'@context': 'https://schema.org',
'@type': 'WebPage',
'@id': `${SITE.url}${canonicalPath}`,
url: `${SITE.url}${canonicalPath}`,
name: copy.pageTitle,
description: copy.metaDescription,
isPartOf: {
'@type': 'WebSite',
url: SITE.url,
name: SITE.title,
description: siteDescription,
},
inLanguage: localeHtmlLang[locale],
}}
>
<HeroSection
title={copy.heroTitle}
subTitle={copy.heroSubtitle}
primaryBtn={copy.primaryCta}
primaryBtnURL={localizeHref('/contact', locale)}
secondaryBtn={copy.secondaryCta}
secondaryBtnURL={localizeHref('/platform', locale)}
withReview={false}
supportingLine={copy.supportingLine}
src={heroImage}
alt={copy.heroAlt}
/>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.painTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.painSubtitle}
</p>
</div>
<div class="mt-8 grid gap-6 md:grid-cols-2 xl:grid-cols-4">
{
copy.painCards.map((card: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/80 p-6 shadow-xs dark:border-neutral-700 dark:bg-white/[0.04]">
<h3 class="text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-pretty text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] border border-neutral-300 bg-linear-to-br from-neutral-100 to-yellow-100/70 p-6 md:p-10 dark:border-neutral-700 dark:from-neutral-900 dark:to-neutral-800"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.outcomeTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.outcomeSubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-2">
{
copy.outcomeCards.map((card: any) => (
<article class="rounded-2xl bg-white/80 p-5 dark:bg-neutral-950/60">
<h3 class="text-base font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.stakeholderTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.stakeholderSubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-2 xl:grid-cols-4">
{
copy.stakeholderCards.map((card: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/70 p-6 dark:border-neutral-700 dark:bg-white/[0.04]">
<h3 class="text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-pretty text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="grid gap-8 lg:grid-cols-[minmax(0,0.7fr)_minmax(0,1.3fr)] lg:items-start"
>
<div>
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.workflowTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.workflowSubtitle}
</p>
</div>
<div class="grid gap-4 md:grid-cols-2">
{
copy.workflowSteps.map((step: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/70 p-5 dark:border-neutral-700 dark:bg-white/[0.04]">
<span class="inline-flex rounded-full bg-yellow-400 px-3 py-1 text-xs font-semibold tracking-[0.18em] text-neutral-900 uppercase">
{step.step}
</span>
<h3 class="mt-4 text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{step.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{step.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] border border-neutral-300 bg-neutral-100/80 p-6 md:p-10 dark:border-neutral-700 dark:bg-white/[0.05]"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.differentiationTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.differentiationSubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-3">
{
copy.differentiationCards.map((card: any) => (
<article class="rounded-2xl bg-neutral-200/80 p-5 dark:bg-neutral-900/70">
<h3 class="text-base font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="grid gap-8 border-y border-neutral-300 py-10 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)] lg:items-center lg:py-14 dark:border-neutral-700"
>
<div>
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.trustTeaserTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.trustTeaserSubtitle}
</p>
<div class="mt-6">
<SecondaryCTA
title={copy.trustTeaserCta}
url={localizeHref('/trust', locale)}
/>
</div>
</div>
<ul class="grid gap-3">
{
copy.trustPoints.map((point: string) => (
<li class="rounded-2xl border border-neutral-300 bg-neutral-100/70 px-5 py-4 text-sm font-medium text-neutral-700 dark:border-neutral-700 dark:bg-white/[0.04] dark:text-neutral-300">
{point}
</li>
))
}
</ul>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 pb-10 sm:px-6 lg:px-8 lg:pb-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] bg-linear-to-r from-neutral-900 to-neutral-700 px-6 py-8 text-neutral-50 md:px-10 md:py-12 dark:from-neutral-100 dark:to-neutral-300 dark:text-neutral-900"
>
<div class="max-w-(--breakpoint-lg)">
<h2 class="text-2xl font-bold text-balance md:text-3xl">
{copy.finalCtaTitle}
</h2>
<p
class="mt-3 max-w-2xl text-pretty text-neutral-200 dark:text-neutral-700"
>
{copy.finalCtaSubtitle}
</p>
</div>
<div class="mt-6 flex flex-col gap-3 sm:flex-row">
<PrimaryCTA
title={copy.finalPrimaryCta}
url={localizeHref('/contact', locale)}
/>
<SecondaryCTA
title={copy.finalSecondaryCta}
url={localizeHref('/platform', locale)}
/>
</div>
</div>
</section>
</MainLayout>

View File

@ -0,0 +1,292 @@
---
import MainLayout from '@/layouts/MainLayout.astro';
import HeroSection from '@components/sections/landing/HeroSection.astro';
import PrimaryCTA from '@components/ui/buttons/PrimaryCTA.astro';
import SecondaryCTA from '@components/ui/buttons/SecondaryCTA.astro';
import heroImage from '@images/tenantial-review-board.avif';
import { SITE } from '@data/constants';
import { siteCopy } from '@data/site-copy';
import { localeHtmlLang, localizeHref, localizedPath } from '@/i18n';
const locale = 'de' as const;
const copy = siteCopy[locale].useCases.msp;
const siteDescription = siteCopy[locale].site.description;
const canonicalPath = localizedPath('/use-cases/msp', locale);
---
<MainLayout
lang={locale}
title={copy.pageTitle}
customDescription={copy.metaDescription}
customOgTitle={copy.pageTitle}
structuredData={{
'@context': 'https://schema.org',
'@type': 'WebPage',
'@id': `${SITE.url}${canonicalPath}`,
url: `${SITE.url}${canonicalPath}`,
name: copy.pageTitle,
description: copy.metaDescription,
isPartOf: {
'@type': 'WebSite',
url: SITE.url,
name: SITE.title,
description: siteDescription,
},
inLanguage: localeHtmlLang[locale],
}}
>
<HeroSection
title={copy.heroTitle}
subTitle={copy.heroSubtitle}
primaryBtn={copy.primaryCta}
primaryBtnURL={localizeHref('/contact', locale)}
secondaryBtn={copy.secondaryCta}
secondaryBtnURL={localizeHref('/platform', locale)}
withReview={false}
supportingLine={copy.supportingLine}
src={heroImage}
alt={copy.heroAlt}
/>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.painTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.painSubtitle}
</p>
</div>
<div class="mt-8 grid gap-6 md:grid-cols-2 xl:grid-cols-4">
{
copy.painCards.map((card: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/80 p-6 shadow-xs dark:border-neutral-700 dark:bg-white/[0.04]">
<h3 class="text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-pretty text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] border border-neutral-300 bg-linear-to-br from-neutral-100 to-yellow-100/70 p-6 md:p-10 dark:border-neutral-700 dark:from-neutral-900 dark:to-neutral-800"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.outcomeTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.outcomeSubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-2">
{
copy.outcomeCards.map((card: any) => (
<article class="rounded-2xl bg-white/80 p-5 dark:bg-neutral-950/60">
<h3 class="text-base font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="grid gap-8 lg:grid-cols-[minmax(0,0.7fr)_minmax(0,1.3fr)] lg:items-start"
>
<div>
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.workflowTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.workflowSubtitle}
</p>
</div>
<div class="grid gap-4 md:grid-cols-2">
{
copy.workflowSteps.map((step: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/70 p-5 dark:border-neutral-700 dark:bg-white/[0.04]">
<span class="inline-flex rounded-full bg-yellow-400 px-3 py-1 text-xs font-semibold tracking-[0.18em] text-neutral-900 uppercase">
{step.step}
</span>
<h3 class="mt-4 text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{step.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{step.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.capabilityTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.capabilitySubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-2 xl:grid-cols-3">
{
copy.capabilityCards.map((card: any) => (
<article class="rounded-3xl border border-neutral-300 bg-neutral-100/70 p-6 dark:border-neutral-700 dark:bg-white/[0.04]">
<h3 class="text-lg font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-pretty text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] border border-neutral-300 bg-neutral-100/80 p-6 md:p-10 dark:border-neutral-700 dark:bg-white/[0.05]"
>
<div class="max-w-(--breakpoint-md)">
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.boundaryTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.boundarySubtitle}
</p>
</div>
<div class="mt-8 grid gap-4 md:grid-cols-3">
{
copy.boundaryCards.map((card: any) => (
<article class="rounded-2xl bg-neutral-200/80 p-5 dark:bg-neutral-900/70">
<h3 class="text-base font-semibold text-neutral-800 dark:text-neutral-200">
{card.title}
</h3>
<p class="mt-3 text-sm leading-6 text-neutral-600 dark:text-neutral-400">
{card.content}
</p>
</article>
))
}
</div>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 2xl:max-w-full"
>
<div
class="grid gap-8 border-y border-neutral-300 py-10 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)] lg:items-center lg:py-14 dark:border-neutral-700"
>
<div>
<h2
class="text-2xl font-bold text-balance text-neutral-800 md:text-3xl dark:text-neutral-200"
>
{copy.trustTeaserTitle}
</h2>
<p
class="mt-3 max-w-prose text-pretty text-neutral-600 md:text-lg dark:text-neutral-400"
>
{copy.trustTeaserSubtitle}
</p>
<div class="mt-6">
<SecondaryCTA
title={copy.trustTeaserCta}
url={localizeHref('/trust', locale)}
/>
</div>
</div>
<ul class="grid gap-3">
{
copy.trustPoints.map((point: string) => (
<li class="rounded-2xl border border-neutral-300 bg-neutral-100/70 px-5 py-4 text-sm font-medium text-neutral-700 dark:border-neutral-700 dark:bg-white/[0.04] dark:text-neutral-300">
{point}
</li>
))
}
</ul>
</div>
</section>
<section
class="mx-auto max-w-[85rem] px-4 pb-10 sm:px-6 lg:px-8 lg:pb-14 2xl:max-w-full"
>
<div
class="rounded-[2rem] bg-linear-to-r from-neutral-900 to-neutral-700 px-6 py-8 text-neutral-50 md:px-10 md:py-12 dark:from-neutral-100 dark:to-neutral-300 dark:text-neutral-900"
>
<div class="max-w-(--breakpoint-lg)">
<h2 class="text-2xl font-bold text-balance md:text-3xl">
{copy.finalCtaTitle}
</h2>
<p
class="mt-3 max-w-2xl text-pretty text-neutral-200 dark:text-neutral-700"
>
{copy.finalCtaSubtitle}
</p>
</div>
<div class="mt-6 flex flex-col gap-3 sm:flex-row">
<PrimaryCTA
title={copy.finalPrimaryCta}
url={localizeHref('/contact', locale)}
/>
<SecondaryCTA
title={copy.finalSecondaryCta}
url={localizeHref('/platform', locale)}
/>
</div>
</div>
</section>
</MainLayout>

View File

@ -20,6 +20,12 @@ test('mobile navigation opens with vendored foundation behavior', async ({
await expect(
mobilePanel.getByRole('link', { name: 'Plattform', exact: true })
).toBeVisible();
await expect(
mobilePanel.getByRole('link', { name: 'MSPs', exact: true })
).toHaveAttribute('href', '/use-cases/msp');
await expect(
mobilePanel.getByRole('link', { name: 'Interne IT', exact: true })
).toHaveAttribute('href', '/use-cases/mittelstand');
await expect(
mobilePanel.getByRole('link', { name: 'Vertrauen', exact: true })
).toHaveAttribute('href', '/trust');
@ -52,6 +58,41 @@ test('mobile navigation exposes localized trust links', async ({
}
});
test('mobile navigation exposes localized use-case links', async ({
page,
isMobile,
}) => {
test.skip(!isMobile, 'mobile navigation is covered by the mobile project');
for (const { route, links } of [
{
route: '/',
links: [
{ label: 'MSPs', href: '/use-cases/msp' },
{ label: 'Interne IT', href: '/use-cases/mittelstand' },
],
},
{
route: '/en/',
links: [
{ label: 'MSPs', href: '/en/use-cases/msp' },
{ label: 'Internal IT', href: '/en/use-cases/mittelstand' },
],
},
] as const) {
await page.goto(route);
await page.getByLabel('Toggle navigation').click();
const mobilePanel = page.locator('#navbar-collapse-with-animation');
for (const link of links) {
await expect(
mobilePanel.getByRole('link', { name: link.label, exact: true })
).toHaveAttribute('href', link.href);
}
}
});
test('theme toggle keeps page content visible', async ({ page }) => {
await page.goto('/');
@ -89,6 +130,38 @@ test('homepage mobile first viewport remains readable', async ({
await expectNoHorizontalOverflow(page);
});
test('homepage exposes localized buyer-path teasers', async ({ page }) => {
for (const { route, teaserLinks } of [
{
route: '/',
teaserLinks: [
{ name: 'MSP-Use-Case ansehen', href: '/use-cases/msp' },
{ name: 'Interne IT ansehen', href: '/use-cases/mittelstand' },
],
},
{
route: '/en/',
teaserLinks: [
{ name: 'Explore MSP use case', href: '/en/use-cases/msp' },
{
name: 'Explore internal IT use case',
href: '/en/use-cases/mittelstand',
},
],
},
] as const) {
await page.goto(route);
const main = page.locator('main');
for (const link of teaserLinks) {
await expect(
main.getByRole('link', { name: link.name, exact: true })
).toHaveAttribute('href', link.href);
}
}
});
test('desktop keyboard reaches navigation, CTAs, footer, and contact controls', async ({
page,
isMobile,
@ -131,6 +204,8 @@ test('desktop keyboard reaches navigation, CTAs, footer, and contact controls',
}
expect([...reached].join('\n')).toContain('/platform');
expect([...reached].join('\n')).toContain('/use-cases/msp');
expect([...reached].join('\n')).toContain('/use-cases/mittelstand');
expect([...reached].join('\n')).toContain('/trust');
expect([...reached].join('\n')).toContain('/welcome-to-docs/');
expect([...reached].join('\n')).toContain('Kontakt');
@ -139,6 +214,68 @@ test('desktop keyboard reaches navigation, CTAs, footer, and contact controls',
expect([...reached].join('\n')).toContain('E-Mail-Entwurf vorbereiten');
});
for (const { route, heading, terms, contactHref } of [
{
route: '/use-cases/msp',
heading: /Microsoft 365 Governance.*MSPs/i,
terms: [/Review Packs/i, /Accepted Risks/i, /PSA/i],
contactHref: '/contact',
},
{
route: '/en/use-cases/msp',
heading: /Microsoft 365 governance.*MSPs/i,
terms: [/review packs/i, /accepted risks/i, /PSA/i],
contactHref: '/en/contact',
},
] as const) {
test(`${route} communicates the MSP buyer path quickly`, async ({ page }) => {
await page.goto(route);
await expect(page.getByRole('heading', { name: heading })).toBeVisible();
for (const term of terms) {
await expect(page.locator('main')).toContainText(term);
}
await expect(
page.locator(`main a[href="${contactHref}"]`).first()
).toBeVisible();
await expectNoHorizontalOverflow(page);
});
}
for (const { route, heading, terms, contactHref } of [
{
route: '/use-cases/mittelstand',
heading: /Kontrolle und Evidence/i,
terms: [/IT Operations/i, /IT-Leitung/i, /Governance-Layer/i],
contactHref: '/contact',
},
{
route: '/en/use-cases/mittelstand',
heading: /Control and evidence/i,
terms: [/IT Operations/i, /IT Leadership/i, /Governance layer/i],
contactHref: '/en/contact',
},
] as const) {
test(`${route} communicates the internal IT buyer path quickly`, async ({
page,
}) => {
await page.goto(route);
await expect(page.getByRole('heading', { name: heading })).toBeVisible();
for (const term of terms) {
await expect(page.locator('main')).toContainText(term);
}
await expect(
page.locator(`main a[href="${contactHref}"]`).first()
).toBeVisible();
await expectNoHorizontalOverflow(page);
});
}
for (const { route, locale } of [
{ route: '/trust', locale: 'de' },
{ route: '/en/trust', locale: 'en' },
@ -154,10 +291,51 @@ for (const { route, locale } of [
});
}
for (const { route, heading, contactHref } of [
{
route: '/use-cases/msp',
heading: /Microsoft 365 Governance.*MSPs/i,
contactHref: '/contact',
},
{
route: '/use-cases/mittelstand',
heading: /Kontrolle und Evidence/i,
contactHref: '/contact',
},
{
route: '/en/use-cases/msp',
heading: /Microsoft 365 governance.*MSPs/i,
contactHref: '/en/contact',
},
{
route: '/en/use-cases/mittelstand',
heading: /Control and evidence/i,
contactHref: '/en/contact',
},
] as const) {
test(`${route} remains readable across configured viewports`, async ({
page,
}) => {
await page.goto(route);
await expect(page.getByRole('heading', { name: heading })).toBeVisible();
await expect(
page.locator(`main a[href="${contactHref}"]`).first()
).toBeVisible();
await expectNoHorizontalOverflow(page);
});
}
test('reduced motion keeps preview pages understandable', async ({ page }) => {
await page.emulateMedia({ reducedMotion: 'reduce' });
for (const route of ['/', '/platform', '/pricing'] as const) {
for (const route of [
'/',
'/platform',
'/pricing',
'/use-cases/msp',
'/use-cases/mittelstand',
] as const) {
await page.goto(route);
await expect(page.locator('h1').first()).toBeVisible();
@ -175,7 +353,11 @@ test.describe('without JavaScript', () => {
'/platform',
'/contact',
'/trust',
'/use-cases/msp',
'/use-cases/mittelstand',
'/en/trust',
'/en/use-cases/msp',
'/en/use-cases/mittelstand',
] as const) {
await page.goto(route);

View File

@ -28,6 +28,16 @@ const routeMetadata = {
description:
/Policy-Drift früh erkennen|Konfigurationsstände versioniert sichern/i,
},
'/use-cases/msp': {
title: /MSP.*Tenantial|Tenantial.*MSP/i,
description:
/Microsoft 365 Governance|Reviews|Evidence|Backups|Accepted Risks/i,
},
'/use-cases/mittelstand': {
title: /Mittelstand|Enterprise IT|Tenantial/i,
description:
/Microsoft 365 Governance|Policy-Drift|Evidence|Backups|Recovery/i,
},
'/platform': {
title: /Plattform \| Tenantial/i,
description: /Policy Governance|Microsoft 365/i,
@ -85,6 +95,16 @@ const routeMetadata = {
description:
/Detect Microsoft 365 policy drift early|versioned configuration backups/i,
},
'/en/use-cases/msp': {
title: /MSP.*Tenantial|Tenantial.*MSP/i,
description:
/Microsoft 365 governance|reviews|evidence|backups|accepted risks/i,
},
'/en/use-cases/mittelstand': {
title: /Enterprise IT|Mittelstand|Tenantial/i,
description:
/Microsoft 365 governance|policy drift|evidence|backups|recovery/i,
},
'/en/platform': {
title: /Platform \| Tenantial/i,
description: /policy governance|Microsoft 365/i,
@ -173,6 +193,40 @@ test('homepage first viewport explains core Tenantial capabilities', async ({
await expectCoreCapabilitiesVisible(page);
});
for (const { route, links } of [
{
route: '/',
links: [
{ name: 'MSP-Use-Case ansehen', href: '/use-cases/msp' },
{ name: 'Interne IT ansehen', href: '/use-cases/mittelstand' },
],
},
{
route: '/en/',
links: [
{ name: 'Explore MSP use case', href: '/en/use-cases/msp' },
{
name: 'Explore internal IT use case',
href: '/en/use-cases/mittelstand',
},
],
},
] as const) {
test(`${route} exposes localized use-case teaser links`, async ({ page }) => {
await page.goto(route);
const main = page.locator('main');
for (const link of links) {
await expect(
main.getByRole('link', { name: link.name, exact: true })
).toHaveAttribute('href', link.href);
}
await expectNoPlaceholderLinks(page);
});
}
test('/platform explains the public product model without internal runtime terms', async ({
page,
}) => {
@ -199,6 +253,37 @@ test('/platform explains the public product model without internal runtime terms
expect(text).not.toMatch(/\bGraph runtime\b/i);
});
for (const { route, links } of [
{
route: '/platform',
links: [
{ name: 'MSP-Pfad ansehen', href: '/use-cases/msp' },
{ name: 'Interne IT ansehen', href: '/use-cases/mittelstand' },
],
},
{
route: '/en/platform',
links: [
{ name: 'See MSP path', href: '/en/use-cases/msp' },
{ name: 'See internal IT path', href: '/en/use-cases/mittelstand' },
],
},
] as const) {
test(`${route} exposes compact buyer-path links`, async ({ page }) => {
await page.goto(route);
const main = page.locator('main');
for (const link of links) {
await expect(
main.getByRole('link', { name: link.name, exact: true })
).toHaveAttribute('href', link.href);
}
await expectNoPlaceholderLinks(page);
});
}
for (const route of renderedRoutes) {
test(`public links on ${route} resolve intentionally`, async ({
page,
@ -245,6 +330,21 @@ for (const route of [
});
}
for (const route of [
'/use-cases/msp',
'/use-cases/mittelstand',
'/en/use-cases/msp',
'/en/use-cases/mittelstand',
] as const) {
test(`${route} keeps buyer-story claims conservative`, async ({ page }) => {
await page.goto(route);
await expectNoForbiddenPublicClaims(page);
await expectNoProviderOrDataOverclaims(page);
await expectNoHorizontalOverflow(page);
});
}
for (const { route, locale } of [
{ route: '/trust', locale: 'de' },
{ route: '/en/trust', locale: 'en' },
@ -334,6 +434,48 @@ for (const { route, trustHref, label } of [
});
}
for (const { route, navLinks } of [
{
route: '/',
navLinks: [
{ name: 'MSPs', href: '/use-cases/msp' },
{ name: 'Interne IT', href: '/use-cases/mittelstand' },
],
},
{
route: '/en/',
navLinks: [
{ name: 'MSPs', href: '/en/use-cases/msp' },
{ name: 'Internal IT', href: '/en/use-cases/mittelstand' },
],
},
] as const) {
test(`${route} exposes use-case links in navigation and footer`, async ({
page,
isMobile,
}) => {
await page.goto(route);
const header = page.locator('header');
const footer = page.locator('footer');
if (isMobile) {
await page.getByLabel('Toggle navigation').click();
}
for (const link of navLinks) {
await expect(
header.getByRole('link', { name: link.name, exact: true })
).toHaveAttribute('href', link.href);
await expect(
footer.getByRole('link', { name: link.name, exact: true })
).toHaveAttribute('href', link.href);
}
await expectNoPlaceholderLinks(page);
});
}
for (const [route, expected] of Object.entries(routeMetadata)) {
test(`metadata is route-specific for ${route}`, async ({ page }) => {
await page.goto(route);

View File

@ -2,6 +2,8 @@ import { expect, type APIRequestContext, type Page } from '@playwright/test';
export const renderedRoutes = [
'/',
'/use-cases/msp',
'/use-cases/mittelstand',
'/platform',
'/pricing',
'/contact',
@ -16,6 +18,8 @@ export const renderedRoutes = [
'/guides/first-project-checklist/',
'/platform/evidence-review/',
'/en/',
'/en/use-cases/msp',
'/en/use-cases/mittelstand',
'/en/platform',
'/en/pricing',
'/en/contact',
@ -95,6 +99,13 @@ const forbiddenPublicPatterns = [
{ label: 'Google supported claim', pattern: /Google supported/i },
{ label: 'AWS supported claim', pattern: /AWS supported/i },
{ label: 'automatic restore claim', pattern: /automatic restore/i },
{ label: 'one-click restore claim', pattern: /one[- ]click restore/i },
{ label: 'immutable backup claim', pattern: /immutable backups?/i },
{
label: 'real-time drift detection claim',
pattern: /real[- ]time drift detection/i,
},
{ label: 'court-proof evidence claim', pattern: /court[- ]proof evidence/i },
{ label: 'autonomous remediation claim', pattern: /autonomous remediation/i },
{ label: 'neutral SaaS residue', pattern: /neutral SaaS visual/i },
{ label: 'lorem ipsum residue', pattern: /lorem ipsum/i },

View File

@ -0,0 +1,39 @@
# Specification Quality Checklist: MSP & Mittelstand Use-Case Pages
**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2026-05-26
**Feature**: [spec.md](../spec.md)
## Content Quality
- [x] No implementation details (languages, frameworks, APIs)
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders
- [x] All mandatory sections completed
## Requirement Completeness
- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable
- [x] Success criteria are technology-agnostic (no implementation details)
- [x] All acceptance scenarios are defined
- [x] Edge cases are identified
- [x] Scope is clearly bounded
- [x] Dependencies and assumptions identified
## Feature Readiness
- [x] All functional requirements have clear acceptance criteria
- [x] User scenarios cover primary flows
- [x] Feature meets measurable outcomes defined in Success Criteria
- [x] No implementation details leak into specification
## Notes
- Initial validation passed with no remaining clarification markers.
- The spec is ready for `/speckit.plan`.
- 2026-05-27 implementation close-out: `/use-cases/msp`, `/use-cases/mittelstand`, `/en/use-cases/msp`, and `/en/use-cases/mittelstand` were implemented with homepage, navigation, footer, and compact platform-page discoverability.
- Browser validation passed via `corepack pnpm build`, `WEBSITE_PORT=4322 corepack pnpm test tests/smoke/public-routes.spec.ts tests/smoke/interaction.spec.ts`, and `WEBSITE_PORT=4322 corepack pnpm --filter @tenantatlas/website test` (`324 passed`, `6 skipped`).
- Static forbidden-term scans over `apps/website/src`, `apps/website/public`, and `apps/website/dist` returned no matches; no `apps/website/public` or `apps/website/src/images` proof artifacts were added.
- `corepack pnpm --filter @tenantatlas/website format:check` still reports nine pre-existing unrelated formatting issues outside this feature's touched files.

View File

@ -0,0 +1,207 @@
# Implementation Plan: MSP & Mittelstand Use-Case Pages
**Branch**: `407-msp-mittelstand-use-case-pages` | **Date**: 2026-05-27 | **Spec**: [spec.md](spec.md)
**Input**: Feature specification from `/specs/407-msp-mittelstand-use-case-pages/spec.md`
## Summary
Deliver two buyer-specific public pages in `apps/website` for MSP and Mittelstand/Enterprise IT audiences, integrate them into existing homepage/navigation/footer discovery, and enforce strict metadata/copy guardrails against unsupported claims.
The implementation remains website-only and reuses the current Astro page architecture plus central localized copy in `apps/website/src/data_files/site-copy.ts`.
## Technical Context
**Language/Version**: TypeScript 6.0.3 and Astro 6.3.3 content/runtime files
**Primary Dependencies**: Astro, Playwright, Tailwind CSS v4 (`@tailwindcss/vite`), Starlight docs stack
**Storage**: N/A (static public website content only)
**Testing**: Playwright smoke tests in `apps/website/tests/smoke` plus `astro check` during build
**Validation Lanes**: browser, confidence
**Target Platform**: Static website build and browser-rendered public routes
**Project Type**: Web application (Astro static site)
**Performance Goals**: No measurable runtime change target beyond maintaining current public page readability and route load behavior
**Constraints**: Preserve root workspace contracts (`package.json` scripts, `WEBSITE_PORT`, `apps/*` workspace), no `apps/platform` changes, no fake claims/proof artifacts
**Scale/Scope**: Two new DE routes plus EN counterparts, homepage integration, nav/footer updates, smoke-test updates
## UI / Surface Guardrail Plan
- **Guardrail scope**: no operator-facing surface change
- **Native vs custom classification summary**: N/A
- **Shared-family relevance**: public website copy and navigation families only
- **State layers in scope**: shell and page
- **Audience modes in scope**: customer/read-only
- **Decision/diagnostic/raw hierarchy plan**: decision-first on public marketing pages; no diagnostics/raw layer in scope
- **Raw/support gating plan**: N/A
- **One-primary-action / duplicate-truth control**: each use-case page keeps one primary CTA flow (`/contact`) and one supporting product CTA (`/platform`) to avoid action sprawl
- **Handling modes by drift class or surface**: report-only
- **Repository-signal treatment**: review-mandatory for public claim language
- **Special surface test profiles**: N/A
- **Required tests or manual smoke**: manual-smoke and browser smoke
- **Exception path and spread control**: none
- **Active feature PR close-out entry**: Smoke Coverage
## Shared Pattern & System Fit
- **Cross-cutting feature marker**: yes
- **Systems touched**: `site-copy` locale dictionaries, homepage composition, navigation/footer rendering, public route smoke inventory, metadata assertions
- **Shared abstractions reused**: localized copy object in `apps/website/src/data_files/site-copy.ts`, nav resolver in `apps/website/src/utils/navigation.ts`, smoke helper guardrail utilities in `apps/website/tests/smoke/smoke-helpers.ts`
- **New abstraction introduced? why?**: none
- **Why the existing abstraction was sufficient or insufficient**: existing copy-first Astro structure already centralizes public text and links; this feature extends those structures without introducing a new page framework
- **Bounded deviation / spread control**: none
## OperationRun UX Impact
- **Touches OperationRun start/completion/link UX?**: no
- **Central contract reused**: N/A
- **Delegated UX behaviors**: N/A
- **Surface-owned behavior kept local**: none
- **Queued DB-notification policy**: N/A
- **Terminal notification path**: N/A
- **Exception path**: none
## Provider Boundary & Portability Fit
- **Shared provider/platform boundary touched?**: yes
- **Provider-owned seams**: Microsoft 365-first and Intune-first-domain public wording
- **Platform-core seams**: public governance vocabulary, claim boundaries, trust-teaser language
- **Neutral platform terms / contracts preserved**: policy drift, evidence, review packs, accepted risks, audit trail, controlled recovery context
- **Retained provider-specific semantics and why**: Microsoft 365 and Intune remain explicit to reflect current-release product truth and avoid generic ambiguity
- **Bounded extraction or follow-up path**: document-in-feature only; no follow-up spec required for this scope
## Constitution Check
GATE status: Pass for website-only scope.
- Inventory-first: N/A (no inventory runtime changes)
- Read/write separation: Pass (no write behavior)
- Graph contract path: N/A (no Graph/API runtime)
- Deterministic capabilities: N/A
- RBAC-UX and tenant/workspace isolation: N/A (public unauthenticated pages)
- Run observability / OperationRun UX: N/A
- TEST-GOV-001: Pass (browser lane explicit, narrow smoke coverage, no helper cost expansion planned)
- PROP-001 / ABSTR-001 / PERSIST-001 / STATE-001 / BLOAT-001: Pass (no new persistence, abstractions, enums, or semantic frameworks)
- XCUT-001: Pass (reuse existing site copy/nav/test helper patterns)
- PROV-001: Pass (bounded provider wording, no platform-core runtime coupling)
- DECIDE-AUD-001: N/A for operator/status surfaces; public marketing hierarchy is still explicitly simplified
## Test Governance Check
- **Test purpose / classification by changed surface**: Browser
- **Affected validation lanes**: browser, confidence
- **Why this lane mix is the narrowest sufficient proof**: changes are public route/content/navigation/metadata concerns proven by route smoke and static-claim checks
- **Narrowest proving command(s)**:
- `pnpm --filter @tenantatlas/website build`
- `pnpm --filter @tenantatlas/website test tests/smoke/public-routes.spec.ts`
- `pnpm --filter @tenantatlas/website test tests/smoke/interaction.spec.ts`
- **Fixture / helper / factory / seed / context cost risks**: none
- **Expensive defaults or shared helper growth introduced?**: no
- **Heavy-family additions, promotions, or visibility changes**: none
- **Surface-class relief / special coverage rule**: public website browser smoke only
- **Closing validation and reviewer handoff**: reviewers verify route reachability, no placeholder links, no banned claims, route-family consistency, and that changed files remain inside `apps/website` plus feature spec artifacts
- **Budget / baseline / trend follow-up**: none
- **Review-stop questions**: lane fit, hidden helper cost, overbroad browser assertions, claim-boundary completeness
- **Escalation path**: document-in-feature
- **Active feature PR close-out entry**: Smoke Coverage
- **Why no dedicated follow-up spec is needed**: this is bounded copy/routing work inside existing public-site structures
## Project Structure
### Documentation (this feature)
```text
specs/407-msp-mittelstand-use-case-pages/
├── plan.md
├── spec.md
├── tasks.md
└── checklists/
└── requirements.md
```
### Source Code (repository root)
```text
apps/website/
├── src/
│ ├── pages/
│ │ ├── index.astro
│ │ ├── en/index.astro
│ │ ├── use-cases/msp.astro
│ │ ├── use-cases/mittelstand.astro
│ │ ├── en/use-cases/msp.astro
│ │ └── en/use-cases/mittelstand.astro
│ ├── components/pages/HomePage.astro
│ ├── components/pages/PlatformPage.astro
│ ├── data_files/site-copy.ts
│ ├── utils/navigation.ts
│ └── i18n.ts
└── tests/smoke/
├── public-routes.spec.ts
├── interaction.spec.ts
└── smoke-helpers.ts
```
**Structure Decision**: Web app/Astro structure under `apps/website`; no backend or platform-runtime extension.
## Route Family Decision
Selected route family: `/use-cases/...`
Chosen routes:
- `/use-cases/msp`
- `/use-cases/mittelstand`
- `/en/use-cases/msp`
- `/en/use-cases/mittelstand`
Reasoning:
- Matches the feature intent explicitly.
- Fits existing page-based Astro routing model.
- Keeps fallback route complexity unnecessary for this release.
Fallback route families (`/solutions/...`, `/einsatzbereiche/...`) are not used for this implementation.
## Platform Teaser Decision (FR-030)
Decision: include a compact platform-page teaser.
Implementation rule:
- Teaser contains a short audience split plus links to both use-case routes.
- Teaser stays compact and avoids duplicating the full use-case page copy.
## Static Claim Scan Commands
- `rg -n -i -e 'one[- ]click restore|immutable backups?|real[- ]time drift detection|court[- ]proof evidence|guaranteed compliance|guaranteed recovery|automatic restore|autonomous remediation' apps/website/src apps/website/public`
- `rg -n -i -e 'one[- ]click restore|immutable backups?|real[- ]time drift detection|court[- ]proof evidence|guaranteed compliance|guaranteed recovery|automatic restore|autonomous remediation' apps/website/dist`
- `git diff --name-only -- apps/website/public apps/website/src/images`
## Validation Results
- `corepack pnpm build` — pass.
- `WEBSITE_PORT=4322 corepack pnpm test tests/smoke/public-routes.spec.ts tests/smoke/interaction.spec.ts` — pass (`324 passed`, `6 skipped`).
- `WEBSITE_PORT=4322 corepack pnpm --filter @tenantatlas/website test` — pass (`324 passed`, `6 skipped`).
- `corepack pnpm --filter @tenantatlas/website format:check` — fails on nine pre-existing unrelated website files: `src/components/sections/landing/HeroSection.astro`, `src/components/sections/navbar&footer/FooterSection.astro`, `src/components/ui/blocks/IconBlock.astro`, `src/components/ui/blocks/LeftSection.astro`, `src/components/ui/blocks/MainSection.astro`, `src/components/ui/blocks/RightSection.astro`, `src/components/ui/blocks/StatsBig.astro`, `src/components/ui/blocks/StatsSmall.astro`, and `src/components/ui/forms/RegisterModal.astro`.
- `git status --short` confirms the implementation scope stayed out of `apps/platform/**`.
- `git diff --name-only -- apps/website/public apps/website/src/images` returned no changed files.
## Claim Scan Outcome
- No forbidden-term matches were found in `apps/website/src`, `apps/website/public`, or `apps/website/dist`.
- No intentional scan-hit rationale is needed for this feature.
## Comprehension Check Notes
- `SC-001` MSP comprehension check — pass. The hero, pain, outcomes, workflow, and PSA-boundary sections make repeatable governance reviews, evidence, follow-up, and service packaging visible within the first reading pass.
- `SC-002` Enterprise IT comprehension check — pass. The hero, stakeholder, workflow, and differentiation sections make drift visibility, traceable changes, evidence, and controlled recovery context visible within the first reading pass.
## Residual Follow-ups
- Repository-wide Prettier debt remains in nine untouched website files. This feature left those files unchanged.
## Complexity Tracking
No constitutional violations and no bloat-triggering additions are planned for this feature.
## Proportionality Review
N/A for this implementation plan. The feature introduces no new enum/status family, DTO/presenter/envelope layer, persisted entity/table/artifact, interface/contract/registry/resolver, taxonomy system, or cross-domain UI framework.

View File

@ -0,0 +1,324 @@
# Feature Specification: MSP & Mittelstand Use-Case Pages
**Feature Branch**: `407-msp-mittelstand-use-case-pages`
**Created**: 2026-05-26
**Status**: Draft
**Input**: User description: "Create dedicated public website use-case pages for MSPs and Mittelstand / Enterprise IT that position Tenantial as a Microsoft 365 governance layer for repeatable governance reviews, evidence, policy drift visibility, audit preparation, and controlled recovery context without turning the site into a generic Intune, helpdesk, or compliance-automation story."
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
- **Problem**: MSP buyers and internal IT buyers cannot quickly tell whether Tenantial fits their operating model once they move beyond the homepage, trust surface, and provider taxonomy.
- **Today's failure**: Public copy still risks sounding abstract, too architecture-heavy, or too Intune-adjacent, so buyers cannot answer fast whether Tenantial helps recurring customer governance reviews or internal control and audit preparation.
- **User-visible improvement**: A public visitor can self-qualify in one visit through two buyer-specific pages that translate Tenantial into repeatable governance outcomes for MSPs and for Mittelstand / Enterprise IT.
- **Smallest enterprise-capable version**: Two dedicated public use-case pages, lightweight homepage exposure, real discovery links through existing IA, page-specific metadata, and explicit claim boundaries.
- **Explicit non-goals**: No `apps/platform` changes, no MSP dashboard, no customer portal, no runtime Review Pack generation, no PSA integration, no billing, no fake case studies, no fake logos, no fake ROI numbers, no fake certifications, no fake downloadable PDFs, and no placeholder routes or links.
- **Permanent complexity imported**: Two bounded public website routes or equivalent IA destinations, one compact homepage teaser, optional nav/footer exposure, buyer-specific metadata, and public copy guardrails. No models, persistence, services, runtime abstractions, or product-state machinery are introduced.
- **Why now**: Spec 404 corrected sales messaging, Spec 405 corrected trust posture, and Spec 406 corrected provider/domain scope. The next sales blocker is buyer self-identification for MSPs versus internal IT teams.
- **Why not local**: A few extra homepage sentences cannot carry both the MSP service-delivery story and the internal-control story without flattening one of them into generic positioning.
- **Approval class**: Core Enterprise.
- **Red flags triggered**: Public overclaim risk, buyer-specific sales language, IA touch across homepage/nav/footer, and Microsoft 365 versus Intune category boundary wording.
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 2 | Wiederverwendung: 2 | **Gesamt: 11/12**
- **Decision**: approve.
### Red Flag Defense
This spec intentionally adds two audience-specific pages because the current public-site sequence still leaves the commercial fit decision implicit. The scope stays bounded to website IA, copy, and metadata. It must not become a runtime MSP feature, a pricing spec, a provider-support promise, or a fake proof surface.
## Scope
This spec defines two dedicated public website use-case pages for Tenantial's two primary buyer groups.
- **Relevant application for later implementation**: public website only
- **Depends on**: Spec 404 - Public Website Sales Copy & Positioning Rewrite; Spec 405 - DACH Trust, Datenschutz & Security Website Surface; Spec 406 - Provider & Policy Domain Public Taxonomy
- **Must not depend on**: `apps/platform` runtime changes
- **Primary audience**: MSP owners, MSP operators, IT leaders, enterprise IT teams, security teams, and DACH Mittelstand evaluators
- **Public message**: Microsoft 365 governance first, Intune as the first strong policy domain rather than the whole category, repeatable governance outcomes, audit-ready evidence, and clear boundaries against helpdesk, PSA, admin-center-clone, or blind automation positioning
- **Out of scope**: provider runtime support, customer portals, Review Pack generation, PSA integrations, billing or plans, localization foundations, fake customer proof, fake certifications, root workspace contract changes, and non-website implementation work
## Goals
- **G1**: Create a dedicated MSP page that sells Tenantial as a repeatable governance service layer for Microsoft 365 customer environments.
- **G2**: Create a dedicated Mittelstand / Enterprise IT page that sells Tenantial as a control, evidence, and auditability layer for internal Microsoft 365 operations.
- **G3**: Keep visible copy sharp, commercial, and grounded in B2B cybersecurity / IT-operations language.
- **G4**: Reuse the public positioning already established in Specs 404 through 406.
- **G5**: Hold a clear claim boundary around audits, evidence, backups, recovery, and provider support.
## Non-goals
- No `apps/platform` runtime work.
- No MSP portfolio dashboard or customer portal.
- No Review Pack generation or downloadable PDF artifact system.
- No PSA, ticketing, or billing integration.
- No Google, AWS, Okta, or generic multi-cloud support promise.
- No fake logos, fake case studies, fake ROI claims, or fake legal/compliance statements.
- No placeholder links, placeholder dropdowns, or `href="#"`.
## Spec Scope Fields *(mandatory)*
- **Scope**: N/A - public website surface outside authenticated workspace, tenant, or canonical-view product flows
- **Primary Routes**: preferred public routes `/use-cases/msp` and `/use-cases/mittelstand`; fallback to real route families such as `/solutions/...` or `/einsatzbereiche/...` only if current website IA requires them
- **Data Ownership**: no workspace-owned, tenant-owned, provider-owned, customer, backup, evidence, audit, or runtime product data is created, changed, or persisted by this feature
- **RBAC**: public read-only content only; no membership, role, capability, authorization, or authenticated product behavior changes
For canonical-view specs, the spec MUST define:
- **Default filter behavior when tenant-context is active**: N/A - no tenant-context or canonical product view is introduced
- **Explicit entitlement checks preventing cross-tenant leakage**: N/A - no authenticated tenant, workspace, or provider data is involved
## Cross-Cutting / Shared Pattern Reuse *(mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write `N/A - no shared interaction family touched`)*
- **Cross-cutting feature?**: yes
- **Interaction class(es)**: public navigation, footer links, homepage teaser, platform-page teaser, CTA links, metadata, and public claim language
- **Systems touched**: current public website shell, page-layout conventions, homepage, platform page, navigation, footer, and page metadata
- **Existing pattern(s) to extend**: existing public website layout, section, card/grid, badge, CTA, and metadata conventions
- **Shared contract / presenter / builder / renderer to reuse**: current website content structures and reusable presentation components
- **Why the existing shared path is sufficient or insufficient**: the site already has the public shell and sales surfaces; this feature needs buyer-specific destinations inside that shell, not a second microsite or a new design system
- **Allowed deviation and why**: a dedicated use-case route family is allowed when current IA supports it because the buyer stories need one focused destination each
- **Consistency impact**: Microsoft 365-first wording, Intune-as-first-strong-domain wording, evidence and review language, no-helpdesk boundary, trust teaser behavior, and safe metadata must stay aligned across homepage, platform page, use-case pages, nav, footer, and SEO copy
- **Review focus**: verify that links are real, the two pages are not duplicates, the MSP page clearly speaks to repeatable customer governance, the Enterprise IT page clearly speaks to internal control and auditability, and no unsupported claims appear
## OperationRun UX Impact *(mandatory when the feature creates, queues, deduplicates, resumes, blocks, completes, or deep-links to an `OperationRun`; otherwise write `N/A - no OperationRun start or link semantics touched`)*
- **Touches OperationRun start/completion/link UX?**: no
- **Shared OperationRun UX contract/layer reused**: N/A
- **Delegated start/completion UX behaviors**: N/A
- **Local surface-owned behavior that remains**: none
- **Queued DB-notification policy**: N/A
- **Terminal notification path**: N/A
- **Exception required?**: none
## Provider Boundary / Platform Core Check *(mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write `N/A - no shared provider/platform boundary touched`)*
- **Shared provider/platform boundary touched?**: yes
- **Boundary classification**: mixed public vocabulary only
- **Seams affected**: Microsoft 365-first positioning, Intune-as-first-strong-domain wording, provider-permission transparency, provider-extensible secondary messaging, and boundary language for helpdesk, PSA, admin center, and unsupported providers
- **Neutral platform terms preserved or introduced**: Microsoft 365 governance, policy drift, evidence, review packs, accepted risks, controlled recovery context, audit trail, provider permissions, recurring governance reviews, and customer-safe review consumption
- **Provider-specific semantics retained and why**: Microsoft 365 and Intune remain explicit because they are the first public market and the first strong policy domain; that specificity is necessary to avoid generic governance wording
- **Why this does not deepen provider coupling accidentally**: the feature sells buyer outcomes and boundaries, not a provider capability matrix or runtime provider framework
- **Follow-up path**: none for this feature; later audience or provider expansion belongs in follow-up public website specs only if product truth changes
## UI / Surface Guardrail Impact *(mandatory when operator-facing surfaces are changed; otherwise write `N/A`)*
N/A - public website use-case surfaces only; no authenticated operator-facing product surface is changed.
## Decision-First Surface Role *(mandatory when operator-facing surfaces are changed)*
N/A - no operator-facing product surface change.
## Audience-Aware Disclosure *(mandatory when operator-facing surfaces are changed)*
N/A - public buyer-facing website copy only; no operator diagnostics, support mode, or raw evidence surface is added here.
## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*
N/A - no operator-facing product surface change.
## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*
N/A - no operator-facing product surface change.
## Proportionality Review *(mandatory when structural complexity is introduced)*
- **New source of truth?**: no
- **New persisted entity/table/artifact?**: no
- **New abstraction?**: no
- **New enum/state/reason family?**: no
- **New cross-domain UI framework/taxonomy?**: no - the feature reuses the current public website shell and existing page patterns
- **Current operator problem**: public buyers cannot quickly map Tenantial to either repeatable MSP governance delivery or internal Microsoft 365 control and audit preparation
- **Existing structure is insufficient because**: homepage, trust, and provider taxonomy surfaces explain product truth but do not translate that truth into the two primary buying contexts
- **Narrowest correct implementation**: two dedicated public use-case pages with lightweight discovery from existing IA
- **Ownership cost**: future public copy, metadata, and links must keep buyer language and claim boundaries aligned with actual product truth
- **Alternative intentionally rejected**: expanding the homepage alone, because that would collapse two different commercial stories into one generic message
- **Release truth**: current public website truth only; no runtime product promise or future platform abstraction is introduced
### Compatibility posture
This feature assumes a pre-production environment.
Backward compatibility, legacy aliases, migration shims, historical fixtures, and compatibility-specific tests are out of scope unless explicitly required by this spec.
Canonical replacement is preferred over preservation.
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
- **Test purpose / classification**: Browser
- **Validation lane(s)**: browser, confidence
- **Why this classification and these lanes are sufficient**: public use-case quality is proven by reachable routes, readable desktop/mobile layouts, real links, static claim scans, and any existing website build/check/test commands that validate the public site
- **New or expanded test families**: none beyond website-only static checks and any existing public-site smoke coverage
- **Fixture / helper cost impact**: none
- **Heavy-family visibility / justification**: none
- **Special surface test profile**: N/A - public website surface
- **Standard-native relief or required special coverage**: ordinary public-site coverage only; verify route reachability, readable layout, real CTA links, homepage discovery, and claim-boundary compliance
- **Reviewer handoff**: confirm only website-facing files change, no `apps/platform` files change, all exposed links resolve to real destinations, and copy keeps MSP and Enterprise IT narratives distinct without unsafe promises
- **Budget / baseline / trend impact**: none expected
- **Escalation needed**: follow-up-spec only if later work needs public localization foundations, additional audience pages, or new proof assets
- **Active feature PR close-out entry**: Smoke Coverage
- **Planned validation commands**:
- inspect root and website package metadata before running scripts
- run only existing website `check`, `build`, or `test` commands if present
- run static scans for placeholder links, banned internal phrases, and unsupported claims in website source and committed public assets
- run desktop and mobile browser smoke for the MSP page, the Mittelstand page, homepage entry points, and any nav/footer links if local preview is available
## User Scenarios & Testing *(mandatory)*
### User Story 1 - MSP Buyer Self-Qualifies Fast (Priority: P1)
An MSP owner or operator opens the MSP use-case page and can immediately tell that Tenantial helps scale repeatable Microsoft 365 governance reviews across customer environments.
**Why this priority**: The MSP story is one of the two primary commercial entry points and is currently too implicit on the public site.
**Independent Test**: Can be fully tested by opening the MSP page and confirming that the hero, pain points, outcomes, workflow, and boundary section all describe recurring customer governance rather than generic IT administration.
**Acceptance Scenarios**:
1. **Given** a public MSP evaluator, **When** they read the MSP page hero and outcome sections, **Then** they understand that Tenantial helps with repeatable governance reviews, evidence, and service packaging across customer environments.
2. **Given** a visitor scanning the MSP page quickly, **When** they read the pain cards and workflow steps, **Then** they see manual review effort, hidden policy drift, weak customer evidence, and follow-up tracking translated into a repeatable governance process.
3. **Given** a visitor trying to classify the product, **When** they read the MSP boundary section, **Then** they see that Tenantial is not positioned as a PSA, ticketing suite, helpdesk, or blind remediation engine.
---
### User Story 2 - Internal IT Buyer Understands Control Value (Priority: P1)
An IT leader, security team member, or enterprise IT evaluator opens the Mittelstand / Enterprise IT page and can immediately tell that Tenantial helps make Microsoft 365 policy changes, drift, evidence, and recovery context more controllable and reviewable.
**Why this priority**: The internal IT story is the second primary buying context and must not be flattened into MSP language or generic compliance copy.
**Independent Test**: Can be fully tested by opening the Enterprise IT page and confirming that the hero, pain points, stakeholder view, outcomes, workflow, and differentiation section all speak to internal control and auditability.
**Acceptance Scenarios**:
1. **Given** an internal IT evaluator, **When** they read the hero and outcome sections, **Then** they understand that Tenantial helps with policy drift visibility, change traceability, evidence, review preparation, and controlled recovery context.
2. **Given** a visitor scanning the stakeholder cards, **When** they review IT Operations, Security, IT leadership, and Audit / Datenschutz roles, **Then** they can see how the same governance surface supports different internal stakeholders.
3. **Given** a visitor comparing tools, **When** they read the differentiation section, **Then** they see that Tenantial is not framed as another admin center, helpdesk, PSA, SIEM, or autonomous compliance automation product.
---
### User Story 3 - Public Visitors Can Reach Both Buyer Paths (Priority: P2)
A public visitor should be able to discover both use-case pages through the existing website IA without broken links or placeholder navigation.
**Why this priority**: Buyer-specific messaging only helps if it is discoverable from the surfaces where visitors first form expectations.
**Independent Test**: Can be fully tested by following homepage, platform-page, navigation, or footer links to both use-case pages on desktop and mobile.
**Acceptance Scenarios**:
1. **Given** a visitor on the homepage, **When** they use the use-case teaser entry points, **Then** both buyer pages resolve through real links.
2. **Given** a visitor using any nav or footer links exposed by this feature, **When** they open the MSP or Mittelstand destination, **Then** each link resolves without placeholders or dead routes.
3. **Given** a mobile visitor, **When** they navigate to either use-case page, **Then** the headline, core sections, and primary CTA remain readable and actionable.
---
### User Story 4 - Buyers See Safe Claim Boundaries (Priority: P2)
A public evaluator should be able to understand what Tenantial helps with today without reading claims about unsupported automation, compliance guarantees, or non-existent provider support.
**Why this priority**: The feature improves sellability only if it avoids creating new trust risk.
**Independent Test**: Can be fully tested by reviewing both use-case pages, their metadata, and any homepage/nav/footer exposure for banned phrases and unsupported claims.
**Acceptance Scenarios**:
1. **Given** a visitor reading either page, **When** they review the evidence, audit, backup, and recovery language, **Then** they do not see claims about real-time detection, automatic remediation, one-click restore, immutable backups, or guaranteed compliance.
2. **Given** a visitor reading trust teasers or provider references, **When** they inspect the copy, **Then** they do not see Google, AWS, or other non-verified providers presented as live support.
3. **Given** a visitor reading page headlines and supporting copy, **When** they look for product-category cues, **Then** they see Microsoft 365 first and Intune only as the first strong policy domain rather than the full product category.
### Edge Cases
- What happens when the current website IA does not support `/use-cases/...` cleanly? The implementation must choose a real route family that matches current conventions and document the decision.
- What happens when a suggested CTA target such as trust, demo, platform, or review-pack detail does not exist as a real destination? The CTA must be omitted or mapped to an existing real destination.
- What happens when the active site language is German-first, English-first, or mixed? The pages must follow the current site convention instead of introducing a new localization foundation.
- What happens when a copy line risks sounding like Tenantial is a helpdesk, admin-center clone, compliance certification, or autonomous remediation tool? The line must be rewritten to preserve governance-layer positioning.
- What happens when review packs, accepted risks, or evidence are referenced? They must be framed as governance deliverables and review outcomes, not as fake downloadable artifacts or automated guarantees.
## Assumptions
- The current public website can support two real buyer-specific destinations without changing root workspace contracts.
- At least one real destination exists for primary CTA flows such as platform, demo/contact, or trust; secondary CTA variants may be omitted when no real destination exists.
- The current language strategy may be German-first or mixed; implementation should follow existing conventions rather than normalizing the whole site.
- Review packs, accepted risks, evidence, and recovery context can be marketed as governance outcomes without claiming runtime automation, downloadable PDFs, or legal certification.
- Intune remains the first strong public policy domain, but the feature must not collapse Tenantial into an Intune-only category story.
## Requirements *(mandatory)*
This feature introduces no Microsoft Graph calls, no write/change product behavior, no persistence, no OperationRun flow, no RBAC mutation, and no provider runtime capability. Its only additions are bounded public website pages, discovery links, and metadata that translate existing product truth into buyer-specific positioning.
### Functional Requirements
#### Scope And Route
- **FR-001**: The implementation MUST remain public-website-only and MUST NOT require `apps/platform` runtime changes.
- **FR-002**: The public website MUST provide one dedicated MSP use-case page.
- **FR-003**: The public website MUST provide one dedicated Mittelstand / Enterprise IT use-case page.
- **FR-004**: The implementation MUST follow the current website route family; preferred routes are `/use-cases/msp` and `/use-cases/mittelstand`, with real fallback route families such as `/solutions/...` or `/einsatzbereiche/...` only when current IA requires them.
- **FR-005**: Both use-case pages MUST be reachable from at least one existing public-site entry point such as the homepage, platform page, navigation, or footer.
- **FR-006**: Every CTA, teaser, nav link, footer link, and in-page link added by this feature MUST resolve to a real destination; placeholder links and `href="#"` are forbidden.
#### MSP Page Positioning
- **FR-007**: The MSP page MUST position Tenantial as a repeatable Microsoft 365 governance layer for service providers managing customer environments.
- **FR-008**: The MSP page MUST explain outcomes in terms of fewer manual tenant checks, less screenshot- or Excel-based governance work, stronger customer evidence, repeatable review preparation, and clearer follow-up on findings and accepted risks.
- **FR-009**: The MSP page MUST include a hero section, pain section, outcomes section, repeatable workflow section, capability section, trust teaser, boundary section, and final CTA.
- **FR-010**: The MSP pain section MUST cover manual reviews, hidden policy drift, weak customer-facing evidence, and the lack of a repeatable governance package.
- **FR-011**: The MSP outcome section MUST cover customer review packs, multi-customer control, audit-ready evidence, recurring governance-service packaging, and clear follow-up handling.
- **FR-012**: The MSP workflow section MUST describe a repeatable sequence that captures policy state, identifies drift, bundles evidence, classifies risks, prepares review context, and keeps follow-up visible.
- **FR-013**: The MSP capability section MUST cover governance reviews, policy backup and versioning, drift visibility, accepted-risk visibility, audit evidence, and a PSA handoff boundary.
- **FR-014**: The MSP boundary section MUST state that Tenantial is not a PSA, ticketing system, generic helpdesk, all-in-one MSP suite, blind remediation engine, or Intune-only backup utility.
- **FR-015**: The MSP trust teaser MAY link to the existing trust route only when that route exists as a real destination and MUST avoid unverified legal, hosting, or certification claims.
- **FR-016**: The MSP final CTA MUST use only real destinations and MUST keep the sales promise bounded to governance visibility, evidence, backups, review preparation, and controlled follow-up.
#### Mittelstand / Enterprise IT Positioning
- **FR-017**: The Mittelstand / Enterprise IT page MUST position Tenantial as a control, evidence, and auditability layer for internal Microsoft 365 operations.
- **FR-018**: The page MUST explain outcomes in terms of policy drift visibility, change traceability, audit-ready evidence, review preparation, recovery context, and clearer decision records.
- **FR-019**: The page MUST include a hero section, pain section, outcomes section, stakeholder section, workflow section, differentiation section, trust teaser, and final CTA.
- **FR-020**: The pain section MUST cover undocumented changes, audit pressure, recovery uncertainty, and screenshot- or export-based governance processes.
- **FR-021**: The outcomes section MUST cover drift visibility, change traceability, evidence preparation, safer recovery assessment, and documented decisions.
- **FR-022**: The stakeholder section MUST speak separately to IT Operations, Security teams, IT leadership, and Audit / Datenschutz stakeholders.
- **FR-023**: The workflow section MUST describe a sequence that secures state, identifies drift, prepares evidence, evaluates risk, prepares review context, and records next decisions.
- **FR-024**: The differentiation section MUST explain that Tenantial is the governance layer above Microsoft admin surfaces rather than another admin center.
- **FR-025**: The Mittelstand trust teaser MAY link to the existing trust route only when that route exists as a real destination and MUST avoid unverified legal, hosting, or certification claims.
- **FR-026**: The Mittelstand final CTA MUST use only real destinations and MUST keep the sales promise bounded to control, evidence, reviews, and controlled recovery preparation.
#### Homepage, Navigation, Footer, And Discovery
- **FR-027**: The homepage MUST expose a compact buyer teaser for both MSPs and Mittelstand / Enterprise IT when the current homepage structure can support it without a heavy IA rewrite.
- **FR-028**: The homepage teaser MUST summarize each buyer outcome distinctly and MUST link to the corresponding real destination.
- **FR-029**: Navigation or footer links MAY expose the use-case pages only where current IA supports them; the feature MUST NOT introduce a placeholder dropdown or a heavy nav system solely for these two pages.
- **FR-030**: Any platform-page teaser added by this feature MUST reinforce the same buyer split and MUST NOT duplicate whole page copy verbatim.
#### Metadata, Language, And Claim Guardrails
- **FR-031**: The MSP page MUST have metadata that describes Microsoft 365 governance for MSPs, including repeatable reviews, evidence, backups, accepted risks, and review preparation.
- **FR-032**: The Mittelstand / Enterprise IT page MUST have metadata that describes Microsoft 365 governance for internal IT teams, including drift visibility, changes, evidence, backups, reviews, and recovery context.
- **FR-033**: Visible copy and metadata MUST use strong but safe governance language such as policy drift, evidence, review packs, accepted risks, audit trail, controlled recovery preparation, and repeatable governance reviews.
- **FR-034**: Visible copy and metadata MUST NOT use weak internal phrases such as product-category debates, architecture-taxonomy jargon, source-of-truth-first phrasing, provider-neutral-core wording, or other internal implementation language.
- **FR-035**: Visible copy and metadata MUST NOT claim real-time drift detection, automatic remediation, automatic restore, immutable backups, complete compliance, legal certification, court-proof evidence, or live Google/AWS support unless separately verified as current product truth.
- **FR-036**: Intune MAY appear as the first strong policy domain or first strong example, but the pages MUST present Tenantial as Microsoft 365 governance first and MUST NOT frame Intune as the entire product category.
- **FR-037**: Review packs, accepted risks, evidence, provider permissions, and recovery context MAY be described as governance outcomes, but the feature MUST NOT introduce fake downloadable artifacts, fake proof packs, or fake automated deliverables.
#### Scope Safety
- **FR-038**: The implementation MUST NOT introduce fake logos, fake case studies, fake ROI numbers, fake certifications, fake legal claims, fake downloadable PDFs, or placeholder routes.
- **FR-039**: The implementation MUST preserve root workspace contracts, including existing root script names, the website package name, the `WEBSITE_PORT` convention, and the `apps/*` workspace convention.
- **FR-040**: The implementation MUST document the chosen route family and the exact validation commands run when the feature is implemented.
## UI Action Matrix *(mandatory when Filament is changed)*
N/A - no Filament Resource, RelationManager, or Page is changed by this feature.
### Key Entities *(include if feature involves data)*
- **MSP Use-Case Page**: A public buyer-facing page that explains repeatable Microsoft 365 governance delivery for service providers across customer environments.
- **Mittelstand / Enterprise IT Use-Case Page**: A public buyer-facing page that explains internal control, evidence, auditability, and recovery-context value for Microsoft 365 teams.
- **Use-Case Discovery Link**: A homepage, platform-page, navigation, or footer entry that routes a visitor to one of the buyer-specific pages through a real destination and buyer-specific summary.
## Success Criteria *(mandatory)*
### Measurable Outcomes
- **SC-001**: In internal copy review, a first-time MSP evaluator can identify within 60 seconds that Tenantial helps scale repeatable governance reviews, evidence, and follow-up across customer Microsoft 365 environments.
- **SC-002**: In internal copy review, a first-time internal IT evaluator can identify within 60 seconds that Tenantial helps with policy drift visibility, change traceability, evidence, and controlled recovery preparation for Microsoft 365.
- **SC-003**: QA finds zero placeholder links or broken exposed routes across the new use-case pages and any homepage, platform-page, navigation, or footer entry points changed by this feature.
- **SC-004**: Static copy review finds zero occurrences of banned internal phrases or unsupported claims on new or updated public surfaces created by this feature.
- **SC-005**: Desktop and mobile smoke review confirms that both buyer pages remain readable, keep their primary CTA visible, and preserve distinct buyer messaging without layout breakage.

View File

@ -0,0 +1,276 @@
# Tasks: MSP & Mittelstand Use-Case Pages
**Input**: Design documents from `/specs/407-msp-mittelstand-use-case-pages/`
**Prerequisites**: `plan.md` (required), `spec.md` (required)
**Tests**: Runtime behavior changes are in scope for `apps/website`, so browser smoke and route/metadata assertions are required.
## Test Governance Checklist
- [x] Lane assignment is named and is the narrowest sufficient proof for the changed behavior.
- [x] New or changed tests stay in the smallest honest family, and any browser addition is explicit.
- [x] Shared helpers and fixtures stay cheap by default; any widening is isolated or documented.
- [x] Planned validation commands cover the change without unrelated lane cost.
- [x] Surface test profile is explicit (`Browser`, `public website`).
- [x] Any escalation or follow-up spec decision is documented in the PR notes.
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: Confirm repository contracts, discover concrete website integration points, and define scope-safe implementation boundaries.
- [x] T001 Confirm active feature branch and clean target scope in `specs/407-msp-mittelstand-use-case-pages/spec.md`
- [x] T002 Verify root workspace contracts in `package.json`
- [x] T003 Verify workspace package contracts in `apps/website/package.json`
- [x] T004 Map current route and locale entrypoints in `apps/website/src/pages/index.astro` and `apps/website/src/pages/en/index.astro`
- [x] T005 [P] Map homepage composition surface in `apps/website/src/components/pages/HomePage.astro`
- [x] T006 [P] Map navigation/footer source of truth in `apps/website/src/data_files/site-copy.ts` and `apps/website/src/utils/navigation.ts`
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: Establish IA decision, shared copy scaffolding, and smoke-test hooks used by all user stories.
**⚠️ CRITICAL**: No user story work should begin before this phase is complete.
- [x] T007 Decide and document route family in `specs/407-msp-mittelstand-use-case-pages/plan.md` (selected: `/use-cases/...`)
- [x] T008 Add use-case copy schema for DE locale in `apps/website/src/data_files/site-copy.ts`
- [x] T009 [P] Add use-case copy schema for EN locale in `apps/website/src/data_files/site-copy.ts`
- [x] T010 Add nav/footer link slots for use-case discoverability in `apps/website/src/data_files/site-copy.ts`
- [x] T011 [P] Extend route smoke inventory for new pages in `apps/website/tests/smoke/smoke-helpers.ts`
- [x] T012 Add baseline route metadata placeholders for new pages in `apps/website/tests/smoke/public-routes.spec.ts`
- [x] T013 Capture static-claim scan command set in `specs/407-msp-mittelstand-use-case-pages/plan.md`
**Checkpoint**: Foundation is ready for story implementation.
---
## Phase 3: User Story 1 - MSP Buyer Self-Qualifies Fast (Priority: P1) 🎯 MVP
**Goal**: Deliver an MSP-specific page that clearly sells repeatable Microsoft 365 governance services and boundaries.
**Independent Test**: Open `/use-cases/msp`, verify hero/pain/outcomes/workflow/capabilities/boundary/final CTA, and confirm real links plus no unsupported claims.
### Tests for User Story 1
- [x] T014 [P] [US1] Add MSP route title/description assertions in `apps/website/tests/smoke/public-routes.spec.ts`
- [x] T015 [P] [US1] Add MSP content-intent assertions in `apps/website/tests/smoke/interaction.spec.ts`
### Implementation for User Story 1
- [x] T016 [US1] Create MSP route page in `apps/website/src/pages/use-cases/msp.astro`
- [x] T017 [US1] Create EN MSP route page in `apps/website/src/pages/en/use-cases/msp.astro`
- [x] T018 [US1] Implement MSP hero copy and primary CTAs in `apps/website/src/data_files/site-copy.ts`
- [x] T019 [US1] Implement MSP pain section cards in `apps/website/src/data_files/site-copy.ts`
- [x] T020 [US1] Implement MSP outcomes section in `apps/website/src/data_files/site-copy.ts`
- [x] T021 [US1] Implement MSP workflow steps in `apps/website/src/data_files/site-copy.ts`
- [x] T022 [US1] Implement MSP capability cards and PSA boundary copy in `apps/website/src/data_files/site-copy.ts`
- [x] T023 [US1] Implement MSP trust teaser and final CTA with real destinations in `apps/website/src/data_files/site-copy.ts`
- [x] T024 [US1] Complete MSP page section rendering directly in `apps/website/src/pages/use-cases/msp.astro`
**Checkpoint**: User Story 1 is independently functional and demonstrable.
---
## Phase 4: User Story 2 - Internal IT Buyer Understands Control Value (Priority: P1)
**Goal**: Deliver a Mittelstand/Enterprise IT page focused on internal control, auditability, drift visibility, and recovery context.
**Independent Test**: Open `/use-cases/mittelstand`, verify stakeholder-specific value framing and differentiation from admin-center/helpdesk/automation tools.
### Tests for User Story 2
- [x] T025 [P] [US2] Add Mittelstand route title/description assertions in `apps/website/tests/smoke/public-routes.spec.ts`
- [x] T026 [P] [US2] Add Mittelstand content-intent assertions in `apps/website/tests/smoke/interaction.spec.ts`
### Implementation for User Story 2
- [x] T027 [US2] Create Mittelstand route page in `apps/website/src/pages/use-cases/mittelstand.astro`
- [x] T028 [US2] Create EN Mittelstand route page in `apps/website/src/pages/en/use-cases/mittelstand.astro`
- [x] T029 [US2] Implement Mittelstand hero copy and CTAs in `apps/website/src/data_files/site-copy.ts`
- [x] T030 [US2] Implement Mittelstand pain section cards in `apps/website/src/data_files/site-copy.ts`
- [x] T031 [US2] Implement Mittelstand outcomes section in `apps/website/src/data_files/site-copy.ts`
- [x] T032 [US2] Implement stakeholder cards (IT Ops, Security, IT-Leitung, Audit/Datenschutz) in `apps/website/src/data_files/site-copy.ts`
- [x] T033 [US2] Implement Mittelstand workflow steps in `apps/website/src/data_files/site-copy.ts`
- [x] T034 [US2] Implement differentiation and trust teaser copy in `apps/website/src/data_files/site-copy.ts`
- [x] T035 [US2] Implement Mittelstand final CTA with real destinations in `apps/website/src/data_files/site-copy.ts`
**Checkpoint**: User Story 2 is independently functional and demonstrable.
---
## Phase 5: User Story 3 - Public Visitors Reach Both Buyer Paths (Priority: P2)
**Goal**: Ensure both use-case pages are discoverable through homepage and existing IA without placeholder links.
**Independent Test**: From homepage plus nav/footer entry points, both use-case routes are reachable on desktop/mobile and all links resolve intentionally.
### Tests for User Story 3
- [x] T036 [P] [US3] Add homepage teaser-link assertions in `apps/website/tests/smoke/interaction.spec.ts`
- [x] T037 [P] [US3] Add navigation/footer intentional-link assertions for use-case routes in `apps/website/tests/smoke/public-routes.spec.ts`
### Implementation for User Story 3
- [x] T038 [US3] Add homepage use-case teaser section structure in `apps/website/src/components/pages/HomePage.astro`
- [x] T039 [US3] Add homepage MSP teaser copy and route mapping in `apps/website/src/data_files/site-copy.ts`
- [x] T040 [US3] Add homepage Mittelstand teaser copy and route mapping in `apps/website/src/data_files/site-copy.ts`
- [x] T041 [US3] Add DE navigation links for use cases in `apps/website/src/data_files/site-copy.ts`
- [x] T042 [US3] Add EN navigation links for use cases in `apps/website/src/data_files/site-copy.ts`
- [x] T043 [US3] Add DE footer links for use cases in `apps/website/src/data_files/site-copy.ts`
- [x] T044 [US3] Add EN footer links for use cases in `apps/website/src/data_files/site-copy.ts`
- [x] T045 [US3] Ensure localized href handling for new routes in `apps/website/src/i18n.ts`
- [x] T046 [US3] Validate no `href="#"` is introduced in use-case entrypoints by scanning `apps/website/src`
- [x] T068 [US3] Decide whether to add a compact platform teaser for use cases and record decision for FR-030 in `specs/407-msp-mittelstand-use-case-pages/plan.md`
- [x] T069 [US3] If platform teaser is enabled, add concise MSP/Enterprise links in `apps/website/src/components/pages/PlatformPage.astro` without duplicating full use-case copy
**Checkpoint**: User Story 3 is independently functional and demonstrable.
---
## Phase 6: User Story 4 - Buyers See Safe Claim Boundaries (Priority: P2)
**Goal**: Enforce copy and metadata guardrails so pages remain commercial but do not overclaim.
**Independent Test**: Source and rendered pages pass forbidden-term scans and metadata/title checks for both use-case routes.
### Tests for User Story 4
- [x] T047 [P] [US4] Add forbidden-claim assertions for use-case routes in `apps/website/tests/smoke/public-routes.spec.ts`
- [x] T048 [P] [US4] Extend reusable forbidden-claim patterns if needed in `apps/website/tests/smoke/smoke-helpers.ts`
### Implementation for User Story 4
- [x] T049 [US4] Add DE metadata title/description strings for MSP and Mittelstand in `apps/website/src/data_files/site-copy.ts`
- [x] T050 [US4] Add EN metadata title/description strings for MSP and Mittelstand in `apps/website/src/data_files/site-copy.ts`
- [x] T051 [US4] Remove weak/internal phrasing from new copy sections in `apps/website/src/data_files/site-copy.ts`
- [x] T052 [US4] Enforce MSP boundary claims in route content at `apps/website/src/pages/use-cases/msp.astro`
- [x] T053 [US4] Enforce Mittelstand boundary claims in route content at `apps/website/src/pages/use-cases/mittelstand.astro`
- [x] T054 [US4] Run static forbidden-term scans on `apps/website/src` and `apps/website/public`
- [x] T055 [US4] If `apps/website/dist` is updated, run forbidden-term scans on `apps/website/dist`
- [x] T056 [US4] Document any intentional scan hit rationale in `specs/407-msp-mittelstand-use-case-pages/plan.md`
- [x] T057 [US4] Confirm no fake proof artifacts were added by reviewing `apps/website/public` and `apps/website/src/images`
- [x] T058 [US4] Confirm Intune remains first strong domain but not full category story in new use-case copy within `apps/website/src/data_files/site-copy.ts`
- [x] T070 [US4] Execute a 60-second MSP comprehension check (SC-001) and record pass/fail notes in `specs/407-msp-mittelstand-use-case-pages/plan.md`
- [x] T071 [US4] Execute a 60-second Enterprise IT comprehension check (SC-002) and record pass/fail notes in `specs/407-msp-mittelstand-use-case-pages/plan.md`
**Checkpoint**: User Story 4 is independently functional and demonstrable.
---
## Phase 7: Polish & Cross-Cutting Concerns
**Purpose**: Final validation, formatting, build/test execution, and close-out reporting.
- [x] T059 [P] Run formatting check using scripts in `apps/website/package.json` via `pnpm --filter @tenantatlas/website format:check`
- [x] T060 Run Astro/build validation for routes under `apps/website/src/pages` via `pnpm --filter @tenantatlas/website build`
- [x] T061 Run smoke suite defined in `apps/website/playwright.config.ts` via `pnpm --filter @tenantatlas/website test -- --grep smoke`
- [x] T062 Run route-level smoke in `apps/website/tests/smoke/public-routes.spec.ts` via `pnpm --filter @tenantatlas/website test tests/smoke/public-routes.spec.ts`
- [x] T063 Perform desktop browser smoke for `/use-cases/msp` and `/use-cases/mittelstand` in `apps/website/tests/smoke/interaction.spec.ts`
- [x] T064 Perform mobile viewport smoke for `/use-cases/msp` and `/use-cases/mittelstand` in `apps/website/tests/smoke/interaction.spec.ts`
- [x] T065 Confirm changed-file scope excludes `apps/platform/**` by reviewing `specs/407-msp-mittelstand-use-case-pages/tasks.md` against `git status --short`
- [x] T066 Record command results, route decision, and residual follow-ups in `specs/407-msp-mittelstand-use-case-pages/plan.md`
- [x] T067 Record active feature close-out summary in `specs/407-msp-mittelstand-use-case-pages/checklists/requirements.md`
---
## Dependencies & Execution Order
### Phase Dependencies
- **Setup (Phase 1)**: No dependencies, starts immediately.
- **Foundational (Phase 2)**: Depends on Setup completion and blocks story work.
- **User Stories (Phases 3-6)**: Depend on Foundational completion; US1 and US2 can run in parallel, then US3 and US4.
- **Polish (Phase 7)**: Depends on all selected user stories being complete.
### User Story Dependencies
- **US1 (P1)**: Starts after Phase 2, no dependency on other stories.
- **US2 (P1)**: Starts after Phase 2, no dependency on other stories.
- **US3 (P2)**: Depends on US1 and US2 routes existing.
- **US4 (P2)**: Depends on US1 and US2 content existing; can overlap with late US3 work.
### Within Each User Story
- Tests/tasks defining assertions are created before or alongside implementation and must fail before final pass.
- Route files and copy schema come before link wiring.
- Implementation completes before build/smoke validation.
### Parallel Opportunities
- Setup tasks marked `[P]` can run in parallel.
- Foundational test-hook and locale-copy tasks marked `[P]` can run in parallel.
- US1 and US2 can be developed in parallel once foundational tasks complete.
- US3 nav and footer link tasks can run in parallel across locales.
- US4 metadata and forbidden-term scan tasks marked `[P]` can run in parallel.
---
## Parallel Example: User Story 1
```bash
Task: "T014 [US1] Add MSP route title/description assertions in apps/website/tests/smoke/public-routes.spec.ts"
Task: "T015 [US1] Add MSP content-intent assertions in apps/website/tests/smoke/interaction.spec.ts"
Task: "T016 [US1] Create MSP route page in apps/website/src/pages/use-cases/msp.astro"
Task: "T017 [US1] Create EN MSP route page in apps/website/src/pages/en/use-cases/msp.astro"
```
## Parallel Example: User Story 2
```bash
Task: "T025 [US2] Add Mittelstand route title/description assertions in apps/website/tests/smoke/public-routes.spec.ts"
Task: "T026 [US2] Add Mittelstand content-intent assertions in apps/website/tests/smoke/interaction.spec.ts"
Task: "T027 [US2] Create Mittelstand route page in apps/website/src/pages/use-cases/mittelstand.astro"
Task: "T028 [US2] Create EN Mittelstand route page in apps/website/src/pages/en/use-cases/mittelstand.astro"
```
## Parallel Example: User Story 3
```bash
Task: "T041 [US3] Add DE navigation links for use cases in apps/website/src/data_files/site-copy.ts"
Task: "T042 [US3] Add EN navigation links for use cases in apps/website/src/data_files/site-copy.ts"
Task: "T043 [US3] Add DE footer links for use cases in apps/website/src/data_files/site-copy.ts"
Task: "T044 [US3] Add EN footer links for use cases in apps/website/src/data_files/site-copy.ts"
```
## Parallel Example: User Story 4
```bash
Task: "T047 [US4] Add forbidden-claim assertions for use-case routes in apps/website/tests/smoke/public-routes.spec.ts"
Task: "T048 [US4] Extend reusable forbidden-claim patterns if needed in apps/website/tests/smoke/smoke-helpers.ts"
Task: "T049 [US4] Add DE metadata title/description strings for MSP and Mittelstand in apps/website/src/data_files/site-copy.ts"
Task: "T050 [US4] Add EN metadata title/description strings for MSP and Mittelstand in apps/website/src/data_files/site-copy.ts"
```
---
## Implementation Strategy
### MVP First (US1 Only)
1. Complete Phase 1 (Setup).
2. Complete Phase 2 (Foundational).
3. Complete Phase 3 (US1).
4. Validate US1 independently with route metadata plus smoke assertions.
5. Demo/deploy MVP slice if desired.
### Incremental Delivery
1. Finish Setup + Foundational once.
2. Deliver US1 (MSP page), validate, and ship.
3. Deliver US2 (Mittelstand page), validate, and ship.
4. Deliver US3 (discoverability), validate, and ship.
5. Deliver US4 (claim boundaries), validate, and ship.
### Suggested MVP Scope
- **MVP**: User Story 1 only (MSP use-case page), because it delivers a complete buyer-facing value slice with independent validation.
---
## Notes
- `[P]` tasks touch different files and can run in parallel.
- `[USx]` tags map every story-phase task to a specific user story.
- All file paths target `apps/website` or `specs/407-msp-mittelstand-use-case-pages` to preserve scope.
- No task introduces `apps/platform` runtime changes or root workspace contract changes.