# Projektarten, Zuordnungs-Ablauf und Bereich „Services“ – Design Stand: 2026-09-30 · Status: vom Nutzer im Chat freigegeben (Abschnitte 1–3), Spec zur Durchsicht Gesamtvorhaben in drei Teilprojekten, **nacheinander**: jedes wird gebaut, geht live und wird vom Nutzer live getestet, **bevor** das nächste beginnt. 1. **Projektarten + Services** (diese Spec) 2. Preview 2.0 (statisch / Build / Dev-Server bei Bedarf, Build ohne Portal-Geheimnisse) – eigene Spec 3. Funktion „Website-Analyse“ (Einwilligung, eigene Auswertung, Heatmap, Rechtstexte) – eigene Spec Recherchen dazu: `/root/reports/analyse-funktion-2026-09-30/` (projekttypen-preview.md, technik-analyse-heatmap.md, recht-tracking-deutschland.md). ## Ziel Jedes Repo hat eine **Art** (Website, Web-App, …). Egal ob es in Gitea oder im WOMS angelegt wird, wird die anlegende Person durch einen Ablauf geführt, bis Art, Kunde und Ticket feststehen. Es entstehen **keine leeren Tickets** und **keine verwaisten Kunden-Repos**. Im WOMS zeigt ein Bereich „Services“ unsere Leistungsarten, was je Art möglich ist und welche Projekte welche Art haben. ## Entscheidungen (vom Nutzer) | # | Entscheidung | |---|---| | P1 | Arten: **Website, Web-App, App, Migration/Umzug, Automation/Skript, Sonstiges**. Landingpage und Shop laufen als Website; Wartung ist ein Abo, keine Art; Template bleibt eigene Markierung. | | P2 | Bestehende Repos bekommen **keine automatische Art**; sie stehen auf „Art fehlt“, bis jemand sie von Hand setzt. | | P3 | Gitea bleibt erlaubt. Wer ein Repo in Gitea anlegt, bekommt eine **Mail** (Muster Push-Zeitmail) mit Link in den Zuordnungs-Ablauf. | | P4 | Der Ablauf gilt **auch** für den Mail-Link, **mit WOMS-Login** (inkl. 2FA). | | P5 | Ablauf: Art → Für einen Kunden? → Kunde → Ticket (vorhandenes oder neu) → Abschließen. Ein neues Ticket entsteht **erst beim Abschließen**. | | P6 | Bereich „Services“ = Variante **B**: Katalog + Projektlisten je Art. Funktionen werden **nur am Projekt** geschaltet. | | P7 | Jetzt nur das Gerüst und als Funktion „Website-Analyse“ (Status *In Entwicklung*). Weitere Funktionen fragt Claude am Ende ab. | ## 1. Datenmodell und Erkennung **`websiteProjects` – neue Attribute** (Schema-Skript `scripts/projektarten-setup.mjs`, idempotent, Muster `portal-setup.mjs`): - `kind` (string 20, optional): `website` | `webapp` | `app` | `migration` | `automation` | `other`; leer = Art fehlt - `forCustomer` (boolean, optional; leer = noch nicht beantwortet) - `kindSetBy` (string 64), `kindSetAt` (ISO-String) - `createdByGitea` (string 64): Gitea-Login der anlegenden Person (für die Mail) - `assignMailSentAt`, `assignReminderSentAt` (ISO-Strings) `projectType` (preview/website/template/repo) bleibt unverändert und regelt weiter nur das Hosting. **Katalog** `server/services/projectKinds.js` (einzige Quelle der Wahrheit): ```js KINDS = [ { key: 'website', label: 'Website', preview: 'yes', features: ['analyse'], description: '…' }, { key: 'webapp', label: 'Web-App', preview: 'possible', features: [], … }, { key: 'app', label: 'App', preview: 'no', … }, { key: 'migration', label: 'Migration/Umzug', preview: 'no', ticketType: 'Migration', … }, { key: 'automation', label: 'Automation/Skript', preview: 'no', … }, { key: 'other', label: 'Sonstiges', preview: 'no', … }, ] FEATURES = { analyse: { label: 'Website-Analyse', status: 'in_development' } } ``` Ausgeliefert über `GET /api/admin/services` (Admin-JWT wie die anderen WOMS-Aufrufe). WOMS hat keine eigene Kopie. **Erkennung neuer Repos** 1. Org-Webhook WEBklar (Hook 112) bekommt zusätzlich das Ereignis `repository` (created). Der Handler in `server/routes/webhook/gitea.js` legt das Projekt-Dokument an (`upsertWebsiteProjectByRepo`), setzt `createdByGitea = sender.login` und stößt die Mail an. `deleted` wird ignoriert (Verhalten wie heute). 2. Job alle 10 Minuten in `server/index.js`: `importNewRepos()` (dieselbe Funktion wie „Suche neue Repos“) findet Repos in persönlichen Konten. `createdByGitea` = Repo-Owner (bei Org-Repos ohne Hook-Ereignis leer ⇒ keine Mail, erscheint nur in „Art fehlt“). 3. **Nur neu angelegte** Projekt-Dokumente lösen eine Mail aus (Dokument in diesem Lauf erzeugt **und** Repo `created_at` jünger als 24 h). Beim ersten Lauf nach dem Livegang entsteht so keine Mail-Welle. 4. Empfänger = Mitarbeiter, dessen Kürzel/Anzeigename zum Gitea-Login passt (`findEmployeeForPusher` aus `pushTimeMail.js` wiederverwenden). Kein Treffer ⇒ keine Mail, Log-Zeile. 5. Mail (neue Staff-Vorlage **T16 „Neues Repo zuordnen“**, Stil wie T15): Repo-Name, Gitea-Link, wer, wann, Knopf „Jetzt zuordnen“ ⇒ `https://ticket.webklar.com/projects/zuordnen/`. 6. Erinnerung: 1× nach 24 h, falls `kind` noch leer (derselbe 10-Minuten-Job). Danach nichts mehr. ## 2. Zuordnungs-Ablauf (WOMS) Route **`/projects/zuordnen/:id`** (ProtectedRoute, also WOMS-Login + 2FA). Kopf: Repo-Name, Gitea-Link, angelegt von/am. Schritte mit „Zurück“/„Weiter“: 1. **Was ist das?** sechs Knöpfe aus dem Katalog. 2. **Für einen Kunden?** Ja / Nein (internes Projekt ⇒ weiter zu 5). 3. **Welcher Kunde?** Suche über Kunden; „Neuer Kunde“ öffnet das vorhandene Kunden-Formular und kehrt mit dem neuen Kunden zurück. 4. **Welches Ticket?** offene Tickets (Status ≠ Closed/Cancelled) dieses Kunden, oder „Neues Ticket anlegen“ mit vorausgefüllten, änderbaren Feldern: Thema „ – “, Ticket-Art `Migration` bei Art Migration sonst `Webpage`, Angefragt von = Ansprechpartner des Kunden, Start heute, Details = Repo-Link. 5. **Zusammenfassung + „Abschließen“.** Bei Art Website mit Kunde: Preview-Schalter an, Subdomain-Vorschlag aus dem Repo-Namen (änderbar, Prüfung wie heute). **Abschließen** = ein Aufruf `POST /api/admin/website-projects/:id/zuordnen` `{ kind, forCustomer, customerId?, ticketId? | newTicket?, preview?: { subdomain } }`. Der Server: 1. prüft Eingaben (Art aus Katalog, Kunde existiert, Ticket gehört zum Kunden und ist offen); 2. legt ggf. das Ticket an (neue Funktion `createTicketForProject` in `ticketAdmin.js`, Felder wie das WOMS-Formular); 3. ruft `assignProject(projectId, { customerId, ticketId })` (Umzug in die Org, Pushes nachtragen); 4. setzt `kind`, `forCustomer`, `kindSetBy` (Mitarbeiter aus dem JWT), `kindSetAt`; 5. bei Website + Preview: `updateWebsiteProject(id, { subdomain, projectType: 'preview' })`. Scheitert Schritt 3 nach einem neu angelegten Ticket, wird das Ticket wieder gelöscht (kein leeres Ticket). Antwort `{ ticketId }` ⇒ WOMS springt ins Ticket. Weitere Einstiege: - WOMS „Neues Repo anlegen“ (Projekte): nach Name/Vorlage direkt weiter in diesen Ablauf. - Ticket ⇒ „Projekt zuweisen“: Kunde/Ticket bekannt; fehlt die Art, fragt ein kleiner Dialog nur Schritt 1. - Bereits zugeordnet (`kind` gesetzt) ⇒ Seite zeigt „Bereits erledigt von am “ mit Link zum Ticket; Art bleibt dort änderbar. ## 3. Bereich „Services“ (WOMS) Menüpunkt **„Services“** neben „Projekte“, Route `/services`. Daten: `GET /api/admin/services` liefert Katalog + Projekte gruppiert nach `kind` (Repo, Kunde, Ticket, Preview-URL, Funktionszustände). - Eine Karte je Art: Name, Beschreibung, Anzahl, **mögliche Funktionen** mit Status (Website-Analyse: *In Entwicklung*), **Projekte dieser Art** als Liste (Klick ⇒ Ticket bzw. Projekt). - Karte **„Art fehlt“**: alle Repos ohne `kind`, je mit Knopf „Zuordnen“ ⇒ Ablauf aus Abschnitt 2. - Kein Umschalten hier. Umschalten der Funktionen kommt mit Teilprojekt 3 **am Projekt** (Ticket ⇒ Projekte). - Kundenportal: Tab „Funktionen“ zeigt dem Kunden nur Funktionen, die laut Katalog zur Art seines Projekts passen (Anbindung an die Funktionen-Spec, sobald diese live ist). ## Fehlerfälle - Gitea-Login ohne passenden Mitarbeiter ⇒ keine Mail, Projekt steht in „Art fehlt“. - SMTP-Fehler ⇒ `assignMailSentAt` bleibt leer, nächster Job-Lauf versucht es erneut (höchstens 3 Versuche). - Zwei Personen schließen gleichzeitig ab ⇒ zweiter Aufruf bekommt 409 „bereits zugeordnet“. - Appwrite nicht erreichbar ⇒ Job überspringt den Lauf, keine Teil-Zustände. ## Tests - Unit (Portal, `node --test`): Katalog, Eingabeprüfung, Mail-Auswahl „nur neue Repos“, Erinnerung, Rückbau des Tickets bei Fehler, 409 bei Doppel-Abschluss. - WOMS (vitest): Schritt-Logik des Ablaufs, Vorbelegung des neuen Tickets. - Playwright gegen Fixture-Daten: Ablauf komplett (intern, Kunde + vorhandenes Ticket, Kunde + neues Ticket), Services-Seite. - Live-Test mit dem Nutzer: Repo in Gitea anlegen ⇒ Mail ⇒ Ablauf ⇒ Ticket/Preview prüfen; danach aufräumen. ## Livegang (je Schritt mit OK des Nutzers) L1 Schema-Skript · L2 Portal pushen (main) · L3 Hook 112 um `repository` erweitern · L4 WOMS pushen (test) · L5 Live-Test mit dem Nutzer · danach erst Teilprojekt 2. ## Nicht Teil dieser Spec Preview-Modi/Dev-Server (Teilprojekt 2), Analyse und deren Rechtstexte (Teilprojekt 3), weitere Funktionen im Katalog (werden am Ende beim Nutzer abgefragt), Umbenennen/Abschaffen von `projectType`.