11 KiB
GraphQL Middlelayer + Astro Frontend
Ein moderner, skalierbarer Onlineshop mit GraphQL-basiertem Middlelayer und Astro-Frontend. Der Middlelayer fungiert als flexible Abstraktionsschicht zwischen Frontend und verschiedenen Datenquellen.
🚀 Features
- GraphQL API mit Apollo Server v5
- Astro Frontend mit SSR und Client-Side Interaktivität
- Adapter Pattern für flexible Datenquellen (Mock, Headless CMS, Database)
- Performance-Optimierungen:
- Dataloader für Batch-Loading (verhindert N+1 Queries)
- Redis/In-Memory Caching
- Response Caching
- Query Complexity Limits
- Monitoring & Observability:
- Structured Logging (Winston)
- Prometheus Metrics
- Distributed Tracing
- Type-Safe mit TypeScript durchgängig
- Modern UI mit Tailwind CSS und Alpine.js
- Internationalization (i18n):
- URL-basierte Locales (
/de,/en) - Übersetzungen aus Middlelayer (mit Default-Fallback)
- CMS-Inhalte mehrsprachig (vorbereitet für Contentful)
- URL-basierte Locales (
📋 Voraussetzungen
- Node.js 18+
- npm oder yarn
- (Optional) Redis für verteiltes Caching
🛠️ Installation
# Dependencies installieren
npm install
# (Optional) Redis installieren (macOS)
brew install redis
brew services start redis
🏃 Quick Start
# GraphQL Server + Astro Frontend starten
npm start
# Oder einzeln:
npm run mock:server # Nur GraphQL Server (Port 4000)
npm run dev # Nur Astro Frontend (Port 4321)
📁 Projektstruktur
/
├── middlelayer/ # GraphQL Middlelayer
│ ├── adapters/ # Datenquellen-Adapter (Mock, CMS, etc.)
│ ├── config/ # Konfiguration
│ ├── monitoring/ # Logging, Metrics, Tracing
│ ├── plugins/ # Apollo Server Plugins
│ ├── types/ # TypeScript Typen
│ ├── utils/ # Utilities (Cache, Dataloader, etc.)
│ ├── index.ts # Server Entry Point
│ ├── schema.ts # GraphQL Schema
│ └── resolvers.ts # GraphQL Resolvers
│
├── src/ # Astro Frontend
│ ├── components/ # Astro Komponenten
│ ├── layouts/ # Layout Templates
│ ├── lib/ # Utilities & GraphQL Client
│ ├── pages/ # Astro Pages
│ └── styles/ # Global Styles
│
└── docs/ # Dokumentation
⚙️ Konfiguration
Environment Variables
Erstelle eine .env Datei im Root-Verzeichnis:
# Server Ports
PORT=4000 # GraphQL Server Port
METRICS_PORT=9090 # Metrics Server Port
# Logging
LOG_LEVEL=info # debug, info, warn, error
NODE_ENV=development # development, production
# GraphQL
MAX_QUERY_COMPLEXITY=1000 # Query Complexity Limit
# Redis (Optional)
REDIS_ENABLED=true # Redis Cache aktivieren
REDIS_HOST=localhost # Redis Host
REDIS_PORT=6379 # Redis Port
REDIS_PASSWORD= # Optional: Redis Password
# Cache TTLs (in Millisekunden)
CACHE_PAGES_TTL=60000 # 60 Sekunden
CACHE_PAGE_SEO_TTL=300000 # 5 Minuten
CACHE_NAVIGATION_TTL=300000 # 5 Minuten
CACHE_PRODUCTS_TTL=30000 # 30 Sekunden
Cache-Konfiguration
Cache-TTLs können über Environment Variables oder direkt in middlelayer/config/cache.ts konfiguriert werden.
🌐 Endpoints
| Service | URL | Beschreibung |
|---|---|---|
| GraphQL API | http://localhost:4000 |
GraphQL Endpoint & Playground |
| Metrics | http://localhost:9090/metrics |
Prometheus Metrics |
| Health Check | http://localhost:9090/health |
Service Health Status |
| Astro Frontend | http://localhost:4321 |
Frontend Application |
📊 GraphQL Schema
Queries
# Produkte
query {
products(limit: 4) {
id
name
price
originalPrice
promotion {
category
text
}
}
product(id: "prod-123") {
id
name
description
price
}
}
# CMS (mit Locale-Support)
query {
pageSeo(locale: "de") {
title
description
}
page(slug: "/about", locale: "de") {
headline
subheadline
}
pages(locale: "en") {
slug
name
}
navigation(locale: "de") {
links {
name
slug
}
}
}
# Übersetzungen
query {
translations(locale: "de", namespace: "auth") {
locale
translations {
key
value
}
}
}
}
page(slug: "/") {
slug
name
headline
}
navigation {
name
links {
name
url
}
}
}
🏗️ Architektur
Middlelayer
Der Middlelayer verwendet das Adapter Pattern für flexible Datenquellen:
Frontend (Astro)
↓
GraphQL API (Apollo Server)
↓
DataService (Singleton)
↓
DataAdapter (Interface)
↓
┌─────────────┬──────────────┬─────────────┐
│ Mock Adapter│ CMS Adapter │ DB Adapter │
└─────────────┴──────────────┴─────────────┘
Vorteile:
- Einfaches Wechseln zwischen Datenquellen
- Testbarkeit durch Mock-Adapter
- Zentrale Logik im DataService
- Caching auf Service-Ebene
Frontend
- Astro für Server-Side Rendering
- Alpine.js für Client-Side Interaktivität
- Tailwind CSS für Styling
- GraphQL Client für Datenabfragen
🔧 Entwicklung
NPM Scripts
npm run mock:server # Startet GraphQL Server
npm run dev # Startet Astro Dev Server
npm start # Startet beide (concurrently)
npm run build # Production Build
npm run preview # Preview Production Build
Neuen Adapter hinzufügen
- Implementiere
DataAdapterInterface:
// middlelayer/adapters/myAdapter.ts
import type { DataAdapter } from './interface.js';
export class MyAdapter implements DataAdapter {
async getProducts(limit?: number): Promise<Product[]> {
// Implementierung
}
// ... weitere Methoden
}
- In
middlelayer/adapters/config.tsregistrieren:
export function createAdapter(): DataAdapter {
const adapterType = process.env.ADAPTER_TYPE || 'mock';
if (adapterType === 'myAdapter') {
return new MyAdapter();
}
// ...
}
📈 Monitoring
Prometheus Metrics
Metriken sind verfügbar unter http://localhost:9090/metrics:
graphql_queries_total- Anzahl der Queriesgraphql_query_duration_seconds- Query-Dauercache_hits_total/cache_misses_total- Cache-Statistikendataservice_calls_total- DataService-Aufrufeerrors_total- Fehler-Anzahl
Logging
Structured Logging mit Winston:
- Console Output (Development)
- JSON Logs (Production)
- Log-Level konfigurierbar
Tracing
Automatische Trace-ID-Generierung für Request-Tracking.
🚀 Deployment
Production Build
npm run build
Docker (Beispiel)
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
RUN npm run build
CMD ["npm", "start"]
🧪 Testing
# GraphQL Query testen
curl -X POST http://localhost:4000 \
-H "Content-Type: application/json" \
-d '{"query":"{ products(limit: 4) { id name price } }"}'
# Health Check
curl http://localhost:9090/health
# Metrics
curl http://localhost:9090/metrics
📚 Weitere Dokumentation
- Architektur & Skalierung - Detaillierte Architektur-Analyse
- Redis Setup - Redis Cache Konfiguration
- Monitoring - Monitoring & Observability
🐛 Bekannte Probleme
Query Complexity Schema-Realm-Konflikt
Problem: graphql-query-complexity hat einen Schema-Realm-Konflikt mit Apollo Server.
Workaround: Das Plugin überspringt den Check bei Realm-Konflikten automatisch. Funktioniert, aber Complexity-Check wird manchmal übersprungen.
Status: Funktioniert, permanente Lösung in Arbeit.
🌍 Internationalization (i18n)
URL-basierte Locales
Das System unterstützt URL-basierte Locales:
/de- Deutsche Version/en- Englische Version/- Auto-Redirect zu Browser-Locale oder Cookie
Übersetzungen
Architektur:
- Defaults: Fallback-Übersetzungen in
src/lib/i18n/defaults.ts - Middlelayer: Übersetzungen können vom GraphQL-Server geladen werden
- Überschreibungen: Middlelayer-Übersetzungen überschreiben Defaults
Verwendung in React:
import { useI18n } from "../lib/i18n/useI18n.js";
function MyComponent() {
const { t } = useI18n("auth");
return <h1>{t("login.title")}</h1>;
}
Verwendung in Alpine.js:
<div x-data="{ t: window.i18n?.t || ((key) => key) }">
<button x-text="t('nav.login')"></button>
</div>
CMS-Locale-Support
Contentful-Ansatz: Contentful verwendet ein Locale-System, bei dem:
- Jedes Content-Feld lokalisiert werden kann
- Standard-Locale wird definiert (z.B.
en-US) - Fallback-Locales können konfiguriert werden
- API-Aufrufe enthalten
locale-Parameter:fields.headline['en-US']
Unser System:
- GraphQL-Schema unterstützt
locale-Parameter für alle CMS-Queries - Adapter-Interface ist vorbereitet für Locale-Parameter
- Mock-Adapter gibt aktuell alle Locales gleich zurück (TODO: Locale-spezifische Mock-Daten)
- Bei Contentful-Integration: Adapter würde
locale-Parameter an Contentful API weitergeben
Beispiel GraphQL Query:
query {
page(slug: "/about", locale: "de") {
headline # Deutsche Übersetzung
subheadline
}
page(slug: "/about", locale: "en") {
headline # Englische Übersetzung
subheadline
}
}
🔮 Roadmap
- Query Complexity Schema-Realm-Problem dauerhaft lösen
- Database Adapter (PostgreSQL, MySQL)
- Headless CMS Adapter (Contentful, Strapi)
- Locale-spezifische Inhalte implementieren
- Fallback-Locales konfigurieren
- Rate Limiting
- Authentication/Authorization ✅ (implementiert)
- GraphQL Subscriptions
- i18n: Weitere Sprachen hinzufügen
- i18n: Locale-spezifische Mock-Daten für CMS
- E2E Tests
🤝 Beitragen
- Fork das Repository
- Erstelle einen Feature Branch (
git checkout -b feature/AmazingFeature) - Committe deine Änderungen (
git commit -m 'Add some AmazingFeature') - Push zum Branch (
git push origin feature/AmazingFeature) - Öffne einen Pull Request
📝 Lizenz
Dieses Projekt ist privat.
👥 Autoren
- Entwickelt mit ❤️ für moderne E-Commerce-Lösungen
Hinweis: Dieses Projekt ist in aktiver Entwicklung. Für Fragen oder Probleme öffne bitte ein Issue.