2025-06-01 23:41:02 +02:00

16 KiB

MYP Frontend-System

🌐 Moderne Web-Oberfläche & Analytics-Dashboard

Entwickler: Torben Haack
Fachrichtung: Fachinformatiker für Daten- und Prozessanalyse
Zweck: Moderne React-basierte Benutzeroberfläche für das MYP-Druckerverwaltungssystem

🎯 Projektübersicht

Das Frontend-System ist eine vollständige Next.js-Webanwendung, die als moderne Benutzeroberfläche für Till Tomczaks Backend-APIs dient. Es bietet eine intuitive, responsive Bedienung und erweiterte Analytics-Funktionen für alle Stakeholder des MYP-Systems.

Kernfunktionen

  • Moderne Web-UI: React 18 + Next.js 14 für optimale Performance
  • Backend-Integration: Nahtlose Anbindung an Till Tomczaks REST-APIs
  • Advanced Analytics: Interaktive Dashboards und Datenvisualisierung
  • Responsive Design: Optimiert für Desktop, Tablet und Mobile
  • Real-time Updates: Live-Synchronisation mit Backend-Daten

🏗️ Architektur & Integration

System-Übersicht

┌─────────────────────┐    ┌─────────────────────┐    ┌─────────────────────┐
│   Frontend-Server   │◄──►│   Backend-Server    │◄──►│  Raspberry Pi       │
│   (Port 3000)       │    │   (Port 5000/443)   │    │  (Hardware)         │
│   Torben Haack      │    │   Till Tomczak      │    │   Till Tomczak      │
│                     │    │                     │    │                     │
│ • Next.js App       │    │ • Flask REST-API    │    │ • Smart-Plug Control│
│ • React Components  │    │ • SQLite Database   │    │ • Kiosk Interface   │
│ • Analytics UI      │    │ • Authentication    │    │ • Offline Operation │
│ • Chart Libraries   │    │ • Business Logic    │    │ • Touch Interface   │
│ • Export Functions  │    │ • Hardware APIs     │    │ • System Services   │
└─────────────────────┘    └─────────────────────┘    └─────────────────────┘

Frontend-Technologie-Stack

  • Framework: Next.js 14 mit App Router
  • Language: TypeScript für Type-Safety
  • UI-Library: Radix UI + Tailwind CSS
  • State Management: React Server Components + SWR
  • Charts: Recharts + Tremor für Datenvisualisierung
  • Database: Drizzle ORM mit SQLite (für Frontend-spezifische Daten)
  • Authentication: Backend-Session-Integration

🚀 Installation & Setup

Voraussetzungen

  • Node.js 18+
  • pnpm (empfohlen) oder npm
  • Zugriff auf Till Tomczaks Backend-Server

1. Frontend-Installation

# Repository klonen
git clone <repository-url>
cd Projektarbeit-MYP/frontend

# Abhängigkeiten installieren
pnpm install

# Frontend-Datenbank einrichten (für UI-spezifische Daten)
pnpm db:create-default
pnpm db:generate-sqlite
pnpm db:migrate

# Environment-Konfiguration
cp .env.example .env.local
# Backend-API-URL in .env.local eintragen

2. Backend-Integration konfigurieren

# .env.local
NEXT_PUBLIC_BACKEND_API_URL=http://backend-server:5000/api
NEXT_PUBLIC_BACKEND_WS_URL=ws://backend-server:5000/ws

# Für lokale Entwicklung
NEXT_PUBLIC_BACKEND_API_URL=http://localhost:5000/api

3. Entwicklung starten

# Entwicklungsserver starten
pnpm dev

# Frontend läuft auf http://localhost:3000
# Backend-APIs werden von http://backend-server:5000/api konsumiert

4. Produktions-Deployment

# Build für Produktion
pnpm build

# Produktionsserver starten
pnpm start

# Oder mit PM2 für Produktionsumgebung
pm2 start ecosystem.config.js

📁 Projektstruktur

frontend/
├── src/
│   ├── app/                         # Next.js App Router
│   │   ├── (dashboard)/            # Dashboard-Layout-Gruppe
│   │   │   ├── page.tsx            # Haupt-Dashboard
│   │   │   ├── printers/           # Drucker-Management
│   │   │   ├── jobs/               # Job-Verwaltung
│   │   │   └── analytics/          # Analytics-Dashboards
│   │   ├── admin/                  # Admin-Bereich
│   │   ├── auth/                   # Authentifizierung (Backend-Integration)
│   │   └── api/                    # Frontend-API-Routes (Proxy/Cache)
│   ├── components/                 # React-Komponenten
│   │   ├── ui/                     # Basis-UI-Komponenten (Radix UI)
│   │   ├── charts/                 # Chart-Komponenten (Recharts)
│   │   ├── forms/                  # Formular-Komponenten
│   │   ├── layout/                 # Layout-Komponenten
│   │   └── printer/                # Drucker-spezifische Komponenten
│   ├── lib/                        # Utility-Bibliotheken
│   │   ├── api/                    # Backend-API-Client
│   │   ├── auth/                   # Authentifizierung
│   │   ├── utils/                  # Helper-Funktionen
│   │   └── analytics/              # Analytics-Algorithmen
│   ├── hooks/                      # Custom React Hooks
│   ├── types/                      # TypeScript-Typen
│   └── styles/                     # Global Styles
├── public/                         # Statische Assets
├── docs/                           # Frontend-Dokumentation
├── drizzle/                        # Frontend-DB-Migrationen
└── package.json                    # Dependencies

🔗 Backend-API-Integration

API-Client-Implementation

// src/lib/api/myp-client.ts
export class MYPApiClient {
  private baseURL: string;
  
  constructor() {
    this.baseURL = process.env.NEXT_PUBLIC_BACKEND_API_URL || 'http://localhost:5000/api';
  }

  // Drucker-Management (Till Tomczaks Backend APIs)
  async getPrinters(): Promise<Printer[]> {
    const response = await fetch(`${this.baseURL}/printers`, {
      credentials: 'include', // Session-Cookies übertragen
    });
    return response.json();
  }

  async createPrinter(printer: CreatePrinterRequest): Promise<Printer> {
    const response = await fetch(`${this.baseURL}/printers`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify(printer),
    });
    return response.json();
  }

  // Job-Management
  async getJobs(): Promise<Job[]> {
    const response = await fetch(`${this.baseURL}/jobs`, {
      credentials: 'include',
    });
    return response.json();
  }

  async createJob(job: CreateJobRequest): Promise<Job> {
    const response = await fetch(`${this.baseURL}/jobs`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify(job),
    });
    return response.json();
  }

  // Smart-Plug-Steuerung (über Backend)
  async controlPrinter(printerId: string, action: 'on' | 'off'): Promise<void> {
    await fetch(`${this.baseURL}/plugs/${printerId}/${action}`, {
      method: 'POST',
      credentials: 'include',
    });
  }

  // Analytics & Statistiken
  async getStats(): Promise<Statistics> {
    const response = await fetch(`${this.baseURL}/stats`, {
      credentials: 'include',
    });
    return response.json();
  }
}

React Hooks für API-Integration

// src/hooks/usePrinters.ts
import useSWR from 'swr';
import { MYPApiClient } from '@/lib/api/myp-client';

const apiClient = new MYPApiClient();

export function usePrinters() {
  const { data, error, mutate } = useSWR('/printers', () => apiClient.getPrinters(), {
    refreshInterval: 30000, // Alle 30 Sekunden aktualisieren
  });

  return {
    printers: data || [],
    isLoading: !error && !data,
    isError: error,
    refresh: mutate,
  };
}

export function useJobs() {
  const { data, error, mutate } = useSWR('/jobs', () => apiClient.getJobs(), {
    refreshInterval: 10000, // Alle 10 Sekunden aktualisieren
  });

  return {
    jobs: data || [],
    isLoading: !error && !data,
    isError: error,
    refresh: mutate,
  };
}

📊 Analytics & Visualisierung

Dashboard-Komponenten

// src/components/charts/PrinterUsageChart.tsx
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';

interface PrinterUsageChartProps {
  data: UsageData[];
}

export function PrinterUsageChart({ data }: PrinterUsageChartProps) {
  return (
    <ResponsiveContainer width="100%" height={400}>
      <LineChart data={data}>
        <CartesianGrid strokeDasharray="3 3" />
        <XAxis dataKey="date" />
        <YAxis />
        <Tooltip />
        <Line type="monotone" dataKey="usage" stroke="#8884d8" strokeWidth={2} />
      </LineChart>
    </ResponsiveContainer>
  );
}

Analytics-Algorithmen

// src/lib/analytics/calculations.ts
export class Analytics {
  static calculateUsageStats(jobs: Job[]): UsageStats {
    const totalJobs = jobs.length;
    const totalDuration = jobs.reduce((sum, job) => sum + job.duration, 0);
    const averageDuration = totalDuration / totalJobs;

    return {
      totalJobs,
      totalDuration,
      averageDuration,
      peakHours: this.identifyPeakHours(jobs),
      efficiency: this.calculateEfficiency(jobs),
    };
  }

  static generateReport(data: any[]): ReportData {
    // Report-Generierung für PDF/Excel-Export
    return {
      summary: this.calculateSummary(data),
      charts: this.prepareChartData(data),
      tables: this.prepareTableData(data),
    };
  }

  private static identifyPeakHours(jobs: Job[]): number[] {
    const hourCounts = new Array(24).fill(0);
    jobs.forEach(job => {
      const hour = new Date(job.startTime).getHours();
      hourCounts[hour]++;
    });
    return hourCounts;
  }
}

🎨 UI/UX-Design

Design-System

// src/components/ui/button.tsx (Radix UI + Tailwind)
import { cn } from '@/lib/utils';

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
  size?: 'default' | 'sm' | 'lg' | 'icon';
}

export function Button({ className, variant = 'default', size = 'default', ...props }: ButtonProps) {
  return (
    <button
      className={cn(
        'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
        {
          'bg-primary text-primary-foreground hover:bg-primary/90': variant === 'default',
          'bg-destructive text-destructive-foreground hover:bg-destructive/90': variant === 'destructive',
          // ... weitere Varianten
        },
        {
          'h-10 px-4 py-2': size === 'default',
          'h-9 rounded-md px-3': size === 'sm',
          // ... weitere Größen
        },
        className
      )}
      {...props}
    />
  );
}

Responsive Layout

// src/components/layout/DashboardLayout.tsx
export function DashboardLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="min-h-screen bg-background">
      <header className="border-b">
        <div className="container mx-auto px-4 py-4">
          <nav className="flex items-center justify-between">
            <h1 className="text-2xl font-bold">MYP Dashboard</h1>
            <UserMenu />
          </nav>
        </div>
      </header>
      
      <div className="container mx-auto px-4 py-8">
        <div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
          <aside className="lg:col-span-1">
            <Navigation />
          </aside>
          <main className="lg:col-span-3">
            {children}
          </main>
        </div>
      </div>
    </div>
  );
}

📈 Erweiterte Features

Real-time Updates via WebSocket

// src/hooks/useRealTimeUpdates.ts
export function useRealTimeUpdates() {
  const [socket, setSocket] = useState<WebSocket | null>(null);

  useEffect(() => {
    const ws = new WebSocket(process.env.NEXT_PUBLIC_BACKEND_WS_URL!);
    
    ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      // Updates an SWR-Cache weiterleiten
      mutate('/printers', data.printers, false);
      mutate('/jobs', data.jobs, false);
    };

    setSocket(ws);
    return () => ws.close();
  }, []);

  return socket;
}

Export-Funktionen

// src/lib/export/exportUtils.ts
export class ExportUtils {
  static async generatePDFReport(data: ReportData): Promise<Blob> {
    const { jsPDF } = await import('jspdf');
    const doc = new jsPDF();
    
    // PDF-Generierung
    doc.text('MYP Analytics Report', 20, 20);
    // ... Report-Inhalte hinzufügen
    
    return doc.output('blob');
  }

  static async generateExcelReport(data: ReportData): Promise<Blob> {
    const XLSX = await import('xlsx');
    const workbook = XLSX.utils.book_new();
    
    // Excel-Sheet erstellen
    const worksheet = XLSX.utils.json_to_sheet(data.tables);
    XLSX.utils.book_append_sheet(workbook, worksheet, 'Analytics');
    
    return XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
  }
}

🚀 Deployment

Produktions-Konfiguration

# .env.production
NEXT_PUBLIC_BACKEND_API_URL=https://backend.myp.mercedes-benz.com/api
NEXT_PUBLIC_BACKEND_WS_URL=wss://backend.myp.mercedes-benz.com/ws

PM2 Ecosystem

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'myp-frontend',
    script: 'npm',
    args: 'start',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'production',
      PORT: 3000,
    },
  }],
};

Docker-Support

# Dockerfile
FROM node:18-alpine

WORKDIR /app

# Dependencies
COPY package*.json ./
RUN npm ci --only=production

# App
COPY . .
RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]

🔧 Development-Workflow

Code-Quality

# Linting & Formatting
pnpm lint          # ESLint check
pnpm lint:fix      # ESLint fix
pnpm format        # Prettier formatting

# Testing
pnpm test          # Unit tests
pnpm test:e2e      # End-to-end tests

# Build-Checks
pnpm build         # Production build
pnpm type-check    # TypeScript check

Integration-Testing

// tests/integration/api.test.ts
describe('Backend-Integration', () => {
  test('should fetch printers from backend', async () => {
    const client = new MYPApiClient();
    const printers = await client.getPrinters();
    
    expect(printers).toBeInstanceOf(Array);
    expect(printers[0]).toHaveProperty('id');
    expect(printers[0]).toHaveProperty('name');
  });
});

👥 Entwickler-Information

Torben Haack - Frontend & Analytics-Spezialist

  • UI/UX-Expertise: React-Komponenten und responsive Design
  • Integration-Spezialist: Nahtlose Backend-API-Anbindung
  • Analytics-Entwicklung: Datenvisualisierung und Reporting
  • Performance-Optimierung: Next.js und React Best Practices

Beitrag zum Gesamtsystem

Das Frontend-System ergänzt Till Tomczaks Backend-Infrastructure um:

  • Moderne Benutzeroberfläche: Intuitive Web-UI für alle Stakeholder
  • Advanced Analytics: Erweiterte Datenauswertung und Visualisierung
  • Cross-Platform-Support: Responsive Design für alle Endgeräte
  • Export-Funktionen: PDF/Excel-Reports für Management und Analyse

📚 Dokumentation & Support

Entwickler-Ressourcen

Integration mit Backend

  • Backend-APIs: Till Tomczaks REST-Endpunkte unter /api/*
  • Authentifizierung: Session-basiert über Backend-System
  • Real-time: WebSocket-Verbindung für Live-Updates

Entwickelt von: Torben Haack
Projektart: Frontend & Analytics für MYP-System
Framework: Next.js 14 + TypeScript + React 18
Integration: Vollständige Backend-API-Anbindung (Till Tomczak)
Status: Produktionsbereit