Skip to content

Runbook: Escalation Routing Management

Manage escalation reference data: business areas, services, topics, subtopics, and routing rows. Two interfaces are available — the CLI for individual changes, and an Excel bulk load for replacing the full dataset at once. Both target the same tables.

Prerequisite: complete CLI Setup before proceeding. The bulk load also requires a database connection string and VPN access — see Bulk Load from Excel for details.


Background

  • Business areas — top-level organisational groupings (e.g. "Employment Benefits").
  • Services — categories of work (e.g. "Renewals"). Topics are assigned to services.
  • Topics — specific subjects within a service (e.g. "Annual Renewal"). The LLM matches the user's intent against the list of topics.
  • Subtopics — optional further refinement under a topic (e.g. "Late Submission").
  • Routing rows — link a business area + topic (+ optional subtopic) to contact details (email, phone, context text, notes). When the system classifies a request it looks up the matching routing row to determine where to send it.

CLI Management

All commands below target PROD. Swap --profile prod for --profile uat to target UAT.

Business Areas

List all business areas

altaforge-ra-cli --profile prod api admin escalation-business-area list
[
  { "id": 1, "name": "Employment Benefits" },
  { "id": 2, "name": "Housing Services" }
]

Add a business area

altaforge-ra-cli --profile prod api admin escalation-business-area add "New Business Area"

Rename a business area

altaforge-ra-cli --profile prod api admin escalation-business-area update <BUSINESS_AREA_ID> "Updated Name"

Delete a business area

altaforge-ra-cli --profile prod api admin escalation-business-area delete <BUSINESS_AREA_ID>

Warning: Only delete a business area after removing all routing rows that reference it. Deleting a business area still referenced by routing rows will produce an error. Delete routing rows first (see Routing rows).


Services

List all services

altaforge-ra-cli --profile prod api admin escalation-service list
[
  { "id": 1, "name": "Renewals" },
  { "id": 2, "name": "New Applications" }
]

Add a service

altaforge-ra-cli --profile prod api admin escalation-service add "New Service"

Rename a service

altaforge-ra-cli --profile prod api admin escalation-service update <SERVICE_ID> "Updated Service Name"

Delete a service

altaforge-ra-cli --profile prod api admin escalation-service delete <SERVICE_ID>

Warning: Deleting a service cascade-deletes all topics under it, and their subtopics. Any routing rows that reference those topics must be deleted first — they are not removed automatically. Run escalation-routing list --service "<SERVICE_NAME>" to find them, delete each one, then delete the service.


Topics

Topics are assigned to a service at creation time and cannot be reassigned. To move a topic to a different service, delete the old topic and recreate it under the new service.

List topics

altaforge-ra-cli --profile prod api admin escalation-topic list

Filter by service:

altaforge-ra-cli --profile prod api admin escalation-topic list --service-id <SERVICE_ID>
[
  { "id": 10, "serviceId": 1, "name": "Annual Renewal" },
  { "id": 11, "serviceId": 1, "name": "Mid-Year Adjustment" }
]

Add a topic

altaforge-ra-cli --profile prod api admin escalation-topic add <SERVICE_ID> "Topic Name"

Rename a topic

altaforge-ra-cli --profile prod api admin escalation-topic update <TOPIC_ID> "Updated Topic Name"

Delete a topic

altaforge-ra-cli --profile prod api admin escalation-topic delete <TOPIC_ID>

Warning: Deleting a topic cascade-deletes all subtopics under it. Any routing rows that reference this topic must be deleted first. Run escalation-subtopic list --topic-id <TOPIC_ID> to review subtopics and escalation-routing list --topic "<TOPIC_NAME>" to find routing rows.


Subtopics

List subtopics

altaforge-ra-cli --profile prod api admin escalation-subtopic list

Filter by topic:

altaforge-ra-cli --profile prod api admin escalation-subtopic list --topic-id <TOPIC_ID>
[
  { "id": 20, "topicId": 10, "name": "Late Submission" },
  { "id": 21, "topicId": 10, "name": "Change of Circumstances" }
]

Add a subtopic

altaforge-ra-cli --profile prod api admin escalation-subtopic add <TOPIC_ID> "Subtopic Name"

Rename a subtopic

altaforge-ra-cli --profile prod api admin escalation-subtopic update <SUBTOPIC_ID> "Updated Subtopic Name"

Delete a subtopic

altaforge-ra-cli --profile prod api admin escalation-subtopic delete <SUBTOPIC_ID>

Warning: You cannot delete a subtopic while routing rows reference it. Delete or repoint the routing rows first (see Routing rows).


Routing Rows

A routing row joins a business area and a topic (with an optional subtopic) to contact details. When the escalation classifier matches a user's request to a topic, the system finds the corresponding routing row to determine where to route it.

List routing rows

altaforge-ra-cli --profile prod api admin escalation-routing list

Filter by service name (exact match) or topic name (partial match):

altaforge-ra-cli --profile prod api admin escalation-routing list --service "Renewals"
altaforge-ra-cli --profile prod api admin escalation-routing list --topic "Annual"
altaforge-ra-cli --profile prod api admin escalation-routing list --service "Renewals" --topic "Annual"
[
  {
    "id": 30,
    "businessAreaId": 1,
    "topicId": 10,
    "subtopicId": null,
    "email": "renewals@example.com",
    "phone": "1-800-555-0100",
    "context": "For annual renewal enquiries",
    "requiredInformation": "Please have your file number ready.",
    "attachments": [{ "name": "Renewal Form", "link": "https://example.com/form.pdf" }],
    "resources": [{ "name": "Policy Guide", "link": "https://example.com/guide" }],
    "notes": "Route to Team A on Tuesdays",
    "extraFields": null,
    "fieldOverrides": { "reference_number": { "label": "File Number", "required": true } }
  }
]

Inspect a single routing row

altaforge-ra-cli --profile prod api admin escalation-routing get <ROUTING_ID>

Add a routing row

Required positional arguments: BUSINESS_AREA_ID and TOPIC_ID. All other arguments are optional.

altaforge-ra-cli --profile prod api admin escalation-routing add \
  <BUSINESS_AREA_ID> <TOPIC_ID> \
  --subtopic-id <SUBTOPIC_ID> \
  --email EMAIL \
  --phone PHONE \
  --context "Context text shown to the user" \
  --required-information "Body text shown in the escalation panel" \
  --attachments '[{"name": "Form A", "link": "https://example.com/form.pdf"}]' \
  --resources '[{"name": "Policy Guide", "link": "https://example.com/guide"}]' \
  --notes "Internal notes for operators" \
  --extra-fields '{"key": "value"}' \
  --field-overrides '{"reference_number": {"label": "File Number", "required": true}}'

--field-overrides currently supports one key: reference_number. Set it to override the default reference label shown in the escalation panel (e.g. "File Number" instead of the default):

altaforge-ra-cli --profile prod api admin escalation-routing add 1 10 \
  --field-overrides '{"reference_number": {"label": "File Number", "required": true}}'

Example — route topic 10 under business area 1 with contact details and body text:

altaforge-ra-cli --profile prod api admin escalation-routing add 1 10 \
  --email renewals@example.com \
  --phone "1-800-555-0100" \
  --context "Contact the renewals team for assistance." \
  --required-information "Please have your file number and last notice ready." \
  --attachments '[{"name": "Renewal Form", "link": "https://example.com/renewal.pdf"}]'

Update a routing row

At least one argument must be provided. Pass --business-area-id or --topic-id to repoint the row; pass any combination of the other flags to update individual fields:

altaforge-ra-cli --profile prod api admin escalation-routing update <ROUTING_ID> \
  --email new-contact@example.com \
  --phone "1-800-555-0200"

altaforge-ra-cli --profile prod api admin escalation-routing update <ROUTING_ID> \
  --required-information "Updated body text." \
  --attachments '[{"name": "New Form", "link": "https://example.com/new.pdf"}]'

altaforge-ra-cli --profile prod api admin escalation-routing update <ROUTING_ID> \
  --business-area-id 2 --topic-id 15

Delete a routing row

altaforge-ra-cli --profile prod api admin escalation-routing delete <ROUTING_ID>

Common Workflows

Add a new topic and wire up its routing

  1. Find or create the service:
    altaforge-ra-cli --profile prod api admin escalation-service list
    altaforge-ra-cli --profile prod api admin escalation-service add "Service Name"  # if needed
    
  2. Add the topic under the service. Note the id in the output.
    altaforge-ra-cli --profile prod api admin escalation-topic add <SERVICE_ID> "Topic Name"
    
  3. Optionally add subtopics:
    altaforge-ra-cli --profile prod api admin escalation-subtopic add <TOPIC_ID> "Subtopic Name"
    
  4. Find the business area ID:
    altaforge-ra-cli --profile prod api admin escalation-business-area list
    
  5. Create the routing row:
    altaforge-ra-cli --profile prod api admin escalation-routing add <BUSINESS_AREA_ID> <TOPIC_ID> \
      --email contact@example.com
    

Update a contact address on a routing row

  1. Find the routing row:
    altaforge-ra-cli --profile prod api admin escalation-routing list --topic "Topic Name"
    
  2. Note the id, then update:
    altaforge-ra-cli --profile prod api admin escalation-routing update <ROUTING_ID> \
      --email new-contact@example.com
    

Remove a topic and its routing

  1. Find all routing rows that reference the topic:
    altaforge-ra-cli --profile prod api admin escalation-routing list --topic "Topic Name"
    
  2. Delete each routing row:
    altaforge-ra-cli --profile prod api admin escalation-routing delete <ROUTING_ID>
    
  3. Delete the topic (subtopics cascade-delete automatically):
    altaforge-ra-cli --profile prod api admin escalation-topic delete <TOPIC_ID>
    

Apply the same change to UAT first

Replace --profile prod with --profile uat in any command above. UAT and PROD are independent; changes to one do not affect the other.


Bulk Load from Excel

Use the bulk load when replacing the full dataset from a master Excel spreadsheet rather than making individual CLI changes. The script connects directly to the database — you must be on VPN.

Prerequisites

  • The govlab-ls-research-assistant repository is cloned locally.
  • uv is installed and on PATH.
  • You have the DATABASE_URL connection string for the target environment. Obtain this from a developer or the deployment documentation.
  • You have the master Excel spreadsheet (.xlsx) for the client.

1. Configure scripts/.env

The script reads database credentials from scripts/.env at the repository root. Create or update it before each run if targeting a different environment.

DATABASE_URL=postgresql+asyncpg://<user>:<password>@<host>:5432/<database>
Engine URL format
PostgreSQL postgresql+asyncpg://user:password@host:5432/dbname
MSSQL (Azure AD auth) mssql+aioodbc://host:1433/dbname?driver=ODBC+Driver+18+for+SQL+Server&authentication=ActiveDirectoryInteractive
MSSQL (SQL auth) mssql+aioodbc://user:password@host:1433/dbname?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes

The database is not publicly accessible. You must be connected to the virtual network (VPN or equivalent) to reach it.

2. Prepare the Excel spreadsheet

The script reads the first sheet of the .xlsx file. Column names must appear in the first row. topic is required — rows without a topic are silently skipped (counted in the info output only, no warning emitted). business_area and service are also required; rows with a topic but missing either of these are skipped with a warning in the script output. All other columns are optional.

Column Description
topic Required. The escalation topic (e.g. "Benefits Renewal").
business_area Required. Business area owning the topic.
service Required. Service name. Rows missing business_area or service are skipped with a warning in the script output.
email Support team email address for this topic. See UAT warning below.
phone Phone number for escalation.
subtopic More specific categorisation under the topic.
context Additional context shown to the user.
body_1, body_2, body_3 Required information fields — combined into a single block.
note_1, note_2, note_3 Internal notes — combined into a single block.
attachment_1, attachment_1_link First attachment name and URL.
attachment_2, attachment_2_link Second attachment name and URL.
resource_1, resource_1_link Resource name and URL.
request_id Original request ID from the source system (stored for reference).
reference Reference number label override.

UAT warning: replace email addresses before loading

The email column contains real support team addresses used to route escalation notifications. Do not load a spreadsheet containing production email addresses into UAT — doing so risks sending test traffic to live support teams.

Before loading into UAT, replace every value in the email column with a safe test address, for example request.testing@aara.ca. Use a separate copy of the spreadsheet for this — do not modify the master.

3. Load the data

The standard workflow is a full replace: the script atomically deletes all existing routing rows for the client and inserts the new ones in a single transaction. If the insert fails for any reason, the original data is left intact.

Warning: CLEAR=--clear permanently removes all existing routing rows for the client before loading. Any routing row not present in the spreadsheet will be lost. Before running, confirm that the spreadsheet is the complete and authoritative dataset — not just the rows you are adding or changing.

Note: CLEAR=--clear clears routing rows only. The dimension tables (business areas, services, topics, subtopics) are always upserted and are not removed by --clear. This means dimensions added by earlier loads persist even after a full replace.

Always use CLEAR=--clear unless you have been explicitly told to append.

PROD

make load-escalation-requests \
  EXCEL="path/to/Request Table for Email Escalation.xlsx" \
  CLIENT=AARA \
  CLEAR=--clear

UAT

Ensure email addresses in the spreadsheet have been replaced (see above) before running.

make load-escalation-requests \
  EXCEL="path/to/Request Table for Email Escalation - UAT.xlsx" \
  CLIENT=AARA \
  CLEAR=--clear

The script prints the number of records loaded on success:

Successfully loaded 42 records for client "AARA".

Append mode (avoid unless instructed)

Omitting CLEAR=--clear inserts new records without removing existing ones. This causes duplicates if the same spreadsheet is loaded more than once. Only use append mode if a developer has explicitly instructed you to.

4. Verify the load

After loading, confirm the record count in the script output looks correct. If you are unsure, ask a developer to verify via the application's escalation endpoint.

If the script exits with an error before printing the success message, the database has not been modified — the transaction was rolled back. Check the error output and escalate to a developer if you cannot resolve it.


Escalation

If a command returns an unexpected error, escalate to the development team with:

  • The exact command run (or make target and arguments).
  • The full error output.
  • The environment (UAT or PROD) and approximate time.
  • The client name (CLIENT=) if running a bulk load.