2026-07-09 18:19:47 +00:00
|
|
|
# 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/) │ 2GIS 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. See `backend/` for details.
|
|
|
|
|
- `android/` — Kotlin/Compose app skeleton (MVVM, Hilt, Retrofit, Room,
|
|
|
|
|
DataStore, 2GIS MapKit, on-device TextToSpeech).
|
|
|
|
|
|
|
|
|
|
## Backend quickstart
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
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
|
|
|
|
|
|
2026-07-09 19:11:31 +00:00
|
|
|
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.
|
|
|
|
|
|
2026-07-09 20:10:40 +00:00
|
|
|
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.
|
|
|
|
|
|
2026-07-09 18:19:47 +00:00
|
|
|
## Android quickstart
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
cp android/local.properties.example android/local.properties
|
|
|
|
|
# fill in sdk.dir and DGIS_API_KEY (test key: b4df01a8-61db-4cb9-8286-7e069495987d)
|
|
|
|
|
cd android && ./gradlew :app:assembleDebug
|
|
|
|
|
```
|
|
|
|
|
|
2026-07-09 19:11:31 +00:00
|
|
|
Point the app's API base URL (`API_BASE_URL` in `local.properties`) at
|
2026-07-09 20:10:40 +00:00
|
|
|
`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
|
2026-07-09 19:11:31 +00:00
|
|
|
Wi-Fi/LAN.
|
2026-07-09 18:19:47 +00:00
|
|
|
|
2026-07-09 20:10:40 +00:00
|
|
|
Run unit tests before building — `./gradlew testDebugUnitTest`, then
|
|
|
|
|
`./gradlew :app:assembleDebug`.
|
|
|
|
|
|
2026-07-09 21:28:52 +00:00
|
|
|
## 2GIS map SDK
|
|
|
|
|
|
|
|
|
|
The app depends on the real 2GIS MapKit SDK (`ru.dgis.sdk:sdk-map` +
|
|
|
|
|
`compose-map`, from `https://artifactory.2gis.dev/sdk-maven-release`, wired
|
|
|
|
|
up in `settings.gradle.kts`/`app/build.gradle.kts`). It needs a **separate**
|
|
|
|
|
key from the `DGIS_API_KEY` above:
|
|
|
|
|
|
|
|
|
|
- `DGIS_API_KEY` (the `b4df01a...` value) is a 2GIS **public REST/JS API**
|
|
|
|
|
key — not used by the native SDK at all currently.
|
|
|
|
|
- The native MapKit SDK instead needs a **`dgissdk.key` file**, issued
|
|
|
|
|
per-app (tied to the package name `com.guidecity.app`) from
|
|
|
|
|
https://dev.2gis.com/. Place it at `android/app/src/main/assets/dgissdk.key`
|
|
|
|
|
(gitignored — don't commit it).
|
|
|
|
|
|
|
|
|
|
Without that key file, `DgisSdkProvider` fails to initialize (logged, not
|
|
|
|
|
crashed) and `DgisMapView` falls back to a placeholder canvas rendering
|
|
|
|
|
(user location + nearby place dots, no real map tiles). Once a real key is
|
|
|
|
|
in place, the real map should render automatically — no code changes needed.
|
|
|
|
|
|
|
|
|
|
Also note: the SDK bundles native libraries per CPU architecture, which
|
|
|
|
|
balloons APK size a lot (~19MB → ~190MB unfiltered). `app/build.gradle.kts`
|
|
|
|
|
restricts `ndk.abiFilters` to `arm64-v8a` only (~69MB) since that covers
|
|
|
|
|
virtually all real devices today — remove that filter if you need to test
|
|
|
|
|
on an x86 emulator or 32-bit device.
|
|
|
|
|
|
2026-07-09 18:19:47 +00:00
|
|
|
## 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).
|
2026-07-09 21:28:52 +00:00
|
|
|
Nearby-search radius caps at 10km. Place markers aren't yet plotted on the
|
|
|
|
|
real 2GIS map (only the placeholder does that) — follow-up work.
|
2026-07-09 18:19:47 +00:00
|
|
|
|
2026-07-09 21:28:52 +00:00
|
|
|
The 2GIS REST/JS API key above is used directly via
|
|
|
|
|
`local.properties`/`BuildConfig` for development convenience — don't ship it
|
|
|
|
|
as-is in a public repo. Same goes for `dgissdk.key` once you have one.
|