Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
5a28f4b
Update application.properties
SauravBizbRolly Nov 26, 2025
ea12e3e
add column in create BeneficiaryModel
SauravBizbRolly Nov 26, 2025
50c5952
Elasticsearch implementation for Beneficiary Search (#324)
vanitha1822 Dec 18, 2025
1bc9298
variable added
sac2kadam Dec 31, 2025
4b975ff
Merge pull request #330 from PSMRI/add_ci_docker_properties
drtechie Dec 31, 2025
c501e80
update language
SauravBizbRolly Jan 7, 2026
ec3aac3
update language
SauravBizbRolly Jan 7, 2026
bafc879
Downgrade version from 3.6.1 to 3.6.0
SauravBizbRolly Jan 7, 2026
65efdc7
Elastic Search Implementation for Advanced Search (#327)
vanitha1822 Jan 8, 2026
38a4147
Remove empty line in application.properties
SauravBizbRolly Jan 8, 2026
17620d3
fix:signature check for mmu
vishwab1 Jan 9, 2026
68b246e
Merge pull request #335 from PSMRI/release-3.6.1-sign
snehar-nd Jan 9, 2026
9c1493a
Update application.properties
SauravBizbRolly Jan 9, 2026
984d533
Update application.properties
SauravBizbRolly Jan 9, 2026
c3bc3cb
fix: retrive any user without deleted
vishwab1 Jan 13, 2026
8dcdfc3
Merge pull request #336 from PSMRI/release-3.6.1-sign
snehar-nd Jan 13, 2026
5190737
implement state wise hide un hide form fields
SauravBizbRolly Jan 14, 2026
b5f0670
Merge pull request #337 from PSMRI/feature/hide_feilds_state_wise
SauravBizbRolly Jan 14, 2026
4d20b8c
implement state wise hide un hide form fields
SauravBizbRolly Jan 14, 2026
bed849b
implement state wise hide un hide form fields
SauravBizbRolly Jan 16, 2026
dd2c323
enhance welcome sms code
SauravBizbRolly Jan 18, 2026
6d224eb
Merge pull request #338 from PSMRI/feature/manage_upload_file
SauravBizbRolly Jan 18, 2026
4104ad0
fix hide unhide form issue
SauravBizbRolly Jan 18, 2026
c162bcc
Merge pull request #340 from PSMRI/fix_form_feilds_issue
SauravBizbRolly Jan 18, 2026
fdbc9b7
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
0c64cef
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
b3a1922
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
c4c1d48
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
f10f37c
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
b3da893
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
f94d0b0
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
be7889e
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
0022329
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
ba824be
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
c0c5333
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
2e18fdd
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
acd9d8e
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
475a4ac
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
f952708
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
64b2a7e
fix hide unhide form issue
SauravBizbRolly Jan 21, 2026
97f7d5f
Merge branch 'release-3.6.1' into feature/form_validation
SauravBizbRolly Jan 21, 2026
cb1b06e
Merge pull request #343 from PSMRI/feature/form_validation
SauravBizbRolly Jan 21, 2026
833f157
fix: video consultation functionality
vanitha1822 Jul 23, 2025
114dee9
fix: pom version update
vanitha1822 Mar 24, 2026
8e9a650
fix: add cti-server-ip
vanitha1822 Mar 30, 2026
dfa00ac
fix: comment unwanted code
vanitha1822 Mar 30, 2026
9f379fb
fix: update videocall url property
vanitha1822 Mar 30, 2026
f0a1177
fix: update cti-server-ip
vanitha1822 Mar 30, 2026
eec7cfe
docs: add CLAUDE.md for Claude Code guidance
snehar-nd Mar 30, 2026
4b5d250
fix: KM issue
vanitha1822 Mar 31, 2026
e1c84e8
fix: KM issue
vanitha1822 Mar 31, 2026
cd61d46
fix: remove unwanted imports
vanitha1822 Mar 31, 2026
92d49ad
fix: conflicts
vanitha1822 Mar 31, 2026
f1496fa
fix: update the temp path
vanitha1822 Apr 1, 2026
72f0c28
Fix the OpenKM Issue (#389)
vanitha1822 Apr 7, 2026
79b050d
Fix ConfigProperties to resolve env variable placeholders via Spring …
vishwab1 Apr 7, 2026
31ff821
fix: update sms issue
vanitha1822 Apr 8, 2026
eefbed1
fix: merge with 3.6.2
vanitha1822 Apr 8, 2026
ac388d2
fix: build issue
vanitha1822 Apr 8, 2026
00aa6da
fix: update condition
vanitha1822 Apr 8, 2026
c49d792
fix: edit ben issue
vanitha1822 Apr 9, 2026
9bbfdfc
fix: phone number issue for sms
vanitha1822 Apr 9, 2026
61cc94e
fix: update the url with jwt token
vanitha1822 Apr 9, 2026
a48b4af
fix: jitsi authorization issue
vanitha1822 Apr 10, 2026
389c20d
fix: skip auth
vanitha1822 Apr 10, 2026
1fc6509
fix: hash key updation
vanitha1822 Apr 10, 2026
640841b
fix: jwt type in header for authorization
vanitha1822 Apr 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# CLAUDE.md - Common-API

## Project Overview

Common-API is the gateway microservice for the AMRIT healthcare platform. It provides shared APIs consumed by all frontend UIs including authentication, beneficiary registration, call handling, location masters, notifications, feedback, reporting, and integrations with external systems (c-Zentrix CTI, Everwell, eAusadha, eSanjeevani, ABDM, Firebase, Honeywell POCT devices).

## Tech Stack

- Java 17
- Spring Boot 3.2.2
- Spring Data JPA / Hibernate
- MySQL 8.0
- Redis (session management, caching)
- MongoDB (optional, for specific integrations)
- Maven (build tool)
- Swagger/OpenAPI (API documentation)
- Lombok, MapStruct
- CryptoJS-compatible AES encryption
- Firebase Admin SDK
- WAR packaging (deploys to Wildfly)

## Build and Run

```bash
# Build
mvn clean install -DENV_VAR=local

# Run locally (start Redis first)
mvn spring-boot:run -DENV_VAR=local

# Package WAR
mvn -B package --file pom.xml -P <profile> # profiles: dev, local, test, ci, uat

# Run tests
mvn test
```

### Configuration

- Copy `src/main/environment/common_example.properties` to `common_local.properties` and edit.
- Environment selected via `-DENV_VAR=<env>`.
- Swagger UI: `http://localhost:8083/swagger-ui.html`

## Package Structure

Base package: `com.iemr.common`

| Layer | Package | Description |
|-------|---------|-------------|
| Controllers | `controller.*` | REST endpoints (40+ sub-packages) |
| Services | `service.*` | Business logic |
| Repositories | `repository.*`, `repo.*` | JPA repositories |
| Entities | `data.*` | JPA entity classes |
| DTOs | `model.*` | Transfer objects |
| Mappers | `mapper.*` | Object mapping |
| Config | `config.*` | Swagger, encryption, Firebase, Quartz, prototypes |
| Constants | `constant` | Application constants |
| Utils | `utils.*` | Redis, HTTP, session, validation, exception |

## Key Functional Domains

- **Authentication/Authorization**: `controller.users` - login, session, user management
- **Beneficiary Registration**: `controller.beneficiary` - create, search, update beneficiaries
- **Call Handling**: `controller.callhandling` - CTI integration, call lifecycle
- **Feedback/Grievance**: `controller.feedback`, `controller.grievance` - feedback and complaint management
- **Location**: `controller.location` - state, district, block, village masters
- **Notifications**: `controller.notification` - alerts, SMS, email, Firebase push
- **Reporting**: `controller.report`, `controller.secondaryReport` - CRM reports
- **Helpline 104**: `controller.helpline104history` - medical advice history
- **COVID**: `controller.covid` - vaccination status
- **CTI Integration**: `controller.cti` - c-Zentrix computer telephony
- **External Integrations**: `controller.eausadha`, `controller.esanjeevani`, `controller.everwell`, `controller.honeywell`, `controller.brd`, `controller.carestream`
- **ABDM**: `controller.abdmfacility` - Ayushman Bharat Digital Mission
- **KM File Management**: `controller.kmfilemanager` - OpenKM document management
- **OTP/SMS**: `controller.otp`, `controller.sms` (via SMS gateway)
- **Scheduling**: `controller.questionconfig`, `controller.scheme`
- **Door-to-Door App**: `controller.door_to_door_app` - field worker support
- **NHM Dashboard**: `controller.nhmdashboard` - National Health Mission integration

## Architecture Notes

- Entry point: `CommonMain.java` (main class in `utils` package)
- Acts as the API gateway; all frontend UIs authenticate through Common-API
- Session management via Redis with 27-minute timeout
- HTTP interceptors attach `Authorization` and `ServerAuthorization` headers
- Status code `5002` signals session expiration to frontends
- AES + PBKDF2 encryption for password handling (`config.encryption`)
- Firebase integration for push notifications (`config.firebase`)
- Quartz scheduler for background jobs (`config.quartz`)
- Extensive test coverage with unit tests under `src/test/`

## CI/CD

- GitHub Actions: `package.yml`, `build-on-pull-request.yml`, `sast.yml`, `commit-lint.yml`, `codeql.yml`
- Conventional Commits enforced via Husky + commitlint
- Checkstyle configuration in `checkstyle.xml`
- JaCoCo for code coverage, SonarQube integration configured
- Dockerfile for containerized deployment
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.iemr.common-API</groupId>
<artifactId>common-api</artifactId>
<version>3.6.0</version>
<version>3.7.0</version>
<packaging>war</packaging>

<name>Common-API</name>
Expand Down
14 changes: 12 additions & 2 deletions src/main/environment/common_ci.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ km-base-path=@env.KM_API_BASE_PATH@
km-root-path=/okm:personal/users/
km-guest-user=@env.KM_GUEST_USER@
km-guest-password=@env.KM_GUEST_PASSWORD@
tempFilePath=@env.TEMP_FILE_PATH@

# CTI Config
cti-server-ip=@env.CTI_SERVER_IP@
Expand Down Expand Up @@ -189,10 +190,19 @@ captcha.enable-captcha=@env.ENABLE_CAPTCHA@

cors.allowed-origins=@env.CORS_ALLOWED_ORIGINS@

video-call-url=@env.VIDEO_CALL_URL@
jibri.output.path=@env.JIBRI_OUTPUT_PATH@
# Jitsi configuration
videocall.url=@env.VIDEO_CALL_URL@
video.recording.path=@env.VIDEO_RECORDING_PATH@

# Jitsi JWT (prosody token-auth)
jitsi.app.id=@env.JITSI_APP_ID@
jitsi.app.secret=@env.JITSI_APP_SECRET@
jitsi.domain=@env.JITSI_DOMAIN@
jitsi.sub=@env.JITSI_SUB@
jitsi.token.ttl.seconds=@env.JITSI_TOKEN_TTL_SECONDS@
jitsi.room.prefix=@env.JITSI_ROOM_PREFIX@
jitsi.default.user.email=@env.JITSI_DEFAULT_USER_EMAIL@

platform.feedback.ratelimit.enabled=@env.PLATFORM_FEEDBACK_RATELIMIT_ENABLED@
platform.feedback.ratelimit.pepper=@env.PLATFORM_FEEDBACK_RATELIMIT_PEPPER@
platform.feedback.ratelimit.trust-forwarded-for=@env.PLATFORM_FEEDBACK_RATELIMIT_TRUST_FORWARDED_FOR@
Expand Down
13 changes: 11 additions & 2 deletions src/main/environment/common_docker.properties
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ everwellRegisterBenficiary = ${COMMON_API_BASE_URL}/beneficiary/create
## LungAssessment credentials
lungAssessmentEmail = ${SWAASA_EMAIL}
lungAssessmentPassword =${SWAASA_PASSWORD}

tempFilePath=${TEMP_FILE_PATH}

## SWASSA APIs
lungAssessmentAdminLogin = ${SWAASA_BASE_URL}/api/adminLogin
Expand Down Expand Up @@ -192,10 +192,19 @@ firebase.enabled=${FIREBASE_ENABLE}
firebase.credential-file=${FIREBASE_CREDENTIAL}


video-call-url=${VIDEO_CALL_URL}
videocall.url=${VIDEO_CALL_URL}
jibri.output.path={JIBRI_OUTPUT_PATH}
video.recording.path={VIDEO_RECORDING_PATH}

# Jitsi JWT (prosody token-auth)
jitsi.app.id=${JITSI_APP_ID}
jitsi.app.secret=${JITSI_APP_SECRET}
jitsi.domain=${JITSI_DOMAIN}
jitsi.sub=${JITSI_SUB}
jitsi.token.ttl.seconds=${JITSI_TOKEN_TTL_SECONDS}
jitsi.room.prefix=${JITSI_ROOM_PREFIX}
jitsi.default.user.email=${JITSI_DEFAULT_USER_EMAIL}

# Platform Feedback module
platform.feedback.ratelimit.enabled=${PLATFORM_FEEDBACK_RATELIMIT_ENABLED}
platform.feedback.ratelimit.pepper=${PLATFORM_FEEDBACK_RATELIMIT_PEPPER}
Expand Down
14 changes: 12 additions & 2 deletions src/main/environment/common_example.properties
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ km-root-path=/okm:personal/users/
km-guest-user=guest
km-guest-password=guest

tempFilePath=/tmp

# CTI Config
cti-server-ip=10.208.122.99
cti-logger_base_url=http://10.208.122.99/logger
Expand Down Expand Up @@ -198,8 +200,8 @@ grievanceAllocationRetryConfiguration=3
logging.path=logs/
logging.file.name=logs/common-api.log

video-call-url=https://vc.piramalswasthya.org/?
jibri.output.path=/srv/jibri/recordings
# Jitsi configuration
videocall.url=https://vc.piramalswasthya.org/?
video.recording.path=/srv/recordings

captcha.secret-key= <Enter Cloudflare Secret Key>
Expand All @@ -226,3 +228,11 @@ platform.feedback.ratelimit.backoff-minutes=15

### generate Beneficiary IDs URL
generateBeneficiaryIDs-api-url=/generateBeneficiaryController/generateBeneficiaryIDs

JITSI_APP_ID=piramal_vc
JITSI_APP_SECRET=5b9883418be6f228ffe3ceaa74dd3d3b91737733a4a85c5e82fc584ad449850b
JITSI_DOMAIN=vc.piramalswasthya.org
JITSI_SUB=meet.jitsi
JITSI_TOKEN_TTL_SECONDS=3600
JITSI_ROOM_PREFIX=piramal-meeting-
JITSI_DEFAULT_USER_EMAIL=admin@piramalswasthya.org
2 changes: 2 additions & 0 deletions src/main/java/com/iemr/common/CommonApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.client.RestTemplate;

Expand All @@ -40,6 +41,7 @@

@SpringBootApplication
@EnableScheduling
@EnableAsync(proxyTargetClass = true)
public class CommonApplication extends SpringBootServletInitializer {

@Bean
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/iemr/common/config/InterceptorConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public class InterceptorConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestInterceptor);
registry.addInterceptor(requestInterceptor)
.excludePathPatterns("/video-consultation/resolve", "**/video-consultation/resolve");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

import org.springframework.stereotype.Service;

@Service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
Expand Down Expand Up @@ -70,6 +71,8 @@
import com.iemr.common.service.userbeneficiarydata.MaritalStatusService;
import com.iemr.common.service.userbeneficiarydata.StatusService;
import com.iemr.common.service.userbeneficiarydata.TitleService;
import com.iemr.common.utils.CookieUtil;
import com.iemr.common.utils.JwtUtil;
import com.iemr.common.utils.mapper.InputMapper;
import com.iemr.common.utils.mapper.OutputMapper;
import com.iemr.common.utils.response.OutputResponse;
Expand Down Expand Up @@ -103,6 +106,8 @@ public class BeneficiaryRegistrationController {
private BeneficiaryOccupationService beneficiaryOccupationService;
private GovtIdentityTypeService govtIdentityTypeService;

@Autowired
private JwtUtil jwtUtil;

@Autowired
public void setBenRelationshipTypeService(BenRelationshipTypeService benRelationshipTypeService) {
Expand Down Expand Up @@ -342,6 +347,54 @@ public String searchUserByPhone(
return response.toString();
}

@Operation(summary = "Provide the list of beneficiaries using Elasticsearch")
@RequestMapping(value = "/searchUser", method = RequestMethod.POST, headers = "Authorization")
public String searchUser(@RequestBody String request, HttpServletRequest httpRequest) {
OutputResponse response = new OutputResponse();
try {
logger.info("Universal search request received");

JsonParser parser = new JsonParser();
JsonObject requestObj = parser.parse(request).getAsJsonObject();

String searchQuery = null;
if (requestObj.has("search") && !requestObj.get("search").isJsonNull()) {
searchQuery = requestObj.get("search").getAsString();
}

if (searchQuery == null || searchQuery.trim().isEmpty()) {
response.setError(400, "Search query is required");
return response.toString();
}

String auth = httpRequest.getHeader("Authorization");

Integer userID = jwtUtil.getUserIdFromRequest(httpRequest);

logger.info("ES search for userId: {}", userID);

Boolean is1097 = false;
if (requestObj.has("is1097") && !requestObj.get("is1097").isJsonNull()) {
is1097 = requestObj.get("is1097").getAsBoolean();
}

logger.info("Searching with query: {}, userId: {}, is1097: {}", searchQuery, userID, is1097);
String result = iemrSearchUserService.searchUser(searchQuery, userID, auth, is1097);

if (result == null || result.trim().isEmpty()) {
response.setError(200, "No beneficiaries found");
return response.toString();
}

return result;

} catch (Exception e) {
logger.error("Error in universal search: {}", e.getMessage(), e);
response.setError(400, "Error searching beneficiaries: " + e.getMessage());
return response.toString();
}
}

@Operation(summary = "Provide the list of beneficiaries based on search criteria")
@RequestMapping(value = "/searchBeneficiary", method = RequestMethod.POST, headers = "Authorization")
public String searchBeneficiary(
Expand All @@ -364,6 +417,41 @@ public String searchBeneficiary(
return output.toString();
}

/**
* Elasticsearch-based advanced search endpoint
*/
@Operation(summary = "Advanced search beneficiaries using Elasticsearch")
@RequestMapping(value = "/searchBeneficiaryES", method = RequestMethod.POST, headers = "Authorization")
public String searchBeneficiaryES(
@RequestBody BeneficiaryModel request,
HttpServletRequest httpRequest) {

logger.info("searchBeneficiaryES request: {}", request);
OutputResponse output = new OutputResponse();

try {

String auth = httpRequest.getHeader("Authorization");

Integer userID = jwtUtil.getUserIdFromRequest(httpRequest);

logger.info("ES Advanced search for userId: {}", userID);

String result = iemrSearchUserService.findBeneficiaryES(request, userID, auth);

return result;

} catch (NumberFormatException ne) {
logger.error("searchBeneficiaryES failed with number format error: {}", ne.getMessage(), ne);
output.setError(400, "Invalid number format in search criteria");
return output.toString();
} catch (Exception e) {
logger.error("searchBeneficiaryES failed with error: {}", e.getMessage(), e);
output.setError(500, "Error searching beneficiaries: " + e.getMessage());
return output.toString();
}
}

@Operation(summary = "Provide all common data list needed for beneficiary registration")
@RequestMapping(value = "/getRegistrationData", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON, headers = "Authorization")
public String getRegistrationData() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ public ResponseEntity<ApiResponse<?>> deleteField(@PathVariable Long fieldId) {
}

@GetMapping(value = "form/{formId}/fields")
public ResponseEntity<ApiResponse<?>> getStructuredForm(@PathVariable String formId, @RequestParam(name = "lang", defaultValue = "en") String lang) {
public ResponseEntity<ApiResponse<?>> getStructuredForm(@PathVariable String formId, @RequestParam(name = "lang", defaultValue = "en") String lang,@RequestHeader(value = "jwttoken") String token) {
try {
Object result = formMasterService.getStructuredFormByFormId(formId,lang);
Object result = formMasterService.getStructuredFormByFormId(formId,lang,token);
return ResponseEntity.status(HttpStatus.OK)
.body(ApiResponse.success("Form structure fetched successfully", HttpStatus.OK.value(), result));
} catch (Exception e) {
Expand All @@ -97,4 +97,6 @@ public ResponseEntity<ApiResponse<?>> getStructuredForm(@PathVariable String for
}




}
Loading