No external auth providers to keep authentication fully self-sovereign
and avoid dependency on third-party services. Removes Google Sign-In,
Apple Sign-In components, utilities, endpoints, translations, and
mobile dependencies across all apps and shared packages.
Google/Apple integrations for data sync (Contacts import, Calendar sync)
are intentionally preserved as they serve a different purpose.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New reviews table (userId, locationId, rating 1-5, comment, unique per user)
- ReviewService with CRUD, stats aggregation, batch stats for lists
- ReviewController with GET/POST/DELETE endpoints at /reviews/:locationId
- Location list and detail endpoints now include reviewStats (avg + count)
- Star rating display on location cards (home page)
- Full review section on detail page: star picker, comment, submit, delete
- i18n: 13 new review-related translations (DE/EN)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Svelte 5 restricts {@const} to block contexts only. Use direct
isOpenNow() calls in {#if} conditions instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
shared-auth depends on shared-types for contactsClient, causing build
failure when the package isn't available.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add isOpenNow() utility that checks current time against opening hours
- Show "Open now" / "Closed" badge on location cards and detail page
- Add category filter pills to the map page (click to filter markers)
- Add opening hours to seed data for cafés, bars, restaurant, shops, museums
- Add missing category colors to detail page
- i18n: openNow, closedNow, filterAll (DE/EN)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SvelteKit prerendering of /offline failed because favicon.png was
referenced in app.html but not present in the static directory.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The package was dynamically imported in the map page but not declared
in package.json, causing production builds to fail.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The shared-pwa package was missing from the Dockerfile build steps,
causing the web container build to fail on esbuild resolution.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add cafe, bar, park, beach, hotel, event_venue, and viewpoint categories
to the CityCorners city guide. Each category includes 5 real Konstanz
locations with descriptions, addresses, and coordinates.
Changes across all layers: DB schema enum, DTOs, lookup keyword detection,
i18n (DE/EN), map colors, filter pills, landing page, and seed data.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New script generates COPY blocks between marker comments, eliminating
manual maintenance. All 17 web Dockerfiles updated with markers.
Supports --check flag for CI validation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. SEO Slugs: Auto-generated from name (ä→ae, ö→oe, etc.), unique with
-2/-3 suffix. Routes accept both UUID and slug. Seed data includes slugs.
2. Opening Hours + Contact: website, phone, openingHours fields in schema.
Displayed on detail page, editable in add/edit forms.
3. Landing Page with API: Fetches locations from backend at build time,
falls back to hardcoded JSON if API unreachable.
4. Frontend Tests: Vitest setup with api.test.ts (50 backend + web tests).
5. Marker Clustering: leaflet.markercluster for 10+ locations on map,
direct markers for fewer.
6. Favorite Collections: New collections table with CRUD endpoints.
Favorites page has tabs for favorites vs collections. Create, view,
delete collections with location management.
7. Rate Limiting: In-memory guard (10 req/min) on write endpoints.
Returns 429 with retryAfter.
8. Soft Deletes: deletedAt field, all reads filter deleted records.
POST /locations/:id/restore endpoint for owners.
50 backend tests passing, 0 type errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove unnecessary wrapper div in WidgetContainer
- Increase grid gap from gap-4 to gap-5 for breathing room
- Add auto-rows-fr for equal row heights
- Add min-h on widget content so empty widgets aren't tiny
- Change default layout to 3 equal columns (small)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Photo Gallery:
- New `images` JSONB array field in locations schema
- POST /locations/:id/images endpoint to add photos (auth required)
- Gallery with thumbnail strip and image counter on detail page
- Any authenticated user can add photos to any location
- "Add photo" button inline with thumbnails
2. Nearby Locations:
- GET /locations/:id/nearby endpoint with Haversine distance query
- Configurable radius (default 2km, max 10km)
- Returns up to 5 nearby locations sorted by distance
- Horizontal scroll card strip on detail page showing distance
3. Search Suggestions + History:
- GET /locations/suggestions endpoint (prefix matching, fast)
- Search history stored in localStorage (max 8 entries)
- Empty search shows recent history with clock icon
- Selected locations automatically saved to history
- Falls back to full-text search if no prefix matches
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Owner tracking (createdBy):
- Add createdBy field to locations schema
- Set createdBy to userId on location creation
- Only owners can edit/delete their own locations
- Seed/unowned locations remain editable by anyone
2. Edit/Delete UI:
- Edit button + full edit form at /locations/:id/edit
- Delete button with confirmation dialog on detail page
- Both only visible to the location owner
- ForbiddenException (403) if non-owner tries to modify
3. Pagination:
- Backend returns paginated results (page, limit, total, totalPages)
- Frontend "Load more" button for infinite scroll
- Category filter reloads from API with server-side filtering
- Default 20 items per page, max 100
Tests updated: 36 tests passing (5 new for ownership + pagination).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Lazy loading for location card images
- Category filter pills now show count (e.g. "Restaurants (3)")
- Better empty states with category-specific messages and emoji
- Share button on detail page (Web Share API with clipboard fallback)
- "On map" and "Directions" (Google Maps) buttons on detail page
- Geolocation "locate me" button on map page with user marker
- Image URL retry button on add form when image fails to load
- i18n keys for all new features (DE/EN)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mac Mini had 25k+ TIME_WAIT sockets exhausting the 16k ephemeral port range,
blocking all outgoing TCP connections. Root cause: ~50 health checks at 30s
intervals + n8n automation creating excessive short-lived connections.
- Remove n8n service and volume (no longer needed)
- Increase health check intervals: 30s → 120s (app services), 10s → 30s (infra)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a "Kosten" tab showing all 40+ credit operations across all apps,
grouped by app with category filters (AI, Productivity, Premium) and
color-coded cost badges.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add `locale` prop to all 6 apps using QuickInputBar
(todo, contacts, zitare, citycorners, questions, calendar)
- Enable `deferSearch` on apps with create flow
(contacts, zitare, questions) to match todo behavior
- Pass locale through Calendar's UnifiedBar wrapper
- Questions: default to 'en' locale (English-first app)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests: Jest + ts-jest with mock factories. 4 test suites covering LocationService (CRUD, search), FavoriteService (add/remove, conflicts), LocationLookupService (web search, extraction, error handling), LocationController (endpoints, query params).
Docs: Complete CLAUDE.md rewrite with live URLs, all endpoints, web pages, features, environment variables, Docker config, and test overview.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend: GET /locations/lookup?q= endpoint that searches via mana-search, extracts content from top results, auto-detects address and category, returns pre-filled data with source links.
Frontend: /add page now has a two-step flow:
1. Search step: user enters a place name, backend scrapes the web
2. Edit step: form pre-filled with found data (name, description, address, category), user can review/edit before submitting. Shows source links.
Also fixed all API paths to use /api/v1/ prefix via centralized api() helper.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
API paths: Created centralized api() helper in $lib/api.ts. All fetch calls now use /api/v1/ prefix matching the production NestJS route structure.
New feature: /add page where authenticated users can submit new locations with name, category, description, and optional address. Added "Hinzufügen" nav item with plus icon.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Align all 20 web app auth stores to a consistent pattern:
- Use DEV_* constants with import.meta.env.DEV guard (no localhost leak in prod)
- Pass backendUrl to initializeWebAuth for automatic 401 token refresh
- Add redirectTo to forgotPassword for correct post-reset redirect
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PWA: @vite-pwa/sveltekit with shared-pwa config, offline fallback page, service worker with standard caching preset.
i18n: svelte-i18n with DE/EN locale files, all UI strings translated, language switcher in PillNav, auth pages use shared-i18n translations.
Landing: Migrated from scoped CSS to Tailwind CSS with @astrojs/tailwind. Hero section, card grid, category filter buttons, detail page with timeline. Removed unused components (Welcome, ThemeToggle, update-locations.js).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend: GET /locations/search?q= endpoint with ILIKE on name, description, address.
Frontend: QuickInputBar wired up in app layout, searches locations via API, navigates to detail page on select.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New project with three apps:
- Landing (Astro): static site with SVG illustrations, location data
- Backend (NestJS, port 3025): CRUD API for locations + favorites, Drizzle ORM, auth via mana-core-auth
- Web (SvelteKit, port 5196): Tailwind 4, PillNav, auth (login/register/SSO), Leaflet map, favorites with optimistic updates, theme/settings
Infrastructure: DB init SQL, setup-databases.sh, generate-env.mjs, root package.json scripts, Dockerfiles, docker-compose.macmini.yml (backend:3025, web:5022), Cloudflare wrangler.toml.
Branding: registered in shared-branding (AppId, APP_BRANDING, APP_ICONS, MANA_APPS, CitycornersLogo).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>