Conversation
📝 WalkthroughWalkthroughIntroduces an interactive map feature with backend handlers serving a map page and city contribution API endpoint, a repository function querying city contribution counts, and a comprehensive frontend implementation using Leaflet with geocoding integration, styling, and navigation updates. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Handler as Backend Handler
participant Repo as Repository
participant DB as Database
participant API as Nominatim API
participant Leaflet
Client->>Handler: GET /karte
Handler->>Repo: GetCityContribCounts()
Repo->>DB: Query contributions by city
DB-->>Repo: City contribution rows
Repo-->>Handler: []CityContrib
Handler-->>Client: Render map.html with city data
Client->>Client: DOM Ready
Client->>Client: initMap()
Client->>Handler: GET /api/map-data
Handler->>Repo: GetCityContribCounts()
Repo->>DB: Query contributions by city
DB-->>Repo: City contribution rows
Repo-->>Handler: []CityContrib
Handler-->>Client: JSON response
Client->>API: Geocode city names (with rate limiting)
API-->>Client: Coordinates for each city
Client->>Leaflet: Create markers with popups & legend
Client->>Leaflet: Fit map bounds to geocoded cities
Leaflet-->>Client: Interactive map rendered
Possibly Related PRs
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan for PR comments
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (5)
src/lib/map.ts (1)
48-59: Consider caching geocoded coordinates server-side.With 1.1s delay per city to respect Nominatim's rate limit, loading time scales linearly. For 30 cities, users wait ~33 seconds. Consider:
- Caching lat/lon in the database after first geocode
- Returning coordinates from
/api/map-datadirectly- Or at minimum, showing a progress indicator during geocoding
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/map.ts` around lines 48 - 59, The geocoding loop in geocodeAll (which calls geocodeCity and returns GeocodedCity[]) causes linear delays; modify the server-side flow to cache coordinates for CityContrib entries: when handling /api/map-data, first check the DB record for existing lat/lon and return those immediately; update geocodeAll to skip API calls for cities with cached coords and persist newly fetched coords back to the DB (use CityContrib identifier to save lat/lon), and if you cannot complete caching in this change, add a progress indicator in the client for the /api/map-data request to reflect ongoing geocoding.web/templates/components/header.html (1)
27-27: Consider adding accessible text for screen readers.The emoji-only link
🗺️lacks descriptive text for screen reader users. Consider adding a visually hidden label similar to how other sites handle icon-only navigation.♿ Proposed accessibility improvement
- <a href="/karte" {{ if eq .CurrentPath "/karte" }}class="nav-active"{{ end }}>🗺️</a> + <a href="/karte" {{ if eq .CurrentPath "/karte" }}class="nav-active"{{ end }}>🗺️<span class="sr-only">Karte</span></a>Note: The static analysis warnings about HTML escaping and tag pairing are false positives—HTMLHint doesn't recognize Go template syntax.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/templates/components/header.html` at line 27, The emoji-only navigation link in header.html (the anchor with href="/karte" and the template condition checking .CurrentPath) is not accessible to screen readers; update that anchor to include descriptive accessible text by adding either an aria-label="Map" (or localized equivalent) or a visually hidden <span> (e.g., class="sr-only") containing a short label like "Map" while keeping the emoji visible, ensuring the template condition (if eq .CurrentPath "/karte") and any existing classes remain unchanged.web/templates/app/map.html (1)
9-9: Give the map region a label and non-JS fallback.This is an empty mount node right now, so a failed Leaflet/init load leaves a blank box and assistive tech gets no name for the region. Add an
aria-label/aria-labelledbyand a small fallback such as loading text or a<noscript>message.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/templates/app/map.html` at line 9, The map mount node with id "map" and class "leaflet-map-container" is currently an empty div which leaves a blank, unlabeled region if Leaflet/JS fails; add an accessible label (aria-label or aria-labelledby) to that div and include non-JS fallback content (e.g., a short "Loading map…" text inside the div or a <noscript> message) so assistive tech gets a name and users without JS see a message — ensure the JS that mounts the Leaflet map still replaces or preserves the content appropriately (targeting the "map" element).web/static/style.css (2)
2047-2064: These selectors don't match the shipped markup.
web/templates/app/map.htmluses.page-headerand.page-title, but this block styles.map-hero,.map-hero-left, and.map-title. As written, those rules never affect the new page. Remove them or align the template/classes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/static/style.css` around lines 2047 - 2064, The CSS selectors .map-hero, .map-hero-left, and .map-title do not match the shipped markup (.page-header and .page-title); update the stylesheet so the rules apply to the live page by either removing the unused .map-* rules or renaming them to the markup classes (e.g., replace .map-hero with .page-header, .map-hero-left with the appropriate page header child class, and .map-title with .page-title) and keep the same properties, or alternatively update the template classes to .map-hero/.map-title if you prefer to keep the CSS; ensure you change all occurrences of .map-hero, .map-hero-left, and .map-title so styles take effect.
2240-2258: Add a:focus-visiblestate for the city cards.These are primary navigation links on the new page, but only hover gets a custom state. Mirror the hover affordance on
:focus-visibleso keyboard navigation is obvious.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/static/style.css` around lines 2240 - 2258, The city card lacks a keyboard-visible focus state; add a :focus-visible rule for .map-city-item that mirrors the hover affordance by setting the same border-color (rgba(0, 0, 0, 0.18)) and box-shadow (var(--shadow-sm)) so keyboard users see the same visual cue as hover; apply outline: none only if you replicate an equivalent visible focus style, and keep the selector as .map-city-item:focus-visible to target keyboard focus specifically.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/handlers/app/map.go`:
- Line 22: Replace uses of context.Background() passed to repository methods
with the incoming HTTP request context so DB queries cancel when the client
disconnects; specifically, change calls like
repository.GetCityContribCounts(context.Background()) (and the similar call at
the other occurrence) to use c.Request().Context() instead, ensuring you pass
the Echo handler's context (c) into GetCityContribCounts and any analogous
repository methods so cancellation/timeout propagation works correctly.
- Around line 54-55: The handler currently returns err.Error() in the JSON
response after calling sentryhelper.CaptureException(c, err), which can leak
sensitive internals; change the response body to a generic message (e.g.,
"internal server error" or "an internal error occurred") while keeping
sentryhelper.CaptureException(c, err) to report the full error internally, and
ensure the c.JSON call still returns http.StatusInternalServerError — update the
return in the code that builds the response map so it does not include
err.Error().
In `@internal/repository/map.go`:
- Around line 30-38: The code iterates over rows into []CityContrib using
rows.Next and rows.Scan but never checks rows.Err(), so iteration/scan/network
errors are swallowed; after the for rows.Next() loop (which fills result via
CityContrib and rows.Scan) call rows.Err(), and if non-nil return that error (or
wrap it) instead of returning the partial result and nil; update the function
that builds and returns result to propagate this error so callers can detect
iteration failures.
In `@src/lib/map.ts`:
- Around line 164-168: Update the Leaflet attribution URL to the correct domain:
replace "https://leaflet.js.com" with "https://leafletjs.com" in the L.tileLayer
attribution string (look for the L.tileLayer(...).addTo(map) call in this file)
so the attribution link points to the proper Leaflet website.
- Around line 76-81: The popup HTML interpolates unsanitized city.name into
marker.bindPopup, allowing XSS; change the popup creation to escape city.name
before interpolation (e.g., add a small helper escapeHtml that replaces & < > "
' / with entities and call it when building the string) or build the popup using
DOM APIs (createElement + textContent) and then set
marker.bindPopup(popupElement.outerHTML); update the code locations using
marker.bindPopup and ensure all uses of city.name in popup content go through
the escape helper or DOM text assignment.
In `@web/templates/app/map.html`:
- Line 29: The city count label currently always uses the plural "Beiträge";
update the template in map.html (the span with class "map-city-count" that
renders {{ .Count }}) to choose the correct German form by checking the count
(e.g., if .Count equals 1 render "Beitrag", otherwise "Beiträge") using the
template's conditional/if syntax so "1 Beitrag" displays correctly while all
other counts stay as "Beiträge".
---
Nitpick comments:
In `@src/lib/map.ts`:
- Around line 48-59: The geocoding loop in geocodeAll (which calls geocodeCity
and returns GeocodedCity[]) causes linear delays; modify the server-side flow to
cache coordinates for CityContrib entries: when handling /api/map-data, first
check the DB record for existing lat/lon and return those immediately; update
geocodeAll to skip API calls for cities with cached coords and persist newly
fetched coords back to the DB (use CityContrib identifier to save lat/lon), and
if you cannot complete caching in this change, add a progress indicator in the
client for the /api/map-data request to reflect ongoing geocoding.
In `@web/static/style.css`:
- Around line 2047-2064: The CSS selectors .map-hero, .map-hero-left, and
.map-title do not match the shipped markup (.page-header and .page-title);
update the stylesheet so the rules apply to the live page by either removing the
unused .map-* rules or renaming them to the markup classes (e.g., replace
.map-hero with .page-header, .map-hero-left with the appropriate page header
child class, and .map-title with .page-title) and keep the same properties, or
alternatively update the template classes to .map-hero/.map-title if you prefer
to keep the CSS; ensure you change all occurrences of .map-hero, .map-hero-left,
and .map-title so styles take effect.
- Around line 2240-2258: The city card lacks a keyboard-visible focus state; add
a :focus-visible rule for .map-city-item that mirrors the hover affordance by
setting the same border-color (rgba(0, 0, 0, 0.18)) and box-shadow
(var(--shadow-sm)) so keyboard users see the same visual cue as hover; apply
outline: none only if you replicate an equivalent visible focus style, and keep
the selector as .map-city-item:focus-visible to target keyboard focus
specifically.
In `@web/templates/app/map.html`:
- Line 9: The map mount node with id "map" and class "leaflet-map-container" is
currently an empty div which leaves a blank, unlabeled region if Leaflet/JS
fails; add an accessible label (aria-label or aria-labelledby) to that div and
include non-JS fallback content (e.g., a short "Loading map…" text inside the
div or a <noscript> message) so assistive tech gets a name and users without JS
see a message — ensure the JS that mounts the Leaflet map still replaces or
preserves the content appropriately (targeting the "map" element).
In `@web/templates/components/header.html`:
- Line 27: The emoji-only navigation link in header.html (the anchor with
href="/karte" and the template condition checking .CurrentPath) is not
accessible to screen readers; update that anchor to include descriptive
accessible text by adding either an aria-label="Map" (or localized equivalent)
or a visually hidden <span> (e.g., class="sr-only") containing a short label
like "Map" while keeping the emoji visible, ensuring the template condition (if
eq .CurrentPath "/karte") and any existing classes remain unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: aae2c06f-99af-43ba-9f0c-38208432ef19
📒 Files selected for processing (10)
internal/handlers/app/map.gointernal/handlers/routes.gointernal/repository/map.gopackage.jsonsrc/lib/map.tssrc/main.tssrc/styles.cssweb/static/style.cssweb/templates/app/map.htmlweb/templates/components/header.html
| func MapHandler(c echo.Context) error { | ||
| stats := utils.GetFooterStats() | ||
|
|
||
| cities, err := repository.GetCityContribCounts(context.Background()) |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Use request context for proper cancellation propagation.
context.Background() won't cancel the DB query if the client disconnects. Use c.Request().Context() to propagate cancellation signals.
♻️ Proposed fix
func MapHandler(c echo.Context) error {
stats := utils.GetFooterStats()
- cities, err := repository.GetCityContribCounts(context.Background())
+ cities, err := repository.GetCityContribCounts(c.Request().Context()) func MapDataHandler(c echo.Context) error {
- cities, err := repository.GetCityContribCounts(context.Background())
+ cities, err := repository.GetCityContribCounts(c.Request().Context())Also applies to: 52-52
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@internal/handlers/app/map.go` at line 22, Replace uses of
context.Background() passed to repository methods with the incoming HTTP request
context so DB queries cancel when the client disconnects; specifically, change
calls like repository.GetCityContribCounts(context.Background()) (and the
similar call at the other occurrence) to use c.Request().Context() instead,
ensuring you pass the Echo handler's context (c) into GetCityContribCounts and
any analogous repository methods so cancellation/timeout propagation works
correctly.
| sentryhelper.CaptureException(c, err) | ||
| return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) |
There was a problem hiding this comment.
Avoid exposing internal error details in API response.
err.Error() may contain sensitive information (DB connection details, query errors). Return a generic message instead.
🛡️ Proposed fix
if err != nil {
sentryhelper.CaptureException(c, err)
- return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
+ return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to load map data"})
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| sentryhelper.CaptureException(c, err) | |
| return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) | |
| if err != nil { | |
| sentryhelper.CaptureException(c, err) | |
| return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to load map data"}) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@internal/handlers/app/map.go` around lines 54 - 55, The handler currently
returns err.Error() in the JSON response after calling
sentryhelper.CaptureException(c, err), which can leak sensitive internals;
change the response body to a generic message (e.g., "internal server error" or
"an internal error occurred") while keeping sentryhelper.CaptureException(c,
err) to report the full error internally, and ensure the c.JSON call still
returns http.StatusInternalServerError — update the return in the code that
builds the response map so it does not include err.Error().
| var result []CityContrib | ||
| for rows.Next() { | ||
| var c CityContrib | ||
| if err := rows.Scan(&c.Name, &c.Count); err != nil { | ||
| continue | ||
| } | ||
| result = append(result, c) | ||
| } | ||
| return result, nil |
There was a problem hiding this comment.
Check rows.Err() after iteration to catch scan/network errors.
The loop may exit early due to iteration errors (e.g., connection loss). Without checking rows.Err(), these errors are silently ignored and partial data is returned as if successful.
🐛 Proposed fix
for rows.Next() {
var c CityContrib
if err := rows.Scan(&c.Name, &c.Count); err != nil {
continue
}
result = append(result, c)
}
+ if err := rows.Err(); err != nil {
+ return nil, err
+ }
return result, nil
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@internal/repository/map.go` around lines 30 - 38, The code iterates over rows
into []CityContrib using rows.Next and rows.Scan but never checks rows.Err(), so
iteration/scan/network errors are swallowed; after the for rows.Next() loop
(which fills result via CityContrib and rows.Scan) call rows.Err(), and if
non-nil return that error (or wrap it) instead of returning the partial result
and nil; update the function that builds and returns result to propagate this
error so callers can detect iteration failures.
| marker.bindPopup(` | ||
| <div class="map-popup"> | ||
| <strong>${city.name}</strong> | ||
| <span>${city.count} Beitrag${city.count !== 1 ? "e" : ""}</span> | ||
| </div> | ||
| `); |
There was a problem hiding this comment.
Sanitize city name to prevent XSS.
city.name originates from user-contributed data stored in the database. If a malicious city name like <img src=x onerror=alert(1)> is stored, it will be rendered unsanitized in the popup.
🛡️ Proposed fix using text escaping
+function escapeHtml(str: string): string {
+ const div = document.createElement("div");
+ div.textContent = str;
+ return div.innerHTML;
+}
+
function buildMarker(city: GeocodedCity): L.CircleMarker {
// ...
marker.bindPopup(`
<div class="map-popup">
- <strong>${city.name}</strong>
+ <strong>${escapeHtml(city.name)}</strong>
<span>${city.count} Beitrag${city.count !== 1 ? "e" : ""}</span>
</div>
`);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/map.ts` around lines 76 - 81, The popup HTML interpolates unsanitized
city.name into marker.bindPopup, allowing XSS; change the popup creation to
escape city.name before interpolation (e.g., add a small helper escapeHtml that
replaces & < > " ' / with entities and call it when building the string) or
build the popup using DOM APIs (createElement + textContent) and then set
marker.bindPopup(popupElement.outerHTML); update the code locations using
marker.bindPopup and ensure all uses of city.name in popup content go through
the escape helper or DOM text assignment.
| L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { | ||
| attribution: | ||
| '© <a href="https://leaflet.js.com">Leaflet</a> | © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>', | ||
| maxZoom: 18, | ||
| }).addTo(map); |
There was a problem hiding this comment.
Fix typo in Leaflet attribution URL.
The URL leaflet.js.com should be leafletjs.com.
🔧 Proposed fix
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution:
- '© <a href="https://leaflet.js.com">Leaflet</a> | © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
+ '© <a href="https://leafletjs.com">Leaflet</a> | © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
maxZoom: 18,
}).addTo(map);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/map.ts` around lines 164 - 168, Update the Leaflet attribution URL to
the correct domain: replace "https://leaflet.js.com" with
"https://leafletjs.com" in the L.tileLayer attribution string (look for the
L.tileLayer(...).addTo(map) call in this file) so the attribution link points to
the proper Leaflet website.
| {{ range .Cities }} | ||
| <a href="/?city={{ .Name }}" class="map-city-item"> | ||
| <span class="map-city-name">{{ .Name }}</span> | ||
| <span class="map-city-count">{{ .Count }} Beiträge</span> |
There was a problem hiding this comment.
Pluralize the contribution label.
1 Beiträge reads incorrectly in German. Switch the suffix for the singular case so the city list copy stays correct.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/templates/app/map.html` at line 29, The city count label currently always
uses the plural "Beiträge"; update the template in map.html (the span with class
"map-city-count" that renders {{ .Count }}) to choose the correct German form by
checking the count (e.g., if .Count equals 1 render "Beitrag", otherwise
"Beiträge") using the template's conditional/if syntax so "1 Beitrag" displays
correctly while all other counts stay as "Beiträge".
dmnktoe
left a comment
There was a problem hiding this comment.
Review: Interaktive Leaflet-Karte
Die Struktur ist sauber (Repository → Handler → Template → TS-Modul folgt der bestehenden Aufteilung), aber es gibt zwei Punkte, die vor einem Merge weg müssen, und einen dritten, der die Karte in der Praxis unbenutzbar macht.
🔴 Blocker
1. XSS im Marker-Popup — src/lib/map.ts
marker.bindPopup(`
<div class="map-popup">
<strong>${city.name}</strong>bindPopup mit einem String parst den Inhalt als HTML. city.name kommt aus contributions.user_city, und das ist ungefiltertes Nutzereingabe-Feld: in internal/handlers/app/upload.go:284 wird player_city nur durch strings.TrimSpace geschickt, es gibt keine serverseitige Whitelist gegen die Meilisearch-Städte. Die Autocomplete-Validierung in city-autocomplete.ts ist rein clientseitig und damit umgehbar.
Ein Beitrag mit dem Ort '<img src=x onerror=…>' führt also bei jeder Person aus, die /karte öffnet. Überall sonst geht der Ortsname durch html/template und wird escaped — dieser Pfad ist die einzige Ausnahme.
Fix: Popup per DOM aufbauen und textContent setzen, statt zu interpolieren. Dasselbe gilt für bindTooltip (dort ist es mit String(city.count) aktuell unkritisch, aber gleiche Klasse Problem).
2. echo/v4 — der Branch kompiliert gegen aktuelles main nicht
internal/handlers/app/map.go importiert github.com/labstack/echo/v4, main ist inzwischen auf echo/v5 v5.3.1. Der PR hängt an a0d0d923 vom 12. März; das package.json im Diff zeigt noch meilisearch ^0.55.0, swiper ^12.1.1 und @datadog/browser-rum — alles seitdem geändert. Bitte zuerst rebasen, sonst wird beim Merge versehentlich die halbe Dependency-Historie zurückgedreht.
🟠 Substanziell
3. Nominatim-Geocoding im Browser, bei jedem Seitenaufruf
geocodeAll läuft sequenziell mit 1,1 s Pause pro Stadt. Bei 40 Städten sind das ~45 Sekunden leere Karte — für jede Besucherin, bei jedem Aufruf, ohne Cache. Dazu kommt:
- Nominatims Nutzungsbedingungen verbieten systematisches/bulk Geocoding ausdrücklich und verlangen, Ergebnisse zu cachen.
- Der
User-Agent-Header ingeocodeCityist ein forbidden header name — Browser verwerfen ihn stillschweigend. Die Requests gehen also unidentifiziert raus, und genau das blockt Nominatim. - Kein Timeout, kein
AbortController.
Ihr habt die Koordinaten aber bereits: der Meilisearch-cities-Index liefert lat/lon (siehe CityHit in src/lib/city-autocomplete.ts). Wenn /api/map-data die Koordinaten serverseitig mitliefert — aus dem Index oder aus einer lat/lon-Spalte an contributions —, verschwinden Wartezeit, externe Abhängigkeit und Policy-Problem auf einen Schlag.
4. rows.Err() fehlt — internal/repository/map.go
GetCityContribCounts prüft nach der Schleife nicht rows.Err(). Alle iterierenden Funktionen in internal/repository/derive.go tun das. Ein Lesefehler mitten in der Iteration kommt aktuell als kurzes, erfolgreiches Ergebnis zurück.
5. Interne Fehler gehen an den Client — MapDataHandler
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})pgx-Fehler enthalten Tabellen-, Spalten- und teils Verbindungsdetails. Loggen + Sentry ja, aber nach außen eine generische Meldung.
🟡 Kleinigkeiten
-
if (res.ok) cities = await res.json();— bei einem 500er bleibtcitiesleer und die Seite zeigt „Noch keine Städte eingetragen." Ein Serverfehler sieht damit aus wie ein leerer Datenbestand. Dercatchfängt nur Netzwerkfehler. -
Attribution-Link ist kaputt:
https://leaflet.js.com→https://leafletjs.com. -
Daten werden doppelt geholt.
MapHandlerrendert die Städteliste serverseitig,initMapholt dieselben Zeilen danach nochmal über/api/map-data. Entweder die Daten inline mitgeben (<script type="application/json">) und den Endpunkt streichen, oder umgekehrt. -
Die beiden Stat-Cards zählen unterschiedliche Grundmengen. „Städte" ist
len .Cities(nur Beiträge mit nicht-leeremuser_city), „Beiträge" istFooterStats.TotalContributions(alle). Die Zahlen passen nicht zueinander. -
{{ .Count }} Beiträgeist immer Plural — „1 Beiträge". Inmap.tsist das mitcity.count !== 1korrekt gelöst, im Template nicht. -
@import "leaflet/dist/leaflet.css"liegt zwischenswiper/css/navigationundswiper/css/paginationund zerteilt den Swiper-Block. Besser dahinter. -
Keine Tests, während die anderen
src/lib-Module von 95 Tests abgedeckt sind.markerColorund der Fallback-Pfad vongeocodeCitywären billig und lohnend.
Merge-Reihenfolge
#143, #144 und #145 hängen alle am selben Stand und hängen sich gegenseitig in die Quere: alle drei hängen unten an web/static/style.css an, #143 und #145 ändern beide header.html, #143 und #145 beide src/main.ts. Am wenigsten weh tut #145 → #144 → #143, jeweils mit Rebase dazwischen.
Generated by Claude Code
Summary by CodeRabbit
Release Notes