feat(share): Nur-Ansicht-Teilen-Link (live, optional PIN) + QR (v1.6.9)
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 31m39s

Neuer öffentlicher Teilen-Link für die aktuelle Lage — ohne Login nur zum
Ansehen, live aktualisiert. Optional mit 4–8-stelliger PIN geschützt.

- DB: Project.shareToken (unique) / sharePin (bcrypt) / shareEnabled + Migration
- API: POST/GET /api/projects/[id]/share (Verwaltung, Mandanten-Check, VIEWER blockiert),
  GET/POST /api/share/[token] (öffentlich, PIN-Prüfung, Rate-Limit gegen Brute-Force)
- Öffentliche Seite /view/[token]: PIN-Gate, read-only MapView, Socket-Live + 30s-Poll
- Teilen-Dialog im Werkzeuge-/Mobil-Menü: Link kopieren, QR-Code, PIN setzen/entfernen,
  Teilen beenden (widerruft den Link)
- Middleware: /api/share/ öffentlich freigeschaltet

Hinweis: hochgeladene Custom-Symbole zeigen im anonymen Viewer den Platzhalter
(Icon-Endpunkte bleiben auth-geschützt); eingebaute taktische Zeichen erscheinen normal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pepe Ziberi
2026-07-22 23:30:47 +02:00
parent eb5da2f0c3
commit 6aa70e1504
10 changed files with 630 additions and 1 deletions

View File

@@ -86,6 +86,11 @@ async function migrate() {
`ALTER TABLE tenants ADD COLUMN IF NOT EXISTS "modulesConfig" JSONB`,
// Windrichtung fürs Lagebild
`ALTER TABLE projects ADD COLUMN IF NOT EXISTS "windDirection" INTEGER`,
// Öffentlicher Nur-Ansicht-Teilen-Link (live, optional PIN)
`ALTER TABLE projects ADD COLUMN IF NOT EXISTS "shareToken" TEXT`,
`ALTER TABLE projects ADD COLUMN IF NOT EXISTS "sharePin" TEXT`,
`ALTER TABLE projects ADD COLUMN IF NOT EXISTS "shareEnabled" BOOLEAN NOT NULL DEFAULT false`,
`CREATE UNIQUE INDEX IF NOT EXISTS "projects_shareToken_key" ON projects ("shareToken")`,
]
let added = 0
for (const sql of columnMigrations) {

View File

@@ -175,6 +175,12 @@ model Project {
// neuere Änderungen stillschweigend überschreibt.
featuresVersion Int @default(0)
// Öffentlicher Nur-Ansicht-Teilen-Link (live). shareToken = zufälliger Slug im Link,
// sharePin = bcrypt-Hash einer optionalen PIN (NULL = keine PIN), shareEnabled = aktiv/aus.
shareToken String? @unique
sharePin String?
shareEnabled Boolean @default(false)
// Live editing lock (session-based for same-account multi-device)
editingById String?
editingUserName String?