Kontolöschung und Datenexport mit Claude Code: Apple 5.1.1(v) und Google Play bestehen
Wenn Nutzer in deiner App ein Konto anlegen können, verlangen Apple und Google beide, dass sie es auch in der App wieder löschen können, und Google will zusätzlich eine Webseite für Löschanfragen. Claude Code kann das Feature an einem Nachmittag bauen, aber erst, wenn es weiß, wo jedes Stück Nutzerdaten liegt. Dieser Guide beginnt mit dieser Datenkarte und baut dann die Löschung, einen Export „Meine Daten herunterladen“ und das Aufräumen in der WebViewGold-App.
Ab $109 einmalig pro Plattform, oder unser Team erledigt alles ab $698.
Genehmigungsgarantie – oder Geld zurück innerhalb von 14 Tagen
Kein Programmieren nötig
Einmalzahlung, kostenlose Updates
24/7 Support von echten Menschen
Made in Germany seit 2014 · ISO 27001
9:41
Deine App
Deine AppJetzt auf dem Smartphone
App Store · Google Play Freigegeben
Was die Stores tatsächlich verlangen
Apple, Richtlinie 5.1.1(v): Wenn deine App das Anlegen von Konten unterstützt, müssen Nutzer die Kontolöschung in der App anstoßen können. Apples Hinweise verlangen die Löschung des Kontodatensatzes und der zugehörigen personenbezogenen Daten, keinen Schalter zum Deaktivieren; Daten, die du von Gesetzes wegen aufbewahren musst, darfst du behalten, und du solltest Nutzern sagen, wie lange die Löschung dauert. Wenn du Sign in with Apple anbietest, widerrufe beim Löschen des Kontos die Tokens des Nutzers über Apples REST API. Über Apple abgeschlossene Abos werden durch das Löschen des Kontos nicht gekündigt, sag Nutzern also, wie sie kündigen.
Google Play: Apps, in denen Nutzer Konten anlegen können, müssen die Löschung in der App anbieten und dazu einen Web-Link, über den Nutzer die Löschung beantragen können, ohne die App neu zu installieren. Diesen Link trägst du im Datensicherheitsformular ein, und die Löschung muss die mit dem Konto verknüpften Daten umfassen, abgesehen von dem, was du als aufbewahrt angibst. Der Guide zur Kontolöschung bei Google Play behandelt die Seite der Konsole.
Datenexport: Keiner der beiden Stores verlangt ihn, aber Datenschutzgesetze wie die DSGVO geben Nutzern ein Recht auf Auskunft und Datenübertragbarkeit, und ein Button „Meine Daten herunterladen“ beantwortet solche Anfragen ohne Support-Ticket. Er ist außerdem ein guter Test für deine Datenkarte: Was der Agent nicht exportieren kann, kann er wahrscheinlich auch nicht löschen.
Was Claude Code übernimmt und was du machst
Bereich
Claude Code
Du
Datenkarte
Durchsucht im Plan-Modus Code, Migrationen, SDK-Imports und Webhooks und entwirft DATA_MAP.md
Ergänzen, was der Code nicht zeigen kann (Spreadsheets, Support-Postfach, manuelle Exporte), und Aufbewahrungsfristen bestätigen
Code
Einstellungs-UI, Export- und Lösch-Routen, Cleanup-Helper, Migrationen, Tests, Seite /delete-account
Prüfen, Umgebungsvariablen beim Hoster setzen, deployen
Store-Konsolen
Entwirft die Änderungen an der Datenschutzerklärung und die Antworten für das Datensicherheitsformular
Die Lösch-URL in der Play Console eintragen, App Privacy in App Store Connect aktualisieren
WebViewGold
Nichts nötig; kann die Downloader-Optionen setzen, wenn die Projekte im Repository liegen
Ein neuer Build, wenn du die Downloader-Einstellungen änderst
Prompt 1: die Datenkarte, im Plan-Modus
Im Plan-Modus kann Claude Code das Repository lesen und durchsuchen, ohne etwas zu bearbeiten. Speichere das Ergebnis als DATA_MAP.md und korrigiere es, bevor du weitermachst; diese Datei sorgt dafür, dass die Löschung vollständig ist.
Im Plan-Modus (Shift+Tab) in Claude Code einfügen
Nur Plan-Modus, ändere keine Dateien. Wir brauchen eine Kontolöschung in der App (Apple-Richtlinie 5.1.1(v) und die Google-Play-Richtlinie zur Kontolöschung) und einen Export „Meine Daten herunterladen“. Erstelle zuerst eine vollständige Datenkarte.
Durchsuche die Codebasis, die Migrationen, die Namen der Umgebungsvariablen, SDK-Imports, Cronjobs und Webhook-Handler und liste jede Stelle auf, an der Daten über einen Nutzer liegen: Auth-Datensätze, jede Tabelle mit einer Spalte user_id, owner_id oder email und wie sie auf den Nutzer verweist, Storage-Buckets und Dateipfade, Stripe-Kunden und -Abos, RevenueCat-Kunden, OneSignal-Subscription-IDs, Sign-in-with-Apple-Tokens, Analytics und Error-Tracking, E-Mail- und Newsletter-Tools, Logs und Backups.
Gib für jeden Eintrag an: wo er liegt, welcher Identifier ihn mit dem Nutzer verknüpft, wie er gelöscht wird (Foreign-Key-Kaskade, API-Aufruf oder Aufbewahrung mit Begründung) und ob er in den Export gehört. Markiere alles, bei dem du unsicher bist. Gib das Ergebnis als Markdown-Tabelle aus, die ich als DATA_MAP.md speichern kann.
Ich bin sehr glücklich, dass ich diese App gekauft habe! Extrem einfach und großartige Dokumentation. Ich stand in Kontakt mit dem Kundenservice, sie antworteten sehr schnell und sehr freundlich. Sie lösten meine Frage innerhalb eines Tages. 10/10 würde ich empfehlen.
Storage API, pro Nutzerordner (das Auflisten ist nicht rekursiv)
Links oder die Dateien
Stripe-Kunde und -Abos
Abos kündigen; Rechnungen wie gesetzlich vorgeschrieben aufbewahren und das in /privacy sagen
Tarif und Rechnungsliste
Abo im App Store / bei Google Play
Kannst du nicht kündigen; in der App cancelinapppurchase:// anzeigen
Tarifname
RevenueCat-Kunde
Kundenlöschung über die RevenueCat REST API
Nein
OneSignal-Subscription-IDs
Deine gespeicherten Zeilen löschen; optional den OneSignal-Nutzer über deren API
Nein
Sign in with Apple
Das Token am Revoke-Endpunkt von Apple widerrufen
Nein
Analytics, Error-Tracking, E-Mail-Tools
Lösch-API des Anbieters oder dokumentierte Aufbewahrung
Meist nein
Prompt 2: Löschung und Export bauen
Wechsle zurück in den normalen Berechtigungsmodus, damit du jede Änderung einzeln prüfen kannst, oder in den Accept-Edits-Modus, wenn du lieber am Ende das komplette Diff prüfst.
In Claude Code einfügen, sobald DATA_MAP.md stimmt
Implementiere Kontolöschung und Datenexport auf Basis von DATA_MAP.md. Unsere App läuft auch in nativen iOS- und Android-Apps, die mit WebViewGold gebaut sind (der User-Agent enthält WebViewGoldApp).
1. Einstellungen > Konto: ein Button „Meine Daten herunterladen“ und ein Button „Konto löschen“.
2. Export: GET /api/account/export liefert für den angemeldeten Nutzer eine JSON-Datei mit jedem exportierbaren Eintrag aus der Datenkarte, gesendet mit Content-Type application/json und Content-Disposition attachment; filename=my-data.json. Löse ihn mit einem normalen Link auf diese URL aus, nicht mit einem Download per Blob oder createObjectURL: In der App reagiert der WebViewGold-Downloader auf Dateiendungen und Content-Disposition-Header. Wenn ein Export groß werden kann, erzeuge ihn in einem Hintergrundjob und schick per E-Mail einen signierten Link, der nach 24 Stunden abläuft.
3. Löschen: ein Bestätigungsscreen, der erklärt, was gelöscht wird, was wir aus rechtlichen Gründen behalten (Rechnungen) und dass Abos im App Store oder bei Google Play nicht automatisch gekündigt werden. Zeige in der App einen Link „Abo verwalten“, der zu cancelinapppurchase:// navigiert, wenn der Nutzer ein Store-Abo hat. Verlange die Eingabe von DELETE.
4. POST /api/account/delete: authentifizieren, dann in dieser Reihenfolge Stripe-Abos kündigen, den RevenueCat-Kunden löschen, Sign-in-with-Apple-Tokens widerrufen, falls wir welche haben (Apple REST API, /auth/revoke), Storage-Dateien löschen, Zeilen löschen (bevorzugt über ON DELETE CASCADE; leg eine Migration an, wo das fehlt) und zuletzt den Auth-Nutzer mit dem Admin-Client löschen. Nur serverseitig; der Service-Role-Key darf nie im Client-Bundle landen. Mach die Route idempotent, damit ein erneuter Versuch nach einem teilweisen Fehlschlag den Job zu Ende bringt.
5. Nach Erfolg: abmelden und /account-deleted anzeigen. In der App navigiert der Button „Fertig“ dort zu reset://, um die Cookies und den Cache zu leeren, die der Wrapper vorhält.
6. Eine öffentliche Seite /delete-account für Leute, die die App nicht mehr haben: erklärt den Weg in der App und bietet ein Anfrageformular oder eine E-Mail-Adresse, funktioniert ohne Login und auf einem 320-px-Screen.
7. Aktualisiere /privacy mit den Aufbewahrungsfristen und der URL /delete-account.
8. Tests für die Lösch-Route: Ein Nutzer mit Daten in jeder Tabelle hat am Ende null Zeilen, und ein zweiter Aufruf der Route ist trotzdem erfolgreich.
Berichte die geänderten Dateien, die Migrationen und jeden manuellen Schritt, den ich erledigen muss.
Die Lösch-Route, in einer Reihenfolge, die keine IDs verliert
Zuerst die Drittanbieter, solange du die Kunden-IDs noch kennst; der Auth-Nutzer zuletzt, weil die meisten Foreign Keys an ihm hängen. Die Helper in account-cleanup kapseln die Aufrufe an Stripe, RevenueCat und Apple aus deiner Datenkarte.
typescript
// app/api/account/delete/route.ts (nur Server)
import { NextResponse } from "next/server";
import { createClient as createAdmin } from "@supabase/supabase-js";
import { createClient } from "@/lib/supabase/server";
import { cancelStripeSubscriptions, deleteRevenueCatCustomer, revokeAppleTokens } from "@/lib/account-cleanup";
export async function POST(req: Request) {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
if (!user) return NextResponse.json({ error: "unauthorized" }, { status: 401 });
const { confirm } = await req.json();
if (confirm !== "DELETE") return NextResponse.json({ error: "confirmation missing" }, { status: 400 });
const admin = createAdmin(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!);
// 1. Drittanbieter, solange die IDs noch existieren (jeder Helper tut nichts, wenn es nichts zu tun gibt)
await cancelStripeSubscriptions(user.id);
await deleteRevenueCatCustomer(user.id);
await revokeAppleTokens(user.id);
// 2. Dateien: list() ist nicht rekursiv, verschachtelte Ordner brauchen einen eigenen Durchlauf
const { data: files } = await admin.storage.from("uploads").list(user.id);
if (files && files.length > 0) {
await admin.storage.from("uploads").remove(files.map((f) => user.id + "/" + f.name));
}
// 3. Zeilen verschwinden mit dem Nutzer über ON DELETE CASCADE (siehe DATA_MAP.md)
// 4. Der Auth-Nutzer, ganz zum Schluss
const { error } = await admin.auth.admin.deleteUser(user.id);
if (error) return NextResponse.json({ error: "delete failed, safe to retry" }, { status: 500 });
return NextResponse.json({ ok: true });
}
Den Export in der App herunterladbar machen
Zwei kleine Einstellungen entscheiden, ob die Datei auf dem Handy ankommt.
Eine echte Datei-URL ausliefern
Die Route oben liefert JSON mit einem Content-Disposition-Header vom Typ attachment. Verlinke sie mit einem einfachen Anchor-Link; per JavaScript erzeugte Blob-Downloads deckt die Doku des WebViewGold-Downloaders nicht ab.
iOS
Aktiviere entweder autodownloader in Config.swift (Downloads anhand von Content-Disposition-Headern) oder liefere die Datei unter einer URL aus, die auf .json endet, und füge ".json" zu extentionARY hinzu. Siehe die Doku zum iOS-Datei-Downloader.
Android
Aktiviere AUTO_DOWNLOAD_FILES in Config.java oder füge die Endung zu downloadableExtension hinzu; requireStorage muss auf true bleiben, wenn du Downloads nutzt. Siehe die Doku zum Android-Datei-Downloader.
Einmal neu bauen
Das sind native Einstellungen, sie brauchen also einen neuen Build. Alles andere in diesem Guide kommt mit deinem nächsten Web-Deploy. Der Cloud Builder kann diesen Build ohne lokales Xcode oder Android Studio erstellen.
Checkliste
Leg in den Builds aus TestFlight und dem internen Test ein frisches Konto an, füge Inhalte hinzu, lade eine Datei hoch und kauf, falls du Abos verkaufst, eins in der Sandbox.
Tippe auf „Meine Daten herunterladen“: Die Datei kommt auf dem Handy an und enthält deine Inhalte, kein leeres Objekt.
Tippe auf „Konto löschen“: Die Bestätigung erklärt die Folgen und enthält den Hinweis zum Abo, der Link „Abo verwalten“ öffnet den Store-Screen, die Eingabe von DELETE schließt den Ablauf ab, und die App zeigt die Bestätigung.
Tippe in der Bestätigung auf „Fertig“: reset:// leert Cookies und Cache des Wrappers. Notiere, was dein Build danach anzeigt, und stell sicher, dass es ein sauberer Neustart ist, kein Fehler.
Versuch, dich erneut anzumelden: Das Konto existiert nicht mehr. Eine Abfrage nach der Nutzer-ID liefert in jeder Tabelle aus DATA_MAP.md null Zeilen, und der Storage-Ordner ist leer.
Bei einem Testnutzer mit Sign in with Apple verschwindet die App nach der Löschung aus der Sign-in-with-Apple-Liste in den Einstellungen dieses Apple Accounts, was zeigt, dass das Token widerrufen wurde.
Öffne /delete-account in einem privaten Browserfenster auf einem Handy: Die Seite funktioniert ohne Login, und dieselbe URL steht im Datensicherheitsformular der Play Console.
Stolperfallen
Nur Soft Delete. Ein deleted_at-Flag ist eine Deaktivierung. Reviewer und Google erwarten, dass die Daten weg sind, abgesehen von offengelegter Aufbewahrung.
Den Auth-Nutzer zuerst löschen. Ohne Kaskaden bleiben Zeilen übrig; mit Kaskaden verlierst du die IDs, die du für Stripe und RevenueCat gebraucht hättest. Drittanbieter zuerst, Auth zuletzt.
Vergessener Storage. Avatare und Uploads überleben das Löschen der Zeilen. Die Datenkarte gibt es, um genau das abzufangen.
Den Demo-Account des Reviewers löschen. Reviewer testen die Löschung eventuell mit dem Account, den du ihnen gegeben hast. Schreib in die Review-Notizen, dass sie sich auch neu registrieren können, und leg den Demo-Account nach jedem Review neu an.
Versteckt hinter dem Support. „Schreib uns eine E-Mail, um dein Konto zu löschen“ als einziger Weg fällt bei den meisten Apps durch 5.1.1(v). Der Button in der App muss die Löschung starten.
Häufig gestellte Fragen
Reicht es, das Konto zu deaktivieren?
Nein. Apple verlangt die Löschung des Kontos und der zugehörigen personenbezogenen Daten, und Google Play verlangt, dass die Daten gelöscht und nicht nur ausgeblendet werden. Deaktivierung kann eine zusätzliche Option sein, aber nicht die einzige.
Darf ich nach der Löschung einige Daten behalten?
Ja, wenn du eine gesetzliche Pflicht oder einen berechtigten Grund hast, etwa Rechnungen nach Steuerrecht. Leg das in deiner Datenschutzerklärung und im Datensicherheitsformular offen.
Darf die Löschung ein paar Tage dauern?
Eine kurze Karenzzeit ist üblich. Starte die Löschung in der App, sag dem Nutzer genau, wann die Daten weg sind, und prüf in Apples aktuellen Hinweisen zur Kontolöschung, welche Formulierungen Reviewer erwarten.
Was passiert mit Abos, die in der App gekauft wurden?
Abos im App Store oder bei Google Play kannst du nicht im Namen des Nutzers kündigen. Zeige einen Link „Abo verwalten“ (in der App cancelinapppurchase://) und sag klar, dass die Abrechnung weiterläuft, bis der Nutzer kündigt.
Welches Format sollte der Export haben?
Ein strukturiertes, maschinenlesbares Format wie JSON oder CSV. Eine JSON-Datei pro Konto lässt sich am einfachsten erzeugen, testen und erklären.
Drei Wege, deine App in die Stores zu bringen
Gleiches Ergebnis, unterschiedlich viel Arbeit auf deiner Seite. Alle drei kommen mit Genehmigungsgarantie und 24/7 Support von echten Menschen.
Selbst machen
$109 pro Plattform, einmalig
Die WebViewGold-Lizenz: ein fertiges Xcode- oder Android-Studio-Projekt. URL einfügen, Name und Icon setzen, Features einschalten, bauen und einreichen. Kostenlose Updates für immer.
Kein Mac, kein Xcode, kein Android Studio: Du konfigurierst im Browser, wir bauen beide Apps in der Cloud und übergeben sie an App Store Connect und die Play Console.
Schick uns deine URL und dein Icon. Unser Team konfiguriert, baut und liefert deine App innerhalb von 72 Stunden, White-Label, inklusive Quellprojekten. Beide Plattformen für $1,158.
Erstattungen erfolgen zu den in unseren FAQ genannten Bedingungen: eine nicht inhaltsbedingte Ablehnung durch Apple und/oder Google, geltend gemacht innerhalb von 14 Tagen nach dem Kauf.