Backend¶
Flask REST API. Atsevišķs repo geo-backend. Deploy uz Hetzner Docker.
Tehnoloģijas¶
- Python 3.11 + Flask app-factory (
create_appgeo-backend/app.py) - Flasgger — auto-generated Swagger UI no YAML docstrings
- SQLAlchemy → PostgreSQL 16 + PostGIS (native uz host)
- Flask-Migrate — schema migrations
- Stripe — subscriptions + webhook
- JWT auth —
@auth_requireddecorator - prometheus-client — custom
/metricsendpoint - Gunicorn 3 workers production
App layout¶
app.py ← create_app() factory
config/settings.py ← env config (DATABASE_URL, JWT_SECRET, ...)
models/ ← SQLAlchemy models
├── company.py
├── user.py
├── device.py + device_activity.py
└── feedback.py
routes/ ← Blueprints
services/ ← Biznesa loģika + importeri
middleware/ ← @auth_required dekorators
Blueprints¶
5 reģistrēti create_app:
auth_bp (/auth/*)¶
| Endpoint | Method | Auth | Mērķis |
|---|---|---|---|
/auth/register |
POST | – | Jauns konts (rate-limit 3/h) |
/auth/login |
POST | – | JWT issue (rate-limit 5/min) |
/auth/password-reset |
POST | – | Parole reset e-pasts |
/auth/password-reset/confirm |
POST | – | Apstipriniet ar token |
api_bp (/api/*)¶
Visi prasa @auth_required (Bearer JWT vai bare token).
| Endpoint | Method | Mērķis |
|---|---|---|
/api/ca/<n> |
GET | CA polygon ar WKT |
/api/employees |
GET, POST, DELETE | Komandas pārvalde |
/api/subscription/list |
GET | ntfy abonementu saraksts |
/api/subscription |
POST | Pievienot kadastram |
/api/subscription/<id> |
DELETE | Atcelt |
/api/encumbrance/history/<n> |
GET | Apgrūtinājumu vēsture |
/api/property/<id>/{mikroliegumi,iadt,biotopi,sugu-atradnes} |
GET | DAP datu paneles |
/api/forest/by-cadastre/<n> |
GET | VMD MVR kompartmenti |
/api/geocode/{search,reverse} |
GET | VAR adrešu meklēšana |
Pilns saraksts: /apidocs Swagger UI.
stripe_bp¶
Stripe webhook (rate-limit exempt, jo Stripe atkārto līdz pieņemts).
device_bp (/api/device/*)¶
| Endpoint | Auth | Mērķis |
|---|---|---|
/api/device/register |
– | App startup device registration |
/api/device/heartbeat |
– | Periodisks ping ar metrikām |
services_config_bp¶
/api/services-config — public, mobile lasa, lai atjauninātu services.json config bez APK update.
Auth middleware¶
- Validē JWT no
Authorizationheader (Bearer <token>vai bare<token>) - Ielādē
g.user,g.company - Atgriež 403
subscription_expired, ja Stripe sub aptver AUTH_BYPASS=1vidēs (default ON dev'ā) — endpoint'i strādā ar synthetic test user; uzliktAUTH_BYPASS=0prod'ā
Importeri¶
Standalone Python moduļi services/ ar import_all(db_url) + argparse main().
Daily (katru dienu)¶
| Skripts | Datu avots | Cron | Aptuvenais ilgums |
|---|---|---|---|
vzd_refresh.py --include-vmd |
VZD kadastrs + VMD CA polygons | 03:00 | ~17 min |
encumbrance_diff.py |
Apgrūtinājumu diff + ntfy push | 04:00 | ~5 min |
lad_deadline_notifier.py |
LAD termiņi → ntfy | 06:00 | ~10 sek |
Weekly (pirmdienās)¶
| Skripts | Datu avots | Cron | Aptuvenais |
|---|---|---|---|
lad_import.py |
LAD lauku bloki, ainavu elementi | 04:00 | ~2 min, 333K rindas |
var_import.py |
VAR adreses (data.gov.lv CKAN) |
04:30 | ~5 min, 549K punkti |
iadt_import.py |
DAP ĪADT + dabas pieminekļi | 05:00 | ~2 min, 17K |
biotopi_import.py |
DAP EU biotopi | 05:30 | ~3 min, 68K |
sugu_atradnes_import.py |
DAP sugu atradnes | 05:45 | ~3 min, 275K |
lvm_infra_import.py |
LVM ceļi/tilti/drenāža | 06:00 | ~1 min, 277K |
lvgmc_water_import.py |
LVĢMC upes, ezeri | 06:30 | ~30 sek, 471 |
osm_heritage_import.py |
OSM kultūras pieminekļi | 07:00 | ~1 min, 2.6K |
mikroliegumi_import.py |
DAP mikroliegumi SHP | 07:30 | ~1 min, 4.7K |
ArcGIS REST koplietotā loģika¶
iadt, biotopi, sugu_atradnes importeri koplieto services/_importer_common.py:
fetch_arcgis_page/iterate_arcgis_layer— paginationto_multipolygon_wkt— GeoJSON → WKT ar point bufferepoch_ms_to_date,int_or_none,update_import_meta— common helpers
Pievienojot jaunu ArcGIS REST importeri (LĢIA, NKMP utt.), atkārtoti izmantot šo moduli — paraugi ir 3 esošie importeri (~150 LOC katrs).
Domēna servisi¶
Ne-importeri, bet biznesa loģika:
| Serviss | Mērķis |
|---|---|
vmd_api.py |
VMD public API klients (CA WKT fetch) |
encumbrance_diff.py |
Apgrūtinājumu salīdzinājuma loģika + ntfy push |
stripe_service.py |
Stripe checkout + sub status helpers |
email_service.py |
Gmail SMTP integrācija notifikācijām un kļūdām |
lad_deadline_notifier.py |
LAD termiņa notifikāciju ģenerēšana |
vzd_local_service.py |
Atsevišķa Flask app uz port 5050 ar VZD/VMD lookups + /api/geocode/* + custom Prometheus exporter |
Konteinera arhitektūra¶
Divi konteineri no tā paša Docker image (registry.gitlab.com/.../geo-backend:latest):
| Konteiners | Port | Skripts | Mērķis |
|---|---|---|---|
geo-backend |
5000 | gunicorn app:app |
Auth, Stripe, devices |
klm-vzd-service |
5050 | python services/vzd_local_service.py |
VZD lookups + geocode + Prometheus /metrics |
Postgres ir native uz host (port 5432), nav Docker'ī. DATABASE_URL no abiem konteineriem norāda uz host.docker.internal:5432. Razons: pg_dump/backup vienkārši, dati ārpus Docker volumes.
Custom Prometheus metrikas¶
klm-vzd-service publicē uz /metrics. Lasāmais resursu saraksts (klm_* prefiks):
klm_api_requests_total{endpoint}— counterklm_cron_last_run_seconds{cron_job}— Unix timestamp pēdējam cron runklm_cron_last_exit_code{cron_job}— pēdējais exit code (0 = OK)klm_data_freshness_seconds{resource}— sekundes kopš pēdējā import_meta atjauninājumaklm_db_row_count{table}— DB rindu skaits galvenajām tabulāmklm_device_subscription_count— Stripe aktīvas subsklm_import_rows_total{resource}— pēdējā import rindu skaitsklm_unique_device_count— unikālidevice_tokennouser_subscriptiontabulasklm_notifications_sent_24h{delivered}— ntfy push notifikācijas 24h ar success/fail labels
Deploy¶
Push uz main → GitLab CI:
- build — Docker image (~3 min)
- init-db —
deployment/postgres-init/*.sql(tikai kad mainās) - deploy — SSH uz Hetzner: pull image, recreate
geo-backend+klm-vzd-servicekonteinerus, install crontab, 3 min health check
Pilna deploy plāns + cron pattern: geo-backend/docs/DEPLOYMENT.md.
Diska budžets uz Hetzner¶
| Komponents | Aptuvenais izmērs |
|---|---|
/var/lib/postgresql |
16 GB (15 GB vmd_db + indeksi) |
/var/lib/docker (overlay + images) |
5-10 GB pēc prune |
/var/backups/klm-postgres |
~5 GB (3 weekly backups @ 1.3 GB) |
| Observability volumes | ~2.5 GB (Prometheus TSDB) |
| Wiki + nginx logs | < 100 MB |
Pilns 38 GB diska budžets, parasti 60-75% lietots pēc tīrīšanas.
Backup un Disaster Recovery¶
- PG backup: svētdienās 03:00 (
/opt/klm/backup_db.sh) - Cleanup: ik dienas 02:00, tur 21 dienu vai dzēš 0-baitu failus
- Plāns:
docs/DISASTER_RECOVERY.md
Saites uz dziļāku saturu¶
- Ops Runbook — alertu reakcijas
- VMD-VZD-LAD-LVM domain — kas ir kas Latvijas mežu pasaulē
apidocs— Swagger UI (jāautorizē JWT)