# Design Specification: Epic 5 (Sync Control Panel & DLQ UI)

**Assignee Focus:** Frontend Developer (React / Blade)
**Prerequisites:** Epic 1 (`field_metadata` table defined)

---

## 1. Business Justification & Problem Statement

Our multi-tenant architecture allows clients to create custom fields in NetSuite (e.g., `custentity_supplier`). The sync engine requires strict mapping instructions to handle these. Additionally, when a payload violates the Epic 1 contracts, the Orchestrator routes it to a Dead Letter Queue (DLQ). Without a User Interface, support teams and tenant admins have no way to map their custom fields or resolve failed sync events.

## 2. Proposed Architectural Solution

We will build two distinct configuration interfaces within the SuiteX application. The first is a **Custom Field Mapper**, allowing users to map NetSuite field IDs to SuiteX fields, which will write to the `field_metadata` table. The second is a **Dead Letter Queue Dashboard**, providing a table view of failed sync events with actionable resolution buttons (Retry/Dismiss).

## 3. Functional Requirements

| # | Requirement | Details |
|---|---|---|
| A | **Custom Field Mapper UI** | A configuration view where a user can define: NetSuite Field ID (e.g., `custentity_supplier`), Data Type (String, Boolean, Date, etc.), and Conflict Policy (NetSuite Wins, SuiteX Wins, Manual). |
| B | **DLQ Dashboard** | A data table view displaying failed events. Columns must include: `Timestamp`, `Record Type`, `Record ID`, and `Error Reason`. |
| C | **DLQ Detail Modal** | Clicking a failed event opens a modal displaying the raw Canonical JSON payload and the exact schema validation error that caused the failure. |
| D | **Action Triggers** | "Retry Sync" and "Dismiss" buttons on DLQ rows, calling mocked backend API endpoints for now. |

## 4. Architectural Boundaries & Technical Constraints

- **Tenant Isolation:** All API requests are scoped to the current tenant via the authenticated session. Tenant context is resolved server-side via `TenantService::getCurrentTenantId()` — no client-side `account_id` is passed in request bodies or query params.
- **Mocked Backend:** Because the Orchestrator (Epic 7) isn't built yet, the backend team will stub Laravel API routes returning static JSON responses. The frontend developer builds against those contracts.
- **Frontend Stack:** All new UI components use Blade + React. Livewire is not used for new work. The Custom Field Mapper is a React component embedded in a Blade page. The DLQ Dashboard is also React, consistent with the `Table` and `EnhancedImport` patterns.

## 5. Testable Acceptance Criteria

### Scenario 1 — Field Mapping Entry

> **Given** a tenant admin accesses the Sync Settings page
> **When** they add a new custom field mapping for `Project`
> **Then** the UI validates the form and submits a correctly formatted JSON payload (matching the `field_metadata` schema) to the mock save endpoint, receiving a `201 Created` response.

### Scenario 2 — DLQ Inspection

> **Given** a mocked list of failed events in the DLQ
> **When** a user clicks a specific failed Project event
> **Then** a modal opens displaying the raw JSON payload with syntax highlighting and the error reason prominently labelled (e.g., "Invalid ISO8601 Date").

## 6. Deliverables

1. **Custom Field Mapper Component:** Blade page hosting a React component for adding/editing tenant-specific `field_metadata` configurations.
2. **DLQ Data Table Component:** React component for viewing and filtering failed sync events.
3. **Event Inspector Modal:** A read-only, syntax-highlighted JSON viewer for diagnosing schema failures.
4. **Mock API Integration:** Frontend wired to consume mocked data structures representing the `field_metadata` table and DLQ states.
