Skip to content

bug: fix createLikes notification logic and avoid mutating updateTransactionById edits - #129

Open
devin-ai-integration[bot] wants to merge 2 commits into
developfrom
devin/1782858236-fix-database-bugs
Open

devin-ai-integration[bot] wants to merge 2 commits into
developfrom
devin/1782858236-fix-database-bugs

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jun 30, 2026

Copy link
Copy Markdown

Summary

Bug fixes in backend/database.ts.

createLikes — always-true condition made branches dead code. The guard userId !== senderId || userId !== receiverId is always true (one userId can't equal both), so the else if/else never ran. Changed ||&& and corrected which party each branch notifies:

-/* istanbul ignore next */
-if (userId !== senderId || userId !== receiverId) {
+if (userId !== senderId && userId !== receiverId) {
   createLikeNotification(senderId, ...);
   createLikeNotification(receiverId, ...);
 } else if (userId === senderId) {
-  createLikeNotification(senderId, ...);   // notified self
+  createLikeNotification(receiverId, ...); // liker is sender → notify receiver
 } else {
-  createLikeNotification(receiverId, ...); // notified self
+  createLikeNotification(senderId, ...);   // liker is receiver → notify sender
 }

Removed the /* istanbul ignore next */ since the branches are now reachable.

createComments — identical bug. createComments had the exact same always-true condition and self-notifying branches. Applied the same fix (flagged by Devin Review).

updateTransactionById — mutated its edits argument. It set status directly on the caller-supplied Partial<Transaction> (which is req.body at the call site). Now builds a local copy so the input is untouched; behavior (status set to complete only inside the isRequestTransaction branch) is preserved:

+const finalEdits = { ...edits };
 if (isRequestTransaction(transaction)) {
   ...
-  edits.status = TransactionStatus.complete;
+  finalEdits.status = TransactionStatus.complete;
 }
-db.get(TRANSACTION_TABLE).find(transaction).assign(edits).write();
+db.get(TRANSACTION_TABLE).find(transaction).assign(finalEdits).write();

yarn types (tsc --noEmit) and prettier check pass.

Link to Devin session: https://app.devin.ai/sessions/b5be0ee641734dc091f3756e5d9656a3
Requested by: @parkerwindsurf


Devin Review

Status Commit
⚪ Not started

Run Devin Review

Open in Devin Review (Staging)
Open in Devin Review

…Id edits

Co-Authored-By: Parker Drew <parker.drew@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Devin Review found 4 potential issues.

Open in Devin Review

Comment thread backend/database.ts
Comment thread backend/database.ts
const sender = getUserById(senderId);
const receiver = getUserById(receiverId);

const finalEdits = { ...edits };

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

📝 Info: Shallow copy of edits prevents mutation of caller's object

The change at backend/database.ts:584 creates finalEdits = { ...edits } so that when finalEdits.status is set to TransactionStatus.complete on line 590, the original edits object passed by the caller is not mutated. This matters because updateTransactionById is called from backend/transaction-routes.ts:179 with req.body, and mutating req.body could cause subtle issues if it's referenced again later. The fix is correct and well-scoped.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread backend/database.ts
Comment on lines +629 to 636
if (userId !== senderId && userId !== receiverId) {
createLikeNotification(senderId, transactionId, like.id);
createLikeNotification(receiverId, transactionId, like.id);
} else if (userId === senderId) {
createLikeNotification(senderId, transactionId, like.id);
} else {
createLikeNotification(receiverId, transactionId, like.id);
} else {
createLikeNotification(senderId, transactionId, like.id);
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

📝 Info: Original createLikes condition was always true, making branches unreachable

The old condition userId !== senderId || userId !== receiverId at backend/database.ts:628 (LEFT) was a tautology whenever senderId !== receiverId (which is always true since a user cannot transact with themselves). This means the old code always entered the first branch, sending notifications to both parties regardless of who liked the transaction. The fix to && correctly makes the condition false when the liker is either the sender or receiver, allowing the sub-branches to execute. The swapped notification targets in lines 632-635 are also correct: when the liker is the sender, only the receiver should be notified, and vice versa.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread backend/database.ts
Co-Authored-By: Parker Drew <parker.drew@cognition.ai>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Devin Review found 2 new potential issues.

Open in Devin Review

Comment thread backend/database.ts
Comment on lines +629 to 636
if (userId !== senderId && userId !== receiverId) {
createLikeNotification(senderId, transactionId, like.id);
createLikeNotification(receiverId, transactionId, like.id);
} else if (userId === senderId) {
createLikeNotification(senderId, transactionId, like.id);
} else {
createLikeNotification(receiverId, transactionId, like.id);
} else {
createLikeNotification(senderId, transactionId, like.id);
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🚩 Condition fix changes notification behavior for all like/comment actions

The old condition userId !== senderId || userId !== receiverId was always true when sender ≠ receiver (which is the normal case for transactions), meaning both sender and receiver were always notified — even when one of them was the person performing the action. The else if / else branches were dead code (confirmed by /* istanbul ignore next */ markers that were removed).

The new && condition means the first branch only fires for third-party users. When the liker/commenter is the sender or receiver, only the OTHER party is now notified. This is a behavioral change: previously both parties always got notifications; now participants don't get self-notifications.

This is almost certainly the intended fix, but it's worth confirming there are no E2E tests or frontend logic that depend on self-notifications being generated (e.g., notification count assertions in Cypress tests at cypress/tests/).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Confirmed intended — this matches the behavior requested in the task. Checked for dependencies:

  • CI (.github/workflows/main.yml) only runs yarn test:unit:ci (vitest); the Cypress E2E suite isn't run in CI. All 44 unit tests pass, including likes.test.ts, comments.test.ts, and notifications.test.ts.
  • The E2E notification specs (cypress/tests/ui/notifications.spec.ts) assert on the other party's notification counts (third-party liker → both notified; participant liker → other party notified), not on self-notifications, so they're consistent with this change.

Comment thread backend/database.ts
Comment on lines +629 to 636
if (userId !== senderId && userId !== receiverId) {
createLikeNotification(senderId, transactionId, like.id);
createLikeNotification(receiverId, transactionId, like.id);
} else if (userId === senderId) {
createLikeNotification(senderId, transactionId, like.id);
} else {
createLikeNotification(receiverId, transactionId, like.id);
} else {
createLikeNotification(senderId, transactionId, like.id);
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

📝 Info: Edge case: sender equals receiver is not guarded

If a transaction somehow has senderId === receiverId, the first branch (userId !== senderId && userId !== receiverId) would be false when the user is that person, falling to else if (userId === senderId) which would call createLikeNotification(receiverId, ...) — effectively a self-notification. This is the same behavior as before the change, so it's not a regression. In practice, createTransaction at backend/database.ts:528 takes separate userId and receiverId, so this edge case shouldn't occur in normal operation.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed — not a regression (same behavior as before for the senderId === receiverId case), and transactions are always created with distinct sender/receiver, so it won't occur in practice. Leaving as-is to keep the change scoped.

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.

0 participants