Spec: Admin-Panel ins Ticketsystem (Kundenansicht, Protokoll, Team-Schnittstelle, 4 Etappen)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
546d3c84d0
commit
5fb39f1a1b
1 file changed
+309
@@ -0,0 +1,309 @@
|
||||
# Admin-Panel ins Ticketsystem – Design
|
||||
|
||||
Stand: 2026-10-01 · Status: vom Nutzer im Chat freigegeben (Abschnitte 1–5), Spec zur Durchsicht
|
||||
Betrifft zwei Repos: **Portal** `knso/Webklar-Kundenbereich` (project.webklar.com, Branch `main`) und
|
||||
**WOMS** `JUSN/tickte-system` (ticket.webklar.com, Branch `test`).
|
||||
|
||||
## Ziel
|
||||
|
||||
project.webklar.com ist nur noch die Oberfläche für Kunden. Das Admin-Panel (`public/admin.html`) wird
|
||||
abgeschafft. Mitarbeiter arbeiten ausschließlich im Ticketsystem (WOMS) und kommen nur noch für zwei Dinge
|
||||
auf project.webklar.com: eine **Preview** ansehen oder das **Portal eines Kunden so öffnen, wie er es sieht**
|
||||
(z. B. bei Fernwartung am Telefon), jeweils per Klick aus dem Ticketsystem.
|
||||
|
||||
## Entscheidungen (vom Nutzer)
|
||||
|
||||
| # | Entscheidung |
|
||||
|---|---|
|
||||
| E1 | Admin-Panel fällt komplett weg. „Übersicht“ und „Projekte“ des Panels ersatzlos (Projekte gibt es im WOMS). |
|
||||
| E2 | Kundenansicht: **Variante A**. Erlaubt ist, was den Kunden nichts kostet; gesperrt bleiben Verträge, Geld und Passwort. Jede Aktion wird **protokolliert**. |
|
||||
| E3 | **Alle Mitarbeiter gleich**: Chat, Gutschriften, Abo-Angebote, E-Mail-Speicher und Kundenansicht für jeden Mitarbeiter, nicht nur Admins. |
|
||||
| E4 | Rechnungsanalyse (`kalkulation.html`) **erstmal raus**; Code bleibt in Git, kommt zurück, wenn die Leads wieder laufen. |
|
||||
| E5 | **Alles zu einem Kunden an einem Ort**: neue Tabs auf der WOMS-Kundenseite; Sidebar-Unterpunkte unter „Kunden“ sind Sammellisten. |
|
||||
| E6 | Technischer **Weg 1**: Der Portal-Server bleibt das Backend (Stripe, SMTP, Dateien), WOMS bekommt die Oberflächen. |
|
||||
| E7 | Ausnahmen bei den Sammellisten: **Chat** ist ein Messenger mit zwei Spalten; **E-Mail-Speicher** hakt man direkt in der Liste ab. |
|
||||
| E8 | In der Kundenansicht sind auch **Erklärungen im Namen des Kunden** gesperrt (Chat als Kunde, Gutschrift beantragen, Rückfrage beantworten). In der Praxis wird damit heute nur **News** frei. |
|
||||
| E9 | Kundenansicht endet nach **2 Stunden**; Protokoll wird nach **12 Monaten** gelöscht; Datenschutzerklärung bekommt dazu einen Satz. |
|
||||
| E10 | Mitarbeiter-Login auf project.webklar.com wird gesperrt (Hinweis + Link ins Ticketsystem). |
|
||||
| E11 | Team-Mails: Texte und Design bleiben, nur Links (und Linktext „Admin-Bereich“ → „Ticketsystem“). |
|
||||
| E12 | Umsetzung in **4 Etappen**; das Admin-Panel bleibt bis Etappe 4 in Betrieb. |
|
||||
|
||||
## Ist-Zustand (kurz)
|
||||
|
||||
- Admin-Panel: Tabs Übersicht, Projekte, Kunden, Chat, Gutschriften, Abo-Angebote, E-Mail-Speicher. Es spricht
|
||||
`/api/portal-admin/*` mit Cookie-Sitzung (`requireAdminSession`, `server/routes/portalAdmin.js:38`). Jede
|
||||
Mitarbeiter-Anmeldung im Portal (Eintrag in `employees` **oder** Label `admin`) bekommt diese Sitzung.
|
||||
- WOMS ruft das Portal heute schon cross-origin mit Appwrite-JWT auf (`/api/admin/*`, `requireAppwriteStaff`,
|
||||
verlangt Label `admin`): Finanzen, Kunden anlegen/löschen, Projekte, Services, Analyse.
|
||||
- „Als Kunde ansehen“ gibt es (`POST /api/portal-admin/view-as/:id`); jede Schreib-Route sperrt sich dort einzeln.
|
||||
- WOMS: Sidebar ist eine flache Liste (`src/components/Navbar.jsx:57-69`), Kundenseite
|
||||
`src/pages/CustomerDetailPage.jsx` mit Tabs aus `src/lib/customerTabs.js` (Tab nur im React-State).
|
||||
|
||||
## 1. WOMS: Sidebar und Kundenseite
|
||||
|
||||
### Sidebar
|
||||
|
||||
```
|
||||
Kunden
|
||||
Chat ● n ungelesene Kundennachrichten
|
||||
Gutschriften ● n offene Anträge
|
||||
Abo-Angebote
|
||||
E-Mail-Speicher ● n offene Speicher-Aufgaben
|
||||
```
|
||||
|
||||
- Einträge in `links` bekommen optional `children`; Unterpunkte sind eingerückt und immer sichtbar. Eingeklappt
|
||||
erscheinen sie als Symbole unter dem Kunden-Symbol. Zahlen nur, wenn > 0.
|
||||
- Zahlen kommen aus einem Hook, der **alle 60 s** fragt, solange der Browser-Tab sichtbar ist
|
||||
(`document.visibilityState`). Fehler lassen die letzte Zahl stehen.
|
||||
- Der Knopf **„Projekt-Admin“** entfällt (Etappe 4).
|
||||
- Routen: `/customers/chat` (optional `?kunde=<id>`), `/customers/gutschriften`, `/customers/angebote`,
|
||||
`/customers/email-speicher`. Statische Segmente gehen in react-router v6 vor `/customers/:id`.
|
||||
|
||||
### Kundenseite
|
||||
|
||||
Tabs: `Übersicht · Tickets · Rechnungen · Projekte · Chat · Abo & Angebote · Gutschriften · Funktionen · Protokoll`
|
||||
|
||||
- „Rechnungen“ bleibt **nur für Admins** (die Finanzen-API ist admin-only). Alle neuen Tabs sehen alle Mitarbeiter.
|
||||
- „Uebersicht“ wird zu „Übersicht“.
|
||||
- Der Tab steht in der Adresse: `/customers/<id>?tab=chat|abo|gutschriften|funktionen|protokoll|…`; beim
|
||||
Gutschriften-Tab zusätzlich `&antrag=<id>` (öffnet den Antrag direkt). Unbekannte Tabs → Übersicht (wie heute
|
||||
`resolveCustomerTab`).
|
||||
- Kopfzeile: Knopf **„Kundenansicht öffnen“** (neuer Browser-Tab). Ohne Portal-Zugang
|
||||
(`portalAccessEnabled && appwriteUserId` fehlt) ausgegraut mit Hinweis „Kein Portal-Zugang“.
|
||||
- Karte „Portal-Zugang“: Link „Portal öffnen“ (führte nur zum Login) wird durch denselben Knopf ersetzt; neu ist
|
||||
die Zeile **„Letzter Login“**.
|
||||
|
||||
## 2. WOMS: die Bereiche
|
||||
|
||||
Grundsatz: **Funktionsgleich zum heutigen Admin-Panel**, nur im WOMS-Look. Keine neuen Funktionen. Mails an
|
||||
Kunden und Stripe-Buchungen bleiben exakt wie heute (gleiche Server-Logik).
|
||||
|
||||
### Chat (Messenger `/customers/chat` und Kunden-Tab „Chat“)
|
||||
|
||||
- Links: Gesprächsliste (ungelesene oben, letzte Nachricht, Zeit) und Feld „Neue Nachricht an Kunde…“
|
||||
(Kundenauswahl). Rechts: Gespräch. Im Kunden-Tab steckt dasselbe Gespräch ohne Liste.
|
||||
- Anhänge wie heute: Bild, Kamerafoto, Datei, Sprachnachricht; Lightbox, Audio-Player, Download.
|
||||
- Eingabezeile und Sprechblasen: WOMS lädt **`chat-composer.js` und `chat-composer.css` zur Laufzeit von
|
||||
project.webklar.com** (eine Quelle, kein Auseinanderlaufen) und bettet `ChatComposer.create(...)` /
|
||||
`ChatComposer.renderMessage(...)` in eine React-Komponente ein. Farben gleicht eine kleine WOMS-CSS an.
|
||||
Der Composer bekommt eine neue Option für Anfrage-Header (Bearer-JWT beim Hochladen und Entfernen); ohne
|
||||
die Option verhält er sich wie bisher (Kundenseite unverändert).
|
||||
- Nach dem Senden zeigt WOMS das Ergebnis des Mail-Hinweises an den Kunden (K17) wie heute im Panel.
|
||||
- Neue Nachrichten im offenen Gespräch: Abfrage alle 15 s (wie das Panel heute, nur bei sichtbarem Tab);
|
||||
gelesene Kundennachrichten werden wie heute als gelesen markiert.
|
||||
|
||||
### Gutschriften (Sammelliste und Kunden-Tab)
|
||||
|
||||
- Filter „Offen“ / „Alle“; im Kunden-Tab nur die Anträge dieses Kunden.
|
||||
- Detail wie heute: Antrag, Nachweise (öffnen), automatische Prüfung, Rechner (Rechnungsbetrag, Rechnung gilt
|
||||
für, Bezahlt bis, Übernahme ab), weitere Anträge des Kunden, Verlauf, Stripe-Guthaben.
|
||||
- Aktionen wie heute: „Genehmigen & gutschreiben“, „Rückfrage senden“, „Ablehnen“, „Jetzt in Stripe
|
||||
gutschreiben“, „In Stripe öffnen“.
|
||||
|
||||
### Abo & Angebote (Sammelliste „Abo-Angebote“ und Kunden-Tab)
|
||||
|
||||
- Kunden-Tab oben: **Abo-Status** (Abo, Leistungsbeginn, nächste Abbuchung, gekündigt zum, Speicher), sichtbar
|
||||
für alle Mitarbeiter. Darunter die Angebote dieses Kunden und „Neues Angebot“ (Kunde vorbelegt).
|
||||
- Sammelliste: Filter „Offen & aktiv“ / „Alle“, „Neues Angebot“ mit Kundenauswahl, Zurückziehen,
|
||||
Mail erneut senden. Coupon in Stripe wie heute.
|
||||
|
||||
### E-Mail-Speicher (nur Sammelliste)
|
||||
|
||||
- Gesamtübersicht, fällige konsoleH-Aufgaben mit Anleitung und Knopf „Erledigt“ direkt in der Zeile,
|
||||
gescheiterte Änderungen der letzten 30 Tage.
|
||||
|
||||
### Funktionen (Kunden-Tab)
|
||||
|
||||
- Pro Projekt News an/aus, wie heute im Kunden-Tab des Panels.
|
||||
|
||||
### Protokoll (Kunden-Tab)
|
||||
|
||||
- Einträge der Kundenansicht dieses Kunden, neueste zuerst: Zeit, Mitarbeiter, Aktion, Detail.
|
||||
|
||||
### Ersatzlos weg
|
||||
|
||||
Übersicht (Statistik, letzte Logins), Projekt- und Kundentabelle des Panels, Invoice-Ninja-Rechnungsliste
|
||||
(`GET /customers/:id/invoices`), Kunden-Aktivität (`/customers/:id/activity`, im WOMS-Tab „Tickets“ enthalten),
|
||||
Kundennummer-Bearbeitung des Panels (Stammdaten bearbeitet WOMS schon selbst).
|
||||
|
||||
## 3. Portal: Kundenansicht und Protokoll
|
||||
|
||||
### Öffnen
|
||||
|
||||
1. WOMS öffnet synchron einen leeren Tab (gegen Pop-up-Sperren), ruft
|
||||
`POST /api/team/customers/:id/kundenansicht` (Bearer-JWT) und setzt danach die Adresse des Tabs.
|
||||
2. Der Server prüft: Kunde existiert und hat Portal-Zugang. Er erzeugt einen **Einmal-Link**
|
||||
(`staffPreviewTokens`, neuer Zweck `kundenansicht`, 60 s, einmal einlösbar) und antwortet mit
|
||||
`{ openUrl: https://project.webklar.com/api/auth/kundenansicht?token=… }`.
|
||||
3. `GET /api/auth/kundenansicht` löst das Token ein, setzt die Portal-Sitzung
|
||||
`{ role:'admin', viewAs:true, viewId, viewExpiresAt, appwriteUserId, adminName, adminEmail, customerId, name, email }`
|
||||
(`viewId` = zufällige Kennung, `viewExpiresAt` = jetzt + 2 h, Cookie-Laufzeit ebenfalls 2 h) und ein
|
||||
**Preview-Cookie für genau diesen Kunden** (Rolle Kunde, 2 h), damit Previews aus der Kundenansicht
|
||||
funktionieren. Protokoll: `geoeffnet`. Weiter auf `/dashboard.html`.
|
||||
4. Abgelaufenes oder verbrauchtes Token: Hinweisseite „Link abgelaufen, bitte im Ticketsystem erneut öffnen“.
|
||||
|
||||
### Banner und Ende
|
||||
|
||||
- Banner oben: „Kundenansicht: *Kunde* · geöffnet von *Mitarbeiter* · Beenden“.
|
||||
- „Beenden“: `POST /api/auth/kundenansicht/ende` → Protokoll `beendet`, Portal- und Preview-Cookie löschen,
|
||||
Weiterleitung auf `https://ticket.webklar.com/customers/<id>` (Basis aus neuer Variable `TICKET_BASE_URL`).
|
||||
- Nach 2 h: jede Anfrage antwortet `401 { code:'view_expired' }`, Cookies werden gelöscht, Protokoll
|
||||
`abgelaufen`; das Dashboard zeigt „Kundenansicht abgelaufen – im Ticketsystem erneut öffnen“.
|
||||
|
||||
### Schutz vor Verwechslung (ein Browser = eine Portal-Sitzung)
|
||||
|
||||
- `/api/auth/me` liefert in der Kundenansicht `viewId`. Alle API-Aufrufe des Dashboards (`app.js`,
|
||||
`funktionen.js`, `analyse-view.js`, Composer) senden den Header `X-Kundenansicht: <viewId>`.
|
||||
- Server-Middleware vor allen Kunden-Routen: In einer Kundenansicht mit abweichender Kennung → `409
|
||||
{ code:'view_replaced', kunde:<Name> }`. Schreibende Anfragen **ohne** Kennung → ebenfalls 409.
|
||||
- Das Dashboard rendert bei 409 nichts Neues, sondern zeigt nur: „Diese Ansicht wurde durch die
|
||||
Kundenansicht von *B* ersetzt. Tab schließen.“
|
||||
|
||||
### Was erlaubt ist (fail-closed)
|
||||
|
||||
- Neue zentrale Middleware: In einer Kundenansicht ist **jede nicht-lesende Anfrage gesperrt** (403
|
||||
„In der Kundenansicht nicht möglich“), außer einer ausdrücklichen Erlaubnisliste:
|
||||
- News: anlegen, Bild hochladen, ändern, löschen (`/api/news` POST/PATCH/DELETE; `rejectViewAs` entfällt dort).
|
||||
- `POST /api/funktionen/analyse/heatmap-link` (nur ein Ansichts-Link, kostet nichts).
|
||||
- Ende der Kundenansicht und Abmelden.
|
||||
- Damit bleiben gesperrt: Abo bestellen/verwalten/wechseln, Speicher, News kaufen, Analyse an/aus (AVV-Zustimmung),
|
||||
Passwort, Chat senden/Anhänge, Gutschrift beantragen/antworten – und **jede künftige Schreib-Route**, bis sie
|
||||
bewusst auf die Liste kommt. Die bestehenden Einzelsperren bleiben als zweite Sicherung stehen.
|
||||
- `POST /api/chat/read` fällt unter die Sperre: Die Kundenansicht markiert Team-Nachrichten **nicht** mehr als
|
||||
„vom Kunden gelesen“ (Korrektur).
|
||||
- Lesende Anfragen mit Nebenwirkung, die bleiben dürfen: Abgleich offener Wechsel (`GET /api/abo`),
|
||||
Freischalten fertiger Funktionen und Rechnungs-Links (`GET /api/funktionen`) – reine Synchronisierung.
|
||||
- Das Dashboard blendet gesperrte Bedienelemente in der Kundenansicht weiter aus bzw. deaktiviert sie (wie heute).
|
||||
|
||||
### Protokoll
|
||||
|
||||
- Neue Appwrite-Collection **`customerViewLog`**: `customerId` (string 64, Pflicht), `staffUserId` (string 64),
|
||||
`staffName` (string 128), `action` (string 32), `detail` (string 300); Index `customerId` + `$createdAt`.
|
||||
Nur der Server-Schlüssel schreibt/liest (keine Client-Rechte).
|
||||
- Aktionen: `geoeffnet`, `beendet`, `abgelaufen`, `news_angelegt`, `news_bild`, `news_geaendert`,
|
||||
`news_geloescht` (Detail: Titel bzw. Anfang des Textes).
|
||||
- Geschrieben **vom Server** im Anschluss an die erfolgreiche Aktion; schlägt das Schreiben fehl, wird das
|
||||
geloggt (Server-Log), die Aktion selbst bleibt gültig.
|
||||
- Löschen: täglicher Aufräumlauf im Portal-Server, Einträge älter als 12 Monate.
|
||||
- Anlegen: Setup-Skript mit dem Server-Schlüssel; fehlt dem Schlüssel das Recht, legt der Nutzer die Collection
|
||||
nach Vorgabe in der Appwrite-Konsole an.
|
||||
|
||||
### Datenschutzerklärung (Portal, Abschnitt 6)
|
||||
|
||||
Der Satz „Um Sie zu unterstützen, können unsere Mitarbeiter Ihr Portal so ansehen, wie Sie es sehen. Eine Nachricht
|
||||
in Ihrem Namen senden können sie dabei nicht.“ wird ersetzt durch:
|
||||
|
||||
> Um Sie zu unterstützen, können unsere Mitarbeiter Ihr Portal so öffnen, wie Sie es sehen, und dabei für Sie
|
||||
> News-Beiträge anlegen, ändern oder löschen. Bestellungen, Zahlungen, Änderungen an Ihrem Passwort sowie
|
||||
> Nachrichten oder Anträge in Ihrem Namen sind dabei ausgeschlossen. Jedes Öffnen und jede Änderung halten wir
|
||||
> mit Mitarbeiter und Zeitpunkt fest und löschen diese Einträge nach 12 Monaten. Rechtsgrundlage dafür ist
|
||||
> Art. 6 Abs. 1 lit. f DSGVO; unser berechtigtes Interesse ist die Nachvollziehbarkeit von Zugriffen auf Ihr Konto.
|
||||
|
||||
„Stand“ aktualisieren, PDF-Fassung `docs/WEBklar-Datenschutzerklaerung.pdf` neu erzeugen (wie in d4241d2).
|
||||
Geht mit Etappe 1 live.
|
||||
|
||||
## 4. Portal: Schnittstelle für das Ticketsystem und Abschaltung
|
||||
|
||||
### Neuer Eingang `/api/team/*`
|
||||
|
||||
- Middleware `requireStaffJwt`: prüft `Authorization: Bearer <Appwrite-JWT>` über Appwrite `/account` (wie
|
||||
`requireAppwriteStaff`), dann `resolveStaffAccount` (Eintrag in `employees` **oder** Label `admin`); sonst 403.
|
||||
Sie stellt die Mitarbeiter-Identität in derselben Form bereit wie die bisherige Admin-Sitzung
|
||||
(`appwriteUserId`, `name`, `email`, `isAdmin`), damit die bestehenden Handler unverändert bleiben.
|
||||
Die 2FA ist damit abgedeckt: Appwrite beantwortet `/account` ohne abgeschlossenen zweiten Faktor mit 401
|
||||
(`user_more_factors_required`), die Middleware lässt dann nichts durch.
|
||||
- Routen (bestehende Logik, neu eingehängt; während Etappe 1–3 parallel zu `/api/portal-admin/*`):
|
||||
|
||||
| Neu unter `/api/team` | Herkunft |
|
||||
|---|---|
|
||||
| `GET /chats`, `GET /chats/unread-count`, `GET/POST /chats/:id/messages`, `POST /chats/:id/attachments`, `GET/DELETE /chats/:id/attachments/:att`, `POST /chats/:id/read` | `portalAdmin.js` (Chat-Teil wird eigenes Modul) |
|
||||
| `/takeover-credits/*` (+ Filter `?customerId=`) | `takeoverAdminRouter` |
|
||||
| `/offers/*` (+ Filter `?customerId=`) | `offersAdminRouter` |
|
||||
| `/storage-tasks/*` + neu `GET /storage-tasks/open-count` (ohne Stripe-Abgleich, für die Sidebar-Zahl) | `storageTasksAdminRouter` |
|
||||
| `/funktionen/:customerId[/news]` | `funktionenAdmin` |
|
||||
| `GET /customers/:id/abo` | Logik von `/api/admin/customers/:id/abo`, jetzt für alle Mitarbeiter |
|
||||
| `GET /customers/:id/portal` → `{ hasAccess, lastLoginAt }` | neu (`customerPortalAccess`) |
|
||||
| `POST /customers/:id/kundenansicht` | neu (ersetzt `view-as`) |
|
||||
| `GET /customers/:id/protokoll` | neu |
|
||||
| `POST /preview-link` | Logik von `/api/admin/preview-open`, jetzt für alle Mitarbeiter |
|
||||
|
||||
- **Dateien ohne Header** (Bilder, Sprachnachrichten, Downloads im Chat; Nachweise bei Gutschriften): Die
|
||||
Antworten enthalten **signierte Links** (HMAC mit dem Server-Geheimnis, gebunden an Kunde + Datei, 15 min
|
||||
gültig). Die Datei-Routen akzeptieren Bearer-JWT **oder** gültige Signatur.
|
||||
- CORS: erlaubte Header zusätzlich `X-File-Name`, `X-Attachment-Kind`, `X-Duration-Ms`, `X-Image-Width`,
|
||||
`X-Image-Height` (Chat-Upload). Herkunft weiter nur `https://ticket.webklar.com` (+ localhost).
|
||||
- WOMS-Seite: ein gemeinsamer Helfer `teamRequest` nach dem Muster von `src/lib/financeRequest.js`
|
||||
(JWT-Cache, einmal neu versuchen bei 401, deutsche Fehlertexte).
|
||||
|
||||
### Previews aus dem Ticketsystem
|
||||
|
||||
- Die Preview-Knöpfe im WOMS (`PreviewLinkButton`) sind heute einfache Links und funktionieren nur dank der
|
||||
Mitarbeiter-Anmeldung im Portal. Sie holen sich ab Etappe 1 einen Einmal-Link über `POST /api/team/preview-link`
|
||||
(leerer Tab synchron, Adresse danach setzen).
|
||||
|
||||
### Was in Etappe 4 wegfällt
|
||||
|
||||
- `public/admin.html`, `public/admin.js` (und nur dort genutzte Styles), `public/kalkulation.{html,js,css}`.
|
||||
- `/api/portal-admin/*` komplett, darin auch: overview, projects, customers (Liste, PATCH, activity, invoices),
|
||||
appointments, `customers/:id/appointment`, `GET customers/:id`, `view-as`, `exit-view-as`.
|
||||
- `/api/admin/switch-link`, `GET /api/auth/staff-switch`, Zweck `switch` in `staffPreviewTokens`,
|
||||
`/api/admin/preview-open` (ersetzt durch `/api/team/preview-link`). Die Einlöse-Route
|
||||
`GET /api/auth/staff-preview` **bleibt**: sie löst auch die Links von `/api/team/preview-link` ein.
|
||||
- Mitarbeiter-Login: `POST /api/auth/login` erkennt Mitarbeiter wie heute (`resolveStaffAccount`), beendet die
|
||||
gerade erzeugte Appwrite-Sitzung und antwortet `403 { error:'Mitarbeiter arbeiten im Ticketsystem.', ticketUrl }`;
|
||||
die Login-Seite zeigt den Hinweis mit Link. `/api/auth/login/mfa`, `/login/mfa/resend`, `staffMfa` und
|
||||
`startStaffPortalSession` entfallen. Kundenlogin unverändert.
|
||||
- Alte Mitarbeiter-Sitzungen (Rolle admin ohne Kundenansicht): Dashboard und Login leiten ins Ticketsystem.
|
||||
- WOMS (vorher live): Knopf „Projekt-Admin“ und `openProjectAdmin()` entfernen.
|
||||
- Team-Mails:
|
||||
- Fußzeilen-Link „Admin-Bereich“ in 15 Vorlagen → „Ticketsystem“, `https://ticket.webklar.com/customers`.
|
||||
- T01 „Neue Chatnachricht“: Knopf „Im Ticketsystem antworten →“ → `/customers/chat?kunde=<customerId>`
|
||||
(neuer Platzhalter).
|
||||
- T10/T11: `admin_link` → `/customers/<customerId>?tab=gutschriften&antrag=<id>`.
|
||||
- Code-Kommentare/Texte, die „Admin-Panel“ nennen, werden angepasst.
|
||||
|
||||
## 5. Etappen und Livegang
|
||||
|
||||
Jede Etappe ist für sich livefähig; das Admin-Panel läuft bis Etappe 4 weiter.
|
||||
|
||||
| Etappe | Inhalt |
|
||||
|---|---|
|
||||
| **1 Fundament + Kundenansicht** | `/api/team`-Eingang (Middleware, CORS, `teamRequest`), Kundenansicht (Einmal-Link, Sitzung 2 h, Banner, Verwechslungsschutz, fail-closed-Sperre, News frei, Chat-Lesestatus), Protokoll (Collection, Schreiben, Aufräumen, Tab), Datenschutz-Satz, Previews per Einmal-Link, WOMS: Tab in der Adresse, „Übersicht“, Knopf „Kundenansicht öffnen“, Letzter Login, Abo-Status-Route. |
|
||||
| **2 Chat** | Chat-Routen unter `/api/team`, signierte Datei-Links, Composer-Option für Header, WOMS-Messenger, Kunden-Tab, Sidebar mit Unterpunkten und Chat-Zahl. |
|
||||
| **3 Gutschriften, Abo & Angebote, E-Mail-Speicher, Funktionen** | Routen unter `/api/team` (+ Kundenfilter, `open-count`), signierte Nachweis-Links, Sammellisten und Kunden-Tabs, restliche Sidebar-Zahlen. |
|
||||
| **4 Abschalten** | WOMS: „Projekt-Admin“ entfernen (zuerst live). Portal: Admin-Panel, Rechnungsanalyse, `/api/portal-admin`, Switch/Preview-open-Altlasten, Mitarbeiter-Login sperren, Mail-Links. |
|
||||
|
||||
- Reihenfolge je Etappe: **Portal zuerst** (abwärtskompatibel), dann WOMS. Ausnahme Etappe 4: WOMS zuerst.
|
||||
- Pushen macht der Nutzer (Portal `…:main`, WOMS `…:test`; WOMS deployt jeden gepushten Branch, also nie
|
||||
Feature-Branches pushen). Danach prüfe ich den Live-Stand lesend.
|
||||
- Arbeitsorte: Portal-Worktree `dev-admin-umzug` (Branch `feature/admin-umzug`), WOMS-Worktree gleichen Namens.
|
||||
|
||||
## 6. Tests
|
||||
|
||||
- **Portal:** bestehende Unit-Tests (`node --test`) plus neue:
|
||||
- `requireStaffJwt`: ohne JWT 401, ungültig 401, Nicht-Mitarbeiter 403, Mitarbeiter ohne Label `admin` erlaubt.
|
||||
- Kundenansicht: Token einmalig und 60 s; Sitzung endet nach 2 h; **jede** Schreib-Route außerhalb der
|
||||
Erlaubnisliste liefert 403 (Test läuft über die registrierten Express-Routen, damit neue Routen automatisch
|
||||
erfasst werden); News-Aktionen erlaubt und protokolliert; `POST /api/chat/read` gesperrt.
|
||||
- Verwechslung: Tab-Kennung A nach Wechsel zu B → 409, keine Daten von B.
|
||||
- Signierte Links: falscher Kunde, falsche Datei, abgelaufen → 403.
|
||||
- Aufräumlauf löscht nur Einträge > 12 Monate.
|
||||
- Abgeschottete Testumgebung (Appwrite-Nachbau, Stripe-Attrappe, Mail-Falle) für Gutschrift/Angebot über
|
||||
`/api/team` mit Bearer-JWT.
|
||||
- **WOMS:** Unit-Tests für reine Logik (`customerTabs` mit neuen Tabs/URL, Sidebar-Kinder, signierte-Link-Helfer,
|
||||
`teamRequest`); Playwright mit nachgebauten Schnittstellen unter Speicherbremse (`systemd-run … MemoryMax`).
|
||||
- **Nach jedem Livegang:** lesender Live-Check (Routen antworten 401 ohne JWT, CORS-Preflight 204, ausgelieferte
|
||||
Bundles enthalten die neuen Teile). Keine echten Kundendaten verändern; Testdaten klar benannt und danach löschen.
|
||||
|
||||
## Fehlerbehandlung
|
||||
|
||||
- JWT abgelaufen → `teamRequest` holt ein neues und versucht einmal erneut; danach Fehlermeldung.
|
||||
- Portal nicht erreichbar → jede Ansicht zeigt eine Fehlerzeile mit „Erneut versuchen“; Sidebar-Zahlen behalten
|
||||
den letzten Stand.
|
||||
- Kunde ohne Portal-Zugang → Knopf ausgegraut; Server antwortet zusätzlich 409 „Kein Portal-Zugang“.
|
||||
|
||||
## Nicht Teil dieser Spec
|
||||
|
||||
- Rechnungsanalyse/Kalkulation im WOMS (E4, später eigenes Vorhaben).
|
||||
- Neue Funktionen in Chat, Gutschriften, Angeboten oder E-Mail-Speicher.
|
||||
- Änderungen an Kunden-Logins, Kunden-Mails (K01–K19) oder an der WOMS-2FA.
|
||||
Reference in new issue
Block a user