> For the complete documentation index, see [llms.txt](https://docs.openg2p.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openg2p.org/platform/platform-services/master-data-service/country-packs.md).

# Country Packs

What a country pack is, how to build one for a new country, and how MDS loads and upgrades it (the first version is published at once, later loads become drafts)

A **country pack** is one folder holding everything country-specific the platform needs: geography, datasets and a few sample people. MDS is the only service that reads packs. Registries, maps and reports get the data from MDS.

So installing for a different country is a **configuration change, not a rebuild**. The same registry image serves any country; only the pack MDS was seeded with differs.

## What a pack is

### Contents

| Part               | What it is                                                                                                                                                       | Required? |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| **Hierarchy**      | The administrative levels and every unit, with its P-code. The number and names of levels belong to the country (for example *country → region → zone → woreda*) | Yes       |
| **Boundaries**     | The map shape of every unit, one GeoJSON file per level                                                                                                          | Yes       |
| **Datasets**       | The country's own entries: gender, education level, water source and so on. **Themes** add sector datasets, such as crops under `agriculture`                    | No        |
| **Sample people**  | A few dozen individuals and households that belong to the country, for demos and tests                                                                           | No        |
| **Address format** | How an address is written below the lowest level                                                                                                                 | No        |

A pack with only geography is valid for MDS. But a registry on it has **empty coded dropdowns**: registries read datasets from MDS, and MDS gets them only from the pack.

### Where packs live

Packs live in the [`openg2p-data`](https://github.com/OpenG2P/openg2p-data) repository, under `packs/<CODE>`, where the code is usually the [ISO 3166 alpha-3](/platform/platform-services/master-data-service/standards.md) country code. Country data first arrives from a pack; after that it changes through MDS's own drafts and approvals.

Two packs ship today:

| Pack  | Country                  | Levels                                       | Units | Datasets                   | Samples | Licence                          |
| ----- | ------------------------ | -------------------------------------------- | ----- | -------------------------- | ------- | -------------------------------- |
| `XKM` | Kamuntu (**fictitious**) | country → region → district → ward → village | 884   | none                       | none    | CC0-1.0                          |
| `ETH` | Ethiopia                 | country → region → zone → woreda             | 1,271 | core + `agriculture` theme | yes     | CC BY-IGO (attribution required) |

{% hint style="warning" %}
`XKM` is the MDS chart default on purpose (the defaults are on [Deployment](/platform/platform-services/master-data-service/deployment.md#settings-at-install)): an unconfigured install shows a country that does not exist, so invented figures are never attached to a real place. But it is **geography only**. For a registry you can fill in, use a pack with datasets (today, `ETH`).
{% endhint %}

### P-codes

Units are identified by their OCHA **P-codes**; see [Geography: P-codes](/platform/platform-services/master-data-service/geography.md#p-codes).

### Sources and licence

| Pack type                  | Source                                                                                                                                                                          | Licence                                                       |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| Real country               | **OCHA COD-AB** (Common Operational Datasets – Administrative Boundaries), fetched from **HDX**, the Humanitarian Data Exchange. Hierarchy, P-codes and shapes all come from it | **CC BY-IGO: attribution required** wherever the map is shown |
| Fictitious country (`XKM`) | Generated by `generate_synthetic_pack.py`: invented coastline and place names, codes from the ISO user-assigned range                                                           | CC0-1.0                                                       |

Each pack records its source, licence and upstream version in `manifest.json`. On load, MDS sets the geography's [data licence](/platform/platform-services/master-data-service/public-catalogue.md#data-licence) from it, unless an administrator already set one. COD-AB boundaries are **operational**: they are not a statement on the legal or political status of any territory.

## How a pack reaches the services

```mermaid
flowchart LR
    PACK["openg2p-data<br/>packs/&lt;CODE&gt;"] -->|"loader Job"| MDS["MDS<br/>hierarchy · datasets · sample people"]
    PACK -->|"loader Job"| OBJ[("Object store<br/>boundaries")]
    MDS -->|"datasets, geography: live<br/>sample people: at install"| REG["Registries"]
    OBJ -->|"at build time"| MAP["Map"]
    REG -->|"figures, joined on P-code"| MAP
```

Who reads what, and how, is on [For Consumers](/platform/platform-services/master-data-service/consumers.md#who-reads-mds-and-how). The registry side is in [Country data & seeding](/products/registry/registry/deployment-and-extension/country-data-and-seeding.md); the map side in [Map drill-down](/platform/platform-services/reporting-and-analytics/map-drill-down.md).

## Setting up a new country

### 1. Fetch the geography

For a country with a COD-AB dataset on HDX:

```bash
cd openg2p-data/scripts/packs
python3 fetch_country_pack.py --country <ISO3> \
    --level-names <level1>,<level2>,<level3> --out ../../packs/<ISO3>
```

It downloads the boundaries, derives the hierarchy from the P-codes, simplifies and repairs the shapes, and writes provenance and licence to the manifest.

* `--level-names`: the country's names for the levels below `country` (default `adm1`, `adm2`, …). Labels only; the hierarchy comes from the data.
* `--max-depth`: the deepest level to include (default `3`).

### 2. Add the country's content

Add the datasets, any themes, the address format and a few dozen sample people. Use the role vocabulary where an entry has a role.

#### Pack file layout

| Path                                                  | What it holds                                                                                                    |
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `manifest.json`                                       | Source, licence, version, level names, unit counts                                                               |
| `levels.json`                                         | The levels: id, name, parent level                                                                               |
| `values.json`                                         | Every unit: id (its P-code), level, parent, name                                                                 |
| `boundaries/<level>.geojson`                          | Simplified map shapes for one level, keyed on P-code                                                             |
| `codelists/<attribute>.json`                          | Core datasets                                                                                                    |
| `domains/<theme>/*.json`                              | Theme datasets, for example `domains/agriculture/`                                                               |
| `address.json`                                        | The address parts below the lowest level                                                                         |
| `samples/individuals.json`, `samples/households.json` | Sample people and their households                                                                               |
| `changes.json`                                        | Optional: real geography change events for the next load (see [Later loads](#later-loads-drafts-not-overwrites)) |

Next to the packs, `openg2p-data` holds `packs/roles.json` (the role vocabulary) and the tooling in `scripts/packs/`.

#### Semantic roles

Reports ask about meaning, not literal values ("is this person the head of the household?"), and a literal such as `'SELF'` breaks when a country uses another code. So dataset entries may carry **roles** from `packs/roles.json`, a closed vocabulary; each role names its dataset and whether one entry or many may hold it.

{% hint style="warning" %}
**Stored and served, not yet used.** MDS keeps each entry's roles and returns them in dataset reads, but no API filters by role and no registry or report reads them yet. Keep roles in packs (they are validated), but do not build on them yet.
{% endhint %}

#### Addresses

**An address is a P-code plus what is written below it, never both.** The P-code already gives the whole chain of units, so no address repeats it as text. `address.json` declares only the parts below the lowest level (for Ethiopia: kebele and house number). Storing unit names beside the P-code holds the same fact twice, and one copy goes wrong when a unit is renamed.

### 3. Validate

```bash
python3 validate_pack.py ../../packs/<ISO3>
```

Run it before committing a pack. It checks:

* the hierarchy: one root, no orphans or cycles, unit counts match the manifest;
* P-codes: each extends its parent's;
* shapes: one per unit, valid rings, every child inside its parent, and a parent's children covering its area;
* datasets, roles, the address format and samples, including that each sample lies inside the unit its P-code names.

A wrong pack does not fail loudly. It seeds orphans or draws a map with holes, and the figures stop adding up later.

### 4. Point MDS at it

Set `masterData.geoSeed.countryPack` in `commons-services` (Rancher: **Country Pack**), and the themes in `geoSeed.domains`. See [Deployment: settings at install](/platform/platform-services/master-data-service/deployment.md#settings-at-install).

### 5. Verify

* MDS holds the number of units the manifest gives.
* Coded dropdowns in the staff portal list the country's entries, including any theme's (for example crops).
* Geo dropdowns populate at every level.
* The map renders and drills down.

## Loading and upgrading in MDS

The rule is: **a pack never overwrites published data.**

The loader runs as a Job in the MDS chart, after the API has prepared the database. It handles each dataset, and the geography, on its own.

### First load: the first version is published at once

Each dataset, and the geography, has its own version numbers (1, 2, 3, …). A dataset that does not exist yet, or the geography when it has no version yet, is loaded as its **first version (number 1)** and **published at once**. Nothing is published yet, so no approval is needed.

This also applies to a dataset that appears later (added in a newer pack, or a theme turned on after install). Labels in every language, codes, typed fields, schemas, descriptions and the publisher are kept as the pack gives them. Each dataset gets its theme from its pack folder (Core, or the theme's name).

### Later loads: drafts, not overwrites

When a dataset or the geography already has a published version, the loader compares the pack with it:

| Pack compared with the published version | What the loader does                                                                                                                                      |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Unchanged                                | Nothing. Re-running is safe                                                                                                                               |
| Different                                | Creates a **draft**: new entries or units added, changed ones updated, missing ones **retired** (never deleted). Changed boundary files go into the draft |
| An open draft already exists             | Skips it                                                                                                                                                  |

Drafts are **not submitted**. Someone reviews, submits and approves them like any other change (see [Change Control and Approvals](/platform/platform-services/master-data-service/change-control.md)); consumers see nothing until then. Steps: [Admin Guide](/platform/platform-services/master-data-service/admin-guide.md#load-a-newer-country-pack-version).

* **Codes are fixed once published.** A pack that gives a published entry a new code stops that dataset's load with an error. To recode, give the new code a new entry id and drop the old entry. See [Codes are fixed once published](/platform/platform-services/master-data-service/concepts.md#codes-are-fixed-once-published).
* **References between datasets.** Approve the referenced dataset first; see [Typed fields](/platform/platform-services/master-data-service/concepts.md#typed-fields).
* **A pack is a snapshot.** It says which units exist, not that one was split. Record the real events (split, merge, recode, …) in the draft, or ship them in `changes.json`; the loader checks them with the API's rules and stops the geography load if one is invalid. See [Geography: change events](/platform/platform-services/master-data-service/geography.md#change-events).

### What you choose at install

Which pack to load, which parts of it, which themes, and whether a first load is published at once are set on [Deployment](/platform/platform-services/master-data-service/deployment.md#settings-at-install). Boundary files go to the object store; see [Geography: boundaries per version](/platform/platform-services/master-data-service/geography.md#boundaries-per-version).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openg2p.org/platform/platform-services/master-data-service/country-packs.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
