Skip to content

feat: account deletion with 24h grace period#292

Merged
dkhalife merged 2 commits intomainfrom
feature/account-deletion
Mar 29, 2026
Merged

feat: account deletion with 24h grace period#292
dkhalife merged 2 commits intomainfrom
feature/account-deletion

Conversation

@dkhalife
Copy link
Copy Markdown
Owner

Summary

Implements Play Store-compliant account deletion across all entry points (web, Android, WebSocket, MCP).

Flow

  1. User requests deletion → account locked immediately (all writes blocked)
  2. 24-hour grace period — user can cancel at any time to fully restore access
  3. Scheduler (every 15 min) permanently deletes all data for accounts past the grace period

Changes

Backend (Go)

  • Migration (

Copilot AI review requested due to automatic review settings March 29, 2026 01:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a Play Store–compliant account deletion flow with an immediate account lock, a 24-hour cancellation grace period, and scheduled permanent deletion across web (REST + WS), Android, and backend services.

Changes:

  • Adds deletion_requested_at to the user model + DB migration, new REST endpoints to request/cancel deletion, and a scheduled deletion job.
  • Enforces “no writes while pending deletion” via HTTP middleware and a WS action allowlist.
  • Adds web + Android UI/UX for requesting/canceling deletion and surfacing the pending-deletion state.

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
frontend/src/views/Settings/Settings.tsx Adds account deletion section to Settings page.
frontend/src/views/Settings/AccountDeletion.tsx New settings UI to request/cancel deletion with confirmation modal.
frontend/src/store/userSlice.ts Adds deletion state + thunks and WS listeners for deletion events.
frontend/src/models/websocket.ts Adds deletion WS event types/payloads.
frontend/src/models/user.ts Adds deletion_requested_at to the user model.
frontend/src/components/DeletionBanner.tsx Adds global pending-deletion banner with cancel action.
frontend/src/api/users.ts Adds REST calls for request/cancel deletion.
frontend/src/App.tsx Renders the deletion banner globally.
apiserver/internal/ws/server.go Blocks non-read-only WS actions when pending deletion.
apiserver/internal/utils/middleware/deletion_guard_test.go Tests HTTP write-blocking middleware behavior.
apiserver/internal/utils/middleware/deletion_guard.go New middleware blocking write methods for pending-deletion accounts.
apiserver/internal/utils/database/database.go Enables SQLite foreign key enforcement.
apiserver/internal/services/users/user_test.go Tests user deletion request/cancel and deletion processing.
apiserver/internal/services/users/user.go Implements deletion request/cancel + scheduled deletion processing.
apiserver/internal/services/scheduler/scheduler.go Adds scheduled account deletion job execution.
apiserver/internal/repos/user/user_test.go Adds repo tests for deletion fields, queries, and cascades.
apiserver/internal/repos/user/user.go Adds repo methods for request/cancel/find/delete user.
apiserver/internal/models/user.go Adds DeletionRequestedAt and PendingDeletion identity flag.
apiserver/internal/migrations/006_account_deletion.go Migration adding deletion_requested_at column.
apiserver/internal/middleware/auth/auth.go Populates PendingDeletion during auth verification.
apiserver/internal/apis/user.go Exposes deletion endpoints + returns deletion timestamp on profile.
apiserver/internal/apis/task.go Applies deletion guard middleware to task routes.
apiserver/internal/apis/label.go Applies deletion guard middleware to label routes.
apiserver/config/config.go Adds scheduler config for account deletion frequency.
android/app/src/main/res/values/strings.xml Adds strings for account deletion UI.
android/app/src/main/java/com/dkhalife/tasks/viewmodel/UserViewModel.kt New VM to load profile + request/cancel deletion.
android/app/src/main/java/com/dkhalife/tasks/ui/screen/TaskListScreen.kt Disables task writes + shows pending-deletion banner.
android/app/src/main/java/com/dkhalife/tasks/ui/screen/SettingsScreen.kt Adds settings UI for deletion request/cancel + dialogs.
android/app/src/main/java/com/dkhalife/tasks/ui/navigation/AppNavigation.kt Wires UserViewModel into Tasks + Settings screens.
android/app/src/main/java/com/dkhalife/tasks/repo/UserRepository.kt Adds repo calls for request/cancel deletion endpoints.
android/app/src/main/java/com/dkhalife/tasks/model/User.kt Adds deletion_requested_at field to profile model.
android/app/src/main/java/com/dkhalife/tasks/api/TaskWizardApi.kt Adds Retrofit endpoints for deletion request/cancel.
Comments suppressed due to low confidence (1)

android/app/src/main/java/com/dkhalife/tasks/ui/screen/TaskListScreen.kt:183

  • TaskItem callbacks are being passed as nested lambdas (e.g., else { { onCompleteTask(task.id) } }), which changes the type to () -> (() -> Unit) and will not match the expected () -> Unit parameters. Pass a single lambda in the else branch (e.g., { onCompleteTask(task.id) }) and use {} for the disabled case.
                                        task = task,
                                        onComplete = if (isPendingDeletion) ({}) else { { onCompleteTask(task.id) } },
                                        onSkip = if (isPendingDeletion) ({}) else { { onSkipTask(task.id) } },
                                        onDelete = if (isPendingDeletion) ({}) else { { onDeleteTask(task.id) } },
                                        onClick = if (isPendingDeletion) ({}) else { { onTaskClick(task.id) } },
                                        onViewHistory = { onViewHistory(task.id) },
                                        onCompleteAndEndRecurrence = if (isPendingDeletion) ({}) else { { onCompleteAndEndRecurrenceTask(task.id) } },
                                        swipeSettings = if (isPendingDeletion) SwipeSettings(enabled = false) else swipeSettings,

@dkhalife dkhalife force-pushed the feature/account-deletion branch from a8c73f3 to 225254d Compare March 29, 2026 02:12
@dkhalife dkhalife merged commit 081081c into main Mar 29, 2026
9 checks passed
@dkhalife dkhalife deleted the feature/account-deletion branch March 29, 2026 02:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants