Changelog

Alle wesentlichen Änderungen an Maschinchenring werden hier dokumentiert.

2026-04-19 Feature

Bilder aus dem Chat löschen

  • Neues MCP-Tool delete_image: Eigentümer können hochgeladene Bilder wieder löschen — der Chat findet die passende imageId über get_item, der Nutzer beschreibt das Bild natürlich-sprachlich (#145).
  • get_item liefert die Bilderliste jetzt aus der Datenbank (vorher ListObjectsV2 aus S3) mit { imageId, url, isThumbnail } pro Bild. Das macht Bilder referenzierbar und das aktuelle Thumbnail sichtbar.
  • Löschen entfernt das Objekt zuerst aus dem Speicher, danach die DB-Row. Schlägt der S3-Delete fehl, bleibt die DB-Row stehen — so gibt es keine unauffindbaren Speicher-Waisen. War das Bild Thumbnail des Geräts, wird thumbnailPath automatisch geleert.
  • Admins haben keine Sonderrechte auf fremde Bilder. Regressionstest in server/src/security.regression.test.ts stellt das sicher.
2026-04-19 Fix

Chat-Verlauf behält KI-Antworten nach Reload

  • Text-Chunks wurden im Chat-Container pro Iteration des Agentic-Loops zurückgesetzt — nur der Text der letzten Iteration landete in der DB. Sobald der Assistent vor einem lokalen Tool-Call (z. B. set_conversation_title) Text produzierte und die Schluss-Iteration leer blieb, ging die sichtbare Antwort beim Neu-Öffnen verloren (#127).
  • Der Fix aus PR #128 war im Chat-Container-Refactor (PR #134) verloren gegangen. Jetzt wird Text wieder über alle Iterationen akkumuliert und auch bei Max-Iteration-Abbruch sowie Stream-Fehlern persistiert.
  • Zwei Regressionstests in chat/src/http/chat.test.ts decken sowohl Text-vor-Tool-Call als auch leere Schluss-Iteration ab.
2026-04-19 Fix

Preise im Chat wieder löschbar

  • Das MCP-Tool update_item akzeptiert für pricePerWeek, pricePerWeekend und deposit jetzt auch null, um einen Preis explizit zu entfernen. Vorher war das Feld nur optional — weggelassen hieß „unverändert lassen", und es gab keinen Weg, einen einmal gesetzten Preis wieder zu entfernen.
  • pricePerDay bleibt weiterhin Pflicht und kann nicht gelöscht werden, weil jedes Gerät einen Tagespreis braucht.
2026-04-19 Fix

Chat-Links zu Geräten funktionieren wieder

  • Das MCP-Tool search_items liefert jetzt itemUrl und thumbnailUrl wie list_items und get_item. Der Chat-Assistent (Haiku) hatte ohne itemUrl die Detailseiten-URL aus dem Gerätenamen zusammengeraten (z. B. /geraete/rasenwalze/), was am Astro-Slug-Handler vorbeiging und auf die Startseite umleitete — für den Nutzer sah das wie ein defekter Link aus (#143).
  • Regressionstest in server/src/mcp/tools.test.ts stellt sicher, dass search_items in Zukunft itemUrl mit der Item-ID liefert.
2026-04-18 Fix

Chat-Input-Feld bleibt über der Tastatur auf iOS (nativer Fix)

  • Der erste Anlauf am 2026-04-17 (Scroll-Korrektur im visualViewport-Resize-Handler plus onFocus- Hack) hat das Problem auf iPhone XR nicht behoben — iOS hat das Layout-Viewport weiterhin hochgescrollt, das Input-Feld landete unter der Tastatur.
  • Nativer Fix: body.fullscreen bekommt position: fixed; inset: 0. Damit gibt es kein scrollbares Layout-Viewport mehr, in das iOS die fokussierte Textarea schieben könnte. Der visualViewport-Resize- Handler muss nur noch die Body-Höhe auf die verbleibende sichtbare Fläche setzen — die Flex-Chain (mainastro-island → Chat) schrumpft sauber mit.
  • Dadurch konnten der window.scrollTo-Workaround im Resize-Handler, der zusätzliche scroll-Listener und der onFocus-Hack am Textarea komplett entfallen — die Lösung bleibt bei der Plattform.
2026-04-17 Feature

Burger-Menü für mobile Navigation

  • Auf schmalen Viewports (≤ 640px) kollabiert die Navigation in website/src/layouts/BaseLayout.astro zu einem Burger-Icon. Ein Klick öffnet die Links als Dropdown unterhalb der Kopfleiste; aria-expanded und aria-controls halten das Ganze tastatur- und screenreader-freundlich.
  • Im eingeloggten Zustand (Chat, Buchungen, Konto, Abmelden) gab es vorher horizontales Scrollen auf iPhone-Breite. Die Links sind jetzt gestapelt und verschwinden hinter dem Icon, bis der Nutzer sie explizit öffnet.
2026-04-17 Fix

Chat-Input-Feld bleibt über der Tastatur auf iOS

  • Auf iPhone XR (und anderen iOS-Geräten) rutschte das Text-Input-Element unter die aufklappende Software-Tastatur, sobald es fokussiert wurde. Ursache: iOS Safari scrollt das Layout- Viewport hoch, ohne die Body-Höhe zu verkleinern, und die bestehende visualViewport-Logik hat diesen Scroll nicht zurückgesetzt.
  • Zusätzlich hing die Flex-Chain an einer <astro-island>- Komponente, die per Default display: inline ist und die Höhenbegrenzung nicht an den Chat-Container weiterreichte.
  • Fix in website/src/layouts/BaseLayout.astro und website/src/components/Chat.tsx: <astro-island> wird im Fullscreen-Modus zum Flex- Item, und der Resize-Handler sowie ein onFocus am Textarea scrollen das Layout-Viewport zurück auf Null, sobald die Tastatur öffnet.
2026-04-16 Refactor

Chat läuft jetzt als eigener Container

  • Der Chat ist ein separater Dienst (mieten-chat, Port 3001) mit eigener SQLite-DB für Unterhaltungen und Nachrichten. Er spricht mit dem Domain-Server genau wie jeder andere MCP-Client — ausschließlich über den öffentlichen /mcp-Endpoint.
  • Die duplizierten Tool-Definitionen und der parallele executeTool-Dispatch im Domain-Server sind weg. Neue MCP-Tools stehen dem Chat automatisch zur Verfügung, ohne dass Code an zwei Stellen angefasst werden muss. Damit ist auch das #128-Symptom (block_period, unblock_period, list_my_blocks im Website-Chat fehlend) strukturell erledigt.
  • Das Auth-Cookie/JWT des Browsers wird vom Chat als authorization_token im mcp_servers-Parameter an die Anthropic-Messages- API durchgereicht. Der Domain-Server verifiziert es mit denselben Routinen wie bei direktem MCP-Zugriff.
  • Der Titel-Shortcut set_conversation_title bleibt bewusst ein lokales Tool im Chat-Container — er schreibt in die Chat-eigene DB und darf die Domain-Grenze nicht überschreiten.
2026-04-16 Feature

Markdown in Gerätebeschreibungen

  • Die Beschreibung eines Geräts (oder eines Sets) wird jetzt als Markdown gerendert. Aufzählungen (- / *), Fettdruck, Links und Überschriften landen in der passenden HTML- Auszeichnung auf /geraete/:slug und /sets/:slug statt als Fließtext zusammenzufallen.
  • Vor dem Rendering läuft jeder Inhalt durch sanitize-html mit strikter Allowlist: nur Fließtext-Tags, keine Bilder, keine Iframes, keine Event-Handler, keine javascript:-URLs, keine <script>- Blöcke. Damit kann die KI (oder ein Vermieter) bösartigen Markdown-Content nicht in ein XSS umwandeln.
  • Externe Links (http:///https://) bekommen automatisch rel="noopener nofollow ugc" und target="_blank"; interne/relative Links bleiben unverändert und öffnen im selben Tab.
  • Regressionstests in e2e/device-pages.spec.ts („renders Markdown bullets and bold in description" + „sanitizes dangerous HTML in description") prüfen beide Seiten der Medaille.
2026-04-15 Performance

Astro-Middleware verifiziert JWT in-process

  • Die Astro-Middleware in website/src/middleware.ts macht bei jedem Request keinen Loopback-HTTP-Call nach /auth/me mehr. Stattdessen importiert sie makeTokenVerifier aus server/src/auth/jwt.ts und prüft den JWT direkt gegen process.env.JWT_PUBLIC_KEY.
  • Öffentliche Seiten (Startseite, Gerätedetails, Impressum, Datenschutz, Docs) zahlen damit keinen Context-Switch mehr für Auth — der JWT-Check läuft komplett in-process.
  • Profil-Daten (Telefon, Adresse) lädt nur noch /konto selbst per /auth/me, weil das die einzige Seite ist, die sie anzeigt. Regressionstests in e2e/stale-auth-cookie.spec.ts bleiben grün.
2026-04-15 Feature

Vermieter können Zeiträume sperren

  • Neue MCP-Tools block_period, unblock_period und list_my_blocks: Vermieter können Zeiträume auf ihren Geräten als „belegt" markieren — z.B. wenn sie das Gerät selbst brauchen oder es bereits über eine andere Plattform vermietet ist.
  • Sperren blockieren Buchungsversuche und erscheinen im öffentlichen Kalender als unverfügbar (ohne Grund oder Namen des Vermieters preiszugeben).
  • Neue Tabelle blocked_periods (Migration 013) — saubere Trennung zu Buchungen: kein Mieter, keine Approval-Logik, keine Dummy-Namen.
  • Regressionstests: server/src/db/queries/blocked_periods.test.ts und der neue Vermieter-Sperren-Block in server/src/mcp/e2e.test.ts.
2026-04-14 Fix

Konto-Zombie-Login und kaputtes Buchung-Stornieren repariert

  • Astro-Middleware prüft jetzt bei jedem Request den auth_token-Cookie gegen /auth/me. Abgelaufene oder nach Server-Reboot ungültige Tokens werden gelöscht — vorher zeigte die Navigation fälschlich "Konto/Abmelden" an, und die Kontoseite hatte leere Profildaten (keine Adresse).
  • Buchung stornieren, bestätigen und ablehnen laufen jetzt über Full-Page-Confirmations (/buchungen/:id/cancel, /accept, /decline) statt eines JS-Popups. Vorher las der Inline-Handler den JWT über document.cookie — der Cookie ist aber httpOnly, also sah er nichts, der Bearer-Header war leer und der Server antwortete mit "Unauthorized". Der E-Mail-Approval-Flow (/buchungen/:id?token=xxx) bleibt davon unberührt.
  • Regressionstests: e2e/cancel-booking.spec.ts, e2e/owner-decision.spec.ts und e2e/stale-auth-cookie.spec.ts.
2026-04-14 Analytics

Anonyme Reichweitenmessung mit Plausible

  • Tracking-Script von analytics.levinkeller.de (selbst gehostetes Plausible) im BaseLayout eingebunden — läuft damit auf allen gerenderten Seiten
  • Cookielos, kein Personenbezug, keine Cross-Site-Tracking-IDs
2026-04-14 Doku

Doku aus Nutzer-Sicht neu geschrieben

  • /docs komplett umgeschrieben: Community-Idee, Rollen (Mieter / Vermieter), Warum-Freischaltung, FAQ (Haftung, Versicherung, Absagen, No-Shows) statt Tech-Stack- und Infrastruktur-Details
  • Neuer Abschnitt "Was darf hier angeboten werden?": kein Marktplatz, keine Dienstleistungen, keine alkoholischen / pornografischen / illegalen Inhalte — Meldung fragwürdiger Angebote per E-Mail mit Link zum Gerät
  • Gewerbetreibende ausdrücklich erlaubt (keine Haftung, egal ob privat oder gewerblich)
  • Kaution im Mieter- und Vermieter-Flow erwähnt — Übergabe direkt zwischen den Parteien, keine Zahlungsabwicklung über die Plattform
  • Betreiber-Hinweis (Levin Keller, Impressum) und Kontakt (post@levinkeller.de) ergänzt
  • /docs/mcp-tools entschlackt: als API-Referenz aus Sicht des Clients positioniert, Implementierungs-Details (Suche, Bilder-Pipeline) entfernt, Admin-Tools aus der öffentlichen Referenz genommen, "Owner" → "Vermieter" vereinheitlicht
2026-04-14 Fix

Vermieter-Status sichtbar im Chat

  • get_profile gibt jetzt lender, admin, lenderStatus (approved / pending / none) und profileComplete zurück — der Chat-Assistent kann den Vermieter-Status damit direkt auslesen statt zu raten
  • request_lender_status ist jetzt auch im Web-Chat (Haiku) als Tool verfügbar; vorher fehlte es in den Chat-Tool-Definitionen
  • Tool-Beschreibungen für den Vermieter-Flow geschärft
  • server/src/mcp/tools.ts in Domänen-Module aufgeteilt (tools/items.ts, tools/bookings.ts, tools/profile.ts, tools/admin.ts, tools/deps.ts)
2026-04-14 Feature

Vermieter-Flow & User-Cleanup

  • Neues MCP-Tool request_lender_status: User beantragt Vermieter-Freischaltung (Profil-Check, 1h-Cooldown, E-Mail an alle Admins)
  • Admin-UI unter /admin/lender-requests/:userId (Cookie-Auth, GET + POST approve/reject)
  • DB-Rename: can_uploadlender, is_adminadmin
  • Spalte lender_requested_at als Spam-Schutz
  • Tote Spalten github_id / google_id entfernt, User-IDs sind jetzt opaque UUIDs
  • GitHub-OAuth übergibt randomUUID() statt GitHub-Login als ID; Profile werden weiterhin per E-Mail gematcht
2026-04-14 Feature

Öffentliche Dokumentation

  • Neue Dokumentationsseiten unter /docs hinzugefügt
  • Vollständige MCP-Tools-Referenz unter /docs/mcp-tools
  • Changelog unter /docs/changelog
  • Footer-Link zur Dokumentation ergänzt
2026-04 Fix

Chat-Rework

  • Chat-Interface überarbeitet und stabilisiert
  • Konversationsverwaltung verbessert
2026-04 Feature

Semantische Suche

  • search_items-Tool mit Hybrid-Suche (semantisch + lexikal)
  • Jina Embeddings für Geräte-Beschreibungen
  • 70% semantisches Gewicht, 30% lexikal
2026-04 Feature

Bild-Upload und imgproxy

  • Bild-Upload-Endpoint POST /images/upload (S3/MinIO)
  • imgproxy-Integration für optimierte, HMAC-signierte Bild-URLs
  • attach_image_to_item-Tool zum Verknüpfen von Bildern
  • Uploader-Berechtigung (can_upload) für Vermieter
2026-04 Feature

Gerätesets

  • Sets: Bündel aus mehreren Geräten zu einem Tagespreis
  • list_sets-Tool
  • Sets-Übersicht auf der Webseite
2026-03 Feature

Chat-Assistent

  • Chat-Interface mit Claude (SSE-Streaming)
  • Konversationspersistenz in SQLite
  • Konversationstitel via set_conversation_title-Tool
2026-02 Feature

Admin-Tools und Vermieter-Verwaltung

  • admin_approve_uploader, admin_revoke_uploader, admin_list_users
  • Vermieter-Whitelist (can_upload-Flag)
  • Admin-Flag (is_admin) für Nutzerverwaltung
2026-01 Feature

OAuth PKCE für MCP-Clients

  • OIDC-Provider mit Authorization Code + PKCE
  • Dynamic Client Registration (POST /oauth/register)
  • Kompatibel mit Claude Desktop und anderen MCP-Clients
2025-12 Feature

Buchungsfluss

  • Buchungsanfragen via MCP-Tool create_booking
  • Owner-Benachrichtigung per E-Mail (Approve/Reject-Links)
  • Stornierung durch Mieter und Owner
  • Status: pendingapproved / rejected / cancelled
2025-12 Feature

Authentifizierung

  • GitHub OAuth (arctic)
  • Magic Link per E-Mail
  • JWT RS256 (jose) als Cookie
2025-11 Feature

MCP-Server und Webseite

  • Initiale Implementierung des MCP-Servers (Streamable HTTP)
  • Astro SSR Website mit Geräteübersicht und Detailseiten
  • Verfügbarkeitskalender
  • SQLite-Datenbankschema (Migrationen)
  • Deployment auf k3s (ARM, Traefik, cert-manager)