Skip to content

Implement JPA auditing and soft delete supportFinal shopmate pr#132

Open
SRokesh-28 wants to merge 12 commits into
omatheusmesmo:mainfrom
SRokesh-28:final-shopmate-pr
Open

Implement JPA auditing and soft delete supportFinal shopmate pr#132
SRokesh-28 wants to merge 12 commits into
omatheusmesmo:mainfrom
SRokesh-28:final-shopmate-pr

Conversation

@SRokesh-28
Copy link
Copy Markdown

@SRokesh-28 SRokesh-28 commented May 17, 2026

Changes made

Closes: #23

  • Enabled Spring Data JPA auditing

  • Added @EnableJpaAuditing in ShoppMateApplication

  • Added auditing annotations to BaseAuditableEntity

  • Added auditing support to DomainEntity

  • Implemented soft delete using @SQLDelete and @Where

  • Applied soft delete to:

    • Category
    • Item
    • ListItem
    • Unit
    • User
    • ShoppingList
    • ListPermission

This improves entity lifecycle tracking and prevents permanent deletion.

Summary by CodeRabbit

  • New Features
    • Automatic auditing now tracks when entities are created and last modified across the application.
    • Soft-delete functionality has been implemented for shopping lists, items, categories, units, and user accounts—records are marked as deleted rather than permanently removed, allowing for data recovery.

Review Change Stack

SRokesh-28 added 10 commits May 17, 2026 17:46
Added Spring Data JPA auditing support annotations to BaseAuditableEntity.

Changes:

* Added @CreatedDate for automatic creation timestamp tracking
* Added @LastModifiedDate for automatic update timestamp tracking
* Added @EntityListeners(AuditingEntityListener.class) to enable auditing event handling
* Added required Spring Data JPA auditing imports
Enabled Spring Data JPA auditing support in the application.

Changes:

* Added @EnableJpaAuditing to the main Spring Boot application class
* Activated automatic auditing support for @CreatedDate and @LastModifiedDate annotations
* Enabled automatic population of audit fields for entities extending BaseAuditableEntity
Added Spring Data JPA auditing support to DomainEntity.

Changes:

* Added @EntityListeners(AuditingEntityListener.class)
* Added @CreatedDate annotation for automatic creation timestamp tracking
* Added @LastModifiedDate annotation for automatic update timestamp tracking
* Enabled auditing support for entities extending DomainEntity
Added Hibernate soft delete support to the Category entity.

Changes:

* Added @SQLDelete annotation to update the deleted flag instead of physically removing records
* Added @where annotation to automatically filter out deleted records from queries
* Enabled logical delete behavior for the categories table
Added Hibernate soft delete support to the Item entity.

Changes:

* Added @SQLDelete annotation to update the deleted flag instead of physically removing records
* Added @where annotation to automatically filter out deleted records from queries
* Enabled logical delete behavior for the items table
Added Hibernate soft delete support to the ListItem entity.

Changes:

* Added @SQLDelete annotation to update the deleted flag instead of physically removing records
* Added @where annotation to automatically filter out deleted records from queries
* Enabled logical delete behavior for the list_items table
Added Hibernate soft delete support to the Unit entity.

Changes:

* Added @SQLDelete annotation to update the deleted flag instead of physically removing records
* Added @where annotation to automatically filter out deleted records from queries
* Enabled logical delete behavior for the units table
Added Hibernate soft delete support to the User entity.

Changes:

* Added @SQLDelete annotation to update the deleted flag instead of physically removing records
* Added @where annotation to automatically filter out deleted records from queries
* Enabled logical delete behavior for the users table
Added Hibernate soft delete support to the ListPermission entity.

Changes:

* Added @SQLDelete annotation to update the deleted flag instead of physically removing records
* Added @where annotation to automatically filter out deleted records from queries
* Enabled logical delete behavior for the list_user_permissions table
Added Hibernate soft delete support to the ShoppingList entity.

Changes:

* Added @SQLDelete annotation to update the deleted flag instead of physically removing records
* Added @where annotation to automatically filter out deleted records from queries
* Enabled logical delete behavior for the lists table
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 17, 2026

📝 Walkthrough

Walkthrough

This PR introduces two foundational infrastructure features: Spring Data JPA auditing to automatically track entity creation and modification timestamps, and Hibernate soft-delete semantics to mark records as deleted instead of physically removing them from the database.

Changes

Data Persistence Infrastructure

Layer / File(s) Summary
Spring Data JPA auditing configuration
backend/src/main/java/com/omatheusmesmo/shoppmate/ShoppMateApplication.java, backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/BaseAuditableEntity.java, backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/DomainEntity.java
Application-level @EnableJpaAuditing is registered, and base entity classes register AuditingEntityListener with field-level @CreatedDate and @LastModifiedDate annotations to automatically populate timestamp columns.
Soft-delete implementation across entities
backend/src/main/java/com/omatheusmesmo/shoppmate/category/entity/Category.java, backend/src/main/java/com/omatheusmesmo/shoppmate/item/entity/Item.java, backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ListItem.java, backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ListPermission.java, backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ShoppingList.java, backend/src/main/java/com/omatheusmesmo/shoppmate/unit/entity/Unit.java, backend/src/main/java/com/omatheusmesmo/shoppmate/user/entity/User.java
All JPA entities are annotated with @SQLDelete (to update a deleted column instead of physically deleting rows) and @Where (to exclude soft-deleted records from queries).

🎯 2 (Simple) | ⏱️ ~12 minutes

🐰 With audits to track the when,
And soft deletes to undo again,
Your data's safe from the void,
No records permanently destroyed!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title mentions the two main changes (JPA auditing and soft delete), but contains extraneous text 'Final shopmate pr' that appears to be noise or unintended duplication. Consider revising the title to 'Implement JPA auditing and soft delete support' to remove the redundant 'Final shopmate pr' suffix and improve clarity.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

🤖🎉 Thank you for your contribution! Your pull request has been submitted successfully. A maintainer from the team will review it as soon as possible. We appreciate your support in making this project better!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (7)
backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ListPermission.java (1)

16-17: ⚡ Quick win

Adjust import ordering for added Hibernate annotations.

Keep third-party imports grouped before project package imports.

As per coding guidelines, "Order imports as: java., jakarta., org.springframework., third-party, project packages in com.omatheusmesmo.shoppmate. domain".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ListPermission.java`
around lines 16 - 17, The new Hibernate annotation imports in ListPermission
(org.hibernate.annotations.SQLDelete and org.hibernate.annotations.Where) are
out of the prescribed import order; reorder the imports so java.*, jakarta.*,
org.springframework.* come first, then third-party imports (org.hibernate.*) and
finally project package imports under com.omatheusmesmo.shoppmate.* in the
ListPermission.java import block to comply with the project's import ordering
guideline.
backend/src/main/java/com/omatheusmesmo/shoppmate/item/entity/Item.java (1)

15-16: ⚡ Quick win

Reorder newly added Hibernate imports.

Place third-party imports before project imports per repository ordering rules.

As per coding guidelines, "Order imports as: java., jakarta., org.springframework., third-party, project packages in com.omatheusmesmo.shoppmate. domain".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/main/java/com/omatheusmesmo/shoppmate/item/entity/Item.java`
around lines 15 - 16, The two Hibernate imports
(org.hibernate.annotations.SQLDelete and org.hibernate.annotations.Where) are
third-party and must be placed before the project package imports; update the
import ordering in Item.java so that java.*/jakarta.*/org.springframework.*
remain first, then the org.hibernate.* imports, and only after them the
com.omatheusmesmo.* project imports—locate the imports around the Item class
declaration and move the SQLDelete and Where lines accordingly.
backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/DomainEntity.java (1)

11-15: ⚡ Quick win

Align import block with project order.

The new imports should be grouped in the required package order.

As per coding guidelines, "Order imports as: java., jakarta., org.springframework., third-party, project packages in com.omatheusmesmo.shoppmate. domain".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/DomainEntity.java`
around lines 11 - 15, Reorder the import block in DomainEntity.java to follow
project guidelines: place java.* imports first (if any), then jakarta.* (e.g.,
jakarta.persistence.EntityListeners), then org.springframework.* (e.g.,
org.springframework.data.annotation.CreatedDate,
org.springframework.data.annotation.LastModifiedDate,
org.springframework.data.jpa.domain.support.AuditingEntityListener), followed by
any third-party and then project packages; update the import section around the
DomainEntity class so the imports are grouped and ordered exactly as specified.
backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ShoppingList.java (2)

19-20: ⚡ Quick win

Place new Hibernate imports in the configured order.

Reorder this block to keep third-party imports before com.omatheusmesmo.shoppmate.* imports.

As per coding guidelines, "Order imports as: java., jakarta., org.springframework., third-party, project packages in com.omatheusmesmo.shoppmate. domain".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ShoppingList.java`
around lines 19 - 20, The import order in ShoppingList.java is incorrect: move
the Hibernate imports (org.hibernate.annotations.SQLDelete and
org.hibernate.annotations.Where) so that third-party imports come before the
project's own packages (com.omatheusmesmo.shoppmate.*); update the import block
to follow the rule "java.*, jakarta.*, org.springframework.*, third-party,
com.omatheusmesmo.shoppmate.*" so the org.hibernate.* entries appear above any
com.omatheusmesmo.shoppmate.* imports in the file.

23-24: Consider indexing for soft-delete query paths.

Since deleted = false becomes a global filter, ensure DB indexes support common access paths (often composite indexes, not just deleted alone) to avoid regressions at scale.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ShoppingList.java`
around lines 23 - 24, The soft-delete filter on the ShoppingList entity
(annotations `@SQLDelete` and `@Where`, table "lists", boolean field "deleted") will
make queries include "deleted = false" globally — add appropriate DB indexes via
a migration to cover these common access paths (e.g., composite indexes that
include deleted plus the frequent query columns such as ownerId/userId,
created_at, or whatever columns your queries filter/sort by) rather than a
standalone deleted index; update DB migration scripts to create composite
indexes like (owner_id, deleted) or (user_id, deleted, created_at) matching the
actual repository queries, and ensure the index names and migration apply to the
"lists" table so the global filter remains performant.
backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/BaseAuditableEntity.java (1)

12-15: ⚡ Quick win

Reorder imports to match repository convention.

Move imports to java.*, jakarta.*, org.springframework.*, third-party, then com.omatheusmesmo.shoppmate.*.

As per coding guidelines, "Order imports as: java., jakarta., org.springframework., third-party, project packages in com.omatheusmesmo.shoppmate. domain".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/BaseAuditableEntity.java`
around lines 12 - 15, Reorder the import block in BaseAuditableEntity so it
follows the repository convention: java.* first (if any), then jakarta.* (e.g.,
jakarta.persistence.EntityListeners), then org.springframework.* (e.g.,
org.springframework.data.annotation.CreatedDate,
org.springframework.data.annotation.LastModifiedDate,
org.springframework.data.jpa.domain.support.AuditingEntityListener), then any
third‑party, then project packages under com.omatheusmesmo.shoppmate.*; adjust
the existing imports accordingly to match that sequence.
backend/src/main/java/com/omatheusmesmo/shoppmate/unit/entity/Unit.java (1)

13-14: ⚡ Quick win

Replace deprecated @Where with @SQLRestriction for forward compatibility with Hibernate 6.3+.

@Where is deprecated in Hibernate 6.3 and later; @SQLRestriction is the recommended replacement. Update the import and annotation:

Suggested update
-import org.hibernate.annotations.Where;
+import org.hibernate.annotations.SQLRestriction;
@@
-@Where(clause = "deleted = false")
+@SQLRestriction("deleted = false")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/main/java/com/omatheusmesmo/shoppmate/unit/entity/Unit.java`
around lines 13 - 14, Replace the deprecated `@Where` annotation on the Unit
entity with `@SQLRestriction` for Hibernate 6.3+ compatibility: remove the import
of org.hibernate.annotations.Where, add the import
org.hibernate.annotations.SQLRestriction, and replace the `@Where`(clause =
"deleted = false") annotation on the Unit class with `@SQLRestriction`(value =
"deleted = false") while keeping the existing `@SQLDelete`(sql = "UPDATE units SET
deleted = true WHERE id=?") annotation intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/BaseAuditableEntity.java`:
- Around line 29-35: The audit fields in BaseAuditableEntity (createdAt,
updatedAt) must not be mutable from application code: remove or make any public
setters for createdAt and updatedAt non-public (private or protected) so callers
cannot override them, and mark createdAt as non-updatable at the JPA level by
adding updatable = false to its `@Column` (e.g., `@Column`(name = "created_at",
updatable = false)). Keep the `@CreatedDate` and `@LastModifiedDate` annotations so
the auditing framework can still set the values.

In
`@backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/DomainEntity.java`:
- Around line 32-38: The audit fields in DomainEntity (createdAt with
`@CreatedDate` and updatedAt with `@LastModifiedDate`) are currently writable
because the class-level `@Setter` exposes them; remove their public setters by
disabling Lombok setters for these fields (e.g., `@Setter`(AccessLevel.NONE) on
createdAt and updatedAt) or otherwise make their setters non-public, and mark
createdAt as non-updatable in the JPA mapping (add updatable = false on the
`@Column` for createdAt) so callers cannot overwrite audited timestamps.

---

Nitpick comments:
In `@backend/src/main/java/com/omatheusmesmo/shoppmate/item/entity/Item.java`:
- Around line 15-16: The two Hibernate imports
(org.hibernate.annotations.SQLDelete and org.hibernate.annotations.Where) are
third-party and must be placed before the project package imports; update the
import ordering in Item.java so that java.*/jakarta.*/org.springframework.*
remain first, then the org.hibernate.* imports, and only after them the
com.omatheusmesmo.* project imports—locate the imports around the Item class
declaration and move the SQLDelete and Where lines accordingly.

In
`@backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ListPermission.java`:
- Around line 16-17: The new Hibernate annotation imports in ListPermission
(org.hibernate.annotations.SQLDelete and org.hibernate.annotations.Where) are
out of the prescribed import order; reorder the imports so java.*, jakarta.*,
org.springframework.* come first, then third-party imports (org.hibernate.*) and
finally project package imports under com.omatheusmesmo.shoppmate.* in the
ListPermission.java import block to comply with the project's import ordering
guideline.

In
`@backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ShoppingList.java`:
- Around line 19-20: The import order in ShoppingList.java is incorrect: move
the Hibernate imports (org.hibernate.annotations.SQLDelete and
org.hibernate.annotations.Where) so that third-party imports come before the
project's own packages (com.omatheusmesmo.shoppmate.*); update the import block
to follow the rule "java.*, jakarta.*, org.springframework.*, third-party,
com.omatheusmesmo.shoppmate.*" so the org.hibernate.* entries appear above any
com.omatheusmesmo.shoppmate.* imports in the file.
- Around line 23-24: The soft-delete filter on the ShoppingList entity
(annotations `@SQLDelete` and `@Where`, table "lists", boolean field "deleted") will
make queries include "deleted = false" globally — add appropriate DB indexes via
a migration to cover these common access paths (e.g., composite indexes that
include deleted plus the frequent query columns such as ownerId/userId,
created_at, or whatever columns your queries filter/sort by) rather than a
standalone deleted index; update DB migration scripts to create composite
indexes like (owner_id, deleted) or (user_id, deleted, created_at) matching the
actual repository queries, and ensure the index names and migration apply to the
"lists" table so the global filter remains performant.

In
`@backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/BaseAuditableEntity.java`:
- Around line 12-15: Reorder the import block in BaseAuditableEntity so it
follows the repository convention: java.* first (if any), then jakarta.* (e.g.,
jakarta.persistence.EntityListeners), then org.springframework.* (e.g.,
org.springframework.data.annotation.CreatedDate,
org.springframework.data.annotation.LastModifiedDate,
org.springframework.data.jpa.domain.support.AuditingEntityListener), then any
third‑party, then project packages under com.omatheusmesmo.shoppmate.*; adjust
the existing imports accordingly to match that sequence.

In
`@backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/DomainEntity.java`:
- Around line 11-15: Reorder the import block in DomainEntity.java to follow
project guidelines: place java.* imports first (if any), then jakarta.* (e.g.,
jakarta.persistence.EntityListeners), then org.springframework.* (e.g.,
org.springframework.data.annotation.CreatedDate,
org.springframework.data.annotation.LastModifiedDate,
org.springframework.data.jpa.domain.support.AuditingEntityListener), followed by
any third-party and then project packages; update the import section around the
DomainEntity class so the imports are grouped and ordered exactly as specified.

In `@backend/src/main/java/com/omatheusmesmo/shoppmate/unit/entity/Unit.java`:
- Around line 13-14: Replace the deprecated `@Where` annotation on the Unit entity
with `@SQLRestriction` for Hibernate 6.3+ compatibility: remove the import of
org.hibernate.annotations.Where, add the import
org.hibernate.annotations.SQLRestriction, and replace the `@Where`(clause =
"deleted = false") annotation on the Unit class with `@SQLRestriction`(value =
"deleted = false") while keeping the existing `@SQLDelete`(sql = "UPDATE units SET
deleted = true WHERE id=?") annotation intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0ab4bb4e-bfda-4858-a76e-14024dcd058b

📥 Commits

Reviewing files that changed from the base of the PR and between e571b77 and c89557c.

📒 Files selected for processing (10)
  • backend/src/main/java/com/omatheusmesmo/shoppmate/ShoppMateApplication.java
  • backend/src/main/java/com/omatheusmesmo/shoppmate/category/entity/Category.java
  • backend/src/main/java/com/omatheusmesmo/shoppmate/item/entity/Item.java
  • backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ListItem.java
  • backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ListPermission.java
  • backend/src/main/java/com/omatheusmesmo/shoppmate/list/entity/ShoppingList.java
  • backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/BaseAuditableEntity.java
  • backend/src/main/java/com/omatheusmesmo/shoppmate/shared/domain/DomainEntity.java
  • backend/src/main/java/com/omatheusmesmo/shoppmate/unit/entity/Unit.java
  • backend/src/main/java/com/omatheusmesmo/shoppmate/user/entity/User.java

- Added @Setter(AccessLevel.NONE) to audit fields
- Prevent manual modification of createdAt and updatedAt
- Ensures Spring Data JPA auditing integrity
- Added @Setter(AccessLevel.NONE) to createdAt and updatedAt
- Prevent manual modification of audit fields
- Added updatable = false for createdAt column
- Ensures Spring Data JPA auditing consistency
@matheusandre1
Copy link
Copy Markdown
Collaborator

Create a service to abstract this and then do a squash commit.

@SRokesh-28
Copy link
Copy Markdown
Author

Hi @matheusandre1, I wanted to clarify the abstraction suggestion before making changes.

Since @SQLDelete requires entity-specific table names (categories, items, users, etc.), I can move shared fields like deleted into a common base class, but the SQL annotations themselves may still need to remain on each entity.

Would you prefer:

  1. A shared base abstraction for common soft-delete fields only
  2. A service-layer abstraction
  3. Another approach you had in mind

I want to make sure the implementation aligns with your intended design before updating the PR.

@matheusandre1
Copy link
Copy Markdown
Collaborator

Updates are repeated, in the case of design and implementation, it depends on what you do, it doesn't need to be anything complex, my review is only for code repetition.

@SRokesh-28
Copy link
Copy Markdown
Author

Hi @matheusandre1, thanks for the clarification. I reviewed the implementation again and wanted to confirm I understood your feedback correctly.

I kept @SQLDelete in each entity because the table names are entity-specific, and from my understanding the shared soft-delete field structure is already handled through the parent entities.

From your comment about repeated updates/code repetition, are you referring to other duplicated parts (for example common auditing or soft-delete related logic across DomainEntity and BaseAuditableEntity), or is there another repeated pattern you had in mind?

I just want to make sure the next update aligns with your expectation before I refactor further.

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.

Feature: Automated Auditing and Soft Delete implementation

2 participants