Zum Hauptinhalt springen
Hilfecenter

Leitfaden für Coding-Agenten (Vibe Coding)

Was ein KI-Coding-Agent wissen muss, bevor er eine Anwendung gegen die teamspace-API baut: Grundregeln für jede Anwendung und Hinweise je Aufgabe – Zeiten erfassen, offene Punkte bearbeiten, Projektauswertungen anzeigen, React-Anwendungen ausliefern und testen.

Diese Seite ist die Quelle für Coding-Agenten, die im Auftrag eines Menschen eine Anwendung gegen die teamspace-API bauen. Oben stehen die Regeln, die für jede Anwendung gelten. Darunter folgen Hinweise je Aufgabe: Zeiten erfassen, offene Punkte bearbeiten, Projektauswertungen anzeigen. Die Angaben sind am 2026-09-10 an einem Testmandanten mit Version 2026.3 geprüft oder stammen aus Anwendungen, die gegen einen echten Server gelaufen sind. Was noch offen ist, steht dabei.

Bevor du anfängst

Quellen, in dieser Reihenfolge:

  1. Diese Seite. Sie sagt, wie die API sich tatsächlich verhält, auch dort, wo die Beschreibung schweigt.
  2. <server>/api/openapi.json (ab Version 26.2, ohne Anmeldung): Adressen, Filter und Felder. Die Datei ist über 1 MB groß. Werte gezielt die Pfade aus, die du brauchst, statt sie ganz zu lesen. Filter, die nicht im Schema des Objekts stehen, sind eigene Felder eines Mandanten. Verwende sie nicht.
  3. <server>/api/api/dto.ts: dieselben Objekte kompakt als TypeScript-Klassen, teils mit Kommentaren.
  4. <server>/api/<collection>/meta und …/meta/template (mit Anmeldung): erlaubte Methoden, Filter mit Typ und die Vorlage für neue Objekte samt gültigen Werten.
  5. Die Anleitungen im Thema API, etwa Zeiten über die API anzeigen und buchen und Aufbau der API-Adressen (URL-Struktur).

Was du den Benutzer fragst:

  • Server-Adresse: die Adresse, unter der er teamspace im Browser öffnet. Steht im Auftrag nur ein Platzhalter wie <Server-Adresse>, frag nach. Nimm nie die Angabe servers aus der OpenAPI-Beschreibung, dort kann eine ganz andere Adresse stehen.
  • Geräte-ID und Token gibt der Benutzer erst in der fertigen Anwendung ein. Bitte ihn, sie dir nicht in den Chat zu schreiben und nicht auf Bildschirmfotos zu zeigen.
  • Fachbegriffe ohne eigenes Feld, etwa „Projektleiter“ oder „Budget“. Was damit gemeint ist, legt der Benutzer fest. Siehe Wenn du Projektauswertungen anzeigen willst.
  • Den Rahmen: nur lesen oder auch schreiben, wo die Anwendung laufen soll, welche Bibliotheken erlaubt sind.

Feldnamen, Pflichtfelder und gültige Werte fragst du nicht ab. Sie stehen hier, in meta/template oder in der optionsUrl eines Feldes. Geht eine Angabe aus keiner Quelle hervor, frag nach, statt sie zu erfinden.

Was für jede Anwendung gilt

Anmeldung

  • Angemeldet wird mit einem Gerätepasswort: Persönliche Einstellungen → Geräte → Neues Gerätepasswort. Der Benutzer braucht dafür die Berechtigung „Synchronisation“.
  • Jede Anfrage schickt Authorization: Basic <base64(Geräte-ID:Token)>. Das Login-Passwort verwendest und speicherst du nie.
  • Einen Endpunkt „aktueller Benutzer“ gibt es nicht. Den angemeldeten Mitarbeiter liefert GET <server>/api/device/<Geräte-ID>;depth=1 im Feld user, seine ID steht in user.value. Klappt dieser Aufruf, gilt der Token.
  • externalAccess: true heißt: Das Gerät gehört einem externen Kontakt, nicht einem Mitarbeiter.
  • Über die API hat der Benutzer genau die Rechte aus der Oberfläche. Das gilt auch für eine Anwendung, die nur liest: Ihr Token könnte alles, was der Benutzer darf.

Listen und Antworten

  • Aufbau: <server>/api/<collection>;<matrix>?<query>. Steuerung mit Semikolon am Pfad (;limit=100;depth=1), Filter hinter dem Fragezeichen (?date=2026-06-01..2026-06-30&project=123,456).
  • Seiten: höchstens 100 Einträge je Abruf, size ist die Gesamtzahl. Blättere mit ;offset=, oder folge in _links dem Eintrag > nextPage, bis es keinen mehr gibt. Ohne Blättern fehlen Daten, ohne dass es auffällt.
  • Leere Listen kommen als "items": null, nicht als []. Behandle null als leere Liste.
  • ;depth=1: Einträge einer Liste bleiben Link-Objekte, die Felder stehen unter data. Ohne depth gibt es nur caption, href und value.
  • Fehlende Felder: Felder ohne Wert können ganz fehlen statt null zu sein, am Projekt zum Beispiel plannedMinutes. Prüf auf beides.
  • Voreinstellungen: Manche Listen filtern ohne Angabe. /api/project liefert nur aktive Projekte ohne Vorlagen, /api/time Projektzeiten und Entwürfe. Die tatsächlich angewandten Filter zeigt _url in der Antwort.
  • Filter: = gleich, *= enthält, von..bis Bereich einschließlich beider Grenzen, A,B mehrere Werte. Ob ein Filter einen Bereich erlaubt, zeigt searchableRange in meta.
  • Aufzählungen wie Belegstatus oder Zahlungsstatus kommen mit technischem value und lesbarer caption, etwa "value": "OPEN_AUTO", "caption": "Offen (auto)". Zeig die caption an.
  • Gültige Werte: Auswahlfelder tragen eine optionsUrl. Für neue Objekte findest du sie in <server>/api/<collection>/meta/template. Übernimm die Adresse, bau sie nicht selbst.
  • ;evaluate=isBookable filtert nicht, sondern ergänzt jeden Eintrag um evaluation: true/false. Zum Filtern nimmst du ?isBookable=true.
  • Zeitstempel: begin und end kommen in UTC (2026-09-10T08:00:00.000+00:00). Andere Felder weichen ab, createDate eines offenen Punkts etwa kommt als 2011-02-22 10:16:59.0.

Schreiben

  • Verknüpfungen schreibst du als reine ID ("project": 4711) oder als { "value": 4711 }.
  • Zum Ändern lädst du das Objekt per GET und schickst es vollständig mit dem geänderten Feld per PUT an die Adresse des einzelnen Elements zurück.
  • Fehlt beim Anlegen ein Pflichtfeld, antwortet der Server mit 403 und nennt es in message.
  • Frag den Benutzer, bevor die Anwendung etwas mit Folgen schreibt.

Sicherheit

  • Nur https://-Adressen zulassen.
  • Geräte-ID und Token nie in den Quelltext. Dauerhaft speichern nur, wenn der Benutzer „Angemeldet bleiben“ wählt.
  • Serverdaten immer als Text ausgeben (textContent), nie als HTML. Ticket-Beschreibungen enthalten zum Beispiel HTML.
  • Verweisen aus Server-Antworten (href, optionsUrl, _links) nur folgen, wenn sie auf die eigene Server-Adresse zeigen. Sonst gehen die Zugangsdaten an eine fremde Adresse.
  • Keine Skripte von fremden Servern laden.
  • Bei Fehlern message anzeigen, nie stacktrace.
  • Dem Benutzer empfehlen, für die Anwendung ein eigenes Gerätepasswort anzulegen und es nach Tests oder bei Verdacht zu widerrufen.

Mehr dazu in Eigene Web-Anwendungen sicher bauen.

Browserzugriff

Eine Anwendung im Browser darf die API direkt aufrufen, ein eigener Proxy ist nicht nötig. Der Server erlaubt jede Herkunft und den Header Authorization. Die erlaubten Methoden hängen an der Adresse: an Listen wie /api/time GET und POST, an einzelnen Elementen wie /api/issue/{id} GET, PUT und DELETE. Schick die Anmeldung im Header, nicht über Cookies.

Fehlerbilder

StatusFormBedeutungWas die Anwendung tut
401reiner TextGeräte-ID oder Token falsch, Gerät gelöschtAnmeldung neu abfragen
403JSON mit messagePflichtfeld fehlt, Datum außerhalb der Schreibberechtigung, fehlende Rechte; auch beim Abruf eines gelöschten Eintragsmessage anzeigen, Eingaben behalten
405JSON mit messageMethode an dieser Adresse nicht erlaubt oder ungültige ID in der AdresseMethode und Adresse prüfen
500Text oder JSONFehler im Server, etwa meta ohne Anmeldung oder der Filter ?type= an issuenicht wiederholen, Anfrage vereinfachen

Module der Oberfläche und Collections

Die API spricht von Collections, der Benutzer von Modulen. Verwechsle sie nicht: „Offene Punkte“ sind issue, nicht ticket.

OberflächeCollectionWichtigIm Hilfecenter
Zeiterfassung, ProjektzeitentimePflicht beim Buchen: date, project, area, fieldProjektzeiten buchen
Rubrik und Bereichtimecategoryan der Buchung als area und field, Werte über optionsUrlProjektzeiten buchen
Offene Punkteissueerledigt ist, was ein Erledigt-Datum hatEinführung in die Offenen Punkte
TicketsticketStatus aus ticketstate, Beschreibung enthält HTMLEinführung ins Ticketsystem
ProjekteprojectPlan- und Ist-Werte, Unterprojekte über mainProjectEinführung ins Projektmanagement
Projektrollen, Projektberechtigungenprojectrole, project/{id}/projectpermissionProjektleitung über die Rolle mit responsibleEinführung ins Projektmanagement
RechnungeninvoiceFeld project, aber kein Filter danachRechnungen stellen und Zahlungen buchen
MitarbeiteruserID für worker und assigneeEinführung in Personal & HR
GerätepasswortdeviceAnmeldung, Besitzer in userAuthentifizieren

Wenn du Zeiten erfassen willst

  1. Mitarbeiter: GET <server>/api/device/<Geräte-ID>;depth=1, dann user.value.
  2. Projekte: GET <server>/api/project;sort=name?isBookable=true&isActive=true&isTemplate=false&isDraft=false.
  3. Rubrik und Bereich: GET <server>/api/time/meta/template, dann die optionsUrl von area und field aufrufen. Zeig die caption zur Auswahl, gebucht wird der value.
  4. Zeiten eines Tages: GET <server>/api/time;depth=1?worker=<id>&date=YYYY-MM-DD. Die Tagessumme ist die Summe von data.amount über alle Einträge mit draftStatus NORMAL. amount, begin und end können null sein. Nach begin sortiert die App selbst.
  5. Buchen: POST <server>/api/time mit date, project, area, field, amount (Minuten) und, wenn gemessen, begin und end. worker darfst du weglassen, dann gilt der Besitzer des Geräts.

Worauf du achten musst:

  • amount immer mitschicken. Der Server berechnet die Dauer nicht aus Beginn und Ende. Ohne amount entsteht eine Buchung ohne Dauer.
  • Fehlende Pflichtfelder meldet der Server mit 403 und „Project is missing!“, „ActivityArea is missing!“ oder „ActivityField is missing!“. Fehlt date oder liegt es außerhalb des erlaubten Zeitraums: „Das Datum liegt außerhalb Ihrer Schreibberechtigungen“.
  • Weitere Pflichtfelder kann eine Installation verlangen, etwa die Beschreibung. Nennt der Auftrag solche Felder, mach sie in der Anwendung zur Pflicht. Zeig die message des Servers trotzdem in jedem Fall an.
  • Erfolg ist 201. Die Antwort enthält die angelegte Buchung, der Header Location ihre Adresse.
  • Minuten anzeigen: Rechne erst bei der Anzeige in Stunden um. Eine Buchung von 2 Minuten darf nicht als „0 Std.“ erscheinen.
  • Eine Stoppuhr gibt es in der API nicht. Die App merkt sich den Beginn selbst, je Mitarbeiter, und bucht beim Stopp.

Beispiele für jede Anfrage und Antwort stehen in Zeiten über die API anzeigen und buchen.

Wenn du offene Punkte liest oder bearbeitest

  1. Eigene offene Punkte nach Fälligkeit: GET <server>/api/issue;depth=1;sort=duedate?assignee=<id>&isDone=false.
  2. Felder unter data: subject (Betreff), description, type, duedate (Fälligkeit), donedate (Erledigt-Datum), progress (Prozent), priority (in der Oberfläche 1 niedrig bis 9 sehr hoch), state (Status als Freitext), project, assignee. Viele davon können null sein.
  3. Typ: type.value ist einer von ISSUETYPE_TODO, ISSUETYPE_GOAL, ISSUETYPE_PROBLEM, ISSUETYPE_IDEA, ISSUETYPE_NOTE, ISSUETYPE_UNKNOWN. Anzeigen solltest du type.caption. Die Liste liefert <server>/api/enum/issueType, dort zählt die Groß- und Kleinschreibung. Die OpenAPI-Beschreibung nennt die Werte ohne das Präfix ISSUETYPE_.
  4. Überfällig ist ein Punkt mit duedate in der Vergangenheit und ohne donedate. Punkte ohne Fälligkeit sind nie überfällig. Soll ihre Position in der Liste feststehen, sortierst du in der App nach.
  5. Nach Typ filtern machst du in der App. Der Filter ?type= endete am Testmandanten mit 500, egal mit welchem Wert.

Erledigen: In der Oberfläche macht allein das Erledigt-Datum einen Punkt erledigt, der Fortschritt spielt dafür keine Rolle. Der Haken in der Oberfläche setzt Datum, Uhrzeit und 100 %, siehe Meine offenen Punkte: anlegen & abarbeiten. In der API heißt das Feld donedate, laut OpenAPI-Beschreibung im Format yyyy-MM-dd HH:mm:ss. Geändert wird mit PUT <server>/api/issue/<id>.

Bis das geprüft ist: Frag vor dem Erledigen nach, schick die Änderung und lade den Punkt danach neu. Steht dann ein donedate darin, hat es geklappt. Sonst zeigst du message an.

Wenn du Projektauswertungen anzeigen willst

Plan- und Ist-Werte

Ein Projekt trägt mehrere Plan/Ist-Paare. „Budget“ ist keines davon allein, der Benutzer muss festlegen, welches gemeint ist:

PaarPlanIst
Stunden (in Minuten)plannedMinutessumMinutes
abrechenbare Stunden (in Minuten)plannedMinutesBillablesumMinutesBillable
Leistungsstunden (in Minuten)plannedMinutesPerformancesumMinutesPerformance
ArbeitskostenplannedWorkingCostssumWorkingCosts
KostenplannedExpensessumExpenses
ErlöseplannedIncomesumIncome

Zu jedem Paar gibt es …Enabled und …Calculated, etwa plannedMinutesEnabled und plannedMinutesCalculated. Ist kein Planwert gepflegt, fehlt das Feld planned… in der Antwort ganz. Am Testmandanten war plannedMinutesCalculated an einem Hauptprojekt trotzdem gefüllt. Was genau darin steckt, ist noch nicht bestätigt, siehe die offenen Fragen unten.

Unterprojekte

  • sumMinutes enthält die Unterprojekte. Am Testmandanten ergab ein Hauptprojekt mit 210 eigenen Minuten ein sumMinutes von 2102, genau die Summe über alle Unterprojekte.
  • Der Filter project enthält sie nicht. /api/time?project=<Hauptprojekt> liefert nur die Zeiten, die direkt auf dem Hauptprojekt gebucht sind, /api/issue?project= ebenso.
  • Alle Projekte eines Baums liefert GET <server>/api/project?mainProject=<id>, das Hauptprojekt selbst eingeschlossen. Nur die direkten Kinder liefert ?parent=<id>. Der Matrix-Parameter ;parent= wirkt an Projekten nicht.
  • Für Auswertungen über den ganzen Baum gibst du alle IDs als Mengenfilter mit: ?project=<id1>,<id2>,<id3>. Das gilt für Zeiten, offene Punkte und Tickets.

Stunden je Mitarbeiter und Woche

GET <server>/api/time;depth=1?project=<IDs des Baums>&date=<von>..<bis>, mit Blättern bis zur letzten Seite. Gruppiere in der App nach data.worker.value und der Kalenderwoche von data.date, summiere data.amount der Einträge mit draftStatus NORMAL. Stimmt die Gesamtsumme mit sumMinutes des Hauptprojekts überein, sind Filter und Unterprojekte richtig.

Projektleitung

Ein Feld „Projektleiter“ gibt es nicht, und auch keinen Filter „Projekte, die ich leite“. Am Testmandanten lässt sich die Projektleitung so bestimmen:

  1. Rollen: GET <server>/api/projectrole;depth=1. Rollen mit data.responsible: true sind verantwortlich, am Testmandanten die Rolle „Verantwortlich“.
  2. Gruppen des Benutzers: GET <server>/api/user/<id>/usergroups.
  3. Berechtigungen je Projekt: GET <server>/api/project/<id>/projectpermission;depth=1. Jeder Eintrag nennt projectRole, userGroup und, wenn geerbt, inheritationFromProject. Leitet der Benutzer das Projekt, gibt es einen Eintrag mit einer verantwortlichen Rolle und einer seiner Gruppen.

Das ist eine Anfrage je Projekt. Stell sie parallel und lade nur die Projekte, die du wirklich anzeigen willst.

Offene Punkte und Tickets je Projekt

  • Offene Punkte: GET <server>/api/issue;depth=1?project=<IDs>&isDone=false.
  • Tickets: GET <server>/api/ticket;depth=1?project=<IDs>. Der Status in data.state ist ein Verweis auf /api/ticketstate mit caption, zum Beispiel „In Arbeit“. Die Status legt jede Installation selbst fest. Jeder trägt eine responsibility: INTERN, EXTERN oder NONE. Am Testmandanten hatten nur die geschlossenen Status („Erfolgreich geschlossen“, „Erfolglos geschlossen“) NONE. Welche Status als offen gelten, frag den Benutzer, bis das bestätigt ist.
  • Ticket-Beschreibungen enthalten HTML. Gib sie als Text aus oder lass sie weg.

Rechnungen

  • Rechnungen haben ein Feld project, lassen sich aber nicht nach Projekt filtern. Lade GET <server>/api/invoice;depth=1 seitenweise und filtere in der App auf data.project.value.
  • data.status ist der Belegstatus (zum Beispiel VALIDATED, „Validiert“), data.payStatus der Zahlungsstatus (zum Beispiel OPEN_AUTO, „Offen (auto)“). Zeig jeweils die caption.
  • data.payStatusOutstanding ist der offene Betrag, data.payStatusPayed der bezahlte, data.dueDate die Fälligkeit.

Wenn du eine React-Anwendung auslieferst

Diese Hinweise stammen aus einer Übersicht für Projektleiter, gebaut mit React und Vite.

  • Ein Doppelklick auf index.html funktioniert nicht. Vite erzeugt JavaScript-Module, und die laden Browser nicht über file://. Die Seite bleibt leer. Sag das dem Benutzer.
  • Lokal ansehen: npm run build, danach npm run preview im Projektordner. Das Terminal muss offen bleiben. „Verbindung abgelehnt“ im Browser heißt: Es läuft kein Server.
  • Klappt localhost nicht, hilft http://127.0.0.1:… oder den Server mit --host 127.0.0.1 starten.
  • Veröffentlichen: den Inhalt von dist/ auf einen beliebigen Webserver kopieren. Mit relativem Basispfad (base: './' in vite.config) läuft die Anwendung auch in einem Unterverzeichnis.
  • Nach jeder Änderung wieder npm run build und dist/ neu hochladen.

Wenn du testest

  • Du hast keine Zugangsdaten. Teste mit nachgebauten Daten und sag dem Benutzer, dass der erste Test gegen den echten Server bei ihm liegt. Dabei zeigen sich meist noch Abweichungen.
  • Bau aussagekräftige Fehlermeldungen ein: die angefragte Adresse ohne Zugangsdaten, den Statuscode und den Aufbau der Antwort mit Feldnamen und Typen, aber ohne Inhalte. Dann genügt dem Benutzer ein Bildschirmfoto, und du kannst den Fehler gezielt beheben.
  • Bau die nachgebauten Daten wie echte Antworten: Einträge als Link-Objekte mit data, leere Listen mit "items": null, fehlende Felder statt null.
  • Teste zwei Fälle: ein Projekt ohne Buchungen, Tickets und offene Punkte und eines mit Daten.
  • Vergleich Summen mit teamspace, etwa die gebuchten Stunden gegen sumMinutes oder die Angabe im Projekt. Stimmen sie, sind Filter und Unterprojekte richtig.

Noch offen: hier fragst du nach

Zu diesen Punkten gibt es noch keine bestätigte Antwort. Frag den Benutzer, statt eine Annahme einzubauen:

  • wie ein offener Punkt über die API erledigt wird, bis der Abschnitt oben geprüft ist
  • ob die Rolle mit responsible in jeder Installation die Projektleitung meint
  • welche Ticket-Status als offen gelten
  • welches Plan/Ist-Paar „Budget“ heißt, und was …Calculated enthält

Für Menschen: der Auftrag an die KI

Wer einen Coding-Agenten beauftragt, achtet auf fünf Dinge:

  • Die echte Server-Adresse eintragen. Ein stehengebliebener Platzhalter wie <Server-Adresse> wird leicht übersehen, dann kann die KI die Beschreibung der Installation nicht lesen.
  • Die Quellen nennen: diese Seite, <Server-Adresse>/api/openapi.json und <Server-Adresse>/api/api/dto.ts.
  • Zusätzliche Pflichtfelder nennen. Ohne date, project, area und field bucht der Server keine Zeit, das steht auf dieser Seite. Verlangt eure Installation mehr, etwa eine Beschreibung, gehört das in den Auftrag.
  • Fachbegriffe festlegen oder Nachfragen ausdrücklich erlauben.
  • Den Rahmen nennen: nur lesen oder auch schreiben, wo die Anwendung laufen soll, welche Bibliotheken erlaubt sind.

Vorlage für eine kleine Anwendung

Diese Vorlage stammt aus einer Zeiterfassungs-App, die als einzelne HTML-Datei entstanden ist. Ersetze alle Angaben in spitzen Klammern, bevor du den Auftrag abschickst:

Baue eine Web-Anwendung als einzelne HTML-Datei ohne externe Abhängigkeiten, die sich über die REST-API mit teamspace verbindet. <Was die Anwendung tun soll, in zwei bis drei Sätzen.>
Server-Adresse: <https://eure-installation> (die Adresse, unter der wir teamspace im Browser öffnen)
Lies zuerst den Leitfaden für Coding-Agenten unter https://help.teamspace.de/thema/api/coding-agenten/, dann <Server-Adresse>/api/openapi.json (nur die benötigten Pfade) und <Server-Adresse>/api/api/dto.ts. Verwende immer die eingegebene Server-Adresse, nicht die Angabe unter „servers“.
Anmeldung per Gerätepasswort (Geräte-ID und Token, Basic Auth).
Zusätzliche Pflichtfelder in unserer Installation: <z. B. Beschreibung bei Zeitbuchungen, sonst „keine“>.
Die Anwendung darf: <nur lesen | Zeiten buchen | offene Punkte erledigen>.
Anforderungen: nur https; Zugangsdaten nie im Code und nur nach Zustimmung speichern; Serverdaten immer als Text ausgeben; Fehlermeldungen des Servers anzeigen.
Frage nach, bevor du etwas annimmst, das nicht in den Quellen steht.

Für einen bestehenden Auftrag

Hast du schon einen Auftrag, reicht dieser Satz:

Lies vor dem Programmieren den Leitfaden für Coding-Agenten unter https://help.teamspace.de/thema/api/coding-agenten/ und die OpenAPI-Beschreibung unter <Server-Adresse>/api/openapi.json. Halte dich an die dort beschriebenen Adressen, Pflichtfelder und Regeln. Wenn eine Angabe nicht daraus hervorgeht, frage nach, statt sie zu erfinden.

Zugangsdaten gehören nicht in den Chat mit der KI und nicht auf Bildschirmfotos. Ist das doch passiert, widerruf das Gerätepasswort in den Persönlichen Einstellungen.

Verwandte Themen