PM-33527 Database SQL scripts - #7616
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7616 +/- ##
==========================================
+ Coverage 60.55% 64.96% +4.41%
==========================================
Files 2142 2144 +2
Lines 94847 94897 +50
Branches 8487 8487
==========================================
+ Hits 57430 61648 +4218
+ Misses 35401 31142 -4259
- Partials 2016 2107 +91 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
@claude Please add a review |
This comment was marked as duplicate.
This comment was marked as duplicate.
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE This PR introduces the database foundation for GDPR-compliant event log cleanup: a new Code Review DetailsNo new actionable findings beyond those already addressed in earlier review rounds. |
mkincaid-bw
left a comment
There was a problem hiding this comment.
This PR creates a new table and modifies an existing table but there are no EF migrations to handle these changes for self-host/lite customers. Is that intentional?
| ON [dbo].[Event]([Date] DESC, [OrganizationId] ASC, [ActingUserId] ASC, [CipherId] ASC) INCLUDE ([ServiceAccountId], [GrantedServiceAccountId]); | ||
|
|
||
| GO | ||
| CREATE NONCLUSTERED INDEX [IX_Event_OrganizationId] |
There was a problem hiding this comment.
ℹ️ Just noting that Events for our cloud database are kept in Azure Table storage, not in the SQL database, so this index would only be applicable to self-host/lite customers.
| @@ -0,0 +1,15 @@ | |||
| CREATE PROCEDURE [dbo].[OrganizationEventCleanup_IncrementProgress] | |||
There was a problem hiding this comment.
This stored procedure name does not follow our naming conventions. This should be named something like OrganizationEventCleanup_UpdateProgress.
| [dbo].[OrganizationEventCleanup] | ||
| SET | ||
| [EventsDeletedCount] = [EventsDeletedCount] + @Delta, | ||
| [LastProgressAt] = SYSUTCDATETIME() |
There was a problem hiding this comment.
When updating a value in the database, the value should be generated in code and passed in as parameters to the stored procedure.. We should not be using built-in SQL functions like SYSUTCDATETIME or GETUTCDATE
| @@ -0,0 +1,14 @@ | |||
| CREATE PROCEDURE [dbo].[OrganizationEventCleanup_MarkCompleted] | |||
There was a problem hiding this comment.
This stored procedure name does not follow our naming conventions. This should be named something like OrganizationEventCleanup_UpdateCompleted.
| [CompletedAt] = SYSUTCDATETIME(), | ||
| [LastProgressAt] = SYSUTCDATETIME() |
There was a problem hiding this comment.
See previous comment regarding SYSUTCDATETIME
| @@ -0,0 +1,14 @@ | |||
| CREATE PROCEDURE [dbo].[OrganizationEventCleanup_MarkStarted] | |||
There was a problem hiding this comment.
This stored procedure name does not follow our naming conventions. This should be named something like OrganizationEventCleanup_UpdateStarted.
| [StartedAt] = COALESCE([StartedAt], SYSUTCDATETIME()), | ||
| [LastProgressAt] = SYSUTCDATETIME() |
There was a problem hiding this comment.
See previous comments regarding SYSUTCDATETIME
| @@ -0,0 +1,16 @@ | |||
| CREATE PROCEDURE [dbo].[OrganizationEventCleanup_RecordError] | |||
There was a problem hiding this comment.
This stored procedure name does not follow our naming conventions. This should be named something like OrganizationEventCleanup_UpdateError.
| SET | ||
| [Attempts] = [Attempts] + 1, | ||
| [LastError] = @Message, | ||
| [LastProgressAt] = SYSUTCDATETIME() |
There was a problem hiding this comment.
See previous comments regarding SYSUTCDATETIME
Yes because my thinking is if they are self-hosted and they want to delete their organization they should have the ability to just delete the table or database on their server since Events are stored in a table for self-hosted/lite customers. @mkincaid-bw |
…warden/server into dirt/pm-33527/db-orphaned-event-logs
|
@claude Please re-review |
|
Claude finished @prograhamming's task in 2m 49s —— View job Code Review — PM-33527 Database SQL scripts (re-review)
SummaryMost prior feedback has been addressed. The atomic claim implementation is solid, naming conventions are now consistent with the contributing guide, and the runaway ✅ Resolved since last review
🟠 Important — still open1. SonarCloud reliability gate still failing 2. No tests added
🟡 Minor3. Hardcoded 10-minute lease in 4. Filtered index would be cheaper for queue read pattern CREATE NONCLUSTERED INDEX [IX_OrganizationEventCleanup_Pending]
ON [dbo].[OrganizationEventCleanup]([CreationDate] ASC)
INCLUDE ([StartDate], [RevisionDate])
WHERE [CompletedDate] IS NULL;5. 6. No terminal-failure / max-attempts cutoff 7. Whitespace-only change to 8. The shape is much closer to mergeable. The SonarCloud reliability finding and the missing tests are the two items I would not ship without; the rest are polish. • Branch: |
|
@claude re-run the review |
|
Claude finished @prograhamming's task in 3m 34s —— View job Code Review — PM-33527 Database SQL scripts (re-review)
SummaryNearly all prior feedback has been addressed cleanly. The atomic claim works correctly, naming conventions match the SQL style guide, the One important new finding around the integration tests and the prior SonarCloud failure remain. ✅ Resolved since last review
🟠 Important — still open1. Integration tests will fail on EF providers (Postgres/MySQL/SQLite/MariaDB)
Because There's no existing helper to scope a
Either way the current state will break CI on the integration test workflow. 2. SonarCloud reliability gate still failing Latest SonarCloud run (2026-05-21) still reports 🟡 Minor3. Filtered index on the queue would stay small as completed rows accumulate
CREATE NONCLUSTERED INDEX [IX_OrganizationEventCleanup_Pending]
ON [dbo].[OrganizationEventCleanup]([CreationDate] ASC)
INCLUDE ([FailureCount], [StartDate], [RevisionDate])
WHERE [CompletedDate] IS NULL;Not blocking; volume is low enough either way. 4.
5.
6. Test
The atomic-claim shape is solid, the failure-cap closes the previous poison-row hole, and the lease const/parameter renames make the code much easier to follow. Item 1 (EF test runs) and 2 (SonarCloud) are the two things I'd want resolved before merge — the rest is polish. |
|
|
@prograhamming I was looking at this with my team and @withinfocus, and it's hard for us to review it only seeing the DB code. Can you please point us to the rest of the change so we can get the whole picture? |
@mkincaid-bw , #7517 is the server side pull request. I added the link in the description since it was left out while the other pull request linked to this one. The jira ticket also has a link to the GDPR document. Is this the information you need? We try to keep pull request reviews on the lighter side for easier reviews, but if there is a better way to handle this, we are open to ideas! |
|
It would be ideal to have these changes in one PR -- the DB work is concise and tightly-coupled to the logic, so the DB engineers' review really must have it to provide any accurate feedback, as would any AI review. This has brought up some questions from me as well, and not just about the DB work. Aside: you invoked direct claude.ai review here and bypassed our configured agent which operates rather differently; let's be sure #7616 (comment) (the sticky comment) is updating. I didn't know this would happen. Reviewing this PR together with #7517, I want to flag a design issue before more shape is locked in. await _organizationRepository.DeleteAsync(organization); // org gone
await _organizationEventCleanupRepository.CreateAsync(new OrganizationEventCleanup
{
OrganizationId = organization.Id, // org no longer exists
});If the second call fails then this gap remains. This needs to be one transaction. Second, This table is the right primitive to solve that class of problem, not just events. I would like to see this renamed to Future cross-system cleanups (Sends, attachments, Stripe) can ride the same checkpoint / retry / observability surface without another bespoke table. This is a big deal for us as we scale. Also, some minor things:
|
|
Closing in favor of a new pull request combining the database changes with the endpoint changes and updates as per feedback. New pull request: #7783 |




🎟️ Tracking
PM-33527
📔 Objective
In order to stay within GDPR compliance when a organization wants to be deleted we need to remove the event logs from Azure Table Storage. This PR is the database changes needed in order to delete the event logs using jobs and long running processes.
Server side changes are implemented in #7517
📸 Screenshots