Add account deletion feature and privacy section

Implement a new endpoint for account deletion in AuthController, allowing users to permanently delete their accounts and associated data. Update AuthService to handle account deletion logic, including confirmation checks and data removal from the database. Enhance frontend with new views and components for account deletion and privacy information, including links in the side menu and profile view. Update mobile app to support account deletion and privacy sections, improving user experience and compliance with data protection standards.
This commit is contained in:
Torsten Schulz (local)
2026-05-15 11:20:08 +02:00
parent afd0d2935d
commit 328bc9e776
18 changed files with 720 additions and 9 deletions

View File

@@ -23,8 +23,8 @@ android {
applicationId = "de.tsschulz.timeclock"
minSdk = 26
targetSdk = 36
versionCode = 6
versionName = "0.8.0-alpha5"
versionCode = 7
versionName = "0.8.0-alpha6"
buildConfigField("String", "API_BASE_URL", "\"${apiBaseUrl.replace("\\", "\\\\").replace("\"", "\\\"")}\"")
}

View File

@@ -159,6 +159,7 @@ fun TimeClockApp(
settingsViewModel = settingsViewModel,
adminState = adminState,
adminViewModel = adminViewModel,
openUrl = openUrl,
)
}
}
@@ -181,6 +182,7 @@ private fun DemoScreen(
settingsViewModel: SettingsViewModel,
adminState: de.tsschulz.timeclock.ui.admin.AdminUiState,
adminViewModel: AdminViewModel,
openUrl: (String) -> Unit,
) {
when (route) {
AppRoute.Week -> WeekOverviewScreen(
@@ -289,6 +291,10 @@ private fun DemoScreen(
onSend = { settingsViewModel.sendInvite(it) },
)
}
AppRoute.AccountDeletion -> AccountDeletionScreen(
onOpenDeletionPage = { openUrl("https://stechuhr3.tsschulz.de/account-loeschen") }
)
AppRoute.Privacy -> PrivacyScreen()
AppRoute.Holidays -> HolidaysAdminScreen(
state = adminState,
isTablet = isTablet,
@@ -302,6 +308,79 @@ private fun DemoScreen(
}
}
@Composable
private fun AccountDeletionScreen(onOpenDeletionPage: () -> Unit) {
TcCard {
SectionTitle("Account und Daten löschen")
PrivacySection(
"Wie lösche ich meinen Account?",
"Die vollständige Account-Löschung erfolgt in der Web-UI unter Persönliches. Dort werden Accountdaten, Anmeldedaten, Google-Verknüpfungen, Zeitbuchungen, Korrekturen, Urlaubs- und Krankmeldungen sowie persönliche Einstellungen gelöscht."
)
PrivacySection(
"Kann ich die Löschung ohne App beantragen?",
"Ja. Die öffentliche Löschseite enthält die Schritte und eine Kontaktmöglichkeit per E-Mail."
)
Row(modifier = Modifier.padding(top = TcSpacing.Lg)) {
TcButton(
text = "Löschseite öffnen",
variant = ButtonVariant.Danger,
onClick = onOpenDeletionPage,
)
}
}
}
@Composable
private fun PrivacyScreen() {
TcCard {
SectionTitle("Datenschutzerklärung")
Text("Stand: 15.05.2026", color = TcColors.TextMuted, fontSize = 13.sp)
PrivacySection(
"Verantwortlicher",
"Verantwortlich für die Datenverarbeitung in TimeClock ist Torsten Schulz. Anschrift: BITTE VOR VERÖFFENTLICHUNG ERGÄNZEN. Kontakt: kontakt@tsschulz.de."
)
PrivacySection(
"Zweck der App",
"TimeClock ist eine Zeiterfassungsanwendung. Die App verarbeitet Daten zur Anmeldung, Zeiterfassung, Auswertung und Verwaltung persönlicher Arbeitszeiten."
)
PrivacySection(
"Welche Daten werden verarbeitet?",
"Verarbeitet werden Accountdaten, Zeitbuchungen, Korrekturen, Urlaub, Krankheit, Feiertage, Arbeitszeitwünsche, Einstellungen, technische Zugriffsdaten und bei Google-Anmeldung die von Google übermittelte Konto-ID, E-Mail-Adresse und der Anzeigename."
)
PrivacySection(
"Rechtsgrundlagen",
"Die Verarbeitung erfolgt insbesondere zur Bereitstellung der Zeiterfassung, zur Erfüllung gesetzlicher Pflichten sowie für Sicherheit, Fehleranalyse und Missbrauchsschutz."
)
PrivacySection(
"Google-Anmeldung",
"Die Google-Anmeldung ist optional. Das Google-Passwort wird nicht an TimeClock übermittelt oder gespeichert."
)
PrivacySection(
"Speicherung und Löschung",
"Daten werden gespeichert, solange der Account besteht oder gesetzliche Aufbewahrungspflichten bestehen. Nutzer können ihren Account in der Web-UI unter Persönliches löschen oder eine Löschung über https://stechuhr3.tsschulz.de/account-loeschen beantragen."
)
PrivacySection(
"Rechte der Nutzer",
"Nutzer können Auskunft, Berichtigung, Löschung, Einschränkung der Verarbeitung und Datenübertragbarkeit verlangen sowie einer Verarbeitung widersprechen. Anfragen können an kontakt@tsschulz.de gerichtet werden."
)
PrivacySection(
"Sicherheit",
"Die Übertragung erfolgt über HTTPS. Passwörter werden nicht im Klartext gespeichert. Zugriffstokens und OAuth-Verknüpfungen werden serverseitig verwaltet."
)
}
}
@Composable
private fun PrivacySection(title: String, body: String) {
Column(
modifier = Modifier.padding(top = TcSpacing.Lg),
verticalArrangement = Arrangement.spacedBy(TcSpacing.Xs),
) {
Text(title, color = TcColors.Text, fontSize = 16.sp, fontWeight = FontWeight.SemiBold)
Text(body, color = TcColors.Text, fontSize = 14.sp, lineHeight = 20.sp)
}
}
@Composable
private fun WeekOverviewScreen(
week: WeekOverviewDto?,

View File

@@ -20,6 +20,8 @@ val userSections = listOf(
MenuItem("Zeitwünsche", AppRoute.Timewish),
MenuItem("Zugriffe verwalten", AppRoute.Permissions),
MenuItem("Einladen", AppRoute.Invite),
MenuItem("Account löschen", AppRoute.AccountDeletion),
MenuItem("Datenschutz", AppRoute.Privacy),
),
),
MenuSection(

View File

@@ -25,6 +25,8 @@ enum class AppRoute(val title: String) {
Timewish("Zeitwünsche"),
Permissions("Zugriffe verwalten"),
Invite("Einladen"),
AccountDeletion("Account löschen"),
Privacy("Datenschutz"),
Holidays("Feiertage"),
Roles("Rechte"),
}