> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Medical Terminology & Code Libraries — Admin Guide

> Feature ID: PF-70 Version: 1.0.0 Status: ✅ Implemented Last Updated: 2026-02-19 Audience: Platform Administrators, Org Admins Permission Required: pf.codes.adm…

**Feature ID:** PF-70\
**Version:** 1.0.0\
**Status:** ✅ Implemented\
**Last Updated:** 2026-02-19\
**Audience:** Platform Administrators, Org Admins\
**Permission Required:** `pf.codes.admin`

> This guide covers code set loading, effective dating, modifier configuration, payer rule management, and troubleshooting for the PF-70 Medical Terminology & Code Library.

***

## Table of Contents

1. [Overview](#overview)
2. [Prerequisites](#prerequisites)
3. [Code Set Loading](#code-set-loading)
4. [Annual Code Set Update Process](#annual-code-set-update-process)
5. [Modifier Configuration](#modifier-configuration)
6. [Payer Rule Configuration](#payer-rule-configuration)
7. [Dev Seed Data](#dev-seed-data)
8. [Troubleshooting](#troubleshooting)

***

## Overview

The PF-70 code library provides a centralized, platform-managed repository of medical codes used across the Encore Health OS:

| Code Set       | Table                 | Purpose                                                |
| -------------- | --------------------- | ------------------------------------------------------ |
| ICD-10-CM      | `pf_icd10_codes`      | Diagnosis codes (problem list, progress notes, claims) |
| CPT            | `pf_cpt_codes`        | Procedure codes (charge capture, claims)               |
| HCPCS          | `pf_hcpcs_codes`      | Ancillary services (peer support, community care)      |
| Code Modifiers | `pf_code_modifiers`   | Org-scoped CPT/HCPCS modifiers                         |
| Payer Rules    | `pf_payer_code_rules` | Org+payer-specific code restrictions                   |

**Architecture pattern:**

* Platform-managed codes (`organization_id IS NULL`) — readable by all authenticated users in all orgs.
* Org-scoped modifiers/payer rules (`organization_id IS NOT NULL`) — visible only within the owning organization.
* User-scoped data (`pf_code_favorites`, `pf_code_recent`) — visible only to the owning user.

***

## Prerequisites

Before loading any code data:

* You must have `pf.codes.admin` permission (typically granted to `org_admin` and `platform_admin` roles).
* For platform-managed code sets, mutations require a Supabase service role or migration script (RLS blocks app-layer writes on platform-managed tables).
* Effective dates must be verified against CMS or the relevant governing body's published release.

***

## Code Set Loading

### How Platform Code Sets Work

Each code version is a separate row in `pf_code_sets`:

```sql theme={null}
-- Example: ICD-10-CM FY 2026
INSERT INTO pf_code_sets (
  code_set,        -- 'ICD10CM', 'CPT', 'HCPCS'
  version,         -- Human-readable version label, e.g. '2026'
  effective_from,  -- CMS release date (YYYY-MM-DD)
  effective_to,    -- NULL for current version; set when superseded
  organization_id, -- NULL = platform-managed (readable by all orgs)
  is_active,
  description
)
VALUES ('ICD10CM', '2026', '2025-10-01', NULL, NULL, TRUE, 'ICD-10-CM FY 2026 — CMS release');
```

### Loading Individual Codes

After inserting the code set row, insert individual codes referencing its `id`:

```sql theme={null}
-- Example: batch insert ICD-10-CM codes
INSERT INTO pf_icd10_codes (
  code_set_id,
  code,
  description,
  effective_from,
  effective_to,      -- NULL = no known expiry
  is_behavioral_health,
  is_sdoh
)
VALUES
  ('<code_set_id>', 'F32.1', 'Major depressive disorder, single episode, moderate', '2025-10-01', NULL, TRUE, FALSE),
  ('<code_set_id>', 'Z59.0', 'Homelessness',                                        '2025-10-01', NULL, FALSE, TRUE),
  -- ... additional rows
;
```

> **Important:** Never hard-delete existing codes. Use `effective_to` to retire them.

### Loading CPT and HCPCS Codes

Same pattern using `pf_cpt_codes` and `pf_hcpcs_codes` respectively:

```sql theme={null}
INSERT INTO pf_cpt_codes (code_set_id, code, description, effective_from, effective_to, is_behavioral_health, category)
VALUES ('<code_set_id>', '90837', 'Psychotherapy, 60 minutes', '2025-01-01', NULL, TRUE, 'Psychiatry');

INSERT INTO pf_hcpcs_codes (code_set_id, code, description, effective_from, effective_to, is_behavioral_health, category)
VALUES ('<code_set_id>', 'H0038', 'Self-help/peer services, per 15 minutes', '2025-01-01', NULL, TRUE, 'Community Support');
```

### Where to Run Load Scripts

* **Development/Staging:** Supabase Dashboard → SQL Editor (`https://supabase.com/dashboard/project/{project_id}/sql/new`)
* **Production:** Via a reviewed and approved migration script in `supabase/migrations/` or Supabase SQL Editor with Live environment selected.

***

## Annual Code Set Update Process

CMS releases ICD-10-CM updates annually on October 1. CPT codes update on January 1.

### Step-by-Step Update Procedure

**Step 1 — Obtain the new code file**

* ICD-10-CM: Download the CMS flat file from [cms.gov/Medicare/Coding/ICD10](https://www.cms.gov/Medicare/Coding/ICD10)
* CPT: AMA annual CPT data file (licensed)
* HCPCS: CMS HCPCS quarterly update files

**Step 2 — Insert a new code set version**

```sql theme={null}
-- New version; DO NOT touch old code_set row
INSERT INTO pf_code_sets (code_set, version, effective_from, organization_id, is_active, description)
VALUES ('ICD10CM', '2026', '2025-10-01', NULL, TRUE, 'ICD-10-CM FY 2026');

SELECT id FROM pf_code_sets WHERE code_set = 'ICD10CM' AND version = '2026';
-- Use this ID for all code inserts
```

**Step 3 — Insert new codes for the new version**

Use a bulk INSERT or import script against the new `code_set_id`.

**Step 4 — Retire the previous version**

```sql theme={null}
-- Set effective_to on the superseded code set (not DELETE)
UPDATE pf_code_sets
SET effective_to = '2025-09-30'  -- last valid day of old version
WHERE code_set = 'ICD10CM'
  AND version = '2025'
  AND organization_id IS NULL;
```

**Step 5 — Verify via search API**

```typescript theme={null}
// In browser console or test:
import { searchCodes } from '@/platform/codes';
const result = await searchCodes({ codeSet: 'ICD10CM', query: 'F32', effectiveDate: '2025-10-15', organizationId: orgId });
console.log(result.results); // Should include FY2026 codes
```

### Rollback Procedure

If a bad load occurs:

1. Clear the affected `pf_icd10_codes` / `pf_cpt_codes` / `pf_hcpcs_codes` rows by the new `code_set_id`:
   ```sql theme={null}
   DELETE FROM pf_icd10_codes WHERE code_set_id = '<new_bad_code_set_id>';
   DELETE FROM pf_code_sets WHERE id = '<new_bad_code_set_id>';
   ```
2. Restore the previous version's `effective_to` to `NULL` if it was incorrectly retired.

***

## Modifier Configuration

Modifiers are **org-scoped** (not platform-managed). Each organization configures its own modifier set.

### Who Can Configure Modifiers

Users with `pf.codes.admin` permission (org\_admin or platform\_admin roles).

### Adding a Modifier

Via the Supabase SQL Editor or, once a UI is built, via Settings → Code Library → Modifiers:

```sql theme={null}
INSERT INTO pf_code_modifiers (
  organization_id,
  modifier_code,
  description,
  effective_from,
  effective_to,         -- NULL = no expiry
  applicable_code_sets, -- array: ['CPT'], ['HCPCS'], or ['CPT', 'HCPCS']
  created_by
)
VALUES (
  '<your_org_id>',
  'GT',
  'Via interactive audio/video telecommunication systems',
  '2025-01-01',
  NULL,
  '["CPT", "HCPCS"]',
  auth.uid()
);
```

### Retiring a Modifier

```sql theme={null}
UPDATE pf_code_modifiers
SET effective_to = '2025-12-31'
WHERE organization_id = '<your_org_id>'
  AND modifier_code = 'GT'
  AND deleted_at IS NULL;
```

***

## Payer Rule Configuration

Payer rules allow orgs to flag specific code-payer combinations as `denied`, `prior_auth`, or `requires_modifier`.

> **Note:** `payer_id` is a bare UUID referencing the PM-layer payer. There is no FK to `pm_payers` (architecture decision C-3: no PF→PM boundary crossing).

### Supported Rule Types

| `rule_type`         | Effect                                                                                |
| ------------------- | ------------------------------------------------------------------------------------- |
| `denied`            | `validateCode` returns invalid; clinician is warned before submission                 |
| `prior_auth`        | `validateCode` returns invalid with prior auth notice                                 |
| `requires_modifier` | `validateCode` checks `rule_config.required_modifier` is present in the modifier list |

### Adding a Payer Rule

```sql theme={null}
INSERT INTO pf_payer_code_rules (
  organization_id,
  payer_id,       -- bare UUID from pm_payers (no FK)
  code_set,       -- 'ICD10CM', 'CPT', 'HCPCS'
  code,
  rule_type,      -- 'denied' | 'prior_auth' | 'requires_modifier'
  rule_config,    -- JSONB: e.g. {"required_modifier": "GT"} for requires_modifier
  effective_from,
  effective_to    -- NULL = no expiry
)
VALUES (
  '<your_org_id>',
  '<payer_uuid>',
  'CPT',
  '90837',
  'requires_modifier',
  '{"required_modifier": "GT"}',
  '2025-01-01',
  NULL
);
```

***

## Dev Seed Data

The following seed data is loaded automatically via migration for development/testing environments. It includes a minimal set of ICD-10-CM, CPT, and HCPCS codes to unblock E2E testing of the search and validation APIs.

**ICD-10-CM seed codes (BH + SDOH):**

| Code    | Description                                         | BH | SDOH |
| ------- | --------------------------------------------------- | -- | ---- |
| F32.1   | Major depressive disorder, single episode, moderate | ✅  |      |
| F33.0   | Major depressive disorder, recurrent, mild          | ✅  |      |
| F41.1   | Generalized anxiety disorder                        | ✅  |      |
| F43.10  | Post-traumatic stress disorder, unspecified         | ✅  |      |
| Z59.0   | Homelessness                                        |    | ✅    |
| Z60.0   | Problems of adjustment to life-cycle transitions    |    | ✅    |
| Z62.810 | Personal history of physical abuse in childhood     |    | ✅    |

**CPT seed codes:**

| Code  | Description                                  |
| ----- | -------------------------------------------- |
| 90791 | Psychiatric diagnostic evaluation            |
| 90832 | Psychotherapy, 30 minutes                    |
| 90837 | Psychotherapy, 60 minutes                    |
| 90853 | Group psychotherapy                          |
| 90846 | Family psychotherapy without patient present |

**HCPCS seed codes:**

| Code  | Description                                          |
| ----- | ---------------------------------------------------- |
| H0038 | Self-help/peer services, per 15 minutes              |
| H2017 | Psychosocial rehabilitation services, per 15 minutes |
| H0019 | Therapeutic behavioral services, per diem            |

***

## Troubleshooting

### Search returns no results

1. **Check code set exists and is active:**
   ```sql theme={null}
   SELECT * FROM pf_code_sets WHERE code_set = 'ICD10CM' AND is_active = TRUE;
   ```
2. **Check effective date:** The search filters to codes where `effective_from <= today AND (effective_to IS NULL OR effective_to >= today)`. Ensure your seed/load date covers the queried date.
3. **Check RLS:** Run the query as an authenticated user. Platform code sets (`organization_id IS NULL`) should be visible to all users. Run `SELECT pf_can_read_code_set('<code_set_id>')` in the SQL editor to test the SECURITY DEFINER helper.

### Permission denied on INSERT/UPDATE

* Verify the user has `pf.codes.admin` permission:
  ```sql theme={null}
  SELECT * FROM pf_module_permissions WHERE permission_key = 'pf.codes.admin';
  SELECT * FROM pf_role_permissions WHERE permission_key = 'pf.codes.admin';
  ```
* Platform-managed code tables (`pf_icd10_codes`, `pf_cpt_codes`, `pf_hcpcs_codes`) block all app-layer mutations (by design). Loads must be done via service role or migration.

### `loinc_unavailable: true` in search metadata

LOINC is deferred to a future PF-70 phase. When CL-08 implementation begins, a `pf_loinc_codes` table will be added. Until then, `codeSet: 'LOINC'` always returns `{ results: [], meta: { loinc_unavailable: true } }`.

### validateCode returns unexpected errors

* Ensure `sanitizeErrorMessage` is wrapping all DB errors in `validateCode.ts`.
* Check the Supabase Edge Function logs if the validation is called via an edge function context.
* For payer rule issues, verify `payer_id` is the correct UUID (no FK enforcement — it is the caller's responsibility to pass the correct UUID).

***

## Related Docs

* [PF-70 Spec](../../specs/pf/specs/PF-70-medical-terminology-code-libraries.md)
* [PF-70 Integration Doc](../architecture/integrations/medical-terminology-code-libraries-integration.md)
* [Platform Integration Layers](../architecture/integrations/PLATFORM_INTEGRATION_LAYERS.md)
* [Permissions Quick Reference](./permissions-quick-reference.md)
* [Supabase SQL Editor](https://supabase.com/dashboard/project/zkgxozahyczcnzpwhbbf/sql/new)
