# Boundaries — magento-orderwebhook

> **Last verified:** 2026-02-26 (Europe/London)
> **Owner:** Engineering
> **Related:** [architecture.md](architecture.md) | [INTEGRATIONS.md](INTEGRATIONS.md)

---

## Internal Components

| Component | Responsibility | Owns Writes | Notes |
|-----------|---------------|-------------|-------|
| `OrderPlaceAfter` observer | Listens to `sales_order_place_after`; triggers `order_placed` webhook for frontend orders | None — delegates to WebhookSender | Skips admin orders via `empty(getRemoteIp())` |
| `OrderSaveAfter` observer | Listens to `sales_order_save_after`; triggers `order_updated` webhook on status → `processing` | None — delegates to WebhookSender | Compares `getOrigData('status')` vs `getStatus()` |
| `WebhookSender` | Core service — builds and sends webhook, handles retry, persists NGauge response | `sales_order` (ngauge fields + comment, single save) | Re-entrancy guard; ObjectManager anti-pattern for `EncryptorInterface` |
| `OrderDataBuilder` | Builds JSON payload from order object | None | Includes DOB, gender, shipping fields |
| `ResendWebhook` controller | Admin UI entry point for manual resend | None — delegates to WebhookSender | ACL-protected; sends `manual_resend` event |
| `NgaugeFields` block | Renders NGauge data on admin order view | None | Uses deprecated `Magento\Framework\Registry` |
| `ngauge_fields.phtml` template | Displays sync status; shows/hides resend button | None | Hides button once `ngauge_order_id` is set |
| `TestWebhookCommand` | CLI command for test webhook send | None — delegates to WebhookSender | Masks config output |

---

## External Boundaries

| External System | Relationship | Direction | Mechanism | Notes |
|-----------------|-------------|-----------|-----------|-------|
| NGauge Platform | Webhook recipient | Outbound | HTTP POST, JSON, Bearer token | Target URL configurable in admin; default `https://ahshub.portalpeople.app` |
| Magento Sales Module (`Magento_Sales`) | Event source + order persistence | Inbound events + shared DB | `sales_order_place_after`, `sales_order_save_after` events; shared `sales_order` table | Module declares dependency in `module.xml` |
| Magento Encrypted Config | API key decryption | Internal | `EncryptorInterface` (via ObjectManager — anti-pattern) | Encrypted value stored in `core_config_data` |
| magento-deliverydates module | Shipping date/message data | Inbound (optional) | `getShippingDate()`, `getShippingMessage()` on order | Null if module absent — no hard dependency declared |

---

## Data Boundary — sales_order Table

This module **extends** the `sales_order` table by adding 3 nullable columns via `db_schema.xml`. It does not own the table.

| Column | Type | Owner | Notes |
|--------|------|-------|-------|
| `ngauge_order_no` | varchar(255) | This module | NGauge-assigned order number |
| `ngauge_order_id` | varchar(255) | This module | NGauge-assigned order ID; gates resend button visibility |
| `ngauge_order_link` | text | This module | Deep-link URL to order in NGauge |

Writes to these columns are performed exclusively by `WebhookSender::persistOrder()` via `orderRepository->save()`.

---

## Config Boundary

All module configuration lives under two config paths:

| Path | Scope | Notes |
|------|-------|-------|
| `order_webhook/general/enabled` | Default | Master on/off switch |
| `order_webhook/general/api_url` | Default | NGauge webhook URL |
| `order_webhook/general/api_key` | Default | Encrypted API key |
| `order_webhook/general/timeout` | Default | HTTP timeout (default: 30s) |
| `order_webhook/general/retry_attempts` | Default | Retry count (default: 3) |
| `order_webhook/general/log_enabled` | Default | Enable logging (default: 1) |
| `order_webhook/ngauge/base_url` | Default | NGauge base URL |
| `order_webhook/ngauge/comment_only` | Default | Skip DB writes; comment only (default: 0) |

---

## Gap Classifications

### CONFIGURATION GAP
- **What is missing:** `extra.bootstrap` in `composer.json` references `PortalPeople\\NgaugeBackupSql\\Module` — incorrect namespace for this module.
- **Where found:** `/modules/magento-orderwebhook/composer.json`
- **Minimum addition required:** Correct the bootstrap reference to `PortalPeople\\OrderWebhook\\Module` or remove it if not needed.

### BOUNDARY GAP
- **What is missing:** No hard module dependency declared for magento-deliverydates, yet `OrderDataBuilder` reads `shipping_date` and `shipping_message` from the order object. If these methods don't exist, a fatal error will occur.
- **Where found:** `/modules/magento-orderwebhook/src/Model/OrderDataBuilder.php`
- **Minimum addition required:** Confirm whether the calling code guards against method absence, or add a soft dependency in `module.xml`.

### OBSERVABILITY GAP
- **What is missing:** `WebhookSender::sendRequest()` uses `ObjectManager::getInstance()` to resolve `EncryptorInterface`, bypassing DI and making this path untestable.
- **Where found:** `/modules/magento-orderwebhook/src/Model/WebhookSender.php`
- **Minimum addition required:** Replace with constructor injection.

### SECURITY CLARITY GAP
- **What is missing:** Customer DOB and gender are transmitted to an external system (NGauge). There is no documented consent basis, data processor agreement reference, or GDPR notice for this transmission.
- **Where found:** `/modules/magento-orderwebhook/src/Model/OrderDataBuilder.php`
- **Minimum addition required:** Document the legal basis for transmitting DOB/gender to NGauge in `GDPR.md`.

### API CONTRACT GAP
- **What is missing:** NGauge API response schema is not documented. Field names inferred from code only.
- **Where found:** `/modules/magento-orderwebhook/src/Model/WebhookSender.php`
- **Minimum addition required:** Obtain and document the NGauge API contract in `API.md`.

---

## Confirmed Facts

- Module declares dependency on `Magento_Sales` in `module.xml`.
- No dependency on magento-deliverydates is declared despite reading from it.
- `WebhookSender` is the sole writer to `ngauge_*` columns.
- The re-entrancy guard prevents recursive save loops.

---

## Unknowns

1. `UNKNOWN — Requires Clarification`: Is `magento-deliverydates` guaranteed to be installed in all deployment environments?
2. `UNKNOWN — Requires Clarification`: Does `OrderDataBuilder` guard against missing `getShippingDate()`/`getShippingMessage()` methods?
3. `UNKNOWN — Requires Clarification`: What is the correct `extra.bootstrap` value for this module?

---

## Evidence

- `/modules/magento-orderwebhook/src/etc/module.xml`
- `/modules/magento-orderwebhook/src/etc/db_schema.xml`
- `/modules/magento-orderwebhook/src/etc/config.xml`
- `/modules/magento-orderwebhook/src/etc/adminhtml/system.xml`
- `/modules/magento-orderwebhook/src/Model/WebhookSender.php`
- `/modules/magento-orderwebhook/src/Model/OrderDataBuilder.php`
- `/modules/magento-orderwebhook/composer.json`
