Loaded and fixed four seed files the user generated with other tools: - moscow_top1500_gen.yaml (1500 places): every single entry had a YAML-breaking bug — the "long" variant's second paragraph was emitted with zero indentation, breaking the block scalar in all 1500 cases identically. Also ~95% of entries had the literal string "null" instead of a real null for empty optional fields. Fixed both mechanically (reindent + string replace) and verified structurally (categories valid, coords sane, no empty content, no dup slugs). Content quality caveat (flagged to and accepted by the user): ~99% of entries have identical short/medium text, and "long" is just short + one bonus paragraph — shallow but broad coverage. - moscow_top1500.yaml, moscow_batch1.yaml, moscow_churches.yaml (15/18/25 places): these are genuinely well-researched, differentiated content (Kremlin cathedrals/palaces, monasteries) comparable in quality to the original hand-written seed files. moscow_top1500.yaml had a different corruption — every line had had a stray "N|" or "N|N|" row-number prefix baked in (looks like terminal output with line numbers got saved as file content) — stripped mechanically. These three files heavily overlap each other (~37 unique slugs across 58 entries) and 8 slugs overlap the generic _gen file; loaded in an order where the better-written content wins on upsert. Database now holds 1556 places (was 27). Verified via direct DB count, the local API, and the public https://guidetest.vrubel.xyz/ endpoint — all agree. Backend pytest suite still passes. No Android changes, so no APK rebuild needed; the existing installed app will see the new data on its next request to the already-updated live backend. Known follow-up (not fixed here): a handful of real-world landmarks now have multiple near-duplicate entries under different slugs (e.g. "Церковь Ризоположения" vs "Церковь Ризоположения Московского Кремля"), since the source files independently slugified the same places differently. Left for a dedicated dedup pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|---|---|---|
| android | ||
| backend | ||
| scripts | ||
| .env.example | ||
| .gitignore | ||
| .telegram.env.example | ||
| docker-compose.yml | ||
| README.md | ||
guideCity
Android walking city-guide app. Detects the user's location, finds nearby landmarks, and narrates historical/architectural information about them by voice while showing a swipeable card stack. Starting city: Moscow.
Architecture
┌────────────────────┐
│ Android app │ Kotlin + Jetpack Compose
│ (android/) │ OSM map, on-device TTS,
└─────────┬──────────┘ location, Room favorites
│ HTTPS / REST (JSON)
┌─────────▼──────────┐
│ FastAPI backend │ Python, SQLAlchemy, Alembic
│ (backend/) │ Dockerized
└─────────┬──────────┘
│ SQL
┌─────────▼──────────┐
│ PostgreSQL+PostGIS │ cities / places / place_content
└────────────────────┘
backend/— FastAPI service exposing city/place/nearby-search endpoints, backed by PostgreSQL+PostGIS. Seebackend/for details.android/— Kotlin/Compose app skeleton (MVVM, Hilt, Retrofit, Room, DataStore, OpenStreetMap via osmdroid, on-device TextToSpeech).
Backend quickstart
cp .env.example .env
docker compose up -d db
docker compose exec api alembic upgrade head # (once api image is built: docker compose up -d --build api adminer first)
docker compose exec api python -m seed.seed_loader --file seed/moscow_gorky_park.yaml
docker compose exec api python -m seed.seed_loader --file seed/moscow_red_square.yaml
docker compose exec api python -m seed.seed_loader --file seed/moscow_city.yaml
curl http://localhost:8000/api/v1/health
curl "http://localhost:8000/api/v1/nearby?lat=55.7525&lon=37.6231"
Swagger UI: http://localhost:8000/docs Adminer (DB inspection): http://localhost:8080
The api service binds 0.0.0.0:8000 (see docker-compose.yml), so it's
also reachable from other devices on the same LAN at
http://<this-machine's-LAN-IP>:8000/ — no extra config needed, just make
sure nothing (firewall, VPN) blocks port 8000 on that interface.
It's also reverse-proxied behind nginx at https://guidetest.vrubel.xyz/,
which works from anywhere (not just the local network) and is the preferred
API_BASE_URL for the Android app during this test phase.
Android quickstart
cp android/local.properties.example android/local.properties
# fill in sdk.dir (and API_BASE_URL if not using the default)
cd android && ./gradlew :app:assembleDebug
Point the app's API base URL (API_BASE_URL in local.properties) at
https://guidetest.vrubel.xyz/ (works from anywhere), http://10.0.2.2:8000/
for the emulator, or your machine's LAN IP for a physical device on the same
Wi-Fi/LAN.
Run unit tests before building — ./gradlew testDebugUnitTest, then
./gradlew :app:assembleDebug.
Map
Uses OpenStreetMap tiles via osmdroid
(map/CityMapView.kt) — free, no API key or account needed, works out of
the box. (An earlier iteration tried the native 2GIS MapKit SDK instead;
dropped because getting a working mobile-SDK key from 2GIS turned out to be
a sales-mediated B2B process, not a quick self-serve signup — see git
history if that's ever worth revisiting.)
Notes / current scope
This is iteration 1: Moscow only (Gorky Park, Red Square area, Moscow-City), no user accounts (favorites are local/Room-only), no speed/heading-aware auto content-length selection yet (reserved API params exist, unused). Nearby-search radius caps at 10km.