Skip to content

feat(audit-logs): improve audit logs search - #52

Merged
wan0v merged 1 commit into
mainfrom
feat/audit-logs-search
Jun 16, 2026
Merged

feat(audit-logs): improve audit logs search#52
wan0v merged 1 commit into
mainfrom
feat/audit-logs-search

Conversation

@wan0v

@wan0v wan0v commented Jun 16, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Audit log filtering now supports text-based search across messages and user details (username, first name, last name), replacing the previous user-based filtering method.

@wan0v
wan0v requested review from Leviasm and LuftigerLuca June 16, 2026 19:28
@wan0v wan0v self-assigned this Jun 16, 2026
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

AuditLogFilterDto replaces the performedByUserId: String? field with searchText: String?. AuditLogSpecification.withFilter is updated to use this new field: it left-joins performedBy to UserEntity, sets query.distinct(true) for non-count queries, and applies a lowercased wildcard OR-predicate across message, username, firstname, and lastname.

Changes

Audit Log Text Search Filter

Layer / File(s) Summary
DTO field: performedByUserIdsearchText
application/.../auditlog/dto/filter/AuditLogFilterDto.kt
performedByUserId: String? is replaced with searchText: String? = null as the filter field on the DTO.
Specification: full-text search predicate with left-join
persistence/.../auditlog/specification/AuditLogSpecification.kt
Adds UserEntity and JoinType imports; uses the query parameter to call distinct(true) for non-count queries; left-joins performedBy to UserEntity; constructs a lowercased %…% pattern and applies an OR LIKE across message, username, firstname, and lastname; removes the old performedByUserId predicate block.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • Leviasm

Poem

🐇 A search by name, a search by text,
No userId needed — what comes next?
A wildcard hops through firstname, last,
Left-joining joins from present to past.
The rabbit approves this fuzzy quest! 🔍

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(audit-logs): improve audit logs search' directly and clearly summarizes the main change: enhancing the audit logs search functionality by replacing performedByUserId filtering with a searchText field and implementing text-based search across multiple fields.
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.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
persistence/src/main/kotlin/com/alleslocker/backend/persistence/auditlog/specification/AuditLogSpecification.kt (2)

23-45: Consider performance implications and input validation for text search.

The implementation uses LIKE with leading wildcards (%...%) across multiple fields via a LEFT JOIN, which has several performance characteristics to consider:

  1. Index usage: Leading wildcard patterns prevent database index usage, requiring full table scans on large audit log tables
  2. Join overhead: The LEFT JOIN to UserEntity adds query complexity
  3. Multiple LIKE operations: The OR predicate evaluates up to four LIKE operations per row
  4. DISTINCT overhead: While correctly skipped for count queries, distinct(true) adds result deduplication cost

Additionally, there's no length validation on searchText, which could allow very long inputs that amplify these performance costs.

Recommendations:

  • Add validation in the DTO or use case to limit searchText length (e.g., max 100 characters)
  • Monitor query performance on production-scale data
  • If search becomes a bottleneck, consider:
    • Database full-text search features (PostgreSQL tsvector, MySQL FULLTEXT)
    • Dedicated search solutions (Elasticsearch, OpenSearch)
    • Computed search columns with appropriate indexes
🤖 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
`@persistence/src/main/kotlin/com/alleslocker/backend/persistence/auditlog/specification/AuditLogSpecification.kt`
around lines 23 - 45, Add length validation on the searchText parameter in the
AuditLogSpecification filtering logic to prevent very long inputs from
amplifying performance costs. Modify the condition where searchText is processed
(in the takeIf or let block) to limit the maximum length to a reasonable value
such as 100 characters. This validation can be applied either by chaining an
additional takeIf condition that checks the length, or by validating at the
start of the let block where the pattern is created and the LIKE queries are
built. This will help mitigate the performance impact of the leading wildcard
LIKE operations across multiple fields in the LEFT JOIN.

26-32: Add integration tests to verify pagination count behavior with searchText filter.

The count query detection correctly checks for Long types (both java.lang.Long and primitive long), which is the standard pattern Spring Data JPA uses when executing count queries during pagination. The conditional application of distinct(true) is correct—it's only applied to content queries, not count queries, preventing count inaccuracies.

However, there are no existing tests for getAllAuditLogsPaged with the searchText filter. Consider adding integration tests to verify:

  1. totalElements count is accurate when using searchText with the LEFT join on performedBy
  2. The distinct behavior doesn't affect the count query results
  3. Pagination works correctly across multiple pages with filtered results
Test suggestion
`@Test`
fun `should return correct total count with searchText filter`() {
    // Given: Create audit logs with and without users, some matching search text
    // When: Filter with searchText and request page
    // Then: Verify totalElements count matches actual distinct results
}
🤖 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
`@persistence/src/main/kotlin/com/alleslocker/backend/persistence/auditlog/specification/AuditLogSpecification.kt`
around lines 26 - 32, Add integration tests for the `getAllAuditLogsPaged`
method in the AuditLogSpecification class to verify pagination behavior with the
searchText filter. Create test cases that verify: (1) the totalElements count is
accurate when filtering with searchText and the LEFT join on performedBy, (2)
the distinct behavior applied in the conditional check does not negatively
affect count query results, and (3) pagination correctly works across multiple
pages when searchText filter is applied. These tests should validate that the
count query detection logic (checking for Long and primitive long types) and the
conditional application of distinct(true) work together correctly to produce
accurate pagination results.
🤖 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
`@persistence/src/main/kotlin/com/alleslocker/backend/persistence/auditlog/specification/AuditLogSpecification.kt`:
- Line 34: The search text is being directly interpolated into the LIKE pattern
without escaping SQL wildcard characters, which will cause `%` and `_`
characters in user input to be treated as wildcards. In the line where pattern
is assigned with `"%${searchText.lowercase()}%"`, you need to escape special
characters in the searchText before interpolation by replacing `%` with `\%`,
`_` with `\_`, and `\` with `\\`. Then use the three-parameter overload of
CriteriaBuilder.like() that accepts an escape character parameter (typically
`\`) when building the query condition. Apply this same escaping logic to all
other occurrences where search text is used to build LIKE patterns in this
specification class.

---

Nitpick comments:
In
`@persistence/src/main/kotlin/com/alleslocker/backend/persistence/auditlog/specification/AuditLogSpecification.kt`:
- Around line 23-45: Add length validation on the searchText parameter in the
AuditLogSpecification filtering logic to prevent very long inputs from
amplifying performance costs. Modify the condition where searchText is processed
(in the takeIf or let block) to limit the maximum length to a reasonable value
such as 100 characters. This validation can be applied either by chaining an
additional takeIf condition that checks the length, or by validating at the
start of the let block where the pattern is created and the LIKE queries are
built. This will help mitigate the performance impact of the leading wildcard
LIKE operations across multiple fields in the LEFT JOIN.
- Around line 26-32: Add integration tests for the `getAllAuditLogsPaged` method
in the AuditLogSpecification class to verify pagination behavior with the
searchText filter. Create test cases that verify: (1) the totalElements count is
accurate when filtering with searchText and the LEFT join on performedBy, (2)
the distinct behavior applied in the conditional check does not negatively
affect count query results, and (3) pagination correctly works across multiple
pages when searchText filter is applied. These tests should validate that the
count query detection logic (checking for Long and primitive long types) and the
conditional application of distinct(true) work together correctly to produce
accurate pagination results.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ea4d0ffb-c95e-4e93-b7b1-46cc95270efc

📥 Commits

Reviewing files that changed from the base of the PR and between b328152 and f0a7642.

📒 Files selected for processing (2)
  • application/src/main/kotlin/com/alleslocker/backend/application/auditlog/dto/filter/AuditLogFilterDto.kt
  • persistence/src/main/kotlin/com/alleslocker/backend/persistence/auditlog/specification/AuditLogSpecification.kt

@wan0v
wan0v merged commit 7ae75ba into main Jun 16, 2026
5 checks passed
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.

2 participants