feat: implement StaySense MVP backend, frontend, imports, and deployment docs
This commit is contained in:
commit
902988276c
24 changed files with 2536 additions and 0 deletions
102
docs/DEPLOYMENT.md
Normal file
102
docs/DEPLOYMENT.md
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
# StaySense Deployment Guide (Linux + Nginx)
|
||||
|
||||
## 1. Voraussetzungen
|
||||
|
||||
- Ubuntu/Debian Server mit sudo
|
||||
- Domain (optional, empfohlen)
|
||||
- Python 3.10+
|
||||
- Nginx
|
||||
- systemd
|
||||
|
||||
Install:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y python3 nginx
|
||||
```
|
||||
|
||||
## 2. Code bereitstellen
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/staysense
|
||||
sudo chown -R $USER:$USER /opt/staysense
|
||||
git clone <REPO_URL> /opt/staysense
|
||||
```
|
||||
|
||||
## 3. Initialisierung
|
||||
|
||||
```bash
|
||||
cd /opt/staysense/backend
|
||||
python3 -c "from db import init_db; init_db()"
|
||||
python3 import_osm_overpass.py
|
||||
python3 run_import_jobs.py --config ../docs/open_data_sources.json --prune-legacy
|
||||
```
|
||||
|
||||
## 4. API als Service starten
|
||||
|
||||
1. Service-Datei kopieren:
|
||||
|
||||
```bash
|
||||
sudo cp /opt/staysense/deploy/systemd/staysense-api.service /etc/systemd/system/
|
||||
```
|
||||
|
||||
2. Secret setzen (Datei anpassen):
|
||||
|
||||
```bash
|
||||
sudo nano /etc/systemd/system/staysense-api.service
|
||||
# STAYSENSE_SERVER_SALT=... setzen
|
||||
```
|
||||
|
||||
3. Aktivieren:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now staysense-api.service
|
||||
sudo systemctl status staysense-api.service
|
||||
```
|
||||
|
||||
## 5. Import-Timer aktivieren
|
||||
|
||||
```bash
|
||||
sudo cp /opt/staysense/deploy/systemd/staysense-import.service /etc/systemd/system/
|
||||
sudo cp /opt/staysense/deploy/systemd/staysense-import.timer /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now staysense-import.timer
|
||||
sudo systemctl list-timers | grep staysense
|
||||
```
|
||||
|
||||
## 6. Nginx konfigurieren
|
||||
|
||||
```bash
|
||||
sudo cp /opt/staysense/deploy/nginx/staysense.conf /etc/nginx/sites-available/staysense
|
||||
sudo ln -s /etc/nginx/sites-available/staysense /etc/nginx/sites-enabled/staysense
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
## 7. API-Route im Frontend anpassen
|
||||
|
||||
Fuer Reverse Proxy `/api` kann in `src/index.html` vor `app.js` gesetzt werden:
|
||||
|
||||
```html
|
||||
<script>
|
||||
window.STAYSENSE_API_BASE = "/api";
|
||||
</script>
|
||||
```
|
||||
|
||||
Danach Nginx reloaden.
|
||||
|
||||
## 8. HTTPS (empfohlen)
|
||||
|
||||
```bash
|
||||
sudo apt install -y certbot python3-certbot-nginx
|
||||
sudo certbot --nginx -d staysense.example.com
|
||||
```
|
||||
|
||||
## 9. Betrieb / Checks
|
||||
|
||||
```bash
|
||||
curl -s http://127.0.0.1:8787/health
|
||||
sudo journalctl -u staysense-api.service -f
|
||||
sudo journalctl -u staysense-import.service -n 100
|
||||
```
|
||||
27
docs/GITHUB_PUBLISH.md
Normal file
27
docs/GITHUB_PUBLISH.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# GitHub Publish Guide
|
||||
|
||||
## 1. Repository erstellen
|
||||
|
||||
- Neues GitHub Repo erstellen, z. B. `staysense-mvp`
|
||||
- Private oder Public nach Bedarf
|
||||
|
||||
## 2. Remote setzen
|
||||
|
||||
```bash
|
||||
cd StaySense
|
||||
git remote add origin git@github.com:<ORG_OR_USER>/<REPO>.git
|
||||
# alternativ HTTPS:
|
||||
# git remote add origin https://github.com/<ORG_OR_USER>/<REPO>.git
|
||||
```
|
||||
|
||||
## 3. Push
|
||||
|
||||
```bash
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
## 4. Empfohlene Repo-Settings
|
||||
|
||||
- Branch Protection fuer `main`
|
||||
- Issues/Projects aktivieren
|
||||
- Secrets fuer Deployment (falls CI/CD)
|
||||
79
docs/IMPLEMENTATION_PLAN.md
Normal file
79
docs/IMPLEMENTATION_PLAN.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# StaySense Umsetzungsplan (MVP NRW)
|
||||
|
||||
## Ziel
|
||||
|
||||
Entscheidung in <10 Sekunden: Ist ein Spot heute Nacht (22-06) voraussichtlich ruhig?
|
||||
|
||||
## Scope
|
||||
|
||||
- Region: NRW, Pilot Kreis Mettmann
|
||||
- Plattform im MVP: Web-App mit iOS-tauglichem Verhalten (Offline-Queue/Cache)
|
||||
- Kein Account-System
|
||||
|
||||
## Architektur
|
||||
|
||||
- Frontend: Vanilla HTML/CSS/JS (`src/`)
|
||||
- Backend: Python Standardbibliothek + SQLite (`backend/`)
|
||||
- Daten: `data/staysense.db`
|
||||
|
||||
## API (MVP)
|
||||
|
||||
- `GET /spot/score?lat=..&lon=..&at=ISO8601`
|
||||
- liefert `score`, `ampel`, `reasons`, `night_window`, `meta`
|
||||
- `POST /spot/signal`
|
||||
- Body: `spot_id`, `signal_type`, `device_token`, `timestamp`
|
||||
- erzwingt 1 Signal pro `(spot, device)` in 24h
|
||||
|
||||
## Datenpipeline
|
||||
|
||||
- OSM Import (Overpass):
|
||||
- Tabellen: `osm_poi`, `osm_zone`, `osm_road`
|
||||
- Script: `backend/import_osm_overpass.py`
|
||||
- OpenData Connector Layer:
|
||||
- Script: `backend/open_data_connector.py`
|
||||
- Konfig: `docs/open_data_sources.json`
|
||||
- Formate: CSV + JSON
|
||||
- Job Runner:
|
||||
- Script: `backend/run_import_jobs.py`
|
||||
- Modi: einmalig (`once`) oder periodisch (`daemon`)
|
||||
- Optionales Legacy-Pruning: `--prune-legacy`
|
||||
|
||||
## Datenmodell
|
||||
|
||||
- `spot`
|
||||
- Standortmetadaten inkl. OSM-Typ und Distanzmetriken
|
||||
- `community_signal`
|
||||
- Signale mit `hashed_device`, ohne PII
|
||||
- `open_data_event`
|
||||
- lokale Risiko-Ereignisse mit Zeitfenster
|
||||
- `data_source_state`
|
||||
- Importstand/Frische je Datenquelle
|
||||
|
||||
## Score Engine v0.1
|
||||
|
||||
- Startwert: `100`
|
||||
- Modifikatoren:
|
||||
- Umgebungstyp (z. B. residential -10, industrial +10)
|
||||
- Distanz zu Polizei/Krankenhaus
|
||||
- Zeitlogik (Wochenende/Feiertag -10, Werktagnacht +5)
|
||||
- lokale Events (z. B. Muellabfuhr -20)
|
||||
- Community-Signale mit Zeit-Decay (`calm`, `noise`, `knock`, `police`)
|
||||
- Ausgabe:
|
||||
- Score 0-100
|
||||
- Ampel
|
||||
- Top-2 bis Top-4 Gruende
|
||||
- Source-Health in `meta.health` (Freshness/Fallback-Info)
|
||||
|
||||
## Datenschutz / Sicherheit
|
||||
|
||||
- Local device token (UUIDv4) nur auf Client
|
||||
- Backend speichert nur HMAC-Hash
|
||||
- Kein Fingerprinting
|
||||
- Kein Login
|
||||
- HTTPS-only fuer Produktion
|
||||
|
||||
## Naechste Schritte
|
||||
|
||||
1. Reale NRW/Kommunal-URLs in `open_data_sources.json` aktivieren
|
||||
2. Health-Checks + Alerting fuer fehlgeschlagene Importjobs
|
||||
3. Postgres + PostGIS Migration
|
||||
41
docs/OPERATIONS.md
Normal file
41
docs/OPERATIONS.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# Operations Runbook
|
||||
|
||||
## Wichtige Befehle
|
||||
|
||||
API neu starten:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart staysense-api.service
|
||||
```
|
||||
|
||||
Import manuell ausfuehren:
|
||||
|
||||
```bash
|
||||
sudo systemctl start staysense-import.service
|
||||
```
|
||||
|
||||
Service-Logs:
|
||||
|
||||
```bash
|
||||
sudo journalctl -u staysense-api.service -f
|
||||
sudo journalctl -u staysense-import.service -f
|
||||
```
|
||||
|
||||
Health check:
|
||||
|
||||
```bash
|
||||
curl -s http://127.0.0.1:8787/health
|
||||
```
|
||||
|
||||
## Backup
|
||||
|
||||
```bash
|
||||
cp /opt/staysense/data/staysense.db /opt/staysense/data/staysense.db.bak
|
||||
```
|
||||
|
||||
## Restore
|
||||
|
||||
```bash
|
||||
cp /opt/staysense/data/staysense.db.bak /opt/staysense/data/staysense.db
|
||||
sudo systemctl restart staysense-api.service
|
||||
```
|
||||
3
docs/open_data_events_template.csv
Normal file
3
docs/open_data_events_template.csv
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
lat,lon,event_type,start_datetime,end_datetime,risk_modifier,source
|
||||
51.2502,6.9735,waste,2026-02-16T06:00:00Z,2026-02-16T08:00:00Z,-20,stadt_mettmann_abfall
|
||||
51.2960,6.8500,market,2026-02-16T05:30:00Z,2026-02-16T10:30:00Z,-12,stadt_ratingen_markt
|
||||
|
42
docs/open_data_sources.json
Normal file
42
docs/open_data_sources.json
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"sources": [
|
||||
{
|
||||
"id": "local_template_csv",
|
||||
"enabled": true,
|
||||
"format": "csv",
|
||||
"file": "open_data_events_template.csv",
|
||||
"source_name": "stadt_mettmann_template",
|
||||
"field_map": {
|
||||
"lat": "lat",
|
||||
"lon": "lon",
|
||||
"event_type": "event_type",
|
||||
"start_datetime": "start_datetime",
|
||||
"end_datetime": "end_datetime",
|
||||
"risk_modifier": "risk_modifier"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "nrw_portal_placeholder_json",
|
||||
"enabled": false,
|
||||
"format": "json",
|
||||
"url": "https://example-opendata.nrw.example/api/events.json",
|
||||
"json_path": "items",
|
||||
"source_name": "open_data_nrw",
|
||||
"field_map": {
|
||||
"external_id": "id",
|
||||
"lat": "latitude",
|
||||
"lon": "longitude",
|
||||
"event_type": "category",
|
||||
"start_datetime": "start",
|
||||
"end_datetime": "end",
|
||||
"risk_modifier": "risk"
|
||||
},
|
||||
"event_type_map": {
|
||||
"abfall": "waste",
|
||||
"markt": "market",
|
||||
"veranstaltung": "event",
|
||||
"baustelle": "construction"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue