feat: add Datenschutzerklärung and Konto löschen pages
Some checks failed
Code Analysis and Production Deploy / analyze (push) Failing after 2m10s
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Has been skipped

- Created datenschutz.vue for the privacy policy with sections on data protection, responsible entity, data processing, rights, and contact information.
- Created konto-loeschen.vue for account deletion requests, detailing the process, affected data, and processing time.
- Added anonymize-playstore-screenshot.sh script for image anonymization using ImageMagick.
- Introduced playstore-assets.mjs for generating Play Store assets, including icons and feature graphics, using sharp.
- Added playstore-assets.sh script to execute the asset generation script.
This commit is contained in:
Torsten Schulz (local)
2026-05-29 16:51:36 +02:00
parent f5045c3cf0
commit 5c3d78245f
12 changed files with 380 additions and 1 deletions

View File

@@ -145,6 +145,8 @@ Kurz: Ziel ist eine native Android-App mit Kotlin + Jetpack Compose, die die Web
- [x] Production-Release-Flavor auf Produktiv-Backend parametrisierbar gemacht (`PRODUCTION_API_BASE_URL`, Default `https://harheimertc.de/`). - [x] Production-Release-Flavor auf Produktiv-Backend parametrisierbar gemacht (`PRODUCTION_API_BASE_URL`, Default `https://harheimertc.de/`).
- [x] Release-Signing per sicheren Gradle-Properties vorbereitet (`RELEASE_STORE_FILE`, `RELEASE_STORE_PASSWORD`, `RELEASE_KEY_ALIAS`, `RELEASE_KEY_PASSWORD`) statt Hardcoding. - [x] Release-Signing per sicheren Gradle-Properties vorbereitet (`RELEASE_STORE_FILE`, `RELEASE_STORE_PASSWORD`, `RELEASE_KEY_ALIAS`, `RELEASE_KEY_PASSWORD`) statt Hardcoding.
- [x] `:app:assembleProductionRelease` erfolgreich gebaut (Stand 2026-05-29). - [x] `:app:assembleProductionRelease` erfolgreich gebaut (Stand 2026-05-29).
- [x] Play-Store-Listing-Basis ergänzt: Datenschutzseite unter `/datenschutz` sowie Skripte für Icon/Feature-Graphic-Export und Screenshot-Anonymisierung inklusive Anleitung (`android-app/PLAYSTORE_ASSETS.md`).
- [x] Konto-Lösch-URL für Play Store ergänzt: öffentliche Seite unter `/konto-loeschen` inklusive Prozessbeschreibung.
- [ ] Offen: Finales Upload-Keystore + Credentials in CI/Build-Host hinterlegen, Play-Store-Release-Notes und Store-Metadaten pflegen. - [ ] Offen: Finales Upload-Keystore + Credentials in CI/Build-Host hinterlegen, Play-Store-Release-Notes und Store-Metadaten pflegen.
[ ] 25. Dokumentation: `README-android.md` mit Setup, Architektur und Release-Anleitung [ ] 25. Dokumentation: `README-android.md` mit Setup, Architektur und Release-Anleitung
@@ -197,6 +199,7 @@ Kurz: Ziel ist eine native Android-App mit Kotlin + Jetpack Compose, die die Web
- 2026-05-28: Caching-Teil von Punkt 17 und MVP-D umgesetzt: OkHttp cached öffentliche GET-Antworten und nutzt gecachte Antworten offline, Coil nutzt denselben authentifizierten Client plus Memory-/Diskcache. Geschützte Daten werden bewusst nicht unverschlüsselt im HTTP-Diskcache persistiert. - 2026-05-28: Caching-Teil von Punkt 17 und MVP-D umgesetzt: OkHttp cached öffentliche GET-Antworten und nutzt gecachte Antworten offline, Coil nutzt denselben authentifizierten Client plus Memory-/Diskcache. Geschützte Daten werden bewusst nicht unverschlüsselt im HTTP-Diskcache persistiert.
- 2026-05-28: Testbasis für Punkt 20 begonnen: JVM-Unit-Tests für E-Mail- und ISO-Datum-Validierung ergänzt; `:app:testLocalDebugUnitTest` läuft mit `compileSdk 35` grün. - 2026-05-28: Testbasis für Punkt 20 begonnen: JVM-Unit-Tests für E-Mail- und ISO-Datum-Validierung ergänzt; `:app:testLocalDebugUnitTest` läuft mit `compileSdk 35` grün.
- 2026-05-28: Punkte 17, 19, 21 und 23 weiter umgesetzt: geschützte Mitglieder-/CMS-Daten werden verschlüsselt in Keystore-gestützten Preferences gecacht und bei Ladefehlern genutzt; Galerie-Accessibility und Thumbnail-Decoding verbessert; Sentry-Android 8.42.0 über optionalen `SENTRY_DSN`-Gradle-Parameter integriert. - 2026-05-28: Punkte 17, 19, 21 und 23 weiter umgesetzt: geschützte Mitglieder-/CMS-Daten werden verschlüsselt in Keystore-gestützten Preferences gecacht und bei Ladefehlern genutzt; Galerie-Accessibility und Thumbnail-Decoding verbessert; Sentry-Android 8.42.0 über optionalen `SENTRY_DSN`-Gradle-Parameter integriert.
- 2026-05-29: Play-Store-Listing-Vorbereitung ergänzt: eigenständige Web-Datenschutzseite (`/datenschutz`) sowie Asset-/Anonymisierungs-Skripte und Anleitung in `android-app/PLAYSTORE_ASSETS.md` hinzugefügt.
8) Android-Testumgebungen 8) Android-Testumgebungen
- Lokal im Emulator: `./gradlew :app:installLocalDebug` verwendet `http://10.0.2.2:3100/` und die App-ID `de.harheimertc.local`. - Lokal im Emulator: `./gradlew :app:installLocalDebug` verwendet `http://10.0.2.2:3100/` und die App-ID `de.harheimertc.local`.

View File

@@ -0,0 +1,70 @@
# Play Store Assets - Harheimer TC Android
## 1) Datenschutzerklaerung (Web-URL)
Empfohlene URL fuer Play Console:
- https://harheimertc.de/datenschutz
Die Seite ist in der Web-App als eigene Route vorhanden.
## 1b) Konto-Loeschung (Web-URL)
Empfohlene URL fuer Play Console:
- https://harheimertc.de/konto-loeschen
Die Seite beschreibt den Loeschprozess und Kontaktweg fuer App- und Webkonto.
## 2) Logo / Grafiken
### Pflicht
- App-Icon (Play): 512 x 512 PNG
### Optional, aber empfohlen
- Feature Graphic: 1024 x 500 PNG
### Generierung
Im Repo ist ein Script vorhanden, das aus dem Vereinslogo fertige Dateien erzeugt:
```bash
./scripts/playstore-assets.sh
```
Ausgabe in:
- android-app/playstore-assets/generated/playstore-icon-512.png
- android-app/playstore-assets/generated/playstore-feature-graphic-1024x500.png
## 3) Screenshots (anonymisiert)
### Grobe Anforderungen (Telefon)
- Mindestens 2 Screenshots
- PNG oder JPEG
- Seitenlaenge je Seite zwischen 320 px und 3840 px
Empfehlung fuer Android-Phone:
- 1080 x 1920 (Portrait)
### Anonymisierung
Script fuer schwarze halbtransparente Balken ueber sensible Bereiche:
```bash
./scripts/anonymize-playstore-screenshot.sh <input.png> <output.png> 'x,y,w,h;x,y,w,h'
```
Beispiel:
```bash
./scripts/anonymize-playstore-screenshot.sh \
android-app/playstore-assets/raw/screen1.png \
android-app/playstore-assets/anon/screen1-anon.png \
'68,118,520,72;70,706,560,98'
```
## 4) Upload in Play Console
- Datenschutzerklaerung: URL eintragen
- Konto-Loeschung: URL eintragen
- App-Icon: playstore-icon-512.png
- Feature Graphic: playstore-feature-graphic-1024x500.png
- Screenshots: anonymisierte PNG/JPEG hochladen

View File

@@ -8,7 +8,7 @@ LOCAL_API_BASE_URL=https://harheimertc.tsschulz.de/
PRODUCTION_API_BASE_URL=https://harheimertc.de/ PRODUCTION_API_BASE_URL=https://harheimertc.de/
# Android app versioning for Play Store uploads # Android app versioning for Play Store uploads
ANDROID_VERSION_CODE=3 ANDROID_VERSION_CODE=4
ANDROID_VERSION_NAME=1.0.0 ANDROID_VERSION_NAME=1.0.0
# Enable R8 for release by default so mapping.txt is generated for Play Console. # Enable R8 for release by default so mapping.txt is generated for Play Console.

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -19,6 +19,18 @@
> >
Impressum Impressum
</NuxtLink> </NuxtLink>
<NuxtLink
to="/datenschutz"
class="text-gray-400 hover:text-primary-400 transition-colors"
>
Datenschutz
</NuxtLink>
<NuxtLink
to="/konto-loeschen"
class="text-gray-400 hover:text-primary-400 transition-colors"
>
Konto loeschen
</NuxtLink>
<NuxtLink <NuxtLink
to="/kontakt" to="/kontakt"
class="text-gray-400 hover:text-primary-400 transition-colors" class="text-gray-400 hover:text-primary-400 transition-colors"

View File

@@ -21,6 +21,8 @@
"sync-public-data": "node scripts/sync-public-data.js", "sync-public-data": "node scripts/sync-public-data.js",
"import-spielplan": "node scripts/import-spielplan.js", "import-spielplan": "node scripts/import-spielplan.js",
"publish-spielplan": "node scripts/publish-imported-spielplan.js", "publish-spielplan": "node scripts/publish-imported-spielplan.js",
"playstore:assets": "./scripts/playstore-assets.sh",
"playstore:anonymize": "./scripts/anonymize-playstore-screenshot.sh",
"test:watch": "vitest watch", "test:watch": "vitest watch",
"lint": "eslint . --fix" "lint": "eslint . --fix"
}, },

110
pages/datenschutz.vue Normal file
View File

@@ -0,0 +1,110 @@
<template>
<div class="min-h-full py-16 px-4 sm:px-6 lg:px-8 bg-gray-50">
<div class="max-w-4xl mx-auto">
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
Datenschutzerklärung
</h1>
<div class="w-24 h-1 bg-primary-600 mb-8" />
<div class="bg-white p-8 rounded-xl shadow-lg space-y-6 text-gray-700">
<section>
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
1. Datenschutz auf einen Blick
</h2>
<p>
Der Schutz Ihrer personenbezogenen Daten hat für den Harheimer TC 1954 e.V. einen hohen Stellenwert.
Wir verarbeiten personenbezogene Daten vertraulich und entsprechend den gesetzlichen Datenschutzvorschriften.
</p>
</section>
<section>
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
2. Verantwortliche Stelle
</h2>
<p>
Harheimer TC 1954 e.V.<br>
Kontakt über die Angaben im
<NuxtLink
to="/impressum"
class="text-primary-600 hover:underline"
>
Impressum
</NuxtLink>
.
</p>
</section>
<section>
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
3. Verarbeitung personenbezogener Daten
</h2>
<p class="mb-3">
Wir verarbeiten personenbezogene Daten insbesondere in folgenden Fällen:
</p>
<ul class="list-disc pl-6 space-y-1">
<li>Kontaktanfragen über Formulare oder E-Mail</li>
<li>Mitgliedschaftsanträge</li>
<li>Nutzung des Mitgliederbereichs (Login, Profilfunktionen)</li>
<li>Newsletter-Anmeldung und -Abmeldung</li>
</ul>
</section>
<section>
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
4. Technische und organisatorische Maßnahmen
</h2>
<p>
Für besonders schützenswerte Daten setzen wir technische Schutzmaßnahmen ein,
darunter Verschlüsselung, rollenbasierte Zugriffssteuerung und abgesicherte
Authentifizierungsverfahren.
</p>
</section>
<section>
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
5. Ihre Rechte
</h2>
<p class="mb-3">
Sie haben im Rahmen der gesetzlichen Vorgaben insbesondere folgende Rechte:
</p>
<ul class="list-disc pl-6 space-y-1">
<li>Auskunft über gespeicherte Daten</li>
<li>Berichtigung unrichtiger Daten</li>
<li>Löschung oder Einschränkung der Verarbeitung</li>
<li>Widerspruch gegen die Verarbeitung</li>
<li>Datenübertragbarkeit</li>
</ul>
</section>
<section>
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
6. Kontakt zum Datenschutz
</h2>
<p>
Bei Fragen zum Datenschutz nutzen Sie bitte die Kontaktangaben im
<NuxtLink
to="/impressum"
class="text-primary-600 hover:underline"
>
Impressum
</NuxtLink>
oder unser
<NuxtLink
to="/kontakt"
class="text-primary-600 hover:underline"
>
Kontaktformular
</NuxtLink>
.
</p>
</section>
</div>
</div>
</div>
</template>
<script setup>
useHead({
title: 'Datenschutzerklärung - Harheimer TC',
})
</script>

75
pages/konto-loeschen.vue Normal file
View File

@@ -0,0 +1,75 @@
<template>
<div class="min-h-full py-16 px-4 sm:px-6 lg:px-8 bg-gray-50">
<div class="max-w-4xl mx-auto">
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
Konto loeschen
</h1>
<div class="w-24 h-1 bg-primary-600 mb-8" />
<div class="bg-white p-8 rounded-xl shadow-lg space-y-6 text-gray-700">
<section>
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
Kontoloeschung fuer App- und Webkonto
</h2>
<p>
Sie koennen die Loeschung Ihres Harheimer-TC-Kontos jederzeit beantragen.
Nach erfolgreicher Pruefung wird Ihr Zugang deaktiviert und Ihre personenbezogenen Daten
gemaess den gesetzlichen Aufbewahrungspflichten geloescht oder anonymisiert.
</p>
</section>
<section>
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
So stellen Sie den Antrag
</h2>
<ol class="list-decimal pl-6 space-y-2">
<li>Melden Sie sich mit Ihrem Konto im Mitgliederbereich an.</li>
<li>Nutzen Sie das Kontaktformular oder schreiben Sie eine E-Mail mit dem Betreff "Konto loeschen".</li>
<li>Nennen Sie dabei die E-Mail-Adresse Ihres Kontos zur Zuordnung.</li>
</ol>
<div class="mt-4 flex flex-wrap gap-3">
<NuxtLink
to="/kontakt"
class="inline-flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-medium rounded-lg transition-colors"
>
Kontaktformular
</NuxtLink>
<NuxtLink
to="/impressum"
class="inline-flex items-center px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-900 font-medium rounded-lg transition-colors"
>
Kontakt per E-Mail im Impressum
</NuxtLink>
</div>
</section>
<section>
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
Welche Daten sind betroffen?
</h2>
<ul class="list-disc pl-6 space-y-1">
<li>Login-Daten und Zugangsdaten werden entfernt oder ungueltig gemacht.</li>
<li>Persoenliche Profildaten im Mitgliederbereich werden geloescht oder anonymisiert.</li>
<li>Rechtlich erforderliche Restdaten (z. B. vereins- oder steuerrechtlich) koennen befristet gespeichert bleiben.</li>
</ul>
</section>
<section>
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
Bearbeitungszeit
</h2>
<p>
Wir bearbeiten Loeschanfragen in der Regel innerhalb von 30 Tagen.
Bei Rueckfragen kontaktieren wir Sie ueber die hinterlegte E-Mail-Adresse.
</p>
</section>
</div>
</div>
</div>
</template>
<script setup>
useHead({
title: 'Konto loeschen - Harheimer TC',
})
</script>

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -lt 3 ]]; then
echo "Nutzung: $0 <input.png> <output.png> <rects>"
echo "rects Format: x,y,w,h;x,y,w,h"
echo "Beispiel: $0 shot.png shot-anon.png '80,120,420,70;72,720,540,90'"
exit 1
fi
INPUT="$1"
OUTPUT="$2"
RECTS="$3"
if ! command -v magick >/dev/null 2>&1; then
echo "Fehler: 'magick' (ImageMagick) ist nicht installiert."
exit 1
fi
TMP="$OUTPUT.tmp.png"
cp "$INPUT" "$TMP"
IFS=';' read -r -a BOXES <<< "$RECTS"
for box in "${BOXES[@]}"; do
IFS=',' read -r x y w h <<< "$box"
magick "$TMP" \
\( -size "${w}x${h}" xc:black -alpha set -channel a -evaluate set 70% +channel \) \
-geometry "+${x}+${y}" -composite "$TMP"
done
mv "$TMP" "$OUTPUT"
echo "Anonymisierte Datei geschrieben: $OUTPUT"

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env node
import { mkdir, readFile } from 'node:fs/promises'
import path from 'node:path'
import sharp from 'sharp'
import { fileURLToPath } from 'node:url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const rootDir = path.resolve(__dirname, '..')
const logoSrc = path.join(rootDir, 'public', 'images', 'logos', 'Harheimer TC.svg')
const outDir = path.join(rootDir, 'android-app', 'playstore-assets', 'generated')
const iconOut = path.join(outDir, 'playstore-icon-512.png')
const featureOut = path.join(outDir, 'playstore-feature-graphic-1024x500.png')
const featureOverlaySvg = `
<svg width="1024" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#0f172a"/>
<stop offset="100%" stop-color="#1e293b"/>
</linearGradient>
</defs>
<rect width="1024" height="500" fill="url(#bg)"/>
<text x="430" y="185" font-size="66" font-family="DejaVu Sans, Arial, sans-serif" font-weight="700" fill="#e5e7eb">Harheimer TC</text>
<text x="430" y="250" font-size="30" font-family="DejaVu Sans, Arial, sans-serif" fill="#cbd5e1">Tischtennis in Frankfurt-Harheim</text>
</svg>
`
async function generateAssets() {
await mkdir(outDir, { recursive: true })
const logoBuffer = await readFile(logoSrc)
const resizedLogoForIcon = await sharp(logoBuffer)
.resize(440, 440, { fit: 'contain' })
.png()
.toBuffer()
await sharp({
create: {
width: 512,
height: 512,
channels: 4,
background: { r: 0, g: 0, b: 0, alpha: 0 },
},
})
.composite([{ input: resizedLogoForIcon, gravity: 'center' }])
.png()
.toFile(iconOut)
const resizedLogoForFeature = await sharp(logoBuffer)
.resize(320, 320, { fit: 'contain' })
.png()
.toBuffer()
await sharp(Buffer.from(featureOverlaySvg))
.composite([{ input: resizedLogoForFeature, left: 72, top: 90 }])
.png()
.toFile(featureOut)
console.log(`Fertig. Assets erzeugt in: ${outDir}`)
console.log(`- ${path.basename(iconOut)}`)
console.log(`- ${path.basename(featureOut)}`)
}
generateAssets().catch((error) => {
console.error('Fehler bei der Asset-Generierung:', error)
process.exitCode = 1
})

6
scripts/playstore-assets.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
node "$ROOT_DIR/scripts/playstore-assets.mjs"