Skip to content

Conversation

@AshokaJS
Copy link
Collaborator

@AshokaJS AshokaJS commented Jun 10, 2025

issue resolved is #6
Approach :-

  1. User Requests Account Deletion
    --extract the user_id from the the JWT token.
    --update the database set is_deleted= true, deleted_at= current_time
    --this marks the account as "soft-deleted".

2.User tries to login again within 90 days.
--during login, after verifying Github OAuth check if the user is soft deleted.
--if deleted_at + 90 days > now then user is within grace period.
--reverse the deletion by deleted = false, deleted_at = NULL.

3.Background Job runs daily.
--run a scheduled Job once a day using cron package.
--it runs the query and permanently deletes the user whose deleted_at timestamp is older than 90 days.

@AshokaJS AshokaJS requested a review from pari-27 June 11, 2025 06:39
@AshokaJS AshokaJS closed this Jun 12, 2025
@AshokaJS AshokaJS deleted the feat/Delete branch June 12, 2025 13:04
@AshokaJS AshokaJS restored the feat/Delete branch June 12, 2025 13:05
@AshokaJS AshokaJS reopened this Jun 12, 2025
Comment on lines 11 to 30
func PermanentDeleteJob(db *sqlx.DB) {
slog.Info("entering into the cleanup job")
c := cron.New()
_, err := c.AddFunc("36 00 * * *", func() {
slog.Info("Job scheduled for user cleanup from database")
ur := repository.NewUserRepository(db) // pass in *sql.DB or whatever is needed
err := ur.DeleteUser(nil)
if err != nil {
slog.Error("Cleanup job error", "error", err)
} else {
slog.Info("User cleanup Job completed.")
}
})

if err != nil {
slog.Error("failed to start user delete job ", "error", err)
}

c.Start()
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we explore different patterns for structure Jobs in Golang, maybe look for things using struct and struct embedding with a Common struct.

Comment on lines 88 to 92
err = s.userService.RecoverAccountInGracePeriod(ctx, userData.Id)
if err != nil {
slog.Error("error in recovering account in grace period during login", "error", err)
return "", apperrors.ErrInternalServer
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Only call recover if userData.IsDeleted is true


router.HandleFunc("PATCH /api/v1/user/email", middleware.Authentication(deps.UserHandler.UpdateUserEmail, deps.AppCfg))

router.HandleFunc("DELETE /api/user/delete", middleware.Authentication(deps.UserHandler.DeleteUser, deps.AppCfg))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Generally in HTTP routes, we keep id in both token and path, and in handler we check if both are equal. So the path would be DELETE /api/user/delete/{user_id}

Comment on lines 52 to 54
val := ctx.Value(middleware.UserIdKey)

userID := val.(int)
Copy link
Collaborator

Choose a reason for hiding this comment

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

We could extract this logic into a util function, so it can be reused in other handlers

Comment on lines 221 to 224
executer := ur.BaseRepository.initiateQueryExecuter(tx)
_, err := executer.ExecContext(ctx, `UPDATE users SET is_deleted = false, deleted_at = NULL WHERE id = $1`, userID)
slog.Error("unable to reverse the soft delete ", "error", err)
return apperrors.ErrInternalServer
Copy link
Collaborator

Choose a reason for hiding this comment

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

missing err check

return user, nil
}

func (ur *userRepository) AccountScheduledForDelete(ctx context.Context, tx *sqlx.Tx, userID int) error {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Logic seems correct, but such logic should be in service layer instead of repo

return nil
}

func (ur *userRepository) DeleteUser(tx *sqlx.Tx) error {
Copy link
Collaborator

Choose a reason for hiding this comment

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

rename function

return User{}, apperrors.ErrInternalServer
}
var user User
err = executer.QueryRowContext(ctx, getUserByIdQuery, userID).Scan(
Copy link
Collaborator

Choose a reason for hiding this comment

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

We could use GetUserById instead

@VishakhaSainani-Josh VishakhaSainani-Josh changed the base branch from main to feat/monthly-overview July 15, 2025 10:15
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.

6 participants