Der Server-Container laeuft mit NODE_ENV=production, dadurch setzt npm
automatisch omit=dev. Build-Toolchains wie Next, Vite, Tailwind oder
TypeScript stehen aber in den devDependencies, weshalb jeder node_build
mit "Cannot find module ..." abbrach und die Preview auf den statischen
Platzhalter zurueckfiel. npm ci/npm install laufen jetzt mit
--include=dev.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bisher liess /api/auth/login nur Appwrite-User mit dem Label "admin" in die
Admin-Ansicht; alle anderen fielen in den Kunden-Login und bekamen "Kein
Kundenkonto fuer diesen Login gefunden". Mitarbeiter ohne Admin-Haken (z.B.
nico@webklar.com) kamen damit nicht auf /admin.html.
Jetzt gilt: Wer in der employees-Collection steht, ist Backoffice-Nutzer. Das
Label "admin" ist nur noch die WOMS-Adminrolle (Mitarbeiterverwaltung) und wird
als isAdmin-Flag in der Portal-Session bzw. in den Preview-Token-Labels
mitgefuehrt - inklusive "Als Kunde ansehen" und zurueck.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der im Gespraech vereinbarte Termin wird mit einem Klick am Akquise-Ticket
eingetragen (startDate/startTime/endTime/assignedTo/assignedName) - genau die
Felder, die das WOMS-Planboard liest. Kein zweiter Datensatz, damit Termin und
Ticket nicht auseinanderlaufen koennen.
- server/services/appointments.js: Ticket des Kunden finden, Termin schreiben,
belegte Zeiten lesen; Umrechnung ISO <-> "dd.mm.yyyy" und "hh:mm" <-> "hhmm"
- Routen GET /api/portal-admin/appointments und
POST /api/portal-admin/customers/:id/appointment
- Bereits vergebene Zeiten sind in der Terminauswahl gesperrt ("belegt"), der
eigene Termin bleibt waehlbar; steht am Ticket schon einer, ist er beim
Oeffnen vorausgewaehlt
- Zeiten, die jemand von Hand in WOMS gesetzt hat, tauchen mit auf
Sicherung gegen Datenverlust: bevorzugt wird das Akquise-Ticket. Gibt es keins,
kommt nur ein anderes offenes Ticket OHNE Datum in Frage - bei Webpage- und
Projekttickets bedeutet startDate den Projektstart, den wuerden wir sonst still
ueberschreiben. Die Rueckmeldung nennt immer Nummer und Art des Tickets.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- runDeploy: Repos mit package.json-build-Script ohne index.html werden
automatisch als node_build gebaut (Expo/Vite/React zeigen sonst nur den
Platzhalter); Build-Fehler fallen auf static+Platzhalter zurueck
- deployNodeBuild: npm-ci-Fallback auf npm install, Output-Erkennung
dist/build/out/web-build, maxBuffer+Timeout
- updateWebsiteProject: bestehenden type/index aus .webklar-preview.json
erhalten statt bei jedem Edit auf static zurueckzusetzen
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fehlt im Repo eine index.html, zeigte die Preview nur die
'wird vorbereitet'-Platzhalterseite, obwohl das eigentliche Projekt
(z.B. prototyp-app.html in knso/videogen) laengst deployt war.
ensureIndexHtml befoerdert jetzt die beste vorhandene HTML-Datei
(bevorzugte Namen, sonst einzige/groesste) per Kopie zur index.html;
der Platzhalter kommt nur noch, wenn gar keine HTML-Datei existiert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Anonymer git clone scheiterte bei privaten Gitea-Repos
("could not read Username"). Clone nutzt jetzt config.gitea.apiToken
via oauth2-Basic-Auth; Token wird aus Fehlermeldungen maskiert.
- runDeploy schreibt Platzhalter-index.html, wenn das Deploy-Verzeichnis
keine index.html enthaelt (leergeraeumtes Repo/Fehlbuild) -> nie mehr
nginx 403 Forbidden, Subdomain bleibt erreichbar.
- deployStatic: Fallback auf Repo-Wurzel bei fehlendem index-Unterordner,
.git wird nicht mehr mit ausgeliefert.
- Webhook: fehlt .webklar-preview.json im Repo, wird die Hosting-Config aus
dem Appwrite-Projektstand rekonstruiert, ins Repo zurueckgeschrieben und
normal deployt (ensureRepoPreviewConfig).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- archiveRepo: fehlt das Gitea-Repo (404), wird nur das Appwrite-Dokument
(ent)archiviert statt hart zu scheitern -> orphaned Projekte lassen sich
aus der Liste entfernen
- Reaktivierungs-Redeploy wird bei fehlendem Repo uebersprungen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- hasPreview existiert im Live-Schema nicht -> Appwrite lehnte Update ab
- syncPreviewTls muss NACH updateDocument laufen, sonst liest es isPublic
noch im alten Zustand (oeffentlicher Router bekam faelschlich preview-auth)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
sanitizeCustomer liefert jetzt customers.archived, damit das Ticketsystem den
Archiviert-Status ueber /api/admin/customers erhaelt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Webhook: Subdomain-Fallback auf Repo-Name nur noch bei aktivierter Preview,
Projekte ohne Website behalten leere Subdomain/previewUrl
- generateNextWoid: numerisches Maximum statt String-Sortierung (gemischt
5-/6-stellige WOIDs im Bestand)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Login: Appwrite-User mit Label 'admin' (Ticketsystem-Mitarbeiter) bekommen
eine Admin-Session und landen auf /admin.html
- Admin-Dashboard: Statistik-Uebersicht, Projektsuche ueber alle Projekte
(inkl. Preview-/Gitea-Links, Vorschau ohne Kunden-Login), Kundenliste mit
Portal-Status, letztem Login und Projektanzahl
- Kundennummer (code) direkt im Admin-Bereich pflegbar
- 'Als Kunde ansehen': Admin sieht das Portal exakt wie der Kunde (Banner
mit Rueckweg zur Admin-Uebersicht)
- Kunden-Dashboard: neue Bereiche 'Meine Rechnungen' (InvoiceNinja inkl.
Link ins Rechnungsportal) und 'Was wurde gemacht' (Tickets + Worksheets
aus dem Ticketsystem, ohne interne Akquise-Tickets); Kundennummer im Header
- Admin-API /api/portal-admin/* (Session-basiert), Kunden-API /api/invoices
und /api/activity
- appwriteClient: uebrig gebliebene Debug-Instrumentierung entfernt
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- previewDeploy.syncPreviewTls(): schreibt Traefik-Router (Host-Regeln) fuer alle
Preview-Subdomains nach preview-hosts.yml, damit Let's Encrypt Zertifikate
ausstellt. Laeuft nach jedem Deploy und beim Serverstart (ersetzt das nie
aufgerufene bash-Script sync-preview-tls.sh).
- createProjectFromTemplate: Subdomain optional. Ohne Subdomain wird nur das
Gitea-Repo angelegt (projectType 'repo', Status 'created'), kein Deploy.
- customerAdmin: Portal-Passwort liegt jetzt im Feld customers.portalPassword
statt als __portalPassword__-Prefix in den Notizen; Legacy-Notizen werden
beim naechsten Update bereinigt. CRM-Stufe (lead/customer) wird beim Setzen
des Portal-Passworts nicht mehr auf 'active' ueberschrieben.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sichert den bisher uncommitteten Produktionsstand des Kundenbereich-Servers,
damit kuenftige Deploys (git reset --hard) nichts mehr verwerfen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
session.secret wird ohne API-Key nicht zurückgegeben. Login nutzt
daher session.userId und die Admin Users API statt account.get().
Co-authored-by: Cursor <cursoragent@cursor.com>
Express-Server für Appwrite-Auth, Session, Projekt-Dashboard und Gitea-Webhook; statisches Frontend und Schema-Dokumentation für woms-database.
Co-authored-by: Cursor <cursoragent@cursor.com>