> 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/partner-management/deployment.md).

# Deployment

Installing Partner Management — images, Helm chart, key values, routing, migrations, uninstall and configuration.

Partner Management ships a single Helm chart (`partner-management`) with three components — the staff-portal-api, the partner-api, and the staff portal UI — plus the standard OpenG2P init dependencies.

{% hint style="info" %}
**Installed as part of commons-services.** In an OpenG2P environment, Partner Management is deployed **as a subchart of `openg2p-commons-services`** (the shared platform services layer) — not installed separately. There it runs alongside the IAM staff-portal API, Audit Manager and AWE, and its components are named `commons-services-pm-staff-portal-api`, `commons-services-pm-partner-api`, and `commons-services-pm-staff-portal-ui`. The `partner-management` dependency in commons-services is pinned to a specific published PM version and bumped on each PM update while both are on `develop`. See [Commons Helm Chart](/operations/deployment/infrastructure-setup/environment-setup-multi-node/openg2p-commons-helm-chart.md).

The standalone chart below is for local/dev or isolated installs; the sections that follow describe that standalone chart, which commons-services embeds and re-wires (component names, DB names, and the Keycloak issuer split).
{% endhint %}

## Images

| Image                                         | Built from                           |
| --------------------------------------------- | ------------------------------------ |
| `openg2p/partner-management-staff-portal-api` | `docker/staff-portal-api/Dockerfile` |
| `openg2p/partner-management-partner-api`      | `docker/partner-api/Dockerfile`      |
| `openg2p/partner-management-staff-portal-ui`  | `docker/staff-portal-ui/Dockerfile`  |

Images **and** the Helm chart are built and published by a single `build-publish` GitHub workflow — a thin stub that calls the central reusable pipeline `openg2p/openg2p-packaging/.github/workflows/build-publish.yml@v1`. All versioning policy (image/chart versions per branch, e.g. `develop` → `0.0.0-develop.<run>`; the `FASTAPI_COMMON_REF` git-ref → SHA pin; changelog generation) lives centrally in `openg2p-packaging` behind the `@v1` tag, so the repo carries no versioning logic of its own. The stub declares only the repo's images and the chart's image-tag paths. See [Helm & Docker Versioning and CI](/operations/deployment/helm-docker-versioning-and-ci.md).

## Helm chart

`deployment/charts/partner-management`. Dependencies (from `https://openg2p.github.io/openg2p-helm`):

| Dependency      | Role                                                                                                                                                 |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `common`        | Shared Bitnami-style template helpers.                                                                                                               |
| `postgres-init` | Creates the service database + user secret.                                                                                                          |
| `keycloak-init` | Registers the `<release>-staff-portal` client + `partner_manager` role in the **staff** realm (same shape as g2p-bridge / national-social-registry). |

A `db-password-sync` pre-install/pre-upgrade hook re-syncs the DB role password to its Secret before the app pods start (persistent commons Postgres), matching g2p-bridge.

### Install

```bash
helm repo add openg2p https://openg2p.github.io/openg2p-helm
helm dep up deployment/charts/partner-management
helm install partner-management openg2p/partner-management \
  --namespace <ns> --create-namespace
```

### Key values

| Value                                                                                                                                | Default                                        | Notes                                                                                                                                      |
| ------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `global.postgresqlHost`                                                                                                              | `commons-postgresql`                           | Shared Postgres.                                                                                                                           |
| `global.keycloakRealm`                                                                                                               | `staff`                                        | Staff realm for admin auth.                                                                                                                |
| `global.authAdminRole`                                                                                                               | `partner_manager`                              | Role required on the staff-portal-api.                                                                                                     |
| `global.authClientId`                                                                                                                | `<release>-staff-portal`                       | Keycloak client the role lives under.                                                                                                      |
| `global.iamServiceUrl`                                                                                                               | `http://commons-services-iam-staff-portal-api` | Shared IAM the UI logs in against.                                                                                                         |
| `global.auditEnabled`                                                                                                                | `true`                                         | Ship admin API calls to the central Audit Manager (non-blocking).                                                                          |
| `global.auditManagerUrl`                                                                                                             | `http://commons-services-auditmanager:80`      | Shared Audit Manager (commons-services release).                                                                                           |
| `staffPortalApi.image.tag`                                                                                                           | `develop`                                      | staff-portal-api image tag.                                                                                                                |
| `partnerApi.image.tag`                                                                                                               | `develop`                                      | partner-api image tag.                                                                                                                     |
| `staffPortalApi.envVars.PARTNER_MANAGER_POLICY_FETCH_CACHE_MAX_AGE`, `partnerApi.envVars.PARTNER_MANAGER_POLICY_FETCH_CACHE_MAX_AGE` | `60`                                           | `Cache-Control` max-age (seconds) on policy-fetch responses; bounds how long callers may use a policy before re-reading it (keys use 300). |
| `staffPortalUi.image.tag`                                                                                                            | `develop`                                      | UI image tag.                                                                                                                              |
| `staffPortalApi.catalogueSources`                                                                                                    | `[]`                                           | Where policy forms get their choices; see [Catalogue sources](#catalogue-sources).                                                         |
| `staffPortalApi.catalogueCacheTtl`, `staffPortalApi.catalogueFetchTimeout`                                                           | `300`, `3`                                     | Seconds a fetched catalogue is reused; per-source fetch timeout.                                                                           |
| `staffPortalApi.masterData.url`                                                                                                      | `http://commons-services-master-data-api`      | Master Data Service for purposes and subject ID types; `""` = free text. See [Master Data code lists](#master-data-code-lists).            |
| `staffPortalApi.masterData.purposeListCode`, `.subjectIdTypeListCode`                                                                | `CONSENT_PURPOSE`, `SUBJECT_ID_TYPE`           | The code lists; `""` = free text for that field.                                                                                           |
| `staffPortalApi.masterData.cacheTtl`, `.timeout`                                                                                     | `300`, `5`                                     | Seconds a list is reused; request timeout.                                                                                                 |

### Catalogue sources

Optional. With sources, the staff portal offers registries' scopes and an exchange's use cases as choices, and the staff-portal-api checks policy requests against them ([how](/platform/platform-services/partner-management/functional-specifications.md#catalogue-sources)). Empty = free text, no checks.

```yaml
staffPortalApi:
  catalogueSources:
    - kind: scopes
      data_controller: farmer-registry   # the registry's Consent Data Controller
      url: http://farmer-registry-partner-api/partner/data_scopes
      label: Farmer Registry
    - kind: use_cases
      url: http://agri-composite-api/composite/v1/use-cases
      label: Agri Stack Composite
```

* `kind` — `scopes` (a registry's data scope catalogue) or `use_cases` (an exchange's published use cases).
* `data_controller` — scopes only, required: the policy's data controller, exactly as the registry reports it (a mismatch shows as the source's error).
* `url` — read with an unsigned `GET` from the staff-portal-api (in-cluster service names work). A registry source needs that registry's **Allow Unsigned Read of Data Scope Catalogue** (on by default in the registry chart): PM has no signing key, so it cannot use the signed `POST`. If the registry has turned it off, the source shows `HTTP 403` and the form falls back to free text.
* `label` — shown in the portal.

In Rancher, **Catalogue Sources** is a text field: paste the same list as YAML (or JSON). It reaches the API as `PARTNER_MANAGER_CATALOGUE_SOURCES` (JSON).

### Master Data code lists

On by default: the policy form's **Purposes** and **Subject ID types** are checklists of the country's Master Data lists, and requests are checked against them ([how](/platform/platform-services/partner-management/functional-specifications.md#master-data-code-lists)). The staff-portal-api reads them with a client-credentials token of this release's own Keycloak client (`global.authClientId`, secret `global.authClientSecret`, token URL from `global.keycloakIssuerUrl`), so that client's service account must be allowed to read Master Data (any authenticated staff-realm caller can). A list the country's pack does not have, or an unreachable MDS, leaves the field free text and never blocks a request. In Rancher: **Catalogue Sources → Master Data URL**, **Purposes List Code**, **Subject ID Types List Code**.

### Routing

Each component exposes an Istio `VirtualService` on the **internal** gateway:

* UI — `partner-management.<ns>.openg2p.org`
* staff-portal-api — `partner-management-staff-portal-api.<ns>.openg2p.org`
* partner-api — `partner-management-partner-api.<ns>.openg2p.org`

In-cluster consumers reach the **partner-api** directly via its Service DNS (`<release>-partner-api`) to fetch partner keys and access policies; the fetch API is not intended for the public internet, which is why it needs no caller signature. The UI reaches the staff-portal-api server-side via `http://<release>-staff-portal-api`.

### Migrations

Each API container runs `... <entrypoint> migrate && gunicorn ...` — a failed migration crashes the pod rather than serving against an un-migrated schema. Both entrypoints run the same idempotent `create_migrate()` against the shared DB. Columns added to an existing table later (e.g. `pm_partner_requests.warnings`) are added with `ALTER TABLE … ADD COLUMN IF NOT EXISTS` in the same step.

## Uninstall

`helm uninstall` leaves behind the PostgreSQL database and role (they live in the shared `commons-postgresql`, not the release) and the hook Jobs (`before-hook-creation` delete policy). Use the full uninstall script — modeled on g2p-bridge's — to clean everything up:

```bash
# Preview (no changes):
./deployment/scripts/uninstall-partner-management.sh --namespace <ns> --dry-run

# For real (interactive confirmation):
./deployment/scripts/uninstall-partner-management.sh --namespace <ns>

# Non-interactive (CI):
./deployment/scripts/uninstall-partner-management.sh --namespace <ns> --yes
```

It runs `helm uninstall`, deletes leftover Jobs/Pods/Secrets/ConfigMaps by `app.kubernetes.io/instance` label, drops the `<release-underscored>` database + `<release-underscored>_user` role inside commons-postgresql, and removes any PVCs/PVs. It preserves other components' databases, the shared commons IAM, and the Keycloak client (`<release>-staff-portal`, reused idempotently on reinstall). Flags: `--release`, `--postgres-release`, `--postgres-namespace`, `--keep-pvs`, `--dry-run`, `--yes`.

## Configuration reference

The APIs read `PARTNER_MANAGER_*` env vars for their own settings (e.g. `PARTNER_MANAGER_POLICY_FETCH_CACHE_MAX_AGE`, default `60`; `PARTNER_MANAGER_CATALOGUE_SOURCES`, a JSON list, default `[]`; `PARTNER_MANAGER_CATALOGUE_CACHE_TTL`, default `300`; `PARTNER_MANAGER_CATALOGUE_FETCH_TIMEOUT`, default `3`; `PARTNER_MANAGER_MDS_URL`, default `""` (off; the chart sets it), `PARTNER_MANAGER_MDS_TOKEN_URL`, `PARTNER_MANAGER_MDS_CLIENT_ID`, `PARTNER_MANAGER_MDS_CLIENT_SECRET`, `PARTNER_MANAGER_MDS_PURPOSE_LIST_CODE`, `PARTNER_MANAGER_MDS_SUBJECT_ID_TYPE_LIST_CODE`, `PARTNER_MANAGER_MDS_CACHE_TTL` (`300`), `PARTNER_MANAGER_MDS_TIMEOUT` (`5`)); the staff-portal-api additionally reads `COMMON_AUTH_*` (consumed by `openg2p-fastapi-auth`) for staff-realm JWT validation. The UI reads `IAM_URL` (shared IAM), `STAFF_PORTAL_API_URL` (this release's staff-portal-api), `LOGIN_PROVIDER_ID`, `COOKIE_DOMAIN`, `REDIRECT_URL`, and `KEYCLOAK_LOGOUT_URL`. See each component's `.env.example`.


---

# 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/partner-management/deployment.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.
