# 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 { // Implementierung } async getPage(slug: string, locale?: string): Promise { // 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

{t("login.title")}

; } ``` **Verwendung in Alpine.js:** ```html
``` ### 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.