From 1bfbd53062c85c9508652c7888b203e79106a335 Mon Sep 17 00:00:00 2001 From: AliceDarkest Date: Tue, 21 Jul 2026 00:37:38 +0200 Subject: [PATCH] AP6 DSGVO: Footer-Rollout, Datenschutz/Impressum, Datenexport, NeuralTest-Entfernung MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Footer-Fragment (fragments/layout :: footer) ueberall ausgerollt: 24 duplizierte Inline-Footer ersetzt, 11 bisher footerlose Seiten (Fehler-/Auth-Seiten + 8 Spielseiten) ergaenzt -> Rechtslinks von jeder Seite erreichbar. Support/Feedback von href="#" auf mailto-Platzhalter umgestellt. - Datenschutzerklaerung vervollstaendigt: NeuralNet-Messaging als Verarbeitungs- taetigkeit (Inhalte, Sender/Empfaenger, Lesebestaetigung, Loeschung via Kaskade), E-Mail-Token (SHA-256, 24h) + SMTP ueber mail.sysnaptik.de, konkrete Speicher- fristen, korrekte Drittland-/CDN-Aussage. - Impressum strukturiert: Pflichtfelder nach § 5 DDG (Name, Anschrift, Vertretung, Kontakt, MStV) als auffaellige Platzhalter (--warn). - Datenexport (Art. 20): GET /profile/export -> ProfileExportService sammelt Stammdaten, Scores, Achievements und NeuralNet-Daten (ohne Passwort) als JSON-Download; drei Repo-Query-Methoden ergaenzt. - V22-Migration: Demo-User NeuralTest entfernt (NeuralNet-Daten per Kaskade). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01WFxcjtc9HNP4VECT6Ur1tE --- .../controller/ProfileController.java | 18 +++ .../repository/GameScoreRepository.java | 3 + .../NeuralNetConnectionRepository.java | 2 + .../NeuralNetMessageRepository.java | 2 + .../service/ProfileExportService.java | 114 ++++++++++++++++++ .../V22__remove_neuraltest_demo_user.sql | 14 +++ .../resources/templates/achievements.html | 9 +- .../resources/templates/admin/dashboard.html | 9 +- .../templates/admin/devlab-game.html | 6 +- .../resources/templates/admin/devlab.html | 6 +- .../resources/templates/admin/mindmatch.html | 9 +- .../templates/admin/syntaxsaga-mission.html | 9 +- .../resources/templates/admin/syntaxsaga.html | 9 +- .../templates/admin/techtacular-category.html | 9 +- .../templates/admin/techtacular.html | 9 +- .../resources/templates/admin/users/form.html | 9 +- .../resources/templates/admin/users/list.html | 9 +- src/main/resources/templates/bughunter.html | 3 +- src/main/resources/templates/codeescape.html | 3 +- src/main/resources/templates/dashboard.html | 9 +- src/main/resources/templates/devlab-game.html | 1 + src/main/resources/templates/devlab.html | 9 +- src/main/resources/templates/error.html | 1 + src/main/resources/templates/finalflux.html | 11 +- .../resources/templates/forgot-password.html | 1 + .../resources/templates/fragments/layout.html | 4 +- src/main/resources/templates/impressum.html | 41 ++++--- src/main/resources/templates/index.html | 9 +- src/main/resources/templates/knowledge.html | 2 +- .../templates/legal/datenschutz.html | 38 +++--- .../templates/legal/nutzungsbedingungen.html | 9 +- .../templates/legal/richtlinien.html | 9 +- src/main/resources/templates/mindmatch.html | 1 + src/main/resources/templates/networker.html | 3 +- src/main/resources/templates/profile.html | 9 +- src/main/resources/templates/progress.html | 9 +- .../resources/templates/reset-password.html | 1 + .../resources/templates/serviceclash.html | 3 +- src/main/resources/templates/settings.html | 9 +- src/main/resources/templates/soziales.html | 2 +- src/main/resources/templates/syntaxsaga.html | 1 + src/main/resources/templates/techtacular.html | 1 + 42 files changed, 238 insertions(+), 197 deletions(-) create mode 100644 src/main/java/com/example/mindflux/service/ProfileExportService.java create mode 100644 src/main/resources/db/migration/V22__remove_neuraltest_demo_user.sql diff --git a/src/main/java/com/example/mindflux/controller/ProfileController.java b/src/main/java/com/example/mindflux/controller/ProfileController.java index 64767c2..c3f0d6b 100644 --- a/src/main/java/com/example/mindflux/controller/ProfileController.java +++ b/src/main/java/com/example/mindflux/controller/ProfileController.java @@ -19,8 +19,13 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.security.Principal; import java.util.List; +import java.util.Map; import com.example.mindflux.dto.WeeklyActivity; import com.example.mindflux.service.AvatarService; +import com.example.mindflux.service.ProfileExportService; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; @Controller public class ProfileController { @@ -39,6 +44,9 @@ public class ProfileController { @Autowired private AvatarService avatarService; + @Autowired + private ProfileExportService profileExportService; + @GetMapping("/profile") public String profile(Model model, Principal principal, @RequestParam(value = "success", required = false) Boolean success) { String username = principal.getName(); @@ -73,6 +81,16 @@ public class ProfileController { return "settings"; } + /** DSGVO-Datenexport (Art. 20): alle Kontodaten als JSON-Download. */ + @GetMapping("/profile/export") + public ResponseEntity> exportData(Principal principal) { + Map data = profileExportService.export(principal.getName()); + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"mindflux-datenexport.json\"") + .contentType(MediaType.APPLICATION_JSON) + .body(data); + } + @GetMapping("/profile/knowledge") public String knowledgeCenter(Model model, Principal principal) { String username = principal.getName(); diff --git a/src/main/java/com/example/mindflux/repository/GameScoreRepository.java b/src/main/java/com/example/mindflux/repository/GameScoreRepository.java index 6a60057..a2a947f 100644 --- a/src/main/java/com/example/mindflux/repository/GameScoreRepository.java +++ b/src/main/java/com/example/mindflux/repository/GameScoreRepository.java @@ -27,6 +27,9 @@ public interface GameScoreRepository extends JpaRepository { /** Alle Spielstände eines Spielers löschen (z. B. beim Löschen des Kontos). */ void deleteByUsername(String username); + /** Alle Spielstände eines Spielers (für den DSGVO-Datenexport). */ + List findByUsernameOrderByPlayedAtDesc(String username); + /** Gesamtsumme aller Scores eines Spielers (XP-Basis). */ @Query("select coalesce(sum(g.score), 0) from GameScore g where g.username = :username") long sumScoreByUsername(@Param("username") String username); diff --git a/src/main/java/com/example/mindflux/repository/NeuralNetConnectionRepository.java b/src/main/java/com/example/mindflux/repository/NeuralNetConnectionRepository.java index 75a0a40..242bee6 100644 --- a/src/main/java/com/example/mindflux/repository/NeuralNetConnectionRepository.java +++ b/src/main/java/com/example/mindflux/repository/NeuralNetConnectionRepository.java @@ -11,4 +11,6 @@ public interface NeuralNetConnectionRepository extends JpaRepository acceptedFor(@Param("username") String username); @Query("select c from NeuralNetConnection c where c.status='ACCEPTED' and ((c.requester=:a and c.addressee=:b) or (c.requester=:b and c.addressee=:a))") Optional acceptedBetween(@Param("a") String a, @Param("b") String b); + @Query("select c from NeuralNetConnection c where c.requester=:u or c.addressee=:u order by c.createdAt asc") + List findAllInvolving(@Param("u") String u); } diff --git a/src/main/java/com/example/mindflux/repository/NeuralNetMessageRepository.java b/src/main/java/com/example/mindflux/repository/NeuralNetMessageRepository.java index f56ae64..96a260a 100644 --- a/src/main/java/com/example/mindflux/repository/NeuralNetMessageRepository.java +++ b/src/main/java/com/example/mindflux/repository/NeuralNetMessageRepository.java @@ -7,4 +7,6 @@ public interface NeuralNetMessageRepository extends JpaRepository conversation(@Param("a") String a, @Param("b") String b); long countByRecipientAndReadAtIsNull(String recipient); + @Query("select m from NeuralNetMessage m where m.sender=:u or m.recipient=:u order by m.sentAt asc") + List findAllInvolving(@Param("u") String u); } diff --git a/src/main/java/com/example/mindflux/service/ProfileExportService.java b/src/main/java/com/example/mindflux/service/ProfileExportService.java new file mode 100644 index 0000000..aa9a59a --- /dev/null +++ b/src/main/java/com/example/mindflux/service/ProfileExportService.java @@ -0,0 +1,114 @@ +package com.example.mindflux.service; + +import com.example.mindflux.model.Achievement; +import com.example.mindflux.model.GameScore; +import com.example.mindflux.model.NeuralNetConnection; +import com.example.mindflux.model.NeuralNetMessage; +import com.example.mindflux.model.User; +import com.example.mindflux.repository.AchievementRepository; +import com.example.mindflux.repository.GameScoreRepository; +import com.example.mindflux.repository.NeuralNetConnectionRepository; +import com.example.mindflux.repository.NeuralNetMessageRepository; +import com.example.mindflux.repository.NeuralNetPrivacyRepository; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Sammelt alle personenbezogenen Daten eines Kontos für den DSGVO-Datenexport + * (Art. 20 – Datenübertragbarkeit). Bewusst OHNE das Passwort-Hash; nur Daten, + * die die betroffene Person selbst erzeugt hat. + */ +@Service +public class ProfileExportService { + + private final UserService userService; + private final GameScoreRepository scores; + private final AchievementRepository achievements; + private final NeuralNetPrivacyRepository privacy; + private final NeuralNetConnectionRepository connections; + private final NeuralNetMessageRepository messages; + + public ProfileExportService(UserService userService, GameScoreRepository scores, + AchievementRepository achievements, NeuralNetPrivacyRepository privacy, + NeuralNetConnectionRepository connections, NeuralNetMessageRepository messages) { + this.userService = userService; + this.scores = scores; + this.achievements = achievements; + this.privacy = privacy; + this.connections = connections; + this.messages = messages; + } + + public Map export(String username) { + Map out = new LinkedHashMap<>(); + out.put("exportiertAm", LocalDateTime.now().toString()); + out.put("hinweis", "DSGVO-Datenexport (Art. 20). Enthält alle zu diesem Konto gespeicherten " + + "personenbezogenen Daten außer dem Passwort-Hash."); + + User user = userService.findByUsername(username); + Map account = new LinkedHashMap<>(); + if (user != null) { + account.put("benutzername", user.getUsername()); + account.put("email", user.getEmail()); + account.put("rolle", user.getRole()); + account.put("emailBestaetigt", user.isEmailVerified()); + account.put("hatProfilbild", user.getProfilePicture() != null && !user.getProfilePicture().isBlank()); + } + out.put("konto", account); + + List> scoreList = new ArrayList<>(); + for (GameScore s : scores.findByUsernameOrderByPlayedAtDesc(username)) { + Map m = new LinkedHashMap<>(); + m.put("spiel", s.getGame()); + m.put("deck", s.getDeck()); + m.put("punkte", s.getScore()); + m.put("zuege", s.getMoves()); + m.put("dauerSekunden", s.getDurationSeconds()); + m.put("gespieltAm", s.getPlayedAt() != null ? s.getPlayedAt().toString() : null); + scoreList.add(m); + } + out.put("spielstaende", scoreList); + + List> achievementList = new ArrayList<>(); + for (Achievement a : achievements.findByUsername(username)) { + Map m = new LinkedHashMap<>(); + m.put("titel", a.getTitle()); + m.put("beschreibung", a.getDescription()); + m.put("erreichtAm", a.getDateAchieved() != null ? a.getDateAchieved().toString() : null); + achievementList.add(m); + } + out.put("erfolge", achievementList); + + Map neural = new LinkedHashMap<>(); + neural.put("nachrichtenAktiviert", privacy.findById(username).map(p -> p.isEnabled()).orElse(false)); + List> connList = new ArrayList<>(); + for (NeuralNetConnection c : connections.findAllInvolving(username)) { + Map m = new LinkedHashMap<>(); + m.put("anfragender", c.getRequester()); + m.put("empfaenger", c.getAddressee()); + m.put("status", c.getStatus()); + m.put("erstelltAm", c.getCreatedAt() != null ? c.getCreatedAt().toString() : null); + connList.add(m); + } + neural.put("verbindungen", connList); + List> msgList = new ArrayList<>(); + for (NeuralNetMessage msg : messages.findAllInvolving(username)) { + Map m = new LinkedHashMap<>(); + m.put("von", msg.getSender()); + m.put("an", msg.getRecipient()); + m.put("text", msg.getBody()); + m.put("gesendetAm", msg.getSentAt() != null ? msg.getSentAt().toString() : null); + m.put("gelesen", msg.getReadAt() != null); + msgList.add(m); + } + neural.put("nachrichten", msgList); + out.put("neuralNet", neural); + + return out; + } +} diff --git a/src/main/resources/db/migration/V22__remove_neuraltest_demo_user.sql b/src/main/resources/db/migration/V22__remove_neuraltest_demo_user.sql new file mode 100644 index 0000000..aac15b4 --- /dev/null +++ b/src/main/resources/db/migration/V22__remove_neuraltest_demo_user.sql @@ -0,0 +1,14 @@ +-- V22: Entfernt das Demo-/Testkonto "NeuralTest" (per V17 fuer den NeuralNet-Flow +-- geseedet) aus produktiven Datenbanken. Ein klar erkennbares Testkonto gehoert +-- nicht in Produktion. +-- +-- Die NeuralNet-Tabellen (neuralnet_privacy, neuralnet_connections, neuralnet_messages) +-- referenzieren users(username) mit ON DELETE CASCADE und werden beim Loeschen des +-- Kontos automatisch mitgeraeumt. game_scores hat keinen Fremdschluessel, daher wird +-- ein evtl. vorhandener Spielstand des Demo-Kontos defensiv vorab entfernt. +-- +-- Wird das Konto fuer die lokale Entwicklung gebraucht, sollte es ueber einen +-- @Profile("dev")-gebundenen Runner neu angelegt werden, nicht per Migration. + +DELETE FROM game_scores WHERE username = 'NeuralTest'; +DELETE FROM users WHERE username = 'NeuralTest'; diff --git a/src/main/resources/templates/achievements.html b/src/main/resources/templates/achievements.html index 3eae94a..252398a 100644 --- a/src/main/resources/templates/achievements.html +++ b/src/main/resources/templates/achievements.html @@ -60,14 +60,7 @@ - +
diff --git a/src/main/resources/templates/admin/dashboard.html b/src/main/resources/templates/admin/dashboard.html index dfd5706..16ebacb 100644 --- a/src/main/resources/templates/admin/dashboard.html +++ b/src/main/resources/templates/admin/dashboard.html @@ -59,14 +59,7 @@ - +
diff --git a/src/main/resources/templates/admin/devlab-game.html b/src/main/resources/templates/admin/devlab-game.html index 0be18b8..3119226 100644 --- a/src/main/resources/templates/admin/devlab-game.html +++ b/src/main/resources/templates/admin/devlab-game.html @@ -99,10 +99,6 @@ - +
diff --git a/src/main/resources/templates/admin/devlab.html b/src/main/resources/templates/admin/devlab.html index 64f43d0..93a214d 100644 --- a/src/main/resources/templates/admin/devlab.html +++ b/src/main/resources/templates/admin/devlab.html @@ -87,10 +87,6 @@

Noch keine Spiele. Lege oben das erste an.

- +
diff --git a/src/main/resources/templates/admin/mindmatch.html b/src/main/resources/templates/admin/mindmatch.html index 44a5439..cca597b 100644 --- a/src/main/resources/templates/admin/mindmatch.html +++ b/src/main/resources/templates/admin/mindmatch.html @@ -122,14 +122,7 @@ - +
diff --git a/src/main/resources/templates/admin/syntaxsaga-mission.html b/src/main/resources/templates/admin/syntaxsaga-mission.html index c693aec..e40f01f 100644 --- a/src/main/resources/templates/admin/syntaxsaga-mission.html +++ b/src/main/resources/templates/admin/syntaxsaga-mission.html @@ -164,14 +164,7 @@ - +
diff --git a/src/main/resources/templates/admin/syntaxsaga.html b/src/main/resources/templates/admin/syntaxsaga.html index 3c4da1f..7d06777 100644 --- a/src/main/resources/templates/admin/syntaxsaga.html +++ b/src/main/resources/templates/admin/syntaxsaga.html @@ -127,14 +127,7 @@ - +
diff --git a/src/main/resources/templates/admin/techtacular-category.html b/src/main/resources/templates/admin/techtacular-category.html index c9b3822..7ddd982 100644 --- a/src/main/resources/templates/admin/techtacular-category.html +++ b/src/main/resources/templates/admin/techtacular-category.html @@ -126,14 +126,7 @@ - +
diff --git a/src/main/resources/templates/admin/techtacular.html b/src/main/resources/templates/admin/techtacular.html index e416edc..c1c5240 100644 --- a/src/main/resources/templates/admin/techtacular.html +++ b/src/main/resources/templates/admin/techtacular.html @@ -83,14 +83,7 @@ - +
diff --git a/src/main/resources/templates/admin/users/form.html b/src/main/resources/templates/admin/users/form.html index 90481fb..c88eccb 100644 --- a/src/main/resources/templates/admin/users/form.html +++ b/src/main/resources/templates/admin/users/form.html @@ -55,14 +55,7 @@ - +
diff --git a/src/main/resources/templates/admin/users/list.html b/src/main/resources/templates/admin/users/list.html index 582d2a6..54722e2 100644 --- a/src/main/resources/templates/admin/users/list.html +++ b/src/main/resources/templates/admin/users/list.html @@ -66,14 +66,7 @@ - +
diff --git a/src/main/resources/templates/bughunter.html b/src/main/resources/templates/bughunter.html index b872a4c..cff6c1d 100644 --- a/src/main/resources/templates/bughunter.html +++ b/src/main/resources/templates/bughunter.html @@ -1 +1,2 @@ -BugHunter · SysnaptiK Neural
BUGHUNTERDEBUG-FALLAKTEN
FALLAKTEN WERDEN GEÖFFNET …
+BugHunter · SysnaptiK Neural
BUGHUNTERDEBUG-FALLAKTEN
FALLAKTEN WERDEN GEÖFFNET …
+ diff --git a/src/main/resources/templates/codeescape.html b/src/main/resources/templates/codeescape.html index 8212859..f566f5e 100644 --- a/src/main/resources/templates/codeescape.html +++ b/src/main/resources/templates/codeescape.html @@ -1 +1,2 @@ -SystemEscape · SysnaptiK Neural
← Dashboard
SYSTEMESCAPEFACILITY ACCESS PROTOCOL
--:--
FACILITY WIRD INITIALISIERT …
+SystemEscape · SysnaptiK Neural
← Dashboard
SYSTEMESCAPEFACILITY ACCESS PROTOCOL
--:--
FACILITY WIRD INITIALISIERT …
+ diff --git a/src/main/resources/templates/dashboard.html b/src/main/resources/templates/dashboard.html index a26d8ef..45c9f79 100644 --- a/src/main/resources/templates/dashboard.html +++ b/src/main/resources/templates/dashboard.html @@ -130,14 +130,7 @@ - +
+
diff --git a/src/main/resources/templates/devlab.html b/src/main/resources/templates/devlab.html index 0245a16..4008b22 100644 --- a/src/main/resources/templates/devlab.html +++ b/src/main/resources/templates/devlab.html @@ -110,14 +110,7 @@ - +
diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html index 2d850bf..6fdbcdd 100644 --- a/src/main/resources/templates/error.html +++ b/src/main/resources/templates/error.html @@ -27,5 +27,6 @@ +
diff --git a/src/main/resources/templates/finalflux.html b/src/main/resources/templates/finalflux.html index 97efb79..d0c9112 100644 --- a/src/main/resources/templates/finalflux.html +++ b/src/main/resources/templates/finalflux.html @@ -1,5 +1,5 @@ - + FinalProtocol - SysnaptiK Neural @@ -123,14 +123,7 @@ - +
diff --git a/src/main/resources/templates/forgot-password.html b/src/main/resources/templates/forgot-password.html index 2f2a8d3..d76981f 100644 --- a/src/main/resources/templates/forgot-password.html +++ b/src/main/resources/templates/forgot-password.html @@ -25,5 +25,6 @@

Zur Anmeldung

+
diff --git a/src/main/resources/templates/fragments/layout.html b/src/main/resources/templates/fragments/layout.html index b07336a..0df87ef 100644 --- a/src/main/resources/templates/fragments/layout.html +++ b/src/main/resources/templates/fragments/layout.html @@ -85,8 +85,8 @@