Files
paliad/internal/handlers/glossary.go
m 460736ad1e refactor(t-paliad-092): rename Go module path patholo → paliad
F-6 from t-paliad-074 architecture audit. The Gitea repo was renamed
m/patholo → mAi/paliad → m/paliad, but go.mod still declared
`mgit.msbls.de/m/patholo` and every internal import echoed the
pre-rebrand name.

Sweep:
- go.mod: module path → mgit.msbls.de/m/paliad
- All *.go files: imports rewritten via sed
- README.md, docs/design-kanzlai-integration.md: mAi/paliad → m/paliad
- Frontend issue-reference comments (mAi/paliad#N → m/paliad#N) in
  i18n.ts, theme.ts, sidebar.ts, app.ts, Sidebar.tsx, PWAHead.tsx,
  global.css

Verified: go build/vet/test ./... clean, bun run build clean,
no remaining mgit.msbls.de/m/patholo or mAi/paliad references
outside docs that intentionally describe the rename history.
2026-04-30 16:46:31 +02:00

250 lines
21 KiB
Go

package handlers
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
"time"
"mgit.msbls.de/m/paliad/internal/auth"
)
type GlossaryTerm struct {
DE string `json:"de"`
EN string `json:"en"`
Definition string `json:"definition,omitempty"`
Category string `json:"category"`
}
type GlossarySuggestion struct {
TermDE string `json:"term_de"`
TermEN string `json:"term_en"`
Definition string `json:"definition,omitempty"`
Category string `json:"category"`
SuggestionType string `json:"suggestion_type"` // "new" or "correction"
ExistingTermDE string `json:"existing_term_de,omitempty"`
}
var glossaryTerms = []GlossaryTerm{
// --- Litigation ---
{DE: "Patentverletzung", EN: "Patent infringement", Definition: "Benutzung einer patentgeschützten Erfindung ohne Zustimmung des Patentinhabers.", Category: "Litigation"},
{DE: "Verletzungsklage", EN: "Infringement action", Definition: "Klage des Patentinhabers gegen den Verletzer auf Unterlassung, Schadensersatz und Auskunft.", Category: "Litigation"},
{DE: "Nichtigkeitsklage", EN: "Nullity action", Definition: "Klage auf Erklärung der Nichtigkeit eines Patents, z.\u202fB. wegen fehlender Neuheit oder erfinderischer Tätigkeit.", Category: "Litigation"},
{DE: "Unterlassungsanspruch", EN: "Injunctive relief", Definition: "Anspruch auf gerichtliches Verbot der weiteren Patentverletzung.", Category: "Litigation"},
{DE: "Schadensersatz", EN: "Damages", Definition: "Geldersatz für den durch die Patentverletzung entstandenen Schaden.", Category: "Litigation"},
{DE: "Streitwert", EN: "Amount in dispute", Definition: "Geschätzter Wert des Streitgegenstands, Grundlage für Gerichts- und Anwaltsgebühren.", Category: "Litigation"},
{DE: "Einstweilige Verfügung", EN: "Preliminary injunction", Definition: "Vorläufige gerichtliche Maßnahme zur sofortigen Unterbindung einer Patentverletzung.", Category: "Litigation"},
{DE: "Berufung", EN: "Appeal", Definition: "Rechtsmittel gegen ein Urteil der ersten Instanz.", Category: "Litigation"},
{DE: "Revision", EN: "Revision (appeal on points of law)", Definition: "Rechtsmittel zum BGH, beschränkt auf Rechtsfragen.", Category: "Litigation"},
{DE: "Prozesskostensicherheit", EN: "Security for costs", Definition: "Sicherheitsleistung für die Verfahrenskosten, die von ausländischen Klägern verlangt werden kann.", Category: "Litigation"},
{DE: "Aussetzung", EN: "Stay of proceedings", Definition: "Vorübergehende Unterbrechung des Verletzungsverfahrens, oft bis zur Entscheidung über die Nichtigkeit.", Category: "Litigation"},
{DE: "Widerklage", EN: "Counterclaim", Definition: "Klage des Beklagten gegen den Kläger im selben Verfahren.", Category: "Litigation"},
{DE: "Beweissicherung", EN: "Preservation of evidence", Definition: "Gerichtliche Anordnung zur Sicherung von Beweismitteln vor deren Vernichtung.", Category: "Litigation"},
{DE: "Beschwerde", EN: "Complaint / Appeal", Definition: "Rechtsbehelf gegen gerichtliche Entscheidungen, die kein Urteil sind.", Category: "Litigation"},
{DE: "Lizenzbereitschaftserklärung", EN: "Licence of right declaration", Definition: "Erklärung des Patentinhabers, jedem eine Lizenz zu angemessenen Bedingungen zu erteilen.", Category: "Litigation"},
{DE: "Merkmalsgliederung", EN: "Feature analysis / Claim breakdown", Definition: "Zerlegung des Patentanspruchs in einzelne Merkmale zur Prüfung der Verletzung.", Category: "Litigation"},
{DE: "Äquivalente Patentverletzung", EN: "Infringement by equivalents", Definition: "Verletzung durch eine Lösung, die dem Patentanspruch zwar nicht wortlautgemäß, aber funktional gleichwertig entspricht.", Category: "Litigation"},
{DE: "Auskunftsanspruch", EN: "Right to information / Disclosure order", Definition: "Anspruch auf Auskunft über Herkunft und Vertriebswege patentverletzender Erzeugnisse.", Category: "Litigation"},
{DE: "Rechnungslegung", EN: "Rendering of accounts", Definition: "Pflicht des Verletzers, über Umsätze und Gewinne aus der Verletzung Auskunft zu erteilen.", Category: "Litigation"},
{DE: "Vernichtungsanspruch", EN: "Destruction claim", Definition: "Anspruch auf Vernichtung patentverletzender Erzeugnisse.", Category: "Litigation"},
{DE: "Rückrufanspruch", EN: "Recall claim", Definition: "Anspruch auf Rückruf patentverletzender Produkte aus dem Vertriebsweg.", Category: "Litigation"},
{DE: "Abmahnung", EN: "Cease-and-desist letter", Definition: "Außergerichtliche Aufforderung an den Verletzer, die Verletzungshandlung einzustellen.", Category: "Litigation"},
{DE: "Unterlassungsvertragsstrafe", EN: "Contractual penalty for breach of injunction", Definition: "Vertragsstrafe bei Verstoß gegen eine strafbewehrte Unterlassungserklärung.", Category: "Litigation"},
// --- Prosecution ---
{DE: "Patentanmeldung", EN: "Patent application", Definition: "Antrag auf Erteilung eines Patents beim zuständigen Amt.", Category: "Prosecution"},
{DE: "Patentanspruch", EN: "Patent claim", Definition: "Definiert den Schutzbereich des Patents. Unterscheidung zwischen unabhängigen und abhängigen Ansprüchen.", Category: "Prosecution"},
{DE: "Priorität", EN: "Priority", Definition: "Recht, die Erstanmeldung als Zeitrang für Folgeanmeldungen in anderen Ländern zu nutzen (12 Monate).", Category: "Prosecution"},
{DE: "Offenlegung", EN: "Publication / Disclosure", Definition: "Veröffentlichung der Patentanmeldung, in der Regel 18 Monate nach Anmeldedatum.", Category: "Prosecution"},
{DE: "Erteilung", EN: "Grant", Definition: "Entscheidung des Patentamts, das Patent zu erteilen.", Category: "Prosecution"},
{DE: "Neuheit", EN: "Novelty", Definition: "Patentierbarkeitsvoraussetzung: Die Erfindung darf nicht zum Stand der Technik gehören.", Category: "Prosecution"},
{DE: "Erfinderische Tätigkeit", EN: "Inventive step", Definition: "Die Erfindung darf sich für den Fachmann nicht in naheliegender Weise aus dem Stand der Technik ergeben.", Category: "Prosecution"},
{DE: "Stand der Technik", EN: "Prior art", Definition: "Gesamtheit aller vor dem Anmeldetag öffentlich zugänglichen Informationen.", Category: "Prosecution"},
{DE: "Beschreibung", EN: "Description / Specification", Definition: "Teil der Patentanmeldung, der die Erfindung so offenbart, dass ein Fachmann sie nacharbeiten kann.", Category: "Prosecution"},
{DE: "Teilanmeldung", EN: "Divisional application", Definition: "Abspaltung eines Teils der ursprünglichen Anmeldung in eine eigene, neue Anmeldung.", Category: "Prosecution"},
{DE: "Gebrauchsmuster", EN: "Utility model", Definition: "Registriertes Schutzrecht für technische Erfindungen ohne Prüfung auf erfinderische Tätigkeit (nur DE).", Category: "Prosecution"},
{DE: "Schutzdauer", EN: "Term of protection", Definition: "Maximale Laufzeit eines Patents (20 Jahre ab Anmeldedatum bei Zahlung der Jahresgebühren).", Category: "Prosecution"},
{DE: "Jahresgebühr", EN: "Annual renewal fee", Definition: "Jährliche Gebühr zur Aufrechterhaltung des Patents.", Category: "Prosecution"},
// --- UPC ---
{DE: "Einheitliches Patentgericht", EN: "Unified Patent Court (UPC)", Definition: "Supranationales Gericht für Patentstreitigkeiten in teilnehmenden EU-Mitgliedstaaten.", Category: "UPC"},
{DE: "Einheitspatent", EN: "Unitary patent", Definition: "Europäisches Patent mit einheitlicher Wirkung in allen teilnehmenden EU-Staaten.", Category: "UPC"},
{DE: "Opt-out", EN: "Opt-out", Definition: "Erklärung, mit der ein europäisches Patent von der Zuständigkeit des UPC ausgenommen wird.", Category: "UPC"},
{DE: "Lokalkammer", EN: "Local division", Definition: "UPC-Kammer mit Sitz in einem teilnehmenden Mitgliedstaat für Verletzungsklagen.", Category: "UPC"},
{DE: "Zentralkammer", EN: "Central division", Definition: "UPC-Kammer in Paris und München für Nichtigkeitsklagen und bestimmte Verletzungsklagen.", Category: "UPC"},
{DE: "Berufungskammer", EN: "Court of Appeal", Definition: "UPC-Berufungsgericht mit Sitz in Luxemburg.", Category: "UPC"},
{DE: "Vertraulichkeitsklub", EN: "Confidentiality club", Definition: "Kreis von Personen, die Zugang zu vertraulichen Informationen im UPC-Verfahren erhalten.", Category: "UPC"},
{DE: "Verfahrenssprache", EN: "Language of proceedings", Definition: "Sprache, in der das UPC-Verfahren geführt wird (abhängig von Kammer und Parteivereinbarung).", Category: "UPC"},
{DE: "Bifurkation", EN: "Bifurcation", Definition: "Trennung von Verletzungs- und Nichtigkeitsverfahren vor verschiedenen Kammern.", Category: "UPC"},
{DE: "Vorläufige Maßnahmen", EN: "Provisional measures", Definition: "Einstweilige Anordnungen des UPC zur Sicherung von Ansprüchen vor dem Hauptverfahren.", Category: "UPC"},
{DE: "Schutzschrift", EN: "Protective letter", Definition: "Vorsorglich eingereichte Verteidigungsschrift gegen einen erwarteten Antrag auf einstweilige Maßnahmen.", Category: "UPC"},
{DE: "Übergangsphase", EN: "Transitional period", Definition: "Zeitraum, in dem bestehende europäische Patente noch von der UPC-Zuständigkeit ausgenommen werden können.", Category: "UPC"},
// --- EPA ---
{DE: "Einspruch", EN: "Opposition", Definition: "Anfechtung eines erteilten europäischen Patents vor dem EPA innerhalb von 9 Monaten nach Erteilung.", Category: "EPA"},
{DE: "Einspruchsabteilung", EN: "Opposition division", Definition: "Dreiköpfiges Gremium des EPA, das über Einsprüche entscheidet.", Category: "EPA"},
{DE: "Beschwerdekammer (EPA)", EN: "Board of Appeal", Definition: "Instanz des EPA für Beschwerden gegen Entscheidungen der Prüfungs- oder Einspruchsabteilung.", Category: "EPA"},
{DE: "Große Beschwerdekammer", EN: "Enlarged Board of Appeal", Definition: "Höchste Instanz des EPA für Rechtsfragen von grundlegender Bedeutung.", Category: "EPA"},
{DE: "Prüfungsabteilung", EN: "Examining division", Definition: "Abteilung des EPA, die Patentanmeldungen auf Patentierbarkeit prüft.", Category: "EPA"},
{DE: "Recherchenbericht", EN: "Search report", Definition: "Bericht des EPA über den für die Patentanmeldung relevanten Stand der Technik.", Category: "EPA"},
{DE: "Europäisches Patentübereinkommen", EN: "European Patent Convention (EPC)", Definition: "Völkerrechtlicher Vertrag, der das europäische Patentrecht und das EPA regelt.", Category: "EPA"},
{DE: "Benennungsstaaten", EN: "Designated states", Definition: "Staaten, für die Schutz aus einer europäischen Patentanmeldung beansprucht wird.", Category: "EPA"},
{DE: "Wiedereinsetzung", EN: "Re-establishment of rights", Definition: "Antrag auf Wiedereinsetzung in eine versäumte Deadline beim EPA.", Category: "EPA"},
{DE: "Weiterbehandlung", EN: "Further processing", Definition: "Verfahren zur Heilung einer Fristversäumnis beim EPA gegen Zahlung einer Gebühr.", Category: "EPA"},
{DE: "Beschränkungsverfahren", EN: "Limitation proceedings", Definition: "Verfahren zur nachträglichen Einschränkung der Patentansprüche eines erteilten europäischen Patents.", Category: "EPA"},
// --- General ---
{DE: "Patentinhaber", EN: "Patent proprietor / Patentee", Definition: "Person oder Unternehmen, dem das Patent gehört.", Category: "General"},
{DE: "Erfinder", EN: "Inventor", Definition: "Natürliche Person, die die technische Lehre des Patents entwickelt hat.", Category: "General"},
{DE: "Lizenz", EN: "Licence", Definition: "Vertragliche Erlaubnis zur Nutzung eines Patents.", Category: "General"},
{DE: "Zwangslizenz", EN: "Compulsory licence", Definition: "Vom Gericht oder Behörde erteilte Lizenz ohne Zustimmung des Patentinhabers.", Category: "General"},
{DE: "Schutzbereich", EN: "Scope of protection", Definition: "Durch die Patentansprüche definierter Umfang des Patentschutzes.", Category: "General"},
{DE: "Fachmann", EN: "Person skilled in the art", Definition: "Hypothetische Bezugsperson mit durchschnittlichem Fachwissen im relevanten Technikgebiet.", Category: "General"},
{DE: "Patentübertragung", EN: "Patent assignment", Definition: "Übertragung des Eigentums an einem Patent auf eine andere Person oder ein Unternehmen.", Category: "General"},
{DE: "Patentfamilie", EN: "Patent family", Definition: "Gesamtheit aller Patentanmeldungen und Patente, die auf dieselbe Priorität zurückgehen.", Category: "General"},
{DE: "Patentregister", EN: "Patent register", Definition: "Amtliches Verzeichnis aller erteilten Patente mit Angaben zu Inhaber, Status und Rechtsänderungen.", Category: "General"},
{DE: "Patentverletzungsgutachten", EN: "Freedom-to-operate opinion", Definition: "Rechtsgutachten zur Frage, ob ein Produkt oder Verfahren Patente Dritter verletzt.", Category: "General"},
{DE: "Ergänzendes Schutzzertifikat", EN: "Supplementary protection certificate (SPC)", Definition: "Zusätzlicher Schutz für Arzneimittel und Pflanzenschutzmittel nach Patentablauf (max. 5 Jahre).", Category: "General"},
{DE: "PCT-Anmeldung", EN: "PCT application", Definition: "Internationale Patentanmeldung nach dem Vertrag über die Internationale Zusammenarbeit auf dem Gebiet des Patentwesens.", Category: "General"},
{DE: "Schriftsatz", EN: "Written submission / Brief", Definition: "Formelles Schreiben an das Gericht oder Amt mit rechtlichem Vorbringen.", Category: "General"},
{DE: "Mündliche Verhandlung", EN: "Oral hearing / Oral proceedings", Definition: "Mündliche Anhörung vor Gericht oder dem EPA.", Category: "General"},
{DE: "Neuheitsschädlich", EN: "Novelty-destroying", Definition: "Eigenschaft einer Entgegenhaltung, die die Neuheit der beanspruchten Erfindung zerstört.", Category: "General"},
{DE: "Aufgabe-Lösungs-Ansatz", EN: "Problem-solution approach", Definition: "Vom EPA angewandte Methode zur Prüfung der erfinderischen Tätigkeit.", Category: "General"},
{DE: "Formstücke", EN: "Formal documents / Forms", Definition: "Standardformulare der Patentämter für Anträge und Mitteilungen.", Category: "General"},
// --- SEP/FRAND ---
{DE: "FRAND", EN: "FRAND", Definition: "Fair, Reasonable and Non-Discriminatory \u2014 Lizenzbedingungen, zu denen sich SEP-Inhaber gegenüber Standardisierungsorganisationen verpflichten.", Category: "SEP/FRAND"},
{DE: "SEP", EN: "SEP", Definition: "Standard Essential Patent \u2014 ein Patent, dessen Nutzung zur Umsetzung eines technischen Standards zwingend erforderlich ist.", Category: "SEP/FRAND"},
{DE: "Standard-essentielles Patent", EN: "Standard-essential patent", Definition: "Deutsche Bezeichnung für ein SEP; ein Patent, das gegenüber einer Standardisierungsorganisation (z.\u202fB. ETSI) als essentiell deklariert wurde.", Category: "SEP/FRAND"},
{DE: "Patentpool", EN: "Patent pool", Definition: "Zusammenschluss mehrerer SEP-Inhaber, die ihre Patente über einen Administrator (z.\u202fB. Avanci, Sisvel) gebündelt lizenzieren.", Category: "SEP/FRAND"},
{DE: "Anti-Suit Injunction", EN: "Anti-suit injunction (ASI)", Definition: "Gerichtliche Anordnung, die einer Party verbietet, ein paralleles Verfahren vor einem anderen Gericht zu führen \u2014 in SEP-Streitigkeiten insbesondere aus den USA und UK bekannt.", Category: "SEP/FRAND"},
{DE: "Anti-Anti-Suit Injunction", EN: "Anti-anti-suit injunction (AASI)", Definition: "Gegenanordnung, die einer Party untersagt, eine Anti-Suit Injunction zu beantragen oder durchzusetzen \u2014 von deutschen Gerichten (München I, Düsseldorf) als Verteidigung etabliert.", Category: "SEP/FRAND"},
{DE: "Injunction Gap", EN: "Injunction gap", Definition: "Zeitraum zwischen dem Verletzungsurteil eines deutschen Gerichts und der Entscheidung des BPatG über den Rechtsbestand \u2014 umstritten, da SEP-Inhaber Unterlassung durchsetzen können, bevor das Patent auf Nichtigkeit überprüft ist.", Category: "SEP/FRAND"},
{DE: "Orange-Book-Standard", EN: "Orange-Book-Standard", Definition: "BGH-Leitentscheidung (KZR 39/06, 2009) zum kartellrechtlichen Zwangslizenzeinwand im SEP-Kontext; überholt durch Huawei/ZTE (EuGH 2015), aber weiterhin zitiert.", Category: "SEP/FRAND"},
{DE: "Huawei/ZTE-Verhandlungsmuster", EN: "Huawei/ZTE negotiation framework", Definition: "EuGH-Urteil C-170/13 (2015): Schrittweises Verhandlungsmuster (Verletzungshinweis, Lizenzangebot des SEP-Inhabers, FRAND-konformes Gegenangebot des Verletzers, Rechnungslegung), das vor Unterlassungsanträgen einzuhalten ist.", Category: "SEP/FRAND"},
{DE: "RAND", EN: "RAND", Definition: "Reasonable and Non-Discriminatory \u2014 US-amerikanische Entsprechung zu FRAND; in ANSI-Kontexten gebräuchlich.", Category: "SEP/FRAND"},
{DE: "ETSI IPR Policy", EN: "ETSI IPR Policy", Definition: "Regelwerk des European Telecommunications Standards Institute zu Offenlegungs- und FRAND-Lizenzverpflichtungen von SEP-Inhabern (insb. Clause 6.1).", Category: "SEP/FRAND"},
{DE: "Patent-Hold-up", EN: "Patent hold-up", Definition: "Missbrauchsvorwurf gegen SEP-Inhaber, die nach der Standardisierung überhöhte Lizenzgebühren verlangen oder Unterlassung drohen, um Implementierer unter Druck zu setzen.", Category: "SEP/FRAND"},
{DE: "Patent-Hold-out", EN: "Patent hold-out", Definition: "Gegenstück zum Hold-up: Implementierer verzögern oder verweigern Lizenzverhandlungen und nutzen die Standardtechnologie ohne Lizenz (\"efficient infringement\").", Category: "SEP/FRAND"},
}
func handleGlossaryPage(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "dist/glossary.html")
}
func handleGlossaryAPI(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, glossaryTerms)
}
func handleGlossarySuggest(w http.ResponseWriter, r *http.Request) {
var suggestion GlossarySuggestion
if err := json.NewDecoder(r.Body).Decode(&suggestion); err != nil {
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Ungültige Anfrage."})
return
}
suggestion.TermDE = strings.TrimSpace(suggestion.TermDE)
suggestion.TermEN = strings.TrimSpace(suggestion.TermEN)
suggestion.Definition = strings.TrimSpace(suggestion.Definition)
suggestion.Category = strings.TrimSpace(suggestion.Category)
suggestion.SuggestionType = strings.TrimSpace(suggestion.SuggestionType)
suggestion.ExistingTermDE = strings.TrimSpace(suggestion.ExistingTermDE)
if suggestion.TermDE == "" || suggestion.TermEN == "" || suggestion.Category == "" {
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "Felder term_de, term_en und category sind erforderlich."})
return
}
if suggestion.SuggestionType == "" {
suggestion.SuggestionType = "new"
}
if suggestion.SuggestionType != "new" && suggestion.SuggestionType != "correction" {
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "suggestion_type muss 'new' oder 'correction' sein."})
return
}
// Get user's access token for authenticated Supabase request
accessToken := ""
email := ""
if cookie, err := r.Cookie(auth.SessionCookieName); err == nil {
accessToken = cookie.Value
email = extractEmailFromJWT(cookie.Value)
}
payload := map[string]string{
"term_de": suggestion.TermDE,
"term_en": suggestion.TermEN,
"definition": suggestion.Definition,
"category": suggestion.Category,
"suggestion_type": suggestion.SuggestionType,
"existing_term_de": suggestion.ExistingTermDE,
"submitted_by": email,
}
jsonBody, err := json.Marshal(payload)
if err != nil {
log.Printf("glossar suggest marshal error: %v", err)
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "Interner Fehler."})
return
}
// Legacy table in shared public schema (pre-paliad migration era);
// the German name is the actual table name and not subject to the
// codebase rename.
endpoint := fmt.Sprintf("%s/rest/v1/glossar_suggestions", authClient.URL)
req2, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonBody))
if err != nil {
log.Printf("glossar suggest request error: %v", err)
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "Interner Fehler."})
return
}
req2.Header.Set("Content-Type", "application/json")
req2.Header.Set("apikey", authClient.AnonKey)
if accessToken != "" {
req2.Header.Set("Authorization", "Bearer "+accessToken)
} else {
req2.Header.Set("Authorization", "Bearer "+authClient.AnonKey)
}
req2.Header.Set("Prefer", "return=minimal")
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Do(req2)
if err != nil {
log.Printf("glossar suggest supabase error: %v", err)
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "Fehler beim Speichern."})
return
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
body, _ := io.ReadAll(resp.Body)
log.Printf("glossar suggest supabase status %d: %s", resp.StatusCode, string(body))
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "Fehler beim Speichern."})
return
}
writeJSON(w, http.StatusCreated, map[string]string{"ok": "true"})
}
func extractEmailFromJWT(token string) string {
parts := strings.Split(token, ".")
if len(parts) != 3 {
return ""
}
decoded, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return ""
}
var claims struct {
Email string `json:"email"`
}
if err := json.Unmarshal(decoded, &claims); err != nil {
return ""
}
return claims.Email
}