# 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 ```bash # Repository klonen git clone 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 # .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 ```bash # Entwicklungsserver starten pnpm dev # Frontend lΓ€uft auf http://localhost:3000 # Backend-APIs werden von http://backend-server:5000/api konsumiert ``` ### 4. Produktions-Deployment ```bash # 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 ```typescript // 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 { const response = await fetch(`${this.baseURL}/printers`, { credentials: 'include', // Session-Cookies ΓΌbertragen }); return response.json(); } async createPrinter(printer: CreatePrinterRequest): Promise { 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 { const response = await fetch(`${this.baseURL}/jobs`, { credentials: 'include', }); return response.json(); } async createJob(job: CreateJobRequest): Promise { 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 { await fetch(`${this.baseURL}/plugs/${printerId}/${action}`, { method: 'POST', credentials: 'include', }); } // Analytics & Statistiken async getStats(): Promise { const response = await fetch(`${this.baseURL}/stats`, { credentials: 'include', }); return response.json(); } } ``` ### React Hooks fΓΌr API-Integration ```typescript // 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 ```typescript // 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 ( ); } ``` ### Analytics-Algorithmen ```typescript // 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 ```typescript // src/components/ui/button.tsx (Radix UI + Tailwind) import { cn } from '@/lib/utils'; interface ButtonProps extends React.ButtonHTMLAttributes { variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'; size?: 'default' | 'sm' | 'lg' | 'icon'; } export function Button({ className, variant = 'default', size = 'default', ...props }: ButtonProps) { return (