# Epic 8: Field Mapper & DLQ Dashboard — Design Spec

## 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:

1. **Custom Field Mapper** — allowing users to map NetSuite field IDs to SuiteX fields, which will write to the **field_metadata** table.
2. **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

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