Release 3.8.2 to main#438
Conversation
add bengali language translation on dynamic forms
* fix: aam-2313 phone number leading with zero - removed zero * fix: allow concurrent sessions for admin, superadmin, and supervisor roles Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: added admin and superadmin for the condition --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ession logout redisTemplate has Jackson2JsonRedisSerializer<User> as value serializer, so reading the plain-string jti: value caused a deserialization failure (statusCode 5000). jti: keys are written via stringRedisTemplate at login, so reads and deletes must also use stringRedisTemplate — restoring the behaviour from commit 80fa0e5 that was accidentally reverted in #423. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix role name from 'admin' to 'provideradmin' to match actual DB value - Add concurrent session exemption to superUserAuthenticate so SuperAdmin can log in from multiple tabs without being blocked Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix: use stringRedisTemplate for jti: key read/delete in concurrent session
…ssword Feature/handel multiple attempt password
Redis keys were stored on MMU login with 30-day TTL but never deleted on logout. Added cleanup in userLogout() so stale camp config does not persist after the MMU session ends. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lets a device on the same network discover the API's LAN IP and port without needing it typed in manually, and bumps version to 3.8.2.
Sn/token expiry
fix issue of feature multiple login attempt
Fix login issue multiple login
….8.2 # Conflicts: # src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java # src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java
Merge release-3.8.1, main ti release-3.8.2
Saurav's PR #431 added a "Remaining attempts: N" message on failed login to warn users before account lockout. Port this into the refactored handleFailedLoginAttempt helper so both userAuthenticate and superUserAuthenticate keep the behavior after merging release-3.8.1's account-lock refactor into release-3.8.2.
The merge of release-3.8.1's account-lock refactor into release-3.8.2 replaced Saurav Mishra's inline multiple-login-attempt logic (PR #426/#431/#432) with the refactored handlePasswordValidationAndLocking helper. The refactor kept the "Remaining attempts" warning but dropped the final lockout message text, falling back to the unrelated generateLockoutErrorMessage used for already-locked accounts. Restore the exact lockout message from PR #432 so the refactored helper preserves both branches' intended behavior.
Merging #431 commit
📝 WalkthroughWalkthroughThe changes add GPS demographic propagation, Bengali dynamic-form translations, role-based authentication session handling, a LAN connectivity endpoint, revised health and JWT behavior, and related configuration updates. ChangesIdentity data propagation
Bengali dynamic form translation
Authentication and session handling
Runtime and API configuration
Estimated code review effort: 4 (Complex) | ~45 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Checkov (3.3.8)pom.xmlTraceback (most recent call last): 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. Comment |
|
|
||
| public static String getLanIPAddress() { | ||
| try (DatagramSocket socket = new DatagramSocket()) { | ||
| socket.connect(InetAddress.getByName("8.8.8.8"), 10002); |
* fix(health): stop reporting MySQL as DOWN when SELECT 1 succeeds checkDatabaseConnectivity() was deriving the status field from the background diagnostic severity (pool usage, long transactions, deadlocks) even after the live SELECT 1 connectivity check succeeded - so a CRITICAL finding from the background scan (e.g. connection pool >95% full) caused /common-api/health to report mysql.status=DOWN despite the database being fully reachable and serving real queries (confirmed: login worked fine while health reported DOWN). status now reflects connectivity only (UP if SELECT 1 succeeds, DOWN only on an actual connection failure); severity continues to surface the background diagnostic findings independently, so capacity/performance warnings are still visible without being misreported as an outage. Removed resolveDatabaseStatus() and the now-unused STATUS_DEGRADED constant, both made dead by this change. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(beneficiary): enhance GPS data handling in beneficiary demographics and address flows * Update `gpsTimestamp` in `BeneficiaryDemographicsModel` and `Address` from `Timestamp` to `Long` to support epoch-millisecond values received from clients. * Add missing GPS-related fields (`latitude`, `longitude`, `digipin`, `isGpsUnavailable`, and `gpsUnavailableReason`) to the `Address` DTO for complete GPS data transfer. * Extend mapper decorators (`BenCompleteDetailMapperDecorator`, `CommonIdentityMapperDecorator`, and `IdentityBenEditMapperDecorator`) to propagate GPS information across beneficiary and identity workflows. * fix: add missing $ to resolve GEN_BENEFICIARY_IDS_API_URL in docker properties Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Sehjot Singh Pannu <sehjot.singh@unthinkable.co>
|
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java (1)
311-327: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy liftKeep credential failures externally indistinguishable.
These messages reveal that a username exists, its remaining attempts, and lock status; unknown usernames still receive only the generic error. Since
IEMRException.getMessage()is propagated, this enables account enumeration. Return one generic authentication error externally and surface attempt guidance only through a non-enumerable flow.🤖 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 `@src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java` around lines 311 - 327, The failed-login branches in the relevant authentication method currently expose account existence, remaining attempts, and lock status through IEMRException messages. Replace all externally propagated credential-failure messages with one generic authentication error for both known and unknown usernames, while moving any attempt guidance to a non-enumerable internal flow such as logging without username-specific disclosure.
🤖 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 `@src/main/java/com/iemr/common/controller/users/IEMRAdminController.java`:
- Around line 182-186: Remove the redundant failed-attempt reset and save after
successful authentication in IEMRAdminController.java:182-186, leaving
account-state persistence to IEMRAdminUserServiceImpl. Remove the raw save(User)
contract from IEMRAdminUserService.java:136 and its repository delegation from
IEMRAdminUserServiceImpl.java:1388-1391; update any resulting references as
needed.
- Around line 195-210: The concurrent-session exemption currently inspects only
the first role mapping and may use an unpopulated collection. Update the checks
around IEMRAdminController’s login flow and the path near userExitsCheck() to
reload and inspect complete role mappings, defining and consistently applying
whether any or all roles must be exempt; add a multi-role test covering the
chosen behavior. Both affected sites require the same complete-mapping logic.
In `@src/main/java/com/iemr/common/dto/identity/Address.java`:
- Around line 55-60: The isGpsUnavailable default is being overwritten with null
during Address mapping. Update Address to default isGpsUnavailable to false or
adjust BenCompleteDetailMapperDecorator to avoid setting the target when the
source value is null; apply the corresponding change at
src/main/java/com/iemr/common/dto/identity/Address.java#L55-L60 and
src/main/java/com/iemr/common/mapper/BenCompleteDetailMapperDecorator.java#L161-L166,
preserving false as the default when no value is supplied.
In
`@src/main/java/com/iemr/common/service/dynamicForm/FormMasterServiceImpl.java`:
- Around line 212-213: Update the option-language checks in
FormMasterServiceImpl to use case-insensitive matching for both English and
Bengali, replacing the exact comparisons in the branches that populate opt
labels. Preserve the existing label selection behavior while ensuring values
such as “BN” and “EN” select the corresponding translations.
- Around line 163-165: Update the Bengali branches in the relevant label,
placeholder, and option translation logic to use the Bengali translation only
when it is nonblank; otherwise preserve the existing field/placeholder default
or English option label. Apply this consistently to the branches assigning
translatedLabel and the corresponding symbols near the referenced locations.
In `@src/main/java/com/iemr/common/utils/CookieUtil.java`:
- Around line 38-39: Update CookieUtil’s cookie Max-Age configuration to match
the 8-hour jwt.access.expiration value in application.properties, replacing the
current 10-hour lifetime while preserving the existing seconds-based setting and
comment.
In `@src/main/java/com/iemr/common/utils/NetworkUtil.java`:
- Around line 51-53: Update the NetworkUtil LAN address resolution failure path
to stop returning FALLBACK_IP when resolution fails. Propagate the failure or
obtain a configured non-loopback address, and ensure ConnectController can
produce its explicit unavailable response instead of advertising loopback with
HTTP 200.
---
Outside diff comments:
In `@src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java`:
- Around line 311-327: The failed-login branches in the relevant authentication
method currently expose account existence, remaining attempts, and lock status
through IEMRException messages. Replace all externally propagated
credential-failure messages with one generic authentication error for both known
and unknown usernames, while moving any attempt guidance to a non-enumerable
internal flow such as logging without username-specific disclosure.
🪄 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: 280d9ccc-54cb-4338-a9db-5bd05be6a89b
📒 Files selected for processing (19)
pom.xmlsrc/main/environment/common_docker.propertiessrc/main/java/com/iemr/common/controller/connect/ConnectController.javasrc/main/java/com/iemr/common/controller/users/IEMRAdminController.javasrc/main/java/com/iemr/common/data/dynamic_from/FormFieldOption.javasrc/main/java/com/iemr/common/data/translation/Translation.javasrc/main/java/com/iemr/common/dto/identity/Address.javasrc/main/java/com/iemr/common/mapper/BenCompleteDetailMapperDecorator.javasrc/main/java/com/iemr/common/mapper/CommonIdentityMapperDecorator.javasrc/main/java/com/iemr/common/mapper/IdentityBenEditMapperDecorator.javasrc/main/java/com/iemr/common/model/beneficiary/BeneficiaryDemographicsModel.javasrc/main/java/com/iemr/common/service/dynamicForm/FormMasterServiceImpl.javasrc/main/java/com/iemr/common/service/health/HealthService.javasrc/main/java/com/iemr/common/service/users/IEMRAdminUserService.javasrc/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.javasrc/main/java/com/iemr/common/utils/CookieUtil.javasrc/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.javasrc/main/java/com/iemr/common/utils/NetworkUtil.javasrc/main/resources/application.properties
| User loggedInUser = mUser.get(0); | ||
|
|
||
| loggedInUser.setFailedAttempt(0); | ||
|
|
||
| iemrAdminUserServiceImpl.save(loggedInUser); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Remove the duplicate stale account-state write. Successful authentication already clears and persists failed-attempt state in IEMRAdminUserServiceImpl; this later save can overwrite a concurrent failed-login/lock update.
src/main/java/com/iemr/common/controller/users/IEMRAdminController.java#L182-L186: do not reset and save the returned user again.src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java#L136-L136: remove the rawsave(User)contract.src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java#L1388-L1391: remove the corresponding repository delegation.
📍 Affects 3 files
src/main/java/com/iemr/common/controller/users/IEMRAdminController.java#L182-L186(this comment)src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java#L136-L136src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java#L1388-L1391
🤖 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 `@src/main/java/com/iemr/common/controller/users/IEMRAdminController.java`
around lines 182 - 186, Remove the redundant failed-attempt reset and save after
successful authentication in IEMRAdminController.java:182-186, leaving
account-state persistence to IEMRAdminUserServiceImpl. Remove the raw save(User)
contract from IEMRAdminUserService.java:136 and its repository delegation from
IEMRAdminUserServiceImpl.java:1388-1391; update any resulting references as
needed.
| String userRole = ""; | ||
| if (mUser.size() == 1 && mUser.get(0).getM_UserServiceRoleMapping() != null) { | ||
| for (UserServiceRoleMapping usrm : mUser.get(0).getM_UserServiceRoleMapping()) { | ||
| if (usrm.getM_Role() != null && usrm.getM_Role().getRoleName() != null) { | ||
| userRole = usrm.getM_Role().getRoleName(); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| if (!CONCURRENT_SESSION_EXEMPT_ROLES.contains(userRole.trim().toLowerCase())) { | ||
| String tokenFromRedis = getConcurrentCheckSessionObjectAgainstUser( | ||
| m_User.getUserName().trim().toLowerCase()); | ||
| if (tokenFromRedis != null) { | ||
| throw new IEMRException( | ||
| "You are already logged in,please confirm to logout from other device and login again"); | ||
| } |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 5 'getUserServiceRoleMapping\s*\(|userExitsCheck\s*\(|CONCURRENT_SESSION_EXEMPT_ROLES' \
src/main/java/com/iemr/common
rg -n -C 5 'IEMRAdminController|concurrent.*session|provideradmin|superadmin' \
src/test/javaRepository: PSMRI/Common-API
Length of output: 38446
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '175,220p' src/main/java/com/iemr/common/controller/users/IEMRAdminController.java
printf '\n----\n'
sed -n '410,470p' src/main/java/com/iemr/common/controller/users/IEMRAdminController.java
printf '\n----\n'
sed -n '700,760p' src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java
printf '\n----\n'
sed -n '1328,1395p' src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.javaRepository: PSMRI/Common-API
Length of output: 10532
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 4 'findByUserName\s*\(|userExitsCheck\s*\(' src/main/java/com/iemr/common
printf '\n----\n'
rg -n -C 6 'interface .*RepositoryCustom|class .*RepositoryCustom|findByUserName' src/main/java/com/iemr/common
printf '\n----\n'
sed -n '1,220p' src/main/java/com/iemr/common/repository/users/IEMRUserRepositoryCustom.javaRepository: PSMRI/Common-API
Length of output: 39428
Use the complete role mappings for concurrent-session checks.
src/main/java/com/iemr/common/controller/users/IEMRAdminController.java#L195-L210: this branch only inspects the first mapping, butgetUserServiceRoleMapping()iterates aSet<Object[]>, so the chosen role can vary for multi-role users.src/main/java/com/iemr/common/controller/users/IEMRAdminController.java#L437-L458: reload the mappings before applying the same check;userExitsCheck()returns users only, so this path should not depend on an already populated role collection.
Define whether an exempt role should match any mapping or require all mappings to be exempt, then add a multi-role test.
📍 Affects 1 file
src/main/java/com/iemr/common/controller/users/IEMRAdminController.java#L195-L210(this comment)src/main/java/com/iemr/common/controller/users/IEMRAdminController.java#L437-L458
🤖 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 `@src/main/java/com/iemr/common/controller/users/IEMRAdminController.java`
around lines 195 - 210, The concurrent-session exemption currently inspects only
the first role mapping and may use an unpopulated collection. Update the checks
around IEMRAdminController’s login flow and the path near userExitsCheck() to
reload and inspect complete role mappings, defining and consistently applying
whether any or all roles must be exempt; add a multi-role test covering the
chosen behavior. Both affected sites require the same complete-mapping logic.
| private Double gpsLatitude; | ||
| private Double gpsLongitude; | ||
| private String digipin; | ||
| private Long gpsTimestamp; | ||
| private Boolean isGpsUnavailable; | ||
| private String gpsUnavailableReason; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Address.java =="
sed -n '1,220p' src/main/java/com/iemr/common/dto/identity/Address.java
echo
echo "== BenCompleteDetailMapperDecorator.java =="
sed -n '1,260p' src/main/java/com/iemr/common/mapper/BenCompleteDetailMapperDecorator.java
echo
echo "== Search for isGpsUnavailable usages =="
rg -n "isGpsUnavailable|getIsGpsUnavailable|setIsGpsUnavailable|GpsUnavailableReason|gpsUnavailable" src/main/javaRepository: PSMRI/Common-API
Length of output: 16013
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== BeneficiaryDemographicsModel excerpt =="
sed -n '150,220p' src/main/java/com/iemr/common/model/beneficiary/BeneficiaryDemographicsModel.java
echo
echo "== All direct reads of getIsGpsUnavailable =="
rg -n "getIsGpsUnavailable\\(" src/main/java
echo
echo "== All direct Boolean checks on isGpsUnavailable =="
rg -n "isGpsUnavailable|GpsUnavailable" src/main/java/com/iemr/common | sed -n '1,200p'Repository: PSMRI/Common-API
Length of output: 4570
Preserve the isGpsUnavailable default when mapping from Address.
BeneficiaryDemographicsModel defaults this flag to false, but Address leaves it nullable and BenCompleteDetailMapperDecorator copies that null straight over, clearing the default. If null is not a meaningful third state, default the DTO to false or skip the setter when the source is null.
src/main/java/com/iemr/common/dto/identity/Address.java#L55-L60src/main/java/com/iemr/common/mapper/BenCompleteDetailMapperDecorator.java#L161-L166
📍 Affects 2 files
src/main/java/com/iemr/common/dto/identity/Address.java#L55-L60(this comment)src/main/java/com/iemr/common/mapper/BenCompleteDetailMapperDecorator.java#L161-L166
🤖 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 `@src/main/java/com/iemr/common/dto/identity/Address.java` around lines 55 -
60, The isGpsUnavailable default is being overwritten with null during Address
mapping. Update Address to default isGpsUnavailable to false or adjust
BenCompleteDetailMapperDecorator to avoid setting the target when the source
value is null; apply the corresponding change at
src/main/java/com/iemr/common/dto/identity/Address.java#L55-L60 and
src/main/java/com/iemr/common/mapper/BenCompleteDetailMapperDecorator.java#L161-L166,
preserving false as the default when no value is supplied.
| }else if ("bn".equalsIgnoreCase(lang)) { | ||
| translatedLabel = label.getBengaliTranslation(); | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Preserve a fallback when Bengali text is unavailable.
These branches assign nullable Bengali values directly, so existing or partially translated records can produce null field labels, placeholders, and option labels. Use Bengali only when it is nonblank; otherwise retain the field/placeholder default and the English option label.
Also applies to: 177-179, 212-213
🤖 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 `@src/main/java/com/iemr/common/service/dynamicForm/FormMasterServiceImpl.java`
around lines 163 - 165, Update the Bengali branches in the relevant label,
placeholder, and option translation logic to use the Bengali translation only
when it is nonblank; otherwise preserve the existing field/placeholder default
or English option label. Apply this consistently to the branches assigning
translatedLabel and the corresponding symbols near the referenced locations.
| else if("en".equals(lang)) map.put("label", opt.getLabelEn()); | ||
| else if("bn".equals(lang)) map.put("label", opt.getLabelBn()); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use case-insensitive matching for option languages.
The field and placeholder paths use equalsIgnoreCase, but option selection requires exact en/bn casing. A request with lang=BN can therefore translate field text while omitting the option label; use equalsIgnoreCase consistently.
🤖 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 `@src/main/java/com/iemr/common/service/dynamicForm/FormMasterServiceImpl.java`
around lines 212 - 213, Update the option-language checks in
FormMasterServiceImpl to use case-insensitive matching for both English and
Bengali, replacing the exact comparisons in the branches that populate opt
labels. Preserve the existing label selection behavior while ensuring values
such as “BN” and “EN” select the corresponding translations.
| // Set the Max-Age (expiry time) in seconds (10 hours) | ||
| cookie.setMaxAge(60 * 60 * 10); // 10 hours expiration |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Keep the cookie lifetime aligned with the access-token lifetime.
The cookie now lasts 10 hours, but jwt.access.expiration in src/main/resources/application.properties is still 8 hours. Browsers can therefore send the stale Jwttoken for two hours after JWT expiry, causing repeated 401 responses. Align the two values.
🤖 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 `@src/main/java/com/iemr/common/utils/CookieUtil.java` around lines 38 - 39,
Update CookieUtil’s cookie Max-Age configuration to match the 8-hour
jwt.access.expiration value in application.properties, replacing the current
10-hour lifetime while preserving the existing seconds-based setting and
comment.
| } catch (Exception e) { | ||
| logger.error("Failed to resolve LAN IP address", e); | ||
| return FALLBACK_IP; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Do not return loopback as a successful LAN address.
When resolution fails, this returns 127.0.0.1; ConnectController then advertises it as the server IP with HTTP 200. A phone will connect to itself and the connectivity flow fails. Propagate the failure or use a configured address so the controller can return an explicit unavailable response.
🤖 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 `@src/main/java/com/iemr/common/utils/NetworkUtil.java` around lines 51 - 53,
Update the NetworkUtil LAN address resolution failure path to stop returning
FALLBACK_IP when resolution fails. Propagate the failure or obtain a configured
non-loopback address, and ensure ConnectController can produce its explicit
unavailable response instead of advertising loopback with HTTP 200.


📋 Description
JIRA ID:
Please provide a summary of the change and the motivation behind it. Include relevant context and details.
✅ Type of Change
ℹ️ Additional Information
Please describe how the changes were tested, and include any relevant screenshots, logs, or other information that provides additional context.
Summary by CodeRabbit
New Features
Improvements
Bug Fixes