```yaml
id: UJ-008
title: Activate a license
actors: [administrator]
surface: admin-spa
goal: Administrator activates one valid license for this site and fresh state shows its entitlement.
trigger: Enter key and activate Activate License at /wp-admin/admin.php?page=international-press-zone#/licensing.
fixtures: [authenticated-admin, live-unused-license-key]
success_state:
  visible: "License activated successfully!" renders with plan and masked key.
  durable: ipz_license_key and ipz_license_data contain activated entitlement.
  persistence: Fresh GET /wp-json/international-press-zone/v1/license returns active entitlement.
source_specs: [admin/src/pages/licensing.js, includes/API/LicenseRestController.php]
readiness: draft
canonical: false
blockers: []
```

## Path

| Hop | Evidence |
|---|---|
| UI trigger | `admin/src/pages/licensing.js:360` |
| Request construction | `admin/src/pages/licensing.js:751` |
| Endpoint auth and parse | `includes/API/LicenseRestController.php:83` |
| Authoritative write | `includes/API/LicenseRestController.php:194` |
| Response | `includes/API/LicenseRestController.php:205` |
| Terminal render | `admin/src/pages/licensing.js:754` |

## Happy path

### H1
- Setup: Administrator authenticated; plugin inactive; live unused `INTL-XXXX-XXXX-XXXX` key exists.
- Action: Enter key and activate `Activate License`.
- Request: `POST /wp-json/international-press-zone/v1/license/activate`.
- Response: `200` with `{success:true,message:"License activated successfully.",license:<exact-entitlement>}`.
- Visible: `License activated successfully!` renders; license card shows plan, status, limits, expiry, and masked key.
- Durable: `ipz_license_key` equals submitted key and `ipz_license_data` equals returned entitlement projection.
- Fresh read: `GET /wp-json/international-press-zone/v1/license` returns `200` with active exact entitlement.
- Forbidden: No second activation, charge, language, content, or translation write occurs.
- Evidence:
  - Setup: `includes/API/LicenseRestController.php:175`
  - Action: `admin/src/pages/licensing.js:360`
  - Request: `admin/src/pages/licensing.js:751`
  - Response: `includes/API/LicenseRestController.php:205`
  - Visible: `admin/src/pages/licensing.js:754`
  - Durable: `includes/API/LicenseRestController.php:194`
  - Fresh read: `includes/API/LicenseRestController.php:123`
  - Forbidden: `includes/API/LicenseRestController.php:194`

## Alternate and failure paths

### A1
- Setup: Administrator authenticated; license key input has invalid format.
- Action: Enter invalid key and activate `Activate License`.
- Request: N/A — client validation rejects before transport.
- Response: N/A — no HTTP request is produced.
- Visible: `Invalid license key format. Please use INTL-XXXX-XXXX-XXXX` renders; activation form remains.
- Durable: `ipz_license_key` and `ipz_license_data` remain unchanged.
- Fresh read: `GET /wp-json/international-press-zone/v1/license` returns `200` with prior inactive state.
- Forbidden: No activation request, entitlement write, or external API call occurs.
- Evidence:
  - Setup: `admin/src/pages/licensing.js:743`
  - Action: `admin/src/pages/licensing.js:360`
  - Request: `admin/src/pages/licensing.js:745`
  - Response: `admin/src/pages/licensing.js:745`
  - Visible: `admin/src/pages/licensing.js:745`
  - Durable: `admin/src/pages/licensing.js:745`
  - Fresh read: `includes/API/LicenseRestController.php:123`
  - Forbidden: `admin/src/pages/licensing.js:745`

## Permissions and boundaries

### P1
- Setup: Actor lacks `manage_options`; valid unused license key exists.
- Action: Submit activation request.
- Request: `POST /wp-json/international-press-zone/v1/license/activate`.
- Response: `403` with `{code:"rest_forbidden",message:"You do not have permission to manage licenses.",data:{status:403}}`.
- Visible: REST denial exposes no key or entitlement.
- Durable: License options remain unchanged.
- Fresh read: Protected license GET returns the same `403` denial.
- Forbidden: No external activation call or option write occurs; key is not disclosed.
- Evidence:
  - Setup: `includes/API/LicenseRestController.php:286`
  - Action: `includes/API/LicenseRestController.php:87`
  - Request: `includes/API/LicenseRestController.php:83`
  - Response: `includes/API/LicenseRestController.php:287`
  - Visible: `includes/API/LicenseRestController.php:287`
  - Durable: `includes/API/LicenseRestController.php:286`
  - Fresh read: `includes/API/LicenseRestController.php:51`
  - Forbidden: `includes/API/LicenseRestController.php:286`

## Source specs

- `admin/src/pages/licensing.js`
- `includes/API/LicenseRestController.php`
