# Product Migration: Breaking Changes

> Last Updated: 2026-02-16

---

## 1. Pricing API Changes

| Before | After |
|--------|-------|
| `ClientProductPrice` model (`catalog_client_product_prices` table) | `ProductPrice` model (`core_product_prices` table) |
| Client-scoped pricing in catalog domain | Unified pricing in Core domain |

### Affected Endpoints
- All catalog pricing CRUD endpoints now operate on `core_product_prices`
- Response structure unchanged (via `ClientPricingResource`)

### Migration Path
- Existing `catalog_client_product_prices` records remain intact
- New pricing data goes to `core_product_prices`
- Use `catalog_to_sales_product_map` to correlate old product IDs

---

## 2. Database Constraints

### New Check Constraint
```sql
-- catalog_inventories: cannot set both variant_id AND sales_product_id
ALTER TABLE catalog_inventories ADD CONSTRAINT chk_single_product_ref 
    CHECK (NOT (variant_id IS NOT NULL AND sales_product_id IS NOT NULL));
```

### Schema Changes
- `catalog_inventories.variant_id`: Changed from `NOT NULL` → `NULLABLE`

---

## 3. Deprecated References

| Model/File | Change |
|-----------|--------|
| `Catalog\Products\Models\Product::clientPrices()` | Marked `@deprecated` — returns `ProductPrice` now |
| `Core\Client\Models\Client::clientProducts()` | Now points to `ProductPrice` via `company_id` |
| `ClientProductPrice` model | No longer used by services — left for backward compatibility |

---

## 4. Required Actions for Consumers

1. **API consumers**: No action required — response format is unchanged
2. **Direct model usage**: Replace `ClientProductPrice::class` with `Core\Products\Models\ProductPrice::class`
3. **Inventory queries**: Use `sales_product_id` instead of `variant_id` for new records
