diff --git a/Documentation/Docker-setup/config.env b/Documentation/Docker-setup/config.env
index 91c38a33..203863f2 100644
--- a/Documentation/Docker-setup/config.env
+++ b/Documentation/Docker-setup/config.env
@@ -29,4 +29,4 @@ ELEVATE_DATA_CONTAINER_NAME=elevate-data
# Kafka-Topics
PROJECT_TOPIC=sl-improvement-project-submission-dev
-METABASE_TOPIC=sl-improvement-metabase-dev
\ No newline at end of file
+METABASE_TOPIC=sl-improvement-metabase-dev
diff --git a/Documentation/Docker-setup/docker-compose.yml b/Documentation/Docker-setup/docker-compose.yml
index f9a9f2ea..ba68548b 100644
--- a/Documentation/Docker-setup/docker-compose.yml
+++ b/Documentation/Docker-setup/docker-compose.yml
@@ -129,7 +129,7 @@ services:
# Elevate Data Service
elevate-data:
- image: shikshalokamqa/elevate-data:latest
+ image: shikshalokamqa/elevate-data:v3.0.2
restart: always
container_name: elevate-data
ports:
@@ -178,4 +178,4 @@ volumes:
elevate_data:
driver: local
kafka_data:
- driver: local
\ No newline at end of file
+ driver: local
diff --git a/jobs-core/src/main/resources/base-config.conf b/jobs-core/src/main/resources/base-config.conf
index 93625de1..9a1fac4f 100644
--- a/jobs-core/src/main/resources/base-config.conf
+++ b/jobs-core/src/main/resources/base-config.conf
@@ -27,4 +27,4 @@ task {
restart-strategy.attempts = 3
restart-strategy.delay = 30000 # in milli-seconds
consumer.parallelism = 1
-}
\ No newline at end of file
+}
diff --git a/jobs-core/src/main/scala/org/shikshalokam/job/BaseJobConfig.scala b/jobs-core/src/main/scala/org/shikshalokam/job/BaseJobConfig.scala
index 2d1e9af1..c5bd6136 100644
--- a/jobs-core/src/main/scala/org/shikshalokam/job/BaseJobConfig.scala
+++ b/jobs-core/src/main/scala/org/shikshalokam/job/BaseJobConfig.scala
@@ -38,6 +38,13 @@ class BaseJobConfig(val config: Config, val jobName: String) extends Serializabl
properties.setProperty("bootstrap.servers", kafkaBrokerServers)
properties.setProperty("group.id", groupId)
properties.setProperty(ConsumerConfig.ISOLATION_LEVEL_CONFIG, "read_committed")
+
+ // Add timeout configurations to handle connection issues better
+ // Default timeout is 30 seconds, increase to 60 seconds for better reliability
+ // properties.setProperty(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG, "60000")
+ // properties.setProperty(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "30000")
+ // properties.setProperty(ConsumerConfig.METADATA_MAX_AGE_CONFIG, "300000")
+
kafkaAutoOffsetReset.map {
properties.setProperty("auto.offset.reset", _)
}
@@ -50,6 +57,11 @@ class BaseJobConfig(val config: Config, val jobName: String) extends Serializabl
properties.put(ProducerConfig.LINGER_MS_CONFIG, new Integer(10))
properties.put(ProducerConfig.BATCH_SIZE_CONFIG, new Integer(16384 * 4))
properties.put(ProducerConfig.COMPRESSION_TYPE_CONFIG, "snappy")
+
+ // Add timeout configurations for producer
+ // properties.setProperty(ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG, "60000")
+ // properties.setProperty(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, "120000")
+
properties
}
diff --git a/metabase-jobs/project-dashboard-creator/src/main/resources/metabase-project-dashboard.conf b/metabase-jobs/project-dashboard-creator/src/main/resources/metabase-project-dashboard.conf
index 9dbcad79..c8e64da9 100644
--- a/metabase-jobs/project-dashboard-creator/src/main/resources/metabase-project-dashboard.conf
+++ b/metabase-jobs/project-dashboard-creator/src/main/resources/metabase-project-dashboard.conf
@@ -32,4 +32,4 @@ metabase {
domainName = "http://localhost:3000/dashboard/"
metabaseApiKey = "d3f4ult-api-key"
evidenceBaseUrl = "https://elevate-api.sunbirdsaas.com/project/v1/cloud-services/files/download?file="
-}
\ No newline at end of file
+}
diff --git a/metabase-jobs/project-dashboard-creator/src/test/resources/test.conf b/metabase-jobs/project-dashboard-creator/src/test/resources/test.conf
index 467347ba..0452ecff 100644
--- a/metabase-jobs/project-dashboard-creator/src/test/resources/test.conf
+++ b/metabase-jobs/project-dashboard-creator/src/test/resources/test.conf
@@ -33,4 +33,4 @@ metabase {
domainName = "http://localhost:3000/dashboard/"
metabaseApiKey = "d3f4ult-api-key"
evidenceBaseUrl = "https://TESTING="
-}
\ No newline at end of file
+}
diff --git a/stream-jobs/pom.xml b/stream-jobs/pom.xml
index d5be4f07..afcf04fb 100644
--- a/stream-jobs/pom.xml
+++ b/stream-jobs/pom.xml
@@ -20,6 +20,7 @@
survey-stream-processor
observation-stream-processor
user-stream-processor
+ user-mapping-stream-processor
mentoring-stream-processor
diff --git a/stream-jobs/project-stream-processor/src/main/resources/project-stream.conf b/stream-jobs/project-stream-processor/src/main/resources/project-stream.conf
index 35a3d1c1..d685516b 100644
--- a/stream-jobs/project-stream-processor/src/main/resources/project-stream.conf
+++ b/stream-jobs/project-stream-processor/src/main/resources/project-stream.conf
@@ -28,4 +28,4 @@ postgres{
reports{
enabled = ["admin", "state", "district", "program", "solution"]
-}
\ No newline at end of file
+}
diff --git a/stream-jobs/project-stream-processor/src/test/resources/test.conf b/stream-jobs/project-stream-processor/src/test/resources/test.conf
index efe92aee..eff4dab0 100644
--- a/stream-jobs/project-stream-processor/src/test/resources/test.conf
+++ b/stream-jobs/project-stream-processor/src/test/resources/test.conf
@@ -27,4 +27,4 @@ postgres{
reports{
enabled = ["admin", "state", "district", "program", "solution"]
-}
\ No newline at end of file
+}
diff --git a/stream-jobs/user-mapping-stream-processor/obs_kafka_response.json b/stream-jobs/user-mapping-stream-processor/obs_kafka_response.json
new file mode 100644
index 00000000..d4e30c6d
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/obs_kafka_response.json
@@ -0,0 +1,6772 @@
+{
+ "_id": "696f0469add4262f415219ad",
+ "entityId": "6953d07fe83c1c0014713c05",
+ "observationId": "696f0469add4262f415219a0",
+ "createdBy": "3087",
+ "status": "completed",
+ "evidencesStatus": [
+ {
+ "externalId": "OB",
+ "tip": null,
+ "name": "Observation",
+ "description": null,
+ "modeOfCollection": "onfield",
+ "canBeNotApplicable": false,
+ "notApplicable": null,
+ "canBeNotAllowed": false,
+ "remarks": null,
+ "startTime": 1768894219120,
+ "endTime": 1768894222118,
+ "isSubmitted": true,
+ "submissions": [
+ {
+ "externalId": "OB",
+ "startTime": 1768894219120,
+ "endTime": 1768894222118,
+ "isSubmitted": false,
+ "gpsLocation": null,
+ "submittedBy": "3087",
+ "submittedByName": "Farabi Ahmedullah",
+ "submittedByEmail": null,
+ "submissionDate": "2026-01-20T07:30:24.523Z",
+ "isValid": true
+ }
+ ],
+ "hasConflicts": false
+ }
+ ],
+ "evidences": {
+ "OB": {
+ "externalId": "OB",
+ "tip": null,
+ "name": "Observation",
+ "description": null,
+ "modeOfCollection": "onfield",
+ "canBeNotApplicable": false,
+ "notApplicable": false,
+ "canBeNotAllowed": false,
+ "remarks": null,
+ "startTime": 1768894219120,
+ "endTime": 1768894222118,
+ "isSubmitted": true,
+ "submissions": [
+ {
+ "status": "submit",
+ "externalId": "OB",
+ "answers": {
+ "696660cdf56b708ddc8dfbb2": {
+ "qid": "696660cdf56b708ddc8dfbb2",
+ "value": "sagar",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Facilitator Name",
+ ""
+ ],
+ "labels": [
+ "sagar"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135767,
+ "endTime": 1768892119361,
+ "criteriaId": "696660bde56b708ddc8dfc55",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbb2": {
+ "qid": "696660bce56b708ddc8dfbb2",
+ "value": "good",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Province",
+ ""
+ ],
+ "labels": [
+ "good"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135789,
+ "endTime": 1768892124079,
+ "criteriaId": "696660bde56b708ddc8dfc55",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbb3": {
+ "qid": "696660bce56b708ddc8dfbb3",
+ "value": "20",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Pilot Site",
+ ""
+ ],
+ "labels": [
+ "20"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135796,
+ "endTime": 1768892127781,
+ "criteriaId": "696660bde56b708ddc8dfc55",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbb4": {
+ "qid": "696660bce56b708ddc8dfbb4",
+ "value": "2026-01-20T06:55:00.000Z",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Date of Collection",
+ ""
+ ],
+ "labels": [
+ "2026-01-20T06:55:00.000Z"
+ ],
+ "responseType": "date",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135803,
+ "endTime": 1768892129231,
+ "criteriaId": "696660bde56b708ddc8dfc55",
+ "responseType": "date",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbb5": {
+ "qid": "696660bce56b708ddc8dfbb5",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Record if the captured residential address is correct",
+ ""
+ ],
+ "labels": [
+ "Yes"
+ ],
+ "responseType": "radio",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135820,
+ "endTime": 1768892136961,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "radio",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbb6": {
+ "qid": "696660bce56b708ddc8dfbb6",
+ "value": "vaibhav",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "What is your name?",
+ ""
+ ],
+ "labels": [
+ "vaibhav"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135827,
+ "endTime": 1768892300964,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbb7": {
+ "qid": "696660bce56b708ddc8dfbb7",
+ "value": "123",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "What is your ID number?",
+ ""
+ ],
+ "labels": [
+ "123"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135845,
+ "endTime": 1768892306434,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbb8": {
+ "qid": "696660bce56b708ddc8dfbb8",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Is the respondent a man or a woman? (record from observation)",
+ ""
+ ],
+ "labels": [
+ "Man (Male)"
+ ],
+ "responseType": "radio",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135850,
+ "endTime": 1768892306546,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "radio",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbb9": {
+ "qid": "696660bce56b708ddc8dfbb9",
+ "value": "9876543210",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "What is your cell phone number?",
+ ""
+ ],
+ "labels": [
+ "9876543210"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135855,
+ "endTime": 1768892315705,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbba": {
+ "qid": "696660bce56b708ddc8dfbba",
+ "value": "9087654321",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Please may I have an alternative number for you?",
+ ""
+ ],
+ "labels": [
+ "9087654321"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135859,
+ "endTime": 1768892325383,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbbb": {
+ "qid": "696660bce56b708ddc8dfbbb",
+ "value": "sagar@gmail.com",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "And what is your email address?",
+ ""
+ ],
+ "labels": [
+ "sagar@gmail.com"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135865,
+ "endTime": 1768892330800,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbbc": {
+ "qid": "696660bce56b708ddc8dfbbc",
+ "value": "R2",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Does the respondent have any disabilities?",
+ ""
+ ],
+ "labels": [
+ "No"
+ ],
+ "responseType": "radio",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135868,
+ "endTime": 1768892332857,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "radio",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbbd": {
+ "qid": "696660bce56b708ddc8dfbbd",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Which disability?",
+ ""
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": "",
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": [
+ {
+ "operator": "===",
+ "value": "R1",
+ "_id": "696660bce56b708ddc8dfbbc"
+ }
+ ],
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbbe": {
+ "qid": "696660bce56b708ddc8dfbbe",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Who is the head of this household?",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135873,
+ "endTime": 1768892334962,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbbf": {
+ "qid": "696660bce56b708ddc8dfbbf",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Please specify:",
+ ""
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": "",
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": [
+ {
+ "operator": "===",
+ "value": "R7",
+ "_id": "696660bce56b708ddc8dfbbe"
+ }
+ ],
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbc0": {
+ "qid": "696660bce56b708ddc8dfbc0",
+ "value": "R2",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Do you have children under the age of 18 living with you here in this household?",
+ ""
+ ],
+ "labels": [
+ "No"
+ ],
+ "responseType": "radio",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135884,
+ "endTime": 1768892338963,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "radio",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbc1": {
+ "qid": "696660bce56b708ddc8dfbc1",
+ "value": [],
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Children Information",
+ ""
+ ],
+ "labels": [],
+ "responseType": "matrix",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": "",
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "matrix",
+ "evidenceMethod": "OB",
+ "visibleIf": [
+ {
+ "operator": "===",
+ "value": "R1",
+ "_id": "696660bce56b708ddc8dfbc0"
+ }
+ ],
+ "rubricLevel": "",
+ "countOfInstances": 0
+ },
+ "696660bce56b708ddc8dfbc6": {
+ "qid": "696660bce56b708ddc8dfbc6",
+ "value": 19,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "How many other people over the age of 18 are living in the household?",
+ ""
+ ],
+ "labels": [
+ 19
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135887,
+ "endTime": 1768892345891,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbc7": {
+ "qid": "696660bce56b708ddc8dfbc7",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "18-24 years",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135893,
+ "endTime": 1768892356170,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbc8": {
+ "qid": "696660bce56b708ddc8dfbc8",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "25-34 years",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135897,
+ "endTime": 1768892357034,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbc9": {
+ "qid": "696660bce56b708ddc8dfbc9",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "35-39 years",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135910,
+ "endTime": 1768892357822,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbca": {
+ "qid": "696660bce56b708ddc8dfbca",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "60 or older",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135914,
+ "endTime": 1768892359002,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbcb": {
+ "qid": "696660bce56b708ddc8dfbcb",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Never been to school",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135917,
+ "endTime": 1768892360178,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbcc": {
+ "qid": "696660bce56b708ddc8dfbcc",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Crèche/nursery school",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135921,
+ "endTime": 1768892360528,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbcd": {
+ "qid": "696660bce56b708ddc8dfbcd",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Some primary school",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135924,
+ "endTime": 1768892360787,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbce": {
+ "qid": "696660bce56b708ddc8dfbce",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Primary completed",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135927,
+ "endTime": 1768892361132,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbcf": {
+ "qid": "696660bce56b708ddc8dfbcf",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Some high school",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135929,
+ "endTime": 1768892361495,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbd0": {
+ "qid": "696660bce56b708ddc8dfbd0",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "High school completed (Matric)",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135932,
+ "endTime": 1768892362105,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbd1": {
+ "qid": "696660bce56b708ddc8dfbd1",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "N. Qualification/Vocational training",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135935,
+ "endTime": 1768892362541,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbd2": {
+ "qid": "696660bce56b708ddc8dfbd2",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Higher certificate",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135954,
+ "endTime": 1768892362828,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbd3": {
+ "qid": "696660bce56b708ddc8dfbd3",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Diploma",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135959,
+ "endTime": 1768892363139,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbd4": {
+ "qid": "696660bce56b708ddc8dfbd4",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "University degree",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135967,
+ "endTime": 1768892363487,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbd5": {
+ "qid": "696660bce56b708ddc8dfbd5",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "How many of each of these grants does your household receive?",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135974,
+ "endTime": 1768892231025,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbd6": {
+ "qid": "696660bce56b708ddc8dfbd6",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Child support grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135977,
+ "endTime": 1768892231983,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbd7": {
+ "qid": "696660bce56b708ddc8dfbd7",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Child support grant top up",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135980,
+ "endTime": 1768892232653,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbd8": {
+ "qid": "696660bce56b708ddc8dfbd8",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Foster care grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135984,
+ "endTime": 1768892233147,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bce56b708ddc8dfbd9": {
+ "qid": "696660bce56b708ddc8dfbd9",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Government disability grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135989,
+ "endTime": 1768892233558,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbda": {
+ "qid": "696660bde56b708ddc8dfbda",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "War veterans grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135993,
+ "endTime": 1768892234216,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbdb": {
+ "qid": "696660bde56b708ddc8dfbdb",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Covid-19 social grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135996,
+ "endTime": 1768892235268,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbdc": {
+ "qid": "696660bde56b708ddc8dfbdc",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Social Relief of Distress (SRD) grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135999,
+ "endTime": 1768892235815,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbdd": {
+ "qid": "696660bde56b708ddc8dfbdd",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Grant for older persons",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136001,
+ "endTime": 1768892236165,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbde": {
+ "qid": "696660bde56b708ddc8dfbde",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Care dependency grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136004,
+ "endTime": 1768892236497,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbdf": {
+ "qid": "696660bde56b708ddc8dfbdf",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Grant-in-Aid",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136007,
+ "endTime": 1768892236827,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbe0": {
+ "qid": "696660bde56b708ddc8dfbe0",
+ "value": [
+ "R2"
+ ],
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Now, which of these grants do YOU receive?",
+ ""
+ ],
+ "labels": [
+ "R2"
+ ],
+ "responseType": "multiselect-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136009,
+ "endTime": 1768892240771,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "multiselect-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbe1": {
+ "qid": "696660bde56b708ddc8dfbe1",
+ "value": "R2",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Unemployment insurance fund/UIF/UIF TERS Covid Benefits",
+ ""
+ ],
+ "labels": [
+ "R2"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136021,
+ "endTime": 1768892243834,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbe2": {
+ "qid": "696660bde56b708ddc8dfbe2",
+ "value": "R2",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Income from household business",
+ ""
+ ],
+ "labels": [
+ "R2"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136027,
+ "endTime": 1768892246041,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbe3": {
+ "qid": "696660bde56b708ddc8dfbe3",
+ "value": "R2",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wages from PUBLIC SECTOR job",
+ ""
+ ],
+ "labels": [
+ "R2"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136033,
+ "endTime": 1768892247941,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbe4": {
+ "qid": "696660bde56b708ddc8dfbe4",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wages from PRIVATE SECTOR job",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136041,
+ "endTime": 1768892249559,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbe5": {
+ "qid": "696660bde56b708ddc8dfbe5",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wage from individuals (domestic worker, gardener)",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136051,
+ "endTime": 1768892250456,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbe6": {
+ "qid": "696660bde56b708ddc8dfbe6",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from rent you receive",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136063,
+ "endTime": 1768892251059,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbe7": {
+ "qid": "696660bde56b708ddc8dfbe7",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Piece job (fixed piece rate for task)",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136071,
+ "endTime": 1768892251580,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbe8": {
+ "qid": "696660bde56b708ddc8dfbe8",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Work pension or provident fund",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136078,
+ "endTime": 1768892252293,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbe9": {
+ "qid": "696660bde56b708ddc8dfbe9",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from friend or family member",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136087,
+ "endTime": 1768892254554,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbea": {
+ "qid": "696660bde56b708ddc8dfbea",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from maintenance from former spouse/partner",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136094,
+ "endTime": 1768892255359,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbeb": {
+ "qid": "696660bde56b708ddc8dfbeb",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Other income source",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136102,
+ "endTime": 1768892255927,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbec": {
+ "qid": "696660bde56b708ddc8dfbec",
+ "value": "hello",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Please specify other income source",
+ ""
+ ],
+ "labels": [
+ "hello"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136111,
+ "endTime": 1768892261589,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbed": {
+ "qid": "696660bde56b708ddc8dfbed",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Unemployment insurance fund/UIF/UIF TERS Covid Benefits",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136116,
+ "endTime": 1768892262794,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbee": {
+ "qid": "696660bde56b708ddc8dfbee",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Income from my own business",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136126,
+ "endTime": 1768892263361,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbef": {
+ "qid": "696660bde56b708ddc8dfbef",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wages from PUBLIC SECTOR job",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136138,
+ "endTime": 1768892263920,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbf0": {
+ "qid": "696660bde56b708ddc8dfbf0",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wages from PRIVATE SECTOR job",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136146,
+ "endTime": 1768892264477,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbf1": {
+ "qid": "696660bde56b708ddc8dfbf1",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wage from individuals (domestic worker, gardener)",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136152,
+ "endTime": 1768892264949,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbf2": {
+ "qid": "696660bde56b708ddc8dfbf2",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from rent you receive",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136159,
+ "endTime": 1768892265483,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbf3": {
+ "qid": "696660bde56b708ddc8dfbf3",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Piece job (fixed piece rate for task)",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136169,
+ "endTime": 1768892266078,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbf4": {
+ "qid": "696660bde56b708ddc8dfbf4",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Work pension or provident fund",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136177,
+ "endTime": 1768892266577,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbf5": {
+ "qid": "696660bde56b708ddc8dfbf5",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from friend or family member",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136185,
+ "endTime": 1768892267094,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbf6": {
+ "qid": "696660bde56b708ddc8dfbf6",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from maintenance from former spouse/partner",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136192,
+ "endTime": 1768892267580,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbf7": {
+ "qid": "696660bde56b708ddc8dfbf7",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Other income source",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136201,
+ "endTime": 1768892269177,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbf8": {
+ "qid": "696660bde56b708ddc8dfbf8",
+ "value": "hello",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Please specify other income source",
+ ""
+ ],
+ "labels": [
+ "hello"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136214,
+ "endTime": 1768892271723,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbf9": {
+ "qid": "696660bde56b708ddc8dfbf9",
+ "value": [
+ {
+ "696660bde56b708ddc8dfbfa": {
+ "qid": "696660bde56b708ddc8dfbfa",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Asset Type",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": 1768892281734,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbfb": {
+ "qid": "696660bde56b708ddc8dfbfb",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Specify Other Asset",
+ ""
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": "",
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": [
+ {
+ "operator": "===",
+ "value": "R13",
+ "_id": "696660bde56b708ddc8dfbfa"
+ }
+ ],
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbfc": {
+ "qid": "696660bde56b708ddc8dfbfc",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Quantity owned by household",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": 1768892283774,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbfd": {
+ "qid": "696660bde56b708ddc8dfbfd",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Quantity owned by you",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": 1768892285684,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbfe": {
+ "qid": "696660bde56b708ddc8dfbfe",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Value per unit (R)",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": 1768892288414,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ }
+ }
+ ],
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Asset Inventory",
+ ""
+ ],
+ "labels": [
+ [
+ {
+ "_id": "696660bde56b708ddc8dfbfa",
+ "externalId": "Q75_4766403683020-1768317117023",
+ "question": [
+ "Asset Type",
+ ""
+ ],
+ "tip": "",
+ "hint": "",
+ "responseType": "select-dropdown",
+ "value": "R1",
+ "isCompleted": false,
+ "showRemarks": false,
+ "remarks": "",
+ "visibleIf": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "Productive tools and equipment"
+ },
+ {
+ "value": "R2",
+ "label": "Land"
+ },
+ {
+ "value": "R3",
+ "label": "Cattle"
+ },
+ {
+ "value": "R4",
+ "label": "Horses"
+ },
+ {
+ "value": "R5",
+ "label": "Goats"
+ },
+ {
+ "value": "R6",
+ "label": "Sheep"
+ },
+ {
+ "value": "R7",
+ "label": "Chicken/duck/poultry"
+ },
+ {
+ "value": "R8",
+ "label": "Cell phone (smartphone)"
+ },
+ {
+ "value": "R9",
+ "label": "Cell phone (old)"
+ },
+ {
+ "value": "R10",
+ "label": "Radio"
+ },
+ {
+ "value": "R11",
+ "label": "Television"
+ },
+ {
+ "value": "R12",
+ "label": "Computer"
+ },
+ {
+ "value": "R13",
+ "label": "Other"
+ }
+ ],
+ "sliderOptions": [],
+ "children": [
+ "696660bde56b708ddc8dfbfb"
+ ],
+ "questionGroup": [
+ "A1"
+ ],
+ "questionType": "auto",
+ "modeOfCollection": "",
+ "usedForScoring": "",
+ "fileName": [],
+ "validation": {
+ "required": false
+ },
+ "accessibility": "",
+ "canBeNotApplicable": "false",
+ "instanceQuestions": [],
+ "isAGeneralQuestion": false,
+ "autoCapture": false,
+ "rubricLevel": "",
+ "sectionHeader": "",
+ "allowAudioRecording": false,
+ "page": "p4",
+ "questionNumber": "",
+ "prefillFromEntityProfile": false,
+ "entityFieldName": "",
+ "isEditable": true,
+ "showQuestionInPreview": false,
+ "createdFromQuestionId": "69666080e56b708ddc8dfb89",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "reportType": "default",
+ "updatedAt": "2026-01-13T15:11:57.036Z",
+ "createdAt": "2026-01-13T15:10:56.812Z",
+ "deleted": false,
+ "__v": 0,
+ "evidenceMethod": "OB",
+ "payload": {
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "rubricLevel": ""
+ },
+ "startTime": "",
+ "endTime": 1768892281734,
+ "gpsLocation": "",
+ "file": ""
+ },
+ {
+ "_id": "696660bde56b708ddc8dfbfb",
+ "externalId": "Q76_4766403683020-1768317117024",
+ "question": [
+ "Specify Other Asset",
+ ""
+ ],
+ "tip": "",
+ "hint": "",
+ "responseType": "text",
+ "isCompleted": false,
+ "showRemarks": false,
+ "remarks": "",
+ "visibleIf": [
+ {
+ "operator": "===",
+ "value": "R13",
+ "_id": "696660bde56b708ddc8dfbfa"
+ }
+ ],
+ "options": [],
+ "sliderOptions": [],
+ "children": [],
+ "questionGroup": [
+ "A1"
+ ],
+ "questionType": "auto",
+ "modeOfCollection": "",
+ "usedForScoring": "",
+ "fileName": [],
+ "validation": {
+ "required": false
+ },
+ "accessibility": "",
+ "canBeNotApplicable": "false",
+ "instanceQuestions": [],
+ "isAGeneralQuestion": false,
+ "autoCapture": false,
+ "rubricLevel": "",
+ "sectionHeader": "",
+ "allowAudioRecording": false,
+ "page": "p4",
+ "questionNumber": "",
+ "prefillFromEntityProfile": false,
+ "entityFieldName": "",
+ "isEditable": true,
+ "showQuestionInPreview": false,
+ "createdFromQuestionId": "69666080e56b708ddc8dfb90",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "reportType": "default",
+ "updatedAt": "2026-01-13T15:11:57.036Z",
+ "createdAt": "2026-01-13T15:10:56.831Z",
+ "deleted": false,
+ "__v": 0,
+ "evidenceMethod": "OB",
+ "payload": {
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "rubricLevel": ""
+ },
+ "startTime": "",
+ "endTime": "",
+ "gpsLocation": "",
+ "file": ""
+ },
+ {
+ "_id": "696660bde56b708ddc8dfbfc",
+ "externalId": "Q77_4766403683020-1768317117025",
+ "question": [
+ "Quantity owned by household",
+ ""
+ ],
+ "tip": "",
+ "hint": "",
+ "responseType": "number",
+ "value": 1,
+ "isCompleted": false,
+ "showRemarks": false,
+ "remarks": "",
+ "visibleIf": "",
+ "options": [],
+ "sliderOptions": [],
+ "children": [],
+ "questionGroup": [
+ "A1"
+ ],
+ "questionType": "auto",
+ "modeOfCollection": "",
+ "usedForScoring": "",
+ "fileName": [],
+ "validation": {
+ "required": false,
+ "IsNumber": "true"
+ },
+ "accessibility": "",
+ "canBeNotApplicable": "false",
+ "instanceQuestions": [],
+ "isAGeneralQuestion": false,
+ "autoCapture": false,
+ "rubricLevel": "",
+ "sectionHeader": "",
+ "allowAudioRecording": false,
+ "page": "p4",
+ "questionNumber": "",
+ "prefillFromEntityProfile": false,
+ "entityFieldName": "",
+ "isEditable": true,
+ "showQuestionInPreview": false,
+ "createdFromQuestionId": "69666080e56b708ddc8dfb98",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "reportType": "default",
+ "updatedAt": "2026-01-13T15:11:57.036Z",
+ "createdAt": "2026-01-13T15:10:56.856Z",
+ "deleted": false,
+ "__v": 0,
+ "evidenceMethod": "OB",
+ "payload": {
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "rubricLevel": ""
+ },
+ "startTime": "",
+ "endTime": 1768892283774,
+ "gpsLocation": "",
+ "file": ""
+ },
+ {
+ "_id": "696660bde56b708ddc8dfbfd",
+ "externalId": "Q78_4766403683020-1768317117026",
+ "question": [
+ "Quantity owned by you",
+ ""
+ ],
+ "tip": "",
+ "hint": "",
+ "responseType": "number",
+ "value": 1,
+ "isCompleted": false,
+ "showRemarks": false,
+ "remarks": "",
+ "visibleIf": "",
+ "options": [],
+ "sliderOptions": [],
+ "children": [],
+ "questionGroup": [
+ "A1"
+ ],
+ "questionType": "auto",
+ "modeOfCollection": "",
+ "usedForScoring": "",
+ "fileName": [],
+ "validation": {
+ "required": false,
+ "IsNumber": "true"
+ },
+ "accessibility": "",
+ "canBeNotApplicable": "false",
+ "instanceQuestions": [],
+ "isAGeneralQuestion": false,
+ "autoCapture": false,
+ "rubricLevel": "",
+ "sectionHeader": "",
+ "allowAudioRecording": false,
+ "page": "p4",
+ "questionNumber": "",
+ "prefillFromEntityProfile": false,
+ "entityFieldName": "",
+ "isEditable": true,
+ "showQuestionInPreview": false,
+ "createdFromQuestionId": "69666080e56b708ddc8dfb9f",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "reportType": "default",
+ "updatedAt": "2026-01-13T15:11:57.036Z",
+ "createdAt": "2026-01-13T15:10:56.877Z",
+ "deleted": false,
+ "__v": 0,
+ "evidenceMethod": "OB",
+ "payload": {
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "rubricLevel": ""
+ },
+ "startTime": "",
+ "endTime": 1768892285684,
+ "gpsLocation": "",
+ "file": ""
+ },
+ {
+ "_id": "696660bde56b708ddc8dfbfe",
+ "externalId": "Q79_4766403683020-1768317117026",
+ "question": [
+ "Value per unit (R)",
+ ""
+ ],
+ "tip": "",
+ "hint": "",
+ "responseType": "number",
+ "value": 1,
+ "isCompleted": false,
+ "showRemarks": false,
+ "remarks": "",
+ "visibleIf": "",
+ "options": [],
+ "sliderOptions": [],
+ "children": [],
+ "questionGroup": [
+ "A1"
+ ],
+ "questionType": "auto",
+ "modeOfCollection": "",
+ "usedForScoring": "",
+ "fileName": [],
+ "validation": {
+ "required": false,
+ "IsNumber": "true"
+ },
+ "accessibility": "",
+ "canBeNotApplicable": "false",
+ "instanceQuestions": [],
+ "isAGeneralQuestion": false,
+ "autoCapture": false,
+ "rubricLevel": "",
+ "sectionHeader": "",
+ "allowAudioRecording": false,
+ "page": "p4",
+ "questionNumber": "",
+ "prefillFromEntityProfile": false,
+ "entityFieldName": "",
+ "isEditable": true,
+ "showQuestionInPreview": false,
+ "createdFromQuestionId": "69666080e56b708ddc8dfba6",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "reportType": "default",
+ "updatedAt": "2026-01-13T15:11:57.036Z",
+ "createdAt": "2026-01-13T15:10:56.909Z",
+ "deleted": false,
+ "__v": 0,
+ "evidenceMethod": "OB",
+ "payload": {
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "rubricLevel": ""
+ },
+ "startTime": "",
+ "endTime": 1768892288414,
+ "gpsLocation": "",
+ "file": ""
+ }
+ ]
+ ],
+ "responseType": "matrix",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": "",
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "matrix",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "countOfInstances": 1
+ }
+ },
+ "startTime": 1768894219120,
+ "endTime": 1768894222118,
+ "isSubmitted": false,
+ "gpsLocation": null,
+ "submittedBy": "3087",
+ "submittedByName": "Farabi Ahmedullah",
+ "submittedByEmail": null,
+ "submissionDate": "2026-01-20T07:30:24.523Z",
+ "isValid": true
+ }
+ ],
+ "hasConflicts": false
+ }
+ },
+ "criteria": [
+ {
+ "_id": "696660bde56b708ddc8dfc55",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "__v": 0,
+ "createdAt": "2026-01-13T15:11:57.240Z",
+ "criteriaType": "manual",
+ "deleted": false,
+ "description": "Facilitator & Administrative Details",
+ "externalId": "TDCL1_3765453411688-1768317117215",
+ "flag": "",
+ "frameworkCriteriaId": "69665ea0e56b708ddc8df9a3",
+ "name": "Facilitator & Administrative Details",
+ "owner": "3092",
+ "remarks": "",
+ "rubric": {
+ "name": "Facilitator & Administrative Details",
+ "description": "Facilitator & Administrative Details",
+ "type": "auto",
+ "levels": {
+ "L1": {
+ "level": "L1",
+ "label": "Level 1",
+ "description": "NA",
+ "expression": ""
+ }
+ }
+ },
+ "score": "",
+ "showRemarks": null,
+ "timesUsed": 12,
+ "updatedAt": "2026-01-13T15:11:57.240Z",
+ "weightage": 100
+ },
+ {
+ "_id": "696660bde56b708ddc8dfc57",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "__v": 0,
+ "createdAt": "2026-01-13T15:11:57.257Z",
+ "criteriaType": "manual",
+ "deleted": false,
+ "description": "Participant Details",
+ "externalId": "TDCL1_4765453411688-1768317117222",
+ "flag": "",
+ "frameworkCriteriaId": "69665ea0e56b708ddc8df9a4",
+ "name": "Participant Details",
+ "owner": "3092",
+ "remarks": "",
+ "rubric": {
+ "name": "Participant Details",
+ "description": "Participant Details",
+ "type": "auto",
+ "levels": {
+ "L1": {
+ "level": "L1",
+ "label": "Level 1",
+ "description": "NA",
+ "expression": ""
+ }
+ }
+ },
+ "score": "",
+ "showRemarks": null,
+ "timesUsed": 12,
+ "updatedAt": "2026-01-13T15:11:57.257Z",
+ "weightage": 100
+ },
+ {
+ "_id": "696660bde56b708ddc8dfc59",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "__v": 0,
+ "createdAt": "2026-01-13T15:11:57.274Z",
+ "criteriaType": "manual",
+ "deleted": false,
+ "description": "Household Composition",
+ "externalId": "TDCL1_5765453411688-1768317117225",
+ "flag": "",
+ "frameworkCriteriaId": "69665ea0e56b708ddc8df9a5",
+ "name": "Household Composition",
+ "owner": "3092",
+ "remarks": "",
+ "rubric": {
+ "name": "Household Composition",
+ "description": "Household Composition",
+ "type": "auto",
+ "levels": {
+ "L1": {
+ "level": "L1",
+ "label": "Level 1",
+ "description": "NA",
+ "expression": ""
+ }
+ }
+ },
+ "score": "",
+ "showRemarks": null,
+ "timesUsed": 12,
+ "updatedAt": "2026-01-13T15:11:57.274Z",
+ "weightage": 100
+ },
+ {
+ "_id": "696660bde56b708ddc8dfc5b",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "__v": 0,
+ "createdAt": "2026-01-13T15:11:57.295Z",
+ "criteriaType": "manual",
+ "deleted": false,
+ "description": "Government Grants",
+ "externalId": "TDCL1_6765453411688-1768317117227",
+ "flag": "",
+ "frameworkCriteriaId": "69665ea0e56b708ddc8df9a6",
+ "name": "Government Grants",
+ "owner": "3092",
+ "remarks": "",
+ "rubric": {
+ "name": "Government Grants",
+ "description": "Government Grants",
+ "type": "auto",
+ "levels": {
+ "L1": {
+ "level": "L1",
+ "label": "Level 1",
+ "description": "NA",
+ "expression": ""
+ }
+ }
+ },
+ "score": "",
+ "showRemarks": null,
+ "timesUsed": 12,
+ "updatedAt": "2026-01-13T15:11:57.295Z",
+ "weightage": 100
+ },
+ {
+ "_id": "696660bde56b708ddc8dfc5d",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "__v": 0,
+ "createdAt": "2026-01-13T15:11:57.311Z",
+ "criteriaType": "manual",
+ "deleted": false,
+ "description": "Household Income Sources",
+ "externalId": "TDCL1_7765453411688-1768317117230",
+ "flag": "",
+ "frameworkCriteriaId": "69665ea0e56b708ddc8df9a7",
+ "name": "Household Income Sources",
+ "owner": "3092",
+ "remarks": "",
+ "rubric": {
+ "name": "Household Income Sources",
+ "description": "Household Income Sources",
+ "type": "auto",
+ "levels": {
+ "L1": {
+ "level": "L1",
+ "label": "Level 1",
+ "description": "NA",
+ "expression": ""
+ }
+ }
+ },
+ "score": "",
+ "showRemarks": null,
+ "timesUsed": 12,
+ "updatedAt": "2026-01-13T15:11:57.311Z",
+ "weightage": 100
+ },
+ {
+ "_id": "696660bde56b708ddc8dfc5f",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "__v": 0,
+ "createdAt": "2026-01-13T15:11:57.325Z",
+ "criteriaType": "manual",
+ "deleted": false,
+ "description": "Participant Income Sources",
+ "externalId": "TDCL1_8765453411688-1768317117232",
+ "flag": "",
+ "frameworkCriteriaId": "69665ea0e56b708ddc8df9a8",
+ "name": "Participant Income Sources",
+ "owner": "3092",
+ "remarks": "",
+ "rubric": {
+ "name": "Participant Income Sources",
+ "description": "Participant Income Sources",
+ "type": "auto",
+ "levels": {
+ "L1": {
+ "level": "L1",
+ "label": "Level 1",
+ "description": "NA",
+ "expression": ""
+ }
+ }
+ },
+ "score": "",
+ "showRemarks": null,
+ "timesUsed": 12,
+ "updatedAt": "2026-01-13T15:11:57.325Z",
+ "weightage": 100
+ },
+ {
+ "_id": "696660bde56b708ddc8dfc61",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "__v": 0,
+ "createdAt": "2026-01-13T15:11:57.339Z",
+ "criteriaType": "manual",
+ "deleted": false,
+ "description": "Assets",
+ "externalId": "TDCL1_9765453411688-1768317117234",
+ "flag": "",
+ "frameworkCriteriaId": "69665ea0e56b708ddc8df9a9",
+ "name": "Assets",
+ "owner": "3092",
+ "remarks": "",
+ "rubric": {
+ "name": "Assets",
+ "description": "Assets",
+ "type": "auto",
+ "levels": {
+ "L1": {
+ "level": "L1",
+ "label": "Level 1",
+ "description": "NA",
+ "expression": ""
+ }
+ }
+ },
+ "score": "",
+ "showRemarks": null,
+ "timesUsed": 12,
+ "updatedAt": "2026-01-13T15:11:57.339Z",
+ "weightage": 100
+ }
+ ],
+ "themes": [
+ {
+ "type": "theme",
+ "label": "theme",
+ "name": "Observation Theme",
+ "externalId": "OB",
+ "weightage": 100,
+ "criteria": [
+ {
+ "criteriaId": "696660bde56b708ddc8dfc55",
+ "weightage": 100
+ },
+ {
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "weightage": 100
+ },
+ {
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "weightage": 100
+ },
+ {
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "weightage": 100
+ },
+ {
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "weightage": 100
+ },
+ {
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "weightage": 100
+ },
+ {
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "weightage": 100
+ }
+ ]
+ }
+ ],
+ "entityExternalId": "3090",
+ "entityInformation": {
+ "targetedEntityTypes": [],
+ "externalId": "3090",
+ "name": "Suvarna Kale",
+ "onBoardingProjectId": "696492a35f21a60014b6c4c5",
+ "status": "ONBOARDED",
+ "registryDetails": {
+ "code": "3090",
+ "locationId": "3090"
+ },
+ "parentInformation": {
+ "linkageChampion": [
+ {
+ "_id": "6953d07fe83c1c0014713c00",
+ "externalId": "3087",
+ "name": "Farabi Ahmedullah"
+ }
+ ]
+ },
+ "_id": "6953d07fe83c1c0014713c05",
+ "type": "participant",
+ "typeId": "6953d07ee83c1c0014713bf8"
+ },
+ "observationInformation": {
+ "name": "Household Profile",
+ "description": "Household Profile",
+ "createdBy": "3087",
+ "frameworkId": "69665f69e56b708ddc8df9b2",
+ "frameworkExternalId": "9ec11dfa-d787-11f0-ac92-4cd717431bdc",
+ "solutionId": "696660bde56b708ddc8dfc71",
+ "solutionExternalId": "9ec11dfa-d787-11f0-ac92-4cd717431bdc-OBSERVATION-TEMPLATE_CHILD",
+ "startDate": "2026-01-20T04:28:25.047Z",
+ "endDate": "2027-01-20T04:28:25.047Z",
+ "status": "published",
+ "entityTypeId": "6953d07ee83c1c0014713bf8",
+ "entityType": "participant",
+ "createdFor": [
+ "3087"
+ ],
+ "rootOrganisations": [],
+ "isAPrivateProgram": false,
+ "link": "d0fd0f793173c1dac39775504b2ecb22",
+ "isExternalProgram": false,
+ "userProfile": {
+ "id": "3087",
+ "email_verified": "false",
+ "name": "Farabi Ahmedullah",
+ "username": "farabi",
+ "phone_code": "91",
+ "about": "my self farabi",
+ "dob": "22-12-1990",
+ "share_link": null,
+ "status": "ACTIVE",
+ "image": null,
+ "has_accepted_terms_and_conditions": false,
+ "languages": null,
+ "preferred_language": "en",
+ "tenant_code": "brac",
+ "meta": null,
+ "created_at": "2025-12-29T06:28:30.499Z",
+ "updated_at": "2026-01-09T11:59:33.769Z",
+ "deleted_at": null,
+ "organizations": [
+ {
+ "id": "67",
+ "name": "BRAC GBL org",
+ "code": "brac_gbl",
+ "description": "BRAC GBL org",
+ "status": "ACTIVE",
+ "related_orgs": null,
+ "tenant_code": "brac",
+ "meta": null,
+ "created_by": null,
+ "updated_by": 1,
+ "roles": [
+ {
+ "id": "213",
+ "title": "session_manager",
+ "label": "Linkage Champion",
+ "user_type": 0,
+ "status": "ACTIVE",
+ "organization_id": "67",
+ "visibility": "PUBLIC",
+ "tenant_code": "brac"
+ },
+ {
+ "id": "214",
+ "title": "org_admin",
+ "label": "Supervisor",
+ "user_type": 0,
+ "status": "ACTIVE",
+ "organization_id": "67",
+ "visibility": "PUBLIC",
+ "tenant_code": "brac"
+ }
+ ]
+ }
+ ],
+ "permissions": [
+ {
+ "module": "user",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "form",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "cloud-services",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "organization",
+ "request_type": [
+ "POST",
+ "GET"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "entity-type",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "entity",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "PUT",
+ "PATCH",
+ "GET"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "org-admin",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "notification",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "account",
+ "request_type": [
+ "GET",
+ "POST"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "user-role",
+ "request_type": [
+ "GET",
+ "POST",
+ "DELETE",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "organization-feature",
+ "request_type": [
+ "POST",
+ "GET",
+ "PATCH",
+ "DELETE"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "feature",
+ "request_type": [
+ "GET"
+ ],
+ "service": "user"
+ }
+ ],
+ "image_cloud_path": null
+ },
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "updatedAt": "2026-01-20T04:28:25.230Z",
+ "createdAt": "2026-01-13T15:11:57.344Z"
+ },
+ "feedback": [],
+ "solutionId": "696660bde56b708ddc8dfc71",
+ "solutionExternalId": "9ec11dfa-d787-11f0-ac92-4cd717431bdc-OBSERVATION-TEMPLATE_CHILD",
+ "submissionsUpdatedHistory": [],
+ "entityType": "participant",
+ "programId": null,
+ "programExternalId": null,
+ "submissionNumber": 1,
+ "pointsBasedMaxScore": 0,
+ "pointsBasedScoreAchieved": 0,
+ "pointsBasedPercentageScore": 0,
+ "isAPrivateProgram": false,
+ "scoringSystem": null,
+ "isRubricDriven": false,
+ "userProfile": {
+ "id": "3087",
+ "email_verified": "false",
+ "name": "Farabi Ahmedullah Two",
+ "username": "farabi",
+ "phone_code": "91",
+ "about": "my self farabi Two",
+ "dob": "22-12-2000",
+ "share_link": null,
+ "status": "ACTIVE",
+ "image": null,
+ "has_accepted_terms_and_conditions": false,
+ "languages": null,
+ "preferred_language": "en",
+ "tenant_code": "brac",
+ "meta": null,
+ "created_at": "2025-12-29T06:28:30.499Z",
+ "updated_at": "2026-01-09T11:59:33.769Z",
+ "deleted_at": null,
+ "organizations": [
+ {
+ "id": "67",
+ "name": "BRAC GBL org",
+ "code": "brac_gbl",
+ "description": "BRAC GBL org",
+ "status": "ACTIVE",
+ "related_orgs": null,
+ "tenant_code": "brac",
+ "meta": null,
+ "created_by": null,
+ "updated_by": 1,
+ "roles": [
+ {
+ "id": "213",
+ "title": "session_manager",
+ "label": "Linkage Champion",
+ "user_type": 0,
+ "status": "ACTIVE",
+ "organization_id": "67",
+ "visibility": "PUBLIC",
+ "tenant_code": "brac"
+ },
+ {
+ "id": "214",
+ "title": "org_admin",
+ "label": "Supervisor",
+ "user_type": 0,
+ "status": "ACTIVE",
+ "organization_id": "67",
+ "visibility": "PUBLIC",
+ "tenant_code": "brac"
+ }
+ ]
+ }
+ ],
+ "permissions": [
+ {
+ "module": "user",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "form",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "cloud-services",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "organization",
+ "request_type": [
+ "POST",
+ "GET"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "entity-type",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "entity",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "PUT",
+ "PATCH",
+ "GET"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "org-admin",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "notification",
+ "request_type": [
+ "POST",
+ "DELETE",
+ "GET",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "account",
+ "request_type": [
+ "GET",
+ "POST"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "user-role",
+ "request_type": [
+ "GET",
+ "POST",
+ "DELETE",
+ "PUT",
+ "PATCH"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "organization-feature",
+ "request_type": [
+ "POST",
+ "GET",
+ "PATCH",
+ "DELETE"
+ ],
+ "service": "user"
+ },
+ {
+ "module": "feature",
+ "request_type": [
+ "GET"
+ ],
+ "service": "user"
+ }
+ ],
+ "image_cloud_path": null
+ },
+ "programInformation": null,
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "isExternalProgram": false,
+ "deleted": false,
+ "title": "Observation 1",
+ "updatedAt": "2026-01-20T07:30:24.603Z",
+ "createdAt": "2026-01-20T04:28:25.528Z",
+ "__v": 0,
+ "answers": {
+ "696660cdf56b708ddc8dfbb2": {
+ "qid": "696660cdf56b708ddc8dfbb2",
+ "value": "sagar",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Facilitator Name",
+ ""
+ ],
+ "labels": [
+ "sagar"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135767,
+ "endTime": 1768892119361,
+ "criteriaId": "696660bde56b708ddc8dfc55",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q1_4766403683020-1768917116969",
+ "question": [
+ "Facilitator Name",
+ ""
+ ],
+ "questionNumber": "",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbb2": {
+ "qid": "696660bce56b708ddc8dfbb2",
+ "value": "good",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Province",
+ ""
+ ],
+ "labels": [
+ "good"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135789,
+ "endTime": 1768892124079,
+ "criteriaId": "696660bde56b708ddc8dfc55",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q2_4766403683020-1768317116969",
+ "question": [
+ "Province",
+ ""
+ ],
+ "questionNumber": "2",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbb3": {
+ "qid": "696660bce56b708ddc8dfbb3",
+ "value": "20",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Pilot Site",
+ ""
+ ],
+ "labels": [
+ "20"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135796,
+ "endTime": 1768892127781,
+ "criteriaId": "696660bde56b708ddc8dfc55",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q3_4766403683020-1768317116970",
+ "question": [
+ "Pilot Site",
+ ""
+ ],
+ "questionNumber": "3",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbb4": {
+ "qid": "696660bce56b708ddc8dfbb4",
+ "value": "2026-01-20T06:55:00.000Z",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Date of Collection",
+ ""
+ ],
+ "labels": [
+ "2026-01-20T06:55:00.000Z"
+ ],
+ "responseType": "date",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135803,
+ "endTime": 1768892129231,
+ "criteriaId": "696660bde56b708ddc8dfc55",
+ "responseType": "date",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q4_4766403683020-1768317116971",
+ "question": [
+ "Date of Collection",
+ ""
+ ],
+ "questionNumber": "4",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbb5": {
+ "qid": "696660bce56b708ddc8dfbb5",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Record if the captured residential address is correct",
+ ""
+ ],
+ "labels": [
+ "Yes"
+ ],
+ "responseType": "radio",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135820,
+ "endTime": 1768892136961,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "radio",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "Yes"
+ },
+ {
+ "value": "R2",
+ "label": "No"
+ }
+ ],
+ "externalId": "Q5_4766403683020-1768317116971",
+ "question": [
+ "Record if the captured residential address is correct",
+ ""
+ ],
+ "questionNumber": "1",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbb6": {
+ "qid": "696660bce56b708ddc8dfbb6",
+ "value": "vaibhav",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "What is your name?",
+ ""
+ ],
+ "labels": [
+ "vaibhav"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135827,
+ "endTime": 1768892300964,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q6_4766403683020-1768317116972",
+ "question": [
+ "What is your name?",
+ ""
+ ],
+ "questionNumber": "2",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbb7": {
+ "qid": "696660bce56b708ddc8dfbb7",
+ "value": "123",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "What is your ID number?",
+ ""
+ ],
+ "labels": [
+ "123"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135845,
+ "endTime": 1768892306434,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q7_4766403683020-1768317116973",
+ "question": [
+ "What is your ID number?",
+ ""
+ ],
+ "questionNumber": "3",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbb8": {
+ "qid": "696660bce56b708ddc8dfbb8",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Is the respondent a man or a woman? (record from observation)",
+ ""
+ ],
+ "labels": [
+ "Man (Male)"
+ ],
+ "responseType": "radio",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135850,
+ "endTime": 1768892306546,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "radio",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "Man (Male)"
+ },
+ {
+ "value": "R2",
+ "label": "Woman (Female)"
+ },
+ {
+ "value": "R3",
+ "label": "Other"
+ }
+ ],
+ "externalId": "Q8_4766403683020-1768317116974",
+ "question": [
+ "Is the respondent a man or a woman? (record from observation)",
+ ""
+ ],
+ "questionNumber": "4",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbb9": {
+ "qid": "696660bce56b708ddc8dfbb9",
+ "value": "9876543210",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "What is your cell phone number?",
+ ""
+ ],
+ "labels": [
+ "9876543210"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135855,
+ "endTime": 1768892315705,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q9_4766403683020-1768317116974",
+ "question": [
+ "What is your cell phone number?",
+ ""
+ ],
+ "questionNumber": "5",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbba": {
+ "qid": "696660bce56b708ddc8dfbba",
+ "value": "9087654321",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Please may I have an alternative number for you?",
+ ""
+ ],
+ "labels": [
+ "9087654321"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135859,
+ "endTime": 1768892325383,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q10_4766403683020-1768317116975",
+ "question": [
+ "Please may I have an alternative number for you?",
+ ""
+ ],
+ "questionNumber": "6",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbbb": {
+ "qid": "696660bce56b708ddc8dfbbb",
+ "value": "sagar@gmail.com",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "And what is your email address?",
+ ""
+ ],
+ "labels": [
+ "sagar@gmail.com"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135865,
+ "endTime": 1768892330800,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q11_4766403683020-1768317116976",
+ "question": [
+ "And what is your email address?",
+ ""
+ ],
+ "questionNumber": "7",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbbc": {
+ "qid": "696660bce56b708ddc8dfbbc",
+ "value": "R2",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Does the respondent have any disabilities?",
+ ""
+ ],
+ "labels": [
+ "No"
+ ],
+ "responseType": "radio",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135868,
+ "endTime": 1768892332857,
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "radio",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "Yes"
+ },
+ {
+ "value": "R2",
+ "label": "No"
+ }
+ ],
+ "externalId": "Q12_4766403683020-1768317116977",
+ "question": [
+ "Does the respondent have any disabilities?",
+ ""
+ ],
+ "questionNumber": "8",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbbd": {
+ "qid": "696660bce56b708ddc8dfbbd",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Which disability?",
+ ""
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": "",
+ "criteriaId": "696660bde56b708ddc8dfc57",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": [
+ {
+ "operator": "===",
+ "value": "R1",
+ "_id": "696660bce56b708ddc8dfbbc"
+ }
+ ],
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q13_4766403683020-1768317116977",
+ "question": [
+ "Which disability?",
+ ""
+ ],
+ "questionNumber": "9",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbbe": {
+ "qid": "696660bce56b708ddc8dfbbe",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Who is the head of this household?",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135873,
+ "endTime": 1768892334962,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "Participant"
+ },
+ {
+ "value": "R2",
+ "label": "Participant\\'s spouse (wife, husband) or partner"
+ },
+ {
+ "value": "R3",
+ "label": "Participant\\'s parent"
+ },
+ {
+ "value": "R4",
+ "label": "Participant\\'s brother or sister"
+ },
+ {
+ "value": "R5",
+ "label": "Another family member"
+ },
+ {
+ "value": "R6",
+ "label": "Participant and someone else share equally"
+ },
+ {
+ "value": "R7",
+ "label": "Other (specify)"
+ }
+ ],
+ "externalId": "Q14_4766403683020-1768317116978",
+ "question": [
+ "Who is the head of this household?",
+ ""
+ ],
+ "questionNumber": "1",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbbf": {
+ "qid": "696660bce56b708ddc8dfbbf",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Please specify:",
+ ""
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": "",
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": [
+ {
+ "operator": "===",
+ "value": "R7",
+ "_id": "696660bce56b708ddc8dfbbe"
+ }
+ ],
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q15_4766403683020-1768317116979",
+ "question": [
+ "Please specify:",
+ ""
+ ],
+ "questionNumber": "2",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbc0": {
+ "qid": "696660bce56b708ddc8dfbc0",
+ "value": "R2",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Do you have children under the age of 18 living with you here in this household?",
+ ""
+ ],
+ "labels": [
+ "No"
+ ],
+ "responseType": "radio",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135884,
+ "endTime": 1768892338963,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "radio",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "Yes"
+ },
+ {
+ "value": "R2",
+ "label": "No"
+ }
+ ],
+ "externalId": "Q16_4766403683020-1768317116981",
+ "question": [
+ "Do you have children under the age of 18 living with you here in this household?",
+ ""
+ ],
+ "questionNumber": "3",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbc1": {
+ "qid": "696660bce56b708ddc8dfbc1",
+ "value": [],
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Children Information",
+ ""
+ ],
+ "labels": [],
+ "responseType": "matrix",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": "",
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "matrix",
+ "evidenceMethod": "OB",
+ "visibleIf": [
+ {
+ "operator": "===",
+ "value": "R1",
+ "_id": "696660bce56b708ddc8dfbc0"
+ }
+ ],
+ "rubricLevel": "",
+ "countOfInstances": 0,
+ "options": [],
+ "externalId": "Q17_4766403683020-1768317116981",
+ "question": [
+ "Children Information",
+ ""
+ ],
+ "questionNumber": "4",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbc6": {
+ "qid": "696660bce56b708ddc8dfbc6",
+ "value": 19,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "How many other people over the age of 18 are living in the household?",
+ ""
+ ],
+ "labels": [
+ 19
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135887,
+ "endTime": 1768892345891,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q22_4766403683020-1768317116985",
+ "question": [
+ "How many other people over the age of 18 are living in the household?",
+ ""
+ ],
+ "questionNumber": "9",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbc7": {
+ "qid": "696660bce56b708ddc8dfbc7",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "18-24 years",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135893,
+ "endTime": 1768892356170,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q23_4766403683020-1768317116985",
+ "question": [
+ "18-24 years",
+ ""
+ ],
+ "questionNumber": "10",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbc8": {
+ "qid": "696660bce56b708ddc8dfbc8",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "25-34 years",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135897,
+ "endTime": 1768892357034,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q24_4766403683020-1768317116986",
+ "question": [
+ "25-34 years",
+ ""
+ ],
+ "questionNumber": "11",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbc9": {
+ "qid": "696660bce56b708ddc8dfbc9",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "35-39 years",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135910,
+ "endTime": 1768892357822,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q25_4766403683020-1768317116987",
+ "question": [
+ "35-39 years",
+ ""
+ ],
+ "questionNumber": "12",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbca": {
+ "qid": "696660bce56b708ddc8dfbca",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "60 or older",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135914,
+ "endTime": 1768892359002,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q26_4766403683020-1768317116988",
+ "question": [
+ "60 or older",
+ ""
+ ],
+ "questionNumber": "13",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbcb": {
+ "qid": "696660bce56b708ddc8dfbcb",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Never been to school",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135917,
+ "endTime": 1768892360178,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q27_4766403683020-1768317116988",
+ "question": [
+ "Never been to school",
+ ""
+ ],
+ "questionNumber": "14",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbcc": {
+ "qid": "696660bce56b708ddc8dfbcc",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Crèche/nursery school",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135921,
+ "endTime": 1768892360528,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q28_4766403683020-1768317116989",
+ "question": [
+ "Crèche/nursery school",
+ ""
+ ],
+ "questionNumber": "15",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbcd": {
+ "qid": "696660bce56b708ddc8dfbcd",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Some primary school",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135924,
+ "endTime": 1768892360787,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q29_4766403683020-1768317116990",
+ "question": [
+ "Some primary school",
+ ""
+ ],
+ "questionNumber": "16",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbce": {
+ "qid": "696660bce56b708ddc8dfbce",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Primary completed",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135927,
+ "endTime": 1768892361132,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q30_4766403683020-1768317116991",
+ "question": [
+ "Primary completed",
+ ""
+ ],
+ "questionNumber": "17",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbcf": {
+ "qid": "696660bce56b708ddc8dfbcf",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Some high school",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135929,
+ "endTime": 1768892361495,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q31_4766403683020-1768317116991",
+ "question": [
+ "Some high school",
+ ""
+ ],
+ "questionNumber": "18",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbd0": {
+ "qid": "696660bce56b708ddc8dfbd0",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "High school completed (Matric)",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135932,
+ "endTime": 1768892362105,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q32_4766403683020-1768317116992",
+ "question": [
+ "High school completed (Matric)",
+ ""
+ ],
+ "questionNumber": "19",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbd1": {
+ "qid": "696660bce56b708ddc8dfbd1",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "N. Qualification/Vocational training",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135935,
+ "endTime": 1768892362541,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q33_4766403683020-1768317116994",
+ "question": [
+ "N. Qualification/Vocational training",
+ ""
+ ],
+ "questionNumber": "20",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbd2": {
+ "qid": "696660bce56b708ddc8dfbd2",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Higher certificate",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135954,
+ "endTime": 1768892362828,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q34_4766403683020-1768317116995",
+ "question": [
+ "Higher certificate",
+ ""
+ ],
+ "questionNumber": "21",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbd3": {
+ "qid": "696660bce56b708ddc8dfbd3",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Diploma",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135959,
+ "endTime": 1768892363139,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q35_4766403683020-1768317116995",
+ "question": [
+ "Diploma",
+ ""
+ ],
+ "questionNumber": "22",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbd4": {
+ "qid": "696660bce56b708ddc8dfbd4",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "University degree",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135967,
+ "endTime": 1768892363487,
+ "criteriaId": "696660bde56b708ddc8dfc59",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q36_4766403683020-1768317116996",
+ "question": [
+ "University degree",
+ ""
+ ],
+ "questionNumber": "23",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbd5": {
+ "qid": "696660bce56b708ddc8dfbd5",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "How many of each of these grants does your household receive?",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135974,
+ "endTime": 1768892231025,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q37_4766403683020-1768317116996",
+ "question": [
+ "How many of each of these grants does your household receive?",
+ ""
+ ],
+ "questionNumber": "1",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbd6": {
+ "qid": "696660bce56b708ddc8dfbd6",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Child support grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135977,
+ "endTime": 1768892231983,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q38_4766403683020-1768317116997",
+ "question": [
+ "Child support grant",
+ ""
+ ],
+ "questionNumber": "2",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbd7": {
+ "qid": "696660bce56b708ddc8dfbd7",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Child support grant top up",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135980,
+ "endTime": 1768892232653,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q39_4766403683020-1768317116998",
+ "question": [
+ "Child support grant top up",
+ ""
+ ],
+ "questionNumber": "3",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbd8": {
+ "qid": "696660bce56b708ddc8dfbd8",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Foster care grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135984,
+ "endTime": 1768892233147,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q40_4766403683020-1768317116999",
+ "question": [
+ "Foster care grant",
+ ""
+ ],
+ "questionNumber": "4",
+ "reportType": "default"
+ },
+ "696660bce56b708ddc8dfbd9": {
+ "qid": "696660bce56b708ddc8dfbd9",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Government disability grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135989,
+ "endTime": 1768892233558,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q41_4766403683020-1768317116999",
+ "question": [
+ "Government disability grant",
+ ""
+ ],
+ "questionNumber": "5",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbda": {
+ "qid": "696660bde56b708ddc8dfbda",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "War veterans grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135993,
+ "endTime": 1768892234216,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q42_4766403683020-1768317117000",
+ "question": [
+ "War veterans grant",
+ ""
+ ],
+ "questionNumber": "6",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbdb": {
+ "qid": "696660bde56b708ddc8dfbdb",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Covid-19 social grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135996,
+ "endTime": 1768892235268,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q43_4766403683020-1768317117000",
+ "question": [
+ "Covid-19 social grant",
+ ""
+ ],
+ "questionNumber": "7",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbdc": {
+ "qid": "696660bde56b708ddc8dfbdc",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Social Relief of Distress (SRD) grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886135999,
+ "endTime": 1768892235815,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q44_4766403683020-1768317117002",
+ "question": [
+ "Social Relief of Distress (SRD) grant",
+ ""
+ ],
+ "questionNumber": "8",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbdd": {
+ "qid": "696660bde56b708ddc8dfbdd",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Grant for older persons",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136001,
+ "endTime": 1768892236165,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q46_4766403683020-1768317117003",
+ "question": [
+ "Grant for older persons",
+ ""
+ ],
+ "questionNumber": "9",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbde": {
+ "qid": "696660bde56b708ddc8dfbde",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Care dependency grant",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136004,
+ "endTime": 1768892236497,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q47_4766403683020-1768317117004",
+ "question": [
+ "Care dependency grant",
+ ""
+ ],
+ "questionNumber": "10",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbdf": {
+ "qid": "696660bde56b708ddc8dfbdf",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Grant-in-Aid",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136007,
+ "endTime": 1768892236827,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q48_4766403683020-1768317117004",
+ "question": [
+ "Grant-in-Aid",
+ ""
+ ],
+ "questionNumber": "11",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbe0": {
+ "qid": "696660bde56b708ddc8dfbe0",
+ "value": [
+ "R2"
+ ],
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Now, which of these grants do YOU receive?",
+ ""
+ ],
+ "labels": [
+ "R2"
+ ],
+ "responseType": "multiselect-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136009,
+ "endTime": 1768892240771,
+ "criteriaId": "696660bde56b708ddc8dfc5b",
+ "responseType": "multiselect-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "Child support grant"
+ },
+ {
+ "value": "R2",
+ "label": "Child support grant top up"
+ },
+ {
+ "value": "R3",
+ "label": "Foster care grant"
+ },
+ {
+ "value": "R4",
+ "label": "Government disability grant"
+ },
+ {
+ "value": "R5",
+ "label": "War veterans grant"
+ },
+ {
+ "value": "R6",
+ "label": "Covid-19 social grant"
+ },
+ {
+ "value": "R7",
+ "label": "Social Relief of Distress (SRD) grant"
+ },
+ {
+ "value": "R8",
+ "label": "Grant for older persons"
+ },
+ {
+ "value": "R9",
+ "label": "Care dependency grant"
+ },
+ {
+ "value": "R10",
+ "label": "Grant-in-Aid"
+ }
+ ],
+ "externalId": "Q49_4766403683020-1768317117005",
+ "question": [
+ "Now, which of these grants do YOU receive?",
+ ""
+ ],
+ "questionNumber": "11",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbe1": {
+ "qid": "696660bde56b708ddc8dfbe1",
+ "value": "R2",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Unemployment insurance fund/UIF/UIF TERS Covid Benefits",
+ ""
+ ],
+ "labels": [
+ "R2"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136021,
+ "endTime": 1768892243834,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q50_4766403683020-1768317117006",
+ "question": [
+ "Unemployment insurance fund/UIF/UIF TERS Covid Benefits",
+ ""
+ ],
+ "questionNumber": "1",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbe2": {
+ "qid": "696660bde56b708ddc8dfbe2",
+ "value": "R2",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Income from household business",
+ ""
+ ],
+ "labels": [
+ "R2"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136027,
+ "endTime": 1768892246041,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q51_4766403683020-1768317117006",
+ "question": [
+ "Income from household business",
+ ""
+ ],
+ "questionNumber": "2",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbe3": {
+ "qid": "696660bde56b708ddc8dfbe3",
+ "value": "R2",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wages from PUBLIC SECTOR job",
+ ""
+ ],
+ "labels": [
+ "R2"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136033,
+ "endTime": 1768892247941,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q52_4766403683020-1768317117008",
+ "question": [
+ "Salary/wages from PUBLIC SECTOR job",
+ ""
+ ],
+ "questionNumber": "3",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbe4": {
+ "qid": "696660bde56b708ddc8dfbe4",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wages from PRIVATE SECTOR job",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136041,
+ "endTime": 1768892249559,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q53_4766403683020-1768317117009",
+ "question": [
+ "Salary/wages from PRIVATE SECTOR job",
+ ""
+ ],
+ "questionNumber": "4",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbe5": {
+ "qid": "696660bde56b708ddc8dfbe5",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wage from individuals (domestic worker, gardener)",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136051,
+ "endTime": 1768892250456,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q54_4766403683020-1768317117010",
+ "question": [
+ "Salary/wage from individuals (domestic worker, gardener)",
+ ""
+ ],
+ "questionNumber": "5",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbe6": {
+ "qid": "696660bde56b708ddc8dfbe6",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from rent you receive",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136063,
+ "endTime": 1768892251059,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q55_4766403683020-1768317117010",
+ "question": [
+ "Money from rent you receive",
+ ""
+ ],
+ "questionNumber": "6",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbe7": {
+ "qid": "696660bde56b708ddc8dfbe7",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Piece job (fixed piece rate for task)",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136071,
+ "endTime": 1768892251580,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q56_4766403683020-1768317117011",
+ "question": [
+ "Piece job (fixed piece rate for task)",
+ ""
+ ],
+ "questionNumber": "7",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbe8": {
+ "qid": "696660bde56b708ddc8dfbe8",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Work pension or provident fund",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136078,
+ "endTime": 1768892252293,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q57_4766403683020-1768317117012",
+ "question": [
+ "Work pension or provident fund",
+ ""
+ ],
+ "questionNumber": "8",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbe9": {
+ "qid": "696660bde56b708ddc8dfbe9",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from friend or family member",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136087,
+ "endTime": 1768892254554,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q58_4766403683020-1768317117012",
+ "question": [
+ "Money from friend or family member",
+ ""
+ ],
+ "questionNumber": "9",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbea": {
+ "qid": "696660bde56b708ddc8dfbea",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from maintenance from former spouse/partner",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136094,
+ "endTime": 1768892255359,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q59_4766403683020-1768317117013",
+ "question": [
+ "Money from maintenance from former spouse/partner",
+ ""
+ ],
+ "questionNumber": "10",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbeb": {
+ "qid": "696660bde56b708ddc8dfbeb",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Other income source",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136102,
+ "endTime": 1768892255927,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q60_4766403683020-1768317117013",
+ "question": [
+ "Other income source",
+ ""
+ ],
+ "questionNumber": "11",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbec": {
+ "qid": "696660bde56b708ddc8dfbec",
+ "value": "hello",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Please specify other income source",
+ ""
+ ],
+ "labels": [
+ "hello"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136111,
+ "endTime": 1768892261589,
+ "criteriaId": "696660bde56b708ddc8dfc5d",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q61_4766403683020-1768317117014",
+ "question": [
+ "Please specify other income source",
+ ""
+ ],
+ "questionNumber": "12",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbed": {
+ "qid": "696660bde56b708ddc8dfbed",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Unemployment insurance fund/UIF/UIF TERS Covid Benefits",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136116,
+ "endTime": 1768892262794,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q62_4766403683020-1768317117015",
+ "question": [
+ "Unemployment insurance fund/UIF/UIF TERS Covid Benefits",
+ ""
+ ],
+ "questionNumber": "13",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbee": {
+ "qid": "696660bde56b708ddc8dfbee",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Income from my own business",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136126,
+ "endTime": 1768892263361,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q63_4766403683020-1768317117015",
+ "question": [
+ "Income from my own business",
+ ""
+ ],
+ "questionNumber": "14",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbef": {
+ "qid": "696660bde56b708ddc8dfbef",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wages from PUBLIC SECTOR job",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136138,
+ "endTime": 1768892263920,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q64_4766403683020-1768317117016",
+ "question": [
+ "Salary/wages from PUBLIC SECTOR job",
+ ""
+ ],
+ "questionNumber": "15",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbf0": {
+ "qid": "696660bde56b708ddc8dfbf0",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wages from PRIVATE SECTOR job",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136146,
+ "endTime": 1768892264477,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q65_4766403683020-1768317117016",
+ "question": [
+ "Salary/wages from PRIVATE SECTOR job",
+ ""
+ ],
+ "questionNumber": "16",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbf1": {
+ "qid": "696660bde56b708ddc8dfbf1",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Salary/wage from individuals (domestic worker, gardener)",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136152,
+ "endTime": 1768892264949,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q66_4766403683020-1768317117017",
+ "question": [
+ "Salary/wage from individuals (domestic worker, gardener)",
+ ""
+ ],
+ "questionNumber": "17",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbf2": {
+ "qid": "696660bde56b708ddc8dfbf2",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from rent you receive",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136159,
+ "endTime": 1768892265483,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q67_4766403683020-1768317117018",
+ "question": [
+ "Money from rent you receive",
+ ""
+ ],
+ "questionNumber": "18",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbf3": {
+ "qid": "696660bde56b708ddc8dfbf3",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Piece job (fixed piece rate for task)",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136169,
+ "endTime": 1768892266078,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q68_4766403683020-1768317117018",
+ "question": [
+ "Piece job (fixed piece rate for task)",
+ ""
+ ],
+ "questionNumber": "19",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbf4": {
+ "qid": "696660bde56b708ddc8dfbf4",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Work pension or provident fund",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136177,
+ "endTime": 1768892266577,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q69_4766403683020-1768317117019",
+ "question": [
+ "Work pension or provident fund",
+ ""
+ ],
+ "questionNumber": "20",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbf5": {
+ "qid": "696660bde56b708ddc8dfbf5",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from friend or family member",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136185,
+ "endTime": 1768892267094,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q70_4766403683020-1768317117020",
+ "question": [
+ "Money from friend or family member",
+ ""
+ ],
+ "questionNumber": "21",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbf6": {
+ "qid": "696660bde56b708ddc8dfbf6",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Money from maintenance from former spouse/partner",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136192,
+ "endTime": 1768892267580,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q71_4766403683020-1768317117020",
+ "question": [
+ "Money from maintenance from former spouse/partner",
+ ""
+ ],
+ "questionNumber": "22",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbf7": {
+ "qid": "696660bde56b708ddc8dfbf7",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Other income source",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136201,
+ "endTime": 1768892269177,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "R0 - R1000"
+ },
+ {
+ "value": "R2",
+ "label": "R1001 – R3000"
+ },
+ {
+ "value": "R3",
+ "label": "R3001 - R5000"
+ },
+ {
+ "value": "R4",
+ "label": "R5001 - R7000"
+ },
+ {
+ "value": "R5",
+ "label": "R7001 – R9000"
+ },
+ {
+ "value": "R6",
+ "label": "R9001 – above"
+ }
+ ],
+ "externalId": "Q72_4766403683020-1768317117021",
+ "question": [
+ "Other income source",
+ ""
+ ],
+ "questionNumber": "23",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbf8": {
+ "qid": "696660bde56b708ddc8dfbf8",
+ "value": "hello",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Please specify other income source",
+ ""
+ ],
+ "labels": [
+ "hello"
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": 1768886136214,
+ "endTime": 1768892271723,
+ "criteriaId": "696660bde56b708ddc8dfc5f",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "options": [],
+ "externalId": "Q73_4766403683020-1768317117022",
+ "question": [
+ "Please specify other income source",
+ ""
+ ],
+ "questionNumber": "24",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbfa": {
+ "qid": "696660bde56b708ddc8dfbfa",
+ "gpsLocation": "",
+ "startTime": "",
+ "endTime": 1768892281734,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "instanceResponses": [
+ "R1"
+ ],
+ "instanceRemarks": [
+ ""
+ ],
+ "instanceFileName": [
+ []
+ ],
+ "options": [
+ {
+ "value": "R1",
+ "label": "Productive tools and equipment"
+ },
+ {
+ "value": "R2",
+ "label": "Land"
+ },
+ {
+ "value": "R3",
+ "label": "Cattle"
+ },
+ {
+ "value": "R4",
+ "label": "Horses"
+ },
+ {
+ "value": "R5",
+ "label": "Goats"
+ },
+ {
+ "value": "R6",
+ "label": "Sheep"
+ },
+ {
+ "value": "R7",
+ "label": "Chicken/duck/poultry"
+ },
+ {
+ "value": "R8",
+ "label": "Cell phone (smartphone)"
+ },
+ {
+ "value": "R9",
+ "label": "Cell phone (old)"
+ },
+ {
+ "value": "R10",
+ "label": "Radio"
+ },
+ {
+ "value": "R11",
+ "label": "Television"
+ },
+ {
+ "value": "R12",
+ "label": "Computer"
+ },
+ {
+ "value": "R13",
+ "label": "Other"
+ }
+ ],
+ "externalId": "Q75_4766403683020-1768317117023",
+ "question": [
+ "Asset Type",
+ ""
+ ],
+ "questionNumber": "26",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbfb": {
+ "qid": "696660bde56b708ddc8dfbfb",
+ "gpsLocation": "",
+ "startTime": "",
+ "endTime": "",
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": [
+ {
+ "operator": "===",
+ "value": "R13",
+ "_id": "696660bde56b708ddc8dfbfa"
+ }
+ ],
+ "rubricLevel": "",
+ "instanceResponses": [
+ null
+ ],
+ "instanceRemarks": [
+ ""
+ ],
+ "instanceFileName": [
+ []
+ ],
+ "options": [],
+ "externalId": "Q76_4766403683020-1768317117024",
+ "question": [
+ "Specify Other Asset",
+ ""
+ ],
+ "questionNumber": "27",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbfc": {
+ "qid": "696660bde56b708ddc8dfbfc",
+ "gpsLocation": "",
+ "startTime": "",
+ "endTime": 1768892283774,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "instanceResponses": [
+ 1
+ ],
+ "instanceRemarks": [
+ ""
+ ],
+ "instanceFileName": [
+ []
+ ],
+ "options": [],
+ "externalId": "Q77_4766403683020-1768317117025",
+ "question": [
+ "Quantity owned by household",
+ ""
+ ],
+ "questionNumber": "28",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbfd": {
+ "qid": "696660bde56b708ddc8dfbfd",
+ "gpsLocation": "",
+ "startTime": "",
+ "endTime": 1768892285684,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "instanceResponses": [
+ 1
+ ],
+ "instanceRemarks": [
+ ""
+ ],
+ "instanceFileName": [
+ []
+ ],
+ "options": [],
+ "externalId": "Q78_4766403683020-1768317117026",
+ "question": [
+ "Quantity owned by you",
+ ""
+ ],
+ "questionNumber": "29",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbfe": {
+ "qid": "696660bde56b708ddc8dfbfe",
+ "gpsLocation": "",
+ "startTime": "",
+ "endTime": 1768892288414,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "instanceResponses": [
+ 1
+ ],
+ "instanceRemarks": [
+ ""
+ ],
+ "instanceFileName": [
+ []
+ ],
+ "options": [],
+ "externalId": "Q79_4766403683020-1768317117026",
+ "question": [
+ "Value per unit (R)",
+ ""
+ ],
+ "questionNumber": "30",
+ "reportType": "default"
+ },
+ "696660bde56b708ddc8dfbf9": {
+ "qid": "696660bde56b708ddc8dfbf9",
+ "value": [
+ {
+ "696660bde56b708ddc8dfbfa": {
+ "qid": "696660bde56b708ddc8dfbfa",
+ "value": "R1",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Asset Type",
+ ""
+ ],
+ "labels": [
+ "R1"
+ ],
+ "responseType": "select-dropdown",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": 1768892281734,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbfb": {
+ "qid": "696660bde56b708ddc8dfbfb",
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Specify Other Asset",
+ ""
+ ],
+ "responseType": "text",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": "",
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "visibleIf": [
+ {
+ "operator": "===",
+ "value": "R13",
+ "_id": "696660bde56b708ddc8dfbfa"
+ }
+ ],
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbfc": {
+ "qid": "696660bde56b708ddc8dfbfc",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Quantity owned by household",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": 1768892283774,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbfd": {
+ "qid": "696660bde56b708ddc8dfbfd",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Quantity owned by you",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": 1768892285684,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ },
+ "696660bde56b708ddc8dfbfe": {
+ "qid": "696660bde56b708ddc8dfbfe",
+ "value": 1,
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Value per unit (R)",
+ ""
+ ],
+ "labels": [
+ 1
+ ],
+ "responseType": "number",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": 1768892288414,
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": ""
+ }
+ }
+ ],
+ "remarks": "",
+ "fileName": [],
+ "gpsLocation": "",
+ "payload": {
+ "question": [
+ "Asset Inventory",
+ ""
+ ],
+ "labels": [
+ [
+ {
+ "_id": "696660bde56b708ddc8dfbfa",
+ "externalId": "Q75_4766403683020-1768317117023",
+ "question": [
+ "Asset Type",
+ ""
+ ],
+ "tip": "",
+ "hint": "",
+ "responseType": "select-dropdown",
+ "value": "R1",
+ "isCompleted": false,
+ "showRemarks": false,
+ "remarks": "",
+ "visibleIf": "",
+ "options": [
+ {
+ "value": "R1",
+ "label": "Productive tools and equipment"
+ },
+ {
+ "value": "R2",
+ "label": "Land"
+ },
+ {
+ "value": "R3",
+ "label": "Cattle"
+ },
+ {
+ "value": "R4",
+ "label": "Horses"
+ },
+ {
+ "value": "R5",
+ "label": "Goats"
+ },
+ {
+ "value": "R6",
+ "label": "Sheep"
+ },
+ {
+ "value": "R7",
+ "label": "Chicken/duck/poultry"
+ },
+ {
+ "value": "R8",
+ "label": "Cell phone (smartphone)"
+ },
+ {
+ "value": "R9",
+ "label": "Cell phone (old)"
+ },
+ {
+ "value": "R10",
+ "label": "Radio"
+ },
+ {
+ "value": "R11",
+ "label": "Television"
+ },
+ {
+ "value": "R12",
+ "label": "Computer"
+ },
+ {
+ "value": "R13",
+ "label": "Other"
+ }
+ ],
+ "sliderOptions": [],
+ "children": [
+ "696660bde56b708ddc8dfbfb"
+ ],
+ "questionGroup": [
+ "A1"
+ ],
+ "questionType": "auto",
+ "modeOfCollection": "",
+ "usedForScoring": "",
+ "fileName": [],
+ "validation": {
+ "required": false
+ },
+ "accessibility": "",
+ "canBeNotApplicable": "false",
+ "instanceQuestions": [],
+ "isAGeneralQuestion": false,
+ "autoCapture": false,
+ "rubricLevel": "",
+ "sectionHeader": "",
+ "allowAudioRecording": false,
+ "page": "p4",
+ "questionNumber": "",
+ "prefillFromEntityProfile": false,
+ "entityFieldName": "",
+ "isEditable": true,
+ "showQuestionInPreview": false,
+ "createdFromQuestionId": "69666080e56b708ddc8dfb89",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "reportType": "default",
+ "updatedAt": "2026-01-13T15:11:57.036Z",
+ "createdAt": "2026-01-13T15:10:56.812Z",
+ "deleted": false,
+ "__v": 0,
+ "evidenceMethod": "OB",
+ "payload": {
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "select-dropdown",
+ "evidenceMethod": "OB",
+ "rubricLevel": ""
+ },
+ "startTime": "",
+ "endTime": 1768892281734,
+ "gpsLocation": "",
+ "file": ""
+ },
+ {
+ "_id": "696660bde56b708ddc8dfbfb",
+ "externalId": "Q76_4766403683020-1768317117024",
+ "question": [
+ "Specify Other Asset",
+ ""
+ ],
+ "tip": "",
+ "hint": "",
+ "responseType": "text",
+ "isCompleted": false,
+ "showRemarks": false,
+ "remarks": "",
+ "visibleIf": [
+ {
+ "operator": "===",
+ "value": "R13",
+ "_id": "696660bde56b708ddc8dfbfa"
+ }
+ ],
+ "options": [],
+ "sliderOptions": [],
+ "children": [],
+ "questionGroup": [
+ "A1"
+ ],
+ "questionType": "auto",
+ "modeOfCollection": "",
+ "usedForScoring": "",
+ "fileName": [],
+ "validation": {
+ "required": false
+ },
+ "accessibility": "",
+ "canBeNotApplicable": "false",
+ "instanceQuestions": [],
+ "isAGeneralQuestion": false,
+ "autoCapture": false,
+ "rubricLevel": "",
+ "sectionHeader": "",
+ "allowAudioRecording": false,
+ "page": "p4",
+ "questionNumber": "",
+ "prefillFromEntityProfile": false,
+ "entityFieldName": "",
+ "isEditable": true,
+ "showQuestionInPreview": false,
+ "createdFromQuestionId": "69666080e56b708ddc8dfb90",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "reportType": "default",
+ "updatedAt": "2026-01-13T15:11:57.036Z",
+ "createdAt": "2026-01-13T15:10:56.831Z",
+ "deleted": false,
+ "__v": 0,
+ "evidenceMethod": "OB",
+ "payload": {
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "text",
+ "evidenceMethod": "OB",
+ "rubricLevel": ""
+ },
+ "startTime": "",
+ "endTime": "",
+ "gpsLocation": "",
+ "file": ""
+ },
+ {
+ "_id": "696660bde56b708ddc8dfbfc",
+ "externalId": "Q77_4766403683020-1768317117025",
+ "question": [
+ "Quantity owned by household",
+ ""
+ ],
+ "tip": "",
+ "hint": "",
+ "responseType": "number",
+ "value": 1,
+ "isCompleted": false,
+ "showRemarks": false,
+ "remarks": "",
+ "visibleIf": "",
+ "options": [],
+ "sliderOptions": [],
+ "children": [],
+ "questionGroup": [
+ "A1"
+ ],
+ "questionType": "auto",
+ "modeOfCollection": "",
+ "usedForScoring": "",
+ "fileName": [],
+ "validation": {
+ "required": false,
+ "IsNumber": "true"
+ },
+ "accessibility": "",
+ "canBeNotApplicable": "false",
+ "instanceQuestions": [],
+ "isAGeneralQuestion": false,
+ "autoCapture": false,
+ "rubricLevel": "",
+ "sectionHeader": "",
+ "allowAudioRecording": false,
+ "page": "p4",
+ "questionNumber": "",
+ "prefillFromEntityProfile": false,
+ "entityFieldName": "",
+ "isEditable": true,
+ "showQuestionInPreview": false,
+ "createdFromQuestionId": "69666080e56b708ddc8dfb98",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "reportType": "default",
+ "updatedAt": "2026-01-13T15:11:57.036Z",
+ "createdAt": "2026-01-13T15:10:56.856Z",
+ "deleted": false,
+ "__v": 0,
+ "evidenceMethod": "OB",
+ "payload": {
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "rubricLevel": ""
+ },
+ "startTime": "",
+ "endTime": 1768892283774,
+ "gpsLocation": "",
+ "file": ""
+ },
+ {
+ "_id": "696660bde56b708ddc8dfbfd",
+ "externalId": "Q78_4766403683020-1768317117026",
+ "question": [
+ "Quantity owned by you",
+ ""
+ ],
+ "tip": "",
+ "hint": "",
+ "responseType": "number",
+ "value": 1,
+ "isCompleted": false,
+ "showRemarks": false,
+ "remarks": "",
+ "visibleIf": "",
+ "options": [],
+ "sliderOptions": [],
+ "children": [],
+ "questionGroup": [
+ "A1"
+ ],
+ "questionType": "auto",
+ "modeOfCollection": "",
+ "usedForScoring": "",
+ "fileName": [],
+ "validation": {
+ "required": false,
+ "IsNumber": "true"
+ },
+ "accessibility": "",
+ "canBeNotApplicable": "false",
+ "instanceQuestions": [],
+ "isAGeneralQuestion": false,
+ "autoCapture": false,
+ "rubricLevel": "",
+ "sectionHeader": "",
+ "allowAudioRecording": false,
+ "page": "p4",
+ "questionNumber": "",
+ "prefillFromEntityProfile": false,
+ "entityFieldName": "",
+ "isEditable": true,
+ "showQuestionInPreview": false,
+ "createdFromQuestionId": "69666080e56b708ddc8dfb9f",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "reportType": "default",
+ "updatedAt": "2026-01-13T15:11:57.036Z",
+ "createdAt": "2026-01-13T15:10:56.877Z",
+ "deleted": false,
+ "__v": 0,
+ "evidenceMethod": "OB",
+ "payload": {
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "rubricLevel": ""
+ },
+ "startTime": "",
+ "endTime": 1768892285684,
+ "gpsLocation": "",
+ "file": ""
+ },
+ {
+ "_id": "696660bde56b708ddc8dfbfe",
+ "externalId": "Q79_4766403683020-1768317117026",
+ "question": [
+ "Value per unit (R)",
+ ""
+ ],
+ "tip": "",
+ "hint": "",
+ "responseType": "number",
+ "value": 1,
+ "isCompleted": false,
+ "showRemarks": false,
+ "remarks": "",
+ "visibleIf": "",
+ "options": [],
+ "sliderOptions": [],
+ "children": [],
+ "questionGroup": [
+ "A1"
+ ],
+ "questionType": "auto",
+ "modeOfCollection": "",
+ "usedForScoring": "",
+ "fileName": [],
+ "validation": {
+ "required": false,
+ "IsNumber": "true"
+ },
+ "accessibility": "",
+ "canBeNotApplicable": "false",
+ "instanceQuestions": [],
+ "isAGeneralQuestion": false,
+ "autoCapture": false,
+ "rubricLevel": "",
+ "sectionHeader": "",
+ "allowAudioRecording": false,
+ "page": "p4",
+ "questionNumber": "",
+ "prefillFromEntityProfile": false,
+ "entityFieldName": "",
+ "isEditable": true,
+ "showQuestionInPreview": false,
+ "createdFromQuestionId": "69666080e56b708ddc8dfba6",
+ "orgId": "brac_gbl",
+ "tenantId": "brac",
+ "reportType": "default",
+ "updatedAt": "2026-01-13T15:11:57.036Z",
+ "createdAt": "2026-01-13T15:10:56.909Z",
+ "deleted": false,
+ "__v": 0,
+ "evidenceMethod": "OB",
+ "payload": {
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "number",
+ "evidenceMethod": "OB",
+ "rubricLevel": ""
+ },
+ "startTime": "",
+ "endTime": 1768892288414,
+ "gpsLocation": "",
+ "file": ""
+ }
+ ]
+ ],
+ "responseType": "matrix",
+ "filesNotUploaded": []
+ },
+ "startTime": "",
+ "endTime": "",
+ "criteriaId": "696660bde56b708ddc8dfc61",
+ "responseType": "matrix",
+ "evidenceMethod": "OB",
+ "visibleIf": "",
+ "rubricLevel": "",
+ "countOfInstances": 1,
+ "options": [],
+ "externalId": "Q74_4766403683020-1768317117023",
+ "question": [
+ "Asset Inventory",
+ ""
+ ],
+ "questionNumber": "25",
+ "reportType": "default"
+ }
+ },
+ "completedDate": "2026-01-20T07:30:24.603Z",
+ "solutionInfo": {
+ "_id": "696660bde56b708ddc8dfc71",
+ "name": "Household Profile",
+ "description": "Household Profile",
+ "scoringSystem": null,
+ "questionSequenceByEcm": {
+ "OB": {
+ "S1": [
+ "Q1_4766403683020-1768917116969",
+ "Q2_4766403683020-1768317116969",
+ "Q3_4766403683020-1768317116970",
+ "Q4_4766403683020-1768317116971",
+ "Q5_4766403683020-1768317116971",
+ "Q6_4766403683020-1768317116972",
+ "Q7_4766403683020-1768317116973",
+ "Q8_4766403683020-1768317116974",
+ "Q9_4766403683020-1768317116974",
+ "Q10_4766403683020-1768317116975",
+ "Q11_4766403683020-1768317116976",
+ "Q12_4766403683020-1768317116977",
+ "Q13_4766403683020-1768317116977",
+ "Q14_4766403683020-1768317116978",
+ "Q15_4766403683020-1768317116979",
+ "Q16_4766403683020-1768317116981",
+ "Q17_4766403683020-1768317116981",
+ "Q18_4766403683020-1768317116982",
+ "Q19_4766403683020-1768317116983",
+ "Q20_4766403683020-1768317116983",
+ "Q21_4766403683020-1768317116984",
+ "Q22_4766403683020-1768317116985",
+ "Q23_4766403683020-1768317116985",
+ "Q24_4766403683020-1768317116986",
+ "Q25_4766403683020-1768317116987",
+ "Q26_4766403683020-1768317116988",
+ "Q27_4766403683020-1768317116988",
+ "Q28_4766403683020-1768317116989",
+ "Q29_4766403683020-1768317116990",
+ "Q30_4766403683020-1768317116991",
+ "Q31_4766403683020-1768317116991",
+ "Q32_4766403683020-1768317116992",
+ "Q33_4766403683020-1768317116994",
+ "Q34_4766403683020-1768317116995",
+ "Q35_4766403683020-1768317116995",
+ "Q36_4766403683020-1768317116996"
+ ],
+ "S2": [
+ "Q37_4766403683020-1768317116996",
+ "Q38_4766403683020-1768317116997",
+ "Q39_4766403683020-1768317116998",
+ "Q40_4766403683020-1768317116999",
+ "Q41_4766403683020-1768317116999",
+ "Q42_4766403683020-1768317117000",
+ "Q43_4766403683020-1768317117000",
+ "Q44_4766403683020-1768317117002",
+ "Q46_4766403683020-1768317117003",
+ "Q47_4766403683020-1768317117004",
+ "Q48_4766403683020-1768317117004",
+ "Q49_4766403683020-1768317117005",
+ "Q50_4766403683020-1768317117006",
+ "Q51_4766403683020-1768317117006",
+ "Q52_4766403683020-1768317117008",
+ "Q53_4766403683020-1768317117009",
+ "Q54_4766403683020-1768317117010",
+ "Q55_4766403683020-1768317117010",
+ "Q56_4766403683020-1768317117011",
+ "Q57_4766403683020-1768317117012",
+ "Q58_4766403683020-1768317117012",
+ "Q59_4766403683020-1768317117013",
+ "Q60_4766403683020-1768317117013",
+ "Q61_4766403683020-1768317117014",
+ "Q62_4766403683020-1768317117015",
+ "Q63_4766403683020-1768317117015",
+ "Q64_4766403683020-1768317117016",
+ "Q65_4766403683020-1768317117016",
+ "Q66_4766403683020-1768317117017",
+ "Q67_4766403683020-1768317117018",
+ "Q68_4766403683020-1768317117018",
+ "Q69_4766403683020-1768317117019",
+ "Q70_4766403683020-1768317117020",
+ "Q71_4766403683020-1768317117020",
+ "Q72_4766403683020-1768317117021",
+ "Q73_4766403683020-1768317117022",
+ "Q74_4766403683020-1768317117023",
+ "Q75_4766403683020-1768317117023",
+ "Q76_4766403683020-1768317117024",
+ "Q77_4766403683020-1768317117025",
+ "Q78_4766403683020-1768317117026",
+ "Q79_4766403683020-1768317117026"
+ ]
+ }
+ }
+ },
+ "entityTypeId": "6953d07ee83c1c0014713bf8"
+}
\ No newline at end of file
diff --git a/stream-jobs/user-mapping-stream-processor/pom.xml b/stream-jobs/user-mapping-stream-processor/pom.xml
new file mode 100644
index 00000000..4ad2aa1c
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/pom.xml
@@ -0,0 +1,220 @@
+
+
+
+ 4.0.0
+
+ org.shikshalokam
+ data-pipeline
+ 1.0
+ ../../pom.xml
+
+ user-mapping-stream-processor
+ 1.0.0
+ jar
+ UserMappingStreamProcessor
+
+ Job for stream processing user mapping events
+
+
+
+ UTF-8
+ 1.4.0
+
+
+
+
+
+ org.shikshalokam
+ jobs-core
+ 1.0.0
+
+
+
+ org.shikshalokam
+ jobs-core
+ 1.0.0
+ test-jar
+ test
+
+
+
+
+ org.apache.flink
+ flink-scala_${scala.version}
+ ${flink.version}
+ provided
+
+
+ org.apache.flink
+ flink-streaming-scala_${scala.version}
+ ${flink.version}
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.15.3
+
+
+
+
+ org.scalatest
+ scalatest_${scala.version}
+ 3.0.6
+ test
+
+
+ org.apache.flink
+ flink-test-utils_${scala.version}
+ ${flink.version}
+ test
+
+
+ org.apache.flink
+ flink-runtime_${scala.version}
+ ${flink.version}
+ test
+ tests
+
+
+ org.mockito
+ mockito-core
+ 4.4.0
+ test
+
+
+
+
+
+ src/main/scala
+ src/test/scala
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 11
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.2.1
+
+
+
+ package
+
+ shade
+
+
+
+
+ com.google.code.findbugs:jsr305
+
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
+
+
+ org.shikshalokam.job.user.mapping.stream.processor.task.UserMappingStreamTask
+
+
+
+ reference.conf
+
+
+
+
+
+
+
+
+ net.alchim31.maven
+ scala-maven-plugin
+ 4.4.0
+
+ ${java.target.runtime}
+ ${java.target.runtime}
+ ${scala.maj.version}
+ false
+
+
+
+ scala-compile-first
+ process-resources
+
+ add-source
+ compile
+
+
+
+ scala-test-compile
+ process-test-resources
+
+ testCompile
+
+
+
+
+
+
+ maven-surefire-plugin
+ ${surefire.plugin.version}
+
+ false
+
+
+
+
+ org.scalatest
+ scalatest-maven-plugin
+ 1.0
+
+ ${project.build.directory}/surefire-reports
+ .
+ user-mapping-jobs-testsuite.txt
+
+
+
+ test
+
+ test
+
+
+
+
+
+
+ org.scoverage
+ scoverage-maven-plugin
+ ${scoverage.plugin.version}
+
+ ${scala.version}
+ true
+ true
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/stream-jobs/user-mapping-stream-processor/src/main/resources/field-mappings.conf b/stream-jobs/user-mapping-stream-processor/src/main/resources/field-mappings.conf
new file mode 100644
index 00000000..c781df81
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/main/resources/field-mappings.conf
@@ -0,0 +1,8 @@
+name = profile.name
+username = profile.username
+dob = profile.dob
+phone_code = profile.phoneCode
+about = profile.about
+preferred_language = profile.preferredLanguage
+tenant_code = profile.tenantCode
+# meta = profile.meta
\ No newline at end of file
diff --git a/stream-jobs/user-mapping-stream-processor/src/main/resources/user-mapping-stream.conf b/stream-jobs/user-mapping-stream-processor/src/main/resources/user-mapping-stream.conf
new file mode 100644
index 00000000..14bd03f1
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/main/resources/user-mapping-stream.conf
@@ -0,0 +1,36 @@
+include "base-config.conf"
+
+kafka {
+ # broker-servers is inherited from base-config.conf ("kafka:9092" for Docker)
+ # Only override if running outside Docker or using a different Kafka instance:
+ # broker-servers = "localhost:9092" # For local development outside Docker
+ # broker-servers = "your-kafka-host:9092" # For remote Kafka instance
+
+ input.topic = "brac.observation.submission.dev"
+ groupId = "dev.users"
+ output.topic = "sl-metabase-user-dashboard-dev"
+ output.mentoring.topic = "sl-metabase-mentoring-dashboard-dev"
+}
+
+task {
+ consumer.parallelism = 1
+ sl.users.stream.parallelism = 1
+ sl.metabase.dashboard.parallelism = 1
+}
+
+postgres{
+ host = "localhost"
+ port = "5432"
+ username = "postgres"
+ password = "Test@123"
+ database = "test"
+ tables = {
+ userMetrics = ${job.env}"_user_metrics"
+ dashboardMetadataTable = ${job.env}"_dashboard_metadata"
+ }
+}
+
+userService {
+ baseUrl = "http://172.132.44.221:7001"
+ authToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImlkIjozMDg3LCJuYW1lIjoiZmFyYWJpIHVwZGF0ZWQgdmlhIGRhdGFwaXBsaW5lIiwic2Vzc2lvbl9pZCI6MjMwMjksIm9yZ2FuaXphdGlvbl9pZHMiOlsiNjciXSwib3JnYW5pemF0aW9uX2NvZGVzIjpbImJyYWNfZ2JsIl0sInRlbmFudF9jb2RlIjoiYnJhYyIsIm9yZ2FuaXphdGlvbnMiOlt7ImlkIjo2NywibmFtZSI6IkJSQUMgR0JMIG9yZyIsImNvZGUiOiJicmFjX2dibCIsImRlc2NyaXB0aW9uIjoiQlJBQyBHQkwgb3JnIiwic3RhdHVzIjoiQUNUSVZFIiwicmVsYXRlZF9vcmdzIjpudWxsLCJ0ZW5hbnRfY29kZSI6ImJyYWMiLCJtZXRhIjpudWxsLCJjcmVhdGVkX2J5IjpudWxsLCJ1cGRhdGVkX2J5IjoxLCJyb2xlcyI6W3siaWQiOjIxMywidGl0bGUiOiJzZXNzaW9uX21hbmFnZXIiLCJsYWJlbCI6IkxpbmthZ2UgQ2hhbXBpb24iLCJ1c2VyX3R5cGUiOjAsInN0YXR1cyI6IkFDVElWRSIsIm9yZ2FuaXphdGlvbl9pZCI6NjcsInZpc2liaWxpdHkiOiJQVUJMSUMiLCJ0ZW5hbnRfY29kZSI6ImJyYWMiLCJ0cmFuc2xhdGlvbnMiOm51bGx9XX1dfSwiaWF0IjoxNzcwMDMyMTIxLCJleHAiOjE3NzAxMTg1MjF9.T-NEvC4BzBIDjF-NHFmOIZlL9XDF6AwcLUllNCZSSJU"
+}
diff --git a/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/domain/Event.scala b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/domain/Event.scala
new file mode 100644
index 00000000..dbc029e5
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/domain/Event.scala
@@ -0,0 +1,152 @@
+package org.shikshalokam.job.user.mapping.stream.processor.domain
+
+import org.shikshalokam.job.domain.reader.JobRequest
+
+import java.sql.Timestamp
+import java.text.SimpleDateFormat
+import java.time.Instant
+import scala.collection.JavaConverters._
+import scala.language.postfixOps
+
+class Event(eventMap: java.util.Map[String, Any], partition: Int, offset: Long) extends JobRequest(eventMap, partition, offset) {
+
+ def eventType: String = readOrDefault[String]("eventType", null)
+
+ def userId: Int = readOrDefault[Int]("id", -1)
+
+ def tenantCode: String = extractValue[String]("tenant_code").orNull
+
+// def username: String = extractValue[String]("username").orNull
+
+ def name: String = extractValue[String]("name").orNull
+
+ def status: String = extractValue[String]("status").orNull
+
+// def isDeleted: Boolean = extractValue[Boolean]("deleted").getOrElse(false)
+
+ def createdBy: Int = extractValue[Int]("created_by").getOrElse(-1)
+
+ def createdAt: Timestamp = parseTimestamp(extractValue[Any]("created_at").orNull)
+
+ def updatedAt: Timestamp = parseTimestamp(extractValue[Any]("updated_at").orNull)
+
+ def userProfileOneId: String = extractValue[String]("state.id").orNull
+
+ def userProfileOneName: String = extractValue[String]("state.name").orNull
+
+ def userProfileOneExternalId: String = extractValue[String]("state.externalId").orNull
+
+ def userProfileTwoId: String = extractValue[String]("district.id").orNull
+
+ def userProfileTwoName: String = extractValue[String]("district.name").orNull
+
+ def userProfileTwoExternalId: String = extractValue[String]("district.externalId").orNull
+
+ def userProfileThreeId: String = extractValue[String]("block.id").orNull
+
+ def userProfileThreeName: String = extractValue[String]("block.name").orNull
+
+ def userProfileThreeExternalId: String = extractValue[String]("block.externalId").orNull
+
+ def userProfileFourId: String = extractValue[String]("cluster.id").orNull
+
+ def userProfileFourName: String = extractValue[String]("cluster.name").orNull
+
+ def userProfileFourExternalId: String = extractValue[String]("cluster.externalId").orNull
+
+ def userProfileFiveId: String = extractValue[String]("school.id").orNull
+
+ def userProfileFiveName: String = extractValue[String]("school.name").orNull
+
+ def userProfileFiveExternalId: String = extractValue[String]("school.externalId").orNull
+
+ def organizations: List[Map[String, Any]] = {
+ val fromDefault = Option(readOrDefault[List[Map[String, Any]]]("organizations", null)).getOrElse(List.empty)
+
+ var fromNew: List[Map[String, Any]] = List.empty
+ var fromOld: List[Map[String, Any]] = List.empty
+
+ if (eventType == "update" || eventType == "bulk-update") {
+ fromNew = Option(readOrDefault[List[Map[String, Any]]]("newValues.organizations", null)).getOrElse(List.empty)
+ fromOld = Option(readOrDefault[List[Map[String, Any]]]("oldValues.organizations", null)).getOrElse(List.empty)
+ }
+
+ (fromDefault ++ fromOld ++ fromNew).distinct
+ }
+
+ def professionalRoleId: String = extractNestedValue[String]("professional_role", "id").orNull
+
+ def professionalRoleName: String = extractNestedValue[String]("professional_role", "name").orNull
+
+ def professionalSubroles: List[Map[String, Any]] = {
+ val defaultList = Option(readOrDefault[List[Map[String, Any]]]("professional_subroles", null)).getOrElse(List.empty)
+ val newList = if (isUpdateEvent) Option(readOrDefault[List[Map[String, Any]]]("newValues.professional_subroles", null)).getOrElse(List.empty) else List.empty
+ val oldList = if (isUpdateEvent) Option(readOrDefault[List[Map[String, Any]]]("oldValues.professional_subroles", null)).getOrElse(List.empty) else List.empty
+
+ (defaultList ++ oldList ++ newList).distinct
+ }
+
+ private def extractValue[T](key: String): Option[T] = {
+ val direct = Option(readOrDefault[T](key, null.asInstanceOf[T]))
+
+ var fromNew: Option[T] = None
+ var fromOld: Option[T] = None
+
+ if (eventType == "update" || eventType == "bulk-update") {
+ fromNew = Option(readOrDefault[T](s"newValues.$key", null.asInstanceOf[T]))
+ fromOld = Option(readOrDefault[T](s"oldValues.$key", null.asInstanceOf[T]))
+ }
+
+ (direct orElse fromNew orElse fromOld).filter(_ != null)
+ }
+
+ private val isUpdateEvent: Boolean = eventType == "update" || eventType == "bulk-update"
+
+ private def extractNestedValue[T](base: String, key: String): Option[T] = {
+ val defaultMap = Option(readOrDefault[Map[String, Any]](base, null)).getOrElse(Map.empty)
+ val newMap = if (isUpdateEvent) Option(readOrDefault[Map[String, Any]](s"newValues.$base", null)).getOrElse(Map.empty) else Map.empty
+ val oldMap = if (isUpdateEvent) Option(readOrDefault[Map[String, Any]](s"oldValues.$base", null)).getOrElse(Map.empty) else Map.empty
+
+ val combined = defaultMap ++ oldMap ++ newMap
+ Option(combined.getOrElse(key, null).asInstanceOf[T]).filter(_ != null)
+ }
+
+ private def parseTimestamp(value: Any): Timestamp = value match {
+ case ts: Timestamp => ts
+ case s: String if s.trim.nonEmpty =>
+ try {
+ Timestamp.valueOf(s)
+ } catch {
+ case _: IllegalArgumentException =>
+ try {
+ Timestamp.from(Instant.parse(s))
+ } catch {
+ case _: Exception =>
+ val formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
+ new Timestamp(formatter.parse(s).getTime)
+ }
+ }
+ case _ => new Timestamp(System.currentTimeMillis())
+ }
+
+ /**
+ * Extract userProfile from observation event
+ * Used for observation-submission events from Kafka topic dev.observation-submission
+ *
+ * @return Map containing userProfile data, or empty map if not found
+ */
+ def userProfile: java.util.Map[String, Any] = {
+ val userProfileValue = readOrDefault[Any]("userProfile", null)
+ if (userProfileValue != null) {
+ userProfileValue match {
+ case javaMap: java.util.Map[_, _] => javaMap.asInstanceOf[java.util.Map[String, Any]]
+ case scalaMap: scala.collection.Map[_, _] => scalaMap.asInstanceOf[scala.collection.Map[String, Any]].asJava
+ case _ => new java.util.HashMap[String, Any]()
+ }
+ } else {
+ new java.util.HashMap[String, Any]()
+ }
+ }
+
+}
+
diff --git a/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/domain/ObservationEvent.scala b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/domain/ObservationEvent.scala
new file mode 100644
index 00000000..f27bae7e
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/domain/ObservationEvent.scala
@@ -0,0 +1,90 @@
+package org.shikshalokam.job.user.mapping.stream.processor.domain
+
+import org.shikshalokam.job.domain.reader.JobRequest
+import ujson.Js
+
+import java.util
+import scala.collection.JavaConverters._
+
+/**
+ * Case class to represent observation submission events from Kafka
+ *
+ */
+class ObservationEvent(eventMap: java.util.Map[String, Any], partition: Int, offset: Long)
+ extends JobRequest(eventMap, partition, offset) {
+
+ def eventType: String = readOrDefault[String]("eventType", null)
+
+ def id: String = {
+ // Priority order: userProfile.id > entityId > id (root) > oldValues.id/newValues.id
+
+ // 1. Try userProfile.id first (highest priority)
+ val userProfileId = readOrDefault[Any]("userProfile.id", null)
+ if (userProfileId != null) {
+ return convertToString(userProfileId)
+ }
+
+ // 2. Try entityId at root level
+ val entityIdValue = readOrDefault[Any]("entityId", null)
+ if (entityIdValue != null) {
+ return convertToString(entityIdValue)
+ }
+
+ // 3. Try id at root level
+ val idValue = readOrDefault[Any]("id", null)
+ if (idValue != null) {
+ return convertToString(idValue)
+ }
+
+ // 4. For update events, try oldValues.id or newValues.id
+ if (eventType == "update" || eventType == "bulk-update") {
+ val newValuesId = readOrDefault[Any]("newValues.id", null)
+ if (newValuesId != null) {
+ return convertToString(newValuesId)
+ }
+
+ val oldValuesId = readOrDefault[Any]("oldValues.id", null)
+ if (oldValuesId != null) {
+ return convertToString(oldValuesId)
+ }
+ }
+
+ null
+ }
+
+ private def convertToString(value: Any): String = {
+ if (value == null) return null
+ value match {
+ case n: Number => n.toString
+ case s: String => s
+ case _ => value.toString
+ }
+ }
+
+ def organizationId: Long = {
+ val value = readOrDefault[Any]("organizationId", null)
+ value match {
+ case l: Long => l
+ case i: Int => i.toLong
+ case n: Number => n.longValue()
+ case _ => -1L
+ }
+ }
+
+ def observationData: util.Map[String, Any] = {
+ val userProfile = readOrDefault[Any]("userProfile", null)
+ if (userProfile != null) {
+ userProfile match {
+ case javaMap: util.Map[_, _] => javaMap.asInstanceOf[util.Map[String, Any]]
+ case scalaMap: scala.collection.Map[_, _] => scalaMap.asInstanceOf[scala.collection.Map[String, Any]].asJava
+ case _ => new util.HashMap[String, Any]()
+ }
+ } else {
+ new util.HashMap[String, Any]()
+ }
+ }
+
+ override def toString: String = {
+ s"ObservationEvent(eventType=$eventType, id=$id, organizationId=$organizationId)"
+ }
+}
diff --git a/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/functions/UserMappingStreamFunction.scala b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/functions/UserMappingStreamFunction.scala
new file mode 100644
index 00000000..bb0656e4
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/functions/UserMappingStreamFunction.scala
@@ -0,0 +1,163 @@
+package org.shikshalokam.job.user.mapping.stream.processor.functions
+
+import org.apache.flink.api.common.typeinfo.TypeInformation
+import org.apache.flink.configuration.Configuration
+import org.apache.flink.streaming.api.functions.ProcessFunction
+import org.shikshalokam.job.user.mapping.stream.processor.domain.ObservationEvent
+import org.shikshalokam.job.user.mapping.stream.processor.task.UserMappingStreamConfig
+import org.shikshalokam.job.user.mapping.stream.processor.util.{FieldMapper, UserApiClient}
+import org.shikshalokam.job.{BaseProcessFunction, Metrics}
+import org.slf4j.LoggerFactory
+import ujson.Obj
+
+import java.util
+import scala.collection.JavaConverters._
+import scala.util.{Failure, Success}
+
+class UserMappingStreamFunction(config: UserMappingStreamConfig)(implicit val mapTypeInfo: TypeInformation[ObservationEvent])
+ extends BaseProcessFunction[ObservationEvent, ObservationEvent](config) {
+
+ private[this] val logger = LoggerFactory.getLogger(classOf[UserMappingStreamFunction])
+
+ override def metricsList(): List[String] = {
+ List(config.skipCount, config.successCount, config.totalEventsCount)
+ }
+
+ override def open(parameters: Configuration): Unit = {
+ super.open(parameters)
+ FieldMapper.getMappings.foreach { case (source, target) =>
+ println(s"[UserMappingStreamFunction] Mapping: $source -> $target")
+ }
+ }
+
+ override def close(): Unit = {
+ super.close()
+ }
+
+ /**
+ * Recursively print all fields and values from a map structure
+ */
+ private def printAllFields(map: java.util.Map[String, Any], prefix: String = "", depth: Int = 0, maxDepth: Int = 5): Unit = {
+ if (depth > maxDepth) {
+ val fullKey = if (prefix.isEmpty) "[Max depth reached]" else s"$prefix[Max depth reached, truncating...]"
+ println(s"[UserMappingStreamFunction] $fullKey")
+ return
+ }
+
+ if (map == null || map.isEmpty) {
+ val fullKey = if (prefix.isEmpty) "[Empty map]" else s"$prefix = [Empty map]"
+ println(s"[UserMappingStreamFunction] $fullKey")
+ return
+ }
+
+ map.asScala.foreach { case (key, value) =>
+ val fullKey = if (prefix.isEmpty) key else s"$prefix.$key"
+ value match {
+ case nestedMap: java.util.Map[_, _] =>
+ println(s"[UserMappingStreamFunction] $fullKey = [Map with ${nestedMap.size()} entries]")
+ printAllFields(nestedMap.asInstanceOf[java.util.Map[String, Any]], fullKey, depth + 1, maxDepth)
+ case list: java.util.List[_] =>
+ println(s"[UserMappingStreamFunction] $fullKey = [List with ${list.size()} items]")
+ list.asScala.zipWithIndex.foreach { case (item, idx) =>
+ item match {
+ case itemMap: java.util.Map[_, _] =>
+ println(s"[UserMappingStreamFunction] $fullKey[$idx] = [Map]")
+ printAllFields(itemMap.asInstanceOf[java.util.Map[String, Any]], s"$fullKey[$idx]", depth + 1, maxDepth)
+ case _ =>
+ println(s"[UserMappingStreamFunction] $fullKey[$idx] = $item")
+ }
+ }
+ case _ =>
+ val valueStr = if (value != null) value.toString else "null"
+ val truncatedValue = if (valueStr.length > 200) valueStr.substring(0, 200) + "..." else valueStr
+ println(s"[UserMappingStreamFunction] $fullKey = $truncatedValue")
+ }
+ }
+ }
+
+ override def processElement(event: ObservationEvent, context: ProcessFunction[ObservationEvent, ObservationEvent]#Context, metrics: Metrics): Unit = {
+
+ try {
+ println(s"***************** Start Processing Observation Event *****************")
+
+ // Print all fields from the event map
+ val eventMap = event.getMap()
+ // printAllFields(eventMap)
+
+ // Update total events count metric
+ metrics.incCounter(config.totalEventsCount)
+
+ // Validate event - ensure id is present
+ val id = event.id
+ if (id == null || id.trim.isEmpty) {
+ logger.error("[UserMappingStreamFunction] id is null or empty")
+ metrics.incCounter(config.skipCount)
+ return
+ }
+
+ // Extract userProfile from observation event
+ // The observationData method already extracts userProfile from the event
+ val userProfile = event.observationData
+
+ if (userProfile == null || userProfile.isEmpty) {
+ logger.warn(s"[UserMappingStreamFunction] userProfile is null or empty for id=$id")
+ metrics.incCounter(config.skipCount)
+ return
+ }
+
+ // Transform userProfile data to profile format using FieldMapper
+ // FieldMapper will:
+ // 1. Only map allowed fields (name, username, dob, phoneCode, about, preferredLanguage, tenantCode, meta)
+ // 2. Skip fields that are null, empty, or missing
+ // 3. Return a profile object with only non-empty fields
+ val profileData = FieldMapper.transform(userProfile)
+
+ // Check if profile data contains any valid (non-empty) fields
+ // Only call API if at least one field is eligible for update
+ val profileObj = profileData.value.get("profile")
+ if (profileObj.isEmpty) {
+ logger.warn(s"[UserMappingStreamFunction] No profile object in transformed data for id=$id")
+ metrics.incCounter(config.skipCount)
+ return
+ }
+
+ val profileFields = profileObj.get.asInstanceOf[ujson.Obj].value
+ if (profileFields.isEmpty) {
+ logger.info(s"[UserMappingStreamFunction] No valid fields to update for id=$id - all fields were empty/null/missing")
+ metrics.incCounter(config.skipCount)
+ return
+ }
+
+ // Call User Service API to patch the profile
+ // Only non-empty fields will be included in the update request
+ println(s"[UserMappingStreamFunction] Calling UserApiClient.patchProfile for id=$id...")
+ UserApiClient.patchProfile(id, profileData, config.userServiceBaseUrl, config.userServiceAuthToken) match {
+ case Success(true) =>
+ logger.info(s"[UserMappingStreamFunction] Successfully updated profile for id=$id with fields: ${profileFields.keys.mkString(", ")}")
+ metrics.incCounter(config.successCount)
+
+ case Success(false) =>
+ logger.warn(s"[UserMappingStreamFunction] API returned success=false for id=$id")
+ metrics.incCounter(config.skipCount)
+
+ case Failure(exception) =>
+ logger.error(s"[UserMappingStreamFunction] Failed to update profile for id=$id", exception)
+ metrics.incCounter(config.skipCount)
+ // Log error but continue processing - don't crash the task for API failures
+ // The error is already logged and metrics are updated
+ }
+
+ println(s"***************** Completed Processing Observation Event for id=$id *****************")
+
+ } catch {
+ case e: Exception =>
+ logger.error(s"[UserMappingStreamFunction] Exception processing observation event", e)
+ e.printStackTrace()
+ metrics.incCounter(config.skipCount)
+ // Log error but continue processing - don't crash the task
+ // This ensures the pipeline continues processing other events even if one fails
+ // For truly fatal errors, Flink's checkpointing and monitoring will detect issues
+ }
+ }
+
+}
diff --git a/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/task/UserMappingStreamConfig.scala b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/task/UserMappingStreamConfig.scala
new file mode 100644
index 00000000..48db4907
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/task/UserMappingStreamConfig.scala
@@ -0,0 +1,149 @@
+package org.shikshalokam.job.user.mapping.stream.processor.task
+
+import com.typesafe.config.Config
+import org.apache.flink.api.common.typeinfo.TypeInformation
+import org.apache.flink.api.java.typeutils.TypeExtractor
+import org.apache.flink.streaming.api.scala.OutputTag
+import org.shikshalokam.job.BaseJobConfig
+import org.shikshalokam.job.user.mapping.stream.processor.domain.Event
+
+
+class UserMappingStreamConfig(override val config: Config) extends BaseJobConfig(config, "UsersMappingStreamJob") {
+
+ implicit val mapTypeInfo: TypeInformation[Event] = TypeExtractor.getForClass(classOf[Event])
+
+ // Kafka Topics Configuration
+ val inputTopic: String = config.getString("kafka.input.topic")
+ val outputTopic: String = config.getString("kafka.output.topic")
+ val mentoringOutputTopic: String = config.getString("kafka.output.mentoring.topic")
+
+ // Output Tags
+ val eventOutputTag: OutputTag[String] = OutputTag[String]("user-dashboard-output-event")
+ val mentoringEventOutputTag: OutputTag[String] = OutputTag[String]("user-mentoring-output-event")
+
+ // Parallelism
+ override val kafkaConsumerParallelism: Int = config.getInt("task.consumer.parallelism")
+ val usersStreamParallelism: Int = config.getInt("task.sl.users.stream.parallelism")
+ val metabaseDashboardParallelism: Int = config.getInt("task.sl.metabase.dashboard.parallelism")
+
+ // Consumers
+ val usersStreamConsumer: String = "user-stream-consumer"
+ val metabaseDashboardProducer: String = "metabase-users-dashboard-producer"
+ val mentoringDashboardProducer: String = "metabase-mentoring-dashboard-producer"
+
+ // Functions
+ val usersStreamFunction: String = "UserMappingStreamFunction"
+
+ // user submissions job metrics
+ val usersCleanupHit: String = "user-cleanup-hit"
+ val skipCount: String = "skipped-message-count"
+ val successCount: String = "success-message-count"
+ val totalEventsCount: String = "total-user-events-count"
+
+
+ // PostgreSQL connection config
+ val pgHost: String = config.getString("postgres.host")
+ val pgPort: String = config.getString("postgres.port")
+ val pgUsername: String = config.getString("postgres.username")
+ val pgPassword: String = config.getString("postgres.password")
+ val pgDataBase: String = config.getString("postgres.database")
+ val userMetrics: String = config.getString("postgres.tables.userMetrics")
+ val dashboardMetadata: String = config.getString("postgres.tables.dashboardMetadataTable")
+
+ // User Service API Configuration
+ val userServiceBaseUrl: String = config.getString("userService.baseUrl")
+ val userServiceAuthToken: String = config.getString("userService.authToken")
+
+ val createTenantUserMetadataTable: String =
+ s"""
+ |CREATE TABLE IF NOT EXISTS @tenantTable (
+ | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
+ | user_id INT,
+ | attribute_code TEXT,
+ | attribute_value TEXT,
+ | attribute_label TEXT,
+ | UNIQUE (user_id, attribute_value)
+ |);
+ """.stripMargin
+
+ val createOrgRolesTable: String =
+ s"""
+ |CREATE TABLE IF NOT EXISTS @orgRolesTable (
+ | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
+ | user_id INT,
+ | org_id INT,
+ | org_name TEXT,
+ | role_id INT,
+ | role_name TEXT,
+ | UNIQUE (user_id, org_id, role_id)
+ |);
+ """.stripMargin
+
+ val createTenantUserTable: String =
+ s"""
+ |CREATE TABLE IF NOT EXISTS @usersTable (
+ | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
+ | user_id INT UNIQUE,
+ | tenant_code TEXT,
+ | username TEXT,
+ | name TEXT,
+ | status TEXT,
+ | is_deleted BOOLEAN,
+ | created_by INT,
+ | created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ | updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ | user_profile_one_id TEXT,
+ | user_profile_one_name TEXT,
+ | user_profile_one_external_id TEXT,
+ | user_profile_two_id TEXT,
+ | user_profile_two_name TEXT,
+ | user_profile_two_external_id TEXT,
+ | user_profile_three_id TEXT,
+ | user_profile_three_name TEXT,
+ | user_profile_three_external_id TEXT,
+ | user_profile_four_id TEXT,
+ | user_profile_four_name TEXT,
+ | user_profile_four_external_id TEXT,
+ | user_profile_five_id TEXT,
+ | user_profile_five_name TEXT,
+ | user_profile_five_external_id TEXT
+ |);
+ """.stripMargin
+
+ val createUserMetricsTable: String =
+ s"""
+ |CREATE TABLE IF NOT EXISTS $userMetrics (
+ | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
+ | tenant_code TEXT UNIQUE,
+ | total_users INT,
+ | active_users INT,
+ | deleted_users INT,
+ | last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ |);
+ """.stripMargin
+
+ val createDashboardMetadataTable: String =
+ s"""
+ |CREATE TABLE IF NOT EXISTS $dashboardMetadata (
+ | id SERIAL PRIMARY KEY,
+ | entity_type TEXT NOT NULL,
+ | entity_name TEXT NOT NULL,
+ | entity_id TEXT UNIQUE NOT NULL,
+ | report_type TEXT,
+ | is_rubrics Boolean,
+ | parent_name TEXT,
+ | linked_to TEXT,
+ | main_metadata JSON,
+ | mi_metadata JSON,
+ | comparison_metadata JSON,
+ | status TEXT,
+ | error_message TEXT,
+ | state_details_url_state TEXT,
+ | state_details_url_admin TEXT,
+ | district_details_url_district TEXT,
+ | district_details_url_state TEXT,
+ | district_details_url_admin TEXT
+ |);
+ """.stripMargin
+
+}
\ No newline at end of file
diff --git a/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/task/UserMappingStreamTask.scala b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/task/UserMappingStreamTask.scala
new file mode 100644
index 00000000..f0b61e22
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/task/UserMappingStreamTask.scala
@@ -0,0 +1,104 @@
+package org.shikshalokam.job.user.mapping.stream.processor.task
+
+import com.typesafe.config.ConfigFactory
+import org.apache.flink.api.common.typeinfo.TypeInformation
+import org.apache.flink.api.java.typeutils.TypeExtractor
+import org.apache.flink.api.java.utils.ParameterTool
+import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
+import org.shikshalokam.job.connector.FlinkKafkaConnector
+import org.shikshalokam.job.user.mapping.stream.processor.domain.ObservationEvent
+import org.shikshalokam.job.user.mapping.stream.processor.functions.UserMappingStreamFunction
+import org.shikshalokam.job.util.FlinkUtil
+
+import java.io.File
+
+class UserMappingStreamTask(config: UserMappingStreamConfig, kafkaConnector: FlinkKafkaConnector){
+
+ private val serialVersionUID = -7729362727131516112L
+ def process(): Unit = {
+ implicit val env: StreamExecutionEnvironment = FlinkUtil.getExecutionContext(config)
+ implicit val eventTypeInfo: TypeInformation[ObservationEvent] = TypeExtractor.getForClass(classOf[ObservationEvent])
+ implicit val stringTypeInfo: TypeInformation[String] = TypeExtractor.getForClass(classOf[String])
+ val source = kafkaConnector.kafkaJobRequestSource[ObservationEvent](config.inputTopic)
+
+ val progressStream = env.addSource(source).name(config.usersStreamConsumer)
+ .uid(config.usersStreamConsumer).setParallelism(config.kafkaConsumerParallelism)
+ .rebalance
+ .process(new UserMappingStreamFunction(config))
+ .name(config.usersStreamFunction).uid(config.usersStreamFunction)
+ .setParallelism(config.usersStreamParallelism)
+
+ progressStream.getSideOutput(config.eventOutputTag)
+ .addSink(kafkaConnector.kafkaStringSink(config.outputTopic))
+ .name(config.metabaseDashboardProducer)
+ .uid(config.metabaseDashboardProducer)
+ .setParallelism(config.metabaseDashboardParallelism)
+
+ // sink for mentoring dashboard events (new)
+ progressStream.getSideOutput(config.mentoringEventOutputTag)
+ .addSink(kafkaConnector.kafkaStringSink(config.mentoringOutputTopic))
+ .name(config.mentoringDashboardProducer)
+ .uid(config.mentoringDashboardProducer)
+ .setParallelism(config.metabaseDashboardParallelism)
+
+ env.execute(config.jobName)
+ }
+}
+
+object UserMappingStreamTask {
+ def main(args: Array[String]): Unit = {
+ println("Starting up the User Mapping Stream Job")
+ val parameterTool = ParameterTool.fromArgs(args)
+ val configFilePath = Option(parameterTool.get("config.file.path"))
+
+ // Load config with proper precedence: system environment > config file > base config
+ val baseConfig = configFilePath.map {
+ path => ConfigFactory.parseFile(new File(path))
+ }.getOrElse(ConfigFactory.load("user-mapping-stream.conf"))
+
+ // System environment variables take precedence, then config file, then base config
+ val config = ConfigFactory.systemEnvironment()
+ .withFallback(baseConfig)
+ .resolve()
+
+ val userMappingStreamConfig = new UserMappingStreamConfig(config)
+
+ // Log Kafka configuration for debugging
+ val brokerServers = userMappingStreamConfig.kafkaBrokerServers
+ // println(s"[UserMappingStreamTask] ========================================")
+ // println(s"[UserMappingStreamTask] Kafka Configuration:")
+ // println(s"[UserMappingStreamTask] Broker Servers: $brokerServers")
+ // println(s"[UserMappingStreamTask] Group ID: ${userMappingStreamConfig.groupId}")
+ // println(s"[UserMappingStreamTask] Input Topic: ${userMappingStreamConfig.inputTopic}")
+ // println(s"[UserMappingStreamTask] Output Topic: ${userMappingStreamConfig.outputTopic}")
+ // println(s"[UserMappingStreamTask] ========================================")
+
+ // Validate Kafka broker servers configuration
+ if (brokerServers == null || brokerServers.trim.isEmpty) {
+ throw new IllegalArgumentException(
+ "Kafka broker-servers is not configured. Please set kafka.broker-servers in your config file " +
+ "or set KAFKA_BROKER_SERVERS environment variable."
+ )
+ }
+
+ // Check if broker-servers is the default Docker value and warn if it might not resolve
+ if (brokerServers == "kafka:9092") {
+ println(s"[UserMappingStreamTask] WARNING: Using default Docker broker-servers 'kafka:9092'. " +
+ "If running outside Docker, this may not resolve. Set kafka.broker-servers in config or KAFKA_BROKER_SERVERS env var.")
+ }
+
+ // Provide troubleshooting information
+ // println(s"[UserMappingStreamTask] Troubleshooting:")
+ // println(s"[UserMappingStreamTask] If you see 'TimeoutException: Timeout expired while fetching topic metadata':")
+ // println(s"[UserMappingStreamTask] 1. Verify Kafka is running: Check if Kafka broker is accessible at $brokerServers")
+ // println(s"[UserMappingStreamTask] 2. Test connection: Try 'telnet ' or 'nc -zv '")
+ // println(s"[UserMappingStreamTask] 3. Check firewall: Ensure port is not blocked")
+ // println(s"[UserMappingStreamTask] 4. Verify address: Confirm the broker address is correct in your config")
+ // println(s"[UserMappingStreamTask] 5. Check topics exist: Verify topics '${userMappingStreamConfig.inputTopic}' and '${userMappingStreamConfig.outputTopic}' exist")
+ // println(s"[UserMappingStreamTask]")
+
+ val kafkaUtil = new FlinkKafkaConnector(userMappingStreamConfig)
+ val task = new UserMappingStreamTask(userMappingStreamConfig, kafkaUtil)
+ task.process()
+ }
+}
diff --git a/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/util/FieldMapper.scala b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/util/FieldMapper.scala
new file mode 100644
index 00000000..0111de6e
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/util/FieldMapper.scala
@@ -0,0 +1,265 @@
+package org.shikshalokam.job.user.mapping.stream.processor.util
+
+import com.typesafe.config.ConfigFactory
+import org.slf4j.LoggerFactory
+import ujson.{Arr, Js, Null, Obj, read, write}
+
+import java.util
+import scala.collection.JavaConverters._
+import scala.util.{Failure, Success, Try}
+
+/**
+ * FieldMapper utility to transform observation data fields to user profile fields
+ * based on mappings defined in field-mappings.conf
+ *
+ * Example mapping:
+ * name -> profile.name
+ * about -> profile.about
+ */
+object FieldMapper {
+
+ private val logger = LoggerFactory.getLogger(FieldMapper.getClass)
+
+ // Load field mappings from config file
+ private val mappings: Map[String, String] = loadMappings()
+
+ mappings.foreach { case (source, target) =>
+ println(s"[FieldMapper] Mapping: $source -> $target")
+ }
+
+ /**
+ * Load field mappings from field-mappings.conf
+ * @return Map of source field -> target field path
+ */
+ private def loadMappings(): Map[String, String] = {
+ try {
+ // Use parseResources to load only our config file, avoiding conflicts with other configs
+ val config = ConfigFactory.parseResources("field-mappings.conf")
+ if (config.isEmpty) {
+ logger.warn("[FieldMapper] field-mappings.conf is empty or not found")
+ return Map.empty[String, String]
+ }
+
+ val configMap = config.entrySet().asScala.map { entry =>
+ val rawKey = entry.getKey
+ val key = rawKey.replaceAll("\"", "")
+ val value = config.getString(rawKey)
+ (key, value)
+ }.toMap
+
+ configMap
+ } catch {
+ case e: Exception =>
+ logger.error(s"[FieldMapper] Failed to load field-mappings.conf: ${e.getMessage}", e)
+ e.printStackTrace()
+ Map.empty[String, String]
+ }
+ }
+
+ /**
+ * Convert a Java Map to ujson.Obj recursively
+ */
+ private def javaMapToUjsonObj(map: java.util.Map[_, _]): ujson.Obj = {
+ val obj = Obj()
+ map.asScala.foreach { case (k, v) =>
+ val key = k.toString
+ obj.value(key) = anyToUjsonValue(v)
+ }
+ obj
+ }
+
+ /**
+ * Convert a Java Collection to ujson.Arr recursively
+ */
+ private def javaCollectionToUjsonArr(coll: java.util.Collection[_]): ujson.Arr = {
+ val arr = ujson.Arr()
+ coll.asScala.foreach { item =>
+ arr.value += anyToUjsonValue(item)
+ }
+ arr
+ }
+
+ /**
+ * Convert any value to ujson.Value recursively
+ */
+ private def anyToUjsonValue(value: Any): ujson.Value = {
+ value match {
+ case null => ujson.Null
+ case s: String => s
+ case n: Number => n.doubleValue()
+ case i: Int => i
+ case l: Long => l
+ case d: Double => d
+ case f: Float => f
+ case b: Boolean => b
+ case map: java.util.Map[_, _] => javaMapToUjsonObj(map)
+ case coll: java.util.Collection[_] => javaCollectionToUjsonArr(coll)
+ case arr: Array[_] =>
+ val ujsonArr = ujson.Arr()
+ arr.foreach { item => ujsonArr.value += anyToUjsonValue(item) }
+ ujsonArr
+ case _ => value.toString
+ }
+ }
+
+ /**
+ * Check if a value is null or empty
+ * Used to determine if a field should be skipped during mapping
+ *
+ * Rule: Update a field only if it has a valid value
+ * If a field is null, empty string, or missing → do not update it
+ *
+ * @param value The value to check
+ * @return true if value is null, empty string, or empty collection (should be skipped)
+ */
+ def isValueEmpty(value: Any): Boolean = {
+ if (value == null) {
+ return true
+ }
+
+ value match {
+ case s: String => s.trim.isEmpty
+ case coll: java.util.Collection[_] => coll.isEmpty
+ case arr: Array[_] => arr.isEmpty
+ case map: java.util.Map[_, _] => map.isEmpty
+ case _ => false // Other types (numbers, booleans) are not considered empty
+ }
+ }
+
+ /**
+ * Transform observation data (userProfile) to user profile patch format
+ *
+ * Only maps the following allowed fields from userProfile:
+ * - name
+ * - username
+ * - dob
+ * - phoneCode (from phone_code)
+ * - about
+ * - preferredLanguage (from preferred_language)
+ * - tenantCode (from tenant_code)
+ * - meta
+ *
+ * Important Rule: Update a field only if it has a valid value
+ * If a field is null, empty string, or missing → do not update it
+ * Existing user data should not be overwritten with empty values
+ *
+ * Input observationData (userProfile) example:
+ * {
+ * "name": "Carol Miranda Updated Two",
+ * "about": "admin Update",
+ * "dob": "22-12-1990",
+ * "phone_code": "+91",
+ * "preferred_language": "en",
+ * "tenant_code": "qa",
+ * "meta": {"key": "value"}
+ * }
+ *
+ * Output profile format:
+ * {
+ * "profile": {
+ * "name": "Carol Miranda Updated Two",
+ * "about": "admin Update",
+ * "dob": "22-12-1990",
+ * "phoneCode": "+91",
+ * "preferredLanguage": "en",
+ * "tenantCode": "qa",
+ * "meta": {"key": "value"}
+ * }
+ * }
+ *
+ * @param observationData Map containing userProfile field values from observation event
+ * @return JsObject representing the profile patch structure with only non-empty fields
+ */
+ def transform(observationData: util.Map[String, Any]): Js.Obj = {
+ try {
+ println(s"[FieldMapper] Starting transformation of userProfile data")
+
+ val profileObj = Obj()
+ var mappedFieldsCount = 0
+
+ // Iterate through each configured mapping (only allowed fields are in the config)
+ mappings.foreach { case (sourceField, targetPath) =>
+ try {
+ // Get value from observation data (userProfile)
+ val value = observationData.get(sourceField)
+
+ // Check if value is null or empty, and skip if so
+ // This ensures we only update fields with valid values
+ if (isValueEmpty(value)) {
+ println(s"[FieldMapper] Source field '$sourceField' is null, empty, or missing - skipping (will not overwrite existing user data)")
+ } else {
+ // Parse target path (e.g., "profile.phoneCode" -> ["profile", "phoneCode"])
+ val pathParts = targetPath.split("\\.")
+
+ if (pathParts.length >= 2) {
+ val rootKey = pathParts(0) // e.g., "profile"
+ val fieldKey = pathParts(1) // e.g., "phoneCode"
+
+ // We expect all mappings to be under "profile", so rootKey should be "profile"
+ if (rootKey == "profile") {
+ // Set the field value directly in profile object
+ // Only non-empty values reach this point
+ value match {
+ case s: String => profileObj.value(fieldKey) = s
+ case n: Number =>
+ // Convert Java Number to ujson numeric value
+ profileObj.value(fieldKey) = n.doubleValue()
+ case i: Int => profileObj.value(fieldKey) = i
+ case l: Long => profileObj.value(fieldKey) = l
+ case d: Double => profileObj.value(fieldKey) = d
+ case f: Float => profileObj.value(fieldKey) = f
+ case b: Boolean => profileObj.value(fieldKey) = b
+ case map: java.util.Map[_, _] =>
+ // Handle nested objects like meta - convert directly to ujson.Obj
+ try {
+ profileObj.value(fieldKey) = javaMapToUjsonObj(map)
+ } catch {
+ case e: Exception =>
+ logger.warn(s"[FieldMapper] Could not convert map to JSON for field $fieldKey, using string representation", e)
+ profileObj.value(fieldKey) = map.toString
+ }
+ case coll: java.util.Collection[_] =>
+ // Handle collections - convert directly to ujson.Arr
+ try {
+ profileObj.value(fieldKey) = javaCollectionToUjsonArr(coll)
+ } catch {
+ case e: Exception =>
+ logger.warn(s"[FieldMapper] Could not convert collection to JSON for field $fieldKey, using string representation", e)
+ profileObj.value(fieldKey) = coll.toString
+ }
+ case _ => profileObj.value(fieldKey) = value.toString
+ }
+
+ mappedFieldsCount += 1
+ println(s"[FieldMapper] Mapped $sourceField -> $targetPath = $value")
+ } else {
+ println(s"[FieldMapper] WARNING: Root key '$rootKey' is not 'profile', skipping field $sourceField")
+ }
+ } else {
+ println(s"[FieldMapper] WARNING: Invalid target path format: $targetPath (expected format: 'profile.field')")
+ }
+ }
+ } catch {
+ case e: Exception =>
+ logger.error(s"[FieldMapper] Error mapping field $sourceField: ${e.getMessage}", e)
+ }
+ }
+
+ // Return the result with "profile" as root
+ val result = Obj("profile" -> profileObj)
+ // println(s"[FieldMapper] Transformation complete. Mapped $mappedFieldsCount non-empty fields. Result: ${result.render()}")
+ result
+
+ } catch {
+ case e: Exception =>
+ logger.error(s"[FieldMapper] Error during transformation: ${e.getMessage}", e)
+ e.printStackTrace()
+ Obj("profile" -> Obj()) // Return empty profile on error
+ }
+ }
+
+ /**
+ * Get the mappings for debugging
+ */
+ def getMappings: Map[String, String] = mappings
+}
diff --git a/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/util/UserApiClient.scala b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/util/UserApiClient.scala
new file mode 100644
index 00000000..32b9b23f
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/main/scala/org/shikshalokam/job/user/mapping/stream/processor/util/UserApiClient.scala
@@ -0,0 +1,123 @@
+package org.shikshalokam.job.user.mapping.stream.processor.util
+
+import org.slf4j.LoggerFactory
+import ujson.{Js, Obj}
+import requests._
+
+import scala.util.{Failure, Success, Try}
+
+/**
+ * HTTP client for making PATCH requests to User Service API
+ *
+ * Endpoint: PATCH {baseUrl}/user/v1/user/update
+ * Header: X-auth-token: {token}
+ * Content-Type: application/json
+ */
+object UserApiClient {
+
+ private val logger = LoggerFactory.getLogger(UserApiClient.getClass)
+
+ /**
+ * Patch user profile data for a user
+ *
+ * @param id The user ID to update
+ * @param profileData JSON object containing profile data (e.g., {"profile": {"phone": "...", "gender": "..."}})
+ * @param baseUrl The base URL for the User Service API
+ * @param authToken The authentication token for the User Service API
+ * @return Success(true) if update successful, Failure(exception) otherwise
+ */
+ def patchProfile(id: String, profileData: Js.Obj, baseUrl: String, authToken: String): Try[Boolean] = {
+ if (id == null || id.trim.isEmpty) {
+ val error = new IllegalArgumentException("id cannot be null or empty")
+ logger.error("[UserApiClient] id is null or empty", error)
+ return Failure(error)
+ }
+
+ try {
+ val url = s"$baseUrl/user/v1/user/update"
+
+ println(s"[UserApiClient] Initialized with BASE_URL: $baseUrl")
+ println(s"[UserApiClient] AUTH_TOKEN configured: ${if (authToken.nonEmpty) "***" else "NOT SET"}")
+
+ // Merge id with profileData into a single payload
+ // The API expects the payload directly, so we'll include id and merge profile fields
+ val payloadObj = Obj()
+
+ // Add id to payload to identify which user to update
+ payloadObj.value("id") = id
+
+ // Merge profile fields from profileData into payload
+ val profileObj = profileData.value.get("profile")
+ if (profileObj.isDefined) {
+ // Merge profile fields directly into payload (flatten the structure)
+ profileObj.get.asInstanceOf[Obj].value.foreach { case (key, value) =>
+ payloadObj.value(key) = value
+ }
+ } else {
+ // If no profile object, use the entire profileData
+ profileData.value.foreach { case (key, value) =>
+ payloadObj.value(key) = value
+ }
+ }
+
+ val jsonPayload = payloadObj.render()
+
+ // println(s"[UserApiClient] PATCH Request to: $url")
+ // println(s"[UserApiClient] Request payload: $jsonPayload")
+
+ val headers = Map(
+ "X-auth-token" -> authToken,
+ "Content-Type" -> "application/json"
+ )
+
+ // println(s"[UserApiClient] Request headers: X-auth-token=***, Content-Type=application/json")
+
+ // Use check = false to prevent RequestFailedException from being thrown for non-2xx status codes
+ // This allows us to handle error responses gracefully
+ val response = requests.patch(
+ url,
+ data = jsonPayload,
+ headers = headers,
+ check = false
+ )
+
+ // println(s"[UserApiClient] Response status code: ${response.statusCode}")
+ // println(s"[UserApiClient] Response body: ${response.text}")
+
+ if (response.statusCode >= 200 && response.statusCode < 300) {
+ logger.info(s"[UserApiClient] Successfully updated profile for id=$id")
+ Success(true)
+ } else {
+ val error = new Exception(s"User Service API returned status ${response.statusCode}: ${response.text}")
+ logger.error(s"[UserApiClient] API error for id=$id: ${error.getMessage}", error)
+ Failure(error)
+ }
+
+ } catch {
+ case e: Exception =>
+ logger.error(s"[UserApiClient] Exception while patching profile for id=$id: ${e.getMessage}", e)
+ e.printStackTrace()
+ Failure(e)
+ }
+ }
+
+ /**
+ * Test connection to user service (for debugging)
+ *
+ * @param baseUrl The base URL for the User Service API
+ */
+ def testConnection(baseUrl: String): Try[Boolean] = {
+ try {
+ val url = s"$baseUrl/api/users/health"
+ println(s"[UserApiClient] Testing connection to: $url")
+
+ val response = requests.get(url)
+ println(s"[UserApiClient] Health check response: ${response.statusCode}")
+ Success(response.statusCode == 200)
+ } catch {
+ case e: Exception =>
+ println(s"[UserApiClient] Connection test failed: ${e.getMessage}")
+ Failure(e)
+ }
+ }
+}
diff --git a/stream-jobs/user-mapping-stream-processor/src/test/resources/test.conf b/stream-jobs/user-mapping-stream-processor/src/test/resources/test.conf
new file mode 100644
index 00000000..531ea25c
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/test/resources/test.conf
@@ -0,0 +1,26 @@
+include "base-test.conf"
+
+kafka {
+ input.topic = "dev.userCreate"
+ groupId = "dev.users"
+ output.topic = "sl-metabase-user-dashboard-dev"
+ output.mentoring.topic = "sl-metabase-mentoring-dashboard-dev"
+}
+
+task {
+ consumer.parallelism = 1
+ sl.users.stream.parallelism = 1
+ sl.metabase.dashboard.parallelism = 1
+}
+
+postgres{
+ host = "localhost"
+ port = "5432"
+ username = "postgres"
+ password = "Test@123"
+ database = "test"
+ tables = {
+ userMetrics = ${job.env}"_user_metrics"
+ dashboardMetadataTable = ${job.env}"_dashboard_metadata"
+ }
+}
diff --git a/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/fixture/ObservationEventsMock.scala b/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/fixture/ObservationEventsMock.scala
new file mode 100644
index 00000000..6c88c01a
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/fixture/ObservationEventsMock.scala
@@ -0,0 +1,37 @@
+package org.shikshalokam.user.mapping.stream.processor.fixture
+
+object ObservationEventsMock {
+
+ // Sample observation submission event matching the expected format
+ val OBSERVATION_SUBMITTED: String = """{
+ "eventType": "observation-submitted",
+ "id": 3088,
+ "organizationId": 1,
+ "observationData": {
+ "name": "Carol Miranda Updated Two",
+ "about": "admin Update",
+ "dob": "22-12-1990"
+ }
+ }"""
+
+ // Additional test case with minimal data (only name)
+ val OBSERVATION_SUBMITTED_MINIMAL: String = """{
+ "eventType": "observation-submitted",
+ "id": 3088,
+ "organizationId": 2,
+ "observationData": {
+ "name": "Test Student Name"
+ }
+ }"""
+
+ // Test case with only about field
+ val OBSERVATION_SUBMITTED_ABOUT_ONLY: String = """{
+ "eventType": "observation-submitted",
+ "id": 3089,
+ "organizationId": 3,
+ "observationData": {
+ "about": "Updated about information"
+ }
+ }"""
+
+}
diff --git a/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/spec/GenerateUserSink.scala b/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/spec/GenerateUserSink.scala
new file mode 100644
index 00000000..d4d463b7
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/spec/GenerateUserSink.scala
@@ -0,0 +1,19 @@
+package org.shikshalokam.user.mapping.stream.processor.spec
+
+import org.apache.flink.streaming.api.functions.sink.SinkFunction
+
+import java.util
+
+class GenerateUserSink extends SinkFunction[String] {
+
+ override def invoke(value: String): Unit = {
+ synchronized{
+ println(value)
+ GenerateUserSink.values.add(value)
+ }
+ }
+}
+
+object GenerateUserSink {
+ val values: util.List[String] = new util.ArrayList()
+}
\ No newline at end of file
diff --git a/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/spec/ObservationEventSource.scala b/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/spec/ObservationEventSource.scala
new file mode 100644
index 00000000..d7e24808
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/spec/ObservationEventSource.scala
@@ -0,0 +1,21 @@
+package org.shikshalokam.user.mapping.stream.processor.spec
+
+import org.apache.flink.streaming.api.functions.source.SourceFunction
+import org.apache.flink.streaming.api.functions.source.SourceFunction.SourceContext
+import org.shikshalokam.job.user.mapping.stream.processor.domain.ObservationEvent
+import org.shikshalokam.job.util.JSONUtil
+import org.shikshalokam.user.mapping.stream.processor.fixture.ObservationEventsMock
+
+class ObservationEventSource extends SourceFunction[ObservationEvent] {
+
+ override def run(ctx: SourceContext[ObservationEvent]): Unit = {
+ val filePath = "/home/ttpl-rt-221/elevate/data-pipeline/stream-jobs/user-mapping-stream-processor/obs_kafka_response.json"
+ val source = scala.io.Source.fromFile(filePath)
+ val jsonContent = try source.mkString finally source.close()
+
+ ctx.collect(new ObservationEvent(JSONUtil.deserialize[java.util.Map[String, Any]](jsonContent), 0, 0))
+ }
+
+ override def cancel(): Unit = {}
+
+}
diff --git a/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/spec/UserMappingStreamFunctionTestSpec.scala b/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/spec/UserMappingStreamFunctionTestSpec.scala
new file mode 100644
index 00000000..0ffff4a2
--- /dev/null
+++ b/stream-jobs/user-mapping-stream-processor/src/test/scala/org/shikshalokam/user/mapping/stream/processor/spec/UserMappingStreamFunctionTestSpec.scala
@@ -0,0 +1,59 @@
+package org.shikshalokam.user.mapping.stream.processor.spec
+
+import com.typesafe.config.{Config, ConfigFactory}
+import org.apache.flink.api.common.typeinfo.TypeInformation
+import org.apache.flink.api.java.typeutils.TypeExtractor
+import org.apache.flink.runtime.testutils.MiniClusterResourceConfiguration
+import org.apache.flink.test.util.MiniClusterWithClientResource
+import org.mockito.Mockito
+import org.mockito.Mockito.when
+import org.shikshalokam.BaseTestSpec
+import org.shikshalokam.job.connector.FlinkKafkaConnector
+import org.shikshalokam.job.user.mapping.stream.processor.domain.ObservationEvent
+import org.shikshalokam.job.user.mapping.stream.processor.task.{UserMappingStreamConfig, UserMappingStreamTask}
+
+
+class UserMappingStreamFunctionTestSpec extends BaseTestSpec {
+
+ implicit val mapTypeInfo: TypeInformation[java.util.Map[String, AnyRef]] = TypeExtractor.getForClass(classOf[java.util.Map[String, AnyRef]])
+ implicit val eventTypeInfo: TypeInformation[ObservationEvent] = TypeExtractor.getForClass(classOf[ObservationEvent])
+ implicit val stringTypeInfo: TypeInformation[String] = TypeExtractor.getForClass(classOf[String])
+
+ val flinkCluster = new MiniClusterWithClientResource(new MiniClusterResourceConfiguration.Builder()
+ .setConfiguration(testConfiguration())
+ .setNumberSlotsPerTaskManager(1)
+ .setNumberTaskManagers(1)
+ .build)
+
+ val mockKafkaUtil: FlinkKafkaConnector = mock[FlinkKafkaConnector](Mockito.withSettings().serializable())
+
+ val config: Config = ConfigFactory.load("test.conf")
+ val jobConfig: UserMappingStreamConfig = new UserMappingStreamConfig(config)
+
+
+ override protected def beforeAll(): Unit = {
+ super.beforeAll()
+ //Embedded Postgres connection
+ flinkCluster.before()
+ }
+
+ override protected def afterAll(): Unit = {
+ super.afterAll()
+ flinkCluster.after()
+ }
+
+ def initialize(): Unit = {
+ when(mockKafkaUtil.kafkaJobRequestSource[ObservationEvent](jobConfig.inputTopic))
+ .thenReturn(new ObservationEventSource)
+ when(mockKafkaUtil.kafkaStringSink(jobConfig.outputTopic))
+ .thenReturn(new GenerateUserSink)
+ when(mockKafkaUtil.kafkaStringSink(jobConfig.mentoringOutputTopic))
+ .thenReturn(new GenerateUserSink)
+ }
+
+ "Observation Mapping Stream Job " should "execute successfully " in {
+ initialize()
+ new UserMappingStreamTask(jobConfig, mockKafkaUtil).process()
+ }
+
+}
\ No newline at end of file