+
Mitarbeiter
+ {error &&
{error}
}
+
+
-
-
setNewName(e.target.value)} style={{ flex: 2, minWidth: 120, fontSize: 16, padding: 10, borderRadius: 8, border: '1.5px solid #dbeafe' }} />
-
setNewEmail(e.target.value)} style={{ flex: 2, minWidth: 120, fontSize: 16, padding: 10, borderRadius: 8, border: '1.5px solid #dbeafe' }} />
-
setNewPassword(e.target.value)} style={{ flex: 2, minWidth: 120, fontSize: 16, padding: 10, borderRadius: 8, border: '1.5px solid #dbeafe' }} />
-
-
+
+
+ {loading ?
Lade…
: (
+
+
+
+ | Name |
+ E-Mail |
+ Rolle |
+ Aktiv |
+ |
+
+
+
+ {list.map(m => (
+
+ | {m.name} {m.id === user.id && Ich} |
+ {m.email} |
+
+
+ |
+
+
+ |
+
+ {m.id !== user.id && (
+
+ )}
+ |
+
+ ))}
+
+
+ )}
-
- Rolle "admin" sieht das Admin-Dashboard.
- Hinweis: Neue Mitarbeiter benötigen E-Mail und Passwort für den Login.
-
-
);
}
diff --git a/src/components/SuperAdmin.jsx b/src/components/SuperAdmin.jsx
new file mode 100644
index 0000000..8db6e9d
--- /dev/null
+++ b/src/components/SuperAdmin.jsx
@@ -0,0 +1,190 @@
+import { useEffect, useState } from 'react';
+import { FaPlus, FaSignOutAlt, FaTrash, FaClock, FaUsers, FaUser } from 'react-icons/fa';
+import { api } from '../api/client';
+
+export default function SuperAdmin({ user, onLogout }) {
+ const [tenants, setTenants] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [showNew, setShowNew] = useState(false);
+ const [createdInfo, setCreatedInfo] = useState(null);
+
+ const load = async () => {
+ setLoading(true);
+ try { setTenants(await api.getTenants()); } finally { setLoading(false); }
+ };
+ useEffect(() => { load(); }, []);
+
+ const extend = async (id, days) => {
+ await api.updateTenant(id, { extend_days: days });
+ load();
+ };
+ const setStatus = async (id, status) => { await api.updateTenant(id, { status }); load(); };
+ const del = async (id) => { if (!confirm('Tenant inkl. aller Daten loeschen?')) return; await api.deleteTenant(id); load(); };
+
+ return (
+
+
+
+
+
P
+
Pfandsystem · SuperAdmin
+
+
{user.email}
+
+
+
+
+
+
+
+
Tenants
+
{tenants.length} Tenants · {tenants.filter(t => t.typ === 'demo').length} Demos
+
+
+
+
+ {loading ? Lade…
: (
+
+
+
+
+ | Name |
+ Slug |
+ Typ |
+ Status |
+ User / Kunden |
+ Ablauf |
+ |
+
+
+
+ {tenants.map(t => {
+ const expired = t.demo_expires_at && new Date(t.demo_expires_at) < new Date();
+ return (
+
+ |
+ {t.name}
+ {t.kontakt_email}
+ |
+ {t.slug} |
+
+ {t.typ}
+ |
+
+
+ |
+
+ {t.user_count}
+ {t.kunden_count}
+ |
+
+ {t.demo_expires_at ? (
+
+
+ {new Date(t.demo_expires_at).toLocaleDateString('de-DE')}
+
+ ) : —}
+ |
+
+ {t.typ === 'demo' && (
+
+ )}
+
+ |
+
+ );
+ })}
+ {tenants.length === 0 && (
+ | Noch keine Tenants. |
+ )}
+
+
+
+ )}
+
+
+ {showNew &&
setShowNew(false)} onCreated={(info) => { setCreatedInfo(info); setShowNew(false); load(); }} />}
+ {createdInfo && setCreatedInfo(null)} />}
+
+ );
+}
+
+function NewTenantModal({ onClose, onCreated }) {
+ const [form, setForm] = useState({ name: '', kontakt_email: '', firma: '', days: 30, seed: true });
+ const [busy, setBusy] = useState(false);
+ const [error, setError] = useState('');
+
+ const submit = async (e) => {
+ e.preventDefault();
+ setBusy(true); setError('');
+ try { onCreated(await api.createTenant(form)); }
+ catch (e) { setError(e.message); } finally { setBusy(false); }
+ };
+
+ return (
+
+ );
+}
+
+function CreatedInfoModal({ info, onClose }) {
+ return (
+
+
e.stopPropagation()} className="bg-white rounded-xl max-w-md w-full p-6 shadow-soft space-y-3">
+
Demo-Account angelegt
+
Der Interessent erhaelt eine Einladungs-Mail. Hier zur Sicherheit die Daten:
+
+ - Slug:
- {info.slug}
+ - E-Mail:
- {info.admin_email}
+ - Passwort:
- {info.admin_password_oneshot}
+ - Gueltig:
- {info.demo_expires_in_days} Tage
+
+
Das Passwort wird nur einmal angezeigt.
+
+
+
+ );
+}
+
+function Field({ label, children }) {
+ return
{children}
;
+}
diff --git a/src/components/TourPlanung.jsx b/src/components/TourPlanung.jsx
new file mode 100644
index 0000000..c585d71
--- /dev/null
+++ b/src/components/TourPlanung.jsx
@@ -0,0 +1,102 @@
+import { useEffect, useState } from 'react';
+import { FaMapMarkedAlt, FaCheckCircle, FaClock, FaInfoCircle } from 'react-icons/fa';
+import { api } from '../api/client';
+
+const API_BASE = import.meta.env.VITE_API_URL || '/api';
+
+export default function TourPlanung() {
+ const [kunden, setKunden] = useState([]);
+ const [done, setDone] = useState(() => {
+ try { return new Set(JSON.parse(localStorage.getItem('tour_done') || '[]')); } catch { return new Set(); }
+ });
+ const [loading, setLoading] = useState(true);
+ const [showInfo, setShowInfo] = useState(null);
+
+ useEffect(() => {
+ api.getKunden().then(d => setKunden(d || [])).finally(() => setLoading(false));
+ }, []);
+
+ const toggle = (id) => {
+ const next = new Set(done);
+ if (next.has(id)) next.delete(id); else next.add(id);
+ setDone(next);
+ localStorage.setItem('tour_done', JSON.stringify([...next]));
+ };
+
+ const sorted = [...kunden].sort((a, b) => {
+ if (a.lieferzeit_bis && b.lieferzeit_bis) return a.lieferzeit_bis.localeCompare(b.lieferzeit_bis);
+ if (a.lieferzeit_bis) return -1;
+ if (b.lieferzeit_bis) return 1;
+ return a.name.localeCompare(b.name);
+ });
+
+ const openMaps = (adresse) => {
+ window.open(`https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(adresse)}`, '_blank');
+ };
+
+ const resetTour = () => { setDone(new Set()); localStorage.removeItem('tour_done'); };
+
+ return (
+
+
+
+
Meine Tour
+
{done.size} / {sorted.length} erledigt
+
+ {done.size > 0 && (
+
+ )}
+
+
+ {loading ?
Lade…
: (
+
+ {sorted.map((k, idx) => {
+ const erledigt = done.has(k.id);
+ return (
+ -
+
+
+
{k.name}
+
{k.adresse || '— keine Adresse —'}
+
+ {k.lieferzeit_bis && (
+ bis {k.lieferzeit_bis}
+ )}
+ {k.anlieferungshinweis && (
+
+ )}
+
+
+
+
+ );
+ })}
+ {sorted.length === 0 && - Keine Kunden in der Tour.
}
+
+ )}
+
+ {showInfo && (
+
setShowInfo(null)} className="fixed inset-0 z-50 bg-slate-900/60 flex items-center justify-center p-4">
+
e.stopPropagation()} className="bg-white rounded-xl max-w-md w-full p-6 shadow-soft">
+
+
{showInfo.name}
+
+
+
+ {showInfo.anlieferungshinweis}
+
+
+
+ )}
+
+ );
+}
diff --git a/src/fonts.css b/src/fonts.css
deleted file mode 100644
index 19d1777..0000000
--- a/src/fonts.css
+++ /dev/null
@@ -1,14 +0,0 @@
-@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;700&family=Work+Sans:wght@400;700&display=swap');
-
-body, input, button, select, textarea {
- font-family: 'DM Sans', 'Work Sans', Arial, Helvetica, sans-serif;
- letter-spacing: 0.01em;
- font-smooth: always;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-h1, h2, h3, h4, h5, h6 {
- font-family: 'DM Sans', 'Work Sans', Arial, Helvetica, sans-serif;
- font-weight: 700;
-}
diff --git a/src/index.css b/src/index.css
new file mode 100644
index 0000000..f3ad32f
--- /dev/null
+++ b/src/index.css
@@ -0,0 +1,43 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ html { font-family: 'Inter', system-ui, sans-serif; }
+ body { @apply text-slate-800; }
+}
+
+@layer components {
+ .btn {
+ @apply inline-flex items-center justify-center gap-2 rounded-lg px-4 py-2.5
+ text-sm font-semibold shadow-sm transition
+ focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2
+ focus-visible:ring-brand-500 disabled:opacity-50 disabled:cursor-not-allowed;
+ }
+ .btn-primary { @apply btn bg-brand-600 text-white hover:bg-brand-700; }
+ .btn-secondary { @apply btn bg-white text-slate-700 ring-1 ring-slate-300 hover:bg-slate-50; }
+ .btn-danger { @apply btn bg-rose-600 text-white hover:bg-rose-700; }
+ .btn-ghost { @apply btn bg-transparent text-slate-600 hover:bg-slate-100 shadow-none; }
+
+ .input {
+ @apply block w-full rounded-lg border-0 bg-white px-3.5 py-2.5
+ text-slate-900 shadow-sm ring-1 ring-inset ring-slate-300
+ placeholder:text-slate-400 focus:ring-2 focus:ring-inset focus:ring-brand-600
+ sm:text-sm sm:leading-6 disabled:bg-slate-50 disabled:text-slate-500;
+ }
+ .label { @apply block text-sm font-medium text-slate-700 mb-1.5; }
+
+ .card {
+ @apply bg-white rounded-xl shadow-card ring-1 ring-slate-200/60 p-5 sm:p-6;
+ }
+ .card-title { @apply text-lg font-semibold text-slate-900 mb-4; }
+
+ .badge {
+ @apply inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium ring-1 ring-inset;
+ }
+ .badge-green { @apply badge bg-emerald-50 text-emerald-700 ring-emerald-200; }
+ .badge-amber { @apply badge bg-amber-50 text-amber-800 ring-amber-200; }
+ .badge-rose { @apply badge bg-rose-50 text-rose-700 ring-rose-200; }
+ .badge-slate { @apply badge bg-slate-100 text-slate-700 ring-slate-200; }
+ .badge-brand { @apply badge bg-brand-50 text-brand-700 ring-brand-200; }
+}
diff --git a/src/main.jsx b/src/main.jsx
index 7c15040..6fd23c4 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -1,4 +1,4 @@
-import './fonts.css';
+import './index.css';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
diff --git a/src/supabase/client.js b/src/supabase/client.js
deleted file mode 100644
index 733b874..0000000
--- a/src/supabase/client.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import { createClient } from '@supabase/supabase-js';
-
-const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
-const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
-
-export const supabase = createClient(supabaseUrl, supabaseAnonKey);
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..0b59e40
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,30 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ["./index.html", "./src/**/*.{js,jsx}"],
+ theme: {
+ extend: {
+ fontFamily: {
+ sans: ['Inter', 'system-ui', 'Segoe UI', 'Helvetica', 'Arial', 'sans-serif'],
+ },
+ colors: {
+ brand: {
+ 50: '#eef2ff',
+ 100: '#e0e7ff',
+ 200: '#c7d2fe',
+ 300: '#a5b4fc',
+ 400: '#818cf8',
+ 500: '#6366f1',
+ 600: '#4f46e5',
+ 700: '#4338ca',
+ 800: '#3730a3',
+ 900: '#312e81',
+ }
+ },
+ boxShadow: {
+ card: '0 1px 3px 0 rgb(15 23 42 / 0.06), 0 1px 2px -1px rgb(15 23 42 / 0.04)',
+ soft: '0 4px 16px -2px rgb(15 23 42 / 0.08)',
+ }
+ },
+ },
+ plugins: [],
+}
diff --git a/test-login.sh b/test-login.sh
deleted file mode 100755
index 0b04a23..0000000
--- a/test-login.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-cd /root/backend
-echo "Starte Backend..."
-node server.js > /tmp/backend.log 2>&1 &
-BACKEND_PID=$!
-echo "Backend PID: $BACKEND_PID"
-sleep 3
-
-echo ""
-echo "Teste Login..."
-curl -X POST http://localhost:3001/api/auth/login \
- -H "Content-Type: application/json" \
- -d '{"email":"admin@pfandsystem.de","password":"admin123"}'
-
-echo ""
-echo ""
-echo "Backend Logs:"
-cat /tmp/backend.log
-
-kill $BACKEND_PID 2>/dev/null
diff --git a/test-system.sh b/test-system.sh
deleted file mode 100755
index 8054b3c..0000000
--- a/test-system.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/bash
-# System-Test-Script
-
-echo "🧪 Pfandsystem Test-Suite"
-echo "=========================="
-echo ""
-
-# 1. Container-Status
-echo "1️⃣ Container-Status:"
-docker-compose ps
-echo ""
-
-# 2. Backend Health Check
-echo "2️⃣ Backend Health Check:"
-curl -s http://localhost:3001/health || echo "❌ Backend nicht erreichbar"
-echo ""
-echo ""
-
-# 3. MySQL-Verbindung
-echo "3️⃣ MySQL-Verbindung:"
-docker exec pfandsystem-mysql mysql -u pfandsystem -ppfandsystem_secure_password -e "SELECT 'MySQL OK' as status;" 2>/dev/null || echo "❌ MySQL nicht erreichbar"
-echo ""
-
-# 4. Backend-Logs (letzte 10 Zeilen)
-echo "4️⃣ Backend-Logs (letzte 10 Zeilen):"
-docker-compose logs --tail=10 backend
-echo ""
-
-# 5. Frontend erreichbar
-echo "5️⃣ Frontend Check:"
-curl -s -o /dev/null -w "HTTP Status: %{http_code}\n" http://localhost:80
-echo ""
-
-# 6. API-Endpunkte testen
-echo "6️⃣ API-Endpunkte:"
-echo " /api/auth/login:"
-curl -s -o /dev/null -w " HTTP Status: %{http_code}\n" -X POST http://localhost:3001/api/auth/login \
- -H "Content-Type: application/json" \
- -d '{"email":"test","password":"test"}'
-echo ""
-
-echo "✅ Test abgeschlossen"
diff --git a/traefik/dynamic/local-backend.yml b/traefik/dynamic/local-backend.yml
deleted file mode 100644
index 09971be..0000000
--- a/traefik/dynamic/local-backend.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-http:
- routers:
- # Backend API Router (zeigt auf lokales Backend)
- pfandsystem-api-local:
- rule: "Host(`pfandsystem.backdigital.de`) && PathPrefix(`/api`)"
- service: pfandsystem-api-local
- entryPoints:
- - web
- - websecure
- tls:
- certResolver: letsencrypt
- priority: 100
-
- # Backend Uploads Router
- pfandsystem-uploads-local:
- rule: "Host(`pfandsystem.backdigital.de`) && PathPrefix(`/uploads`)"
- service: pfandsystem-api-local
- entryPoints:
- - web
- - websecure
- tls:
- certResolver: letsencrypt
- priority: 100
-
- services:
- # Backend Service (zeigt auf Docker-Host via Bridge)
- pfandsystem-api-local:
- loadBalancer:
- servers:
- - url: "http://172.17.0.1:3001"
diff --git a/traefik/letsencrypt/acme.json b/traefik/letsencrypt/acme.json
deleted file mode 100644
index a316172..0000000
--- a/traefik/letsencrypt/acme.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "letsencrypt": {
- "Account": {
- "Email": "vonperfall@r83.io",
- "Registration": {
- "body": {
- "status": "valid"
- },
- "uri": "https://acme-v02.api.letsencrypt.org/acme/acct/2709684531"
- },
- "PrivateKey": "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",
- "KeyType": "4096"
- },
- "Certificates": [
- {
- "domain": {
- "main": "pfandsystem.backdigital.de"
- },
- "certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdEekNDQlBlZ0F3SUJBZ0lTQmFnUTdubFlvOGtKekE4aU1iSTNzYzZ6TUEwR0NTcUdTSWIzRFFFQkN3VUEKTURNeEN6QUpCZ05WQkFZVEFsVlRNUll3RkFZRFZRUUtFdzFNWlhRbmN5QkZibU55ZVhCME1Rd3dDZ1lEVlFRRApFd05TTVRNd0hoY05NalV4TURBM01URXpPVEUyV2hjTk1qWXdNVEExTVRFek9URTFXakFsTVNNd0lRWURWUVFECkV4cHdabUZ1WkhONWMzUmxiUzVpWVdOclpHbG5hWFJoYkM1a1pUQ0NBaUl3RFFZSktvWklodmNOQVFFQkJRQUQKZ2dJUEFEQ0NBZ29DZ2dJQkFNNkpVR2ZBWWM3L2hvWUhWb0Q1ZGo1TGsrTmVnNDhQeXQyNlF5citUUkYxdkdyOQpZOEJZY0xlQVRLdlQyZmRrYjM4eGJabUl0cXNoUHRQTktJY1gwazU3VFZrMzkxeG9yalNPSkxneXBhUVVnL2FDCit2ejRrNnV0eGJXanIyRmdpNFdYYXV3a0JDM3g5dndiNXdzbWwyK0VDaUNyanFqbGF0R0xCamFqcnZlOU5YcjkKc28yZjNYaUY1Vm9zWUF2VktQa09CQ1BCLy9KUjcxS292WnBYQ21YQWlicGkraWtleXNzRGd5VnVManF0aGV6NgpRTEdDZUI2eFZQbWlDdGljaGZ4azIyZWExVkZOK0RkcS9KSDlSNE9SWmNVd0FnQVJnZU1mbFNZNURVUnJIRzQ5Ci8xR3dpaE8rakZBWVFkbFR1OURBdUhVd3NqOU9PK3pIOHAzWFMyUUt2YkhocUltZHFBcExQNW9RKzJEMFhTUHYKNTdRZktNUldxVFk3RXZPREl5bzZQVFh6WGhDZWRycS91QVY0KzltWTNvdGtZOHRETnI0MHJpbTh1WnNrM0QrNgpkVHo5RmFCWDUwaGs5OVQ2ZG1PbExBc3hISmJXZTN0cHVsTEpiR1dPVUpOOWZWTE52UjNjQVFDVi9oUVcyd1hwCitBdVNPd1gycU96SGFlNjFPdFZEQ0lnM1ZuZjFvWUNSODByaWdLRVFEU2U2VHZ6ejk4ZzBRTlJJQnoyakUxTjcKN1JDbExQMHQrQ0h4cDFtM2NCWU5DaTczQTlWVnhKejVMNGk3ZnJKWkVNU2lVVGlLNE8zRlJoQTBVa3NtVWJxZQpVL2hsU0hkUEFEQUxRZFZLdTlyWkZpdFROdEVXRUZhZE4wM0V5djRZeGJ4c1lERUZvTExwZDBjK1dUQURBZ01CCkFBR2pnZ0lwTUlJQ0pUQU9CZ05WSFE4QkFmOEVCQU1DQmFBd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3RUcKQ0NzR0FRVUZCd01DTUF3R0ExVWRFd0VCL3dRQ01BQXdIUVlEVlIwT0JCWUVGSjQ1R204Q3RuUWE4MnRuUVk0WQowOVRSMGJLNk1COEdBMVVkSXdRWU1CYUFGT2Vybnc4c002QlQwMTVQZU1peWhBNDcxcEl6TURNR0NDc0dBUVVGCkJ3RUJCQ2N3SlRBakJnZ3JCZ0VGQlFjd0FvWVhhSFIwY0RvdkwzSXhNeTVwTG14bGJtTnlMbTl5Wnk4d0pRWUQKVlIwUkJCNHdISUlhY0daaGJtUnplWE4wWlcwdVltRmphMlJwWjJsMFlXd3VaR1V3RXdZRFZSMGdCQXd3Q2pBSQpCZ1puZ1F3QkFnRXdMZ1lEVlIwZkJDY3dKVEFqb0NHZ0g0WWRhSFIwY0RvdkwzSXhNeTVqTG14bGJtTnlMbTl5Clp5ODFNaTVqY213d2dnRURCZ29yQmdFRUFkWjVBZ1FDQklIMEJJSHhBTzhBZFFDa1FzVUdTV0JoVkk4UDFPcWMKKzNvdEprVk5oNmwvTDk5RldmWW5UenFFVkFBQUFabStyWVBtQUFBRUF3QkdNRVFDSUZrY0F4cGMxRG9vZVh4Lwp0WE1nNk9iT2xNc2o1U0dSRzJrY05CQ0JnbzhlQWlBVXIvZDJyYVkyZDMzV3k1ZlZ4RkZUTHNpdURNYVIxcFdMCjB1emo4Umptc2dCMkFCbUcxTWNvcW0vK3VnTnZlQ3BOQVpHcXppMXlNUSt1emwxd1FTMGxUTWZVQUFBQm1iNnQKZytzQUFBUURBRWN3UlFJZ1RiVm1EdUxGeDQ2R3N5cDgySXdZU21saHhjZDVnYjkrMXg2cUlyYXlwYThDSVFDZgpDQ24xMG5pWkRLWTZ4a3ZlcU8wRjdRRXdNQ1RoSU5oVHBjUHpWM0w3QXpBTkJna3Foa2lHOXcwQkFRc0ZBQU9DCkFRRUFPdlpCeVlJaXhQdXZQMEx5YWdXL0hsdXlNcFowNk0wSWlDZkhkQXBxUHNiamZGYWw3SW1OM0ZCY3JyZEoKbnYzVjBFb2ZlWkdQSEI4WWFPVmJtcklkcGU4UjZ6aXlTaG9wQzRmcUNXT3A0T3VCaXVldytreEp4dVdsRWw3YQpzU2FtZ09jTHpHTFNtU0x3ZUdmZkNQdEI5eUVhODB6VkN1SmhtNWUvalJFbm0vVFdCdjlsWmI2bnRwT29Eazl5CjVUenBGQlpFNzhJUFBFaXQxV1o2U2JLSGtTVi9mdHdMaGZja3VBaE5lekxHMnpWMFYwMlRZQkl6UHhrNmQ1ZFoKTEd1SS8wRVhrWXNiVkNHRzh3OHFiQ1laVUUyQzZvSENnTzBSUzBDWHlFMHBoZlh4Vnlpd2Z0YjJrVDBBVHhiZgovbElSV2JvbjVlNm4vcHJYSFViOWQ4Qlg2QT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlGQlRDQ0F1MmdBd0lCQWdJUVdnRHlFdGpVdElEemtrRlg2aW1EQlRBTkJna3Foa2lHOXcwQkFRc0ZBREJQCk1Rc3dDUVlEVlFRR0V3SlZVekVwTUNjR0ExVUVDaE1nU1c1MFpYSnVaWFFnVTJWamRYSnBkSGtnVW1WelpXRnkKWTJnZ1IzSnZkWEF4RlRBVEJnTlZCQU1UREVsVFVrY2dVbTl2ZENCWU1UQWVGdzB5TkRBek1UTXdNREF3TURCYQpGdzB5TnpBek1USXlNelU1TlRsYU1ETXhDekFKQmdOVkJBWVRBbFZUTVJZd0ZBWURWUVFLRXcxTVpYUW5jeUJGCmJtTnllWEIwTVF3d0NnWURWUVFERXdOU01UTXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUsKQW9JQkFRQ2xaM0NOMEZhQlpCVVhZYzI1QnRTdEdaQ01KbEEzbUJaamtsVGIyY3lFQlpQczArd0lHNkJnVVVOSQpmU3ZIU0phZXRDM2FuY2duTzFlaG42dncxZzdVRGpES2I1dXgwZGFrblRJK1dFNDFiMFZZYUhFWC9EN1lYWUtnCkw3SlJiTEFhWGJoWnpqVmx5SXVocnhBMy8rT2NYY0pKRnpUL2pDdUxqZkM4Y1N5VERCMEZ4THJIemFySlhuelIKeVFIM25BUDIvQXBkOU5wNzV0dDJRbkRyOUUwaTJnQjNiOWJKWHhmOTJuVXVwVmNNOXVwY3R1QnpwV2pQb1hUaQpkWUorRUovQjlhTHJBZWs0c1FwRXpOUENpZlZKTllJS05MTWM2WWpDUjA2Q0RnbzI4RWRQaXZFcEJIWGF6ZUdhClhQOWVuWmlWdXBwRDBFcWlGd1VCQkREVE1yT1BBZ01CQUFHamdmZ3dnZlV3RGdZRFZSMFBBUUgvQkFRREFnR0cKTUIwR0ExVWRKUVFXTUJRR0NDc0dBUVVGQndNQ0JnZ3JCZ0VGQlFjREFUQVNCZ05WSFJNQkFmOEVDREFHQVFILwpBZ0VBTUIwR0ExVWREZ1FXQkJUbnE1OFBMRE9nVTlOZVQzaklzb1FPTzlhU016QWZCZ05WSFNNRUdEQVdnQlI1CnRGbm1lN2JsNUFGemdBaUl5QnBZOXVtYmJqQXlCZ2dyQmdFRkJRY0JBUVFtTUNRd0lnWUlLd1lCQlFVSE1BS0cKRm1oMGRIQTZMeTk0TVM1cExteGxibU55TG05eVp5OHdFd1lEVlIwZ0JBd3dDakFJQmdabmdRd0JBZ0V3SndZRApWUjBmQkNBd0hqQWNvQnFnR0lZV2FIUjBjRG92TDNneExtTXViR1Z1WTNJdWIzSm5MekFOQmdrcWhraUc5dzBCCkFRc0ZBQU9DQWdFQVVUZFlVcUVpbXpXN1Rick95cExxQ2ZMN1ZPd1lmL1E3OU9INWNITENaZWdnZlFoRGNvbmwKazdLZ2g4YjB2aSsvWHVXdTdDTjhuL1VQZWcxdm8zRyt0YVhpcnJ5dHRoUWluQUhHd2MvVWRiT3lnSmE5enVCYwpWeXFvSDNDWFRYREluVCs4YStjM2FFVk1KMlN0K3BTbjRlZCtXa0RwOGlqc2lqdkV5RndFNDdodWxXMEx0empnCjlmT1Y1UG1yZy96eFdiUnVMK2swREJESEVKZW5uQ3NBZW43YzM1UG14N2pwbUovSHRnUmhjbnoweWpTQnZ5SXcKNkwxUUl1cGtDdjJTQk9EVC94REQzZ2ZRUXlLdjZyb1Y0RzJFaGZFeUFzV3Btb2p4akNVQ0dpeWc5N0Z2RHRtLwpOSzJMU2M5bHliS3hCNzNJMitQMkczQ2FXcHZ2cEFpSENWdTMwalc4R0N4S2RmaHNYdG5JeTJpbXNrUXFWWjJtCjBQbXhvYmIyOFR1Y3I3eEJLN0N0d3ZQcmI3OW9zN3UyWFAzTzVmOWIvSDY2R055UnJnbFJYbHJZakkxb0dZTC8KZjRJMW4vU2d1c2RhNld2QTZDMTkwa3hqVTE1WTEybUhVNCtCeHlSOWN4MmhoR1M5ZkFqTVpLSnNzMjhxeHZ6NgpBeHU0Q2FEbVJOWnBLL3BRclhGMTd5WENYa21FV2d2U09FWnk2WjlwY2JMSVZFR2NrVi9pVmVxMEFPbzJwa2c5CnA0UVJJeTB0SzJkaVJFTkxTRjJLeXNGd2JZNkIyNkJGZUZzM3Yxc1lWUmhGVzluTGtPclFWcG9yQ1MwS3labWYKd1ZEODlxU1RsbmN0TGNabklhdmpLc0tVdTFuQTFpVTB5WU1kWWVwS1I3bFdibndoZHgzZXdvaz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=",
- "key": "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS1FJQkFBS0NBZ0VBem9sUVo4Qmh6ditHaGdkV2dQbDJQa3VUNDE2RGp3L0szYnBES3Y1TkVYVzhhdjFqCndGaHd0NEJNcTlQWjkyUnZmekZ0bVlpMnF5RSswODBvaHhmU1RudE5XVGYzWEdpdU5JNGt1REtscEJTRDlvTDYKL1BpVHE2M0Z0YU92WVdDTGhaZHE3Q1FFTGZIMi9Cdm5DeWFYYjRRS0lLdU9xT1ZxMFlzR05xT3U5NzAxZXYyeQpqWi9kZUlYbFdpeGdDOVVvK1E0RUk4SC84bEh2VXFpOW1sY0taY0NKdW1MNktSN0t5d09ESlc0dU9xMkY3UHBBCnNZSjRIckZVK2FJSzJKeUYvR1RiWjVyVlVVMzROMnI4a2YxSGc1Rmx4VEFDQUJHQjR4K1ZKamtOUkdzY2JqMy8KVWJDS0U3Nk1VQmhCMlZPNzBNQzRkVEN5UDA0NzdNZnluZGRMWkFxOXNlR29pWjJvQ2tzL21oRDdZUFJkSSsvbgp0QjhveEZhcE5qc1M4NE1qS2pvOU5mTmVFSjUydXIrNEJYajcyWmplaTJSankwTTJ2alN1S2J5NW15VGNQN3AxClBQMFZvRmZuU0dUMzFQcDJZNlVzQ3pFY2x0WjdlMm02VXNsc1pZNVFrMzE5VXMyOUhkd0JBSlgrRkJiYkJlbjQKQzVJN0JmYW83TWRwN3JVNjFVTUlpRGRXZC9XaGdKSHpTdUtBb1JBTko3cE8vUFAzeURSQTFFZ0hQYU1UVTN2dApFS1VzL1MzNElmR25XYmR3RmcwS0x2Y0QxVlhFblBrdmlMdCtzbGtReEtKUk9Jcmc3Y1ZHRURSU1N5WlJ1cDVUCitHVklkMDhBTUF0QjFVcTcydGtXSzFNMjBSWVFWcDAzVGNUSy9oakZ2R3hnTVFXZ3N1bDNSejVaTUFNQ0F3RUEKQVFLQ0FnRUFneUFhdEVRbjFNdldGSEhFTWM0dmpBMWZyeExxWTRHYlFucG0rbnpKWVRSbWsyYWNWaG5RTmpCMgpmUURiZVgyQ2JEWnRadlN0UktpdXdybVY2Vzd1VG5WcC9pTFNJUkUweUprV0p2dkF2aE5vVkxHRHQrZjVtUjJTClVHZkRpUWRLalY0OHUvK0J4OG0vRFFDS0IwSlJFck81MmxRUkZwblEzNGhzUVhSYU9WOGUvUjdrcFpYQmZpdEUKR2FQaXRxQjJpdWlqS0RDYTFyVytRN1J0Ni9jbTJzTUtyaEw0ei9LRXZhOVZMQVp2dzBFM3JlU1QvaDdmTkYxUgpuY3VMSjByNHBlMUNmdHlHWWtBbVBzamw0YW4wSlV2Q1dSYkpybEZ2TFV0MzNmU0t2ODFoRjN5MUJLQVlpY0NJClJMR2gzT0NVZFV4bHo4RkM2WDQ1L1hKVVRuSEpvbTROZ0ZuZW5BUThTL3BQU1J4cnBZblRwcGxGK1ZlRDRYK20KbXZsZThPeFQ1UTRLVlNtZGNNU2sxWmFsM1lFVHN2bDJiQ3RPcTM3b0JiK2VVejhmTjUxeDhURTJyN3RCSWJnQwpYUFVjdnR6Sk1qZytHbkIxelgyd1I0RjNraFJneGhCZDNQMlg2LzVDcE41SDdndldQc2dxc1ZNTktWblhCcHdiClRMa0xWY3hOSlNJVVNMRnJraDM5RG03eFk2dEQ5cTJ4QWczVXVVbDdBcWlaaWlMSGlFNExhTDZlVjBMS1BQSy8KSnhqVGt0NG8xQVlJWFg0Uk55clVHS3JuNUtGeWtEcE1vK0FHR1R4YXpBTlh6WExUZWhyUkVUQWY0aWRKSU9rUQo5NUVsb3FpV29CajRJTTBJd3BOY0xtTnZGTFRuSGtvc2VqMVIyaDkrZ2RMNURCV3JGTUVDZ2dFQkFQQkgxOVlYCnJYVVdqQTRzdU02NWxXVmdHSjBUR0wvd1Q0ZjlRVVB1UGhGbmlaL2lqcDlaYmpWMWVhTGExTGQyU2VLWGRKUFQKa2lWZzdvN3U3bjZsVmZVUWlWQ0pvNTZsMGR5cmFPTHVRNy9mYWczbDFyeDRad2dWVWcrWEtwdEpIaDdoQVhzUgpyL2NjaENPQVlsc0k4NEVhWkllc0xhaXdWOEQzT2V5R1p2VVR0S0taQVFxSFZTQmlPbThMSGlob1BIOE1RRlZqCnVZa3krR0p5VHNzN1RuUUhZSU11UFU3Q1lQQUFhanB5OHBmYTFIQmRWbFgwdHUvcURGWXlxRHNrVjRDOEcxcWUKZ2FEL2d2MDJzQ2M0WEJ3MFo1UXM5MlhFb0pISjN3V0txRXNPWVRsRE9UOUQzQ0ljUlhBdmNEd1BVQ3JzNEgyZgpHdUowc3VNTkQ4Z2FyOFVDZ2dFQkFOd01WTUg4aFI0aHFUZWpxdjUvelV2OXJuWTk0QTBXVnZVYzUxVE12SFo2ClRWdVp5T3dMOUNkb1cvZFdEV3ZySVJSNmlqcGZLQ1p0WWxSQ3U2MDBxbWYvTk5nSGM5bXVlK0dLTSt6OEd2MW8KUlNNQzg3MExYZ0RwOGJpbDNlNGg3MThSOTdxRzhiTzg0aXMxTHphTTZPQlFURmZyZzMrMnJueGRPdE9uSkpKbwpmQWtTU1N1YUFTZnhySXFSYmtMVmxtcmI1QnFBLy82em02d0hOU0c2R09PZDVkRXRWeVV2bUhoM2I0SVVGMGFYCndNNk8veFNqZlIrK0YvUEJxcVVnVUFrZzE2ckV1TVRYWDZzOSs1K2duME1rZkcxczFielpZbDNQU3R0TjBac1AKdDNMaU1YNFBnZkpXTkNBWjRTYm9KK1E3WDMxNGlhYkpKOVlEUUdEOFZTY0NnZ0VCQUx2M043MWZvRzNzU1h2OQpPRVZmb0tOQlhYL2pKSVZpTkpVcFpSa0RFc01Dd0FLM2RPTHJUdSs3Q29CL3Q5QWRWUWRSZS96NGtXZDBRS3JICjl3SlR6TDU5UlM0ZnZrT3BiRmE0TU1EMXEwSTZQL2pIU0FrQUYzbVhWQzZtRHNxVGxHQ0xuR0R1SVQycXJTUW8KbHNpb1kvVW05R1crSjZuQzZhTW13OFZvRHJyQnc1ay9JRFZnVVJPWVJDWUNDSUdMcVdlcDZkbml2WTI2dGR3dApsNzRja3U3cHBuSjRoYlZMRWhJdUFPdmdhQzZySFcwWlZ5UyszeTBuWnFjMzBhc1NidkZpTmZQWjg0WkMyL0hDCkNtTmtENHB3NUdaaUZ0Y2h6b3E5NVIyc3JxS29pUjRHbkk0RlEvdmJLZWJzOVZ2R2p1eEZpZ2c3b3doc1NsU2MKTHpCVzBCRUNnZ0VBRkcyQW9OR1VlZ3VkN2ZCZnUyaVo0bWdXZmh1WVpSNmh5L2QyOGtSZmFwQklCaXpzbmgwdAorVXFTM3c4NkI3NjRQM0p3eXFKeTA3NXIxbTZyaFpUU0RQMkFKbDNxdjFhWFlZUzI5VlVpSEV4RnZzNVRXa1ZuCjRLWFhMdEVYSFRoQlJJNGlkVXA1dmJuWE5UT213bVdxYU1pTGpjM3JVenZlVHVWSXhNVkxlOXYvUjhoT3lxRnQKWWd2cGZLT3JuTUMvU2dSSDFMNE5CZFFlcTRXdnhRWEZzYnZDemZ4cmpxUXdmMTUzRjVoTjROdk5wbDlZQnM1MgpteS9HZ1hhRkpQY3U5dW41bTN6UHVsWlVKMDJGd25maTBSVGVDRHFHVFJYUkwreENnc0ZpcUFaNWZVektVMjJWCkhxNHFBS0RtYWZvN1dkQzVPS2lyL3JQRjR2UkNVYjZiR1FLQ0FRQVVxeTkzYkVnWWVkV1FpYTd6d3NSVlIrK0cKeWpFQ2lCK0Jyc21qWU1QVFZhYUdUQXNVT3I0ck53WHB6U1UvNTMvTWdMcFdlUjVxQUFyajFqVFM3TkpoOHlJeApMdWtYUmoxWTVReGhPSmdzZzNSdk1uaHlTOVdYUVVzaVloaXdBalhIMEhiWGtmRGVzS295QUM2U29yUHpEVlpSCkJxdlkyYTE4amZHUEtES2ovNnVnUXRpdDdONVVoVHQ3R1B3RVEvMWg4cnZ1djhHS2NlT1dqY2JrUTlIbVBmdHYKaUZWajlaUkNnbEd5ZWRkTkJlT2lycjByazRyZTQ2Qy94THMzSTlRdzFwUU9oV3ZoL0xWelZMNGFzVktuRHFzNwpSdVhvVWw5endXSTdWWXJqa3I5bnkrV1E5ZGlqZysyZ0VyclNLeDkrOFdONmtUbHRtYmpmYU10dkRmQ2gKLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K",
- "Store": "default"
- }
- ]
- }
-}
\ No newline at end of file
diff --git a/traefik/traefik.yml b/traefik/traefik.yml
deleted file mode 100644
index 50978e9..0000000
--- a/traefik/traefik.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-api:
- dashboard: true
- insecure: true
-
-entryPoints:
- web:
- address: ":80"
- websecure:
- address: ":443"
-
-certificatesResolvers:
- letsencrypt:
- acme:
- email: vonperfall@r83.io
- storage: /letsencrypt/acme.json
- httpChallenge:
- entryPoint: web
-
-providers:
- docker:
- endpoint: "unix:///var/run/docker.sock"
- exposedByDefault: false
- network: root_pfandsystem-network
- file:
- directory: /etc/traefik/dynamic
- watch: true
-
-log:
- level: INFO
-
-accessLog:
- filePath: "/var/log/access.log"
diff --git a/vite.config.js b/vite.config.js
index 288f1f6..135e719 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -8,24 +8,16 @@ export default defineConfig({
VitePWA({
registerType: 'autoUpdate',
manifest: {
- name: 'Pfandsystem PWA',
- short_name: 'PfandPWA',
+ name: 'Pfandsystem',
+ short_name: 'Pfandsystem',
start_url: '.',
display: 'standalone',
- background_color: '#ffffff',
- theme_color: '#1976d2',
- description: 'Digitale Pfandverwaltung für Bäckereien',
+ background_color: '#f8fafc',
+ theme_color: '#4338ca',
+ description: 'Digitale Pfand- und Tourenverwaltung',
icons: [
- {
- src: 'icon-192.png',
- sizes: '192x192',
- type: 'image/png'
- },
- {
- src: 'icon-512.png',
- sizes: '512x512',
- type: 'image/png'
- }
+ { src: 'icon-192.png', sizes: '192x192', type: 'image/png' },
+ { src: 'icon-512.png', sizes: '512x512', type: 'image/png' }
]
},
includeAssets: ['icon-192.png', 'icon-512.png'],
@@ -33,10 +25,6 @@ export default defineConfig({
injectRegister: 'auto',
})
],
- build: {
- outDir: 'dist',
- },
- server: {
- port: 5173,
- },
+ build: { outDir: 'dist' },
+ server: { port: 5173 },
});