docs(citycorners): update CLAUDE.md for multi-city platform

Rewrite project docs to reflect the new multi-city architecture:
local-first data layer, city-scoped routes, and community-driven
content model.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-03-29 14:28:02 +02:00
parent e73d64c999
commit 89e6a202df

View file

@ -1,13 +1,12 @@
# CityCorners
City guide for Konstanz (Bodensee) showcasing locations, restaurants, museums, and sights.
Open platform for city guides worldwide — users create cities and add locations, growing the platform organically from the community.
## Live URLs
| Service | URL |
|---------|-----|
| **Web App** | https://citycorners.mana.how |
| **API** | https://citycorners-api.mana.how |
| **Landing** | https://citycorners-landing.pages.dev |
## Architecture
@ -16,83 +15,70 @@ City guide for Konstanz (Bodensee) showcasing locations, restaurants, museum
apps/citycorners/
├── apps/
│ ├── landing/ # Astro static site (Tailwind, Cloudflare Pages)
│ ├── backend/ # NestJS API (port 3025 dev, 3041 prod)
│ └── web/ # SvelteKit web app (port 5196 dev, 5022 prod)
└── CLAUDE.md
```
### Tech Stack
- **Backend:** NestJS 10, Drizzle ORM, PostgreSQL, mana-core-auth (JWT)
- **Data Layer:** Local-first via @manacore/local-store (Dexie.js/IndexedDB)
- **Sync:** mana-sync (Go, WebSocket) for server synchronization
- **Web:** SvelteKit 2, Svelte 5 runes, Tailwind 4, Leaflet maps, svelte-i18n (DE/EN), PWA
- **Landing:** Astro 5, Tailwind 3, static site generation
- **Search:** mana-search integration (SearXNG + content extraction)
- **Auth:** mana-core-auth (JWT, guest mode supported)
## Development
```bash
# Full stack (auth + backend + web)
# Full stack (auth + web)
pnpm dev:citycorners:full
# Individual apps
pnpm dev:citycorners:landing
pnpm dev:citycorners:backend
pnpm dev:citycorners:web
# Database
pnpm citycorners:db:push # Push schema
pnpm citycorners:db:studio # Drizzle Studio
pnpm citycorners:db:seed # Seed 41 sample locations
# Tests
pnpm --filter @citycorners/backend test # Run all tests (31 tests)
pnpm --filter @citycorners/backend test:watch # Watch mode
pnpm --filter @citycorners/backend test:cov # Coverage report
# Deploy
pnpm deploy:landing:citycorners # Landing to Cloudflare Pages
```
## Database
## Data Model (Local-First)
PostgreSQL database `citycorners` with Drizzle ORM.
Three IndexedDB collections managed by `@manacore/local-store`:
### Schema
- **locations** name, category (enum: sight/restaurant/shop/museum/cafe/bar/park/beach/hotel/event_venue/viewpoint), description, address, lat/lng, imageUrl, timeline (JSONB array of {year, event})
- **favorites** userId, locationId (FK → locations, cascade delete), unique constraint on (userId, locationId)
## API Endpoints
All endpoints are prefixed with `/api/v1/` in production (via shared-nestjs-setup).
### Cities
- **id** (string, PK)
- **name** (string) — city/village/town name
- **slug** (string, indexed) — URL-friendly name
- **country** (string, indexed)
- **state** (string, optional) — state/region
- **description** (string, optional)
- **latitude** (number) — center coordinates
- **longitude** (number)
- **imageUrl** (string, optional)
- **createdBy** (string, optional) — user ID
### Locations
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| GET | `/locations` | No | List all (optional `?category=sight\|restaurant\|shop\|museum`) |
| GET | `/locations/search?q=` | No | Text search (ILIKE on name, description, address) |
| GET | `/locations/lookup?q=` | No | Web lookup via mana-search (scrapes info, auto-fills form) |
| GET | `/locations/:id` | No | Get single location |
| POST | `/locations` | Yes | Create location |
| PUT | `/locations/:id` | Yes | Update location |
| DELETE | `/locations/:id` | Yes | Delete location |
- **id** (string, PK)
- **cityId** (string, indexed, FK → cities)
- **name** (string, indexed)
- **category** (enum, indexed: sight/restaurant/shop/museum/cafe/bar/park/beach/hotel/event_venue/viewpoint)
- **description** (string, optional)
- **address** (string, optional)
- **latitude/longitude** (number, optional)
- **imageUrl** (string, optional)
- **timeline** (JSON array of {year, event}, optional)
### Favorites
- **id** (string, PK)
- **locationId** (string, indexed, FK → locations)
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| GET | `/favorites` | Yes | List user's favorite location IDs |
| POST | `/favorites/:locationId` | Yes | Add to favorites |
| DELETE | `/favorites/:locationId` | Yes | Remove from favorites |
## Web App Pages
## Web App Routes
| Route | Description |
|-------|-------------|
| `/` | Location grid with category filter pills |
| `/map` | Leaflet map with color-coded markers |
| `/locations/:id` | Detail page with mini-map, timeline, favorite button |
| `/add` | Two-step flow: web lookup → edit form → submit |
| `/` | City discovery — search & browse cities |
| `/add-city` | Create a new city (auth required) |
| `/cities/:slug` | City home — location grid with category filters |
| `/cities/:slug/map` | Leaflet map with color-coded markers |
| `/cities/:slug/add` | Add a location to city (auth required) |
| `/cities/:slug/locations/:id` | Location detail with map, timeline, nearby |
| `/cities/:slug/locations/:id/edit` | Edit location (creator only) |
| `/favorites` | User's saved locations |
| `/settings` | Theme mode/variant, account, about |
| `/login`, `/register` | Auth via shared-auth-ui |
@ -100,16 +86,20 @@ All endpoints are prefixed with `/api/v1/` in production (via shared-nestjs-setu
## Features
- **PWA:** Installable, offline fallback, service worker caching (API: NetworkFirst, images: CacheFirst)
- **i18n:** German + English, language switcher in PillNav, localStorage persistence
- **Favorites:** Optimistic updates, auth-gated heart button on cards + detail page
- **Search:** QuickInputBar in PillNav, backend ILIKE search
- **Web Lookup:** mana-search integration for auto-filling location data from the web
- **Branding:** Registered in shared-branding (AppId, icon, APP_URLS, app switcher)
- **Multi-City Platform:** Users create cities/villages and add locations within them
- **Local-First:** All CRUD via IndexedDB, works offline, syncs to server
- **Guest Mode:** Browse with seed data (Konstanz, Zürich, Berlin)
- **PWA:** Installable, offline fallback, service worker caching
- **i18n:** German + English, language switcher
- **Context-Aware Navigation:** Nav items change based on city context
- **Categories:** 11 location types with color-coded markers
- **Favorites:** Heart button on cards, auth-gated
- **Geocoding:** Auto-coordinates from city/address names (Nominatim)
- **Slug Generation:** Auto-generated URL-safe slugs with umlaut handling
## Categories
| DB Value | Label (DE) | Label (EN) | Card Color |
| DB Value | Label (DE) | Label (EN) | Marker Color |
|----------|------------|------------|------------|
| `sight` | Sehenswürdigkeit | Sight | Blue |
| `restaurant` | Restaurant | Restaurant | Red |
@ -123,27 +113,14 @@ All endpoints are prefixed with `/api/v1/` in production (via shared-nestjs-setu
| `event_venue` | Veranstaltungsort | Event Venue | Pink |
| `viewpoint` | Aussichtspunkt | Viewpoint | Sky |
## Tests
4 test suites, 31 tests covering:
- `LocationService` CRUD, search, category filtering
- `FavoriteService` add/remove/check, conflict handling
- `LocationLookupService` web search, content extraction, address/category detection, error handling
- `LocationController` endpoint routing, query params, auth guards
## Docker
- **Backend:** `apps/citycorners/apps/backend/Dockerfile` (multi-stage, port 3041 prod)
- **Web:** `apps/citycorners/apps/web/Dockerfile` (multi-stage, port 5022 prod)
- **Entrypoints:** Auto schema push, optional seed on start
- **docker-compose.macmini.yml:** Both services configured with health checks
- **docker-compose.macmini.yml:** Web service with health check
## Environment Variables
| Variable | Used by | Description |
|----------|---------|-------------|
| `DATABASE_URL` | Backend | PostgreSQL connection string |
| `MANA_CORE_AUTH_URL` | Backend | Auth service URL |
| `MANA_SEARCH_URL` | Backend | mana-search service URL |
| `PUBLIC_BACKEND_URL` | Web | Backend API URL |
| `PUBLIC_MANA_CORE_AUTH_URL` | Web | Auth service URL (client) |
| `PUBLIC_SYNC_SERVER_URL` | Web | mana-sync WebSocket URL |