# P4L Diagnostic Tool

A Next.js application for diagnosing device hardware and generating health certificates.

## Features

- Device hardware scanning (cameras, battery, refresh rate, etc.)
- Hardware verification tests (audio, orientation, flashlight, touch, etc.)
- IMEI verification with OCR
- Health certificate generation and PDF export

## Tech Stack

- Next.js 15
- React 19
- TypeScript
- Tailwind CSS
- html2canvas & jsPDF for PDF generation
- Tesseract.js for OCR

## Getting Started

1. Install dependencies:

   ```bash
   npm install
   ```

2. Run the development server:

   ```bash
   npm run dev
   ```

3. Open [http://localhost:3000](http://localhost:3000) in your browser.

## Project Structure

- `app/` - Next.js app router pages and layouts
- `components/` - Reusable React components
- `public/` - Static assets
- `tailwind.config.js` - Tailwind CSS configuration
- `postcss.config.js` - PostCSS configuration

## Scripts

- `npm run dev` - Start development server
- `npm run build` - Build for production
- `npm run start` - Start production server
- `npm run lint` - Run ESLint

## Device Test URL API

`POST /test/generate-link/` creates a partner diagnostic URL. The endpoint
accepts the `Partner-Code` header without validating it and requires an HS256
JWT in the `Authorization` header. The raw JWT format is supported, matching
the partner contract; a `Bearer` prefix is also accepted. Tokens must include
a numeric `exp` claim.

Request:

```http
POST /test/generate-link/ HTTP/1.1
Content-Type: application/json
Partner-Code: 2001
Authorization: <jwt>

{
  "data": {
    "imei": "908207559145326",
    "partner_name": "etisalat"
  }
}
```

Response:

```json
{
  "status": "success",
  "code": 200,
  "message": "Request successful",
  "data": {
    "url": "https://p4l.diagnostic/devicetest/etisalat?imei=908207559145326"
  }
}
```

The sender must sign the JWT with HS256 using the shared secret declared as
`DEVICE_URL_JWT_SECRET` in `lib/device-url-auth.ts`. The secret is hardcoded as
requested; replace it in both systems before deployment and keep it private.
For compatibility, the endpoint is also available at
`POST /api/device-test-url`.

Generated test URLs include a signed `context_token` containing the IMEI,
partner, redirect URL, and expiry. That token is the free fallback that lets the
flow work on Vercel, serverless, and other environments without paid storage.

When local file storage is writable, the app also persists generated URL
context by `partner_name + imei` and marks that context completed after
`/api/diagnostic-status` returns `200`. This helps during local or single-server
testing. In serverless environments where the file is not writable, the signed
token still validates the URL and expires after 30 minutes, but the same link
can be reused from another browser or device until expiry unless the upstream
backend rejects duplicate submissions. After a successful submit, the frontend
also marks the link completed in browser storage and blocks reuse from the same
browser/device.

Storage is selected in this order:

1. Local file storage with `device-url-context.json`, when the filesystem is
writable.
2. Signed-token fallback, when no writable storage is available.

## Diagnostic Status API

`POST /api/diagnostic-status` submits the completed diagnostic result to the
Protect4Less backend. The browser calls this local endpoint; the Next.js server
adds the backend `Partner-Code` and HS256 `Authorization` token before forwarding
the request. This avoids browser CORS failures and keeps the signing secret out
of the client bundle.

Request:

```http
POST /api/diagnostic-status HTTP/1.1
Content-Type: application/json

{
  "data": {
    "imei": "908207559145326",
    "partner_name": "etisalat",
    "result": {
      "DeviceID": "908207559145326",
      "IMEI": "908207559145326",
      "DiagnosticTests": {}
    }
  }
}
```

Success response:

```json
{
  "status": "success",
  "code": 200,
  "message": "Result Saved Successfully",
  "data": {
    "endpoint": "https://dev.protect4less.com/api/p4l/diagnostics/test-result/",
    "upstream": {}
  }
}
```

Failure responses include the upstream status/body when the backend rejects the
payload, or a gateway-style error when the backend cannot be reached. Configure
the server-side values with `STATUS_ENDPOINT`, `STATUS_PARTNER_CODE`, and
`STATUS_JWT_SECRET`.
