Repository navigation
Date-based token endpoint, soft-delete contacts for RESTORE, redact presigned URLs - #3
Merged
Merged
Conversation
added 5 commits
October 21, 2026 16:08
The v1 token path is being superseded by /oauth/2026-09/token; the request and response shapes are unchanged, so only the URL moves (into a shared constant).
…credential Journal file URLs are presigned S3 URLs whose query string is the credential. A failed download previously gave no hint which file failed, and logging the URL to fix that would leak it. downloadJournalFile now rethrows with status and origin+path only, so the worker's failed handler logs a safe, useful message.
A RESTORE journal event only carries the properties that action changed, so recreating a hard-deleted contact from it left the row mostly empty. DELETE now sets deletedAt (and writes a tombstone for unseen contacts so an older out-of-order CREATE/UPDATE can't resurrect it), upserts clear deletedAt, and the contacts API hides deleted rows. MERGE still hard-deletes merged IDs since they never come back.
zprobs
marked this pull request as ready for review
October 21, 2026 20:52
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/oauth/2026-09/tokeninstead of/oauth/v1/token, so the example uses date-based versions throughout. The request body and theaccess_token/expires_inresponse fields are unchanged. The install and refresh flow (authorization code) is untouched.RESTOREevent carries only the properties changed by the restore itself, usually none. With hard deletes, a restored contact came back empty.DELETEnow setsdeletedAtand keeps the row, andRESTOREclears it, so the contact's stored data returns.DELETEfor a contact we've never seen writes a tombstone, so an older out-of-orderCREATEprocessed later by another worker can't resurrect it.MERGEstill hard-deletes merged-away contacts, because merges are permanent.POST .../snapshots/<ver>/crm).?<redacted>. Logging the full URL would leak the signature. The README notes this.BRAVE Checklist
Backwards compatibility: needs a schema update. Existing checkouts must re-run
npm run db-init(prisma db push) to add the nullableContact.deletedAtcolumn, and the README says so. Existing rows are unaffected (deletedAtstays NULL).Roll(out/back) plan: example app with no deployment. Revert the PR to undo. The extra column is harmless if left in place.
Automated testing:
__tests__/processor.test.ts: 8 integration tests against real Postgres covering the DELETE/RESTORE round trip, an out-of-order UPDATE after a DELETE, a tombstone blocking an older CREATE, a newer UPDATE or SNAPSHOT un-deleting, MERGE still hard-deleting, andGET /api/contactsexcluding soft-deleted rows. They run in CI against the workflow'swebhooks_journal_testDB and skip whenDATABASE_URLdoesn't point at a_testdatabase.__tests__/download.test.tsand__tests__/utils.test.ts: redaction tests.Verification plan: ran the app locally against prod.
/oauth/2026-09/token, and journal polling with that token worked.Soft-deleted contact …: it disappeared from/api/contacts, but its email and name stayed in the row.Restored contact …: it reappeared with its email and name, which the RESTORE event did not carry.Expect dependencies to fail: if the token endpoint fails, the existing error path surfaces it, unchanged. If a journal-file download fails, the job fails with a message naming the file without its credential, and BullMQ's existing retry and backoff applies.