175 lines
6.7 KiB
Markdown
175 lines
6.7 KiB
Markdown
# 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
|
|
- `Product` mit `originalPrice` (Streichpreis) und `promotion` (Objekt mit `category` und `text`)
|
|
- 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 mit `contentTypeId` und `fields`
|
|
- Verwendet `ComponentLayout` (Alias für `contentLayout`)
|
|
- Nur für Mapper und Mock-Daten
|
|
- **Domain-Typen** (`middlelayer/types/c_*.ts`) - Struktur wie Daten in der App verwendet werden
|
|
- `c_*` - Content-Item-Typen mit `type`-Feld für Discriminated Union
|
|
- Verwendet `contentLayout` direkt
|
|
- 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**: `/de` und `/en` URLs
|
|
- **Ü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-Point
|
|
- `middlelayer/schema.ts` - GraphQL Schema
|
|
- `middlelayer/resolvers.ts` - GraphQL Resolvers
|
|
- `middlelayer/dataService.ts` - DataService (Singleton)
|
|
- `middlelayer/adapters/interface.ts` - DataAdapter Interface
|
|
- `middlelayer/adapters/mockdata.ts` - MockdataAdapter
|
|
- `middlelayer/adapters/Mock/_cms/` - Mock-Daten für CMS
|
|
- `middlelayer/mappers/pageMapper.ts` - Konvertiert CMS-Typen zu Domain-Typen
|
|
- `middlelayer/types/cms/` - CMS-spezifische Typen (für Mapper/Mock)
|
|
- `middlelayer/types/c_*.ts` - Domain-Typen (für App)
|
|
- `middlelayer/types/contentLayout.ts` - Einheitlicher Layout-Typ
|
|
- `middlelayer/utils/dataloaders.ts` - Dataloader für Batch-Loading + GraphQLContext
|
|
- `middlelayer/utils/cache.ts` - In-Memory Cache mit Metrics
|
|
- `middlelayer/monitoring/` - Logging, Metrics, Tracing
|
|
- `middlelayer/plugins/` - Apollo Server Plugins
|
|
|
|
### Frontend
|
|
- `src/components/Product.astro` - Produkt-Komponente mit Promotion & Streichpreis
|
|
- `src/components/LoginModal.tsx` - React Login-Modal mit i18n
|
|
- `src/components/RegisterModal.tsx` - React Register-Modal mit i18n
|
|
- `src/lib/graphql/client.ts` - GraphQL Client
|
|
- `src/lib/graphql/queries.ts` - Produkt-Queries
|
|
- `src/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 & SEO
|
|
- `src/middleware.ts` - URL-basierte Locale-Routing
|
|
- `src/pages/[locale]/` - Locale-basierte Routen
|
|
|
|
## Konfiguration
|
|
|
|
### Environment Variables
|
|
```bash
|
|
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
|
|
|
|
1. **Query Complexity Schema-Realm-Konflikt**
|
|
- Problem: `graphql-query-complexity` hat 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
|
|
|
|
2. **GraphQL Version**
|
|
- Alle Pakete verwenden `graphql@16.12.0`
|
|
- `overrides` in `package.json` stellt sicher, dass nur eine Version verwendet wird
|
|
|
|
## NPM Scripts
|
|
|
|
```bash
|
|
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
|
|
|
|
1. **Adapter Pattern**: Ermöglicht einfaches Wechseln zwischen Datenquellen
|
|
2. **Singleton DataService**: Zentrale Stelle für alle Datenoperationen
|
|
3. **Monitoring First**: Von Anfang an Monitoring integriert
|
|
4. **Type Safety**: TypeScript durchgängig verwendet
|
|
5. **Structured Logging**: JSON-Logs für bessere Analyse
|
|
6. **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
|
|
|