first commit

This commit is contained in:
2026-07-16 09:35:32 +02:00
commit dd0746e2e6
179 changed files with 25679 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
# Dev-Setup & Live-Verifikation
## Voraussetzungen
- Node ≥ 20, pnpm 10
- Eine laufende MariaDB/MySQL (lokal reicht)
## 1. Dependencies
```bash
pnpm install
```
## 2. .env konfigurieren
`.env` im Repo-Root (aus `.env.example` kopieren) und die DB-Zugangsdaten setzen.
**Wichtig:** eine DEDIZIERTE Test-DB nutzen, NICHT die echte QBox-DB:
```dotenv
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASSWORD=DEIN_MARIADB_PASSWORT
DB_NAME=d4rk_mdt_dev # isolierte Test-DB — wird automatisch angelegt
VITE_DEV_AUTH_BYPASS=true # Browser-Login im Dev umgehen (Mock-Officer)
```
## 3. Test-DB anlegen + seeden
```bash
pnpm db:setup:dev
```
Das Script (idempotent, non-destruktiv):
1. legt die DB `d4rk_mdt_dev` an (falls nicht vorhanden),
2. erstellt QBox-Stand-in-Tabellen `players` / `player_vehicles`,
3. spielt die `mdt_*`-Migrationen ein,
4. seedet 3 Test-Bürger, 3 Fahrzeuge, 3 Strafen.
Erwartete Ausgabe endet mit: `[setup-dev] Seed abgeschlossen ✅`
## 4. Starten
```bash
pnpm dev # api :3000 + web :5173 (Turborepo, parallel)
```
Browser: http://localhost:5190
## 5. Verifizieren (Testdaten)
- **Personen** → Suche `Max` oder `Erika` → Detail öffnen (Job, Lizenzen, Notizen speichern, Fahndung togglen)
- **Fahrzeuge** → Kennzeichen `COP 007` oder `MAX 001` → „Als gestohlen markieren"
## Gegen die echte QBox-DB (später, produktiv)
`DB_NAME` auf die echte QBox-DB zeigen und **nur** die Migrationen einspielen
(erzeugt ausschließlich `mdt_*`-Tabellen, fasst QBox-Tabellen nie an):
```bash
pnpm db:migrate
```
`pnpm db:setup:dev` dort NICHT ausführen (das legt QBox-Stand-in-Tabellen + Testdaten an).
+64
View File
@@ -0,0 +1,64 @@
# FiveM-Bridge — Setup
Die Bridge (`fivem-bridge/`) verbindet das Ingame-Tablet mit dem MDT-Backend/Web.
Sie ist bewusst minimal: Token holen · Web-App im NUI-iframe öffnen · Dienst/Positionen
pushen · Waypoint setzen. Die eigentliche MDT-Logik lebt im Backend/Web.
## Architektur
```
Cop drückt Taste
→ Client holt Token vom Bridge-Server (lib.callback)
→ Bridge-Server ruft Backend POST /auth/fivem (Header x-bridge-secret)
← { token, user }
→ Client öffnet NUI-Shell (nui/index.html) mit <iframe src=WebUrl>
→ Shell postMessaged { action:'auth', token, user } ins iframe
→ Web-App ist eingeloggt
Server-Thread (nur im Dienst): GetEntityCoords → POST /bridge/officer/position
Dienstwechsel: POST /bridge/officer/duty
Andere Resource: exports.d4rk_tablet:createDispatch(...) → POST /bridge/dispatch
```
## Voraussetzungen
- `qbx_core`, `ox_lib`
- MDT-**Backend** erreichbar (Node, siehe [dev-setup.md](dev-setup.md))
- MDT-**Web-App** gehostet und erreichbar (der Build mit korrekten `VITE_API_URL`/`VITE_SOCKET_URL`, und **`VITE_DEV_AUTH_BYPASS=false`**!)
## server.cfg
```cfg
# MDT-Bridge
set mdt:backendUrl "https://mdt-api.deinserver.de" # Backend-Basis-URL (server→server)
set mdt:webUrl "https://mdt.deinserver.de" # gehostete Web-App (im iframe)
set mdt:bridgeSecret "<langes-zufalls-geheimnis>" # == BRIDGE_HMAC_SECRET im Backend!
set mdt:openCommand "mdt"
ensure d4rk_tablet # bzw. der Ordnername der Bridge-Resource
```
Wichtig:
- `mdt:bridgeSecret` **muss** `BRIDGE_HMAC_SECRET` in der Backend-`.env` entsprechen.
- Backend-`CORS_ORIGINS` muss die `mdt:webUrl`-Origin enthalten (das iframe fetcht cross-origin).
## Nutzung
- Taste/Command (`mdt`) öffnet das Tablet. Nur Jobs aus `Config.JobDepartments` bekommen Zugriff.
- `ESC` schließt es (oder Logout in der Web-App → `mdt:close`).
- **Dienst**: `/mdtduty` toggelt (oder QBox-`SetDuty`-Event). Nur im Dienst wird die Position gepusht → erscheint auf der Leitstellen-Karte.
- **Dispatch aus anderer Resource**:
```lua
exports.d4rk_tablet:createDispatch({
code = '10-90', title = 'Banküberfall', department = 'police',
priority = 'high', location = 'Pacific Standard',
coords = { x = 235.0, y = 216.0, z = 106.0 },
})
```
## Sicherheit
- Bridge↔Backend: Shared-Secret-Header `x-bridge-secret` (server-zu-server). Alternativ HMAC
(`x-mdt-timestamp` + `x-mdt-signature`) — das Backend akzeptiert beides.
- Positionen werden **server-seitig** via `GetEntityCoords` ermittelt (kein Vertrauen in Client-Coords).
- Der JWT-Token wird nur per `postMessage` an das iframe übergeben (nicht in der URL).
## Verifiziert
Backend-Contract per curl getestet: `/auth/fivem` (Secret → Token+User), `/bridge/officer/duty|position`,
`/bridge/dispatch` (Secret → 200, falsches/kein Secret → 401). Der Lua-Teil braucht einen laufenden
FiveM-Server zum Live-Test.