[{"data":1,"prerenderedAt":3143},["ShallowReactive",2],{"/de-de/blog/modernize-java-with-cursor-and-gitlab":3,"navigation-de-de":2369,"banner-de-de":2795,"footer-de-de":2803,"blog-post-authors-de-de-Michael Friedrich":3044,"blog-related-posts-de-de-modernize-java-with-cursor-and-gitlab":3059,"blog-promotions-de-de":3081,"next-steps-de-de":3133},{"id":4,"title":5,"authors":6,"body":8,"category":2348,"date":2349,"description":2350,"extension":2351,"externalUrl":2352,"faq":2352,"featured":152,"heroImage":2353,"meta":2354,"navigation":152,"path":2355,"seo":2356,"slug":2361,"stem":2362,"tags":2363,"template":2367,"updatedDate":2352,"__hash__":2368},"blogPosts/de-de/blog/modernize-java-with-cursor-and-gitlab.md","Java mit Cursor und GitLab modernisieren",[7],"Michael Friedrich",{"type":9,"value":10,"toc":2323},"minimark",[11,16,20,23,39,42,45,48,70,73,77,98,241,245,292,297,300,315,356,363,370,373,384,387,393,397,400,411,418,424,427,436,440,443,449,456,462,465,471,474,477,490,493,496,505,509,518,527,567,633,644,650,653,656,660,668,674,677,680,696,703,709,712,718,721,730,733,739,746,752,755,758,764,767,784,787,793,812,822,826,829,835,842,848,851,857,872,876,879,885,888,894,898,901,905,925,939,945,951,955,960,970,980,1352,1356,1373,1570,1573,1577,1586,1595,1603,2272,2276,2279,2282,2285,2319],[12,13,15],"h2",{"id":14},"warum-java-modernisierung-mehr-als-ein-task-ist","Warum Java-Modernisierung mehr als ein Task ist",[17,18,19],"p",{},"\"Java 8 auf Java 21 modernisieren\" klingt nach einer einzigen Aufgabe, ist es aber nicht. Es betrifft den Build, die Runtime, Abhängigkeiten, APIs, Nebenläufigkeit, Tests, Container und das Produktionsverhalten, oft alles gleichzeitig. Wer einen Agenten bittet, das alles in einem einzigen Prompt zu erledigen, bekommt einen riesigen Merge Request, den niemand sicher reviewen kann.",[17,21,22],{},"Cursor, ein KI-Coding-Agent, ist im fokussierten Teil dieses Problems stark. Bekommt er einen einzelnen fehlschlagenden Test oder ein abgegrenztes Issue, kann er die Implementierung untersuchen, erklären, was schiefging, einen Fix vorschlagen und die Tests ausführen, ohne aus dem Entwicklungsfluss zu reißen. Was er nicht allein entscheiden kann, ist, was \"sicher\" über eine mehrstufige Migration hinweg bedeutet.",[17,24,25,26,32,33,38],{},"Genau hier kommt GitLab ins Spiel: Die ",[27,28,31],"a",{"href":29,"rel":30},"https://about.gitlab.com/de-de/gitlab-duo-agent-platform/",[],"Duo Agent Platform"," orchestriert KI-Workflows im übrigen Software-Lebenszyklus und ist darauf ausgelegt, die Arbeit von Coding-Agenten zu zertifizieren. Die Issue-Hierarchie mit Epics macht den Plan dauerhaft und reviewbar. Der GitLab-Model-Context-Protocol-Server (",[27,34,37],{"href":35,"rel":36},"https://about.gitlab.com/topics/ai/model-context-protocol/",[],"MCP",") bringt den Kontext aus dem Entwicklungszyklus nach Cursor. CI/CD, Security-Scanning, Code-Review, Impact-Analyse und ein serviceübergreifender Test liefern die Belege, die es braucht, bevor sich das Produktionsverhalten ändert.",[17,40,41],{},"Der Nutzen steht damit fest: eine Migration, der ein Team vertrauen kann. Jede Änderung ist abgegrenzt, reviewt, gegen Java 8 und Java 21 getestet und bis zu einem Work Item mit den zugehörigen Entscheidungen und Belegen zurückverfolgbar. Cursor übernimmt die Implementierung, GitLab liefert den Nachweis. Eine bestehende Java-8-Codebasis wird nicht dadurch sicherer zu modernisieren, dass ein Agent den Code schreibt, sondern dadurch, dass jede Änderung abgegrenzt, reviewt, gegen beide Java-Versionen getestet und nachvollziehbar ist.",[17,43,44],{},"Angesprochen sind damit Teams, die auf einer bestehenden Java-8-Codebasis sitzen und agentisches Tempo nutzen wollen, ohne Governance, Review und Nachvollziehbarkeit aufzugeben. Cursor arbeitet schnell innerhalb einer abgegrenzten Aufgabe. Code Review Flow, Developer Flow, CI/CD, Code-Owner-Freigaben und Impact-Analyse sind das, was dieses Tempo sicher macht. Sie sind keine optionalen Kontrollpunkte, sondern der Mechanismus, der jeden von einem Agenten erzeugten Merge Request an denselben Maßstab hält wie jeden anderen.",[17,46,47],{},"Das Folgende ist die praktische Umsetzung: drei aufeinander aufbauende Use Cases, die zeigen, wie sich das Schritt für Schritt in Cursor und GitLab durchführen lässt.",[49,50,51,58,64],"ol",{},[52,53,54],"li",{},[27,55,57],{"href":56},"#einen-fehlschlagenden-end-to-end-test-mit-cursor-beheben","Einen fehlschlagenden End-to-End-Test mit Cursor beheben",[52,59,60],{},[27,61,63],{"href":62},"#quality-gates-zur-java-21-modernisierung-vorbereiten","Quality-Gates zur Java-21-Modernisierung vorbereiten",[52,65,66],{},[27,67,69],{"href":68},"#das-http-connection-handling-mit-java-21-modernisieren","Das HTTP-Connection-Handling mit Java 21 modernisieren",[17,71,72],{},"Die Reihenfolge hat einen Grund: klein anfangen, Projektkontext ergänzen, dann eine Grenze modernisieren.",[12,74,76],{"id":75},"die-demo-umgebung-aus-java-collector-und-rust-backend","Die Demo-Umgebung aus Java-Collector und Rust-Backend",[17,78,79,80,85,86,91,92,97],{},"Für alle drei Use Cases nutzen wir den ",[27,81,84],{"href":82,"rel":83},"https://gitlab.com/gitlab-da/demo-environments/tanuki-iot-platform/sensors/java-http-metrics-collector",[],"Java HTTP Metrics Collector aus der Tanuki IoT Platform",". Er prüft HTTP-Endpunkte, erfasst Metriken wie Antwortstatus und Timing und schickt die Messwerte an sein ",[27,87,90],{"href":88,"rel":89},"https://gitlab.com/gitlab-da/demo-environments/tanuki-iot-platform/backend/rust-metrics-store",[],"Rust-Metrics-Backend",". Das gibt uns eine sichtbare Anwendungsgrenze zum Modernisieren und einen echten Backend-Vertrag zum Verifizieren. Das Rust-Backend haben wir vor einiger Zeit im ",[27,93,96],{"href":94,"rel":95},"https://about.gitlab.com/de-de/blog/fix-bugs-with-codex-and-gitlab/",[],"Tutorial zu Codex und GitLab"," entwickelt, und es fügt sich nun in die Produktionsarchitektur ein:",[99,100,105],"pre",{"className":101,"code":102,"language":103,"meta":104,"style":104},"language-mermaid shiki shiki-themes github-light","flowchart LR\n  subgraph sources[\"HTTP metric sources\"]\n    direction TB\n    health[\"Health endpoint\"]\n    maintenance[\"Maintenance endpoint\"]\n  end\n\n  java[\"Java HTTP metrics collector\"]\n  rust[(\"Rust metrics-store backend\")]\n\n  java -->|\"GET\"| health\n  java -->|\"GET\"| maintenance\n  java -->|\"POST /api/metrics\"| rust\n  rust -->|\"HTTP response\"| java\n\n  classDef source fill:#f8fafc,stroke:#64748b,stroke-width:2px,color:#0f172a\n  classDef focus fill:#dcfce7,stroke:#16a34a,stroke-width:3px,color:#0f172a\n  classDef backend fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0f172a\n\n  class health,maintenance source\n  class java focus\n  class rust backend\n","mermaid","",[106,107,108,117,123,129,135,141,147,154,160,166,171,177,183,189,195,200,206,212,218,223,229,235],"code",{"__ignoreMap":104},[109,110,113],"span",{"class":111,"line":112},"line",1,[109,114,116],{"class":115},"sgsFI","flowchart LR\n",[109,118,120],{"class":111,"line":119},2,[109,121,122],{"class":115},"  subgraph sources[\"HTTP metric sources\"]\n",[109,124,126],{"class":111,"line":125},3,[109,127,128],{"class":115},"    direction TB\n",[109,130,132],{"class":111,"line":131},4,[109,133,134],{"class":115},"    health[\"Health endpoint\"]\n",[109,136,138],{"class":111,"line":137},5,[109,139,140],{"class":115},"    maintenance[\"Maintenance endpoint\"]\n",[109,142,144],{"class":111,"line":143},6,[109,145,146],{"class":115},"  end\n",[109,148,150],{"class":111,"line":149},7,[109,151,153],{"emptyLinePlaceholder":152},true,"\n",[109,155,157],{"class":111,"line":156},8,[109,158,159],{"class":115},"  java[\"Java HTTP metrics collector\"]\n",[109,161,163],{"class":111,"line":162},9,[109,164,165],{"class":115},"  rust[(\"Rust metrics-store backend\")]\n",[109,167,169],{"class":111,"line":168},10,[109,170,153],{"emptyLinePlaceholder":152},[109,172,174],{"class":111,"line":173},11,[109,175,176],{"class":115},"  java -->|\"GET\"| health\n",[109,178,180],{"class":111,"line":179},12,[109,181,182],{"class":115},"  java -->|\"GET\"| maintenance\n",[109,184,186],{"class":111,"line":185},13,[109,187,188],{"class":115},"  java -->|\"POST /api/metrics\"| rust\n",[109,190,192],{"class":111,"line":191},14,[109,193,194],{"class":115},"  rust -->|\"HTTP response\"| java\n",[109,196,198],{"class":111,"line":197},15,[109,199,153],{"emptyLinePlaceholder":152},[109,201,203],{"class":111,"line":202},16,[109,204,205],{"class":115},"  classDef source fill:#f8fafc,stroke:#64748b,stroke-width:2px,color:#0f172a\n",[109,207,209],{"class":111,"line":208},17,[109,210,211],{"class":115},"  classDef focus fill:#dcfce7,stroke:#16a34a,stroke-width:3px,color:#0f172a\n",[109,213,215],{"class":111,"line":214},18,[109,216,217],{"class":115},"  classDef backend fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0f172a\n",[109,219,221],{"class":111,"line":220},19,[109,222,153],{"emptyLinePlaceholder":152},[109,224,226],{"class":111,"line":225},20,[109,227,228],{"class":115},"  class health,maintenance source\n",[109,230,232],{"class":111,"line":231},21,[109,233,234],{"class":115},"  class java focus\n",[109,236,238],{"class":111,"line":237},22,[109,239,240],{"class":115},"  class rust backend\n",[12,242,244],{"id":243},"voraussetzungen","Voraussetzungen",[49,246,247,255,263,266,269,278],{},[52,248,249,254],{},[27,250,253],{"href":251,"rel":252},"https://cursor.com/de/",[],"Cursor"," installiert und konfiguriert. In diesem Tutorial nutzen wir die Cursor-IDE.",[52,256,257,258,262],{},"Ein GitLab-Projekt mit dem Quellcode des Java-Collectors, Issues und Modernisierungs-Work-Items. Nutzen lässt sich der ",[27,259,261],{"href":82,"rel":260},[],"Java HTTP Metrics Collector der Tanuki IoT Platform",".",[52,264,265],{},"Java 8 für den ersten Use Case und Java 21 für die Modernisierungsarbeit",[52,267,268],{},"Maven, Docker und Docker Compose für lokale Builds und funktionale Tests",[52,270,271,272,277],{},"Der ",[27,273,276],{"href":274,"rel":275},"https://docs.gitlab.com/user/model_context_protocol/mcp_server/",[],"GitLab-MCP-Server",", aktiviert auf der GitLab-Instanz oder der Top-Level-Gruppe",[52,279,280,285,286,291],{},[27,281,284],{"href":282,"rel":283},"https://docs.gitlab.com/user/duo_agent_platform/flows/foundational_flows/code_review/",[],"GitLab Duo Code Review Flow",", ",[27,287,290],{"href":288,"rel":289},"https://docs.gitlab.com/user/duo_agent_platform/flows/foundational_flows/developer/",[],"Developer Flow"," und ein Custom Flow für die Impact-Analyse bei Breaking Changes (siehe Abschnitt \"Tipps für Cursor und GitLab\"), aktiviert für das Java-Collector-Projekt. Diese Flows wenden die Projekt-Guardrails auf jeden Merge Request an, den der Agent erstellt.",[293,294,296],"h3",{"id":295},"das-gitlab-projekt-vorbereiten","Das GitLab-Projekt vorbereiten",[17,298,299],{},"Um den Workflow in der eigenen Umgebung nachzuvollziehen, zunächst das Projekt importieren, klonen und in Cursor öffnen:",[49,301,302,309,312],{},[52,303,304,305,308],{},"Den ",[27,306,261],{"href":82,"rel":307},[]," in die eigene GitLab-Umgebung importieren, samt aller offenen Issues.",[52,310,311],{},"Das Projekt in die lokale Umgebung klonen und hineinwechseln.",[52,313,314],{},"Das Projekt in Cursor öffnen.",[99,316,320],{"className":317,"code":318,"language":319,"meta":104,"style":104},"language-shell shiki shiki-themes github-light","git clone https://gitlab.com/gitlab-da/demo-environments/tanuki-iot-platform/sensors/java-http-metrics-collector.git\ncd java-http-metrics-collector\n\ncursor .\n","shell",[106,321,322,335,344,348],{"__ignoreMap":104},[109,323,324,328,332],{"class":111,"line":112},[109,325,327],{"class":326},"s7eDp","git",[109,329,331],{"class":330},"sYBdl"," clone",[109,333,334],{"class":330}," https://gitlab.com/gitlab-da/demo-environments/tanuki-iot-platform/sensors/java-http-metrics-collector.git\n",[109,336,337,341],{"class":111,"line":119},[109,338,340],{"class":339},"sYu0t","cd",[109,342,343],{"class":330}," java-http-metrics-collector\n",[109,345,346],{"class":111,"line":125},[109,347,153],{"emptyLinePlaceholder":152},[109,349,350,353],{"class":111,"line":131},[109,351,352],{"class":326},"cursor",[109,354,355],{"class":330}," .\n",[17,357,358,359,362],{},"Das Projekt enthält eine ",[106,360,361],{},"AGENTS.md","-Datei mit Repository-Anweisungen und Maven-Befehlen. Cursor kann diese lokalen Anweisungen nutzen, um zu verstehen, wie das Projekt organisiert ist und wie Änderungen getestet werden sollen.",[17,364,365],{},[366,367],"img",{"alt":368,"src":369},"Der Java HTTP Metrics Collector in Cursor geöffnet, mit AGENTS.md-Anweisungen","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784733478/l4hqhlzxekmhobu2qg0v.png",[12,371,57],{"id":372},"einen-fehlschlagenden-end-to-end-test-mit-cursor-beheben",[17,374,375,376,379,380,383],{},"Der Collector erlaubt es, den von einem Endpunkt erwarteten HTTP-Statuscode zu konfigurieren. Die Implementierung behandelt jedoch jede ",[106,377,378],{},"2xx","-Antwort als erfolgreich, und ",[106,381,382],{},"503","-Fehler schlugen immer fehl, selbst wenn sie als erwartet konfiguriert waren.",[17,385,386],{},"Der End-to-End-Test legt diese Diskrepanz bereits offen, aber der CI/CD-Job darf fehlschlagen. Das hat aus einem nützlichen Signal hingenommenes Hintergrundrauschen gemacht.",[17,388,389],{},[366,390],{"alt":391,"src":392},"Der fehlschlagende End-to-End-Test und sein auf \"allowed to fail\" gesetzter CI/CD-Job","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784733536/uaxqalqoceujyja7usmv.png",[293,394,396],{"id":395},"mit-cursor-reproduzieren-und-beheben","Mit Cursor reproduzieren und beheben",[17,398,399],{},"Das Problem lässt sich lokal reproduzieren. Die Cursor-IDE mit einem neuen Chat öffnen und damit beginnen, das beobachtbare Problem direkt im Prompt zu beschreiben:",[99,401,405],{"className":402,"code":403,"language":404,"meta":104,"style":104},"language-markdown shiki shiki-themes github-light","Can you help me fix the end-to-end tests in this project? Please create an analysis first, then fix it, and run the tests again.\n","markdown",[106,406,407],{"__ignoreMap":104},[109,408,409],{"class":111,"line":112},[109,410,403],{"class":115},[17,412,413,414,417],{},"Cursor beginnt damit, die Endpunkt-Konfiguration in den ",[106,415,416],{},"HttpCollector"," und den fehlschlagenden End-to-End-Test zurückzuverfolgen, und identifiziert die Ursache.",[17,419,420],{},[366,421],{"alt":422,"src":423},"Cursor analysiert das Problem und die Ursache","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784733605/ojz2pzcftwjfcfscjtwg.png",[17,425,426],{},"Nachdem die fokussierten Tests und die vollständige Maven-Testsuite durchlaufen, einen Branch und Merge Request erstellen. Der zuvor auf \"allowed to fail\" gesetzte End-to-End-Job kann verpflichtend werden, sobald er deterministisch und grün ist.",[99,428,430],{"className":402,"code":429,"language":404,"meta":104,"style":104},"Can you create a git branch and merge request?\n",[106,431,432],{"__ignoreMap":104},[109,433,434],{"class":111,"line":112},[109,435,429],{"class":115},[293,437,439],{"id":438},"reviewen-und-mergen","Reviewen und mergen",[17,441,442],{},"Der Merge Request stößt automatisch CI/CD-Build und -Tests sowie Security-Scanning an.",[17,444,445],{},[366,446],{"alt":447,"src":448},"Merge Request mit behobenen End-to-End-Tests","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784733663/koz3yb3zq5ewwl6vrbgk.png",[17,450,451,455],{},[27,452,454],{"href":282,"rel":453},[],"GitLab Duo Code Review"," reviewt die fokussierte Änderung anschließend anhand der Java-spezifischen Review-Anweisungen des Projekts.",[17,457,458],{},[366,459],{"alt":460,"src":461},"Code-Review-Feedback","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784733717/cjxeoecb4fa7yrvy7i90.png",[17,463,464],{},"Wenn das Review ein konkretes Problem findet, adressieren wir es über den Developer Flow, bevor wir mergen. Das ist der Punkt: Der Code Review Flow stellt sicher, dass jeder von einem Agenten erzeugte Merge Request denselben Maßstab erfüllt wie jeder andere, unabhängig davon, wie schnell Cursor ihn erzeugt hat. Der Merge Request bleibt die Fläche für Zusammenarbeit und Entscheidung.",[17,466,467],{},[366,468],{"alt":469,"src":470},"Developer Flow adressiert das Review-Feedback","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784733848/wehjrbkhhyhze8vtkaby.png",[17,472,473],{},"Der Fix gibt uns eine Verhaltens-Baseline. Wir haben einen echten Bug korrigiert, ohne ihn mit einer Runtime-Migration zu vermischen, und die Tests schützen jetzt den Vertrag über den erwarteten Status während der folgenden Modernisierungsarbeit.",[17,475,476],{},"In diesem Video wird gezeigt, wie Cursor die erwarteten End-to-End-Tests untersucht und behebt:",[478,479,482,483],"figure",{"className":480},[481],"video_container","\n  ",[484,485,489],"iframe",{"src":486,"frameBorder":487,"allowFullScreen":488},"https://www.youtube.com/embed/vpPt8TICiZY","0","true"," ",[12,491,63],{"id":492},"quality-gates-zur-java-21-modernisierung-vorbereiten",[17,494,495],{},"Der erste Fix kam allein mit Repository-Kontext aus. Die nächste Anforderung ist deutlich größer: den Collector von Java 8 auf Java 21 modernisieren.",[17,497,498,499,504],{},"Diese Arbeit hat bereits Planungskontext im ",[27,500,503],{"href":501,"rel":502},"https://gitlab.com/groups/gitlab-da/demo-environments/tanuki-iot-platform/-/work_items/13",[],"Epic zur Java-Modernisierung",": untergeordnete Work Items, Team-Diskussionen, Recherche mit Merge Requests, Pipeline-Historie, Abhängigkeiten und Security-Findings. Diese Details liegen nicht im lokalen Checkout. Statt sie alle in einen riesigen Prompt zu kopieren, lässt sich der GitLab-Kontext mit MCP nach Cursor bringen.",[293,506,508],{"id":507},"den-gitlab-mcp-server-in-cursor-konfigurieren","Den GitLab-MCP-Server in Cursor konfigurieren",[17,510,511,512,517],{},"Zunächst sicherstellen, dass der GitLab-MCP-Server auf der Instanz oder der Top-Level-Gruppe ",[27,513,516],{"href":514,"rel":515},"https://docs.gitlab.com/user/gitlab_duo/model_context_protocol/mcp_server/#prerequisites",[],"aktiviert"," ist. Cursor nutzt HTTP-Transport, um sich ohne zusätzliche Abhängigkeiten direkt zu verbinden.",[17,519,520,521,526],{},"Um ",[27,522,525],{"href":523,"rel":524},"https://docs.gitlab.com/user/gitlab_duo/model_context_protocol/mcp_server/#connect-cursor-to-the-gitlab-mcp-server",[],"Cursor mit dem GitLab-MCP-Server zu verbinden",":",[49,528,529,537,548],{},[52,530,531,532,536],{},"In Cursor zu ",[533,534,535],"strong",{},"Settings > Cursor Settings > Tools & MCP"," gehen.",[52,538,539,540,543,544,547],{},"Unter ",[533,541,542],{},"Installed MCP Servers"," die Option ",[533,545,546],{},"New MCP Server"," wählen.",[52,549,550,551,554,555,558,559,562,563,566],{},"Die folgende Definition zum ",[106,552,553],{},"mcpServers","-Schlüssel in der geöffneten ",[106,556,557],{},"mcp.json","-Datei hinzufügen. Für GitLab.com ",[106,560,561],{},"\u003Cgitlab.example.com>"," durch ",[106,564,565],{},"gitlab.com"," ersetzen. Für GitLab Self-Managed oder Dedicated die eigene Instanz-URL verwenden.",[99,568,572],{"className":569,"code":570,"language":571,"meta":104,"style":104},"language-json shiki shiki-themes github-light","{\n  \"mcpServers\": {\n    \"GitLab\": {\n      \"type\": \"http\",\n      \"url\": \"https://\u003Cgitlab.example.com>/api/v4/mcp\"\n    }\n  }\n}\n","json",[106,573,574,579,587,594,608,618,623,628],{"__ignoreMap":104},[109,575,576],{"class":111,"line":112},[109,577,578],{"class":115},"{\n",[109,580,581,584],{"class":111,"line":119},[109,582,583],{"class":339},"  \"mcpServers\"",[109,585,586],{"class":115},": {\n",[109,588,589,592],{"class":111,"line":125},[109,590,591],{"class":339},"    \"GitLab\"",[109,593,586],{"class":115},[109,595,596,599,602,605],{"class":111,"line":131},[109,597,598],{"class":339},"      \"type\"",[109,600,601],{"class":115},": ",[109,603,604],{"class":330},"\"http\"",[109,606,607],{"class":115},",\n",[109,609,610,613,615],{"class":111,"line":137},[109,611,612],{"class":339},"      \"url\"",[109,614,601],{"class":115},[109,616,617],{"class":330},"\"https://\u003Cgitlab.example.com>/api/v4/mcp\"\n",[109,619,620],{"class":111,"line":143},[109,621,622],{"class":115},"    }\n",[109,624,625],{"class":111,"line":149},[109,626,627],{"class":115},"  }\n",[109,629,630],{"class":111,"line":156},[109,631,632],{"class":115},"}\n",[49,634,635,638,641],{"start":131},[52,636,637],{},"Die Datei speichern und warten, bis sich die OAuth-Autorisierungsseite im Browser öffnet. Öffnet sie sich nicht, Cursor schließen und neu starten.",[52,639,640],{},"Die Autorisierungsanfrage im Browser prüfen und bestätigen.",[52,642,643],{},"Zurück in Cursor die aufgelisteten Tools inspizieren.",[17,645,646],{},[366,647],{"alt":648,"src":649},"Der GitLab-MCP-Server nach der OAuth-Autorisierung in Cursor verbunden","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784733928/anreghjemkrnuezohhzh.png",[17,651,652],{},"Jetzt lässt sich ein neuer Chat starten und eine Frage auf Basis der verfügbaren GitLab-MCP-Tools stellen.",[17,654,655],{},"Wenn Cursor sich bei GitLab MCP authentifiziert, handelt es mit der bestehenden GitLab-Identität. Es kann nur auf Projekte und Ressourcen zugreifen, auf die man ohnehin schon Zugriff hat. MCP bringt freigegebenen Kontext in die IDE. Es umgeht keine GitLab-Berechtigungen.",[293,657,659],{"id":658},"die-umgebung-für-die-java-21-modernisierung-vorbereiten","Die Umgebung für die Java-21-Modernisierung vorbereiten",[17,661,662,663,667],{},"Das ",[27,664,666],{"href":501,"rel":665},[],"Epic zur Modernisierung von Java 8 auf 21"," bricht den nötigen Plan in kleinere Iterationen herunter, wobei jedes Artefakt und jede Änderung für sich testbar ist.",[17,669,670],{},[366,671],{"alt":672,"src":673},"GitLab-Epic mit untergeordneten Issues","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784733989/thwfzpvbs7tcm0un2xg6.png",[17,675,676],{},"Der erste Schritt ist sicherzustellen, dass die CI/CD-Infrastruktur sowohl Java 8 als auch 21 parallel testet. Auch die Testabdeckung von Beginn an in jede Modernisierungsaufgabe hinein zu erhöhen, ist verpflichtend.",[17,678,679],{},"Die Cursor-IDE öffnen und den folgenden Prompt nutzen, um den Planungskontext abzurufen:",[99,681,683],{"className":402,"code":682,"language":404,"meta":104,"style":104},"Please help me modernize this sensor from Java 8 to 21. We want to start with the base line for CI/CD builds in work item 14, and then also look into test coverage from 21. Start the implementation in a new Git branch called `maint-java-21` so we can continue testing different scenarios.\n",[106,684,685],{"__ignoreMap":104},[109,686,687,690,693],{"class":111,"line":112},[109,688,689],{"class":115},"Please help me modernize this sensor from Java 8 to 21. We want to start with the base line for CI/CD builds in work item 14, and then also look into test coverage from 21. Start the implementation in a new Git branch called ",[109,691,692],{"class":339},"`maint-java-21`",[109,694,695],{"class":115}," so we can continue testing different scenarios.\n",[17,697,698,699,702],{},"Nach dem Abschluss der Arbeit am Issue zur Sichtbarkeit des CI-Builds kann Cursor mit dem MCP-Tool ",[106,700,701],{},"create_workitem_note"," zusätzlich einen zusammenfassenden Kommentar in das Issue einfügen.",[17,704,705],{},[366,706],{"alt":707,"src":708},"Cursor-Zusammenfassung mit Tool-Aufruf des GitLab-MCP-Servers","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784734071/bks4lwnncddardc05r3e.png",[17,710,711],{},"Der neue Merge Request stößt CI/CD-Pipelines an sowie den Code Review Flow, der Kommentare zum Development-Style-Guide hinterlässt, in denen Dokumentation eingefordert wird.",[17,713,714],{},[366,715],{"alt":716,"src":717},"Code-Review-Feedback im Merge Request","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784734168/z7ootq0wqmom3yxmdexj.png",[17,719,720],{},"Das Feedback lässt sich unmittelbar in der GitLab-Oberfläche adressieren, indem man den Service-Account des Developer Flow erwähnt.",[99,722,724],{"className":402,"code":723,"language":404,"meta":104,"style":104},"@duo-developer-\u003Cgroup-name> Can you help address the review feedback?\n",[106,725,726],{"__ignoreMap":104},[109,727,728],{"class":111,"line":112},[109,729,723],{"class":115},[17,731,732],{},"Dieser Prompt startet eine neue Hintergrund-Session, und wir können uns währenddessen auf andere Aufgaben konzentrieren. Alternativ lässt sich zurück in die Cursor-IDE wechseln und deren Chat bitten, das Review-Feedback im Merge Request zu adressieren.",[17,734,735],{},[366,736],{"alt":737,"src":738},"Cursor-IDE-Prompt \"There is review feedback in the MR - please help me fix it\"","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784734264/n5ky8nj73bpb1imzrj6h.png",[17,740,741,742,745],{},"Cursor setzt die Änderungen um und fügt mit dem MCP-Tool ",[106,743,744],{},"create_merge_request_note"," Kommentare in die Merge-Request-Threads ein.",[17,747,748],{},[366,749],{"alt":750,"src":751},"GitLab-Merge-Request mit adressierten Code-Review-Kommentaren","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784734337/hah0qxe8ei5h6iefzqz4.png",[17,753,754],{},"Die Änderung behält die temporäre Java-8-Baseline und ergänzt eine eigene Java-21-Build- und -Testvalidierung. Damit wird die Kompatibilität in der Pipeline sichtbar, bevor der Quellcode beginnt, Java-21-only-APIs zu nutzen. Sobald diese Quality-Gates existieren, ist jede weitere agentengetriebene Änderung reviewt, getestet und nachvollziehbar. Das ist derselbe Maßstab, den wir auf jeden anderen Merge Request anwenden, und er ist es, der es sicher macht, Cursor schnell arbeiten zu lassen.",[17,756,757],{},"In diesem Video wird gezeigt, wie Cursor GitLab MCP nutzt, um Quality-Gates vorzubereiten und Code-Review-Feedback zu adressieren:",[478,759,482,761],{"className":760},[481],[484,762,489],{"src":763,"frameBorder":487,"allowFullScreen":488},"https://www.youtube.com/embed/bqT2exfE5Go",[12,765,69],{"id":766},"das-http-connection-handling-mit-java-21-modernisieren",[17,768,769,770,773,774,777,778,783],{},"Der Java HTTP Metrics Collector nutzt derzeit die veraltete ",[106,771,772],{},"HttpURLConnection","-API aus Java 8. Java 21 hat die HTTP-Bibliothek mit ",[106,775,776],{},"java.net.http.HttpClient"," modernisiert, aber das ist nicht bloß ein mechanisches Umbenennen. Redirects, eingeschränkte Header, Timeout-Geltungsbereich, Response-Bodies, Unterbrechung und Verbindungswiederverwendung können sich alle unterschiedlich verhalten. Deshalb liegt die Umsetzung in einem einzigen abgegrenzten Work Item: ",[27,779,782],{"href":780,"rel":781},"https://gitlab.com/gitlab-da/demo-environments/tanuki-iot-platform/sensors/java-http-metrics-collector/-/work_items/16",[],"Replace HttpURLConnection with java.net.http.HttpClient",". Setzen wir das in die Praxis um.",[17,785,786],{},"Die Cursor-IDE mit einem neuen Chat öffnen und um die Umsetzung der Änderungen bitten.",[17,788,789,792],{},[533,790,791],{},"Hinweis:"," Für diesen Use Case wollen wir ein lokales Docker-Compose-Setup nutzen, um die Änderungen zu verifizieren. Wer das Verhalten nachvollziehen möchte, installiert Docker und Docker Compose, andernfalls den zweiten Prompt weglassen.",[99,794,796],{"className":402,"code":795,"language":404,"meta":104,"style":104},"We want to continue modernizing the app to Java 21 - use the same maint-java-21 branch, and start implementing issue 16.\n\nVerify the changes locally using the docker compose setup, after making the changes.\n",[106,797,798,803,807],{"__ignoreMap":104},[109,799,800],{"class":111,"line":112},[109,801,802],{"class":115},"We want to continue modernizing the app to Java 21 - use the same maint-java-21 branch, and start implementing issue 16.\n",[109,804,805],{"class":111,"line":119},[109,806,153],{"emptyLinePlaceholder":152},[109,808,809],{"class":111,"line":125},[109,810,811],{"class":115},"Verify the changes locally using the docker compose setup, after making the changes.\n",[17,813,814,815,817,818,821],{},"Der GitLab-MCP-Server liefert den Issue-Kontext, die Akzeptanzkriterien, Abhängigkeiten und zugehörigen Diskussionen. Das erste Code-Modernisierungs-Issue bleibt bewusst synchron und begrenzt. Es ersetzt ",[106,816,772],{}," durch einen einzigen wiederverwendbaren ",[106,819,820],{},"HttpClient"," und fügt keine Virtual Threads hinzu, ändert nicht das Zeitmodell und behebt keine unabhängigen Abhängigkeiten. Das sind wertvolle Folgeschritte, aber sie zu kombinieren würde es erschweren, Verhaltensänderungen zu isolieren, zu reviewen und zurückzurollen.",[293,823,825],{"id":824},"lokal-umsetzen-und-verifizieren","Lokal umsetzen und verifizieren",[17,827,828],{},"Fokussierte lokale HTTP-Server-Tests decken Methoden, Header, erwartete und unerwartete Statuscodes, Redirects, Timeouts, Response-Metadaten, Verbindungsfehler und Unterbrechung ab.",[17,830,831],{},[366,832],{"alt":833,"src":834},"Cursor führt lokale Maven-Tests aus","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784734391/fuxi3jcrcg5alhuqcrje.png",[17,836,837,838,841],{},"Der funktionale Test mit Docker Compose belegt anschließend, dass authentifizierte Messwerte weiterhin im ",[106,839,840],{},"rust-metrics-store","-Backend ankommen.",[17,843,844],{},[366,845],{"alt":846,"src":847},"Cursor führt lokal Docker Compose mit dem Rust-Backend aus","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784734439/w83djmi4df9dfynb9dfj.png",[17,849,850],{},"Falls die CI/CD-Pipelines nach den Änderungen fehlschlagen, lassen sich die GitLab-MCP-Server-Tools nutzen, um direkt in der Cursor-IDE zu inspizieren und zu beheben, ohne den Kontext zu wechseln.",[17,852,853],{},[366,854],{"alt":855,"src":856},"Cursor-IDE mit Tool-Aufruf des GitLab-MCP-Servers zum Abrufen von CI/CD-Job-Logs","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784734501/g4mfs2zdrffzb9pd8v09.png",[17,858,859,860,865,866,871],{},"In der GitLab-Oberfläche lässt sich der ",[27,861,864],{"href":862,"rel":863},"https://docs.gitlab.com/user/duo_agent_platform/flows/foundational_flows/fix_pipeline/",[],"Fix CI/CD Pipeline Flow"," nutzen oder der ",[27,867,870],{"href":868,"rel":869},"https://docs.gitlab.com/user/duo_agent_platform/agents/foundational_agents/ci_expert_agent/",[],"CI Expert Agent"," um Hilfe bitten.",[293,873,875],{"id":874},"cicd-und-review-belege","CI/CD- und Review-Belege",[17,877,878],{},"GitLab CI/CD, GitLab Duo Code Review, Security-Scanning und KI-gestützte Impact-Analyse liefern die abschließenden Belege im Merge Request. Menschliches Review zählt an den subtilen Grenzen weiterhin am meisten: Jeder beabsichtigte Verhaltensunterschied sollte im Merge Request explizit sein, nicht erst nach dem Deployment entdeckt werden.",[17,880,881],{},[366,882],{"alt":883,"src":884},"Developer Flow mit Impact-Analyse","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784734549/jxqds2bwzcedn7yafdvr.png",[17,886,887],{},"In diesem Video wird gezeigt, wie Cursor und GitLab die HTTP-Bibliothek des Collectors auf Java 21 modernisieren:",[478,889,482,891],{"className":890},[481],[484,892,489],{"src":893,"frameBorder":487,"allowFullScreen":488},"https://www.youtube.com/embed/AZEDvb474n0",[12,895,897],{"id":896},"tipps-für-cursor-und-gitlab","Tipps für Cursor und GitLab",[17,899,900],{},"Hier einige Tipps, um Cursor und GitLab zusammen zu nutzen.",[293,902,904],{"id":903},"impact-analyse-für-breaking-changes-bei-der-modernisierung-automatisieren","Impact-Analyse für Breaking Changes bei der Modernisierung automatisieren",[17,906,271,907,912,913,918,919,924],{},[27,908,911],{"href":909,"rel":910},"https://www.youtube.com/watch?v=AZEDvb474n0",[],"dritte Use Case"," zeigt den Developer Flow bei einer Impact-Analyse für Breaking Changes. Dieser Workflow lässt sich in einen automatisierten ",[27,914,917],{"href":915,"rel":916},"https://docs.gitlab.com/user/duo_agent_platform/flows/custom/",[],"Custom Flow"," überführen, der ausgelöst wird, sobald ein Merge Request bereit ist oder die Pipeline in Ordnung ist. Zusätzlicher Kontext lässt sich aus ",[27,920,923],{"href":921,"rel":922},"https://about.gitlab.com/de-de/blog/introducing-gitlab-orbit/",[],"GitLab Orbit"," abrufen, das einen Kontextgraphen über Code, Work Items, Merge Requests, Schwachstellen und mehr bereitstellt.",[17,926,927,928,933,934,262],{},"Der Beispiel-Flow lässt sich im AI Catalog inspizieren: ",[27,929,932],{"href":930,"rel":931},"https://gitlab.com/explore/ai-catalog/flows/1013017/",[],"MR Impact analysis (Orbit)",". Dank an meine Kollegin Fatima Sarah Kalid für die Inspiration. Custom Flows sind allgemein verfügbar in ",[27,935,938],{"href":936,"rel":937},"https://about.gitlab.com/de-de/blog/multi-step-software-delivery-with-agentic-flows/",[],"GitLab 19.2",[17,940,941],{},[366,942],{"alt":943,"src":944},"Custom Flow im AI Catalog","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784734604/nk2faraxdhghiktndrs5.png",[17,946,947],{},[366,948],{"alt":949,"src":950},"Merge-Request-Impact-Analyse mit einem Custom Flow in der GitLab Duo Agent Platform und Orbit","https://res.cloudinary.com/about-gitlab-com/image/upload/v1784734740/app3pnjwqzoyulojkomq.png",[293,952,954],{"id":953},"richtlinien-und-grenzen-für-agenten-dokumentieren","Richtlinien und Grenzen für Agenten dokumentieren",[956,957,959],"h4",{"id":958},"agentsmd-für-java","AGENTS.md für Java",[17,961,962,963,969],{},"Eine ",[27,964,967],{"href":965,"rel":966},"https://docs.gitlab.com/user/duo_agent_platform/customize/agents_md/",[],[106,968,361],{},"-Datei hilft Cursor und anderen Coding-Agenten, die Projektarchitektur, Befehle, den Code-Stil, Testerwartungen und Grenzen zu verstehen. Diese Anweisungen nah am Code halten und konkret genug, um sie zu verifizieren.",[17,971,972,973,262],{},"Beispiel aus der ",[27,974,977,979],{"href":975,"rel":976},"https://gitlab.com/gitlab-da/demo-environments/tanuki-iot-platform/sensors/java-http-metrics-collector/-/blob/main/AGENTS.md?ref_type=heads",[],[106,978,361],{}," im Java-HTTP-Metrics-Collector-Projekt",[99,981,983],{"className":402,"code":982,"language":404,"meta":104,"style":104},"# Java HTTP Metrics Collector - Agent Instructions\n\n## Overview\n\nThe Java HTTP Metrics Collector is a REST API metrics collection sensor for the Tanuki IoT Platform. It monitors HTTP endpoints, collects performance metrics (response time, status codes, content length), and exports them in Prometheus text format. The application runs continuously with configurable collection intervals and supports concurrent endpoint monitoring.\n\n## Code Style and Standards\n\n### Java 8 Compatibility\n\n- Do not modernize Java 8 code to Java 11+ features unless there is a GitLab issue or task specifically requesting modernization\n- Target Java 8 for source and compilation: `maven.compiler.source=1.8` and `maven.compiler.target=1.8`\n- Use Java 8 compatible patterns (e.g., anonymous inner classes instead of lambdas where appropriate)\n\n### Documentation\n\n- All public classes must have Javadoc describing purpose and usage\n- All public methods must have Javadoc with `@param` and `@return` tags\n- Include code examples in main class Javadoc\n\n### Class Organization\n\n- **Main entry point**: `HttpMetricsCollector` - orchestrates configuration loading, metric collection, and export\n- **Collector**: `HttpCollector` - performs HTTP requests and collects metrics\n- **Exporter**: `PrometheusExporter` - exports metrics in Prometheus text format\n- **Models**: `CollectorConfig`, `EndpointConfig`, `HttpMetric` - data transfer objects\n\n### Dependency Management\n\n- Always use Maven for dependency management\n- Use property-based version management for dependencies (e.g., `${jackson.version}`)\n- Keep dependencies up-to-date in `pom.xml`\n\n### Error Handling\n\n- Use try-catch blocks with proper resource management (try-with-resources where applicable)\n- Log errors using SLF4J Logger\n- Gracefully handle configuration loading failures\n- Implement proper shutdown hooks for resource cleanup\n\n### Concurrency\n\n- Use `ExecutorService` for concurrent HTTP requests\n- Thread pool size is limited to the minimum of endpoint count and 10\n- Properly shutdown executor service with timeout handling\n- Use `Future` objects to collect results from concurrent tasks\n",[106,984,985,991,995,1000,1004,1009,1013,1018,1022,1027,1031,1040,1056,1063,1067,1072,1076,1083,1101,1108,1112,1117,1121,1138,1154,1170,1196,1201,1207,1212,1220,1234,1245,1250,1256,1261,1269,1277,1285,1293,1298,1304,1309,1323,1331,1339],{"__ignoreMap":104},[109,986,987],{"class":111,"line":112},[109,988,990],{"class":989},"surfw","# Java HTTP Metrics Collector - Agent Instructions\n",[109,992,993],{"class":111,"line":119},[109,994,153],{"emptyLinePlaceholder":152},[109,996,997],{"class":111,"line":125},[109,998,999],{"class":989},"## Overview\n",[109,1001,1002],{"class":111,"line":131},[109,1003,153],{"emptyLinePlaceholder":152},[109,1005,1006],{"class":111,"line":137},[109,1007,1008],{"class":115},"The Java HTTP Metrics Collector is a REST API metrics collection sensor for the Tanuki IoT Platform. It monitors HTTP endpoints, collects performance metrics (response time, status codes, content length), and exports them in Prometheus text format. The application runs continuously with configurable collection intervals and supports concurrent endpoint monitoring.\n",[109,1010,1011],{"class":111,"line":143},[109,1012,153],{"emptyLinePlaceholder":152},[109,1014,1015],{"class":111,"line":149},[109,1016,1017],{"class":989},"## Code Style and Standards\n",[109,1019,1020],{"class":111,"line":156},[109,1021,153],{"emptyLinePlaceholder":152},[109,1023,1024],{"class":111,"line":162},[109,1025,1026],{"class":989},"### Java 8 Compatibility\n",[109,1028,1029],{"class":111,"line":168},[109,1030,153],{"emptyLinePlaceholder":152},[109,1032,1033,1037],{"class":111,"line":173},[109,1034,1036],{"class":1035},"sqxcx","-",[109,1038,1039],{"class":115}," Do not modernize Java 8 code to Java 11+ features unless there is a GitLab issue or task specifically requesting modernization\n",[109,1041,1042,1044,1047,1050,1053],{"class":111,"line":179},[109,1043,1036],{"class":1035},[109,1045,1046],{"class":115}," Target Java 8 for source and compilation: ",[109,1048,1049],{"class":339},"`maven.compiler.source=1.8`",[109,1051,1052],{"class":115}," and ",[109,1054,1055],{"class":339},"`maven.compiler.target=1.8`\n",[109,1057,1058,1060],{"class":111,"line":185},[109,1059,1036],{"class":1035},[109,1061,1062],{"class":115}," Use Java 8 compatible patterns (e.g., anonymous inner classes instead of lambdas where appropriate)\n",[109,1064,1065],{"class":111,"line":191},[109,1066,153],{"emptyLinePlaceholder":152},[109,1068,1069],{"class":111,"line":197},[109,1070,1071],{"class":989},"### Documentation\n",[109,1073,1074],{"class":111,"line":202},[109,1075,153],{"emptyLinePlaceholder":152},[109,1077,1078,1080],{"class":111,"line":208},[109,1079,1036],{"class":1035},[109,1081,1082],{"class":115}," All public classes must have Javadoc describing purpose and usage\n",[109,1084,1085,1087,1090,1093,1095,1098],{"class":111,"line":214},[109,1086,1036],{"class":1035},[109,1088,1089],{"class":115}," All public methods must have Javadoc with ",[109,1091,1092],{"class":339},"`@param`",[109,1094,1052],{"class":115},[109,1096,1097],{"class":339},"`@return`",[109,1099,1100],{"class":115}," tags\n",[109,1102,1103,1105],{"class":111,"line":220},[109,1104,1036],{"class":1035},[109,1106,1107],{"class":115}," Include code examples in main class Javadoc\n",[109,1109,1110],{"class":111,"line":225},[109,1111,153],{"emptyLinePlaceholder":152},[109,1113,1114],{"class":111,"line":231},[109,1115,1116],{"class":989},"### Class Organization\n",[109,1118,1119],{"class":111,"line":237},[109,1120,153],{"emptyLinePlaceholder":152},[109,1122,1124,1126,1130,1132,1135],{"class":111,"line":1123},23,[109,1125,1036],{"class":1035},[109,1127,1129],{"class":1128},"sbYKK"," **Main entry point**",[109,1131,601],{"class":115},[109,1133,1134],{"class":339},"`HttpMetricsCollector`",[109,1136,1137],{"class":115}," - orchestrates configuration loading, metric collection, and export\n",[109,1139,1141,1143,1146,1148,1151],{"class":111,"line":1140},24,[109,1142,1036],{"class":1035},[109,1144,1145],{"class":1128}," **Collector**",[109,1147,601],{"class":115},[109,1149,1150],{"class":339},"`HttpCollector`",[109,1152,1153],{"class":115}," - performs HTTP requests and collects metrics\n",[109,1155,1157,1159,1162,1164,1167],{"class":111,"line":1156},25,[109,1158,1036],{"class":1035},[109,1160,1161],{"class":1128}," **Exporter**",[109,1163,601],{"class":115},[109,1165,1166],{"class":339},"`PrometheusExporter`",[109,1168,1169],{"class":115}," - exports metrics in Prometheus text format\n",[109,1171,1173,1175,1178,1180,1183,1185,1188,1190,1193],{"class":111,"line":1172},26,[109,1174,1036],{"class":1035},[109,1176,1177],{"class":1128}," **Models**",[109,1179,601],{"class":115},[109,1181,1182],{"class":339},"`CollectorConfig`",[109,1184,285],{"class":115},[109,1186,1187],{"class":339},"`EndpointConfig`",[109,1189,285],{"class":115},[109,1191,1192],{"class":339},"`HttpMetric`",[109,1194,1195],{"class":115}," - data transfer objects\n",[109,1197,1199],{"class":111,"line":1198},27,[109,1200,153],{"emptyLinePlaceholder":152},[109,1202,1204],{"class":111,"line":1203},28,[109,1205,1206],{"class":989},"### Dependency Management\n",[109,1208,1210],{"class":111,"line":1209},29,[109,1211,153],{"emptyLinePlaceholder":152},[109,1213,1215,1217],{"class":111,"line":1214},30,[109,1216,1036],{"class":1035},[109,1218,1219],{"class":115}," Always use Maven for dependency management\n",[109,1221,1223,1225,1228,1231],{"class":111,"line":1222},31,[109,1224,1036],{"class":1035},[109,1226,1227],{"class":115}," Use property-based version management for dependencies (e.g., ",[109,1229,1230],{"class":339},"`${jackson.version}`",[109,1232,1233],{"class":115},")\n",[109,1235,1237,1239,1242],{"class":111,"line":1236},32,[109,1238,1036],{"class":1035},[109,1240,1241],{"class":115}," Keep dependencies up-to-date in ",[109,1243,1244],{"class":339},"`pom.xml`\n",[109,1246,1248],{"class":111,"line":1247},33,[109,1249,153],{"emptyLinePlaceholder":152},[109,1251,1253],{"class":111,"line":1252},34,[109,1254,1255],{"class":989},"### Error Handling\n",[109,1257,1259],{"class":111,"line":1258},35,[109,1260,153],{"emptyLinePlaceholder":152},[109,1262,1264,1266],{"class":111,"line":1263},36,[109,1265,1036],{"class":1035},[109,1267,1268],{"class":115}," Use try-catch blocks with proper resource management (try-with-resources where applicable)\n",[109,1270,1272,1274],{"class":111,"line":1271},37,[109,1273,1036],{"class":1035},[109,1275,1276],{"class":115}," Log errors using SLF4J Logger\n",[109,1278,1280,1282],{"class":111,"line":1279},38,[109,1281,1036],{"class":1035},[109,1283,1284],{"class":115}," Gracefully handle configuration loading failures\n",[109,1286,1288,1290],{"class":111,"line":1287},39,[109,1289,1036],{"class":1035},[109,1291,1292],{"class":115}," Implement proper shutdown hooks for resource cleanup\n",[109,1294,1296],{"class":111,"line":1295},40,[109,1297,153],{"emptyLinePlaceholder":152},[109,1299,1301],{"class":111,"line":1300},41,[109,1302,1303],{"class":989},"### Concurrency\n",[109,1305,1307],{"class":111,"line":1306},42,[109,1308,153],{"emptyLinePlaceholder":152},[109,1310,1312,1314,1317,1320],{"class":111,"line":1311},43,[109,1313,1036],{"class":1035},[109,1315,1316],{"class":115}," Use ",[109,1318,1319],{"class":339},"`ExecutorService`",[109,1321,1322],{"class":115}," for concurrent HTTP requests\n",[109,1324,1326,1328],{"class":111,"line":1325},44,[109,1327,1036],{"class":1035},[109,1329,1330],{"class":115}," Thread pool size is limited to the minimum of endpoint count and 10\n",[109,1332,1334,1336],{"class":111,"line":1333},45,[109,1335,1036],{"class":1035},[109,1337,1338],{"class":115}," Properly shutdown executor service with timeout handling\n",[109,1340,1342,1344,1346,1349],{"class":111,"line":1341},46,[109,1343,1036],{"class":1035},[109,1345,1316],{"class":115},[109,1347,1348],{"class":339},"`Future`",[109,1350,1351],{"class":115}," objects to collect results from concurrent tasks\n",[956,1353,1355],{"id":1354},"code-review-anweisungen-für-java","Code-Review-Anweisungen für Java",[17,1357,1358,1359,1367,1368,526],{},"Der GitLab Duo Code Review Flow hilft, Style-Guides und Grenzen einzuhalten. Er erwartet spezifische Anweisungen in der ",[27,1360,1363,1364],{"href":1361,"rel":1362},"https://docs.gitlab.com/user/duo_agent_platform/customize/review_instructions/",[],"Datei ",[106,1365,1366],{},".gitlab/duo/mr-review-instructions.yaml",", zum Beispiel für ",[27,1369,1372],{"href":1370,"rel":1371},"https://gitlab.com/gitlab-da/demo-environments/tanuki-iot-platform/sensors/java-http-metrics-collector/-/blob/main/.gitlab/duo/mr-review-instructions.yaml?ref_type=heads",[],"Java",[99,1374,1378],{"className":1375,"code":1376,"language":1377,"meta":104,"style":104},"language-yaml shiki shiki-themes github-light","# Custom instructions for GitLab Duo Code Review\n\ninstructions:\n  # General guidelines\n\n  - name: Code Review\n    instructions: |\n      1. Focus on correctness and performance\n      2. Ensure code comments and documentation are clear and concise\n      3. Be respectful and constructive in comments\n\n  - name: CI/CD Configuration\n    fileFilters:\n      - \".gitlab-ci.yml\"\n    instructions: |\n      1. Do not use YAML anchors\n      2. Always use rules in jobs, avoid using `only`\n\n  # Java style guide\n\n  - name: Java Style Guide\n    fileFilters:\n      - \"**/*.java\"\n    instructions: |\n      1. Do not modernize Java 8 code to Java 11+ features, unless there is a GitLab issue or task specifically requesting modernization\n      2. All public classes must have Javadoc describing purpose and usage\n      3. All public methods must have Javadoc with @param and @return tags\n      4. Include code examples in main class Javadoc\n      5. All public methods must have at least one test case\n      6. Use httpbun.com for test endpoints (status codes, delays, JSON responses)\n","yaml",[106,1379,1380,1386,1390,1399,1404,1408,1421,1432,1437,1442,1447,1451,1462,1469,1477,1485,1490,1495,1499,1504,1508,1519,1525,1532,1540,1545,1550,1555,1560,1565],{"__ignoreMap":104},[109,1381,1382],{"class":111,"line":112},[109,1383,1385],{"class":1384},"sAwPA","# Custom instructions for GitLab Duo Code Review\n",[109,1387,1388],{"class":111,"line":119},[109,1389,153],{"emptyLinePlaceholder":152},[109,1391,1392,1396],{"class":111,"line":125},[109,1393,1395],{"class":1394},"shJU0","instructions",[109,1397,1398],{"class":115},":\n",[109,1400,1401],{"class":111,"line":131},[109,1402,1403],{"class":1384},"  # General guidelines\n",[109,1405,1406],{"class":111,"line":137},[109,1407,153],{"emptyLinePlaceholder":152},[109,1409,1410,1413,1416,1418],{"class":111,"line":143},[109,1411,1412],{"class":115},"  - ",[109,1414,1415],{"class":1394},"name",[109,1417,601],{"class":115},[109,1419,1420],{"class":330},"Code Review\n",[109,1422,1423,1426,1428],{"class":111,"line":149},[109,1424,1425],{"class":1394},"    instructions",[109,1427,601],{"class":115},[109,1429,1431],{"class":1430},"sD7c4","|\n",[109,1433,1434],{"class":111,"line":156},[109,1435,1436],{"class":330},"      1. Focus on correctness and performance\n",[109,1438,1439],{"class":111,"line":162},[109,1440,1441],{"class":330},"      2. Ensure code comments and documentation are clear and concise\n",[109,1443,1444],{"class":111,"line":168},[109,1445,1446],{"class":330},"      3. Be respectful and constructive in comments\n",[109,1448,1449],{"class":111,"line":173},[109,1450,153],{"emptyLinePlaceholder":152},[109,1452,1453,1455,1457,1459],{"class":111,"line":179},[109,1454,1412],{"class":115},[109,1456,1415],{"class":1394},[109,1458,601],{"class":115},[109,1460,1461],{"class":330},"CI/CD Configuration\n",[109,1463,1464,1467],{"class":111,"line":185},[109,1465,1466],{"class":1394},"    fileFilters",[109,1468,1398],{"class":115},[109,1470,1471,1474],{"class":111,"line":191},[109,1472,1473],{"class":115},"      - ",[109,1475,1476],{"class":330},"\".gitlab-ci.yml\"\n",[109,1478,1479,1481,1483],{"class":111,"line":197},[109,1480,1425],{"class":1394},[109,1482,601],{"class":115},[109,1484,1431],{"class":1430},[109,1486,1487],{"class":111,"line":202},[109,1488,1489],{"class":330},"      1. Do not use YAML anchors\n",[109,1491,1492],{"class":111,"line":208},[109,1493,1494],{"class":330},"      2. Always use rules in jobs, avoid using `only`\n",[109,1496,1497],{"class":111,"line":214},[109,1498,153],{"emptyLinePlaceholder":152},[109,1500,1501],{"class":111,"line":220},[109,1502,1503],{"class":1384},"  # Java style guide\n",[109,1505,1506],{"class":111,"line":225},[109,1507,153],{"emptyLinePlaceholder":152},[109,1509,1510,1512,1514,1516],{"class":111,"line":231},[109,1511,1412],{"class":115},[109,1513,1415],{"class":1394},[109,1515,601],{"class":115},[109,1517,1518],{"class":330},"Java Style Guide\n",[109,1520,1521,1523],{"class":111,"line":237},[109,1522,1466],{"class":1394},[109,1524,1398],{"class":115},[109,1526,1527,1529],{"class":111,"line":1123},[109,1528,1473],{"class":115},[109,1530,1531],{"class":330},"\"**/*.java\"\n",[109,1533,1534,1536,1538],{"class":111,"line":1140},[109,1535,1425],{"class":1394},[109,1537,601],{"class":115},[109,1539,1431],{"class":1430},[109,1541,1542],{"class":111,"line":1156},[109,1543,1544],{"class":330},"      1. Do not modernize Java 8 code to Java 11+ features, unless there is a GitLab issue or task specifically requesting modernization\n",[109,1546,1547],{"class":111,"line":1172},[109,1548,1549],{"class":330},"      2. All public classes must have Javadoc describing purpose and usage\n",[109,1551,1552],{"class":111,"line":1198},[109,1553,1554],{"class":330},"      3. All public methods must have Javadoc with @param and @return tags\n",[109,1556,1557],{"class":111,"line":1203},[109,1558,1559],{"class":330},"      4. Include code examples in main class Javadoc\n",[109,1561,1562],{"class":111,"line":1209},[109,1563,1564],{"class":330},"      5. All public methods must have at least one test case\n",[109,1566,1567],{"class":111,"line":1214},[109,1568,1569],{"class":330},"      6. Use httpbun.com for test endpoints (status codes, delays, JSON responses)\n",[17,1571,1572],{},"Im Zuge der Code-Modernisierung wird die erste Richtlinie mit der Java-8-Durchsetzung aktualisiert werden müssen.",[293,1574,1576],{"id":1575},"einen-bewährten-workflow-in-eine-agentische-skill-überführen","Einen bewährten Workflow in eine agentische Skill überführen",[17,1578,1579,1580,1585],{},"Wenn ein spezialisierter Workflow wiederholbar wird, lässt er sich in einer ",[27,1581,1584],{"href":1582,"rel":1583},"https://docs.gitlab.com/user/duo_agent_platform/customize/agent_skills/",[],"agentischen Skill"," festhalten. Skills werden bei Bedarf geladen und belegen das Kontextfenster nicht standardmäßig.",[17,1587,1588,1589,1594],{},"Mit funktionierendem CI/CD, Tests und reviewten Entscheidungen beginnen, damit die agentische Skill bewährte Praxis widerspiegelt und keinen ungetesteten Plan. ",[27,1590,1593],{"href":1591,"rel":1592},"https://gitlab.com/gitlab-da/demo-environments/tanuki-iot-platform/sensors/java-http-metrics-collector/-/work_items/24",[],"Issue 24"," im Modernisierungs-Epic hält den Ansatz in einer fokussierten agentischen Skill für die Java-21+-Modernisierung fest. Das schafft Mehrwert über den aktuellen Merge Request hinaus: Künftige Agenten-Sessions können dieselben Sicherheitsgrenzen wiederverwenden, statt sie aus früheren Diskussionen zu rekonstruieren.",[17,1596,1597,1598,526],{},"Diese Beispiel-Implementierung einer Skill lässt sich ausprobieren, inspiriert von der bestehenden ",[27,1599,1602],{"href":1600,"rel":1601},"https://gitlab.com/gitlab-da/demo-environments/tanuki-iot-platform/sensors/java-http-metrics-collector/-/blob/main/skills/java8-maven-maintenance/SKILL.md?ref_type=heads",[],"Java-8-Maven-Maintenance-Skill",[99,1604,1606],{"className":402,"code":1605,"language":404,"meta":104,"style":104},"---\nname: java21-modernization\ndescription: >-\n  Guide incremental Java 8 to Java 21+ modernization for the HTTP metrics\n  collector. Use when a GitLab work item asks for Java 21 CI visibility,\n  runtime/image upgrades, HttpClient migration, dependency or source API\n  modernization, or review of maint-java-21 style merge requests. Do not use\n  for routine Java 8 maintenance; prefer java8-maven-maintenance instead.\ncompatibility: Requires Maven, Docker Compose, and access to the owning GitLab work item.\n---\n\n# Java 21 Modernization\n\n## Overview\n\nModernize in small, reviewable steps. The owning work item is authoritative.\nPreserve collector → Rust metrics-store behavior unless the issue says otherwise.\n\nCompanion skill: `skills/java8-maven-maintenance/` for the Java 8 default path.\n\n## Before editing\n\n1. Read the owning issue/epic, `AGENTS.md`, `.gitlab-ci.yml`, `pom.xml`,\n   `Dockerfile`, and affected tests.\n2. Record the current baseline:\n   - `maven.compiler.source` / `target`\n   - default CI image vs any `*:java-21` jobs\n   - container base image\n   - observable CLI/Compose behavior\n3. Classify the change into **one** lane:\n   - CI visibility only\n   - runtime / image switch\n   - source / API modernization\n   - dependency upgrade\n   - tests / contract checks\n\nDo not combine lanes in one MR unless the work item explicitly requires it.\n\n## Workflow\n\nCopy and track:\n\n```text\nModernization progress:\n- [ ] Baseline recorded\n- [ ] Scoped to owning work item\n- [ ] Target-JDK CI evidence available before JDK-only APIs\n- [ ] Java 8 lane preserved until exit criteria say otherwise\n- [ ] Unit / IT / Compose checks run\n- [ ] MR documents risks, rollback, human decisions\n```\n\n## Guardrails\n\n- Do not remove Java 8 compatibility unless the work item authorizes it.\n- Do not introduce Java 21-only APIs before target-JDK CI evidence exists.\n- Do not mix runtime upgrades with unrelated refactors.\n- Do not claim performance wins without measurements.\n- Preserve the Java → Rust API and authentication contract.\n- Stop for a human decision when support policy, rollback, data format, or downstream compatibility is unclear.\n\n## Validation\n\n```bash\nmvn -Dmaven.repo.local=.m2/repository test\nmvn -Dmaven.repo.local=.m2/repository clean package\n```\n\nIf Compose or container files change:\n\n```bash\ndocker compose config --quiet\nTANUKI_INGESTION_TOKEN=replace-me docker compose up -d --build\n# confirm metric_sample logs and authenticated ingest still work\ndocker compose down -v\n```\n\n## Completion report\n\nIn the MR description, include:\n\n1. Baseline before the change\n2. Lane changed (CI / runtime / source / deps / tests)\n3. Evidence run (commands + CI jobs)\n4. Remaining risks and rollback\n5. Human decisions still open\n\n## Out of scope\n\n- Broad \"modernize everything to Java 21\" prompts\n- HTTP endpoint semantics unrelated to the JDK migration\n  (use `skills/http-endpoint-collector-behavior/`)\n- Security triage unrelated to the migration slice\n  (use `skills/security-triage-java-sensor/`)\n",[106,1607,1608,1613,1622,1632,1637,1642,1647,1652,1657,1667,1671,1675,1680,1684,1688,1692,1697,1702,1706,1717,1721,1726,1730,1753,1761,1769,1783,1796,1803,1810,1824,1831,1838,1845,1852,1859,1863,1868,1872,1877,1881,1886,1890,1895,1900,1905,1910,1916,1922,1928,1934,1940,1945,1951,1956,1964,1972,1980,1988,1996,2004,2009,2015,2020,2026,2038,2051,2056,2061,2067,2072,2077,2092,2118,2124,2137,2142,2147,2153,2158,2164,2169,2177,2185,2193,2202,2211,2216,2222,2227,2235,2243,2254,2262],{"__ignoreMap":104},[109,1609,1610],{"class":111,"line":112},[109,1611,1612],{"class":115},"---\n",[109,1614,1615,1617,1619],{"class":111,"line":119},[109,1616,1415],{"class":1394},[109,1618,601],{"class":115},[109,1620,1621],{"class":330},"java21-modernization\n",[109,1623,1624,1627,1629],{"class":111,"line":125},[109,1625,1626],{"class":1394},"description",[109,1628,601],{"class":115},[109,1630,1631],{"class":1430},">-\n",[109,1633,1634],{"class":111,"line":131},[109,1635,1636],{"class":330},"  Guide incremental Java 8 to Java 21+ modernization for the HTTP metrics\n",[109,1638,1639],{"class":111,"line":137},[109,1640,1641],{"class":330},"  collector. Use when a GitLab work item asks for Java 21 CI visibility,\n",[109,1643,1644],{"class":111,"line":143},[109,1645,1646],{"class":330},"  runtime/image upgrades, HttpClient migration, dependency or source API\n",[109,1648,1649],{"class":111,"line":149},[109,1650,1651],{"class":330},"  modernization, or review of maint-java-21 style merge requests. Do not use\n",[109,1653,1654],{"class":111,"line":156},[109,1655,1656],{"class":330},"  for routine Java 8 maintenance; prefer java8-maven-maintenance instead.\n",[109,1658,1659,1662,1664],{"class":111,"line":162},[109,1660,1661],{"class":1394},"compatibility",[109,1663,601],{"class":115},[109,1665,1666],{"class":330},"Requires Maven, Docker Compose, and access to the owning GitLab work item.\n",[109,1668,1669],{"class":111,"line":168},[109,1670,1612],{"class":115},[109,1672,1673],{"class":111,"line":173},[109,1674,153],{"emptyLinePlaceholder":152},[109,1676,1677],{"class":111,"line":179},[109,1678,1679],{"class":989},"# Java 21 Modernization\n",[109,1681,1682],{"class":111,"line":185},[109,1683,153],{"emptyLinePlaceholder":152},[109,1685,1686],{"class":111,"line":191},[109,1687,999],{"class":989},[109,1689,1690],{"class":111,"line":197},[109,1691,153],{"emptyLinePlaceholder":152},[109,1693,1694],{"class":111,"line":202},[109,1695,1696],{"class":115},"Modernize in small, reviewable steps. The owning work item is authoritative.\n",[109,1698,1699],{"class":111,"line":208},[109,1700,1701],{"class":115},"Preserve collector → Rust metrics-store behavior unless the issue says otherwise.\n",[109,1703,1704],{"class":111,"line":214},[109,1705,153],{"emptyLinePlaceholder":152},[109,1707,1708,1711,1714],{"class":111,"line":220},[109,1709,1710],{"class":115},"Companion skill: ",[109,1712,1713],{"class":339},"`skills/java8-maven-maintenance/`",[109,1715,1716],{"class":115}," for the Java 8 default path.\n",[109,1718,1719],{"class":111,"line":225},[109,1720,153],{"emptyLinePlaceholder":152},[109,1722,1723],{"class":111,"line":231},[109,1724,1725],{"class":989},"## Before editing\n",[109,1727,1728],{"class":111,"line":237},[109,1729,153],{"emptyLinePlaceholder":152},[109,1731,1732,1735,1738,1741,1743,1746,1748,1751],{"class":111,"line":1123},[109,1733,1734],{"class":1035},"1.",[109,1736,1737],{"class":115}," Read the owning issue/epic, ",[109,1739,1740],{"class":339},"`AGENTS.md`",[109,1742,285],{"class":115},[109,1744,1745],{"class":339},"`.gitlab-ci.yml`",[109,1747,285],{"class":115},[109,1749,1750],{"class":339},"`pom.xml`",[109,1752,607],{"class":115},[109,1754,1755,1758],{"class":111,"line":1140},[109,1756,1757],{"class":339},"   `Dockerfile`",[109,1759,1760],{"class":115},", and affected tests.\n",[109,1762,1763,1766],{"class":111,"line":1156},[109,1764,1765],{"class":1035},"2.",[109,1767,1768],{"class":115}," Record the current baseline:\n",[109,1770,1771,1774,1777,1780],{"class":111,"line":1172},[109,1772,1773],{"class":1035},"   -",[109,1775,1776],{"class":339}," `maven.compiler.source`",[109,1778,1779],{"class":115}," / ",[109,1781,1782],{"class":339},"`target`\n",[109,1784,1785,1787,1790,1793],{"class":111,"line":1198},[109,1786,1773],{"class":1035},[109,1788,1789],{"class":115}," default CI image vs any ",[109,1791,1792],{"class":339},"`*:java-21`",[109,1794,1795],{"class":115}," jobs\n",[109,1797,1798,1800],{"class":111,"line":1203},[109,1799,1773],{"class":1035},[109,1801,1802],{"class":115}," container base image\n",[109,1804,1805,1807],{"class":111,"line":1209},[109,1806,1773],{"class":1035},[109,1808,1809],{"class":115}," observable CLI/Compose behavior\n",[109,1811,1812,1815,1818,1821],{"class":111,"line":1214},[109,1813,1814],{"class":1035},"3.",[109,1816,1817],{"class":115}," Classify the change into ",[109,1819,1820],{"class":1128},"**one**",[109,1822,1823],{"class":115}," lane:\n",[109,1825,1826,1828],{"class":111,"line":1222},[109,1827,1773],{"class":1035},[109,1829,1830],{"class":115}," CI visibility only\n",[109,1832,1833,1835],{"class":111,"line":1236},[109,1834,1773],{"class":1035},[109,1836,1837],{"class":115}," runtime / image switch\n",[109,1839,1840,1842],{"class":111,"line":1247},[109,1841,1773],{"class":1035},[109,1843,1844],{"class":115}," source / API modernization\n",[109,1846,1847,1849],{"class":111,"line":1252},[109,1848,1773],{"class":1035},[109,1850,1851],{"class":115}," dependency upgrade\n",[109,1853,1854,1856],{"class":111,"line":1258},[109,1855,1773],{"class":1035},[109,1857,1858],{"class":115}," tests / contract checks\n",[109,1860,1861],{"class":111,"line":1263},[109,1862,153],{"emptyLinePlaceholder":152},[109,1864,1865],{"class":111,"line":1271},[109,1866,1867],{"class":115},"Do not combine lanes in one MR unless the work item explicitly requires it.\n",[109,1869,1870],{"class":111,"line":1279},[109,1871,153],{"emptyLinePlaceholder":152},[109,1873,1874],{"class":111,"line":1287},[109,1875,1876],{"class":989},"## Workflow\n",[109,1878,1879],{"class":111,"line":1295},[109,1880,153],{"emptyLinePlaceholder":152},[109,1882,1883],{"class":111,"line":1300},[109,1884,1885],{"class":115},"Copy and track:\n",[109,1887,1888],{"class":111,"line":1306},[109,1889,153],{"emptyLinePlaceholder":152},[109,1891,1892],{"class":111,"line":1311},[109,1893,1894],{"class":115},"```text\n",[109,1896,1897],{"class":111,"line":1325},[109,1898,1899],{"class":115},"Modernization progress:\n",[109,1901,1902],{"class":111,"line":1333},[109,1903,1904],{"class":115},"- [ ] Baseline recorded\n",[109,1906,1907],{"class":111,"line":1341},[109,1908,1909],{"class":115},"- [ ] Scoped to owning work item\n",[109,1911,1913],{"class":111,"line":1912},47,[109,1914,1915],{"class":115},"- [ ] Target-JDK CI evidence available before JDK-only APIs\n",[109,1917,1919],{"class":111,"line":1918},48,[109,1920,1921],{"class":115},"- [ ] Java 8 lane preserved until exit criteria say otherwise\n",[109,1923,1925],{"class":111,"line":1924},49,[109,1926,1927],{"class":115},"- [ ] Unit / IT / Compose checks run\n",[109,1929,1931],{"class":111,"line":1930},50,[109,1932,1933],{"class":115},"- [ ] MR documents risks, rollback, human decisions\n",[109,1935,1937],{"class":111,"line":1936},51,[109,1938,1939],{"class":115},"```\n",[109,1941,1943],{"class":111,"line":1942},52,[109,1944,153],{"emptyLinePlaceholder":152},[109,1946,1948],{"class":111,"line":1947},53,[109,1949,1950],{"class":989},"## Guardrails\n",[109,1952,1954],{"class":111,"line":1953},54,[109,1955,153],{"emptyLinePlaceholder":152},[109,1957,1959,1961],{"class":111,"line":1958},55,[109,1960,1036],{"class":1035},[109,1962,1963],{"class":115}," Do not remove Java 8 compatibility unless the work item authorizes it.\n",[109,1965,1967,1969],{"class":111,"line":1966},56,[109,1968,1036],{"class":1035},[109,1970,1971],{"class":115}," Do not introduce Java 21-only APIs before target-JDK CI evidence exists.\n",[109,1973,1975,1977],{"class":111,"line":1974},57,[109,1976,1036],{"class":1035},[109,1978,1979],{"class":115}," Do not mix runtime upgrades with unrelated refactors.\n",[109,1981,1983,1985],{"class":111,"line":1982},58,[109,1984,1036],{"class":1035},[109,1986,1987],{"class":115}," Do not claim performance wins without measurements.\n",[109,1989,1991,1993],{"class":111,"line":1990},59,[109,1992,1036],{"class":1035},[109,1994,1995],{"class":115}," Preserve the Java → Rust API and authentication contract.\n",[109,1997,1999,2001],{"class":111,"line":1998},60,[109,2000,1036],{"class":1035},[109,2002,2003],{"class":115}," Stop for a human decision when support policy, rollback, data format, or downstream compatibility is unclear.\n",[109,2005,2007],{"class":111,"line":2006},61,[109,2008,153],{"emptyLinePlaceholder":152},[109,2010,2012],{"class":111,"line":2011},62,[109,2013,2014],{"class":989},"## Validation\n",[109,2016,2018],{"class":111,"line":2017},63,[109,2019,153],{"emptyLinePlaceholder":152},[109,2021,2023],{"class":111,"line":2022},64,[109,2024,2025],{"class":115},"```bash\n",[109,2027,2029,2032,2035],{"class":111,"line":2028},65,[109,2030,2031],{"class":326},"mvn",[109,2033,2034],{"class":339}," -Dmaven.repo.local=.m2/repository",[109,2036,2037],{"class":330}," test\n",[109,2039,2041,2043,2045,2048],{"class":111,"line":2040},66,[109,2042,2031],{"class":326},[109,2044,2034],{"class":339},[109,2046,2047],{"class":330}," clean",[109,2049,2050],{"class":330}," package\n",[109,2052,2054],{"class":111,"line":2053},67,[109,2055,1939],{"class":115},[109,2057,2059],{"class":111,"line":2058},68,[109,2060,153],{"emptyLinePlaceholder":152},[109,2062,2064],{"class":111,"line":2063},69,[109,2065,2066],{"class":115},"If Compose or container files change:\n",[109,2068,2070],{"class":111,"line":2069},70,[109,2071,153],{"emptyLinePlaceholder":152},[109,2073,2075],{"class":111,"line":2074},71,[109,2076,2025],{"class":115},[109,2078,2080,2083,2086,2089],{"class":111,"line":2079},72,[109,2081,2082],{"class":326},"docker",[109,2084,2085],{"class":330}," compose",[109,2087,2088],{"class":330}," config",[109,2090,2091],{"class":339}," --quiet\n",[109,2093,2095,2098,2101,2104,2107,2109,2112,2115],{"class":111,"line":2094},73,[109,2096,2097],{"class":115},"TANUKI_INGESTION_TOKEN",[109,2099,2100],{"class":1430},"=",[109,2102,2103],{"class":330},"replace-me",[109,2105,2106],{"class":326}," docker",[109,2108,2085],{"class":330},[109,2110,2111],{"class":330}," up",[109,2113,2114],{"class":339}," -d",[109,2116,2117],{"class":339}," --build\n",[109,2119,2121],{"class":111,"line":2120},74,[109,2122,2123],{"class":1384},"# confirm metric_sample logs and authenticated ingest still work\n",[109,2125,2127,2129,2131,2134],{"class":111,"line":2126},75,[109,2128,2082],{"class":326},[109,2130,2085],{"class":330},[109,2132,2133],{"class":330}," down",[109,2135,2136],{"class":339}," -v\n",[109,2138,2140],{"class":111,"line":2139},76,[109,2141,1939],{"class":115},[109,2143,2145],{"class":111,"line":2144},77,[109,2146,153],{"emptyLinePlaceholder":152},[109,2148,2150],{"class":111,"line":2149},78,[109,2151,2152],{"class":989},"## Completion report\n",[109,2154,2156],{"class":111,"line":2155},79,[109,2157,153],{"emptyLinePlaceholder":152},[109,2159,2161],{"class":111,"line":2160},80,[109,2162,2163],{"class":115},"In the MR description, include:\n",[109,2165,2167],{"class":111,"line":2166},81,[109,2168,153],{"emptyLinePlaceholder":152},[109,2170,2172,2174],{"class":111,"line":2171},82,[109,2173,1734],{"class":1035},[109,2175,2176],{"class":115}," Baseline before the change\n",[109,2178,2180,2182],{"class":111,"line":2179},83,[109,2181,1765],{"class":1035},[109,2183,2184],{"class":115}," Lane changed (CI / runtime / source / deps / tests)\n",[109,2186,2188,2190],{"class":111,"line":2187},84,[109,2189,1814],{"class":1035},[109,2191,2192],{"class":115}," Evidence run (commands + CI jobs)\n",[109,2194,2196,2199],{"class":111,"line":2195},85,[109,2197,2198],{"class":1035},"4.",[109,2200,2201],{"class":115}," Remaining risks and rollback\n",[109,2203,2205,2208],{"class":111,"line":2204},86,[109,2206,2207],{"class":1035},"5.",[109,2209,2210],{"class":115}," Human decisions still open\n",[109,2212,2214],{"class":111,"line":2213},87,[109,2215,153],{"emptyLinePlaceholder":152},[109,2217,2219],{"class":111,"line":2218},88,[109,2220,2221],{"class":989},"## Out of scope\n",[109,2223,2225],{"class":111,"line":2224},89,[109,2226,153],{"emptyLinePlaceholder":152},[109,2228,2230,2232],{"class":111,"line":2229},90,[109,2231,1036],{"class":1035},[109,2233,2234],{"class":115}," Broad \"modernize everything to Java 21\" prompts\n",[109,2236,2238,2240],{"class":111,"line":2237},91,[109,2239,1036],{"class":1035},[109,2241,2242],{"class":115}," HTTP endpoint semantics unrelated to the JDK migration\n",[109,2244,2246,2249,2252],{"class":111,"line":2245},92,[109,2247,2248],{"class":115},"  (use ",[109,2250,2251],{"class":339},"`skills/http-endpoint-collector-behavior/`",[109,2253,1233],{"class":115},[109,2255,2257,2259],{"class":111,"line":2256},93,[109,2258,1036],{"class":1035},[109,2260,2261],{"class":115}," Security triage unrelated to the migration slice\n",[109,2263,2265,2267,2270],{"class":111,"line":2264},94,[109,2266,2248],{"class":115},[109,2268,2269],{"class":339},"`skills/security-triage-java-sensor/`",[109,2271,1233],{"class":115},[12,2273,2275],{"id":2274},"fazit","Fazit",[17,2277,2278],{},"Die drei Use Cases in diesem Tutorial bauen aufeinander auf. Cursor hat allein mit Repository-Kontext einen hingenommenen End-to-End-Testfehler behoben. Dann brachte der GitLab-MCP-Server den Modernisierungsplan herein, sodass Cursor Quality-Gates einziehen und die Schleife beim Duo-Review-Feedback direkt aus der IDE schließen konnte. Schließlich nahm Cursor eine einzige abgegrenzte Java-21-Änderung vor und ersetzte HttpURLConnection durch einen wiederverwendbaren HttpClient, abgesichert durch fokussierte Tests, serviceübergreifende Ingestion-Läufe, Pipeline, Security-Scans, eine Software Bill of Materials, Review-Belege und Impact-Analyse.",[17,2280,2281],{},"Eine Legacy-Java-8-Codebasis wird nicht dadurch sicherer zu modernisieren, dass ein Agent den Code schreibt. Sie wird sicherer, weil jede Änderung abgegrenzt, reviewt, gegen Java 8 und Java 21 getestet und bis zu einem Work Item mit den Entscheidungen und Belegen dahinter nachvollziehbar ist. Cursor übernimmt die Implementierung. GitLab liefert den Nachweis. Zusammen machen sie die Migration zu etwas, dem ein Team vertrauen kann.",[17,2283,2284],{},"Wer diesen Workflow ausprobieren möchte, beginnt mit einem Test, der einen hingenommenen Fehler in einer Legacy-Anwendung offenlegt. Diesen Test verlässlich machen, den größeren Modernisierungsplan in GitLab festhalten und eine Grenze wählen, die sich unabhängig ändern und belegen lässt. Das gibt dem Agenten eine fokussierte Aufgabe und dem Team Belege, die es reviewen kann.",[2286,2287,2288,2296,2304],"blockquote",{},[17,2289,2290,2291,2295],{},"Wer die GitLab Duo Agent Platform heute noch nicht nutzt, kann mit ",[27,2292,2294],{"href":29,"rel":2293},[],"einer kostenlosen Testversion"," beginnen.",[17,2297,2298,2299,262],{},"Wer GitLab bereits im Free-Tier nutzt, kann sich für die GitLab Duo Agent Platform anmelden, indem er ",[27,2300,2303],{"href":2301,"rel":2302},"https://docs.gitlab.com/subscriptions/gitlab_credits/#for-the-free-tier-on-gitlabcom",[],"einigen wenigen Schritten folgt",[17,2305,2306,2307,2312,2313,2318],{},"Und wer bereits GitLab Premium oder Ultimate abonniert hat, kann direkt loslegen, indem er ",[27,2308,2311],{"href":2309,"rel":2310},"https://docs.gitlab.com/user/duo_agent_platform/turn_on_off/",[],"die Duo Agent Platform aktiviert"," und die ",[27,2314,2317],{"href":2315,"rel":2316},"https://docs.gitlab.com/subscriptions/gitlab_credits/#included-credits",[],"enthaltenen"," GitLab Credits aus dem Abonnement nutzt.",[2320,2321,2322],"style",{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .surfw, html code.shiki .surfw{--shiki-default:#005CC5;--shiki-default-font-weight:bold}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}html pre.shiki code .sbYKK, html code.shiki .sbYKK{--shiki-default:#24292E;--shiki-default-font-weight:bold}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}",{"title":104,"searchDepth":119,"depth":119,"links":2324},[2325,2326,2327,2330,2334,2338,2342,2347],{"id":14,"depth":119,"text":15},{"id":75,"depth":119,"text":76},{"id":243,"depth":119,"text":244,"children":2328},[2329],{"id":295,"depth":125,"text":296},{"id":372,"depth":119,"text":57,"children":2331},[2332,2333],{"id":395,"depth":125,"text":396},{"id":438,"depth":125,"text":439},{"id":492,"depth":119,"text":63,"children":2335},[2336,2337],{"id":507,"depth":125,"text":508},{"id":658,"depth":125,"text":659},{"id":766,"depth":119,"text":69,"children":2339},[2340,2341],{"id":824,"depth":125,"text":825},{"id":874,"depth":125,"text":875},{"id":896,"depth":119,"text":897,"children":2343},[2344,2345,2346],{"id":903,"depth":125,"text":904},{"id":953,"depth":125,"text":954},{"id":1575,"depth":125,"text":1576},{"id":2274,"depth":119,"text":2275},"ai","2026-07-22","Dieses Tutorial beginnt mit einem gezielten Test-Fix, führt Quality-Gates ein und setzt Codeänderungen mit Lifecycle-Kontext, Tests und Review-Belegen um.","md",null,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1776457632/llddiylsgwuze0u1rjks.png",{},"/de-de/blog/modernize-java-with-cursor-and-gitlab",{"config":2357,"title":2359,"description":2360},{"noIndex":2358},false,"Java 8 auf 21 modernisieren mit Cursor und GitLab","Cursor implementiert fokussiert, GitLab liefert mit CI/CD, Review und Nachvollziehbarkeit die Belege. Ein Tutorial zur sicheren Java-8-auf-21-Modernisierung.","modernize-java-with-cursor-and-gitlab","de-de/blog/modernize-java-with-cursor-and-gitlab",[2364,2365,2366],"AI","product","tutorial","BlogPost","J8o-MWxY2grX8GDFOv1Sxa7sNcVbz3KsPS4Gp_IkbyY",{"logo":2370,"freeTrial":2375,"sales":2380,"login":2385,"items":2390,"search":2714,"minimal":2747,"duo":2765,"switchNav":2774,"pricingDeployment":2785},{"config":2371},{"href":2372,"dataGaName":2373,"dataGaLocation":2374},"/de-de/","gitlab logo","header",{"text":2376,"config":2377},"Kostenlose Testversion anfordern",{"href":2378,"dataGaName":2379,"dataGaLocation":2374},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/de-de&glm_content=default-saas-trial/","free trial",{"text":2381,"config":2382},"Demo anfordern",{"href":2383,"dataGaName":2384,"dataGaLocation":2374},"/de-de/sales/?contact-topic=request-demo","sales",{"text":2386,"config":2387},"Anmelden",{"href":2388,"dataGaName":2389,"dataGaLocation":2374},"https://gitlab.com/users/sign_in/","sign in",[2391,2420,2522,2527,2636,2692],{"text":2392,"config":2393,"menu":2395},"Plattform",{"dataNavLevelOne":2394},"platform",{"type":2396,"columns":2397},"cards",[2398,2404,2412],{"title":2392,"description":2399,"link":2400},"Die intelligente Orchestrierungsplattform für DevSecOps",{"text":2401,"config":2402},"Die Plattform erkunden",{"href":2403,"dataGaName":2394,"dataGaLocation":2374},"/de-de/platform/",{"title":2405,"description":2406,"link":2407},"GitLab Duo Agent Platform","Agentische KI für den gesamten Software-Lebenszyklus",{"text":2408,"config":2409},"Lerne GitLab Duo kennen",{"href":2410,"dataGaName":2411,"dataGaLocation":2374},"/de-de/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":2413,"description":2414,"link":2415},"Warum GitLab?","Erfahre, warum sich Unternehmen für GitLab entscheiden",{"text":2416,"config":2417},"Mehr erfahren",{"href":2418,"dataGaName":2419,"dataGaLocation":2374},"/de-de/why-gitlab/","why gitlab",{"text":2421,"left":152,"config":2422,"menu":2424},"Produkt",{"dataNavLevelOne":2423},"solutions",{"type":2425,"link":2426,"columns":2430,"feature":2501},"lists",{"text":2427,"config":2428},"Alle Lösungen anzeigen",{"href":2429,"dataGaName":2423,"dataGaLocation":2374},"/de-de/solutions/",[2431,2456,2479],{"title":2432,"description":2433,"link":2434,"items":2439},"Automatisierung","CI/CD und Automatisierung zur Beschleunigung der Bereitstellung",{"config":2435},{"icon":2436,"href":2437,"dataGaName":2438,"dataGaLocation":2374},"AutomatedCodeAlt","/de-de/solutions/delivery-automation/","automated software delivery",[2440,2444,2447,2452],{"text":2441,"config":2442},"CI/CD",{"href":2443,"dataGaLocation":2374,"dataGaName":2441},"/de-de/solutions/continuous-integration/",{"text":2405,"config":2445},{"href":2410,"dataGaLocation":2374,"dataGaName":2446},"gitlab duo agent platform - product menu",{"text":2448,"config":2449},"Quellcodeverwaltung",{"href":2450,"dataGaLocation":2374,"dataGaName":2451},"/de-de/solutions/source-code-management/","Source Code Management",{"text":2453,"config":2454},"Automatische Softwarebereitstellung",{"href":2437,"dataGaLocation":2374,"dataGaName":2455},"Automated software delivery",{"title":2457,"description":2458,"link":2459,"items":2464},"Sicherheit","Entwickle Code schneller ohne Abstriche bei der Sicherheit",{"config":2460},{"href":2461,"dataGaName":2462,"dataGaLocation":2374,"icon":2463},"/de-de/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[2465,2469,2474],{"text":2466,"config":2467},"Anwendungssicherheitstests",{"href":2461,"dataGaName":2468,"dataGaLocation":2374},"Application security testing",{"text":2470,"config":2471},"Schutz der Software-Lieferkette",{"href":2472,"dataGaLocation":2374,"dataGaName":2473},"/de-de/solutions/supply-chain/","Software supply chain security",{"text":2475,"config":2476},"Software-Compliance",{"href":2477,"dataGaName":2478,"dataGaLocation":2374},"/de-de/solutions/software-compliance/","software compliance",{"title":2480,"link":2481,"items":2486},"Messung",{"config":2482},{"icon":2483,"href":2484,"dataGaName":2485,"dataGaLocation":2374},"DigitalTransformation","/de-de/solutions/visibility-measurement/","visibility and measurement",[2487,2491,2496],{"text":2488,"config":2489},"Sichtbarkeit und Messung",{"href":2484,"dataGaLocation":2374,"dataGaName":2490},"Visibility and Measurement",{"text":2492,"config":2493},"Wertstrommanagement",{"href":2494,"dataGaLocation":2374,"dataGaName":2495},"/de-de/solutions/value-stream-management/","Value Stream Management",{"text":2497,"config":2498},"Analysen und Einblicke",{"href":2499,"dataGaLocation":2374,"dataGaName":2500},"/de-de/solutions/analytics-and-insights/","Analytics and insights",{"title":2502,"type":2425,"items":2503},"GitLab für",[2504,2510,2516],{"text":2505,"config":2506},"Enterprise",{"icon":2507,"href":2508,"dataGaLocation":2374,"dataGaName":2509},"Building","/de-de/enterprise/","enterprise",{"text":2511,"config":2512},"Kleinunternehmen",{"icon":2513,"href":2514,"dataGaLocation":2374,"dataGaName":2515},"Work","/de-de/small-business/","small business",{"text":2517,"config":2518},"Öffentlicher Sektor",{"icon":2519,"href":2520,"dataGaLocation":2374,"dataGaName":2521},"Organization","/de-de/solutions/public-sector/","public sector",{"text":2523,"config":2524},"Preise",{"href":2525,"dataGaName":2526,"dataGaLocation":2374,"dataNavLevelOne":2526},"/de-de/pricing/","pricing",{"text":2528,"config":2529,"menu":2531},"Ressourcen",{"dataNavLevelOne":2530},"resources",{"type":2425,"link":2532,"columns":2536,"feature":2625},{"text":2533,"config":2534},"Alle Ressourcen anzeigen",{"href":2535,"dataGaName":2530,"dataGaLocation":2374},"/de-de/resources/",[2537,2570,2592],{"title":2538,"items":2539},"Erste Schritte",[2540,2545,2550,2555,2560,2565],{"text":2541,"config":2542},"Installieren",{"href":2543,"dataGaName":2544,"dataGaLocation":2374},"/de-de/install/","install",{"text":2546,"config":2547},"Kurzanleitungen",{"href":2548,"dataGaName":2549,"dataGaLocation":2374},"/de-de/get-started/","quick setup checklists",{"text":2551,"config":2552},"Lernen",{"href":2553,"dataGaLocation":2374,"dataGaName":2554},"https://university.gitlab.com/","learn",{"text":2556,"config":2557},"Produktdokumentation",{"href":2558,"dataGaName":2559,"dataGaLocation":2374},"https://docs.gitlab.com/","product documentation",{"text":2561,"config":2562},"Best-Practice-Videos",{"href":2563,"dataGaName":2564,"dataGaLocation":2374},"/de-de/getting-started-videos/","best practice videos",{"text":2566,"config":2567},"Integrationen",{"href":2568,"dataGaName":2569,"dataGaLocation":2374},"/de-de/integrations/","integrations",{"title":2571,"items":2572},"Entdecken",[2573,2578,2583,2587],{"text":2574,"config":2575},"Kundenerfolge",{"href":2576,"dataGaName":2577,"dataGaLocation":2374},"/de-de/customers/","customer success stories",{"text":2579,"config":2580},"Blog",{"href":2581,"dataGaName":2582,"dataGaLocation":2374},"/de-de/blog/","blog",{"text":2584,"config":2585},"The Source",{"href":2586,"dataGaName":2582,"dataGaLocation":2374},"/de-de/the-source/",{"text":2588,"config":2589},"Remote",{"href":2590,"dataGaName":2591,"dataGaLocation":2374},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":2593,"items":2594},"Vernetzen",[2595,2600,2605,2610,2615,2620],{"text":2596,"config":2597},"GitLab-Services",{"href":2598,"dataGaName":2599,"dataGaLocation":2374},"/de-de/services/","services",{"text":2601,"config":2602},"Beitragen",{"href":2603,"dataGaName":2604,"dataGaLocation":2374},"https://contributors.gitlab.com","contribute",{"text":2606,"config":2607},"Community",{"href":2608,"dataGaName":2609,"dataGaLocation":2374},"/community/","community",{"text":2611,"config":2612},"Forum",{"href":2613,"dataGaName":2614,"dataGaLocation":2374},"https://forum.gitlab.com/","forum",{"text":2616,"config":2617},"Veranstaltungen",{"href":2618,"dataGaName":2619,"dataGaLocation":2374},"/events/","events",{"text":2621,"config":2622},"Partner",{"href":2623,"dataGaName":2624,"dataGaLocation":2374},"/de-de/partners/","partners",{"config":2626,"title":2629,"text":2630,"link":2631},{"background":2627,"textColor":2628},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","Neues bei GitLab","Über die neuesten Funktionen und Verbesserungen auf dem Laufenden bleiben.",{"text":2632,"config":2633},"Aktuelle Nachrichten",{"href":2634,"dataGaName":2635,"dataGaLocation":2374},"/de-de/whats-new/","whats new",{"text":2637,"config":2638,"menu":2640},"Unternehmen",{"dataNavLevelOne":2639},"company",{"type":2425,"columns":2641},[2642],{"items":2643},[2644,2649,2655,2657,2662,2667,2672,2677,2682,2687],{"text":2645,"config":2646},"Über",{"href":2647,"dataGaName":2648,"dataGaLocation":2374},"/de-de/company/","about",{"text":2650,"config":2651,"footerGa":2654},"Karriere",{"href":2652,"dataGaName":2653,"dataGaLocation":2374},"/jobs/","jobs",{"dataGaName":2653},{"text":2616,"config":2656},{"href":2618,"dataGaName":2619,"dataGaLocation":2374},{"text":2658,"config":2659},"Geschäftsführung",{"href":2660,"dataGaName":2661,"dataGaLocation":2374},"/company/team/e-group/","leadership",{"text":2663,"config":2664},"Handbuch",{"href":2665,"dataGaName":2666,"dataGaLocation":2374},"https://handbook.gitlab.com/","handbook",{"text":2668,"config":2669},"Investor Relations",{"href":2670,"dataGaName":2671,"dataGaLocation":2374},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":2673,"config":2674},"Trust Center",{"href":2675,"dataGaName":2676,"dataGaLocation":2374},"/de-de/security/","trust center",{"text":2678,"config":2679},"AI Transparency Center",{"href":2680,"dataGaName":2681,"dataGaLocation":2374},"/de-de/ai-transparency-center/","ai transparency center",{"text":2683,"config":2684},"Newsletter",{"href":2685,"dataGaName":2686,"dataGaLocation":2374},"/company/contact/#contact-forms","newsletter",{"text":2688,"config":2689},"Presse",{"href":2690,"dataGaName":2691,"dataGaLocation":2374},"/press/","press",{"text":2693,"config":2694,"menu":2695},"Kontakt",{"dataNavLevelOne":2639},{"type":2425,"columns":2696},[2697],{"items":2698},[2699,2704,2709],{"text":2700,"config":2701},"Vertrieb kontaktieren",{"href":2702,"dataGaName":2703,"dataGaLocation":2374},"/de-de/sales/","talk to sales",{"text":2705,"config":2706},"Support-Portal",{"href":2707,"dataGaName":2708,"dataGaLocation":2374},"https://support.gitlab.com/hc/en-us","support portal",{"text":2710,"config":2711},"Kundenportal",{"href":2712,"dataGaName":2713,"dataGaLocation":2374},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":2715,"login":2716,"suggestions":2722},"Schließen",{"text":2717,"link":2718},"Um Repositorys und Projekte zu durchsuchen, melde dich an bei",{"text":565,"config":2719},{"href":2388,"dataGaName":2720,"dataGaLocation":2721},"search login","search",{"text":2723,"default":2724},"Vorschläge",[2725,2727,2732,2734,2739,2744],{"text":2405,"config":2726},{"href":2410,"dataGaName":2405,"dataGaLocation":2721},{"text":2728,"config":2729},"Codevorschläge (KI)",{"href":2730,"dataGaName":2731,"dataGaLocation":2721},"/de-de/solutions/code-suggestions/","Code Suggestions (AI)",{"text":2441,"config":2733},{"href":2443,"dataGaName":2441,"dataGaLocation":2721},{"text":2735,"config":2736},"GitLab auf AWS",{"href":2737,"dataGaName":2738,"dataGaLocation":2721},"/de-de/partners/technology-partners/aws/","GitLab on AWS",{"text":2740,"config":2741},"GitLab auf Google Cloud",{"href":2742,"dataGaName":2743,"dataGaLocation":2721},"/de-de/partners/technology-partners/google-cloud-platform/","GitLab on Google Cloud",{"text":2413,"config":2745},{"href":2418,"dataGaName":2746,"dataGaLocation":2721},"Why GitLab?",{"freeTrial":2748,"mobileIcon":2753,"desktopIcon":2758,"secondaryButton":2761},{"text":2749,"config":2750},"Kostenlos testen",{"href":2751,"dataGaName":2379,"dataGaLocation":2752},"https://gitlab.com/-/trials/new/","nav",{"altText":2754,"config":2755},"GitLab-Symbol",{"src":2756,"dataGaName":2757,"dataGaLocation":2752},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":2754,"config":2759},{"src":2760,"dataGaName":2757,"dataGaLocation":2752},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":2538,"config":2762},{"href":2763,"dataGaName":2764,"dataGaLocation":2752},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/de-de/get-started/","get started",{"freeTrial":2766,"mobileIcon":2770,"desktopIcon":2772},{"text":2767,"config":2768},"Mehr über GitLab Duo erfahren",{"href":2410,"dataGaName":2769,"dataGaLocation":2752},"gitlab duo",{"altText":2754,"config":2771},{"src":2756,"dataGaName":2757,"dataGaLocation":2752},{"altText":2754,"config":2773},{"src":2760,"dataGaName":2757,"dataGaLocation":2752},{"button":2775,"mobileIcon":2780,"desktopIcon":2782},{"text":2776,"config":2777},"/Option",{"href":2778,"dataGaName":2779,"dataGaLocation":2752},"#contact","switch",{"altText":2754,"config":2781},{"src":2756,"dataGaName":2757,"dataGaLocation":2752},{"altText":2754,"config":2783},{"src":2784,"dataGaName":2757,"dataGaLocation":2752},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":2786,"mobileIcon":2791,"desktopIcon":2793},{"text":2787,"config":2788},"Zurück zur Preisübersicht",{"href":2525,"dataGaName":2789,"dataGaLocation":2752,"icon":2790},"back to pricing","GoBack",{"altText":2754,"config":2792},{"src":2756,"dataGaName":2757,"dataGaLocation":2752},{"altText":2754,"config":2794},{"src":2760,"dataGaName":2757,"dataGaLocation":2752},{"title":2796,"button":2797,"config":2801},"GitLab Orbit ist da: die Kontextebene für KI-Agenten",{"text":2416,"config":2798},{"href":2799,"dataGaName":2800,"dataGaLocation":2374},"/de-de/gitlab-orbit/","orbit",{"layout":2802,"disabled":2358},"release",{"data":2804},{"text":2805,"source":2806,"edit":2812,"contribute":2817,"config":2822,"items":2827,"minimal":3033},"Git ist eine Marke von Software Freedom Conservancy und unsere Verwendung von „GitLab“ erfolgt unter Lizenz.",{"text":2807,"config":2808},"Quelltext der Seite anzeigen",{"href":2809,"dataGaName":2810,"dataGaLocation":2811},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":2813,"config":2814},"Diese Seite bearbeiten",{"href":2815,"dataGaName":2816,"dataGaLocation":2811},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":2818,"config":2819},"Beteilige dich",{"href":2820,"dataGaName":2821,"dataGaLocation":2811},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":2823,"facebook":2824,"youtube":2825,"linkedin":2826},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[2828,2873,2926,2968,3000],{"title":2523,"links":2829,"subMenu":2844},[2830,2834,2839],{"text":2831,"config":2832},"Tarife anzeigen",{"href":2525,"dataGaName":2833,"dataGaLocation":2811},"view plans",{"text":2835,"config":2836},"Vorteile von Premium",{"href":2837,"dataGaName":2838,"dataGaLocation":2811},"/de-de/pricing/premium/","why premium",{"text":2840,"config":2841},"Vorteile von Ultimate",{"href":2842,"dataGaName":2843,"dataGaLocation":2811},"/de-de/pricing/ultimate/","why ultimate",[2845],{"title":2693,"links":2846},[2847,2849,2851,2853,2858,2863,2868],{"text":2700,"config":2848},{"href":2702,"dataGaName":2384,"dataGaLocation":2811},{"text":2705,"config":2850},{"href":2707,"dataGaName":2708,"dataGaLocation":2811},{"text":2710,"config":2852},{"href":2712,"dataGaName":2713,"dataGaLocation":2811},{"text":2854,"config":2855},"Status",{"href":2856,"dataGaName":2857,"dataGaLocation":2811},"https://status.gitlab.com/","status",{"text":2859,"config":2860},"Nutzungsbedingungen",{"href":2861,"dataGaName":2862,"dataGaLocation":2811},"/terms/","terms of use",{"text":2864,"config":2865},"Datenschutzerklärung",{"href":2866,"dataGaName":2867,"dataGaLocation":2811},"/de-de/privacy/","privacy statement",{"text":2869,"config":2870},"Cookie-Einstellungen",{"dataGaName":2871,"dataGaLocation":2811,"id":2872,"isOneTrustButton":152},"cookie preferences","ot-sdk-btn",{"title":2421,"links":2874,"subMenu":2883},[2875,2879],{"text":2876,"config":2877},"DevSecOps-Plattform",{"href":2403,"dataGaName":2878,"dataGaLocation":2811},"devsecops platform",{"text":2880,"config":2881},"KI-unterstützte Entwicklung",{"href":2410,"dataGaName":2882,"dataGaLocation":2811},"ai-assisted development",[2884],{"title":2885,"links":2886},"Themen",[2887,2891,2896,2901,2906,2911,2916,2921],{"text":2441,"config":2888},{"href":2889,"dataGaName":2890,"dataGaLocation":2811},"/de-de/topics/ci-cd/","cicd",{"text":2892,"config":2893},"GitOps",{"href":2894,"dataGaName":2895,"dataGaLocation":2811},"/de-de/topics/gitops/","gitops",{"text":2897,"config":2898},"DevOps",{"href":2899,"dataGaName":2900,"dataGaLocation":2811},"/de-de/topics/devops/","devops",{"text":2902,"config":2903},"Versionskontrolle",{"href":2904,"dataGaName":2905,"dataGaLocation":2811},"/de-de/topics/version-control/","version control",{"text":2907,"config":2908},"DevSecOps",{"href":2909,"dataGaName":2910,"dataGaLocation":2811},"/de-de/topics/devsecops/","devsecops",{"text":2912,"config":2913},"Cloud-nativ",{"href":2914,"dataGaName":2915,"dataGaLocation":2811},"/de-de/topics/cloud-native/","cloud native",{"text":2917,"config":2918},"KI für das Programmieren",{"href":2919,"dataGaName":2920,"dataGaLocation":2811},"/de-de/topics/devops/ai-for-coding/","ai for coding",{"text":2922,"config":2923},"Agentische KI",{"href":2924,"dataGaName":2925,"dataGaLocation":2811},"/de-de/topics/agentic-ai/","agentic ai",{"title":2927,"links":2928},"Lösungen",[2929,2932,2934,2939,2943,2946,2949,2952,2954,2956,2958,2963],{"text":2466,"config":2930},{"href":2461,"dataGaName":2931,"dataGaLocation":2811},"Application Security Testing",{"text":2453,"config":2933},{"href":2437,"dataGaName":2438,"dataGaLocation":2811},{"text":2935,"config":2936},"Agile Entwicklung",{"href":2937,"dataGaName":2938,"dataGaLocation":2811},"/de-de/solutions/agile-delivery/","agile delivery",{"text":2940,"config":2941},"SCM",{"href":2450,"dataGaName":2942,"dataGaLocation":2811},"source code management",{"text":2441,"config":2944},{"href":2443,"dataGaName":2945,"dataGaLocation":2811},"continuous integration & delivery",{"text":2492,"config":2947},{"href":2494,"dataGaName":2948,"dataGaLocation":2811},"value stream management",{"text":2892,"config":2950},{"href":2951,"dataGaName":2895,"dataGaLocation":2811},"/de-de/solutions/gitops/",{"text":2505,"config":2953},{"href":2508,"dataGaName":2509,"dataGaLocation":2811},{"text":2511,"config":2955},{"href":2514,"dataGaName":2515,"dataGaLocation":2811},{"text":2517,"config":2957},{"href":2520,"dataGaName":2521,"dataGaLocation":2811},{"text":2959,"config":2960},"Bildungswesen",{"href":2961,"dataGaName":2962,"dataGaLocation":2811},"/de-de/solutions/education/","education",{"text":2964,"config":2965},"Finanzdienstleistungen",{"href":2966,"dataGaName":2967,"dataGaLocation":2811},"/de-de/solutions/finance/","financial services",{"title":2528,"links":2969},[2970,2972,2974,2976,2979,2981,2984,2986,2988,2990,2992,2994,2996,2998],{"text":2541,"config":2971},{"href":2543,"dataGaName":2544,"dataGaLocation":2811},{"text":2546,"config":2973},{"href":2548,"dataGaName":2549,"dataGaLocation":2811},{"text":2551,"config":2975},{"href":2553,"dataGaName":2554,"dataGaLocation":2811},{"text":2556,"config":2977},{"href":2558,"dataGaName":2978,"dataGaLocation":2811},"docs",{"text":2579,"config":2980},{"href":2581,"dataGaName":2582,"dataGaLocation":2811},{"text":2982,"config":2983},"Neuerungen",{"href":2634,"dataGaName":2635,"dataGaLocation":2811},{"text":2574,"config":2985},{"href":2576,"dataGaName":2577,"dataGaLocation":2811},{"text":2588,"config":2987},{"href":2590,"dataGaName":2591,"dataGaLocation":2811},{"text":2596,"config":2989},{"href":2598,"dataGaName":2599,"dataGaLocation":2811},{"text":2601,"config":2991},{"href":2603,"dataGaName":2604,"dataGaLocation":2811},{"text":2606,"config":2993},{"href":2608,"dataGaName":2609,"dataGaLocation":2811},{"text":2611,"config":2995},{"href":2613,"dataGaName":2614,"dataGaLocation":2811},{"text":2616,"config":2997},{"href":2618,"dataGaName":2619,"dataGaLocation":2811},{"text":2621,"config":2999},{"href":2623,"dataGaName":2624,"dataGaLocation":2811},{"title":2637,"links":3001},[3002,3004,3006,3008,3010,3012,3017,3022,3024,3026,3028],{"text":2645,"config":3003},{"href":2647,"dataGaName":2639,"dataGaLocation":2811},{"text":2650,"config":3005},{"href":2652,"dataGaName":2653,"dataGaLocation":2811},{"text":2658,"config":3007},{"href":2660,"dataGaName":2661,"dataGaLocation":2811},{"text":2663,"config":3009},{"href":2665,"dataGaName":2666,"dataGaLocation":2811},{"text":2668,"config":3011},{"href":2670,"dataGaName":2671,"dataGaLocation":2811},{"text":3013,"config":3014},"Nachhaltigkeit",{"href":3015,"dataGaName":3016,"dataGaLocation":2811},"/sustainability/","Sustainability",{"text":3018,"config":3019},"Vielfalt, Inklusion und Zugehörigkeit",{"href":3020,"dataGaName":3021,"dataGaLocation":2811},"/de-de/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":2673,"config":3023},{"href":2675,"dataGaName":2676,"dataGaLocation":2811},{"text":2683,"config":3025},{"href":2685,"dataGaName":2686,"dataGaLocation":2811},{"text":2688,"config":3027},{"href":2690,"dataGaName":2691,"dataGaLocation":2811},{"text":3029,"config":3030},"Transparenzerklärung zu moderner Sklaverei",{"href":3031,"dataGaName":3032,"dataGaLocation":2811},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":3034},[3035,3038,3041],{"text":3036,"config":3037},"Terms",{"href":2861,"dataGaName":2862,"dataGaLocation":2811},{"text":3039,"config":3040},"Cookies",{"dataGaName":2871,"dataGaLocation":2811,"id":2872,"isOneTrustButton":152},{"text":3042,"config":3043},"Datenschutz",{"href":2866,"dataGaName":2867,"dataGaLocation":2811},[3045],{"id":3046,"title":7,"body":2352,"config":3047,"content":3049,"description":2352,"extension":3053,"meta":3054,"navigation":152,"path":3055,"seo":3056,"stem":3057,"__hash__":3058},"blogAuthors/en-us/blog/authors/michael-friedrich.yml",{"template":3048},"BlogAuthor",{"name":7,"config":3050},{"headshot":3051,"ctfId":3052},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659879/Blog/Author%20Headshots/dnsmichi-headshot.jpg","dnsmichi","yml",{},"/en-us/blog/authors/michael-friedrich",{},"en-us/blog/authors/michael-friedrich","lJ-nfRIhdG49Arfrxdn1Vv4UppwD51BB13S3HwIswt4",[3060,3068,3076],{"title":3061,"description":3062,"heroImage":3063,"category":2348,"date":3064,"authors":3065,"slug":3067,"externalUrl":2352},"Was die Community beim Transcend Hackathon auf GitLab Orbit gebaut hat","Beim Transcend Hackathon entstanden Agenten, Flows und Skills auf GitLab Orbit – für Fragen, die ein Code-Graph in einer einzigen Abfrage beantwortet.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1780996524/sd1vpl8empy26wizarqj.png","2026-07-20",[3066],"Mattias Michaux","gitlab-transcend-hackathon-orbit",{"title":3069,"description":3070,"heroImage":3071,"category":2348,"date":3072,"authors":3073,"slug":3075,"externalUrl":2352},"Mehrstufige Software-Delivery wird zu vertrauenswürdigen Agentic Flows","Mehrstufige Abläufe einmal definieren, über GitLab-Events auslösen und in der Pipeline ausführen – mit Custom Flows, jetzt allgemein verfügbar.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1783980535/t3gez0gpayfndrhncunf.png","2026-07-16",[3074],"Ozer Dondurmacioglu","multi-step-software-delivery-with-agentic-flows",{"title":3077,"description":3078,"heroImage":3071,"category":2348,"date":3072,"authors":3079,"slug":3080,"externalUrl":2352},"Die GitLab Duo Agent Platform kommt ins Terminal","Duo CLI ist mit GitLab 19.2 jetzt allgemein verfügbar – für Code, Pipelines und mehrstufige Arbeit direkt in der Shell.",[3074],"gitlab-duo-cli-generally-available",{"promotions":3082},[3083,3096,3107,3119],{"id":3084,"categories":3085,"header":3086,"text":3087,"button":3088,"image":3093},"ai-modernization",[2348],"Hält KI, was uns versprochen wurde?","Das Quiz dauert maximal 5 Minuten.",{"text":3089,"config":3090},"Ermittle deinen KI-Reifegrad",{"href":3091,"dataGaName":3092,"dataGaLocation":2582},"/de-de/assessments/ai-modernization-assessment/","modernization assessment",{"config":3094},{"src":3095},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":3097,"categories":3098,"header":3099,"text":3087,"button":3100,"image":3104},"devops-modernization",[2365,2910],"Verwaltest du Tool-Chaos oder stellst du Innovationen bereit?",{"text":3101,"config":3102},"Ermittle deinen DevOps-Reifegrad",{"href":3103,"dataGaName":3092,"dataGaLocation":2582},"/de-de/assessments/devops-modernization-assessment/",{"config":3105},{"src":3106},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":3108,"categories":3109,"header":3111,"text":3087,"button":3112,"image":3116},"security-modernization",[3110],"security","Tauschst du Schnelligkeit gegen Sicherheit ein?",{"text":3113,"config":3114},"Ermittle deinen Sicherheitsreifegrad",{"href":3115,"dataGaName":3092,"dataGaLocation":2582},"/de-de/assessments/security-modernization-assessment/",{"config":3117},{"src":3118},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":3120,"paths":3121,"header":3124,"text":3125,"button":3126,"image":3131},"github-azure-migration",[3122,3123],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Ist dein Team bereit für den Umzug von GitHub nach Azure?","GitHub stellt bereits auf Azure um. Finde heraus, was das für dich bedeutet.",{"text":3127,"config":3128},"Erfahre, wie GitLab im Vergleich zu GitHub abschneidet",{"href":3129,"dataGaName":3130,"dataGaLocation":2582},"/de-de/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":3132},{"src":3106},{"header":3134,"blurb":3135,"button":3136,"secondaryButton":3141},"Beginne noch heute, schneller zu entwickeln","Entdecke, was dein Team mit der intelligenten Orchestrierungsplattform für DevSecOps erreichen kann.\n",{"text":3137,"config":3138},"Kostenlosen Test starten",{"href":3139,"dataGaName":2379,"dataGaLocation":3140},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/de-de/","feature",{"text":2700,"config":3142},{"href":2702,"dataGaName":2384,"dataGaLocation":3140},1784820518363]