Skip to content

Commit 80b20f6

Browse files
authored
Merge pull request #1137 from opencrvs/merge-v19-to-dev
Merge v19 to dev
2 parents 3346e7b + 42f5f4a commit 80b20f6

File tree

9 files changed

+232
-55
lines changed

9 files changed

+232
-55
lines changed

ANALYTICS.md

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# OpenCRVS Analytics Documentation
2+
3+
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
4+
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
5+
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
6+
7+
- [Overview](#overview)
8+
- [Architecture](#architecture)
9+
- [Data Sources](#data-sources)
10+
- [How Data Flows to Metabase](#how-data-flows-to-metabase)
11+
- [Available Data in Example Setup](#available-data-in-example-setup)
12+
- [Deployment](#deployment)
13+
- [Development and Dashboard Management](#development-and-dashboard-management)
14+
- [Why Analytics Data is Not Backed Up](#why-analytics-data-is-not-backed-up)
15+
- [Configuration](#configuration)
16+
- [Development Commands](#development-commands)
17+
18+
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
19+
20+
## Overview
21+
22+
OpenCRVS provides comprehensive analytics capabilities through **Metabase**, an open-source business intelligence platform. This system allows stakeholders to visualize and analyze civil registration data through interactive dashboards, charts, and reports.
23+
24+
The analytics system is designed to:
25+
- Track vital events (births, deaths, etc.) and registration statistics
26+
- Provide insights for decision-making and reporting
27+
- Support data-driven improvements to civil registration processes
28+
- Export non-PII datasets as CSV
29+
30+
## Architecture
31+
32+
The analytics system consists of several key components:
33+
34+
```
35+
┌──────────────────┐ ┌──────────────────┐ ┌─────────────────┐
36+
│ OpenCRVS Core │───▶│ Country config │───▶│ Metabase │
37+
│ Action trigger │ │ Analytics DB │ │ Dashboards │
38+
└──────────────────┘ └──────────────────┘ └─────────────────┘
39+
```
40+
41+
1. **OpenCRVS Core Services**: Submits all performed event actions to country config
42+
2. **PostgreSQL Analytics Database**: Stores processed analytics data in country-defined database. By default this is in PostgreSQL in `analytics` schema
43+
3. **Metabase**: Connects to PostgreSQL and provides visualization capabilities
44+
45+
## Data Sources
46+
47+
OpenCRVS collects analytics data from multiple sources:
48+
49+
### Event Data
50+
- **Birth registrations**: Demographics, locations, registration timing
51+
- **Death registrations**: Cause of death, demographics, locations
52+
- **Custom events**: Additional event types (e.g., tennis club memberships in the example)
53+
- **Registration status**: Draft, registered, certified states
54+
- **Action history**: Workflow actions and state transitions
55+
56+
Country config receives full event documents and can decide which fields should be written into the analytics database and which are PII.
57+
58+
### Configuration-Driven Analytics
59+
The example country config implementation uses configurable analytics fields marked with `analytics: true` in form configurations:
60+
61+
```typescript
62+
// Only fields marked with analytics: true are included
63+
field: {
64+
id: 'childDetails.firstName',
65+
analytics: true, // This field will be tracked
66+
// ... other field properties
67+
}
68+
```
69+
70+
## How Data Flows to Metabase
71+
72+
1. **Event Processing**: When an event receives an action in OpenCRVS (registration, status changes, etc.), country config HTTP action hooks are triggered and the system processes the action through the analytics pipeline defined in `src/analytics/analytics.ts`
73+
74+
2. **Data Extraction**: The analytics service extracts relevant fields from event documents based on form configuration (only fields marked with `analytics: true`)
75+
76+
3. **Data Transformation**: Raw event data is transformed and enriched with additional calculated metrics (e.g., registration delays, demographic statistics).
77+
78+
4. **Database Storage**: Processed data is stored in PostgreSQL in the `analytics` schema, specifically in the `event_actions` table
79+
80+
5. **Metabase Connection**: Metabase connects directly to the PostgreSQL database using configured credentials and queries the analytics schema
81+
82+
6. **Dashboard Rendering**: Pre-configured dashboards and queries in Metabase visualize the data through charts, tables, and maps
83+
84+
## Deployment
85+
86+
### Production Deployment
87+
Metabase is deployed as a Docker service defined in `infrastructure/docker-compose.deploy.yml`:
88+
89+
```yaml
90+
dashboards:
91+
image: metabase/metabase:v0.56.4
92+
volumes:
93+
- /opt/opencrvs/infrastructure/metabase/metabase.init.db.sql:/metabase.init.db.sql
94+
- /opt/opencrvs/infrastructure/metabase/run.sh:/run.sh
95+
# ... other configuration files
96+
environment:
97+
# Database connection settings
98+
- METABASE_DATABASE_HOST=${METABASE_DATABASE_HOST:-postgres}
99+
- METABASE_DATABASE_NAME=${METABASE_DATABASE_NAME:-events}
100+
- METABASE_DATABASE_USER=${METABASE_DATABASE_USER:-events_analytics}
101+
# ... other environment variables
102+
```
103+
104+
### Environment Configuration
105+
The deployment uses environment-specific configurations:
106+
- `infrastructure/metabase/environment-configuration.sql`: Database connections and admin users. **This file does not need to be changed**.
107+
- Environment variables for database credentials and site settings
108+
- Map configurations for geographic visualizations
109+
110+
## Development and Dashboard Management
111+
112+
### ⚠️ Critical: Development vs Production Changes
113+
114+
**Important**: Changes made directly in deployed Metabase environments (staging, production) **WILL NOT PERSIST** and will be reset during the next deployment.
115+
116+
To make persistent dashboard changes:
117+
118+
1. **Work in Development Mode**: Always make changes in your local development environment first
119+
2. **Modify the Source**: Update `infrastructure/metabase/metabase.init.db.sql` by running and using Metabase locally. When you stop the local metabase, all Metabase configuration is stored to this file.
120+
3. **Version Control**: Commit changes to ensure they're deployed to all environments
121+
4. **Deploy**: Changes will only persist across environments when included in the initialization database
122+
123+
### Development Workflow
124+
125+
```bash
126+
# Start Metabase in development mode
127+
yarn metabase
128+
129+
# Access at http://localhost:4444
130+
# Default credentials:
131+
# Username: [email protected]
132+
# Password: m3tabase
133+
```
134+
135+
### Making Dashboard Changes
136+
137+
1. **Create/modify dashboards** in development Metabase UI
138+
2. **Export the changes** by updating stopping the process
139+
3. **Commit changes** to version control
140+
4. **Deploy** to propagate changes to all environments
141+
142+
### Development Commands
143+
144+
```bash
145+
# Start Metabase in development
146+
yarn metabase
147+
148+
# Clear all analytics data
149+
yarn db:clear:all
150+
```
151+
## Why Analytics Data is Not Backed Up
152+
153+
Analytics data in OpenCRVS is **intentionally not included in backup procedures** for several important reasons:
154+
155+
### 1. **Regenerative Nature**
156+
Analytics data can be completely regenerated from the primary data sources. The analytics tables are derived views of the operational data, not the source of truth.
157+
158+
### 2. **Performance Considerations**
159+
- Analytics databases can be very large (GB to TB scale)
160+
- Including them in backups would significantly increase backup time and storage requirements
161+
- Restore operations would be much slower
162+
163+
## Configuration
164+
165+
### Database Connection
166+
Metabase connects to PostgreSQL using these environment variables:
167+
- `METABASE_DATABASE_HOST`: Database host (default: postgres)
168+
- `METABASE_DATABASE_PORT`: Database port (default: 5432)
169+
- `METABASE_DATABASE_NAME`: Database name (default: events)
170+
- `METABASE_DATABASE_USER`: Database user (default: events_analytics)
171+
- `METABASE_DATABASE_PASSWORD`: Database password
172+
173+
### Analytics Schema
174+
The analytics data is stored in the PostgreSQL `analytics` schema, primarily in:
175+
- `analytics.event_actions`: Main table containing processed event data and action histories
176+
177+
### Map Visualizations
178+
Geographic visualizations use:
179+
- `OPENCRVS_METABASE_MAP_NAME`: Map display name
180+
- `OPENCRVS_METABASE_MAP_URL`: GeoJSON source URL
181+
- `OPENCRVS_METABASE_MAP_REGION_KEY`: Key field for geographic regions
182+
- `OPENCRVS_METABASE_MAP_REGION_NAME`: Display name for regions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
- Use nvm to upgrade your local development environment to use node version `22.x.x.`
2727
- Add conditions for the certified copy certificate to ensure it's only available to children who are 1 year or older. [#9684](https://github.com/opencrvs/opencrvs-core/issues/9684)
28+
- Available disk space in root file system alert adjusted to fire when 20GB are remaining, rather than when diskspace usage is at 70%.
2829

2930
- **Upgraded MinIO** to RELEASE.2025-06-13T11-33-47Z and MinIO Client (mc) to RELEASE.2025-05-21T01-59-54Z and ensured compatibility across both amd64 and arm64 architectures.
3031

infrastructure/metabase/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
33
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
44

5-
- [OpenCRVS Dashboards](#opencrvs-dashboards)
5+
- [OpenCRVS Analytics](#opencrvs-analytics)
66
- [Run in development mode](#run-in-development-mode)
77
- [Default credentials](#default-credentials)
88

99
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
1010

11-
# OpenCRVS Dashboards
11+
# OpenCRVS Analytics
1212

1313
### Requirements
1414

infrastructure/monitoring/kibana/config.ndjson

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{"attributes":{"actions":[{"actionRef":"preconfigured:preconfigured-alert-history-es-index","actionTypeId":".index","group":"metrics.inventory_threshold.fired","params":{"documents":["{\"@timestamp\":\"2024-08-06T07:57:35.644Z\",\"tags\":\"{{rule.tags}}\",\"rule\":{\"id\":\"{{rule.id}}\",\"name\":\"{{rule.name}}\",\"params\":{\"{{rule__type}}\":\"{{params}}\"},\"space\":\"{{rule.spaceId}}\",\"type\":\"{{rule.type}}\"},\"kibana\":{\"alert\":{\"id\":\"{{alert.id}}\",\"context\":{\"{{rule__type}}\":\"{{context}}\"},\"actionGroup\":\"{{alert.actionGroup}}\",\"actionGroupName\":\"{{alert.actionGroupName}}\"}},\"event\":{\"kind\":\"alert\"}}"]}}],"alertTypeId":"metrics.alert.inventory.threshold","apiKey":null,"apiKeyOwner":null,"consumer":"alerts","createdAt":"2023-11-17T12:01:46.420Z","createdBy":"elastic","enabled":false,"executionStatus":{"error":null,"lastExecutionDate":"2024-08-06T08:02:44.568Z","status":"pending"},"legacyId":null,"meta":{"versionApiKeyLastmodified":"7.17.18"},"muteAll":false,"mutedInstanceIds":[],"name":"Available disk space in root file system","notifyWhen":"onActionGroupChange","params":{"alertOnNoData":true,"criteria":[{"comparator":">=","customMetric":{"aggregation":"max","field":"system.filesystem.used.pct","id":"alert-custom-metric","type":"custom"},"metric":"custom","threshold":[0.7],"timeSize":1,"timeUnit":"h","warningComparator":">=","warningThreshold":[0.5]}],"filterQuery":"{\"bool\":{\"should\":[{\"match_phrase\":{\"system.filesystem.mount_point\":\"/hostfs\"}}],\"minimum_should_match\":1}}","filterQueryText":"system.filesystem.mount_point : \"/hostfs\"","nodeType":"host","sourceId":"default"},"schedule":{"interval":"1h"},"scheduledTaskId":null,"tags":["infra","opencrvs-builtin"],"throttle":null,"updatedAt":"2024-08-06T08:01:56.542Z","updatedBy":"elastic"},"coreMigrationVersion":"7.17.18","id":"14778650-8541-11ee-9002-2f37fdc4e5d5","migrationVersion":{"alert":"7.16.0"},"references":[],"sort":[1722931316554,643],"type":"alert","updated_at":"2024-08-06T08:01:56.554Z","version":"WzM5MywxXQ=="}
1+
{"attributes":{"actions":[{"actionRef":"preconfigured:preconfigured-alert-history-es-index","actionTypeId":".index","frequency":{"notifyWhen":"onActionGroupChange","summary":false,"throttle":null},"group":"metrics.inventory_threshold.fired","params":{"documents":["{\"@timestamp\":\"2025-10-03T09:15:09.124Z\",\"tags\":\"{{rule.tags}}\",\"rule\":{\"id\":\"{{rule.id}}\",\"name\":\"{{rule.name}}\",\"params\":{\"{{rule__type}}\":\"{{rule.params}}\"},\"space\":\"{{rule.spaceId}}\",\"type\":\"{{rule.type}}\"},\"kibana\":{\"alert\":{\"id\":\"{{alert.id}}\",\"context\":{\"{{rule__type}}\":\"{{context}}\"},\"actionGroup\":\"{{alert.actionGroup}}\",\"actionGroupName\":\"{{alert.actionGroupName}}\"}},\"event\":{\"kind\":\"alert\"}}"]},"uuid":"358daf99-65eb-4ff5-a8a5-7218573d60cd"}],"alertTypeId":"metrics.alert.inventory.threshold","apiKey":null,"apiKeyCreatedByUser":null,"apiKeyOwner":null,"consumer":"alerts","createdAt":"2023-11-17T12:01:46.420Z","createdBy":"elastic","enabled":false,"lastRun":{"alertsCount":{"active":0,"ignored":0,"new":0,"recovered":1},"outcome":"succeeded","outcomeMsg":null,"outcomeOrder":0,"warning":null},"legacyId":null,"meta":{"versionApiKeyLastmodified":"8.14.3"},"muteAll":false,"mutedInstanceIds":[],"name":"Available disk space in root file system","notifyWhen":null,"params":{"alertOnNoData":true,"criteria":[{"comparator":"<","customMetric":{"aggregation":"max","field":"system.filesystem.available","id":"alert-custom-metric","type":"custom"},"metric":"custom","threshold":[21474836480],"timeSize":1,"timeUnit":"h"}],"filterQuery":"{\"bool\":{\"should\":[{\"match_phrase\":{\"system.filesystem.mount_point\":\"/hostfs\"}}],\"minimum_should_match\":1}}","filterQueryText":"system.filesystem.mount_point : \"/hostfs\"","nodeType":"host","sourceId":"default"},"revision":5,"running":false,"schedule":{"interval":"1h"},"scheduledTaskId":null,"snoozeSchedule":[],"tags":["infra","opencrvs-builtin"],"throttle":null,"updatedAt":"2025-10-03T09:19:37.847Z","updatedBy":"elastic"},"coreMigrationVersion":"8.8.0","created_at":"2025-10-03T09:19:37.847Z","id":"14778650-8541-11ee-9002-2f37fdc4e5d5","managed":false,"references":[],"type":"alert","typeMigrationVersion":"10.1.0","updated_at":"2025-10-03T09:19:37.847Z","version":"WzExNjc4ODIsMjIyXQ=="}
22
{"attributes":{"actions":[{"actionRef":"preconfigured:preconfigured-alert-history-es-index","actionTypeId":".index","group":"threshold_met","params":{"documents":["{\"@timestamp\":\"2022-04-18T07:05:33.819Z\",\"tags\":\"{{rule.tags}}\",\"rule\":{\"id\":\"{{rule.id}}\",\"name\":\"{{rule.name}}\",\"params\":{\"{{rule__type}}\":\"{{params}}\"},\"space\":\"{{rule.spaceId}}\",\"type\":\"{{rule.type}}\"},\"kibana\":{\"alert\":{\"id\":\"{{alert.id}}\",\"context\":{\"{{rule__type}}\":\"{{context}}\"},\"actionGroup\":\"{{alert.actionGroup}}\",\"actionGroupName\":\"{{alert.actionGroupName}}\"}},\"event\":{\"kind\":\"alert\"}}"]}}],"alertTypeId":"apm.error_rate","apiKey":null,"apiKeyOwner":null,"consumer":"alerts","createdAt":"2022-06-01T11:30:27.033Z","createdBy":"opencrvs-admin","enabled":false,"executionStatus":{"error":null,"lastExecutionDate":"2024-02-07T08:28:08.400Z","status":"pending"},"legacyId":null,"meta":{"versionApiKeyLastmodified":"7.17.0"},"muteAll":false,"mutedInstanceIds":[],"name":"Error in service","notifyWhen":"onActionGroupChange","params":{"environment":"ENVIRONMENT_ALL","threshold":1,"windowSize":1,"windowUnit":"m"},"schedule":{"interval":"1m"},"scheduledTaskId":null,"tags":[],"throttle":null,"updatedAt":"2024-02-05T03:00:20.633Z","updatedBy":"opencrvs-admin"},"coreMigrationVersion":"7.17.0","id":"3b6722e0-e19e-11ec-ba8e-51649755648d","migrationVersion":{"alert":"7.16.0"},"references":[],"sort":[1707273006619,214975],"type":"alert","updated_at":"2024-02-07T02:30:06.619Z","version":"WzQ5MjAzNCwxOV0="}
33
{"attributes":{"buildNum":46534,"defaultIndex":"metricbeat-*"},"coreMigrationVersion":"7.17.0","id":"7.17.0","migrationVersion":{"config":"7.13.0"},"references":[],"sort":[1707273006619,216009],"type":"config","updated_at":"2024-02-07T02:30:06.619Z","version":"WzQ5MjQyOCwxOV0="}
44
{"attributes":{"actions":[{"actionRef":"preconfigured:preconfigured-alert-history-es-index","actionTypeId":".index","frequency":{"notifyWhen":"onActionGroupChange","summary":false,"throttle":null},"group":"logs.threshold.fired","params":{"documents":["{\"@timestamp\":\"2024-12-23T09:50:26.528Z\",\"tags\":\"{{rule.tags}}\",\"rule\":{\"id\":\"{{rule.id}}\",\"name\":\"{{rule.name}}\",\"params\":{\"{{rule__type}}\":\"{{rule.params}}\"},\"space\":\"{{rule.spaceId}}\",\"type\":\"{{rule.type}}\"},\"kibana\":{\"alert\":{\"id\":\"{{alert.id}}\",\"context\":{\"{{rule__type}}\":\"{{context}}\"},\"actionGroup\":\"{{alert.actionGroup}}\",\"actionGroupName\":\"{{alert.actionGroupName}}\"}},\"event\":{\"kind\":\"alert\"}}"]},"uuid":"1504b514-82e5-47de-a6ef-60795788f7e6"}],"alertTypeId":"logs.alert.document.count","apiKey":null,"apiKeyCreatedByUser":null,"apiKeyOwner":null,"consumer":"alerts","createdAt":"2024-12-23T10:16:28.758Z","createdBy":"opencrvs-admin","enabled":false,"executionStatus":{"error":null,"lastExecutionDate":"2024-12-23T10:20:10.118Z","status":"pending","warning":null},"lastRun":{"alertsCount":{"active":1,"ignored":0,"new":1,"recovered":0},"outcome":"succeeded","outcomeMsg":null,"outcomeOrder":0,"warning":null},"legacyId":null,"meta":{"versionApiKeyLastmodified":"8.16.4"},"monitoring":{"run":{"calculated_metrics":{"p50":529,"p95":565,"p99":565,"success_ratio":1},"history":[{"duration":493,"success":true,"timestamp":1734948992101},{"duration":565,"success":true,"timestamp":1734949097318}],"last_run":{"metrics":{"duration":565,"gap_duration_s":null,"total_alerts_created":null,"total_alerts_detected":null,"total_indexing_duration_ms":null,"total_search_duration_ms":null},"timestamp":"2024-12-23T10:18:17.318Z"}}},"muteAll":false,"mutedInstanceIds":[],"name":"Error while backup ","nextRun":"2024-12-23T11:18:17.247Z","notifyWhen":null,"params":{"count":{"comparator":"more than or equals","value":1},"criteria":[{"comparator":"equals","field":"log.file.path","value":"/var/log/opencrvs-backup.error.log"}],"logView":{"logViewId":"log-view-reference-0","type":"log-view-reference"},"timeSize":1,"timeUnit":"h"},"revision":1,"running":false,"schedule":{"interval":"1h"},"scheduledTaskId":null,"snoozeSchedule":[],"tags":[],"throttle":null,"updatedAt":"2024-12-23T10:17:24.571Z","updatedBy":"opencrvs-admin"},"coreMigrationVersion":"8.8.0","created_at":"2024-12-23T10:17:24.572Z","id":"8caf3676-e78a-4e7c-ba85-c150df55901b","managed":false,"references":[{"id":"default","name":"param:log-view-reference-0","type":"infrastructure-monitoring-log-view"}],"sort":[1734949097887,115],"type":"alert","typeMigrationVersion":"10.1.0","updated_at":"2024-12-23T10:18:17.887Z","version":"WzgyNDExMyw0MDRd"}

infrastructure/monitoring/metricbeat/metricbeat-rollover-policy.json

Lines changed: 15 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,23 @@
11
{
22
"policy": {
3-
"phases": {
4-
"hot": {
5-
"actions": {
6-
"rollover": {
7-
"max_size": "2GB",
8-
"max_age": "1d"
9-
},
10-
"set_priority": {
11-
"priority": 100
12-
}
3+
"phases": {
4+
"hot": {
5+
"min_age": "0ms",
6+
"actions": {
7+
"rollover": {
8+
"max_age": "3d",
9+
"max_size": "200mb"
1310
}
14-
},
15-
"warm": {
16-
"min_age": "3d",
17-
"actions": {
18-
"allocate": {
19-
"number_of_replicas": 0
20-
},
21-
"forcemerge": {
22-
"max_num_segments": 1
23-
},
24-
"set_priority": {
25-
"priority": 50
26-
}
27-
}
28-
},
29-
"cold": {
30-
"min_age": "7d",
31-
"actions": {
32-
"allocate": {
33-
"number_of_replicas": 0
34-
},
35-
"set_priority": {
36-
"priority": 0
37-
}
38-
}
39-
},
40-
"delete": {
41-
"min_age": "30d",
42-
"actions": {
43-
"delete": {}
11+
}
12+
},
13+
"delete": {
14+
"min_age": "2d",
15+
"actions": {
16+
"delete": {
17+
"delete_searchable_snapshot": true
4418
}
4519
}
20+
}
4621
},
4722
"_meta": {
4823
"managed": true,

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@opencrvs/countryconfig",
3-
"version": "1.8.1",
3+
"version": "1.9.0",
44
"description": "OpenCRVS country configuration for reference data",
55
"os": [
66
"darwin",
@@ -69,7 +69,7 @@
6969
"@hapi/boom": "^9.1.1",
7070
"@hapi/hapi": "^20.0.1",
7171
"@hapi/inert": "^6.0.3",
72-
"@opencrvs/toolkit": "1.9.0-rc.9518bea",
72+
"@opencrvs/toolkit": "1.9.0-rc.891a767",
7373
"@types/chalk": "^2.2.0",
7474
"@types/csv2json": "^1.4.0",
7575
"@types/fhir": "^0.0.30",

0 commit comments

Comments
 (0)