From 516d32abf4838c3ea2f89d6921db279057491bc7 Mon Sep 17 00:00:00 2001 From: Andialbundy Date: Wed, 11 Feb 2026 16:44:38 +0100 Subject: [PATCH] feat: add authentication system with admin panel --- PROJECT_CONTEXT.md | 17 +- features/PROJ-1-user-registration.md | 182 ++++++ features/PROJ-2-user-login.md | 189 ++++++ features/PROJ-3-session-management.md | 267 +++++++++ features/PROJ-4-password-reset.md | 285 +++++++++ features/PROJ-5-user-profile.md | 353 +++++++++++ .../PROJ-SUMMARY-authentication-system.md | 268 +++++++++ src/app/(auth)/forgot-password/page.tsx | 195 ++++++ src/app/(auth)/login/page.tsx | 244 ++++++++ src/app/(auth)/register/page.tsx | 321 ++++++++++ src/app/(auth)/reset-password/page.tsx | 394 ++++++++++++ src/app/admin/layout.tsx | 11 + src/app/admin/page.tsx | 13 + src/app/dashboard/layout.tsx | 176 ++++++ src/app/dashboard/page.tsx | 363 +++++++++++ src/app/dashboard/profile/page.tsx | 566 ++++++++++++++++++ src/components/admin/admin-assistant.tsx | 188 ++++++ src/components/admin/admin-dashboard.tsx | 124 ++++ src/components/admin/scraping-registry.tsx | 212 +++++++ src/contexts/auth-context.tsx | 210 +++++++ 20 files changed, 4571 insertions(+), 7 deletions(-) create mode 100644 features/PROJ-1-user-registration.md create mode 100644 features/PROJ-2-user-login.md create mode 100644 features/PROJ-3-session-management.md create mode 100644 features/PROJ-4-password-reset.md create mode 100644 features/PROJ-5-user-profile.md create mode 100644 features/PROJ-SUMMARY-authentication-system.md create mode 100644 src/app/(auth)/forgot-password/page.tsx create mode 100644 src/app/(auth)/login/page.tsx create mode 100644 src/app/(auth)/register/page.tsx create mode 100644 src/app/(auth)/reset-password/page.tsx create mode 100644 src/app/admin/layout.tsx create mode 100644 src/app/admin/page.tsx create mode 100644 src/app/dashboard/layout.tsx create mode 100644 src/app/dashboard/page.tsx create mode 100644 src/app/dashboard/profile/page.tsx create mode 100644 src/components/admin/admin-assistant.tsx create mode 100644 src/components/admin/admin-dashboard.tsx create mode 100644 src/components/admin/scraping-registry.tsx create mode 100644 src/contexts/auth-context.tsx diff --git a/PROJECT_CONTEXT.md b/PROJECT_CONTEXT.md index 479f5189..1c79991a 100644 --- a/PROJECT_CONTEXT.md +++ b/PROJECT_CONTEXT.md @@ -7,8 +7,8 @@ Build web applications faster with AI agents handling Requirements, Architecture --- -## Aktueller Status -Template ready - Start by defining your first feature! +## Current Status +Template ready - Dependencies installed, environment configured, ready for first feature development! --- @@ -32,17 +32,20 @@ Template ready - Start by defining your first feature! ## Features Roadmap -### Your Features Will Appear Here +### Planned Features + +- [PROJ-1] User Authentication System → 🔵 Planned → [Spec](/features/PROJ-1-user-auth.md) +- [PROJ-2] Dashboard with Analytics → ⚪ Backlog +- [PROJ-3] Real-time Notifications → ⚪ Backlog +- [PROJ-4] User Profile Management → ⚪ Backlog + +### How to Add Features Start by defining your first feature using the Requirements Engineer agent: ``` Read .claude/agents/requirements-engineer.md and create a feature spec for [your feature idea] ``` -Example roadmap structure: -- [PROJ-1] Your First Feature → 🔵 Planned → [Spec](/features/PROJ-1-feature-name.md) -- [PROJ-2] Your Second Feature → ⚪ Backlog - --- ## Status-Legende diff --git a/features/PROJ-1-user-registration.md b/features/PROJ-1-user-registration.md new file mode 100644 index 00000000..51f6745b --- /dev/null +++ b/features/PROJ-1-user-registration.md @@ -0,0 +1,182 @@ +# PROJ-1: User Registration + +## Status: 🔵 Planned + +## User Stories +- Als neuer User möchte ich mich mit Email und Passwort registrieren um ein Konto zu erstellen +- als Product Manager möchte ich sichere Passwort-Anforderungen um User-Daten zu schützen +- Als Developer möchte ich OAuth-Integrationen um Registrierung zu vereinfachen +- Als System möchte ich Email-Verifikation um sicherzustellen dass User echt sind + +## Acceptance Criteria +- [ ] User kann mit Email und Passwort registrieren +- [ ] Passwort-Anforderungen: Mindestens 8 Zeichen, 1 Großbuchstabe, 1 Kleinbuchstabe, 1 Zahl +- [ ] OAuth-Registrierung verfügbar für Google und GitHub +- [ ] User erhält Verifizierungs-Email nach Registrierung +- [ ] User kann erst einloggen nach Email-Verifizierung +- [ ] Validierung ob Email bereits registriert ist +- [ ] User-Friendly Fehlermeldungen bei ungültigen Eingaben +- [ ] CSRF-Schutz für alle Formulare +- [ ] Rate Limiting: 5 Registrierungsversuche pro IP pro Minute + +## Edge Cases +- **Doppelte Email-Registrierung**: Zeigt Error Message "Email bereits verwendet" +- **Schwaches Passwort**: Zeigt spezifische Anforderungen für starkes Passwort +- **Ungültige Email**: Validiert Email-Format vor Absendung +- **OAuth-Fehler**: Graceful Fehlerbehandlung wenn OAuth-Provider nicht antwortet +- **Email-Service Down**: Zeigt freundliche Nachricht über Verzögerung bei Verifikation +- **Rate Limit Exceeded**: CAPTCHA nach 5 Fehlversuchen pro Minute +- **CSRF-Attacken**: Automatische Ablehnung bei fehlendem/gültigem Token + +## Technische Anforderungen +- **Performance**: < 300ms Response Time für Registrierung +- **Security**: HTTPS only, bcrypt für Passwort-Hashing +- **Database**: Supabase PostgreSQL für User-Storage +- **Email**: Supabase Auth Email Service für Verifikation +- **Frontend**: Next.js 16 mit shadcn/ui Komponenten + +## Dependencies +- Benötigt: Supabase Setup (infrastructure) + +## File Location +/src/app/(auth)/register/page.tsx +/src/app/api/auth/register/route.ts + +## Tech-Design (Solution Architect) + +### Component-Struktur +Registration Page +├── Page Layout mit Background und Branding +├── Registration Form Container +│ ├── Form Title und Description +│ ├── Email Input Field +│ │ ├── Email Validation (Format + Unique Check) +│ │ └── Real-time Validation Feedback +│ ├── Password Input Field +│ │ ├── Password Strength Indicator +│ │ ├── Show/Hide Password Toggle +│ │ └── Requirements Checklist +│ ├── Password Confirmation Field +│ │ ├── Match Validation +│ │ └── Real-time Feedback +│ ├── Terms & Conditions Checkbox +│ │ ├── Link zu Privacy Policy +│ │ └── Required Validation +│ ├── Submit Button mit Loading State +│ └── Form Error/Success Messages +├── OAuth Provider Section +│ ├── Divider ("oder anmelden mit") +│ ├── Google OAuth Button +│ │ ├── Google Icon +│ │ └── Loading State +│ └── GitHub OAuth Button +│ ├── GitHub Icon +│ └── Loading State +├── Login Redirect Link +│ └── "Bereits ein Konto? Einloggen" +└── Verification Notice Overlay + └── "Email Verification gesendet" + +### Daten-Model +Neue User Records enthalten: +- Primary Key: User ID (UUID von Supabase) +- Email Adresse (unique, not null) +- Passwort Hash (bcrypt, 12 rounds) +- Email Verified Flag (initial false) +- Account Status (pending_verification) +- OAuth Provider Fields (null für Email/Password) +- Registration Source (email oder oauth) +- Created At Timestamp +- IP Address bei Registration +- User Agent String + +Email Verification Records: +- Temporary Verification Token (UUID) +- User ID Reference +- Expiration Time (24 Stunden) +- Sent At Timestamp +- Delivery Status + +### Tech-Entscheidungen +Warum Client-seitige Validierung? +→ Sofortiges Feedback für bessere UX +→ Reduziert Server Load durch vorgefilterte Requests +→ Progressive Enhancement für Accessibility +→ React Hook Form Integration für Konsistenz + +Warum bcrypt mit 12 rounds? +→ Balances Security und Performance +→ Industry Standard für Production +→ Adaptive für zukünftige Hardware +→ Widerstand gegen Brute-Force + +Warum OAuth Flow mit Supabase? +→ Provider-Abstraktion für多种OAuth +→ Built-in Security für Client Secrets +→ Standardisiertes Redirect Handling +→ Automatic Account Mapping + +Warum Email Verification bevor Login? +→ Verhindert Fake-Accounts mit Spam-Emails +→ GDPR-Konformität für Verifizierte Identität +→ Reduziert Support-Aufwand +→ Basis für weitere Communications + +### Dependencies +Benötigte Packages: +- @supabase/auth-ui-react (OAuth UI Components) +- react-hook-form (Form Management) +- @hookform/resolvers mit zod (Validation Schema) +- zod (Type-safe Validation) +- sonner (Toast Notifications) +- lucide-react (Icons für OAuth Provider) +- @types/bcryptjs (TypeScript Support) + +Validierung Dependencies: +- zod-mail (Email Format Validation) +- zod-password (Password Stärke Regeln) +- @hookform/devtools (Development Tools) + +### Integration Patterns +Form Integration: +→ React Hook Form mit Zod Schema Validierung +→ Optimistic UI Updates für Loading States +→ Server-Aktion mit Fehlerbehandlung +→ Success Redirect zu Verification Notice + +OAuth Integration: +→ Supabase Auth UI React Components +→ Custom Styling mit shadcn/ui Design +→ Error Boundary für OAuth Failures +→ Graceful Fallback zu Email Registration + +Security Integration: +→ CSRF Tokens für alle Form Submissions +→ Rate Limiting pro IP Adresse +→ XSS Protection mit Content Security Policy +→ Input Sanitization für alle Fields + +Backend Integration: +→ API Route mit Supabase Client +→ Error Handling für Duplicate Emails +→ Transaction-safe User Creation +→ Async Email Versand mit Retry + +### Performance Considerations +Email Validation Check: +→ Debounced API Calls nach 500ms Typing Pause +→ Client-seitige Format Validierung zuerst +→ Server-seitige Unique Check nur bei validem Format +→ Cache für schon geprüfte Emails + +Password Strength Calculation: +→ Client-seitige Berechnung für sofortiges Feedback +→ Zod Integration für Pattern Matching +→ Visual Feedback mit Progress Bar +→ Accessibility mit Screen Reader Support + +OAuth Loading States: +→ Per-Provider Loading Indicators +→ Timeout Handling für langsame OAuth +→ Cancel Button für User Control +→ Graceful Error Recovery \ No newline at end of file diff --git a/features/PROJ-2-user-login.md b/features/PROJ-2-user-login.md new file mode 100644 index 00000000..4d7b07ae --- /dev/null +++ b/features/PROJ-2-user-login.md @@ -0,0 +1,189 @@ +# PROJ-2: User Login + +## Status: 🔵 Planned + +## User Stories +- Als registrierter User möchte ich mich mit Email und Passwort einloggen um auf mein Konto zuzugreifen +- Als User möchte ich OAuth-Login benutzen um schnellen Zugang ohne Passwort zu haben +- Als Security-Admin möchte ich Rate Limiting um Brute-Force-Angriffe zu verhindern +- Als User möchte ich "Remember Me" wählen um Session-Persistenz zu kontrollieren + +## Acceptance Criteria +- [ ] User kann sich mit Email und Passwort einloggen +- [ ] OAuth-Login verfügbar für Google und GitHub +- [ ] "Remember Me" Checkbox für Session-Persistenz +- [ ] User kann nur einloggen wenn Email verifiziert ist +- [ ] Klare Fehlermeldungen bei falschen Credentials +- [ ] Rate Limiting: 5 Login-Versuche pro Email pro Minute +- [ ] Session Token wird nach erfolgreichem Login erstellt +- [ ] User wird nach Login zum Dashboard weitergeleitet +- [ ] Bei Remember Me = true: Session hält 30 Tage +- [ ] Bei Remember Me = false: Session hält bis Browser-Close + +## Edge Cases +- **Falsche Credentials**: "Email oder Passwort falsch" (nicht spezifisch welcher) +- **Unverifizierte Email**: "Bitte verifiziere deine Email vor dem Login" +- **Rate Limit Exceeded**: "Zu viele Versuche. Bitte warten 5 Minuten." +- **Session Expired**: Automatischer Redirect zu Login mit "Session abgelaufen" +- **OAuth-Fehler**: Graceful Fallback auf Email/Passwort Login +- **Account Disabled**: "Account wurde deaktiviert. Bitte kontaktiere Support" +- **Browser Back Button**: Verhindert Cached Login-Seite nach Logout + +## Technische Anforderungen +- **Performance**: < 200ms Response Time für Login +- **Security**: Secure HTTP-only Cookies, SameSite=Strict +- **Session**: JWT mit expiration, refresh token mechanism +- **OAuth**: NextAuth.js oder Supabase Auth Integration +- **Rate Limiting**: Redis oder In-Memory Storage + +## Dependencies +- Benötigt: PROJ-1 (User Registration) - für User-Existenz +- Benötigt: PROJ-3 (Session Management) - für Session Handling + +## File Location +/src/app/(auth)/login/page.tsx +/src/app/api/auth/login/route.ts + +## Tech-Design (Solution Architect) + +### Component-Struktur +Login Page +├── Page Layout mit Background und Branding +├── Login Form Container +│ ├── Form Title und Welcome Message +│ ├── Email Input Field +│ │ ├── Email Format Validation +│ │ └── Autofill Support +│ ├── Password Input Field +│ │ ├── Show/Hide Password Toggle +│ │ └── Caps Lock Warning +│ ├── Remember Me Checkbox +│ │ ├── Session Duration Erklärung +│ │ └── Browser Compatibility Info +│ ├── Submit Button mit Loading State +│ ├── Form Error Messages +│ └── Success Redirect Handler +├── OAuth Provider Section +│ ├── Divider ("oder einloggen mit") +│ ├── Google OAuth Button +│ │ ├── Google Icon +│ │ └── Loading State +│ └── GitHub OAuth Button +│ ├── GitHub Icon +│ └── Loading State +├── Account Recovery Section +│ ├── "Passwort vergessen?" Link +│ └── Noch kein Konto? Registrieren Link +└── Session Status Checker + ├── Automatic Redirect bei aktiver Session + └── Session Expired Notice + +### Daten-Model +Login Process generiert: +- Session Record mit User ID +- Access Token (JWT, 15 Minuten gültig) +- Refresh Token (Rotation enabled) +- Device Information +- IP Address bei Login +- User Agent String +- Login Timestamp +- Session Type (remember_me oder session) + +Session Security Metadata: +- Failed Login Attempts Counter +- Last Successful Login Timestamp +- Lockout Status bei zu vielen Versuchen +- Two-Factor Setup Status (future) + +### Tech-Entscheidungen +Warum JWT mit Refresh Tokens? +→ Stateless für schnelle Validierung +→ Kurze Access Token Lebensdauer für Security +→ Refresh Token Rotation gegen Theft +→ Cross-Device Session Management +→ Standardisiert und Mobile-freundlich + +Warum "Remember Me" Option? +→ User Control über Session Dauer +→ Balance zwischen Security und Convenience +→ 30 Tage für typische User Habits +→ Compliance mit Privacy Requirements + +Warum Rate Limiting pro Email? +→ Fokussierter Schutz gegen Brute-Force +→ Prevents Email Enumeration Attacks +→ Fair für legitime User mit Fehlversuchen +→ Redis-basiert für Distributed Systems + +Warum Session Validation im Middleware? +→ Zentraler Schutz für alle Routes +→ Performance-Optimiert mit Edge Runtime +→ Automatic Token Refresh +→ Graceful Redirect bei Session Issues + +### Dependencies +Benötigte Packages: +- @supabase/auth-js (Session Management) +- jsonwebtoken (JWT Creation/Validation) +- jose (JWT Refresh Handling) +- react-hook-form (Form Management) +- @hookform/resolvers (Validation) +- sonner (Toast Notifications) +- js-cookie (Cookie Management) +- @types/js-cookie (TypeScript Support) + +Security Dependencies: +- express-rate-limit (Rate Limiting) +- helmet (Security Headers) +- bcryptjs (Password Verification) +- crypto-random-string (CSRF Tokens) + +### Integration Patterns +Auth State Management: +→ React Context mit Session Provider +→ Local Storage für Access Tokens +→ HTTP-Only Cookies für Refresh Tokens +→ Automatic Token Refresh auf API Calls + +Form Validation: +→ Client-seitige Validierung für UX +→ Server-seitige Verification für Security +→ Unified Error Messages für Consistency +→ Progressive Enhancement + +Session Persistence: +→ Cookie-basiert mit httpOnly und secure +→ SameSite=Strict für CSRF Protection +→ Automatic Expiration Handling +→ Cross-Tab Synchronization + +OAuth Integration: +→ Supabase Auth Provider Hooks +→ Custom Redirect Handling +→ Error Recovery für OAuth Failures +→ Account Linking mit existing Users + +### Performance Considerations +Login Response Time: +→ Database Indexes für Email Lookups +→ Connection Pooling für High Load +→ Cached Session Validation +→ Edge Middleware für schnelle Checks + +Token Refresh Strategy: +→ Sliding Expiration für User Experience +→ Background Refresh ohne UI Disruption +→ Fallback für Network Issues +→ Atomic Token Rotation + +Security Optimizations: +→ Bcrypt mit constant-time comparison +→ CSRF Token Rotation pro Request +→ Rate Limiting mit Sliding Window +→ Failed Login Attempt Tracking + +Mobile Optimizations: +→ Touch-friendly Button Sizes +── Keyboard Navigation Support +── Autofill Integration +── Progressive Web App Compatibility \ No newline at end of file diff --git a/features/PROJ-3-session-management.md b/features/PROJ-3-session-management.md new file mode 100644 index 00000000..b8496c59 --- /dev/null +++ b/features/PROJ-3-session-management.md @@ -0,0 +1,267 @@ +# PROJ-3: Session Management + +## Status: 🔵 Planned + +## User Stories +- Als eingeloggter User möchte ich meine Session aktiv halten um kontinuierlich auf die Anwendung zugreifen zu können +- Als System möchte ich Sessions automatisch erneuern um User-Erlebnis zu verbessern +- Als Security-Admin möchte ich Session-Timeouts um unautorisierten Zugriff zu verhindern +- Als User möchte ich mich ausloggen können um meine Session sicher zu beenden + +## Acceptance Criteria +- [ ] Session-Tokens werden automatisch erneuert (sliding expiration) +- [ ] Session expires nach inaktivität (default 7 Tage mit Remember Me) +- [ ] Session expires nach Browser-Close ohne Remember Me +- [ ] Logout-Funktion löscht alle Session-Daten client- und serverseitig +- [ ] Middleware prüft Session auf jeder geschützten Route +- [ ] Session-Verschlüsselung für sensitive Daten +- [ ] Logout von allen Geräten möglich +- [ ] Session-Persistence über Browser-Reloads +- [ ] Validierung von Session-Tokens auf jeder API-Anfrage +- [ ] Graceful Redirect zu Login bei ungültiger Session + +## Edge Cases +- **Session Theft**: Token-Refresh verhindert lange Token-Lebensdauer +- **Multiple Sessions**: User kann auf mehreren Geräten gleichzeitig eingeloggt sein +- **Network Issues**: Retry-Mechanismus für Session-Refresh +- **Server Restart**: Redis-basierte Sessions überleben Server-Restarts +- **Cross-Origin**: Proper CORS headers für session-basierte APIs +- **Token Manipulation**: Server-seitige Signatur-Validierung +- **Database Connection Lost**: Fallback zu In-Memory Session Storage +- **Logout Race Condition**: Atomic logout operations + +## Technische Anforderungen +- **Performance**: < 50ms Session-Check in Middleware +- **Security**: JWT mit RS256 Signatur, Refresh-Token Rotation +- **Storage**: Redis für Server-Side Sessions (Production) +- **Encryption**: AES-256 für sensitive Session-Daten +- **Timeouts**: Access Token 15min, Refresh Token 7-30 Tage +- **Compliance**: GDPR-konforme Session-Daten + +## Dependencies +- Benötigt: PROJ-2 (User Login) - erstellt initiale Session + +## File Location +/src/lib/session-manager.ts +/src/middleware.ts +/src/app/api/auth/refresh/route.ts +/src/app/api/auth/logout/route.ts + +## Tech-Design (Solution Architect) + +### Component-Struktur +Session Management System +├── Session Manager Library +│ ├── Session Creation Logic +│ │ ├── Access Token Generation +│ │ ├── Refresh Token Creation +│ │ └── Device Fingerprinting +│ ├── Session Validation Logic +│ │ ├── Token Signature Verification +│ │ ├── Expiration Checking +│ │ └── User Status Validation +│ ├── Session Refresh Logic +│ │ ├── Automatic Token Rotation +│ │ ├── Sliding Expiration +│ │ └── Background Refresh +│ └── Session Termination Logic +│ ├── Single Session Logout +│ ├── All Devices Logout +│ └── Graceful Cleanup +├── Middleware Protection +│ ├── Route Protection Wrapper +│ │ ├── Public Route Detection +│ │ ├── Protected Route Detection +│ │ └── Admin Route Detection +│ ├── Session Validation Check +│ │ ├── Token Extraction +│ │ ├── Database Validation +│ │ └── Status Checking +│ ├── Automatic Redirect Handler +│ │ ├── Login Redirect +│ │ ├── Access Denied Handler +│ │ └── Session Expired Handler +│ └── Token Refresh Middleware +│ ├── Automatic Refresh +│ ├── Error Recovery +│ └── Retry Logic +├── Session Context Provider +│ ├── Session State Management +│ │ ├── Current User Data +│ │ ├── Session Status +│ │ └── Loading States +│ ├── Session Events Handler +│ │ ├── Login Events +│ │ ├── Logout Events +│ │ └── Token Refresh Events +│ └── Cross-Tab Synchronization +│ ├── Storage Event Listener +│ ├── State Synchronization +│ └── Conflict Resolution +└── Session API Endpoints + ├── Refresh Token Endpoint + │ ├── Token Validation + │ ├── New Token Generation + │ └── Session Update + ├── Logout Endpoint + │ ├── Single Session Logout + │ ├── All Devices Logout + │ └── Cleanup Operations + └── Session Status Endpoint + ├── Active Sessions List + ├── Device Information + └── Session Management + +### Daten-Model +Sessions Tabelle (Server-Side): +- Session ID (Primary Key, UUID) +- User ID (Foreign Key) +- Refresh Token Hash (one-way) +- Access Token ID (für Rotation) +- Device Fingerprint +- User Agent String +- IP Address +- Created At Timestamp +- Last Active Timestamp +- Expires At Timestamp +- Is Active Flag + +Session Events Tabelle: +- Event ID (Primary Key) +- Session ID (Foreign Key) +- Event Type (login, logout, refresh, expired) +- IP Address +- User Agent +- Timestamp +- Additional Metadata + +Device Fingerprints: +- Fingerprint ID (Primary Key) +- Session ID (Foreign Key) +- Browser Information +- Screen Resolution +- Timezone +- Language +- Platform Information + +### Tech-Entscheidungen +Warum Server-Side Session Storage? +→ Additional Security Layer +→ Immediate Session Revocation möglich +→ Multi-Device Management +→ Audit Trail für Security Events +→ Protection gegen Token Replay + +Warum JWT mit Server Validation? +→ Stateless Performance für Access Tokens +→ Server-side Verification für Refresh Tokens +→ Best of Both Worlds Ansatz +→ Scalable Architecture +→ Mobile- und API-freundlich + +Warum Sliding Expiration? +→ Continuous User Experience +→ Security durch regelmäßige Validation +→ Inactivity-basiertes Timeout +→ Reduced Server Load +→ User-friendliche Session Length + +Warum Edge Middleware? +→ Globale Performance Optimierung +→ Reduzierte Latenz für Auth Checks +→ Geographic Distribution +→ Automatic Scaling +→ Zero Cold Starts + +### Dependencies +Benötigte Packages: +- @supabase/auth-js (Auth Core) +- jose (JWT Handling) +- jsonwebtoken (Token Operations) +- next/server (Middleware Runtime) +- crypto (Token Generation) +- ua-parser-js (Device Fingerprinting) +- fingerprint-generator (Device Identification) +- @types/ua-parser-js (TypeScript) + +Security Dependencies: +- helmet (Security Headers) +- express-rate-limit (Rate Limiting) +- cookie (Cookie Parsing) +- csrf (CSRF Protection) +- bcryptjs (Token Hashing) + +Performance Dependencies: +- redis (Session Cache) +- node-cache (In-Memory Cache) +- swr (Client-side Caching) +- react-query (Server State) + +### Integration Patterns +Middleware Integration: +→ Edge Runtime für globale Performance +→ Route-based Protection Rules +→ Automatic Token Refresh +→ Graceful Error Handling + +Client Integration: +→ React Context für globalen State +── Storage Events für Cross-Tab Sync +── Background Token Refresh +── Optimistic UI Updates + +Backend Integration: +── Database Transactions für Session Ops +── Event Sourcing für Audit Trail +── Cleanup Jobs für expired Sessions +── Monitoring für Session Performance + +Security Integration: +── Rate Limiting pro Session/IP +── Device Fingerprinting für Anomalie Detection +── CSRF Token Rotation +── Automatic Logout bei Security Events + +### Performance Considerations +Session Validation: +── Database Indexes für schnelle Lookups +── Connection Pooling für High Concurrency +── Cached Session Status mit TTL +── Batch Operations für Cleanup + +Token Management: +── Minimal JWT Payload für Performance +── Short-lived Access Tokens +── Efficient Token Rotation +── Background Refresh ohne Blocking + +Memory Optimization: +── LRU Cache für active Sessions +── Automatic Cleanup von expired Sessions +── Compression für Session Metadata +── Efficient Data Structures + +Monitoring und Analytics: +── Session Lifetime Metrics +── Login Failure Rates +── Geographic Distribution +── Device Usage Patterns + +### Security Architecture +Token Security: +── RS256 Signature mit Rotation +── Secure Key Storage +── Token Binding zu IP/Device +── Automatic Token Blacklisting + +Session Protection: +── Anti-session Fixation +── Concurrent Session Limits +── Anomaly Detection +── Automatic Revocation bei Risk + +Network Security: +── HTTPS-only Transmission +── Secure Cookie Flags +── CORS Configuration +── CSP Headers \ No newline at end of file diff --git a/features/PROJ-4-password-reset.md b/features/PROJ-4-password-reset.md new file mode 100644 index 00000000..8348a3f5 --- /dev/null +++ b/features/PROJ-4-password-reset.md @@ -0,0 +1,285 @@ +# PROJ-4: Password Reset + +## Status: 🔵 Planned + +## User Stories +- Als User möchte ich mein Passwort zurücksetzen können wenn ich es vergessen habe +- Als Security-Admin möchte ich Passwort-Reset-Links zeitlich begrenzen um Sicherheit zu gewährleisten +- Als User möchte ich Benachrichtigung über Passwort-Änderungen um über Konto-Aktivitäten informiert zu sein +- Als Developer möchte ich sichere Token-Generierung um Reset-Prozess zu schützen + +## Acceptance Criteria +- [ ] User kann Passwort-Reset über Email anfordern +- [ ] Reset-Link wird per Email gesendet mit einmaligem Token +- [ ] Reset-Link ist 15 Minuten gültig +- [ ] User kann neues Passwort über Reset-Seite setzen +- [ ] Passwort-Stärke-Anforderungen wie bei Registrierung +- [ ] Confirmation-Email nach erfolgreichem Passwort-Reset +- [ ] Token wird nach Gebrauch ungültig gemacht +- [ ] Rate Limiting: 3 Reset-Anfragen pro Email pro Stunde +- [ ] User muss neue Passwort-Anforderungen bestätigen +- [ ] Reset-Seite zeigt neue Passwort-Anforderungen an + +## Edge Cases +- **Nicht existente Email**: Zeigt "Wenn Email existiert, Link gesendet" (Security durch Obscurity) +- **Abgelaufener Token**: "Reset-Link abgelaufen. Bitte neuen anfordern." +- **Bereits benutzter Token**: "Reset-Link bereits verwendet. Bitte neuen anfordern." +- **Rate Limit Exceeded**: "Zu viele Anfragen. Bitte warten 60 Minuten." +- **Schwaches neues Passwort**: Zeigt spezifische Passwort-Anforderungen +- **Email Service Down**: "Technische Probleme. Bitte später versuchen." +- **Multiple Active Tokens**: Nur neuester Token ist gültig (ältere invalidiert) +- **Social Login User**: "Password nicht verfügbar für OAuth-Accounts" + +## Technische Anforderungen +- **Security**: Cryptographically secure Random Tokens (128-bit) +- **Performance**: < 500ms für Reset-Email-Versand +- **Email**: Supabase Email Service mit HTML Templates +- **Database**: Separate password_resets Tabelle mit TTL +- **Rate Limiting**: Supabase Row Level Security oder Middleware +- **Audit Trail**: Alle Reset-Versuche geloggt für Security + +## Dependencies +- Benötigt: PROJ-1 (User Registration) - für User-Existenz +- Benötigt: PROJ-3 (Session Management) - für Session-Invalidierung nach Reset + +## File Location +/src/app/(auth)/forgot-password/page.tsx +/src/app/(auth)/reset-password/page.tsx +/src/app/api/auth/forgot-password/route.ts +/src/app/api/auth/reset-password/route.ts + +## Tech-Design (Solution Architect) + +### Component-Struktur +Password Reset System +├── Forgot Password Page +│ ├── Page Layout mit Branding +│ ├── Instructions Section +│ │ ├── Process Erklärung +│ │ └── Expected Delivery Time +│ ├── Email Input Form +│ │ ├── Email Validation +│ │ ├── Loading State +│ │ └── Success/Error Messages +│ ├── Security Notice +│ │ ├── Rate Limiting Info +│ │ └── Email Verification Requirement +│ └── Back to Login Link +├── Reset Password Page +│ ├── Page Layout mit Security Branding +│ ├── Token Validation Section +│ │ ├── Token Expiration Check +│ │ ├── Token Usage Verification +│ │ └── Error Handling für invalid Tokens +│ ├── New Password Form +│ │ ├── Password Input mit Strength Indicator +│ │ ├── Password Confirmation Input +│ │ ├── Requirements Checklist +│ │ └── Submit Button mit Loading +│ ├── Security Information +│ │ ├── Session Invalidation Notice +│ │ └── Login after Reset Info +│ └── Resend Request Link +├── Email Templates +│ ├── Reset Request Email +│ │ ├── Personalized Greeting +│ │ ├── Reset Button mit Embedded Token +│ │ ├── Security Information +│ │ ├── Expiration Notice +│ │ └── Ignore Instructions +│ └── Reset Confirmation Email +│ ├── Success Notification +│ ├── Security Alert +│ ├── Device Information +│ └── Support Contact +├── API Security Layer +│ ├── Rate Limiting Protection +│ │ ├── Per-Email Rate Limiting +│ │ ├── Per-IP Rate Limiting +│ │ └── Global Abuse Protection +│ ├── Token Security +│ │ ├── Cryptographically Secure Generation +│ │ ├── One-way Hashing +│ │ ├── Single Usage Enforcement +│ │ └── Automatic Cleanup +│ └── Session Management +│ ├── All Sessions Invalidation +│ ├── Automatic Logout +│ └── Security Event Logging +└── Admin Dashboard Features + ├── Reset Request Monitoring + ├── Failed Reset Tracking + ├── Security Analytics + └── Manual Intervention Tools + +### Daten-Model +Password Resets Tabelle: +- Reset ID (Primary Key, UUID) +- User ID (Foreign Key, unique constraint) +- Reset Token (one-way hash) +- Token Expiration (15 Minuten) +- Created At Timestamp +- Used At Timestamp (nullable) +- IP Address bei Request +- User Agent String +- Delivery Status (pending, sent, failed) +- Bounce Tracking Information + +Reset Attempts Logging: +- Attempt ID (Primary Key) +- Email Address (hashed) +- IP Address +- Timestamp +- Success/Failure Status +- Error Code +- User Agent +- Geographic Information + +Security Events: +- Event ID (Primary Key) +- User ID (nullable für anonymous requests) +- Event Type (password_reset_request, password_reset_complete) +- IP Address +- Device Fingerprint +- Timestamp +- Additional Metadata + +### Tech-Entscheidungen +Warum Time-limited Reset Tokens? +→ Reduziert Angriffsfläche drastisch +→ Forces schnelle User Action +→ Automatic Cleanup verhindert Database Bloat +→ Industry Standard für Security +→ Compliance mit Security Best Practices + +Warum Rate Limiting pro Email/IP? +→ Prevents Email Spamming +→ Schutz gegen Brute-Force auf Resets +→ Reduces Email Provider Costs +→ Improves System Reliability +── Fair Resource Allocation + +Warum "Security durch Obscurity" bei nicht existenten Emails? +→ Verhindert Email Enumeration +── Schützt User Privacy +── Reduces Attack Surface +── Standard Practice in Auth Systems +── GDPR-konform + +Warum Single Usage Tokens? +→ Prevents Replay Attacks +── Forces Fresh Request für jeden Reset +── Simplifies Security Model +── Reduces Token Abuse Potential +── Easier Audit Trail + +### Dependencies +Benötigte Packages: +- @supabase/auth-js (Email Templates) +- nodemailer oder Supabase Email (Email Versand) +- crypto-random-string (Token Generation) +- bcryptjs (Token Hashing) +- date-fns (Time Calculations) +- react-hook-form (Form Management) +- @hookform/resolvers (Validation) +- zod (Type-safe Validation) + +Security Dependencies: +- express-rate-limit (Rate Limiting) +- helmet (Security Headers) +- csurf (CSRF Protection) +- ip-location (Geographic Tracking) +- ua-parser-js (Device Analysis) + +Email Dependencies: +- @supabase/emails (Template System) +- mjml (Responsive Email Templates) +- handlebars (Template Variables) +- aws-ses oder SendGrid (Delivery) + +### Integration Patterns +Email Integration: +→ Supabase Email Service für Reliability +→ Template-based Email Generation +→ Bounce Handling und Retry Logic +→ Delivery Status Tracking +→ HTML + Text Versions für Compatibility + +Token Security: +→ Cryptographically Secure Random Generation +→ One-way Hashing vor Database Storage +→ Automatic Expiration Enforcement +→ Immediate Invalidation nach Gebrauch +── Secure Transmission via HTTPS + +Form Security: +→ CSRF Token Protection +→ Input Sanitization und Validation +── Rate Limiting mit Sliding Window +── Device Fingerprinting für Anomalie Detection +── Graceful Error Handling + +Backend Integration: +── Atomic Database Operations +── Transaction-safe Token Creation +── Event Sourcing für Audit Trail +── Background Jobs für Cleanup +── Monitoring und Alerting + +### Performance Considerations +Token Generation: +── Vorkompilierte Templates für Emails +── Batch Operations für Cleanup +── Database Indexes für schnelle Lookups +── Connection Pooling für High Load +── Edge Caching für Rate Limiting + +Email Delivery: +── Queue-based Processing für Reliability +── Retry Logic mit Exponential Backoff +── Bounce Detection und Handling +── Provider Fallback Mechanism +── Delivery Analytics + +Database Optimizations: +── Composite Indexes für User+Token Queries +── TTL-based Automatic Cleanup +── Partitioning für Large Scale +── Read Replicas für Performance +── Efficient Query Patterns + +Security Performance: +── Cached Rate Limiting mit Redis +── Precomputed Token Hashes +── Optimized Database Schemas +── Minimal Logging Overhead +── Efficient Security Checks + +### Security Architecture +Token Security: +── 128-bit Cryptographically Secure Tokens +── One-way Hashing mit bcrypt +── Automatic Single Usage Enforcement +── Secure Random Number Generation +── Tamper-evident Design + +Attack Prevention: +── Rate Limiting auf mehreren Ebenen +── IP-based Blacklisting für Abuse +── CAPTCHA bei verdächtigen Mustern +── Geographic Anomaly Detection +── Device Fingerprinting + +Data Protection: +── Email Address Hashing für Logs +── Minimal Data Retention +── GDPR-konforme Data Handling +── Secure Token Storage +── Privacy-focused Design + +Incident Response: +── Automated Security Event Logging +── Real-time Alerting für Anomalies +── Manual Override Capabilities +── Emergency Disable Procedures +── Forensic Data Preservation \ No newline at end of file diff --git a/features/PROJ-5-user-profile.md b/features/PROJ-5-user-profile.md new file mode 100644 index 00000000..3f9fddd9 --- /dev/null +++ b/features/PROJ-5-user-profile.md @@ -0,0 +1,353 @@ +# PROJ-5: Basic User Profile + +## Status: 🔵 Planned + +## User Stories +- Als eingeloggter User möchte ich mein Profil anzeigen und bearbeiten um meine Daten aktuell zu halten +- Als User möchte ich meinen Namen und Avatar ändern um Personalisierung zu ermöglichen +- Als Security-Admin möchte ich Email-Änderung mit Verifikation schützen um Account-Übernahme zu verhindern +- Als User möchte ich mein Konto löschen können um meine Daten zu kontrollieren (GDPR) + +## Acceptance Criteria +- [ ] User kann Profil-Daten anzeigen (Name, Email, Avatar, Registrierungsdatum) +- [ ] User kann Namen und Avatar aktualisieren +- [ ] Email-Änderung erfordert neue Verifikation +- [ ] Avatar Upload mit Bild-Validierung (JPG, PNG, max 2MB) +- [ ] Profile-Änderungen werden sofort gespeichert +- [ ] Konto-Löschung mit Bestätigung und 30-tägiger Grace-Periode +- [ ] Email-Benachrichtigung bei wichtigen Profil-Änderungen +- [ ] Account-Status anzeigen (verifiziert, aktiv) +- [ ] Login-Geschichte anzeigen (letzten 10 Logins mit Gerät/IP) +- [ ] Passwort-Änderung möglich über Profil-Seite + +## Edge Cases +- **Avatar Upload Fehler**: "Falsches Format oder Datei zu groß (max 2MB)" +- **Email-Änderung Konflikt**: "Email bereits verwendet" +- **Konto-Löschung**: "Alle Daten werden nach 30 Tagen endgültig gelöscht" +- **Network Issues**: Optimistic UI Updates mit serverseitiger Validierung +- **Concurrent Updates**: Last-writer-wins mit timestamp +- **Storage Limit**: Max 5MB pro User für Avatar/Grafiken +- **Profile Viewing**: Andere User können kein Profil sehen (keine public profiles) +- **GDPR Export**: User kann alle Daten exportieren vor Löschung + +## Technische Anforderungen +- **Storage**: Supabase Storage für Avatars +- **File Upload**: Client-seitige Validierung + server-seitige checks +- **Security**: Row Level Security für Profil-Zugriff +- **Performance**: < 200ms für Profil-Laden +- **GDPR**: Data Portability und Right to Erasure +- **Audit**: Alle Profil-Änderungen werden mit timestamp geloggt + +## Dependencies +- Benötigt: PROJ-2 (User Login) - für authentifizierten Zugriff +- Benötigt: PROJ-3 (Session Management) - für Session-Validierung + +## File Location +/src/app/dashboard/profile/page.tsx +/src/app/api/user/profile/route.ts +/src/app/api/user/avatar/route.ts +/src/components/profile/ProfileForm.tsx + +## Tech-Design (Solution Architect) + +### Component-Struktur +User Profile System +├── Profile Dashboard Page +│ ├── Page Layout mit User Navigation +│ ├── Profile Overview Section +│ │ ├── Avatar Display mit Upload Button +│ │ ├── User Name Display +│ │ ├── Email Address Display +│ │ ├── Account Status Badge +│ │ └── Registration Date Display +│ ├── Profile Edit Form +│ │ ├── Name Input Field mit Validation +│ │ ├── Email Change Section +│ │ │ ├── New Email Input +│ │ │ ├── Password Confirmation +│ │ │ └── Verification Notice +│ │ ├── Avatar Upload Component +│ │ │ ├── File Input mit Drag & Drop +│ │ │ ├── Image Preview +│ │ │ ├── Crop Tool +│ │ │ └── Validation Feedback +│ │ └── Save/Cancel Actions +│ ├── Security Section +│ │ ├── Password Change Button +│ │ ├── Two-Factor Setup (future) +│ │ ├── Active Sessions List +│ │ └── Logout All Devices Button +│ ├── Account Management +│ │ ├── Login History Display +│ │ ├── Data Export Button +│ │ ├── Account Deletion Section +│ │ └── Privacy Settings +│ └── Notification Preferences +│ ├── Email Notifications Toggle +│ ├── Security Alerts Toggle +│ └── Marketing Communications Toggle +├── Avatar Upload System +│ ├── File Upload Component +│ │ ├── Drag & Drop Zone +│ │ ├── File Selection Button +│ │ ├── Progress Indicator +│ │ └── Error Display +│ ├── Image Processing Pipeline +│ │ ├── Client-side Validation +│ │ ├── Image Compression +│ │ ├── Aspect Ratio Adjustment +│ │ └── Format Conversion +│ ├── Storage Integration +│ │ ├── Supabase Storage Upload +│ │ ├── Unique Filename Generation +│ │ ├── Metadata Storage +│ │ └── Cleanup Operations +│ └── Preview Management +│ ├── Real-time Preview +│ ├── Undo Functionality +│ ├── Version History +│ └── Fallback to Default +├── Email Verification Flow +│ ├── Email Change Request +│ │ ├── New Email Input Form +│ │ ├── Password Confirmation +│ │ ├── Verification Email Sending +│ │ └── Pending Status Display +│ ├── Verification Process +│ │ ├── Email Link Handling +│ │ ├── Token Validation +│ │ ├── Atomic Email Update +│ │ └── Notification System +│ └── Rollback Mechanism +│ ├── Verification Timeout +│ ├── Failed Verification +│ └── Original Email Restoration +├── Account Deletion System +│ ├── Deletion Request Flow +│ │ ├── Confirmation Dialog +│ │ ├── Password Verification +│ │ ├── Reason Collection +│ │ └── Grace Period Setup +│ ├── Grace Period Management +│ │ ├── 30-day Countdown +│ │ ├── Cancellation Option +│ │ ├── Immediate Data Wipe Option +│ │ └── Data Export Preparation +│ └── Data Deletion Pipeline +│ ├── Automatic Deletion after Grace Period +│ ├── Complete Data Wipe +│ ├── Audit Trail Preservation +│ └── Confirmation Notification +└── Data Export System + ├── Export Request Handler + │ ├── Data Collection + │ ├── Format Selection + │ ├── Compression + │ └── Secure Download Link + ├── Export Content + │ ├── Profile Information + │ ├── Login History + │ ├── Account Settings + │ └── Associated Data + └── Download Management + ├── Temporary Secure Links + ├── Access Tracking + ├── Automatic Cleanup + └── Download History + +### Daten-Model +User Profiles Tabelle (extends auth.users): +- User ID (Primary Key, Foreign Key) +- Display Name (string, nullable) +- Avatar URL (string, nullable) +- Email Change Pending (boolean) +- New Email (string, nullable) +- Email Verification Token (string, nullable) +- Account Deletion Requested (boolean) +- Deletion Request Date (timestamp) +- Grace Period End Date (timestamp) +- Data Export Requested (boolean) +- Export Ready (boolean) +- Export Download URL (string, nullable) +- Profile Updated At (timestamp) +- Privacy Settings (JSON) + +Avatar Storage Metadata: +- File ID (Primary Key) +- User ID (Foreign Key) +- Original Filename +- Storage Path +- File Size +- MIME Type +- Upload Date +- Last Accessed +- Compression Settings + +Email Change History: +- Change ID (Primary Key) +- User ID (Foreign Key) +- Old Email +- New Email +- Change Date +- Verified Flag +- Verification Date +- IP Address +- User Agent + +Account Activity Log: +- Activity ID (Primary Key) +- User ID (Foreign Key) +- Activity Type (profile_update, email_change, password_change) +- Old Values (JSON) +- New Values (JSON) +- Timestamp +- IP Address +- Device Information + +### Tech-Entscheidungen +Warum Supabase Storage für Avatars? +→ Integrated mit Auth System +→ Built-in File Upload Security +→ Automatic CDN Distribution +→ Row Level Security Protection +→ Cost-effective für Images + +Warum Client-side Image Processing? +→ Reduziert Server Load +→ Schnelle User Feedback +── File Size Optimization vor Upload +── Progressive Enhancement +── Better Mobile Experience + +Warum Email Change mit Verification? +→ Verhindert Account Hijacking +── Zweistufige Bestätigung +── Security für sensible Änderungen +── Audit Trail für Compliance +── GDPR-konforme Datenänderung + +Warum Grace Period für Account Deletion? +── Users können ihre Entscheidung überdenken +── Datenrettung bei Fehlern +── Legal Requirements für Data Retention +── Better User Experience +── Reduced Support Tickets + +### Dependencies +Benötigte Packages: +- @supabase/storage-js (File Uploads) +- react-dropzone (Drag & Drop Uploads) +- react-image-crop (Image Cropping) +- browser-image-compression (File Optimization) +- file-saver (Data Export Download) +- react-hook-form (Form Management) +- @hookform/resolvers mit zod (Validation) +- date-fns (Date Operations) + +Avatar Processing: +- sharp (Server-side Image Processing) +- @types/sharp (TypeScript Support) +- multer (File Upload Middleware) +- mime-types (File Type Detection) +- crypto (Secure Filenames) + +Security Dependencies: +- helmet (Security Headers) +- rate-limiter-flexible (Rate Limiting) +- csurf (CSRF Protection) +- bcryptjs (Password Confirmation) +- crypto-random-string (Token Generation) + +Export Dependencies: +- json2csv (CSV Export) +- archiver (ZIP Creation) +- stream (File Streaming) +- fs-extra (File Operations) +- @types/archiver (TypeScript) + +### Integration Patterns +Avatar Integration: +→ Drag & Drop mit react-dropzone +→ Client-side Compression vor Upload +→ Supabase Storage mit Row Level Security +→ Automatic CDN Distribution +→ Fallback zu Default Avatar + +Form Integration: +→ React Hook Form mit Zod Validation +→ Optimistic Updates für besseres UX +→ Server-seitige Verification für Security +→ Undo-Funktionalität für wichtige Änderungen +→ Cross-Tab State Synchronization + +Security Integration: +→ Password Confirmation für sensible Änderungen +→ Email Verification für Identity Proof +→ Rate Limiting pro User/IP +→ Audit Logging für alle Änderungen +→ CSRF Protection für alle Forms + +Data Export Integration: +→ Async Export Generation mit Queue +── Secure Download Links mit Expiration +── Multiple Formate (JSON, CSV) +── Incremental Exports für large Data +── Email Benachrichtigung bei Export Ready + +### Performance Considerations +Image Optimization: +── Client-side Compression reduces Upload Time +── Multiple Sizes für verschiedene Use Cases +── Progressive Loading für Avatars +── Cache Headers für Browser Caching +── CDN Integration für globale Distribution + +Database Performance: +── Database Indexes für Profile Queries +── Connection Pooling für High Concurrency +── Read Replicas für Profile Reads +── Efficient JSON Storage für Settings +── Batch Operations für Bulk Updates + +File Storage Performance: +── Supabase Storage CDN Integration +── Automatic Image Optimization +── Cache Headers für Avatars +── Compression für File Uploads +── Lazy Loading für Profile Images + +User Interface Performance: +── Progressive Enhancement für Forms +── Optimistic Updates für sofortiges Feedback +── Debounced Validations +── Virtual Scrolling für Activity History +── Skeleton Loading States + +### Security Architecture +Data Protection: +── Row Level Security für Profile Access +── Encryption für sensitive Profile Data +── Secure File Upload mit Type Validation +── GDPR-konforme Data Handling +── Minimal Data Collection Principle + +Account Security: +── Two-step Verification für Email Changes +── Password Confirmation für sensitive Actions +── Rate Limiting für Profile Updates +── Device Fingerprinting für Anomaly Detection +── Automatic Security Event Logging + +Privacy Features: +── Granular Privacy Controls +── Data Portability mit Export +── Right to Erasure mit Grace Period +── Transparent Data Usage +── User-controlled Data Sharing + +Access Control: +── Session-based Profile Access +── CSRF Protection für alle Forms +── Secure File Downloads mit Expiration +── Rate Limited API Access +── IP-based Anomaly Detection \ No newline at end of file diff --git a/features/PROJ-SUMMARY-authentication-system.md b/features/PROJ-SUMMARY-authentication-system.md new file mode 100644 index 00000000..1499291e --- /dev/null +++ b/features/PROJ-SUMMARY-authentication-system.md @@ -0,0 +1,268 @@ +# PROJ-SUMMARY: User Authentication System + +## Status: 🔵 Planned + +## Overview +Complete user authentication and profile management system for the AI Coding Starter Kit. This foundational system provides secure user registration, login, session management, and profile capabilities with enterprise-grade security features. + +## Features Breakdown + +### PROJ-1: User Registration +- Email/password registration with strong password requirements +- OAuth integration (Google, GitHub) +- Mandatory email verification +- Rate limiting and security protections + +### PROJ-2: User Login +- Email/password authentication +- OAuth login providers +- "Remember Me" session persistence option +- Comprehensive security measures + +### PROJ-3: Session Management +- Secure JWT-based sessions with refresh tokens +- Automatic session renewal +- Multi-device support +- Secure logout functionality + +### PROJ-4: Password Reset +- Secure password reset flow via email +- Time-limited reset tokens +- Rate limiting protection +- User-friendly error handling + +### PROJ-5: Basic User Profile +- Profile viewing and editing +- Avatar upload functionality +- Email change with verification +- Account deletion with GDPR compliance + +## Technical Stack +- **Frontend**: Next.js 16, TypeScript, Tailwind CSS, shadcn/ui +- **Backend**: Next.js API Routes, Middleware +- **Database**: Supabase PostgreSQL +- **Authentication**: Supabase Auth with custom extensions +- **Storage**: Supabase Storage for avatars +- **Email**: Supabase Email Service + +## Security Features +- HTTPS-only communication +- Encrypted password storage (bcrypt) +- Rate limiting on all auth endpoints +- CSRF protection +- Session token rotation +- Email verification required +- Audit logging for security events + +## Target Users +- Solo developers working on personal projects +- Small teams collaborating on projects +- Enterprise users requiring robust security +- All user types benefit from unified authentication experience + +## Implementation Priority +1. **PROJ-1** (Foundation - User Registration) +2. **PROJ-2** (Core Access - User Login) +3. **PROJ-3** (Essential - Session Management) +4. **PROJ-4** (Important - Password Reset) +5. **PROJ-5** (Enhancement - User Profile) + +## Dependencies +Each feature builds upon the previous ones, creating a complete authentication ecosystem that can serve as the foundation for all future application features. + +## Compliance +- GDPR-compliant data handling +- Right to erasure implementation +- Data portability options +- Secure data storage and transmission + +## Tech-Design (Solution Architect) + +### Component-Struktur + +Auth System +├── Registration Page (/register) +│ ├── Registration Form (Email/Password) +│ │ ├── Email Input mit Validierung +│ │ ├── Password Input mit Stärke-Anzeige +│ │ ├── Password Bestätigung Input +│ │ ├── Terms & Conditions Checkbox +│ │ └── Submit Button +│ ├── OAuth Provider Buttons +│ │ ├── Google Login Button +│ │ └── GitHub Login Button +│ ├── Login Link ("Bereits Konto?") +│ └── Success/Error Nachrichten +├── Login Page (/login) +│ ├── Login Form (Email/Password) +│ │ ├── Email Input +│ │ ├── Password Input +│ │ ├── Remember Me Checkbox +│ │ └── Submit Button +│ ├── OAuth Provider Buttons +│ │ ├── Google Login Button +│ │ └── GitHub Login Button +│ ├── "Forgot Password" Link +│ └── Registration Link ("Noch kein Konto?") +├── Password Reset Pages +│ ├── Forgot Password Page (/forgot-password) +│ │ ├── Email Input +│ │ ├── Submit Button +│ │ └── Back to Login Link +│ └── Reset Password Page (/reset-password) +│ ├── New Password Input mit Stärke-Anzeige +│ ├── Password Bestätigung Input +│ └── Submit Button +├── User Profile Page (/dashboard/profile) +│ ├── Profile Form +│ │ ├── Name Input +│ │ ├── Email Display (Read-only mit Änderung-Option) +│ │ ├── Avatar Upload Bereich +│ │ ├── Registration Datum Display +│ │ └── Account Status Display +│ ├── Security Section +│ │ ├── Password Change Button +│ │ ├── Login History Display +│ │ └── Logout All Devices Button +│ └── Danger Zone +│ ├── Delete Account Button +│ └── Export Data Button +└── Auth Components (Global) + ├── Session Manager (Middleware Integration) + ├── Auth Context Provider + ├── Protected Route Wrapper + └── Login/Logout Buttons + +### Daten-Model + +User Tabelle (Supabase): +- Eindeutige User ID (UUID) +- Email Adresse (unique, verified flag) +- Passwort Hash (bcrypt, nur für Email/Password Accounts) +- Name (optional, für Profile) +- Avatar URL (Supabase Storage Pfad) +- Account Status (active, disabled, pending_deletion) +- Email Verified Flag (boolean) +- OAuth Provider Info (google_id, github_id) +- Registrierungs Datum +- Letztes Login Datum +- Created At / Updated At Timestamps + +Password Resets Tabelle: +- Eindeutige Reset ID (UUID) +- User ID (Foreign Key) +- Reset Token (cryptographically secure) +- Token Expiration Zeit +- Created At Timestamp +- Used Flag (boolean) + +Sessions Tabelle (Optional für Server-Side): +- Session ID (UUID) +- User ID (Foreign Key) +- Refresh Token Hash +- Device Information +- IP Address +- Created At / Expires At Timestamps + +Audit Logs Tabelle: +- Log ID (UUID) +- User ID (Foreign Key) +- Action Type (login, logout, password_change, profile_update) +- IP Address +- User Agent +- Timestamp +- Additional Metadata + +### Tech-Entscheidungen + +Warum Supabase als Backend? +→ Volles "Backend-as-a-Service" Paket mit PostgreSQL, Auth, Storage +→ Built-in OAuth Integration für Google/GitHub +→ Row Level Security für Daten-Schutz +→ Echtzeit-Updates für Session Management +→ Scalable Hosting mit Backups + +Warum Next.js API Routes? +→ Full-Stack Framework mit integriertem Routing +→ Server-Side Middleware für Auth Checks +→ Edge Runtime Support für Performance +→ TypeScript Unterstützung out-of-the-box +→ SEO-freundlich mit SSR/SSG Optionen + +Warum JWT mit Refresh Tokens? +→ Stateless Authentication für Performance +→ Kurze Access Token Lebensdauer (15min) für Security +→ Refresh Token Rotation gegen Token Theft +→ Cross-Device Session Management +→ Standardisiert und gut supported + +Warum bcrypt für Passwörter? +→ Industry Standard für Passwort Hashing +→ Adaptive Work Factor für zukünftige Security +→ Salting automatisch inklusive +→ Resistent gegen Rainbow Tables + +Warum Rate Limiting mit Middleware? +→ Schutz vor Brute-Force Angriffen +→ Zentrale Implementierung für alle Endpoints +→ Redis-basiert für Distributed Systems +→ Konfigurierbare Limits pro Endpoint + +Warum Supabase Storage für Avatars? +→ Integrierte File Uploads mit Security +→ Automatische Bild-Optimierung +→ CDN-Integration für Performance +→ Row Level Security auch für Files +→ Günstig und skalierbar + +### Dependencies + +Benötigte Packages: +- @supabase/auth-js (Auth Core Library) +- @supabase/storage-js (File Uploads) +- jsonwebtoken (JWT Handling) +- bcryptjs (Passwort Hashing) +- crypto (für Random Tokens) +- nodemailer oder Supabase Email (Email Versand) +- react-hook-form (Form Handling) +- @hookform/resolvers mit zod (Validation) +- sonner (Toast Notifications) +- next-iron-session oder jwt-decode (Session Helpers) + +Security Packages: +- helmet (Security Headers) +- express-rate-limit (Rate Limiting) +- cors (Cross-Origin Protection) +- crypto-random-string (Secure Tokens) + +### Integration Patterns + +Auth Flow Integration: +→ Client-Seite: React Context für globalen Auth State +→ Server-Seite: Middleware für Session Validierung +→ Database: Row Level Security Policies +→ API: Protected Routes mit Auth Check + +OAuth Integration: +→ Supabase Auth Provider Konfiguration +→ Client-Seite OAuth Buttons mit Redirect +→ Server-Seite User Mapping zu internem Account +→ Graceful Fallback bei OAuth-Problemen + +Session Management: +→ HTTP-Only Cookies für Refresh Tokens +→ Local Storage für Access Tokens +→ Automatic Token Refresh im Background +→ Multi-Device Session Tracking + +Error Handling: +→ Zentralisierte Error Components +→ User-Friendly Fehlermeldungen +→ Security durch Obscurity bei sensitiven Fehlern +→ Retry-Mechanismen für Network Issues + +Performance Optimierungen: +→ Edge Middleware für schnelle Auth Checks +→ Cached User Profiles mit Invalidation +→ Lazy Loading für Auth Components +→ Optimistic Updates für Profile Änderungen \ No newline at end of file diff --git a/src/app/(auth)/forgot-password/page.tsx b/src/app/(auth)/forgot-password/page.tsx new file mode 100644 index 00000000..b468784e --- /dev/null +++ b/src/app/(auth)/forgot-password/page.tsx @@ -0,0 +1,195 @@ +'use client' + +import { useState } from 'react' +import { useForm } from 'react-hook-form' +import { zodResolver } from '@hookform/resolvers/zod' +import * as z from 'zod' +import { Button } from "@/components/ui/button" +import { Card, CardHeader, CardTitle, CardContent, CardDescription, CardFooter } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Alert, AlertDescription } from "@/components/ui/alert" +import { Loader2, Mail, ArrowLeft, Clock, Shield } from 'lucide-react' +import Link from 'next/link' + +const formSchema = z.object({ + email: z.string().email("Ungültige Email-Adresse") +}) + +type FormData = z.infer + +export default function ForgotPasswordPage() { + const [isLoading, setIsLoading] = useState(false) + const [isSubmitted, setIsSubmitted] = useState(false) + const [error, setError] = useState(null) + const [submittedEmail, setSubmittedEmail] = useState('') + + const { + register, + handleSubmit, + formState: { errors } + } = useForm({ + resolver: zodResolver(formSchema) + }) + + const onSubmit = async (data: FormData) => { + setIsLoading(true) + setError(null) + + try { + // TODO: Implement actual password reset request with Supabase + console.log('Password reset request for:', data.email) + + // Simulate API call + await new Promise(resolve => setTimeout(resolve, 2000)) + + setSubmittedEmail(data.email) + setIsSubmitted(true) + } catch (err) { + setError(err instanceof Error ? err.message : 'Anfrage fehlgeschlagen') + } finally { + setIsLoading(false) + } + } + + if (isSubmitted) { + return ( +
+ + +
+ +
+ Email gesendet + + Wir haben dir einen Link zum Zurücksetzen des Passworts gesendet + +
+ +
+

+ Sende einen Link zu {submittedEmail} +

+ +
+
+ + Link gültig für 15 Minuten +
+
+ + Aus Sicherheitsgründen zeigen wir nicht an, ob die Email existiert +
+
+ +
+

• Überprüfe deinen Posteingang

+

• Kontrolle auch den Spam-Ordner

+

• Warte einige Minuten auf die Zustellung

+
+
+ +
+

+ Keine Email erhalten? +

+ +
+
+ + + + Zurück zum Login + + +
+
+ ) + } + + return ( +
+ + + Passwort vergessen + + Gib deine Email-Adresse ein und wir senden dir einen Link zum Zurücksetzen + + + + {error && ( + + {error} + + )} + + {/* Security Notice */} +
+
+ +
+

Hinweis zur Sicherheit

+

+ Aus Schutz deiner Privatsphäre zeigen wir nicht an, ob eine Email-Adresse + registriert ist. Wenn du keine Email erhältst, überprüfe deine Eingabe + oder wende dich an den Support. +

+
+
+
+ + {/* Rate Limiting Info */} +
+
+ + + Du kannst maximal 3 Anfragen pro Stunde stellen. Rate Limiting ist aktiv. + +
+
+ +
+
+ + + {errors.email && ( +

{errors.email.message}

+ )} +
+ + +
+
+ + + + Zurück zum Login + + +
+
+ ) +} \ No newline at end of file diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx new file mode 100644 index 00000000..0415a671 --- /dev/null +++ b/src/app/(auth)/login/page.tsx @@ -0,0 +1,244 @@ +'use client' + +import { useState, useEffect } from 'react' +import { useForm } from 'react-hook-form' +import { zodResolver } from '@hookform/resolvers/zod' +import * as z from 'zod' +import { Button } from "@/components/ui/button" +import { Card, CardHeader, CardTitle, CardContent, CardDescription, CardFooter } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Checkbox } from "@/components/ui/checkbox" +import { Separator } from "@/components/ui/separator" +import { Alert, AlertDescription } from "@/components/ui/alert" +import { Loader2, Eye, EyeOff, Github, Chrome, AlertCircle } from 'lucide-react' +import Link from 'next/link' + +const formSchema = z.object({ + email: z.string().email("Ungültige Email-Adresse"), + password: z.string().min(1, "Passwort ist erforderlich"), + rememberMe: z.boolean().optional() +}) + +type FormData = z.infer + +export default function LoginPage() { + const [isLoading, setIsLoading] = useState(false) + const [showPassword, setShowPassword] = useState(false) + const [error, setError] = useState(null) + const [sessionExpired, setSessionExpired] = useState(false) + + const { + register, + handleSubmit, + formState: { errors } + } = useForm({ + resolver: zodResolver(formSchema) + }) + + // Check for session expired flag in URL or localStorage + useEffect(() => { + const urlParams = new URLSearchParams(window.location.search) + const expired = urlParams.get('expired') + const localExpired = localStorage.getItem('session_expired') + + if (expired === 'true' || localExpired === 'true') { + setSessionExpired(true) + localStorage.removeItem('session_expired') + } + }, []) + + const onSubmit = async (data: FormData) => { + setIsLoading(true) + setError(null) + + try { + // TODO: Implement actual login logic with Supabase + console.log('Login data:', data) + + // Simulate API call + await new Promise(resolve => setTimeout(resolve, 2000)) + + // Simulate successful login - redirect to dashboard + // Using window.location.href for hard redirect as per frontend-dev.md + window.location.href = '/dashboard' + } catch (err) { + setError(err instanceof Error ? err.message : 'Login fehlgeschlagen') + } finally { + setIsLoading(false) + } + } + + const handleOAuthLogin = async (provider: 'google' | 'github') => { + setIsLoading(true) + setError(null) + + try { + // TODO: Implement OAuth login with Supabase + console.log(`OAuth login with ${provider}`) + + // Simulate OAuth flow + await new Promise(resolve => setTimeout(resolve, 1500)) + + // Simulate successful OAuth login + window.location.href = '/dashboard' + } catch (err) { + setError(err instanceof Error ? err.message : 'OAuth Login fehlgeschlagen') + } finally { + setIsLoading(false) + } + } + + return ( +
+ + + Willkommen zurück + + Melde dich mit deinem Konto an + + + + {sessionExpired && ( + + + + Deine Sitzung ist abgelaufen. Bitte melde dich erneut an. + + + )} + + {error && ( + + {error} + + )} + +
+
+ + + {errors.email && ( +

{errors.email.message}

+ )} +
+ +
+ +
+ + +
+ {errors.password && ( +

{errors.password.message}

+ )} +
+ +
+
+ + +
+ + Passwort vergessen? + +
+ +
+

+ "Angemeldet bleiben" hält dich für 30 Tage eingeloggt. + Ohne diese Option wirst du beim Schließen des Browsers ausgeloggt. +

+
+ + +
+ +
+
+ +
+
+ Oder anmelden mit +
+
+ +
+ + +
+
+ +

+ Noch kein Konto?{' '} + + Registrieren + +

+

+ By logging in, you agree to our{' '} + + Terms of Service + {' '} + and{' '} + + Privacy Policy + +

+
+
+
+ ) +} \ No newline at end of file diff --git a/src/app/(auth)/register/page.tsx b/src/app/(auth)/register/page.tsx new file mode 100644 index 00000000..3ec46664 --- /dev/null +++ b/src/app/(auth)/register/page.tsx @@ -0,0 +1,321 @@ +'use client' + +import { useState } from 'react' +import { useForm } from 'react-hook-form' +import { zodResolver } from '@hookform/resolvers/zod' +import * as z from 'zod' +import { Button } from "@/components/ui/button" +import { Card, CardHeader, CardTitle, CardContent, CardDescription, CardFooter } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Checkbox } from "@/components/ui/checkbox" +import { Separator } from "@/components/ui/separator" +import { Badge } from "@/components/ui/badge" +import { Alert, AlertDescription } from "@/components/ui/alert" +import { Loader2, Eye, EyeOff, Mail, Github, Chrome } from 'lucide-react' +import Link from 'next/link' + +const passwordRequirements = [ + { regex: /.{8,}/, text: "Mindestens 8 Zeichen" }, + { regex: /[A-Z]/, text: "1 Großbuchstabe" }, + { regex: /[a-z]/, text: "1 Kleinbuchstabe" }, + { regex: /[0-9]/, text: "1 Zahl" } +] + +const formSchema = z.object({ + email: z.string().email("Ungültige Email-Adresse"), + password: z.string().min(8, "Mindestens 8 Zeichen"), + confirmPassword: z.string(), + terms: z.boolean().refine(val => val === true, "AGBs müssen akzeptiert werden") +}).refine(data => data.password === data.confirmPassword, { + message: "Passwörter stimmen nicht überein", + path: ["confirmPassword"] +}) + +type FormData = z.infer + +export default function RegisterPage() { + const [isLoading, setIsLoading] = useState(false) + const [showPassword, setShowPassword] = useState(false) + const [showConfirmPassword, setShowConfirmPassword] = useState(false) + const [passwordStrength, setPasswordStrength] = useState(0) + const [error, setError] = useState(null) + const [success, setSuccess] = useState(false) + + const { + register, + handleSubmit, + formState: { errors }, + watch + } = useForm({ + resolver: zodResolver(formSchema) + }) + + const password = watch('password') + const confirmPassword = watch('confirmPassword') + + // Calculate password strength + const calculatePasswordStrength = (password: string) => { + let strength = 0 + passwordRequirements.forEach(req => { + if (req.regex.test(password)) strength++ + }) + return strength + } + + // Update password strength when password changes + const handlePasswordChange = (value: string) => { + const strength = calculatePasswordStrength(value) + setPasswordStrength(strength) + } + + const onSubmit = async (data: FormData) => { + setIsLoading(true) + setError(null) + + try { + // TODO: Implement actual registration logic with Supabase + console.log('Registration data:', data) + + // Simulate API call + await new Promise(resolve => setTimeout(resolve, 2000)) + + setSuccess(true) + } catch (err) { + setError(err instanceof Error ? err.message : 'Registrierung fehlgeschlagen') + } finally { + setIsLoading(false) + } + } + + const handleOAuthLogin = async (provider: 'google' | 'github') => { + setIsLoading(true) + try { + // TODO: Implement OAuth login + console.log(`OAuth login with ${provider}`) + } catch (err) { + setError(err instanceof Error ? err.message : 'OAuth Login fehlgeschlagen') + } finally { + setIsLoading(false) + } + } + + if (success) { + return ( +
+ + +
+
+ +
+

Verifizierungs-Email gesendet

+

+ Wir haben dir eine Email mit einem Bestätigungslink gesendet. Bitte überprüfe dein Postfach. +

+

+ Keine Email erhalten? Überprüfe deinen Spam-Ordner. +

+
+
+
+
+ ) + } + + return ( +
+ + + Konto erstellen + + Registriere dich mit Email und Passwort + + + + {error && ( + + {error} + + )} + +
+
+ + + {errors.email && ( +

{errors.email.message}

+ )} +
+ +
+ +
+ handlePasswordChange(e.target.value) + })} + className={errors.password ? 'border-red-500' : ''} + /> + +
+ + {/* Password Requirements Checklist */} +
+ {passwordRequirements.map((req, index) => ( +
+
+ + {req.text} + +
+ ))} +
+ + {/* Password Strength Indicator */} + {password && ( +
+
+ Passwort-Stärke + + {passwordStrength <= 1 ? "Schwach" : passwordStrength <= 2 ? "Mittel" : "Stark"} + +
+
+
+
+
+ )} +
+ +
+ +
+ + +
+ {errors.confirmPassword && ( +

{errors.confirmPassword.message}

+ )} + {confirmPassword && password === confirmPassword && ( +

Passwörter stimmen überein

+ )} +
+ +
+ + +
+ {errors.terms && ( +

{errors.terms.message}

+ )} + + + + +
+
+ +
+
+ Oder registrieren mit +
+
+ +
+ + +
+ + +

+ Bereits ein Konto?{' '} + + Einloggen + +

+
+ +
+ ) +} \ No newline at end of file diff --git a/src/app/(auth)/reset-password/page.tsx b/src/app/(auth)/reset-password/page.tsx new file mode 100644 index 00000000..d050a6b5 --- /dev/null +++ b/src/app/(auth)/reset-password/page.tsx @@ -0,0 +1,394 @@ +'use client' + +import { useState, useEffect, Suspense } from 'react' +import { useForm } from 'react-hook-form' +import { zodResolver } from '@hookform/resolvers/zod' +import * as z from 'zod' +import { Button } from "@/components/ui/button" +import { Card, CardHeader, CardTitle, CardContent, CardDescription, CardFooter } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Alert, AlertDescription } from "@/components/ui/alert" +import { Badge } from "@/components/ui/badge" +import { Loader2, Eye, EyeOff, AlertTriangle, CheckCircle, Shield, ArrowLeft } from 'lucide-react' +import Link from 'next/link' +import { useSearchParams } from 'next/navigation' + +const passwordRequirements = [ + { regex: /.{8,}/, text: "Mindestens 8 Zeichen" }, + { regex: /[A-Z]/, text: "1 Großbuchstabe" }, + { regex: /[a-z]/, text: "1 Kleinbuchstabe" }, + { regex: /[0-9]/, text: "1 Zahl" } +] + +const formSchema = z.object({ + password: z.string().min(8, "Mindestens 8 Zeichen"), + confirmPassword: z.string() +}).refine(data => data.password === data.confirmPassword, { + message: "Passwörter stimmen nicht überein", + path: ["confirmPassword"] +}) + +type FormData = z.infer + +function ResetPasswordPageContent() { + const searchParams = useSearchParams() + const token = searchParams.get('token') + + const [isLoading, setIsLoading] = useState(false) + const [showPassword, setShowPassword] = useState(false) + const [showConfirmPassword, setShowConfirmPassword] = useState(false) + const [passwordStrength, setPasswordStrength] = useState(0) + const [tokenValid, setTokenValid] = useState(null) + const [error, setError] = useState(null) + const [success, setSuccess] = useState(false) + + const { + register, + handleSubmit, + formState: { errors }, + watch + } = useForm({ + resolver: zodResolver(formSchema) + }) + + const password = watch('password') + const confirmPassword = watch('confirmPassword') + + // Validate token on component mount + useEffect(() => { + if (!token) { + setTokenValid(false) + setError('Ungültiger Reset-Link. Bitte fordere einen neuen Link an.') + return + } + + const validateToken = async () => { + try { + // TODO: Implement actual token validation with Supabase + console.log('Validating token:', token) + + // Simulate token validation + await new Promise(resolve => setTimeout(resolve, 1000)) + + // For demo, consider any token as valid + setTokenValid(true) + } catch (err) { + setTokenValid(false) + setError(err instanceof Error ? err.message : 'Ungültiger oder abgelaufener Token') + } + } + + validateToken() + }, [token]) + + // Calculate password strength + const calculatePasswordStrength = (password: string) => { + let strength = 0 + passwordRequirements.forEach(req => { + if (req.regex.test(password)) strength++ + }) + return strength + } + + // Update password strength when password changes + const handlePasswordChange = (value: string) => { + const strength = calculatePasswordStrength(value) + setPasswordStrength(strength) + } + + const onSubmit = async (data: FormData) => { + if (!token) return + + setIsLoading(true) + setError(null) + + try { + // TODO: Implement actual password reset with Supabase + console.log('Reset password with token:', token, 'new password:', data.password) + + // Simulate API call + await new Promise(resolve => setTimeout(resolve, 2000)) + + setSuccess(true) + } catch (err) { + setError(err instanceof Error ? err.message : 'Passwort-Reset fehlgeschlagen') + } finally { + setIsLoading(false) + } + } + + // Token validation loading state + if (tokenValid === null) { + return ( +
+ + +
+ +

Validiere Reset-Link...

+

Bitte warten

+
+
+
+
+ ) + } + + // Token invalid + if (tokenValid === false) { + return ( +
+ + +
+ +
+ Ungültiger Link + + Dieser Reset-Link ist ungültig oder abgelaufen + +
+ +
+
+ +
+

Mögliche Ursachen:

+
    +
  • Der Link wurde bereits verwendet
  • +
  • Der Link ist älter als 15 Minuten
  • +
  • Der Link wurde manipuliert
  • +
+
+
+
+ +
+ + +
+
+
+
+ ) + } + + // Success state + if (success) { + return ( +
+ + +
+ +
+ Passwort geändert + + Dein Passwort wurde erfolgreich zurückgesetzt + +
+ +
+
+
+ + Alle Sitzungen wurden beendet +
+
+ +

+ Aus Sicherheitsgründen wurden alle aktiven Sitzungen beendet. + Du musst dich neu anmelden. +

+ +

+ Du erhältst in Kürze eine Bestätigungs-Email über die Passwort-Änderung. +

+
+ + +
+
+
+ ) + } + + // Reset password form + return ( +
+ + + Neues Passwort festlegen + + Wähle ein sicheres neues Passwort für dein Konto + + + + {error && ( + + {error} + + )} + + {/* Security Notice */} +
+
+ +
+

Sicherheitshinweis

+

+ Nach der Passwort-Änderung werden alle aktuellen Sitzungen beendet + und du musst dich neu anmelden. +

+
+
+
+ +
+
+ +
+ handlePasswordChange(e.target.value) + })} + className={errors.password ? 'border-red-500' : ''} + /> + +
+ + {/* Password Requirements Checklist */} +
+ {passwordRequirements.map((req, index) => ( +
+
+ + {req.text} + +
+ ))} +
+ + {/* Password Strength Indicator */} + {password && ( +
+
+ Passwort-Stärke + + {passwordStrength <= 1 ? "Schwach" : passwordStrength <= 2 ? "Mittel" : "Stark"} + +
+
+
+
+
+ )} +
+ +
+ +
+ + +
+ {errors.confirmPassword && ( +

{errors.confirmPassword.message}

+ )} + {confirmPassword && password === confirmPassword && ( +

Passwörter stimmen überein

+ )} +
+ + + + + + + + Zurück zum Login + + + +
+ ) +} + +export default function ResetPasswordPage() { + return ( + + + +
+ +

Lade...

+

Bitte warten

+
+
+
+
+ }> + + + ) +} \ No newline at end of file diff --git a/src/app/admin/layout.tsx b/src/app/admin/layout.tsx new file mode 100644 index 00000000..df857e77 --- /dev/null +++ b/src/app/admin/layout.tsx @@ -0,0 +1,11 @@ +export default function AdminLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( +
+ {children} +
+ ) +} \ No newline at end of file diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx new file mode 100644 index 00000000..0717dfd9 --- /dev/null +++ b/src/app/admin/page.tsx @@ -0,0 +1,13 @@ +'use client' + +import { AdminDashboard } from "@/components/admin/admin-dashboard" + +export default function AdminPage() { + // Mock user data - in production, this would come from authentication + const mockUser = { + email: "admin@example.com", + name: "Administrator" + } + + return +} \ No newline at end of file diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx new file mode 100644 index 00000000..be54dc2c --- /dev/null +++ b/src/app/dashboard/layout.tsx @@ -0,0 +1,176 @@ +'use client' + +import { ReactNode } from 'react' +import Link from 'next/link' +import { Button } from "@/components/ui/button" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger +} from "@/components/ui/dropdown-menu" +import { User, Settings, LogOut, Home, Shield, Crown } from 'lucide-react' + +interface DashboardLayoutProps { + children: ReactNode +} + +export default function DashboardLayout({ children }: DashboardLayoutProps) { + // Mock user data - in real app this would come from auth context + const user = { + displayName: 'Max Mustermann', + email: 'user@example.com', + avatarUrl: null + } + + const handleLogout = async () => { + try { + // TODO: Implement actual logout with Supabase + console.log('Logging out...') + + // Simulate logout + await new Promise(resolve => setTimeout(resolve, 500)) + + // Hard redirect to login as per frontend-dev.md + window.location.href = '/login' + } catch (err) { + console.error('Logout error:', err) + } + } + + return ( +
+ {/* Header */} +
+
+
+ {/* Logo/Brand */} +
+ +
+ +
+ Dashboard + +
+ + {/* Navigation */} + + + {/* User Menu */} +
+ + + + + +
+
+

{user.displayName}

+

+ {user.email} +

+
+
+ + + + + Profil + + + + + + Einstellungen + + + + + + Sicherheit + + + + + + Admin Panel + + + + + + Ausloggen + +
+
+
+
+
+
+ + {/* Main Content */} +
+ {children} +
+ + {/* Mobile Navigation (if needed) */} +
+ +
+
+ ) +} \ No newline at end of file diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx new file mode 100644 index 00000000..d0727b16 --- /dev/null +++ b/src/app/dashboard/page.tsx @@ -0,0 +1,363 @@ +'use client' + +import Link from 'next/link' +import { Button } from "@/components/ui/button" +import { Card, CardHeader, CardTitle, CardContent, CardDescription } from "@/components/ui/card" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Badge } from "@/components/ui/badge" +import { Separator } from "@/components/ui/separator" +import { + User, + Calendar, + Mail, + Shield, + Settings, + FileText, + Activity, + Bell, + AlertTriangle, + CheckCircle +} from 'lucide-react' + +export default function DashboardPage() { + // Mock user data + const user = { + displayName: 'Max Mustermann', + email: 'user@example.com', + avatarUrl: null, + emailVerified: true, + createdAt: '2024-01-15T10:30:00Z', + lastLoginAt: '2024-02-05T14:22:00Z' + } + + // Mock stats + const stats = { + totalLogins: 42, + profileCompleteness: 85, + securityScore: 'High', + lastActivity: '2024-02-05T16:30:00Z' + } + + // Mock notifications + const notifications = [ + { + id: 1, + type: 'success', + title: 'Profil aktualisiert', + message: 'Dein Profil wurde erfolgreich aktualisiert', + timestamp: '2 Stunden ago' + }, + { + id: 2, + type: 'warning', + title: 'Sicherheitshinweis', + message: 'Neue Anmeldung von unerkanntem Gerät', + timestamp: '1 Tag ago' + }, + { + id: 3, + type: 'info', + title: 'Willkommen!', + message: 'Danke für die Registrierung bei unserer Plattform', + timestamp: '3 Wochen ago' + } + ] + + return ( +
+ {/* Welcome Header */} +
+
+

Willkommen zurück, {user.displayName}!

+

+ Hier ist eine Übersicht über dein Konto und deine Aktivitäten +

+
+
+ + {user.emailVerified ? "Verifiziert" : "Nicht verifiziert"} + + +
+
+ + {/* Stats Grid */} +
+ + +
+
+ +
+
+

{stats.totalLogins}

+

Gesamte Logins

+
+
+
+
+ + + +
+
+ +
+
+

{stats.profileCompleteness}%

+

Profil-Vollständigkeit

+
+
+
+
+ + + +
+
+ +
+
+

{stats.securityScore}

+

Sicherheits-Level

+
+
+
+
+ + + +
+
+ +
+
+

+ {new Date(stats.lastActivity).toLocaleDateString('de-DE', { + day: '2-digit', + month: 'short' + })} +

+

Letzte Aktivität

+
+
+
+
+
+ +
+ {/* Account Overview */} +
+ + + + + Konto-Übersicht + + + Wichtige Informationen über dein Konto + + + +
+
+ + + + {user.displayName.charAt(0).toUpperCase()} + + +
+

{user.displayName}

+

Profil-Name

+
+
+
+
+ +
+
+

{user.email}

+

Email-Adresse

+
+
+
+
+ +
+
+

Verifiziert

+

Email-Status

+
+
+
+
+ +
+
+

+ {new Date(user.createdAt).toLocaleDateString('de-DE')} +

+

Mitglied seit

+
+
+
+ + + +
+ + +
+
+
+ + {/* Quick Actions */} + + + Schnellaktionen + + Häufig genutzte Funktionen und Einstellungen + + + +
+ + + + + + + +
+
+
+
+ + {/* Notifications */} +
+ + + + + Benachrichtigungen + + + Aktuelle Updates und Warnungen + + + + {notifications.map((notification) => ( +
+
+ {notification.type === 'success' && ( + + )} + {notification.type === 'warning' && ( + + )} + {notification.type === 'info' && ( + + )} +
+
+

{notification.title}

+

{notification.message}

+

{notification.timestamp}

+
+
+ ))} + + +
+
+ + {/* Security Status */} + + + + + Sicherheits-Status + + + +
+
+ Email-Verifizierung + Aktiv +
+
+ Passwort-Stärke + Stark +
+
+ Zwei-Faktor-Auth + Nicht aktiv +
+
+ Aktive Sitzungen + 1 Gerät +
+
+ + +
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/src/app/dashboard/profile/page.tsx b/src/app/dashboard/profile/page.tsx new file mode 100644 index 00000000..f3009e85 --- /dev/null +++ b/src/app/dashboard/profile/page.tsx @@ -0,0 +1,566 @@ +'use client' + +import { useState, useEffect } from 'react' +import { useForm } from 'react-hook-form' +import { zodResolver } from '@hookform/resolvers/zod' +import * as z from 'zod' +import { Button } from "@/components/ui/button" +import { Card, CardHeader, CardTitle, CardContent, CardDescription } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" + +import { Alert, AlertDescription } from "@/components/ui/alert" +import { Badge } from "@/components/ui/badge" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" +import { + Loader2, + Mail, + Calendar, + Shield, + Camera, + Save, + Eye, + EyeOff, + Download, + Trash2, + Clock, + Monitor, + MapPin +} from 'lucide-react' + +const profileFormSchema = z.object({ + displayName: z.string().min(1, "Anzeigename ist erforderlich").max(50, "Maximal 50 Zeichen"), + email: z.string().email("Ungültige Email-Adresse") +}) + +const passwordFormSchema = z.object({ + currentPassword: z.string().min(1, "Aktuelles Passwort ist erforderlich"), + newPassword: z.string().min(8, "Mindestens 8 Zeichen"), + confirmPassword: z.string() +}).refine(data => data.newPassword === data.confirmPassword, { + message: "Passwörter stimmen nicht überein", + path: ["confirmPassword"] +}) + +type ProfileFormData = z.infer +type PasswordFormData = z.infer + +export default function ProfilePage() { + const [isLoading, setIsLoading] = useState(false) + const [isPasswordLoading, setIsPasswordLoading] = useState(false) + const [showCurrentPassword, setShowCurrentPassword] = useState(false) + const [showNewPassword, setShowNewPassword] = useState(false) + const [showConfirmPassword, setShowConfirmPassword] = useState(false) + const [error, setError] = useState(null) + const [success, setSuccess] = useState(null) + + // Mock user data + const [userData, setUserData] = useState<{ + id: string; + email: string; + displayName: string; + avatarUrl: string | null; + emailVerified: boolean; + createdAt: string; + lastLoginAt: string; + }>({ + id: '123', + email: 'user@example.com', + displayName: 'Max Mustermann', + avatarUrl: null, + emailVerified: true, + createdAt: '2024-01-15T10:30:00Z', + lastLoginAt: '2024-02-05T14:22:00Z' + }) + + const [loginHistory] = useState([ + { + id: 1, + timestamp: '2024-02-05T14:22:00Z', + device: 'Chrome 120 on macOS', + location: 'Berlin, Germany', + ip: '192.168.1.1' + }, + { + id: 2, + timestamp: '2024-02-04T09:15:00Z', + device: 'Safari 17 on iPhone', + location: 'Munich, Germany', + ip: '192.168.1.2' + }, + { + id: 3, + timestamp: '2024-02-03T16:45:00Z', + device: 'Firefox 121 on Windows', + location: 'Hamburg, Germany', + ip: '192.168.1.3' + } + ]) + + const { + register: registerProfile, + handleSubmit: handleProfileSubmit, + formState: { errors: profileErrors }, + reset: resetProfile + } = useForm({ + resolver: zodResolver(profileFormSchema), + defaultValues: { + displayName: userData.displayName, + email: userData.email + } + }) + + const { + register: registerPassword, + handleSubmit: handlePasswordSubmit, + formState: { errors: passwordErrors }, + reset: resetPassword, + watch: watchPassword + } = useForm({ + resolver: zodResolver(passwordFormSchema) + }) + + const newPassword = watchPassword('newPassword') + const confirmPassword = watchPassword('confirmPassword') + + useEffect(() => { + resetProfile({ + displayName: userData.displayName, + email: userData.email + }) + }, [userData, resetProfile]) + + const onProfileSubmit = async (data: ProfileFormData) => { + setIsLoading(true) + setError(null) + setSuccess(null) + + try { + // TODO: Implement actual profile update with Supabase + console.log('Profile update:', data) + + // Simulate API call + await new Promise(resolve => setTimeout(resolve, 2000)) + + setUserData(prev => ({ + ...prev, + displayName: data.displayName, + email: data.email + })) + + setSuccess('Profil wurde erfolgreich aktualisiert') + } catch (err) { + setError(err instanceof Error ? err.message : 'Profil-Update fehlgeschlagen') + } finally { + setIsLoading(false) + } + } + + const onPasswordSubmit = async (data: PasswordFormData) => { + setIsPasswordLoading(true) + setError(null) + setSuccess(null) + + try { + // TODO: Implement actual password change with Supabase + console.log('Password change:', { ...data, confirmPassword: undefined }) + + // Simulate API call + await new Promise(resolve => setTimeout(resolve, 2000)) + + resetPassword() + setSuccess('Passwort wurde erfolgreich geändert') + } catch (err) { + setError(err instanceof Error ? err.message : 'Passwort-Änderung fehlgeschlagen') + } finally { + setIsPasswordLoading(false) + } + } + + const handleAvatarUpload = async (event: React.ChangeEvent) => { + const file = event.target.files?.[0] + if (!file) return + + // Validate file + if (!file.type.startsWith('image/')) { + setError('Bitte lade ein Bild hoch (JPG, PNG)') + return + } + + if (file.size > 2 * 1024 * 1024) { // 2MB + setError('Bild darf maximal 2MB groß sein') + return + } + + setIsLoading(true) + try { + // TODO: Implement actual avatar upload with Supabase Storage + console.log('Avatar upload:', file) + + // Simulate upload + await new Promise(resolve => setTimeout(resolve, 2000)) + + // Mock successful upload + setUserData(prev => ({ + ...prev, + avatarUrl: `https://api.dicebear.com/7.x/avataaars/svg?seed=${Date.now()}` + })) + + setSuccess('Avatar wurde erfolgreich hochgeladen') + } catch (err) { + setError(err instanceof Error ? err.message : 'Avatar-Upload fehlgeschlagen') + } finally { + setIsLoading(false) + } + } + + const handleDataExport = async () => { + try { + // TODO: Implement actual data export + console.log('Data export requested') + + // Simulate export preparation + await new Promise(resolve => setTimeout(resolve, 1000)) + + // Mock download + const dataStr = JSON.stringify(userData, null, 2) + const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr) + + const exportFileDefaultName = `user-data-${new Date().toISOString().split('T')[0]}.json` + + const linkElement = document.createElement('a') + linkElement.setAttribute('href', dataUri) + linkElement.setAttribute('download', exportFileDefaultName) + linkElement.click() + + setSuccess('Daten wurden erfolgreich exportiert') + } catch (err) { + setError(err instanceof Error ? err.message : 'Daten-Export fehlgeschlagen') + } + } + + const handleAccountDeletion = () => { + // TODO: Implement account deletion flow + console.log('Account deletion requested') + alert('Konto-Löschung: Dies würde einen Bestätigungsdialog mit 30-tägiger Grace Period öffnen.') + } + + return ( +
+
+
+

Profil

+ + {userData.emailVerified ? "Verifiziert" : "Nicht verifiziert"} + +
+ + {error && ( + + {error} + + )} + + {success && ( + + {success} + + )} + +
+ {/* Profile Overview Card */} +
+ + +
+ + + + {userData.displayName.charAt(0).toUpperCase()} + + + +
+ {userData.displayName} + {userData.email} +
+ +
+ + Email +
+
+ + + Mitglied seit {new Date(userData.createdAt).toLocaleDateString('de-DE')} + +
+
+ + + {userData.emailVerified ? 'Email verifiziert' : 'Email nicht verifiziert'} + +
+
+
+
+ + {/* Main Content */} +
+ + + Profil + Sicherheit + Aktivität + + + {/* Profile Tab */} + + + + Profil bearbeiten + + Aktualisiere deine persönlichen Informationen + + + +
+
+ + + {profileErrors.displayName && ( +

{profileErrors.displayName.message}

+ )} +
+ +
+ + + {profileErrors.email && ( +

{profileErrors.email.message}

+ )} +

+ Email-Änderung erfordert eine Verifikation +

+
+ + +
+
+
+
+ + {/* Security Tab */} + + + + Passwort ändern + + Wähle ein sicheres neues Passwort für dein Konto + + + +
+
+ +
+ + +
+ {passwordErrors.currentPassword && ( +

{passwordErrors.currentPassword.message}

+ )} +
+ +
+ +
+ + +
+ {passwordErrors.newPassword && ( +

{passwordErrors.newPassword.message}

+ )} +
+ +
+ +
+ + +
+ {passwordErrors.confirmPassword && ( +

{passwordErrors.confirmPassword.message}

+ )} + {confirmPassword && newPassword === confirmPassword && ( +

Passwörter stimmen überein

+ )} +
+ + +
+
+
+ + {/* Account Management */} + + + Konto-Verwaltung + + Verwalte deine Daten und Privatsphäre + + + +
+ + +
+

+ Daten-Export erstellt eine JSON-Datei mit all deinen Informationen. + Konto-Löschung startet einen 30-tägigen Grace Period. +

+
+
+
+ + {/* Activity Tab */} + + + + Login-Geschichte + + Die letzten 10 Anmeldungen an deinem Konto + + + +
+ {loginHistory.map((login, index) => ( +
+
+
+ + {login.device} +
+
+
+ + {login.location} +
+
+ + {new Date(login.timestamp).toLocaleDateString('de-DE', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit' + })} +
+
+
+ {index === 0 && ( + Aktuell + )} +
+ ))} +
+
+
+
+
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/src/components/admin/admin-assistant.tsx b/src/components/admin/admin-assistant.tsx new file mode 100644 index 00000000..eca8b040 --- /dev/null +++ b/src/components/admin/admin-assistant.tsx @@ -0,0 +1,188 @@ +'use client' + +import * as React from 'react' +import { useState, useRef, useEffect } from 'react' +import { Send, Bot, Loader2, User, Sparkles } from 'lucide-react' +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { ScrollArea } from "@/components/ui/scroll-area" + +interface Message { + role: 'user' | 'model' + text: string +} + +interface AdminAssistantProps { + user?: { + email?: string + name?: string + } +} + +export const AdminAssistant: React.FC = ({ user }) => { + const [messages, setMessages] = useState([]) + const [input, setInput] = useState('') + const [isThinking, setIsThinking] = useState(false) + const messagesEndRef = useRef(null) + const chatSession = useRef(null) + + useEffect(() => { + const greeting = `Hello ${user?.name || user?.email || 'Admin'}. I am your AI Admin Assistant. How can I assist you with management tasks today?` + + setMessages([{ role: 'model', text: greeting }]) + }, [user]) + + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }) + }, [messages]) + + useEffect(() => { + const initChat = async () => { + try { + // Mock initialization - in production, this would connect to Gemini API + const apiKey = process.env.NEXT_PUBLIC_GOOGLE_API_KEY; + if (!apiKey) { + console.warn("API Key missing - using mock mode"); + return; + } + // Initialize chat session here + } catch (error) { + console.error("AI Init failed", error); + } + }; + initChat(); + }, [user]); + + const handleSend = async (e?: React.FormEvent) => { + e?.preventDefault(); + if (!input.trim()) return; + + const userMsg = input.trim(); + setInput(''); + setMessages(prev => [...prev, { role: 'user', text: userMsg }]); + setIsThinking(true); + + try { + // Simulate AI response - in production, this would call Gemini API + setTimeout(() => { + const mockResponse = generateMockResponse(userMsg); + setMessages(prev => [...prev, { role: 'model', text: mockResponse }]); + setIsThinking(false); + }, 1000 + Math.random() * 2000); + } catch { + setMessages(prev => [...prev, { role: 'model', text: 'System Error. Agent disconnected.' }]); + setIsThinking(false); + } + }; + + const generateMockResponse = (userInput: string): string => { + const input = userInput.toLowerCase(); + + if (input.includes('help') || input.includes('assist')) { + return `I can help you with:\n\n🔧 System administration tasks\n📊 Performance monitoring\n🔍 Security audits\n🚀 Deployment management\n📝 Documentation generation\n\nTry commands like: "/status", "/audit", "/deploy"`; + } + + if (input.includes('status')) { + return `🟢 System Status Report:\n\n• Database: Operational\n• API Services: Running\n• Cache: Healthy\n• Active Users: 1\n• Uptime: 99.9%\n\nAll systems are performing optimally.`; + } + + if (input.includes('audit') || input.includes('security')) { + return `🔒 Security Audit Summary:\n\n✅ Authentication: Secure\n✅ Data Encryption: Active\n✅ API Rate Limiting: Configured\n⚠️ SSL Certificate: Expires in 30 days\n✅ Backup Systems: Operational\n\nRecommendation: Update SSL certificate soon.`; + } + + if (input.includes('deploy')) { + return `🚀 Deployment Options:\n\n• Staging: Ready for testing\n• Production: Requires approval\n• Rollback: Available from last 5 deployments\n\nCurrent branch: main\nLast deployment: 2 days ago\nDeployment status: Success`; + } + + return `I understand you want to "${userInput}". Let me help you with that. This is a mock response - in production, I would use Gemini AI to provide intelligent assistance for your administrative tasks.`; + }; + + return ( +
+ {/* Header */} +
+
+
+ +
+
+

AI COMMAND CENTER

+

GEMINI PRO 2.0 // ACTIVE

+
+
+
+
+ ONLINE +
+
+ + {/* Messages */} + +
+ {messages.map((msg, idx) => ( +
+ {msg.role === 'model' && ( +
+ +
+ )} +
+ {msg.text.split('\n').map((line, i) => ( +
{line}
+ ))} +
+ {msg.role === 'user' && ( +
+ +
+ )} +
+ ))} + {isThinking && ( +
+
+ +
+
+ + Processing Request... +
+
+ )} +
+
+ + + {/* Input */} +
+
+ setInput(e.target.value)} + placeholder="Command AI..." + className="pr-12" + disabled={isThinking} + /> + +
+
+ Try: /status, /audit, /deploy, or ask for help +
+
+
+ ) +} \ No newline at end of file diff --git a/src/components/admin/admin-dashboard.tsx b/src/components/admin/admin-dashboard.tsx new file mode 100644 index 00000000..83869a0d --- /dev/null +++ b/src/components/admin/admin-dashboard.tsx @@ -0,0 +1,124 @@ +'use client' + +import React from 'react' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Button } from "@/components/ui/button" +import { Badge } from "@/components/ui/badge" +import { Separator } from "@/components/ui/separator" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" +import { Bot, Activity, Users, Database, Zap, ExternalLink, Search, Send, Loader2, User, Sparkles } from 'lucide-react' +import { AdminAssistant } from './admin-assistant' +import { ScrapingRegistry } from './scraping-registry' + +interface AdminDashboardProps { + user?: { + email?: string + name?: string + } +} + +export const AdminDashboard: React.FC = ({ user }) => { + return ( +
+
+ {/* Header */} +
+
+

Admin Dashboard

+

Welcome back, {user?.name || user?.email || 'Admin'}

+
+ +
+ + {/* Stats Overview */} +
+ + + Active Users + + + +
1
+

Current online users

+
+
+ + + + System Status + + + +
+
+ Operational +
+

All systems running

+
+
+ + + + API Calls + + + +
0
+

Last 24 hours

+
+
+
+ + {/* Main Content */} + + + + + AI Assistant + + + + Scraping Registry + + + + + + + + + AI Command Center + + + Powered by Gemini Pro 2.0 - Your administrative co-pilot + + + + + + + + + + + + + + Scraping Resource Registry + + + Browse and manage web scraping resources and integrations + + + + + + + + +
+
+ ) +} \ No newline at end of file diff --git a/src/components/admin/scraping-registry.tsx b/src/components/admin/scraping-registry.tsx new file mode 100644 index 00000000..a637c406 --- /dev/null +++ b/src/components/admin/scraping-registry.tsx @@ -0,0 +1,212 @@ +'use client' + +import React, { useState, useMemo } from 'react' +import { Search, ExternalLink, Database, Zap, Filter, Globe } from 'lucide-react' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Badge } from "@/components/ui/badge" +import { ScrollArea } from "@/components/ui/scroll-area" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" + +interface ApiEntry { + name: string + url: string + description: string +} + +interface Category { + id: string + name: string + count: number + apis: ApiEntry[] +} + +// Mock data - in production, this would come from a real API +const mockCatalog: Record = { + social_media: { + id: "social_media", + name: "Social Media", + count: 3, + apis: [ + { + name: "Twitter API", + url: "https://api.twitter.com", + description: "Access tweets, user profiles, and trending topics from Twitter's platform." + }, + { + name: "LinkedIn API", + url: "https://api.linkedin.com", + description: "Professional networking data including profiles, jobs, and company information." + }, + { + name: "Instagram Basic Display", + url: "https://api.instagram.com", + description: "User media, profile information, and basic Instagram data access." + } + ] + }, + ecommerce: { + id: "ecommerce", + name: "E-Commerce", + count: 2, + apis: [ + { + name: "Amazon Product API", + url: "https://webservices.amazon.com", + description: "Product information, pricing, and availability data from Amazon marketplace." + }, + { + name: "Shopify Storefront API", + url: "https://shopify.dev/docs/storefront-api", + description: "Access product catalogs, collections, and checkout data from Shopify stores." + } + ] + }, + news: { + id: "news", + name: "News & Content", + count: 3, + apis: [ + { + name: "NewsAPI.org", + url: "https://newsapi.org", + description: "Real-time news articles from thousands of sources worldwide." + }, + { + name: "Reddit API", + url: "https://reddit.com/dev/api", + description: "Posts, comments, and community data from Reddit's platform." + }, + { + name: "Medium API", + url: "https://github.com/Medium/medium-api-docs", + description: "Articles, publications, and author information from Medium." + } + ] + } +} + +export const ScrapingRegistry: React.FC = () => { + const [selectedCategory, setSelectedCategory] = useState('social_media') + const [searchQuery, setSearchQuery] = useState('') + + const categories = useMemo(() => Object.values(mockCatalog), []) + const currentCategory = mockCatalog[selectedCategory] + + const filteredApis = useMemo(() => { + const apis = currentCategory?.apis || [] + if (!searchQuery) return apis + return apis.filter(api => + api.name.toLowerCase().includes(searchQuery.toLowerCase()) || + api.description.toLowerCase().includes(searchQuery.toLowerCase()) + ) + }, [selectedCategory, searchQuery, currentCategory]) + + return ( +
+ {/* Header/Search */} +
+
+ + setSearchQuery(e.target.value)} + /> +
+
+
+ + Registry Status: SYNCHRONIZED +
+ +
+
+ +
+ {/* Sidebar Categories */} +
+
+ {categories.map((cat) => ( + + ))} +
+
+ + {/* Main Content */} + +
+ {filteredApis.length === 0 ? ( +
+ +

No scrapers match your query

+

Try adjusting your search terms

+
+ ) : ( + filteredApis.map((api, idx) => ( + + +
+
+ {api.name} + + {api.description} + +
+ +
+
+ +
+ + +
+
+
+ )) + )} +
+
+
+ + {/* Footer info */} +
+
+
+ LOADED: {currentCategory?.name} // TOTAL_ENTRIES: {currentCategory?.count || 0} +
+
+
+ UPLINK_ACTIVE +
+
+
+
+ ) +} \ No newline at end of file diff --git a/src/contexts/auth-context.tsx b/src/contexts/auth-context.tsx new file mode 100644 index 00000000..84769266 --- /dev/null +++ b/src/contexts/auth-context.tsx @@ -0,0 +1,210 @@ +'use client' + +import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react' + +interface User { + id: string + email: string + name: string + role: 'user' | 'admin' + avatar?: string + emailVerified?: boolean + createdAt: string + lastLoginAt: string +} + +interface AuthContextType { + user: User | null + isLoading: boolean + login: (email: string, password: string) => Promise + loginWithOAuth: (provider: 'google' | 'github') => Promise + logout: () => Promise + refreshUser: () => Promise +} + +const AuthContext = createContext(undefined) + +interface AuthProviderProps { + children: ReactNode +} + +export function AuthProvider({ children }: AuthProviderProps) { + const [user, setUser] = useState(null) + const [isLoading, setIsLoading] = useState(true) + + // Mock user database with admin account + const mockUsers: User[] = [ + { + id: '1', + email: 'admin@example.com', + name: 'Administrator', + role: 'admin', + avatar: null, + emailVerified: true, + createdAt: '2024-01-15T10:30:00Z', + lastLoginAt: new Date().toISOString() + }, + { + id: '2', + email: 'user@example.com', + name: 'Max Mustermann', + role: 'user', + avatar: null, + emailVerified: true, + createdAt: '2024-01-15T10:30:00Z', + lastLoginAt: new Date().toISOString() + } + ] + + // Check for existing session on mount + useEffect(() => { + const checkSession = async () => { + try { + const savedUser = localStorage.getItem('user_session') + if (savedUser) { + const userData = JSON.parse(savedUser) + // Update last login time + userData.lastLoginAt = new Date().toISOString() + setUser(userData) + localStorage.setItem('user_session', JSON.stringify(userData)) + } + } catch (error) { + console.error('Session check failed:', error) + localStorage.removeItem('user_session') + } finally { + setIsLoading(false) + } + } + + checkSession() + }, []) + + const login = async (email: string, password: string) => { + setIsLoading(true) + + try { + // Simulate API call + await new Promise(resolve => setTimeout(resolve, 1000)) + + // Find user in mock database + const foundUser = mockUsers.find(u => u.email === email) + + if (!foundUser) { + throw new Error('Ungültige Email-Adresse oder Passwort') + } + + // Simple password check (in production, use proper hashing) + const validPasswords = { + 'admin@example.com': 'admin123', + 'user@example.com': 'user123' + } + + if (validPasswords[email] !== password) { + throw new Error('Ungültige Email-Adresse oder Passwort') + } + + // Update user with current login time + const loggedInUser = { + ...foundUser, + lastLoginAt: new Date().toISOString() + } + + setUser(loggedInUser) + localStorage.setItem('user_session', JSON.stringify(loggedInUser)) + + // Redirect to dashboard + window.location.href = '/dashboard' + + } catch (error) { + throw error + } finally { + setIsLoading(false) + } + } + + const loginWithOAuth = async (provider: 'google' | 'github') => { + setIsLoading(true) + + try { + // Simulate OAuth flow + await new Promise(resolve => setTimeout(resolve, 1500)) + + // Mock OAuth login - defaults to admin user for Google, user for GitHub + const mockOAuthUser = provider === 'google' + ? mockUsers[0] // Admin + : mockUsers[1] // Regular user + + const loggedInUser = { + ...mockOAuthUser, + lastLoginAt: new Date().toISOString() + } + + setUser(loggedInUser) + localStorage.setItem('user_session', JSON.stringify(loggedInUser)) + + // Redirect to dashboard + window.location.href = '/dashboard' + + } catch (error) { + throw error + } finally { + setIsLoading(false) + } + } + + const logout = async () => { + setIsLoading(true) + + try { + // Simulate logout API call + await new Promise(resolve => setTimeout(resolve, 500)) + + setUser(null) + localStorage.removeItem('user_session') + localStorage.setItem('session_expired', 'true') + + // Redirect to login + window.location.href = '/login' + + } catch (error) { + console.error('Logout error:', error) + } finally { + setIsLoading(false) + } + } + + const refreshUser = async () => { + try { + const savedUser = localStorage.getItem('user_session') + if (savedUser) { + const userData = JSON.parse(savedUser) + setUser(userData) + } + } catch (error) { + console.error('User refresh failed:', error) + } + } + + const value: AuthContextType = { + user, + isLoading, + login, + loginWithOAuth, + logout, + refreshUser + } + + return ( + + {children} + + ) +} + +export function useAuth() { + const context = useContext(AuthContext) + if (context === undefined) { + throw new Error('useAuth must be used within an AuthProvider') + } + return context +} \ No newline at end of file