Spec: Projektarten, Zuordnungs-Ablauf und Bereich Services
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b45108c1de
commit
7a4af8e3c8
1 file changed
+143
@@ -0,0 +1,143 @@
|
||||
# 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`.
|
||||
Reference in new issue
Block a user