Shopware Agentur Frankfurt: Architektur-Optimierung für Shopware 6 (API-first, MVC, PWA-ready)

1) Architektur-Audit: Ist-Zustand messen, bevor Sie umbauen
Für eine belastbare Architektur-Optimierung in Shopware 6 starten wir mit einem Audit, das nicht „Gefühl“, sondern Systemgrenzen sichtbar macht: Latenzen, Kopplungen, Datenflüsse, Release-Risiken und Erweiterbarkeit. Ziel ist eine Architektur, die Änderungen (Sortimente, Pricing, Kampagnen, internationale Expansion) ohne Performance- oder Deployment-Schmerz mitmacht.
Interessiert an diesem Thema?
Kontaktieren Sie uns für eine kostenlose Beratung →Checkliste: Was wir technisch erfassen
- Runtime-Profile: PHP-FPM/Worker, MySQL-Last, Redis-Cache, Messenger-Queues, Indexer-Laufzeiten
- API-Nutzung: Store API / Admin API Konsum, Auth-Strategien, Rate-Limits, Payload-Größen
- Plugin-Landschaft: Event-Subscriber, Decorators, DAL-Extensions, Konfliktpotenzial
- Frontend: Storefront vs. PWA, Rendering-Strategie, Core Web Vitals
- Deployments: Blue/Green oder Rolling, Migrations-/Indexer-Fenster, Rollback-Fähigkeit
- Integrationen: ERP/PIM/CRM/Payments/Versand als synchron vs. asynchron (Queue)
| Feature | Details |
|---|---|
| API-first Readiness | Trennung von Frontend & Commerce-Backbone, klare API-Verträge, versionierte Endpoints |
| MVC-Konformität | Saubere Verantwortlichkeiten (Controller/Service/Repository), wartungsfähige Erweiterungen |
| PWA-Fähigkeit | Store API-First, SSR/ISR-Strategie, Edge-Cache & Token-Handling |
| Deployment-Sicherheit | Migrations-Runbooks, Indexer-Strategie, Rollback-Plan, Secrets-Management |
| Performance | Cache-Hit-Rate, DB-Indizes, Such-Stack, Async-Verarbeitung via Messenger |
2) Zielbild definieren: API-first Approach als Architekturleitlinie
Ein API-first Approach bedeutet: Sie definieren zuerst die Schnittstellenverträge (Ressourcen, Payloads, Auth, Fehlercodes) und bauen UI/Integrationen danach – nicht umgekehrt. Für Shopware 6 ist das besonders relevant, weil Sie damit Storefront, PWA und externe Systeme entkoppeln.
Warum API-first in Shopware 6 konkret hilft
- Entkopplung: Frontend-Teams arbeiten unabhängig von Backend-Teams (Release-Zyklen werden kürzer).
- Skalierung: Hohe Read-Last kann über Caching/CDN/Edge adressiert werden, ohne Kernlogik zu duplizieren.
- Integrationssicherheit: ERP/PIM-Anbindung über stabile Verträge (weniger „Breaking Changes“).
- Messbarkeit: API-Latenzen, Error-Rates und Payload-Größen sind klare Optimierungsmetriken.
API Platform: Rolle im Architekturplan
Unter API Platform verstehen wir die Betriebs- und Design-Schicht Ihrer Schnittstellen: API-Gateway/Reverse Proxy, Auth, Rate-Limiting, Observability, Versionierung und Developer Experience (Doku, Tests). In Shopware-Kontext heißt das: Admin API/Store API sauber konsumieren, ggf. BFF (Backend-for-Frontend) etablieren und Integrationen standardisieren.
3) MVC Pattern in Shopware 6: Wartbarkeit durch klare Verantwortlichkeiten
Das MVC Pattern (Model-View-Controller) sorgt dafür, dass Business-Logik nicht im Controller „klebt“ und Views nicht zu viel wissen. In Shopware 6 (Symfony-basiert) ist das entscheidend, um Plugins/Extensions konfliktarm zu halten.
So wenden wir MVC pragmatisch an
- Controller: Nur Request/Response, Validierung/Mapping, keine Geschäftsregeln.
- Service Layer: Business-Regeln, Orchestrierung, Transaktionsgrenzen.
- Model/DAL: Datenzugriff über Repository/DAL, klare Entities, keine SQL-Spaghetti.
- View: Storefront Twig oder PWA UI; Darstellung, keine Domänenlogik.
4) Referenz-Architektur: Shopware 6 + PWA + Integrationen (API-first)
Ein typisches Zielbild für wachsende Shops: Shopware 6 als Commerce-Kern, eine PWA als Frontend, Integrationen (ERP/PIM/Payments) asynchron über Queue/Events, und eine API Platform für Governance.
flowchart LR
U[User] --> CDN[CDN/Edge Cache]
CDN --> PWA[PWA Frontend (SSR/ISR)]
PWA --> BFF[BFF / API Gateway]
BFF --> SA[Shopware 6 Store API]
BFF --> AA[Shopware 6 Admin API]
SA --> SW[Shopware Core]
SW --> DB[(MySQL)]
SW --> R[(Redis Cache)]
SW --> MQ[(Messenger/Queue)]
MQ --> ERP[ERP]
MQ --> PIM[PIM]
MQ --> PAY[Payment/PSP]
BFF --> OBS[Observability (Logs/Metrics/Tracing)]
5) Schritt-für-Schritt: Architektur-Optimierung (shopware_architecture_plan)
Schritt 1: Domänen & Bounded Contexts schneiden
- Katalog (Produkte, Varianten, Medien)
- Preis/Promotion
- Checkout/Order
- Kunde/Account
- Content/Experience
Ergebnis: Sie wissen, welche Teile synchron sein müssen (Checkout) und welche asynchron werden dürfen (PIM-Import, Fulfillment-Updates).
Schritt 2: API-first Verträge festziehen (Store API / Admin API / BFF)
- Welche Endpoints braucht die PWA wirklich (weniger Overfetching)?
- Welche Daten können gecacht werden (Katalog) und welche nicht (Warenkorb)?
- Wie versionieren wir (v1/v2) und wie testen wir Vertragsbrüche?
Schritt 3: Performance-Fokus: Cache, Suche, Datenbank
- Cache-Hierarchie: HTTP Cache/CDN → App Cache → Redis → DB
- Indexer/Async: Indexing nicht im Peak, Queues überwachen
- DB: Slow Query Log, Indizes, Vermeidung von N+1
Schritt 4: Erweiterungen Shopware-konform (MVC + Events)
- Business-Logik in Services
- Controller schlank halten
- Event Subscriber nur für klare Use-Cases (keine „God Subscriber“)
- Decorators mit Bedacht (Konfliktpotenzial mit anderen Plugins)
Schritt 5: Deployment-Architektur & Runbooks
- Build once, deploy many (Artefakt-Strategie)
- Migrations/Indexer-Prozess als definierter Schritt
- Rollback: Datenbank-Migrationsstrategie und Feature Flags
6) TypeScript: API Integration (PWA/BFF) gegen Shopware 6 Store API
Das folgende Beispiel zeigt eine realistische TypeScript-Integration, die (a) Token-basiert arbeitet, (b) saubere Fehler ausgibt und (c) typische Shopware Store-API Use-Cases abbildet: Context erstellen, Produkte suchen, Warenkorb befüllen.
TypeScript API Integration Codetype ShopwareContextToken = string;
type ShopwareError = {
status?: number;
code?: string;
title?: string;
detail?: string;
};
type ProductListingResponse = {
elements: Array<{
id: string;
name: string;
productNumber: string;
}>;
total: number;
};
class ShopwareStoreApiClient {
private readonly baseUrl: string;
private readonly accessKey: string;
public constructor(params: { baseUrl: string; accessKey: string }) {
this.baseUrl = params.baseUrl.replace(/\/$/, "");
this.accessKey = params.accessKey;
}
private async request<T>(
path: string,
options: {
method?: "GET" | "POST" | "PATCH" | "DELETE";
contextToken?: ShopwareContextToken;
body?: unknown;
} = {}
): Promise<{ data: T; contextToken?: ShopwareContextToken } > {
const url = `${this.baseUrl}${path}`;
const headers: Record<string, string> = {
"Content-Type": "application/json",
"Accept": "application/json",
"sw-access-key": this.accessKey
};
if (options.contextToken) {
headers["sw-context-token"] = options.contextToken;
}
const response = await fetch(url, {
method: options.method ?? "POST",
headers,
body: options.body ? JSON.stringify(options.body) : undefined
});
const nextContextToken = response.headers.get("sw-context-token") ?? undefined;
if (!response.ok) {
let errorBody: any = undefined;
try {
errorBody = await response.json();
} catch {
// ignore
}
const err: ShopwareError = {
status: response.status,
title: errorBody?.errors?.[0]?.title ?? response.statusText,
detail: errorBody?.errors?.[0]?.detail,
code: errorBody?.errors?.[0]?.code
};
throw new Error(`Shopware Store API error: ${JSON.stringify(err)}`);
}
const data = (await response.json()) as T;
return { data, contextToken: nextContextToken };
}
public async createContext(): Promise<ShopwareContextToken> {
const result = await this.request<{ token?: string }>("/store-api/context", {
method: "POST",
body: {}
});
// Shopware may return context token via header; we prefer that.
if (result.contextToken) return result.contextToken;
// Fallback (depending on setup)
if (result.data.token) return result.data.token;
throw new Error("No sw-context-token received from Shopware.");
}
public async searchProducts(params: {
contextToken: ShopwareContextToken;
term: string;
limit?: number;
}): Promise<ProductListingResponse> {
const result = await this.request<ProductListingResponse>("/store-api/search", {
method: "POST",
contextToken: params.contextToken,
body: {
search: params.term,
limit: params.limit ?? 10
}
});
return result.data;
}
public async addToCart(params: {
contextToken: ShopwareContextToken;
productId: string;
quantity: number;
}): Promise<unknown> {
const result = await this.request<unknown>("/store-api/checkout/cart/line-item", {
method: "POST",
contextToken: params.contextToken,
body: {
items: [
{
type: "product",
referencedId: params.productId,
quantity: params.quantity
}
]
}
});
return result.data;
}
}
async function demo() {
const client = new ShopwareStoreApiClient({
baseUrl: "https://example.com",
accessKey: "YOUR_STOREFRONT_ACCESS_KEY"
});
const contextToken = await client.createContext();
const listing = await client.searchProducts({ contextToken, term: "Sneaker", limit: 5 });
if (listing.elements.length > 0) {
await client.addToCart({
contextToken,
productId: listing.elements[0].id,
quantity: 1
});
}
return { contextToken, found: listing.total };
}
7) YAML: Deployment-Konfiguration (Shopware 6) mit klaren Build/Deploy-Schritten
Eine wiederholbare Deployment-Pipeline ist ein Architektur-Baustein. Unten ein Beispiel, wie Sie Shopware 6 in einer CI/CD-Pipeline strukturieren: getrennte Schritte für Build, Cache-Warmup, DB-Migrationen und indexer/async Tasks. Passen Sie Kommandos/Container/Secrets an Ihre Infrastruktur an.
YAML Config for Shopware Deploymentname: Deploy Shopware 6
on:
push:
branches: [ "main" ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
env:
APP_ENV: prod
APP_DEBUG: "0"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.2"
tools: composer:v2
extensions: mbstring, intl, pdo_mysql
- name: Install dependencies
run: |
composer install \
--no-dev \
--prefer-dist \
--no-interaction \
--optimize-autoloader
- name: Build storefront assets
run: |
bin/console theme:compile
- name: Warm up cache
run: |
bin/console cache:clear
bin/console cache:warmup
- name: Run database migrations
run: |
bin/console doctrine:migrations:migrate --no-interaction
- name: Refresh DAL indices (safe default)
run: |
bin/console dal:refresh:index --no-interaction
- name: Deploy artifact to server
env:
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
SSH_KEY: ${{ secrets.SSH_KEY }}
run: |
mkdir -p ~/.ssh
echo "$SSH_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh -o StrictHostKeyChecking=no ${SSH_USER}@${SSH_HOST} "mkdir -p /var/www/shopware"
rsync -az --delete ./ ${SSH_USER}@${SSH_HOST}:/var/www/shopware/
ssh ${SSH_USER}@${SSH_HOST} "cd /var/www/shopware && bin/console messenger:stop-workers || true"
ssh ${SSH_USER}@${SSH_HOST} "cd /var/www/shopware && bin/console cache:clear"
ssh ${SSH_USER}@${SSH_HOST} "cd /var/www/shopware && bin/console messenger:consume -vv --time-limit=300 --memory-limit=256M --limit=200 &"
8) Architektur-Deliverables, die eine Shopware Agentur in Frankfurt liefern sollte
- Systemdiagramm (Ist/Ziel) inkl. Datenflüsse und Latenz-Budgets
- API Contracts (Store API/BFF) inkl. Fehler- und Versionierungsstrategie
- MVC-konforme Customizations (Services/Subscriber/Decorator-Plan)
- Deployment-Runbooks (Migrationsfenster, Indexer, Rollback)
- Observability: Dashboards für API-Latenz, Error-Rates, Queue-Backlog, DB-Slow Queries
Wenn Sie dafür einen Partner suchen: Shopware Agentur.


