> For the complete documentation index, see [llms.txt](https://docs.digit.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.digit.org/complaints-management/digit-complaints-management/release-notes/migration-guide.md).

# Migration Guide

## Change Overview&#x20;

<table><thead><tr><th width="196.4765625">Category</th><th>What Changed</th></tr></thead><tbody><tr><td><strong>New services</strong></td><td><code>digit-config-service</code>, <code>digit-user-preferences-service</code>, <code>novu-bridge</code></td></tr><tr><td><strong>Updated services</strong></td><td><code>pgr-services</code> (v3.0.0), <code>egov-hrms</code>, <code>digit-ui</code></td></tr><tr><td><strong>New DB tables</strong></td><td><code>eg_config_data</code>, <code>user_preference</code>, <code>nb_dispatch_log</code>, <code>eg_pgr_document_v2</code></td></tr><tr><td><strong>Persister configs</strong></td><td><code>boundary-management-urban-persister.yml</code> added; <code>persist-yml-path</code> updated</td></tr><tr><td><strong>Backbone</strong></td><td>MinIO chart replaced, Novu Helm chart added</td></tr><tr><td><strong>Infrastructure</strong></td><td>Kubernetes 1.33, PostgreSQL 15, multi-arch (arm64/x86_64) support</td></tr><tr><td><strong>Localisation keys</strong></td><td>Complaint type/sub-type keys changed from <code>.</code> separator to <code>_</code> (e.g. <code>Streetlight.nostreetlight</code> → <code>Streetlight_nostreetlight</code>)</td></tr></tbody></table>

***

## Pre-requisites

* Running CCRS v2.10 cluster (Kubernetes ≥ 1.28 for in-place upgrade; 1.33 for fresh infrastructure)
* PostgreSQL 12+ (15 recommended for fresh deployments)
* Access to push to your Helm environment repo
* Novu account and API key (required for `novu-bridge`)
* Git access to `egovernments/Citizen-Complaint-Resolution-System`

***

## Steps

### Step 1 — Database Migrations

Run the following SQL migrations **in order** against your DIGIT PostgreSQL instance. They run automatically via Flyway init-containers when you deploy the services, but they are listed here for reference and manual execution if needed.

#### 1.1 digit-config-service

```sql
-- V20260302000000__create_eg_config_data.sql
CREATE TABLE eg_config_data (
    id                  VARCHAR(64) NOT NULL,
    tenantid            VARCHAR(255) NOT NULL,
    uniqueidentifier    VARCHAR(255),
    schemacode          VARCHAR(255) NOT NULL,
    data                JSONB NOT NULL,
    isactive            BOOLEAN NOT NULL DEFAULT TRUE,
    createdby           VARCHAR(64),
    lastmodifiedby      VARCHAR(64),
    createdtime         BIGINT,
    lastmodifiedtime    BIGINT,
    CONSTRAINT pk_eg_config_data PRIMARY KEY (tenantid, schemacode, uniqueidentifier),
    CONSTRAINT uk_eg_config_data UNIQUE (id)
);

CREATE INDEX idx_eg_config_data_schemacode        ON eg_config_data (schemacode);
CREATE INDEX idx_eg_config_data_tenantid          ON eg_config_data (tenantid);
CREATE INDEX idx_eg_config_data_uniqueidentifier  ON eg_config_data (uniqueidentifier);
CREATE INDEX idx_eg_config_data_isactive          ON eg_config_data (isactive);
CREATE INDEX idx_eg_config_data_data_gin          ON eg_config_data USING gin (data);
```

#### 1.2 digit-user-preferences-service

```sql
-- V20260205120000__create_user_preference.sql
CREATE TABLE IF NOT EXISTS user_preference (
    id                  UUID PRIMARY KEY,
    user_id             VARCHAR(64) NOT NULL,
    tenant_id           VARCHAR(64),
    preference_code     VARCHAR(128) NOT NULL,
    payload             JSONB NOT NULL DEFAULT '{}',
    created_by          VARCHAR(64) NOT NULL,
    created_time        BIGINT NOT NULL,
    last_modified_by    VARCHAR(64) NOT NULL,
    last_modified_time  BIGINT NOT NULL
);

CREATE UNIQUE INDEX IF NOT EXISTS idx_user_preference_unique
    ON user_preference (user_id, tenant_id, preference_code);
```

#### 1.3 novu-bridge

```sql
-- V20260217124000__create_nb_dispatch_log.sql
CREATE TABLE IF NOT EXISTS nb_dispatch_log (
    id                      UUID PRIMARY KEY,
    event_id                VARCHAR(64) NOT NULL,
    module                  VARCHAR(128) NOT NULL,
    event_name              VARCHAR(256) NOT NULL,
    tenant_id               VARCHAR(256) NOT NULL,
    channel                 VARCHAR(64) NOT NULL,
    recipient_value         VARCHAR(256) NOT NULL,
    template_key            VARCHAR(256),
    template_version        VARCHAR(64),
    status                  VARCHAR(32) NOT NULL,
    attempt_count           INT NOT NULL DEFAULT 0,
    last_error_code         VARCHAR(128),
    last_error_message      TEXT,
    provider_response_jsonb JSONB,
    created_time            BIGINT NOT NULL,
    last_modified_time      BIGINT NOT NULL
);

-- V20260325120000__add_reference_number.sql
ALTER TABLE nb_dispatch_log ADD COLUMN IF NOT EXISTS reference_number VARCHAR(256);
CREATE INDEX IF NOT EXISTS idx_nb_dispatch_reference_number ON nb_dispatch_log (reference_number);
```

#### 1.4 pgr-services

```sql
-- V20260405084400__create_pgr_document_table.sql
CREATE TABLE IF NOT EXISTS eg_pgr_document_v2 (
    id                  character varying(64) NOT NULL,
    document_type       character varying(64),
    filestore_id        character varying(64),
    document_uid        character varying(64),
    service_id          character varying(64),
    additional_details  jsonb,
    created_by          character varying(64),
    last_modified_by    character varying(64),
    created_time        bigint,
    last_modified_time  bigint,
    CONSTRAINT uk_eg_pgr_document_v2 PRIMARY KEY (id),
    CONSTRAINT fk_eg_pgr_document_v2 FOREIGN KEY (service_id)
        REFERENCES eg_pgr_service_v2 (id) MATCH SIMPLE
        ON UPDATE NO ACTION ON DELETE NO ACTION
);

CREATE INDEX IF NOT EXISTS index_eg_pgr_document_v2_tenant_service
    ON eg_pgr_document_v2 (service_id);
CREATE INDEX IF NOT EXISTS index_eg_pgr_document_v2_filestore_id
    ON eg_pgr_document_v2 (filestore_id);
```

**1.4.1 Data migration — backfill existing PGR documents from workflow**

If you have existing complaints with documents attached via the workflow engine, run the following query to backfill them into `eg_pgr_document_v2`. This is a one-time migration step for existing data.

```sql
-- Backfill PGR documents from workflow tables into eg_pgr_document_v2.
-- Safe to re-run: ON CONFLICT DO NOTHING skips already-migrated rows.
INSERT INTO eg_pgr_document_v2 (
    id,
    document_type,
    filestore_id,
    document_uid,
    service_id,
    additional_details,
    created_by,
    last_modified_by,
    created_time,
    last_modified_time
)
SELECT
    d.id,
    d.documenttype,
    d.filestoreid,
    d.documentuid,
    p.businessid,          -- FK → eg_pgr_service_v2.id (validated by JOIN below)
    NULL,                  -- additional_details not available in workflow table
    d.createdby,
    d.lastmodifiedby,
    d.createdtime,
    d.lastmodifiedtime
FROM eg_wf_document_v2 d
JOIN eg_wf_processinstance_v2 p
    ON p.id = d.processinstanceid
JOIN eg_pgr_service_v2 s
    ON s.id = p.businessid
WHERE (p.modulename = 'PGR' OR p.businessservice LIKE 'PGR%')
  AND d.active = true
ON CONFLICT (id) DO NOTHING;
```

**Corrections vs. the original query:**

<table><thead><tr><th width="187.44921875">Issue</th><th width="181.98046875">Original</th><th>Fixed</th></tr></thead><tbody><tr><td>Column list</td><td>Missing</td><td>Explicit <code>INSERT</code> and <code>SELECT</code> columns</td></tr><tr><td>Source column names</td><td><code>documenttype</code>, <code>filestoreid</code> assumed wrong casing</td><td>Correct lowercase names from <code>eg_wf_document_v2</code> schema</td></tr><tr><td><code>moduleName</code> / <code>businessService</code></td><td>Mixed case</td><td>Lowercase <code>modulename</code> / <code>businessservice</code> per actual schema</td></tr><tr><td>Soft-deleted documents</td><td>Not filtered</td><td><code>AND d.active = true</code> excludes inactive documents</td></tr><tr><td>Idempotency</td><td>Fails on re-run</td><td><code>ON CONFLICT (id) DO NOTHING</code> makes it safe to re-run</td></tr><tr><td><code>service_id</code> source</td><td>Ambiguous</td><td>Explicitly mapped from <code>p.businessid</code></td></tr></tbody></table>

> **Verify after running:**
>
> ```sql
> SELECT COUNT(*) FROM eg_pgr_document_v2;
> -- Should match the number of active PGR workflow documents:
> SELECT COUNT(*) FROM eg_wf_document_v2 d
> JOIN eg_wf_processinstance_v2 p ON p.id = d.processinstanceid
> WHERE (p.modulename = 'PGR' OR p.businessservice LIKE 'PGR%')
>   AND d.active = true;
> ```

> **Note:** All migrations run automatically via Flyway init-containers if you apply the Helm charts in Step 2 and Step 3. Manual execution is only needed if you manage schema changes outside of the deployment pipeline.

***

### Step 2 — Deploy New Services

Three new services are introduced in v2.11. Deploy them in this order:

#### 2.1 digit-config-service

Stores notification provider credentials and template bindings in MDMS v2 style.

```bash
helmfile -f devops/deploy-as-code/charts/common-services/common-services-helmfile.yaml \
  -l name=digit-config-service apply
```

**Key configuration** (add to your `env.yaml`):

```yaml
digit-config-service:
  memory_limits: 512Mi
```

**New service endpoint** (add to `module-level-tenant-id` service map):

```yaml
digit-config-service: "http://digit-config-service.egov:8080/"
```

#### 2.2 digit-user-preferences-service

Go microservice that stores per-user notification preferences (channel, language).

```bash
helmfile -f devops/deploy-as-code/charts/common-services/common-services-helmfile.yaml \
  -l name=digit-user-preferences-service apply
```

**Key configuration**:

```yaml
digit-user-preferences-service:
  memory_limits: 256Mi
  db-ssl-mode: "require"
```

**New service endpoint**:

```yaml
digit-user-preferences-service: "http://digit-user-preferences-service.egov:8080/"
```

#### 2.3 novu-bridge

Notification dispatch bridge for SMS, WhatsApp, and email via Novu.

```bash
helmfile -f devops/deploy-as-code/charts/common-services/common-services-helmfile.yaml \
  -l name=novu-bridge apply
```

**Required configuration** (set in your `env.yaml`):

```yaml
novu-bridge:
  memory_limits: 512Mi
  preference-check-path: "/user-preference/v1/_search"
  config-resolve-path: "/config-service/config/v1/_resolve"
  config-search-path: "/config-service/config/v1/_search"
  novu-base-url: "http://novu-api.novu:3000"
  novu-api-key: "<YOUR_NOVU_API_KEY>"   # Set per environment
```

**New service endpoint**:

```yaml
novu-bridge: "http://novu-bridge.egov:8080/"
novu-api:    "http://novu-api.novu:3000/"
```

***

### Step 3 — Update Existing Services

#### 3.1 pgr-services → v3.0.0

Major version bump. Key changes:

* Publishes structured domain events on complaint create/update for the Novu notification pipeline
* Enriches events with `submittedDate`, `assigneeName`, `assigneeDesignation`
* Resolves the service display name from MDMS
* Enriches service request with department name (replaces department code)
* New `eg_pgr_document_v2` table for document attachments

```bash
helmfile -f devops/deploy-as-code/charts/urban/urban-helmfile.yaml \
  -l name=pgr-services apply
```

Image: `pgr-services:v2.11-a520687` / DB: `pgr-services-db:v2.11-a520687`

#### 3.2 egov-hrms

Updated with boundary integration support.

```bash
helmfile -f devops/deploy-as-code/charts/common-services/common-services-helmfile.yaml \
  -l name=egov-hrms apply
```

Image: `egov-hrms:hrms-boundary-0a4e737` / DB: `egov-hrms-db:hrms-boundary-0a4e737`

The HRMS Dev Mode flag has been introduced to remove the dependency on SMS gateway integration. During employee creation, credentials are typically shared via SMS, but this is not feasible in the initial setup, creating challenges in accessing the auto-generated password. To simplify this, the flag has been introduced. However, for production environments, this flag should be set to **false**.

`egov-hrms:`\
&#x20; `java-args: -Dspring.profiles.active=monitoring`\
&#x20; `heap: "-Xmx192m -Xms192m"`\
&#x20; `memory_limits: 386Mi`\
&#x20; `hrms-dev-mode: "true"`

**New secret required** — add `egov-hrms-secrets` to your configmaps (see Section 7).

#### 3.3 digit-ui

Updated open-endpoint and mixed-mode endpoint whitelists. Cleaned up legacy PGR v1 endpoints.

```bash
helmfile -f devops/deploy-as-code/charts/urban/urban-helmfile.yaml \
  -l name=digit-ui apply
```

Image: `digit-ui:v2.11-a520687`

***

### Step 4 — Update Configs (egov-persister)

#### 4.1 New persister config

A new file `boundary-management-urban-persister.yml` has been added to `configs/egov-persister/`.

Ensure this file is present in your configs repo/path.

#### 4.2 Updated persister configs — `eg_pgr_document_v2` queryMaps

Two existing persister files have been updated to add INSERT queryMaps for the new `eg_pgr_document_v2` table:

**`configs/egov-persister/pgr-services-persister.yml`** — added under the `save-pgr-request` topic mapping:

```yaml
- query: INSERT INTO eg_pgr_document_v2(id, document_type, filestore_id, document_uid, service_id, additional_details, created_by, last_modified_by, created_time, last_modified_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
  basePath: service.documents.*
  jsonMaps:
  - jsonPath: $.service.documents.*.id
  - jsonPath: $.service.documents.*.documentType
  - jsonPath: $.service.documents.*.fileStoreId
  - jsonPath: $.service.documents.*.documentUid
  - jsonPath: $.service.id
  - jsonPath: $.service.documents.*.additionalDetails
    type: JSON
    dbType: JSONB
  - jsonPath: $.service.auditDetails.createdBy
  - jsonPath: $.service.auditDetails.lastModifiedBy
  - jsonPath: $.service.auditDetails.createdTime
  - jsonPath: $.service.auditDetails.lastModifiedTime
```

**`configs/egov-persister/pgr-migration-batch.yml`** — added under the `save-pgr-request-batch` topic mapping with the same queryMap structure shown above.

Ensure your configs repo has the latest versions of both files before restarting `egov-persister`.

#### 4.3 Update persist-yml-path

In your `env.yaml`, update the `egov-persister` `persist-yml-path` to add the new file at the end:

```yaml
egov-persister:
  persist-yml-path: >-
    file:///work-dir/Citizen-Complaint-Resolution-System/configs/egov-persister/audit-service-persister.yml,
    file:///work-dir/Citizen-Complaint-Resolution-System/configs/egov-persister/egov-user-event-persister.yml,
    file:///work-dir/Citizen-Complaint-Resolution-System/configs/egov-persister/egov-workflow-v2-persister.yml,
    file:///work-dir/Citizen-Complaint-Resolution-System/configs/egov-persister/hrms-employee-persister.yml,
    file:///work-dir/Citizen-Complaint-Resolution-System/configs/egov-persister/pgr-migration-batch.yml,
    file:///work-dir/Citizen-Complaint-Resolution-System/configs/egov-persister/pgr-services-persister.yml,
    file:///work-dir/Citizen-Complaint-Resolution-System/configs/egov-persister/mdms-persister.yml,
    file:///work-dir/Citizen-Complaint-Resolution-System/configs/egov-persister/boundary-persister.yml,
    file:///work-dir/Citizen-Complaint-Resolution-System/configs/egov-persister/boundary-management-urban-persister.yml
```

> Restart `egov-persister` after updating this value.

***

### Step 5 — Update Helm Environment Config

Apply the following changes to your `devops/deploy-as-code/charts/environments/env.yaml`:

#### 5.1 New global config values

```yaml
global:
  dev-enabled: "true"         # set to "false" in production
  egov-mdms-search-endpoint: /mdms-v2/v1/_search
```

#### 5.2 New secrets in `env-secrets.yaml`

Add the following secret blocks (fill in actual values per environment):

```yaml
# MinIO root credentials
minio:
  root-user: <minio_root_user>
  root-password: <minio_root_password>

# Filestore (S3/MinIO) config
egov-filestore:
  fixed-bucketname: <filestore_s3_bucket>
  minio-url: "http://minio-svc.backbone:9000/"

# HRMS secrets
egov-hrms: 
  employee-default-password: eGov@123   # Change as required by your deployment
```

#### 5.3 Updated configmaps

Three new Kubernetes secret templates are introduced in `core-services/configmaps/`:

* `egov-filestore-secret.yaml`
* `egov-hrms-secrets.yaml`
* `minio-root-secret.yaml`

Apply:

```bash
helmfile -f devops/deploy-as-code/charts/core-services/core-services-helmfile.yaml \
  -l name=configmaps apply
```

#### 5.4 MDMS endpoint key rename

The `MDMS_V2_HOST` key was renamed. Verify your `env.yaml` uses:

```yaml
egov-mdms-search-endpoint: /mdms-v2/v1/_search
```

***

### Step 6 — Backbone / Infrastructure Changes

#### 6.1 MinIO (chart replaced)

The MinIO Helm chart has been updated to the Bitnami chart (v13.3.1). **This is a breaking change** if you are using the old chart.

```bash
helmfile -f devops/deploy-as-code/charts/backbone-services/backboneservices-helmfile.yaml \
  -l name=minio apply
```

Ensure persistence is configured in `env.yaml`:

```yaml
minio:
  persistence:
    storageClass: <storage_class>   # e.g. "standard" or your cloud storage class
    accessMode: ReadWriteOnce
    size: 20Gi
```

> **Warning:** If migrating an existing MinIO deployment, back up all bucket data before upgrading the chart. The new chart may not be compatible with the existing PVC if the storage class differs.

#### 6.2 Novu backbone services

Novu is now deployed as a backbone service (v2.3.0 Helm chart). Deploy:

```bash
helmfile -f devops/deploy-as-code/charts/backbone-services/backboneservices-helmfile.yaml \
  -l name=novu apply
```

This installs Novu API, Worker, Dashboard, MongoDB, and Redis.

#### 6.3 Kafka-Kraft image

Kafka-Kraft Bitnami image was updated to fix deprecation. No config change needed — the chart handles this.

***

### Step 7 — Terraform / Infra-as-Code Changes

> Skip this section if you are upgrading an existing cluster without reprovisioning infrastructure.

Changes in `devops/infra-as-code/terraform/sample-aws/`:

| Parameter          | v2.10        | v2.11               |
| ------------------ | ------------ | ------------------- |
| Kubernetes version | 1.28         | **1.33**            |
| PostgreSQL version | 14.x         | **15.12**           |
| DB instance class  | db.t3.medium | **db.t4g.medium**   |
| Worker node arch   | x86\_64 only | **x86\_64 + arm64** |

The `variables.tf` now includes an `architecture` variable:

```hcl
variable "architecture" {
  description = "Architecture for worker nodes (x86_64 or arm64)"
  default     = "x86_64"
}
```

Set `architecture = "arm64"` to use Graviton instances (`t4g.xlarge`).

***

### Step 8 — Localisation Key Format Change (Complaint Type / Sub-type)

**Breaking change.** The separator used in localisation message codes for complaint types and sub-types has changed from `.` (dot) to `_` (underscore).

#### What changed

| v2.10 key format          | v2.11 key format          |
| ------------------------- | ------------------------- |
| `SERVICEDEFS.SERVICECODE` | `SERVICEDEFS_SERVICECODE` |

**Example:**

| v2.10                        | v2.11                        |
| ---------------------------- | ---------------------------- |
| `SERVICEDEFS.BADSTREETLIGHT` | `SERVICEDEFS_BADSTREETLIGHT` |
| `SERVICEDEFS.pothole`        | `SERVICEDEFS_pothole`        |

#### Why this matters

Any localisation message entries you have loaded (via localisation or the dataloader) using the old `.` separator will **no longer resolve** in the UI after upgrading. The UI will fall back to the raw key, causing untranslated labels to appear for complaint types and sub-types.

#### Action required

**Option A — Re-run the dataloader**&#x20;

If you use the default-data-handler or Jupyter dataloader to seed localisation data, re-run the load after upgrading. The updated loader generates keys with `_` separators automatically. This updates the default data only. It does not update any custom data you added.

**Option B — Manual update via Localisation API**

For each affected tenant, upsert the corrected keys. Example payload:

```json
{
  "RequestInfo": { ... },
  "tenantId": "pb",
  "messages": [
    {
      "code": "SERVICEDEFS_BADSTREETLIGHT",
      "message": "Bad Street Light",
      "module": "rainmaker-pgr",
      "locale": "en_IN"
    }
  ]
}
```

Call `POST /localization/messages/v1/_upsert` for each tenant/locale combination.

**Option C — Bulk rename via SQL (advanced)**

If you have direct DB access to the localisation service database:

```sql
UPDATE message
SET code = replace(code, '.', '_')
WHERE module = 'rainmaker-pgr'
  AND code LIKE 'SERVICEDEFS.%';
```

Notes:

* Table is `message` (not `eg_ms_messages`).
* Scoping to `code LIKE 'SERVICEDEFS.%'` makes the replace safe — only dots inside SERVICEDEFS keys are affected, other modules are untouched.
* No tenant or locale filter needed — this must run across all tenants (`statea`, etc.) and all locales (`en_IN`, `hi_IN`, `default`).
* Handles multi-dot codes like `SERVICEDEFS.NOSTREETLIGHT.DEPT_1` → `SERVICEDEFS_NOSTREETLIGHT_DEPT_1` correctly.

> **Caution:** Test this query on a non-production database first. Take a backup before running.

#### Verification

After migrating keys, open the PGR complaint creation flow in the UI and confirm that complaint type and sub-type labels display correctly in all configured locales.

***

## Rollback Plan

If you need to roll back to v2.10:

1. **Revert Helm deployments** to v2.10 image tags (see Section 12 for tags — check your v2.10 env.yaml for previous values).
2. **Database**: The new tables (`eg_config_data`, `user_preference`, `nb_dispatch_log`, `eg_pgr_document_v2`) can remain — they are additive and do not affect v2.10 services. To fully clean up, drop them manually.
3. **Persister**: Revert `persist-yml-path` to remove `boundary-management-urban-persister.yml`.
4. **New services** (`digit-config-service`, `digit-user-preferences-service`, `novu-bridge`): Scale down to 0 replicas or delete the Helm releases.

***

## Service Image Reference

<table><thead><tr><th width="288.953125">Service</th><th width="239.97265625">v2.11 Image Tag</th><th width="253.04296875">DB Migration Image</th></tr></thead><tbody><tr><td><code>pgr-services</code></td><td><code>v2.11-a520687</code></td><td><code>pgr-services-db:v2.11-a520687</code></td></tr><tr><td><code>novu-bridge</code></td><td><code>v2.11-a520687</code></td><td><code>novu-bridge-db:v2.11-a520687</code></td></tr><tr><td><code>digit-config-service</code></td><td><code>v2.11-a520687</code></td><td><code>digit-config-service-db:v2.11-a520687</code></td></tr><tr><td><code>digit-user-preferences-service</code></td><td><code>v2.11-a520687</code></td><td>—</td></tr><tr><td><code>egov-hrms</code></td><td><code>hrms-boundary-0a4e737</code></td><td><code>egov-hrms-db:hrms-boundary-0a4e737</code></td></tr><tr><td><code>digit-ui</code></td><td><code>v2.11-a520687</code></td><td>—</td></tr></tbody></table>


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.digit.org/complaints-management/digit-complaints-management/release-notes/migration-guide.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
