{"id":28021,"date":"2025-09-13T14:06:43","date_gmt":"2025-09-13T12:06:43","guid":{"rendered":"https:\/\/blog.mi.hdm-stuttgart.de\/?p=28021"},"modified":"2025-09-13T17:03:53","modified_gmt":"2025-09-13T15:03:53","slug":"multiplayer-web-game-mit-aws-schiffe-versenken","status":"publish","type":"post","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/09\/13\/multiplayer-web-game-mit-aws-schiffe-versenken\/","title":{"rendered":"Multiplayer Web-Game mit AWS | Schiffe versenken"},"content":{"rendered":"\n<h3 class=\"wp-block-heading\"><strong>Projektidee<\/strong>:<\/h3>\n\n\n\n<p>Im Rahmen der Vorlesung &#8220;Software Development for Cloud Computing&#8221; sollen die Studierenden in Gruppen ein eigenes Projekt, mit Hilfe von in der Vorlesung gezeigten Cloud Technologien umsetzen. Wir hatten Anfangs Probleme ein geeignetes Thema zu finden, da unser Wissenstand im Thema Cloud nicht besonders gro\u00df war. Letztendlich haben wir uns dazu entschieden ein Multiplayer Spiel im Web umzusetzen, welches auf ein serverless Backend setzt, welches in der AWS-Cloud sitzt. Dabei wollten wir uns ein bisschen mehr herausfordern und ein Spiel als Vorlage nehmen, welches zwar einfach umzusetzen ist, aber auch seine Kniffe hat.<br>Letzen Endes fiel unsere Entscheidung darauf eine Version des bekannten Spiel &#8220;Schiffe versenken&#8221; umzusetzen. &#8220;Schiffe versenken&#8221; hat ein relativ einfaches Spielsystem und ben\u00f6tigt keine komplizierten Berechnungen und eignet sich daher gut f\u00fcr ein erstes \u00dcbungsprojekt im Thema Cloud. Wir hatten Anfangs die Sorge, dass der Projektscope zu klein ist und haben uns bereits M\u00f6glichkeiten \u00fcberlegt, welche das Spielprinzip von &#8220;Schiffe versenken&#8221; interessanter machen, wie z.B. ein Multiplayer mit mehr als zwei Spielern, ein Matchmaking-System, Power-Ups, verschiedene Karten, und noch mehr. Dazu sind wir allerdings aufgrund der untersch\u00e4tzten Komplexit\u00e4t nicht mehr gekommen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Planung und erste Mockups<\/strong>:<\/h3>\n\n\n\n<p>Als erstes haben wir uns \u00fcberlegt, was unsere Applikation im ersten Schritt k\u00f6nnen soll, daf\u00fcr haben wir uns sowohl mit den Technologien als auch mit dem Prinzip des Spiels Schiffe versenken auseinander gesetzt und haben darauf hin einen ersten groben Projektplan entworfen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>1. Schritt<\/strong>\n<ul class=\"wp-block-list\">\n<li>Entwicklung eines Hauptmen\u00fcs, in welchem der Spieler ein neues Spiel erstellen oder einem bestehenden Spiel mit einem Lobby Code beitreten kann. Au\u00dferdem haben wir an dieser Stelle auch bereits eine M\u00f6glichkeit f\u00fcr Einstellungen und Matchmaking konzeptioniert auch wenn wir dazu nicht mehr gekommen sind.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>2. Schritt<\/strong>\n<ul class=\"wp-block-list\">\n<li>Entwicklung einer Lobby, in welcher die Spieler ihre Spielfelder bauen und sich anschlie\u00dfend bereit setzen k\u00f6nnen, damit der Host anschlie\u00dfend das Spiel starten kann.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>3. Schritt <\/strong>\n<ul class=\"wp-block-list\">\n<li>Entwicklung des Spielfelds und des Spiels selber, nach den klassischen Regeln von Schiffe versenken. <\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>4. Schritt<\/strong>\n<ul class=\"wp-block-list\">\n<li>Entwicklung von unseren Erweiterungen des Spielprinzips von Schiffe versenken. <\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>So ein Projektplan ist zwar ganz gut, aber wir mussten schnell feststellen, dass wir oft Dinge vergessen oder \u00fcbersehen haben, sodass das Endprodukt durchaus anders war als urspr\u00fcnglich gedacht.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Erste Mockups<\/h4>\n\n\n\n<div class=\"wp-block-jetpack-slideshow aligncenter\" data-effect=\"slide\" style=\"--aspect-ratio:calc(1034 \/ 579)\"><div class=\"wp-block-jetpack-slideshow_container swiper\"><ul class=\"wp-block-jetpack-slideshow_swiper-wrapper swiper-wrapper\"><li class=\"wp-block-jetpack-slideshow_slide swiper-slide\"><figure><img loading=\"lazy\" decoding=\"async\" width=\"1034\" height=\"579\" alt=\"\" class=\"wp-block-jetpack-slideshow_image wp-image-28024\" data-id=\"28024\" data-aspect-ratio=\"1034 \/ 579\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/MockupMainMenu.png\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/MockupMainMenu.png 1034w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/MockupMainMenu-300x168.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/MockupMainMenu-1024x573.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/MockupMainMenu-768x430.png 768w\" sizes=\"(max-width: 1034px) 100vw, 1034px\" \/><figcaption class=\"wp-block-jetpack-slideshow_caption gallery-caption\">Erstes Mockup des Hauptmen\u00fcs<\/figcaption><\/figure><\/li><li class=\"wp-block-jetpack-slideshow_slide swiper-slide\"><figure><img loading=\"lazy\" decoding=\"async\" width=\"1242\" height=\"698\" alt=\"\" class=\"wp-block-jetpack-slideshow_image wp-image-28025\" data-id=\"28025\" data-aspect-ratio=\"1242 \/ 698\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-113429.png\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-113429.png 1242w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-113429-300x169.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-113429-1024x575.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-113429-768x432.png 768w\" sizes=\"(max-width: 1242px) 100vw, 1242px\" \/><figcaption class=\"wp-block-jetpack-slideshow_caption gallery-caption\">Erstes Mockup des Spielfelds<\/figcaption><\/figure><\/li><\/ul><a class=\"wp-block-jetpack-slideshow_button-prev swiper-button-prev swiper-button-white\" role=\"button\"><\/a><a class=\"wp-block-jetpack-slideshow_button-next swiper-button-next swiper-button-white\" role=\"button\"><\/a><a aria-label=\"Pause Slideshow\" class=\"wp-block-jetpack-slideshow_button-pause\" role=\"button\"><\/a><div class=\"wp-block-jetpack-slideshow_pagination swiper-pagination swiper-pagination-white\"><\/div><\/div><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Architektur und Technologien:<\/strong><\/h3>\n\n\n\n<p>Als n\u00e4chstes haben wir uns \u00fcberlegt, welche Technologien wir f\u00fcr unser Projekt nutzen wollen und welche Lernerfahrungen wir damit machen wollen. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Frontend:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Next.js als Frontendframework<\/li>\n\n\n\n<li>Node.js f\u00fcr den Build<\/li>\n\n\n\n<li>Typescript \/ TSX <\/li>\n\n\n\n<li>Erst Static Web Hosting mit AWS S3 sp\u00e4ter normales Hosting mit Vercel<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Backend:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Node.js Runtime (erst 20.x sp\u00e4ter umgestellt auf 24.x, da der Support f\u00fcr 20.x im September von Amazon eingestellt wurde.)<\/li>\n\n\n\n<li>AWS Lambda Funktionen <\/li>\n\n\n\n<li>DynamoDb (NoSql Datenbank)<\/li>\n\n\n\n<li>AWS Cloudwatch zum debuggen<\/li>\n\n\n\n<li>Terraform Konfiguration f\u00fcr automatisches Deployment des gesamten Backends<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>Die Schnittstelle zwischen Frontend und den Lambda Funktionen bildet ein AWS ApiGateway, auf welchem unser WebSocket l\u00e4uft. Wir haben uns \u00fcberlegt, ob wir lieber mit einer REST Schnittstelle arbeiten wollen, haben uns aber dagegen entschieden, da wir beide bisher noch nicht mit Websockets gearbeitet haben und wir somit hier eine weitere Lernerfahrung einbauen konnten. Au\u00dferdem hat sich sp\u00e4ter herausgestellt, dass im Kontext eines 1 vs. 1 Game ein WebSocket die bessere Wahl war.<br><br>Als Architektur haben wir uns f\u00fcr eine &#8220;Serverless Web Application&#8221; Architektur in AWS entschieden. Wir haben uns nur kurz mit anderen Cloud Providern besch\u00e4ftigt, da wir der Meinung waren, dass das umfassende Free Tier von AWS ein guter Einstiegspunkt in die Cloudwelt ist. Au\u00dferdem wurde im Kontext Serverless in der Vorlesung haupts\u00e4chlich AWS vorgef\u00fchrt, weswegen uns die Entscheidung dahingehend relativ einfach viel.<\/p>\n\n\n\n<p>Serverless bedeutet, dass wir keine Server verwalten m\u00fcssen. AWS \u00fcbernimmt Skalierung, Wartung und Abrechnung nach Nutzung. Das spart Zeit und Kosten, vor allem in der fr\u00fchen Projektphase. Nachteil bei unserer Architektur mit AWS ist, dass wir uns damit stark von Amazon abh\u00e4ngig machen (Vendor Lock-in) und wir teilweise in der Ausf\u00fchrungszeit und der Konfiguration eingeschr\u00e4nkt sind. Bei gro\u00dfen Projekten mit komplexeren Funktionen eignet sich eine vollst\u00e4ndig Serverless Applikation also eher nicht. Hier k\u00f6nnte man dann eher auf ein Backend in Container-Architekturen wie Kubernetes nutzen. Diese bieten mehr Kontrolle und Flexibilit\u00e4t, erfordern aber deutlich mehr Aufwand im Setup und Betrieb. F\u00fcr unser kleines Projekt hat sich die Serverless Architektur als sehr praktisch erwiesen.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-13-120429.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"612\" data-attachment-id=\"28057\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/09\/13\/multiplayer-web-game-mit-aws-schiffe-versenken\/screenshot-2025-09-13-120429\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-13-120429.png\" data-orig-size=\"1545,924\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Screenshot 2025-09-13 120429\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-13-120429-1024x612.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-13-120429-1024x612.png\" alt=\"\" class=\"wp-image-28057\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-13-120429-1024x612.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-13-120429-300x179.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-13-120429-768x459.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-13-120429-1536x919.png 1536w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-13-120429.png 1545w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Projektvorstellung:<\/strong><\/h3>\n\n\n\n<p>Im Nachfolgenden Abschnitt stellen wir kurz den Stand unseres Projektes zum Zeitpunkt der Abgabe vor. Sobald man die Domain aufruft, wird man automatisch in das Men\u00fc weitergeleitet. Dort muss man zuerst seine Schiffe platzieren. Wir haben uns gegen das platzieren in der Lobby entschieden, damit die Lobby nicht so lange aufrecht erhalten werden muss, dazu aber sp\u00e4ter mehr. Das kann man per Drag &amp; Drop machen. W\u00e4hlt man ein Schiff auf dem Spielfeld aus, wird es rot umrandet und man kann mit der R-Taste das Schiff um 90\u00b0 drehen. Die ausgegrauten Buttons sind Features die wir zeitlich nicht mehr entwickeln konnten. Der Debug Button logt uns das Schiff Spielfeld in die Konsole, das war f\u00fcr das debuggen enorm wichtig, da das erstellen der Spielfelder nicht ganz so einfach war, wie anfangs gedacht.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"614\" data-attachment-id=\"28026\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/09\/13\/multiplayer-web-game-mit-aws-schiffe-versenken\/1024-614\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614.png\" data-orig-size=\"1024,614\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"1024-614\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614.png\" alt=\"\" class=\"wp-image-28026\" style=\"width:714px;height:auto\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614-300x180.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614-768x461.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Sofern ein Spieler Schiffe platziert hat, kann er \u00fcber Spiel erstellen und Spiel beitreten. Hierbei \u00f6ffnet sich ein Dialog Fenster in welchem der Spieler seinen Namen eingeben kann und wenn man einem Spiel beitritt wird auch noch ein Lobbycode ben\u00f6tigt, welcher initial vom Backend beim erstellen eines Spiels erstellt wird. Sofern alles richtig funktioniert hat, wird man in die Lobby weitergeleitet, in welcher sich beide Nutzer bereit setzen k\u00f6nnen. Anschlie\u00dfend kann der Host des Spiels das Spiel starten.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614-1-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"614\" data-attachment-id=\"28028\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/09\/13\/multiplayer-web-game-mit-aws-schiffe-versenken\/1024-614-1-2\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614-1-1.png\" data-orig-size=\"1024,614\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"1024-614 (1)\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614-1-1.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614-1-1.png\" alt=\"\" class=\"wp-image-28028\" style=\"width:715px;height:auto\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614-1-1.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614-1-1-300x180.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-614-1-1-768x461.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Sobald der Lobby-Ersteller das Spiel startet, werden beide Nutzer auf die Seite \/game weitergeleitet und das Spiel beginnt, dabei ist der Host des Spiels immer als erster dran. Solange man einen Treffer erzielt, kann man weiterraten, ansonsten ist der Gegner dran. Das Spiel ist beendet, sobald alle Schiffe eines Spielers gefunden wurden. Dann kann man zum Hauptmen\u00fc zur\u00fcckkehren und das Spiel von vorne spielen. Eine Regel des Spiels haben wir dabei nicht eingebaut, normalerweise muss zwischen Schiffen immer ein Feld Platz sein, da wir aber gro\u00dfe Probleme mit dem erstellen der Spielfelder hatten, gerade was die Validierung dieser anging, haben wir diese Regel sowohl im Spiel als auch in der Erstellung nicht beachtet.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-223803-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"614\" data-attachment-id=\"28054\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/09\/13\/multiplayer-web-game-mit-aws-schiffe-versenken\/screenshot-2025-09-12-223803-2\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-223803-1.png\" data-orig-size=\"1630,978\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Screenshot 2025-09-12 223803\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-223803-1-1024x614.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-223803-1-1024x614.png\" alt=\"\" class=\"wp-image-28054\" style=\"width:722px;height:auto\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-223803-1-1024x614.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-223803-1-300x180.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-223803-1-768x461.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-223803-1-1536x922.png 1536w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/Screenshot-2025-09-12-223803-1.png 1630w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Frontend:<\/strong><\/h3>\n\n\n\n<p>Wie bereits erw\u00e4hnt, haben wir uns entschieden, das Frontend mit NextJS umzusetzen, da wir damit schon erste Erfahrungen hatten und man in NextJS mit dem neuen App-Router sehr einfach Single Page Applikationen umsetzen kann. Der ganze Code soll dabei lokal im Browser laufen. In NextJS ben\u00f6tigt man daf\u00fcr client-Components. Diese werden zu Beginn jeder Komponente als solche deklariert. Diese client-Components werden einmal generiert und dann werden dieselben Dateien an die Benutzer geschickt. Bei Server-Components hingegen k\u00f6nnen die zur\u00fcckgegebenen Dateien je nach Anfrage auch anders aussehen.<\/p>\n\n\n\n<p>Zuerst war geplant, das NextJS-Projekt einmal zu bauen und dann in einen S3-Bucket hochzuladen. Dort gibt man die index.html-Datei an, auf die der Benutzer beim Besuchen der Seite geleitet wird. Dann hat man eine statische Website mit html-, CSS- und JavaScript-Dateien, die unver\u00e4ndert an den Browser geschickt werden. Das hat einige Vorteile und Nachteile: Die Dateien lassen sich gut in Content Delivery Networks (CDN) cachen, wodurch die Seite schnell geladen wird. Au\u00dferdem ist kein kompliziertes Server-Backend notwendig, sondern es m\u00fcssen nur Dateien irgendwo hochgeladen und zur Verf\u00fcgung gestellt werden. Das macht es sehr kosteng\u00fcnstig. Au\u00dferdem sind solche statischen Seiten sehr sicher, weil kein serverseitiger Code ausgef\u00fchrt wird, der Schwachstellen haben k\u00f6nnte.<\/p>\n\n\n\n<p>Allerdings bringt diese Methode auch einige Nachteile mit sich, die uns dazu gebracht haben, das ganze doch nicht so umzusetzen:<\/p>\n\n\n\n<p>Zuallererst hat es nicht sofort ohne Probleme geklappt. Sobald man das NextJS-Projekt gebaut hat, sah die Seite die da heraus gekommen war sehr anders aus (siehe Abbildung). Offenbar konnten die CSS-Attribute f\u00fcr eine statische Seite so nicht genutzt werden. Das Frontend war allerdings schon ziemlich fortgeschritten, weshalb eine \u00c4nderung hier einen deutlichen Aufwand bedeutet h\u00e4tte. Au\u00dferdem k\u00f6nnen Funktionen von NextJS bei den statischen Seiten nicht genutzt werden, wie z.B. der App-Router. Dieser bewirkt, dass sich die Ordnerstruktur in der URL widerspiegelt. Hat man z.B. den Ordner &#8220;menu&#8221;, dann erh\u00e4lt man beim Aufruf von &#8220;example.com\/menu&#8221; die page.tsx-Datei aus diesem Ordner. Dieses Routing wird beim Bauen der Seite f\u00fcr eine statische Seite nicht \u00fcbersetzt. Somit funktioniert das Routing nicht mehr. Auch das Auslesen von URL-Parametern (z.B. &#8220;example.com\/lobby?gameId=U4FG56&#8221;) h\u00e4tte Probleme bereitet. Somit haben wir uns gegen das Hosten eine statischen Seite entscheiden und haben die Seite auf Vercel, dem Entwickler hinter NextJS, gehostet. Trotzdem haben wir darauf geachtet, m\u00f6glichst viele Client-Komponenten einzubauen, um die Interaktivit\u00e4t mit der Seite z.B. beim Drag and Drop der Schiffe oder dem Nutzen von Browser-APIs wie das Kopieren des Lobby-Codes \u00fcber einen Knopf zu erm\u00f6glichen.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-517-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"302\" data-attachment-id=\"28048\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/09\/13\/multiplayer-web-game-mit-aws-schiffe-versenken\/1024-517-2\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-517-1.png\" data-orig-size=\"1024,302\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"1024-517\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-517-1.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-517-1.png\" alt=\"\" class=\"wp-image-28048\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-517-1.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-517-1-300x88.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/1024-517-1-768x227.png 768w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Statisch gebautes Hauptmen\u00fc (entstanden aus einer fr\u00fcheren Version des Hauptmen\u00fcs)<\/figcaption><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Automatisches Deployment<\/strong>:<\/h4>\n\n\n\n<p>Zur Entwicklungszeit war es sehr praktisch den lokalen NextJS-Entwicklungsserver zu nutzen. Gegen Ende haben wir uns aber f\u00fcr das Deployment eine GitLab-CICD-Pipeline gebaut. Diese baut bei jedem push auf GitLab das Projekt und l\u00e4dt die gebauten Dateien auf Vercel hoch. Dabei sieht Vercel den Quellcode nicht, weil der Code vom GitLab-Server gebaut wird. Wird auf den main-Branch gepusht, ist die gebaute Seite auch gleich \u00f6ffentlich aufrufbar. Bei anderen Branches wird ein Preview-Build gebaut, der nur mit Authentifizierung bei Vercel aufrufbar ist. Allerdings eignet sich das nicht f\u00fcr unser Projekt, da im free plan nur ein Nutzer Teil des Projekts sein kann.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Arbeiten mit Websockets:<\/strong><\/h4>\n\n\n\n<p>Als das Frontend mit dem Backend verbunden wurde, musste ich erstmal herausfinden, wie eine Verbindung mit dem WebSocket m\u00f6glich ist. Daf\u00fcr habe ich zuerst f\u00e4lschlicherweise die Bibliothek socket.io genutzt. Socket.io ist ein eigenes Protokoll, das \u00fcber eine http-Verbindung anstatt direkt \u00fcber WebSockets l\u00e4uft. Mit dem nativen WebSocket-Protokoll konnte ich eine Verbindung mit dem WebSocket \u00fcber das API-Gateway aufbauen, sobald die Seite erstmalig geladen wird. Da der WebSocket irgendwann timeoutet, wird mittlerweile die Verbindung erst aufgebaut, sobald man auf &#8220;Spiel erstellen&#8221; oder &#8220;Spiel beitreten&#8221; klickt.<\/p>\n\n\n\n<p>Das Objekt, mit dem man die WebSocket-Verbindung nutzen kann, um z.B. Nachrichten zu senden oder zu empfangen, wird in der Root-Komponente &#8220;GameWrapper&#8221; erstellt und initialisiert und an die darunterliegenden Komponenten weitergegeben. Sp\u00e4ter hat es sich als n\u00fctzlicher herausgestellt, alle WebSocket-Funktionen in der Komponente zu kapseln und nur noch Funktionen anzubieten, die das Objekt nutzt. So gibt es z.B. eine sendMessage-Funktion, die eine Nachricht bestehend aus Key-Value-Paaren an das Backend schickt. Ein Aufruf sieht z.B. so aus:<\/p>\n\n\n\n<p><code class=\"\" data-line=\"\">{&quot;action&quot;: &quot;setReady&quot;, &quot;gameId&quot;:&quot;...&quot;, &quot;isReady&quot;: true}<\/code><\/p>\n\n\n\n<p>Da jeder Aufruft und jede Antwort eine &#8220;action&#8221; enth\u00e4lt, ist dies ein extra Feld. Somit ist der erste String, den man der sendMessage-Funktion mitgibt, diese action (z.B. setReady, joinGame, createGame, playerJoinedResponse, &#8230;). Danach gibt man ein Objekt aus Key-Value-Paaren mit. Der Aufruf f\u00fcr die oben beschriebene Aktion sieht dann so aus:<\/p>\n\n\n\n<p><code class=\"\" data-line=\"\">sendMessage(&quot;setReady&quot;, {gameId: gameId, isReady: true})<\/code><\/p>\n\n\n\n<p>Im GameWrapper werden au\u00dferdem alle Nachrichten empfangen und in einem Array &#8220;messages&#8221; gespeichert. Auf dieses Array k\u00f6nnen die child-Komponenten zugreifen und Listener einbauen, die auf bestimmte Befehle h\u00f6ren. Sobald z.B. die Nachricht &#8220;otherPlayerReadyStatus&#8221; empfangen wird, wird der Inhalt \u00fcberpr\u00fcft und dann im Frontend dargestellt (indem der Gegner z.B. gr\u00fcn angezeigt wird).<\/p>\n\n\n\n<p>Dieses Senden und Empfangen der Nachrichten erm\u00f6glicht den Echtzeit-Betrieb der Applikation und bildet die Basis, durch die Informationen an das Backend geschickt und vom Backend empfangen werden.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Backend:<\/strong><\/h3>\n\n\n\n<p>Unser Backend besteht im Grunde auf zwei Teilen. Unseren Lambda Handlern, welche wir mit der Node.js Runtime geschrieben haben und einer Terraform Konfiguration, welche alle unsere AWS Komponenten bei Amazon automatisch deployed. Dabei Nutzen wir f\u00fcr unser Backend einen AWS ApiGateway, welches als WebSocket l\u00e4uft, DynamoDb als persistenten Speicher und AWS Lambda Funktionen f\u00fcr die Serverless Architektur. Urspr\u00fcnglich haben wir \u00fcberlegt unser Backend mit dem Serverless Framework umzusetzen. Uns wurde allerdings empfohlen, dies aufgrund von Einschr\u00e4nkungen in Verbindung mit den anderen Cloud Komponenten nicht zu nutzen. Diese Einschr\u00e4nkungen haben sich nach etwas Recherche nicht wirklich best\u00e4tigt, allerdings haben wir parallel zu dieser Vorlesung noch die Vorlesung &#8220;Software definied Infrastructure&#8221; besucht, in welcher der Umgang mit Terraform gelehrt wird. Daher war es naheliegend f\u00fcr unser Projekt auch Terraform zu nutzen und unser Wissen dahingehend zu vertiefen.<\/p>\n\n\n\n<p>Wir haben in der Entwicklung des Backends von Anfang an auf die Automatisierung des Deployment auf AWS gesetzt. Wir haben also kaum die Web Oberfl\u00e4che von AWS genutzt sondern alles direkt mit Terraform gemacht. Dies hat zu relativ gro\u00dfen Problemen gef\u00fchrt, da wir Anfangs die einzelnen Komponenten nicht zum laufen bekommen haben. Das lag an zwei gr\u00f6\u00dferen Problemen. Wir haben uns initial an einem Tutorial f\u00fcr die Entwicklung von Lambda Funktionen zusammen mit DynamoDb  orientiert. Das Tutorial war allerdings schon etwas \u00e4lter, und nutzte noch eine alte Package Struktur von AWS, bedeutet unser Code wurde von AWS gar nicht gebaut, da die alten Packete  gar nicht mehr von der Runtime unterst\u00fctzt wurden. Herausgefunden haben wir das, indem wir auf der Weboberfl\u00e4che das Testing genutzt haben, wodurch man direkt logs bekommen hat. Das war allerdings ziemlich umst\u00e4ndlich, da jedes mal wenn man die Terraform-Config neu deployed hat diese Tests gel\u00f6scht wurden. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Arbeiten mit Cloudwatch:<\/h4>\n\n\n\n<p>Wir hatten aber noch ein weiteres Problem. Die Kommunikation zwischen den Lambda Funktionen und DynamoDb hat immer zu Fehlern gef\u00fchrt. In dem Testing Environment konnte man nicht wirklich sehen warum. Man muss initial wenn man diese Komponenten mit Terraform deployed eine IAM Policy erstellen, welche bestimmt worauf die Lambda Handler zugreifen d\u00fcrfen. Urspr\u00fcnglich dachten wir aufgrund des Tutorials das Cloudwatch kostenpflichtig ist. Daher haben wir dieses Feature nicht genutzt. Nachdem sich allerdings herausgestellt hat, dass dies nicht so ist, konnten wir mit Cloudwatch schnell die Probleme l\u00f6sen, da die Fehlermeldungen hier viel ausf\u00fchrlicher dargestellt wurden. Mit Cloudwatch konnten wir feststellen das wir die Rechte f\u00fcr Scan und Query vergessen haben und dadurch konnten unsere Lambda Funktionen ihre Aufgabe nicht erf\u00fcllen. Es gab immer wieder Probleme mit den Rechten, sodass wir am Ende eine recht umfangreiche Policy erstellt haben.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"414\" data-attachment-id=\"28060\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/09\/13\/multiplayer-web-game-mit-aws-schiffe-versenken\/image-123\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-3.png\" data-orig-size=\"1321,534\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-3-1024x414.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-3-1024x414.png\" alt=\"\" class=\"wp-image-28060\" style=\"width:795px;height:auto\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-3-1024x414.png 1024w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-3-300x121.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-3-768x310.png 768w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-3.png 1321w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Cloudwatch hat uns auch im verlaufe des Projektes sehr viel geholfen, wenn uns JS irgendwelche &#8220;undefined&#8221; Errors etc. geliefert hat.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">WebSocket und Lambda Funktionen:<\/h4>\n\n\n\n<p>Unsere WebSocket Konfiguration haben wir relativ einfach gehalten. Wir haben nur die Standardrouten umgesetzt, welche unsere Lambda Funktionen ausf\u00fchren, dabei unterscheiden wir zwischen der Connect, Game und Disconnect Route. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Connect<\/strong>\n<ul class=\"wp-block-list\">\n<li>Der Connect Handler k\u00fcmmert sich um die Verbindung eines Clients zum WebSocket. Au\u00dferdem speichert der Handler die connectionId des Nutzer in der DynamoDb Tabelle &#8220;Connections&#8221;. Da wir keine Authentifizierung in unserem Projekt eingebaut haben, dient uns diese ID als Identifizierung eines Nutzers.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Disconnect<\/strong>\n<ul class=\"wp-block-list\">\n<li>Des Disconnect Handler l\u00f6st die Verbindung eines Clients zum WebSocket auf. Au\u00dferdem wird gepr\u00fcft, ob es ein Spiel gibt mit welchem der Nutzer assoziiert wird. In diesem Fall wird auf Basis des Game Status gepr\u00fcft ob das Spiel beendet wird und anschlie\u00dfend gel\u00f6scht wird, damit wir keine unn\u00f6tigen Daten auf der Datenbank haben. <\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Game<\/strong>\n<ul class=\"wp-block-list\">\n<li>Der Game Handler ist das Herzst\u00fcck unseres Backends. Hier ist die gesamte Spiellogik enthalten. Der Handler selber entspricht der Default Route eines Websockets, bedeutet alles was nicht Connect oder Disconnect ist wird an diese Route weitergeleitet. Die Entscheidung, welcher Teil vom Code ausgef\u00fchrt wird, wird von einem Switch Case am Anfang des Handlers entschieden, welcher basierend auf der &#8220;action&#8221;-Property des Body entscheidet was passiert.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-4.png\"><img loading=\"lazy\" decoding=\"async\" width=\"690\" height=\"397\" data-attachment-id=\"28061\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/09\/13\/multiplayer-web-game-mit-aws-schiffe-versenken\/image-124\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-4.png\" data-orig-size=\"690,397\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-4.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-4.png\" alt=\"\" class=\"wp-image-28061\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-4.png 690w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image-4-300x173.png 300w\" sizes=\"auto, (max-width: 690px) 100vw, 690px\" \/><\/a><\/figure>\n\n\n\n<p>Zusammen mit mehreren Hilfsfunktionen bildet dies dann unsere Spiellogik. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">DynamoDb:<\/h4>\n\n\n\n<p>Lambda Funktionen sind stateless, um also Daten zu speichern und Spielst\u00e4nde zu pr\u00fcfen, nutzen wir DynamoDb als Speicher. Anfangs war es etwas kompliziert sich an den NoSql Gedanken zu gew\u00f6hnen, aber man hatte den Dreh relativ schnell raus. Wir haben f\u00fcr unser Projekt zwei Tabellen genutzt. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Connections-Table\n<ul class=\"wp-block-list\">\n<li>Diese Tabelle enth\u00e4lt alle aktiven WebSocket Verbindungen und die Information in welchem Spiel sich eine Verbindung im Moment befindet. <\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Games-Table\n<ul class=\"wp-block-list\">\n<li>Diese Tabelle enth\u00e4lt unsere Spielst\u00e4nde. Die Spielst\u00e4nde sind dabei ein gro\u00dfes JSON Objekt, welches sowohl die Informationen zu beiden Spielern, als auch die Spielfelder enth\u00e4lt. Au\u00dferdem enth\u00e4lt das Objekt einen Schl\u00fcssel GameId, mit welchem wir ein Spiel klar identifizieren k\u00f6nnen. Eine lobbyCode, mit welcher ein Spiel \u00fcber den  lobbyCode Index identifiziert werden kann, und eine Information dar\u00fcber welchen Status ein Spiel gerade hat.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>Beispiel Spiel als JSON:<\/p>\n\n\n\n<p class=\"has-contrast-color has-base-background-color has-text-color has-background has-link-color wp-elements-b8f3dbef0bc60a1f4471d2b372c90536\"><code class=\"\" data-line=\"\">{&lt;br&gt;&quot;gameId&quot;: &quot;ba1bebd8-9b31-4767-bd6d-a3fdecdb163d&quot;, &lt;- Tabellenschl\u00fcssel&lt;br&gt;&quot;game_status&quot;: &quot;waiting&quot;,&lt;br&gt;&quot;lobbyCode&quot;: &quot;J7YP4&quot;, &lt;- Index&lt;br&gt;&quot;player1&quot;: {&lt;br&gt;      &quot;player_board&quot;: {&lt;br&gt;            &quot;allShipsDestroyed&quot;: false,&lt;br&gt;            &quot;ships&quot;: [...]&lt;br&gt;       }&lt;br&gt;       &quot;player_id&quot;: &quot;QzFlWfxZliACE4Q=&quot;,&lt;br&gt;       &quot;player_name&quot;: &quot;...&quot;,&lt;br&gt;       &quot;player_ready&quot;: false&lt;br&gt;        }&lt;br&gt;&quot;player2&quot;: {...}&lt;br&gt;}<\/code><\/p>\n\n\n\n<p>W\u00e4hrend der Entwicklung haben wir oft viel Datenm\u00fcll angesammelt, wie bereits erw\u00e4hnt haben wir daher mit Hilfe des Disconnect Handlers daf\u00fcr gesorgt das alle Spielst\u00e4nde fr\u00fcher oder sp\u00e4ter gel\u00f6scht werden, je nachdem wie der Spielverlauf aussieht und ob ein Spieler die Verbindung verliert. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Tests:<\/h4>\n\n\n\n<p>Abgesehen von den manuellen Tests haben wir uns lange nicht um Tests gek\u00fcmmert. Zum Ende hin haben wir f\u00fcr unser Backend noch Unit Tests geschrieben. Dabei haben wir ein Package von AWS genutzt, welches die DynamoDb mocken kann. Zusammen mit diesem Package haben wir alle Funktionen durchgetestet. Leider hatten wir keine Zeit mehr auch gr\u00f6\u00dfere Integrationstests einzubauen. Sodass zum Beispiel die Verbindung mit dem WebSocket gar nicht getestet wird. Die Unit Tests werden automatisch bevor das Projekt via Vercel deployed wird mit der CI\/CD Pipeline ausgef\u00fchrt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Weitere Herausforderungen:<\/strong><\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Zeitmanagement:<\/h4>\n\n\n\n<p>Eines der gr\u00f6\u00dften Probleme die wir abseits der Rechte Probleme hatten, war unser Zeitmanagement. Wir hatten zwar relativ fr\u00fch im Semester uns ein Thema herausgesucht, haben aber erst recht sp\u00e4t mit der eigentlichen Entwicklung angefangen, sodass wir zum Zeitpunkt der Endpr\u00e4sentation nur einen MVP hatten, der in keiner Weise funktional war. Grund daf\u00fcr war unter anderem das wir w\u00e4hrend der Vorlesungszeit so gut wie gar nicht daran gearbeitet hatten und dann w\u00e4hrend der Pr\u00fcfungsphase mit anderen Projekten mit fr\u00fcherer Deadline besch\u00e4ftigt waren. Wenn wir unser Zeitmanagement besser hinbekommen h\u00e4tten, h\u00e4tten wir am Ende nicht so einen Stress gehabt und h\u00e4tten vielleicht auch unsere urspr\u00fcnglich erdachten Extras einbauen k\u00f6nnen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Unterschiede zwischen dem lokalen und dem Vercel Build:<\/h4>\n\n\n\n<p>Uns ist gegen Ende aufgefallen, dass man sich theoretisch selber blockieren kann, indem man anf\u00e4ngt selber im Web umher zu routen. Bedeutet entweder man springt manuell \u00fcber die URL in Routen in die man eigentlich nicht soll, oder man nutzt f5 oder &#8220;vor\/zur\u00fcck&#8221;. Gerade wenn man hier in die Game Route springt kommt man aufgrund der Ladeanimation nicht mehr ohne weiteres aus der Route raus. Wir wollten daher ein automatisches Routing einbauen, welches verifiziert das ein Nutzer immer noch die Erlaubnis hat in einer Route zu sein. Dieses Problem lie\u00df sich auch auf dem Lokalen Build relativ einfach l\u00f6sen. Sofern keine GameId vorhanden ist oder keine WebSocket Verbindung existiert wird man zur\u00fcck ins Hauptmen\u00fc geschmissen. Auch wenn man f5 dr\u00fcckt, soll man zur\u00fcck ins Hauptmen\u00fc kommen, da wir die Nutzer ja \u00fcber die ConnectionId identifizieren und man daher nach einem Verlust der Connection sowieso nicht mehr in das selbe Spiel zur\u00fcck kann. Beides hat lokal funktioniert, komischerweise aber nicht auf Vercel. Wir konnten das Problem aufgrund der begrenzten debug M\u00f6glichkeiten auf Vercel leider nicht eingrenzen. Es scheint etwas mit dem pr\u00fcfen auf die WebSocket Verbindung in einem Next.js Effect zu tun zu haben, aber wir konnten das Problem leider nicht l\u00f6sen. Um seltsame Seiteneffekte zu vermeiden haben wir das Feature erstmal ausgebaut.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Security:<\/h4>\n\n\n\n<p>Nachdem wir unser Projekt automatisch auf Vercel deployt haben, haben wir uns auch Gedanken \u00fcber die Sicherheit gemacht. Da wir keine personenbezogenen Daten verarbeiten, schien das Thema anfangs nicht wichtig. Sp\u00e4ter hatten wir jedoch die Sorge, dass unser \u00f6ffentlicher WebSocket potenziell missbraucht werden k\u00f6nnte und dadurch hohe Kosten entstehen.<\/p>\n\n\n\n<p>Als erste Ma\u00dfnahme haben wir deshalb eine Origin-Pr\u00fcfung eingebaut, sodass der WebSocket ausschlie\u00dflich von localhost und unserer Vercel-Domain aus aufgerufen werden darf. Auch wenn das keine echte Sicherheit darstellt, erschwert es zumindest automatisierte Angriffe aus fremden Umgebungen. Au\u00dferdem hatten wir die Idee, zu Beginn jeder Session ein Token an die Nutzer auszugeben und dieses als Autorisierung f\u00fcr die WebSocket-Verbindung zu verwenden. Diese L\u00f6sung h\u00e4tte einen deutlich besseren Schutz geboten, da so nur Clients mit g\u00fcltigem Token eine Verbindung aufbauen k\u00f6nnten. Aufgrund der begrenzten Zeit im Projekt am Ende haben wir diesen Ansatz allerdings nicht mehr umgesetzt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Learnings und Fazit<\/strong>:<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Learnings:<\/strong><\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>AWS Grundlagen:\n<ul class=\"wp-block-list\">\n<li>Zustandlose Serverless Funktionen mit AWS Lambdas, Amazon k\u00fcmmert sich um die Skalierung und den Betrieb der Funktionen, wir m\u00fcssen sie nur schreiben und deployen.<\/li>\n\n\n\n<li>WebSocket API mit AWS API-Gateway: Verbindung zwischen Frontend und Backend mit Hilfe von Websockets. Der WebSocket wird bei Amazon deployed und verkn\u00fcpft unsere Frontend Logik mit unseren Lambda Funktionen.<\/li>\n\n\n\n<li>Zustandsspeicherung zwischen den einzelnen Funktionsaufrufen mit DynamoDb, einer NoSql Datenbank, welche sowohl unsere WebSocket Verbindungen als auch unsere Spielst\u00e4nde persistent speichert.<\/li>\n\n\n\n<li>Auch wenn wir uns letztendlich gegen statischen Web Hosting in einem S3 Bucket entschieden haben, haben wir beim testen dieser Vorgehensweise dennoch viel neues gelernt.<\/li>\n\n\n\n<li>Rechte Management (AWS IAM) sowohl bei den einzelnen Komponenten als auch bei den Nutzern.<\/li>\n\n\n\n<li>Debuggen der Lambda Funktionen mit AWS Cloudwatch <\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Frontend Entwicklung:\n<ul class=\"wp-block-list\">\n<li>Tiefere Einblicke in Next.js und der internen States des Frameworks<\/li>\n\n\n\n<li>Dynamisches Routen mit Parametern in der URL<\/li>\n\n\n\n<li>Nutzung einer externen WebSocket API in unserem Frontend Code<\/li>\n\n\n\n<li>Automatisches Deployment der Webseite auf Vercel<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Backend Entwicklung:\n<ul class=\"wp-block-list\">\n<li>Automatisches Deployment des Backends mit Terraform<\/li>\n\n\n\n<li>Umgang mit .env Dateien uns sensiblen Daten im Code<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Sonstiges:\n<ul class=\"wp-block-list\">\n<li>Planung und Zeitmanagement sollte fr\u00fchzeitig gemacht werden (und sich auch dran gehalten werden)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Fazit:<\/strong><\/h4>\n\n\n\n<p>Wir sind mit dem Ergebnis welches wir zum Zeitpunkt der Abgabe erreicht haben durchaus zufrieden. Wir haben es geschafft das Spiel in seinen Grundz\u00fcgen umzusetzen und konnten unser neues Wissen bzgl. Cloud Komponenten gut einbinden. Nachdem wir unser Zeitmanagement unter Kontrolle bekommen haben und die gr\u00f6\u00dften Probleme mit den Rechten und dem Access der Cloud-Komponenten untereinander gel\u00f6st haben, haben wir schnell Fortschritt gemacht und am Ende eine spielbare Version unseres Projekts erreicht. <\/p>\n\n\n\n<p>Auch wenn wir aufgrund der vielen Probleme am Ende unsere eigenen Ideen zur Erweiterung des Spiels nicht einbringen konnten, haben wir trotz des etwas kleineren Projektscopes viele neuen Erfahrungen gemacht, welche wir zuk\u00fcnftig weiter nutzen k\u00f6nnen. Daher k\u00f6nnen wir insgesamt mit dem Ergebnis des Projektes zufrieden sein.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Projektidee: Im Rahmen der Vorlesung &#8220;Software Development for Cloud Computing&#8221; sollen die Studierenden in Gruppen ein eigenes Projekt, mit Hilfe von in der Vorlesung gezeigten Cloud Technologien umsetzen. Wir hatten Anfangs Probleme ein geeignetes Thema zu finden, da unser Wissenstand im Thema Cloud nicht besonders gro\u00df war. Letztendlich haben wir uns dazu entschieden ein Multiplayer [&hellip;]<\/p>\n","protected":false},"author":1264,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1,120,396,22],"tags":[84,83,150,7,533,521,25,202,575],"ppma_author":[1105,1137],"class_list":["post-28021","post","type-post","status-publish","format-standard","hentry","category-allgemein","category-cloud-technologies","category-games","category-student-projects","tag-aws","tag-aws-lambda","tag-ci-cd","tag-cloud","tag-cloud-computing-2","tag-dynamodb","tag-nodejs","tag-serverless","tag-websocket"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":23517,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2022\/08\/29\/multiplayer-game-with-aws-stadtlandfluss\/","url_meta":{"origin":28021,"position":0},"title":"Multiplayer Game with AWS |\u00a0StadtLandFluss","author":"gi004","date":"29. August 2022","format":false,"excerpt":"Dieser Blogbeitrag soll einen Einblick in die Entwicklung unserer Webanwendung mit den unten definierten Funktionen geben sowie unsere L\u00f6sungsans\u00e4tze, Herausforderungen und Probleme aufzeigen.\u00a0 Cloud Computing VorlesungProjekt Idee & InspirationZielEinblick in das Spiel \u2013 DemoFrameworks - Cloud Services - InfrastructureArchitekturCloud KomponentenAWS ServicesDynamo DBS3LambdaAmazon API- GatewayAmazon CloudWatchTestingCI\/CD PipelineSchwierigkeitenFazit Cloud Computing Vorlesung Ziel\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/08\/image.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/08\/image.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/08\/image.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2022\/08\/image.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":25800,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2023\/09\/14\/splid-2-0-die-zukunft-des-gemeinsamen-ausgabenmanagements\/","url_meta":{"origin":28021,"position":1},"title":"Splid 2.0 &#8211; Die Zukunft des gemeinsamen Ausgabenmanagements","author":"David Christoph Scheifers","date":"14. September 2023","format":false,"excerpt":"Im Rahmen der Vorlesung \u201cSoftware Development for Cloud Computing\u201d haben wir uns daf\u00fcr entschieden, einen Klon der App Splid auf Basis unterschiedlicher Cloud Technologien als Web App zu entwickeln, um uns so die Grundkenntnisse des Cloud Computings anzueignen. Projektidee Bei gemeinsamen Aktivit\u00e4ten und Gruppenausgaben ist es sehr hilfreich, einfache und\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/09\/image6.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/09\/image6.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/09\/image6.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/09\/image6.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/09\/image6.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2023\/09\/image6.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":21683,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/18\/ynstagram-cloud-computing-mit-aws-serverless\/","url_meta":{"origin":28021,"position":2},"title":"Ynstagram &#8211; Cloud Computing mit AWS &amp; Serverless","author":"ns144","date":"18. September 2021","format":false,"excerpt":"Im Rahmen der Vorlesung \u201cSoftware Development for Cloud Computing\u201d haben wir uns hinsichtlich des dortigen Semesterprojektes zum Ziel gesetzt einen einfachen Instagram Klon zu entwerfen um uns die Grundkenntnisse des Cloud Computings anzueignen. Grundkonzeption \/ Ziele des Projektes Da wir bereits einige Erfahrung mit React aufgrund anderer studentischer Projekte sammeln\u2026","rel":"","context":"In &quot;Cloud Technologies&quot;","block_context":{"text":"Cloud Technologies","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/cloud-technologies\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Prasentation_CC_01.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":28011,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/09\/11\/cloud-native-security-scanner\/","url_meta":{"origin":28021,"position":3},"title":"Cloud-native Security Scanner","author":"Tim Ruff","date":"11. September 2025","format":false,"excerpt":"Dieses Projekt wurde im Rahmen der Vorlesung \u201eSoftware Development for Cloud Computing\u201c umgesetzt. Ausgangslage und Projektidee Unser bisheriger Fokus im Studium lag haupts\u00e4chlich auf Themen der IT-Security und Machine Learning, weshalb wir beide bis auf die grundlegenden Vorlesungen zum Thema Software Entwicklung kaum Erfahrungen in diesem Bereich gesammelt haben. Aus\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image.jpeg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image.jpeg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image.jpeg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image.jpeg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/09\/image.jpeg?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":12032,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2020\/09\/30\/admin-panel-web-app-in-der-aws-cloud\/","url_meta":{"origin":28021,"position":4},"title":"Admin Panel (Web App) in der AWS Cloud","author":"ss447","date":"30. September 2020","format":false,"excerpt":"1. Einleitung Im Rahmen der Vorlesung \u201eSoftware Development for Cloud Computing\u201c haben wir uns als Gruppe dazu entschieden aufbauend auf teilweise bereits vorhandener Codebasis an einem Startup-Projekt weiterzuarbeiten. Der Hauptfokus lag bei uns auf dem Ausbau von DevOps-Aspekten und auf dem eines stabilen und sicheren Systems, welches auch in der\u2026","rel":"","context":"In &quot;Cloud Technologies&quot;","block_context":{"text":"Cloud Technologies","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/cloud-technologies\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/img.youtube.com\/vi\/qw9ZkWnvR4M\/0.jpg?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":11711,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2020\/09\/29\/perfekter-gluhwein-fur-zuhause-thermometer-mit-raspberry-pi-und-aws\/","url_meta":{"origin":28021,"position":5},"title":"Perfekter Gl\u00fchwein f\u00fcr Zuhause: Thermometer mit Raspberry Pi und AWS","author":"jg129","date":"29. September 2020","format":false,"excerpt":"Abstract Kein anderes Getr\u00e4nk ist mit Weihnachtsm\u00e4rkten so verbunden wie Gl\u00fchwein. Und so trinkt sich der ausschweifende Weihnachtsmarktbesucher im Laufe der Adventszeit von Stand zu Stand bis er schlie\u00dflich am Ende des Jahres seinen Lieblingsstand gefunden hat. Doch auch daheim kann der perfekte Gl\u00fchwein gelingen.\u00a0 Wir zeigen, wie man sich\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/lh3.googleusercontent.com\/rbu36fXExVo14XfyUicXbIFjAgh1bvNnXHlaUVRfqLevpyZx4KVyjeuYdgItPx6y39R8L9Ub_hug03LYM3AIAW_F14vhBiXOZlt92qIpN0Y2h0H-czZ65ERnn3qUoWVh7JfI5ihA","width":350,"height":200,"srcset":"https:\/\/lh3.googleusercontent.com\/rbu36fXExVo14XfyUicXbIFjAgh1bvNnXHlaUVRfqLevpyZx4KVyjeuYdgItPx6y39R8L9Ub_hug03LYM3AIAW_F14vhBiXOZlt92qIpN0Y2h0H-czZ65ERnn3qUoWVh7JfI5ihA 1x, https:\/\/lh3.googleusercontent.com\/rbu36fXExVo14XfyUicXbIFjAgh1bvNnXHlaUVRfqLevpyZx4KVyjeuYdgItPx6y39R8L9Ub_hug03LYM3AIAW_F14vhBiXOZlt92qIpN0Y2h0H-czZ65ERnn3qUoWVh7JfI5ihA 1.5x"},"classes":[]}],"jetpack_sharing_enabled":true,"authors":[{"term_id":1105,"user_id":1264,"is_guest":0,"slug":"leon_obertopp","display_name":"Leon Obertopp","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/c039fa1856e4c66d9e6a540a715074b3611315e9309c9d56d9471cf3df6a5525?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""},{"term_id":1137,"user_id":1283,"is_guest":0,"slug":"bjrn_godeck","display_name":"bg050","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/04302463ab87f73a98ff9852abe41dc6b4b0ec10d7eaf407195a92ec08fb4f05?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/28021","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/users\/1264"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/comments?post=28021"}],"version-history":[{"count":24,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/28021\/revisions"}],"predecessor-version":[{"id":28068,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/28021\/revisions\/28068"}],"wp:attachment":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/media?parent=28021"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/categories?post=28021"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/tags?post=28021"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/ppma_author?post=28021"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}