mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-21 02:46:42 +02:00
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>
149 lines
5.4 KiB
Markdown
149 lines
5.4 KiB
Markdown
# CityCorners
|
||
|
||
City guide for Konstanz (Bodensee) – showcasing locations, restaurants, museums, and sights.
|
||
|
||
## Live URLs
|
||
|
||
| Service | URL |
|
||
|---------|-----|
|
||
| **Web App** | https://citycorners.mana.how |
|
||
| **API** | https://citycorners-api.mana.how |
|
||
| **Landing** | https://citycorners-landing.pages.dev |
|
||
|
||
## Architecture
|
||
|
||
```
|
||
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)
|
||
- **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)
|
||
|
||
## Development
|
||
|
||
```bash
|
||
# Full stack (auth + backend + 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
|
||
|
||
PostgreSQL database `citycorners` with Drizzle ORM.
|
||
|
||
### 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).
|
||
|
||
### 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 |
|
||
|
||
### Favorites
|
||
|
||
| 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
|
||
|
||
| 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 |
|
||
| `/favorites` | User's saved locations |
|
||
| `/settings` | Theme mode/variant, account, about |
|
||
| `/login`, `/register` | Auth via shared-auth-ui |
|
||
| `/offline` | PWA offline fallback |
|
||
|
||
## 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)
|
||
|
||
## Categories
|
||
|
||
| DB Value | Label (DE) | Label (EN) | Card Color |
|
||
|----------|------------|------------|------------|
|
||
| `sight` | Sehenswürdigkeit | Sight | Blue |
|
||
| `restaurant` | Restaurant | Restaurant | Red |
|
||
| `shop` | Laden | Shop | Green |
|
||
| `museum` | Museum | Museum | Purple |
|
||
| `cafe` | Café | Café | Amber |
|
||
| `bar` | Bar | Bar | Orange |
|
||
| `park` | Park | Park | Emerald |
|
||
| `beach` | Strandbad | Beach | Cyan |
|
||
| `hotel` | Hotel | Hotel | Indigo |
|
||
| `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
|
||
|
||
## 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) |
|