# Epic 3: NetSuite Mock Server — Jira Ticket

## Business Justification & Problem Statement

We cannot develop the SuiteX Orchestrator or the Sync Workers against the live NetSuite API because we will instantly exhaust our production/sandbox governance limits, blocking other business operations. Furthermore, we cannot easily force NetSuite to throw specific network errors (like **429 Too Many Requests** or **503 Service Unavailable**) to properly test our sync engine's adaptive throttling and retry queues.

## Proposed Solution

We will build a **standalone Node.js (NestJS) Mock Server** that mimics the NetSuite RESTlet endpoints exactly. For this MVP, it will strictly support the **Project** and **Project Task** domains. It will be deployed as a serverless container on **Google Cloud Run** and utilize a persistent **Cloud SQL (MySQL 8.*)** database to maintain state. This ensures the mock environment remains available for the SuiteX poller without losing data during container scale-to-zero events, while providing middleware to artificially simulate NetSuite's latency and governance throttling.

## Technical Requirements

### Architecture & Infrastructure

- **Framework:** NestJS (TypeScript).
- **Hosting:** Google Cloud Run (stateless container, scaling to zero when idle to minimize costs).
- **Database:** Cloud SQL (MySQL 8.*) using TypeORM or Prisma. Define a **MockRecord** entity holding `recordType`, `internalId`, `lastModifiedDate`, `payload` (JSON), and `writeId`.

### The RESTlet Endpoints (Ingress & Egress)

**Write Endpoint** (`POST /mock-netsuite/restlet/:recordType`):

- Validate incoming payloads against the Epic 1 Canonical JSON schemas.
- Verify idempotency using the SuiteX `writeId`.
- Auto-generate a simulated `internalId` and `lastModifiedDate` upon save.

**Search Endpoint** (`POST /mock-netsuite/search/:recordType`):

- Accept cursor payloads: `{ "lastModifiedDate": "ISO8601", "lastInternalId": "string" }`.
- Return up to **1,000** mocked records sorted by `lastModifiedDate` ASC, `internalId` ASC.

### The Chaos Interceptor (Governance Simulation)

Implement a global NestJS Interceptor with configurable environment variables:

- **Latency:** Inject a random delay (e.g., 200ms–2500ms).
- **Concurrency Throttling:** Track active requests. If active requests > threshold (e.g., 5), immediately reject the request with a **429 Too Many Requests** status.

## Acceptance Criteria (Definition of Done)

### Scenario 1: State Storage & Simulated Ingestion

- **Given** SuiteX initiates an outbound write containing a valid Canonical JSON payload for a Project or Project Task.
- **When** the payload is received by the mock inbound RESTlet endpoint.
- **Then** the Mock Server validates the payload, persists it to the persistent Cloud SQL database, auto-generates a simulated `internalId` and `lastModifiedDate`, and returns a **200 OK** success response with the new ID.

### Scenario 2: Governance Exhaustion (Throttling Simulation)

- **Given** the Mock Server's Chaos Interceptor is configured with a simulated concurrency limit (e.g., 5 active requests).
- **When** SuiteX attempts to execute a batch of concurrent POST requests that exceeds this threshold (e.g., 15 requests).
- **Then** the Mock Server successfully processes the requests up to the limit and explicitly rejects the remainder with a **429 Too Many Requests** HTTP status code, allowing SuiteX to test its adaptive backoff logic.

### Scenario 3: Polling Discovery (Cursor Pagination)

- **Given** the Cloud SQL database is populated with mocked Project records.
- **When** the SuiteX poller queries the mock search endpoint using a cursor (`lastModifiedDate` + `lastInternalId`).
- **Then** the Mock Server returns a paginated list of up to 1,000 records sorted chronologically, accurately simulating NetSuite's `Search.runPaged()` governance limits.

## Deliverables

| Deliverable | Description |
|-------------|-------------|
| **Cloud Run Deployment** | A containerized NestJS application deployed to Google Cloud Run. |
| **Cloud SQL Persistence** | A MySQL 8.* database instance provisioned on Cloud SQL, connected securely via Cloud Run VPC Serverless Access. |
| **Mock RESTlet Endpoint (Write)** | Fully functional POST endpoint enforcing Epic 1 schemas and checking idempotency. |
| **Mock Search Endpoint (Read)** | Fully functional POST endpoint accepting cursor queries and returning paginated results. |
| **The Chaos Interceptor** | Configurable middleware reliably injecting latency and generating 429 errors when limits are breached. |
