Files
sell/README.md

543 lines
15 KiB
Markdown

# 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)
## 📋 Voraussetzungen
- Node.js 18+
- npm oder yarn
- (Optional) Redis für verteiltes Caching
## 🛠️ Installation
```bash
# Dependencies installieren
npm install
# (Optional) Redis installieren (macOS)
brew install redis
brew services start redis
```
## 🏃 Quick Start
```bash
# 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
│ ├── __cms/ # Legacy Contentful-Typen (nicht mehr verwendet)
│ ├── adapters/ # Datenquellen-Adapter (Mock, CMS, etc.)
│ │ ├── Mock/ # Mock-Adapter mit Mock-Daten
│ │ │ ├── _cms/ # CMS Mock-Daten
│ │ │ └── _i18n/ # i18n Mock-Daten
│ │ ├── config.ts # Adapter-Konfiguration
│ │ └── interface.ts # DataAdapter Interface
│ ├── auth/ # Authentication & Authorization
│ ├── config/ # Konfiguration (Cache, etc.)
│ ├── mappers/ # Data Mapper (CMS → Domain)
│ │ └── pageMapper.ts # Page-Transformationen
│ ├── monitoring/ # Logging, Metrics, Tracing
│ ├── plugins/ # Apollo Server Plugins
│ ├── types/ # TypeScript Typen
│ │ ├── cms/ # CMS-spezifische Typen (für Mapper)
│ │ ├── c_*.ts # Domain Content-Item-Typen
│ │ └── *.ts # Weitere Domain-Typen
│ ├── utils/ # Utilities
│ │ ├── cache.ts # Cache-Implementierung
│ │ ├── cacheKeys.ts # Cache-Key-Builder
│ │ ├── dataServiceHelpers.ts # Helper für DataService
│ │ ├── dataloaders.ts # Dataloader + GraphQLContext
│ │ └── errors.ts # Error-Klassen
│ ├── dataService.ts # DataService (Singleton)
│ ├── index.ts # Server Entry Point
│ ├── schema.ts # GraphQL Schema
│ └── resolvers.ts # GraphQL Resolvers
├── src/ # Astro Frontend
│ ├── components/ # Astro Komponenten
│ │ ├── cms/ # CMS Content-Komponenten
│ │ └── ... # Weitere Komponenten
│ ├── layouts/ # Layout Templates
│ ├── lib/ # Utilities & GraphQL Client
│ │ ├── graphql/ # GraphQL Client & Queries
│ │ ├── i18n/ # i18n-System
│ │ └── utils/ # Utilities (Layout, Markdown, etc.)
│ ├── pages/ # Astro Pages
│ │ └── [locale]/ # Locale-basierte Routen
│ └── styles/ # Global Styles
└── docs/ # Dokumentation
```
## ⚙️ Konfiguration
### Environment Variables
Erstelle eine `.env` Datei im Root-Verzeichnis:
```env
# 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
```graphql
# 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
}
}
}
# Content-System (mit Content-Items)
query {
page(slug: "/components", locale: "de") {
slug
name
headline
row1 {
justifyContent
alignItems
content {
... on HTMLContent {
type
name
html
}
... on MarkdownContent {
type
name
content
alignment
}
... on HeadlineContent {
type
text
tag
align
}
... on ImageContent {
type
name
imageUrl
caption
}
}
}
}
}
```
## 🏗️ Architektur
### Middlelayer
Der Middlelayer verwendet das **Adapter Pattern** für flexible Datenquellen:
```
Frontend (Astro)
GraphQL API (Apollo Server)
Resolvers (mit Error Handling Wrapper)
DataService (Singleton, mit Cache + Metrics)
PageMapper (CMS → Domain Transformation)
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
- Type-safe Mapping von CMS zu Domain-Typen
- Konsistentes Error Handling
- Zentralisierte Cache-Keys
- Strategy Pattern für wartbaren Code
### Content-System
Das System verwendet eine **Zwei-Schichten-Typ-Architektur**:
1. **CMS-Typen** (`types/cms/`) - Wie Daten vom CMS kommen
- `*Skeleton` Wrapper mit `contentTypeId` und `fields`
- Verwendet `ComponentLayout` (Alias für `contentLayout`)
- Nur für Mapper und Mock-Daten
2. **Domain-Typen** (`types/c_*.ts`) - Wie Daten in der App verwendet werden
- `c_*` Content-Item-Typen mit `type`-Feld
- Verwendet `contentLayout` direkt
- Für GraphQL Schema, Astro Components, etc.
3. **PageMapper** - Konvertiert CMS-Typen zu Domain-Typen
- Strategy Pattern für wartbaren Code
- Automatische Transformation aller Content-Types
**Content-Komponenten:**
- HTML, Markdown, Iframe, ImageGallery, Image, Quote, YoutubeVideo, Headline
### 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
```bash
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
1. Implementiere `DataAdapter` Interface:
```typescript
// middlelayer/adapters/myAdapter.ts
import type { DataAdapter } from './interface.js';
import type { Page, Product, PageSeo, Navigation } from '../types/index.js';
export class MyAdapter implements DataAdapter {
async getProducts(limit?: number): Promise<Product[]> {
// Implementierung
}
async getPage(slug: string, locale?: string): Promise<Page | null> {
// Implementierung - muss CMS-Typen zurückgeben
// PageMapper konvertiert automatisch zu Domain-Typen
}
// ... weitere Methoden
}
```
2. In `middlelayer/adapters/config.ts` registrieren:
```typescript
export function createAdapter(): DataAdapter {
const adapterType = process.env.ADAPTER_TYPE || 'mock';
if (adapterType === 'myAdapter') {
return new MyAdapter();
}
// ...
}
```
### Content-Komponenten hinzufügen
1. CMS-Typ erstellen: `middlelayer/types/cms/MyComponent.ts`
2. Domain-Typ erstellen: `middlelayer/types/c_myComponent.ts`
3. Mapper erweitern: In `pageMapper.ts` Strategy Map erweitern
4. GraphQL Schema erweitern: In `schema.ts` neuen Type hinzufügen
5. Astro Component erstellen: `src/components/cms/C_myComponent.astro`
## 📈 Monitoring
### Prometheus Metrics
Metriken sind verfügbar unter `http://localhost:9090/metrics`:
- `graphql_queries_total` - Anzahl der Queries
- `graphql_query_duration_seconds` - Query-Dauer
- `cache_hits_total` / `cache_misses_total` - Cache-Statistiken
- `dataservice_calls_total` - DataService-Aufrufe
- `errors_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
```bash
npm run build
```
### Docker (Beispiel)
```dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
RUN npm run build
CMD ["npm", "start"]
```
## 🧪 Testing
```bash
# 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
- [Type Structure](./middlelayer/types/README.md) - Detaillierte Typ-Struktur (CMS vs Domain)
- [Authentication](./middlelayer/auth/README.md) - Authentication & Authorization
- [Monitoring](./middlelayer/monitoring/README.md) - Monitoring & Observability
- [Redis Setup](./middlelayer/utils/REDIS_SETUP.md) - Redis Cache Konfiguration
- [Improvements](./middlelayer/IMPROVEMENTS.md) - Verbesserungsvorschläge & umgesetzte Änderungen
## 🐛 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:**
```tsx
import { useI18n } from "../lib/i18n/useI18n.js";
function MyComponent() {
const { t } = useI18n("auth");
return <h1>{t("login.title")}</h1>;
}
```
**Verwendung in Alpine.js:**
```html
<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:**
```graphql
query {
page(slug: "/about", locale: "de") {
headline # Deutsche Übersetzung
subheadline
}
page(slug: "/about", locale: "en") {
headline # Englische Übersetzung
subheadline
}
}
```
## ✨ Kürzlich implementierte Verbesserungen
-**Strategy Pattern** im PageMapper (statt 8 if-Statements)
-**Code-Duplikation reduziert** in DataService (Helper-Klassen)
-**Konsistentes Error Handling** (Wrapper-Funktion für alle Resolver)
-**Zentralisierte Cache-Keys** (CacheKeyBuilder)
-**Type Safety verbessert** (keine `any` Types mehr)
-**User-Formatierung zentralisiert** (Helper-Funktion)
## 🔮 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
- [x] Authentication/Authorization ✅ (implementiert)
- [ ] GraphQL Subscriptions
- [ ] i18n: Weitere Sprachen hinzufügen
- [ ] i18n: Locale-spezifische Mock-Daten für CMS
- [ ] E2E Tests
## 🤝 Beitragen
1. Fork das Repository
2. Erstelle einen Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Committe deine Änderungen (`git commit -m 'Add some AmazingFeature'`)
4. Push zum Branch (`git push origin feature/AmazingFeature`)
5. Ö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.