6.7 KiB
6.7 KiB
Projekt-Kontext: GraphQL Middlelayer + Astro Frontend
Projekt-Übersicht
Ein GraphQL-basierter Middlelayer mit Astro-Frontend für einen Onlineshop. Der Middlelayer fungiert als Abstraktionsschicht zwischen Frontend und verschiedenen Datenquellen (aktuell Mock-Daten, später Headless CMS, etc.).
Architektur
Middlelayer (middlelayer/)
- GraphQL Server (Apollo Server v5) auf Port 4000
- Adapter Pattern für Datenquellen-Abstraktion
- DataService als Singleton-Aggregator
- Monitoring & Observability:
- Structured Logging (Winston)
- Prometheus Metrics (Port 9090)
- Distributed Tracing
- Performance-Optimierungen:
- Dataloader für Batch-Loading (verhindert N+1 Queries)
- Response Caching
- Query Complexity Limits (mit Workaround für Schema-Realm-Konflikt)
Frontend (src/)
- Astro Framework mit SSR
- Tailwind CSS für Styling
- Alpine.js für Client-Side Interaktivität
- GraphQL Client für Datenabfragen
Datenstrukturen
Produkte
ProductmitoriginalPrice(Streichpreis) undpromotion(Objekt mitcategoryundtext)- Promotion-Typen:
"sale"oder"topseller" - Promotion-Text: z.B.
"-30%"oder"top"
CMS-Daten
Page- Seiten mit SEO, Headlines, Bannern (mit Locale-Support)PageSeo- SEO-Metadaten (mit Locale-Support)Navigation- Navigationsstruktur mit Links (mit Locale-Support)
Content-System
- CMS-Typen (
middlelayer/types/cms/) - Struktur wie Daten vom CMS kommen*Skeleton- Wrapper mitcontentTypeIdundfields- Verwendet
ComponentLayout(Alias fürcontentLayout) - Nur für Mapper und Mock-Daten
- Domain-Typen (
middlelayer/types/c_*.ts) - Struktur wie Daten in der App verwendet werdenc_*- Content-Item-Typen mittype-Feld für Discriminated Union- Verwendet
contentLayoutdirekt - Für GraphQL Schema, Astro Components, etc.
- Content-Komponenten: HTML, Markdown, Iframe, ImageGallery, Image, Quote, YoutubeVideo, Headline
- Mapper (
middlelayer/mappers/pageMapper.ts) - Konvertiert CMS-Typen zu Domain-Typen
Internationalization (i18n)
- URL-basierte Locales:
/deund/enURLs - Übersetzungen: Defaults + Middlelayer-Überschreibungen
- React:
useI18n()Hook für Komponenten - Alpine.js:
window.i18n.t()für Navigation - CMS: Locale-Parameter in allen CMS-Queries
- Contentful-Ansatz: Vorbereitet für Contentful Locale-System (jedes Feld lokalisiert)
Wichtige Dateien
Middlelayer
middlelayer/index.ts- Server-Entry-Pointmiddlelayer/schema.ts- GraphQL Schemamiddlelayer/resolvers.ts- GraphQL Resolversmiddlelayer/dataService.ts- DataService (Singleton)middlelayer/adapters/interface.ts- DataAdapter Interfacemiddlelayer/adapters/mockdata.ts- MockdataAdaptermiddlelayer/adapters/Mock/_cms/- Mock-Daten für CMSmiddlelayer/mappers/pageMapper.ts- Konvertiert CMS-Typen zu Domain-Typenmiddlelayer/types/cms/- CMS-spezifische Typen (für Mapper/Mock)middlelayer/types/c_*.ts- Domain-Typen (für App)middlelayer/types/contentLayout.ts- Einheitlicher Layout-Typmiddlelayer/utils/dataloaders.ts- Dataloader für Batch-Loading + GraphQLContextmiddlelayer/utils/cache.ts- In-Memory Cache mit Metricsmiddlelayer/monitoring/- Logging, Metrics, Tracingmiddlelayer/plugins/- Apollo Server Plugins
Frontend
src/components/Product.astro- Produkt-Komponente mit Promotion & Streichpreissrc/components/LoginModal.tsx- React Login-Modal mit i18nsrc/components/RegisterModal.tsx- React Register-Modal mit i18nsrc/lib/graphql/client.ts- GraphQL Clientsrc/lib/graphql/queries.ts- Produkt-Queriessrc/lib/graphql/cmsQueries.ts- CMS-Queries (mit Locale-Support)src/lib/i18n/- i18n-System (defaults, i18n.ts, useI18n.tsx, alpine.ts)src/layouts/Layout.astro- Layout mit Navigation & SEOsrc/middleware.ts- URL-basierte Locale-Routingsrc/pages/[locale]/- Locale-basierte Routen
Konfiguration
Environment Variables
PORT=4000 # GraphQL Server Port
METRICS_PORT=9090 # Metrics Server Port
LOG_LEVEL=info # Log-Level (debug, info, warn, error)
MAX_QUERY_COMPLEXITY=1000 # Query Complexity Limit
NODE_ENV=development # Environment
Cache-TTLs (konfigurierbar via Environment oder middlelayer/config/cache.ts)
- Pages: 60 Sekunden
- SEO/Navigation: 5 Minuten
- Products: 30 Sekunden
Bekannte Probleme & Workarounds
-
Query Complexity Schema-Realm-Konflikt
- Problem:
graphql-query-complexityhat Schema-Realm-Konflikt mit Apollo Server - Workaround: Plugin überspringt Check bei Realm-Konflikten (siehe
middlelayer/plugins/queryComplexity.ts) - Status: Funktioniert, aber Complexity-Check wird manchmal übersprungen
- Problem:
-
GraphQL Version
- Alle Pakete verwenden
graphql@16.12.0 overridesinpackage.jsonstellt sicher, dass nur eine Version verwendet wird
- Alle Pakete verwenden
NPM Scripts
npm run mock:server # Startet nur GraphQL Server
npm start # Startet GraphQL Server + Astro (concurrently)
npm run dev # Startet nur Astro
Endpoints
- GraphQL:
http://localhost:4000 - GraphQL Playground:
http://localhost:4000 - Metrics:
http://localhost:9090/metrics - Health Check:
http://localhost:9090/health - Astro:
http://localhost:4321
Implementierte Features
✅ GraphQL Server mit Apollo Server v5 ✅ Adapter Pattern für Datenquellen ✅ Mock-Daten für Produkte und CMS ✅ Product-Komponente mit Promotion & Streichpreis ✅ Structured Logging (Winston) ✅ Prometheus Metrics ✅ Distributed Tracing ✅ Dataloader für Batch-Loading ✅ Response Caching ✅ Query Complexity Limits (mit Workaround) ✅ Cache mit Metrics-Tracking ✅ DataService mit Metrics-Tracking
Nächste Schritte / Offene Punkte
- Query Complexity Schema-Realm-Problem dauerhaft lösen
- Redis Cache Integration (statt In-Memory)
- Database Adapter (für echte Datenbank)
- Headless CMS Adapter (Contentful, Strapi, etc.)
- Rate Limiting
- Authentication/Authorization
- GraphQL Subscriptions (falls benötigt)
Wichtige Design-Entscheidungen
- Adapter Pattern: Ermöglicht einfaches Wechseln zwischen Datenquellen
- Singleton DataService: Zentrale Stelle für alle Datenoperationen
- Monitoring First: Von Anfang an Monitoring integriert
- Type Safety: TypeScript durchgängig verwendet
- Structured Logging: JSON-Logs für bessere Analyse
- Metrics: Prometheus-kompatible Metriken für Monitoring
Code-Stil
- TypeScript mit ES Modules
- Doppelte Anführungszeichen für Strings (Prettier)
- Deutsche Kommentare und Fehlermeldungen
- Englische Code-Namen und API-Namen