Files
Webklar-Kundenbereich/docs/superpowers/specs/2026-09-30-projektarten-services-design.md
T

144 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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/<projektId>`.
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 „<Art> – <Repo-Name>“, 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 <Name> am <Datum>“ 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`.