# ORAC Risk API — Postman reference (full paths & bodies)

**Base URL:** `http://localhost:3000` (replace port if your `APP_PORT` differs).

**Headers (all protected routes):**

| Header              | Value                    |
|---------------------|--------------------------|
| `Content-Type`      | `application/json`       |
| `Authorization`     | `Bearer <jwt_token>`     |

**Public (no JWT):**

- `GET /api/health` — no body  
- `POST /api/auth/login` — JSON body below  

**JWT-protected routes** live under **`/api/orac/...`** (see `src/routes/index.js`).

**Access:**

- **`requireAuth`** — user / executor / verifier JWT (any valid app token per `authMiddleware`).
- **`requireAdmin`** — admin JWT only: `account_status`, `country`, `job_title`, `roles`, `user_role`, `users`, `users_logs`.

---

## 1. Login (public)

**POST** `/api/auth/login`

```json
{
  "email": "user@example.com",
  "password": "your_password"
}
```

---

## 2. Health (public)

**GET** `/api/health`  
No body.

---

## 3. Admin-only CRUD (`requireAdmin`)

Prefix each path with **`/api/orac`**.

### 3.1 `account_status` — PK: `status_id`

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/account_status` | — |
| GET | `/api/orac/account_status/:status_id` | — |
| POST | `/api/orac/account_status` | `{ "status_name": "Active" }` (use actual DB columns) |
| PUT | `/api/orac/account_status/:status_id` | `{ "status_name": "Inactive" }` |
| DELETE | `/api/orac/account_status/:status_id` | — |

### 3.2 `country` — PK: `country_id`

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/country` | — |
| GET | `/api/orac/country?country_name_like=Ind` | — |
| POST | `/api/orac/country` | `{ "country_name": "India" }` |
| PUT | `/api/orac/country/:country_id` | partial columns |
| DELETE | `/api/orac/country/:country_id` | — |

### 3.3 `job_title` — PK: `job_title_id`

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/job_title` | — |
| POST | `/api/orac/job_title` | `{ "job_title_name": "Safety Officer" }` |
| PUT | `/api/orac/job_title/:job_title_id` | partial |
| DELETE | `/api/orac/job_title/:job_title_id` | — |

### 3.4 `roles` — PK: `role_id`

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/roles` | — |
| POST | `/api/orac/roles` | `{ "role_name": "User" }` |
| PUT | `/api/orac/roles/:role_id` | partial |
| DELETE | `/api/orac/roles/:role_id` | — |

### 3.5 `user_role` — PK: `user_role_id`, `role_id`, `user_id`

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/user_role` | — |
| GET | `/api/orac/user_role/:user_role_id/:role_id/:user_id` | — |
| POST | `/api/orac/user_role` | `{ "user_role_id": 1, "role_id": 2, "user_id": 10 }` |
| PUT | `/api/orac/user_role/:user_role_id/:role_id/:user_id` | partial |
| DELETE | `/api/orac/user_role/:user_role_id/:role_id/:user_id` | — |

### 3.6 `users` — composite PK: `user_id`, `employee_id`, `status_id`, `job_title_id`, `department_id`, `location_id`

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/users` | — |
| GET | `/api/orac/users?department_id=3&status_id=1` | — |
| POST | `/api/orac/users` | See example below |
| GET | `/api/orac/users/:user_id/:employee_id/:status_id/:job_title_id/:department_id/:location_id` | — |
| PUT | `/api/orac/users/:user_id/:employee_id/:status_id/:job_title_id/:department_id/:location_id` | partial |
| DELETE | `/api/orac/users/:user_id/:employee_id/:status_id/:job_title_id/:department_id/:location_id` | — |

**POST `/api/orac/users` example:**

```json
{
  "user_id": 1,
  "employee_id": "E1001",
  "status_id": 1,
  "job_title_id": 2,
  "department_id": 3,
  "location_id": 4,
  "employee_name": "John Doe",
  "email_id": "john@example.com",
  "phonenumber": "1234567890"
}
```

### 3.7 `users_logs` — PK: `user_id`

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/users_logs` | — |
| POST | `/api/orac/users_logs` | JSON with valid columns + `user_id` |
| PUT | `/api/orac/users_logs/:user_id` | partial |
| DELETE | `/api/orac/users_logs/:user_id` | — |

---

## 4. Shared lookup (`requireAuth`)

### 4.1 `locations` — PK: `location_id`

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/locations` | — |
| GET | `/api/orac/locations?country_id=1` | — |
| POST | `/api/orac/locations` | table columns |
| PUT | `/api/orac/locations/:location_id` | partial |
| DELETE | `/api/orac/locations/:location_id` | — |

### 4.2 `lookup` (countries)

**GET** `/api/orac/lookup/countries` — no body.

### 4.3 `departments` — PK: `department_id`

Standard CRUD under `/api/orac/departments` (same pattern as `locations`).

### 4.4 `location_departments` — PK: `department_id`, `location_id`

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/location_departments` | — |
| POST | `/api/orac/location_departments` | `{ "department_id": 1, "location_id": 2 }` |
| GET | `/api/orac/location_departments/:department_id/:location_id` | — |
| PUT | `/api/orac/location_departments/:department_id/:location_id` | partial |
| DELETE | `/api/orac/location_departments/:department_id/:location_id` | — |

---

## 5. RPN master (`requireAuth`)

**GET** — no body.

- `/api/orac/rpn/likelihood`
- `/api/orac/rpn/severity`

**POST** `/api/orac/rpn/likelihood`

```json
{
  "likelihood_of_harm": "Rare",
  "value": 1
}
```

**PUT** `/api/orac/rpn/likelihood`

```json
{
  "likelihood_of_harm": "Rare",
  "value": 2
}
```

**DELETE** `/api/orac/rpn/likelihood/:likelihood_of_harm` — path param (URL-encode if needed); no body.

**POST** `/api/orac/rpn/severity`

```json
{
  "severity_of_harm": "Negligible",
  "value": 1
}
```

**PUT** `/api/orac/rpn/severity`

```json
{
  "severity_of_harm": "Negligible",
  "value": 2
}
```

**DELETE** `/api/orac/rpn/severity/:severity_of_harm` — no body.

---

## 6. ORAC assessments & workflow (`requireAuth`)

Base resource: `/api/orac/orac_assessments`  
Composite PK for generic CRUD: `assessment_id`, `uploader_user_id`, `assessment_status_id`.

### 6.1 List / filters (GET)

- `GET /api/orac/orac_assessments`
- `GET /api/orac/orac_assessments?country_id=1&location_id=4`
- `GET /api/orac/orac_assessments?assessment_status_id=2`
- `GET /api/orac/orac_assessments?assign_role=executor` (executor JWT)
- `GET /api/orac/orac_assessments?assign_role=verifier` (verifier JWT)
- `GET /api/orac/orac_assessments/user/:user_id/grouped_by_status`

### 6.2 Upload video (multipart — not JSON)

**POST** `/api/orac/orac_assessments/upload`

| Type        | Key / field |
|------------|-------------|
| Header     | `Authorization: Bearer <token>` |
| Body type  | **form-data** |
| File       | field name **`video`** (binary file) |
| Text fields | `uploader_user_id`, `location_id`, `department_id`, `contact_details`, `video_title`, `video_capture_date`, `video_capture_time`, `country_id`, `remarks` |

Example form fields (values are strings):

```
uploader_user_id: 10
location_id: 4
department_id: 2
video_title: Site walkthrough
```

### 6.3 Assignment & workflow (POST JSON)

**POST** `/api/orac/orac_assessments/:assessment_id/assign_executor`

```json
{
  "executor_id": 5,
  "form_id": 12
}
```

(`form_id` optional.)

**POST** `/api/orac/orac_assessments/:assessment_id/assign_verifier`

```json
{
  "verifier_id": 7,
  "form_id": 12
}
```

**POST** `/api/orac/orac_assessments/:assessment_id/assign_form`

```json
{
  "form_id": 12
}
```

**POST** `/api/orac/orac_assessments/:assessment_id/executor_submit_for_verification`

```json
{}
```

**POST** `/api/orac/orac_assessments/:assessment_id/verifier_complete`

```json
{}
```

**POST** `/api/orac/orac_assessments/:assessment_id/verifier_return`

```json
{
  "returned_for": "Please add more detail on hazard X."
}
```

### 6.4 Generic CRUD (same table)

| Method | Path | Body |
|--------|------|------|
| POST | `/api/orac/orac_assessments` | all PK columns + optional fields as per DB |
| PUT | `/api/orac/orac_assessments/:assessment_id/:uploader_user_id/:assessment_status_id` | partial |
| DELETE | `/api/orac/orac_assessments/:assessment_id/:uploader_user_id/:assessment_status_id` | — |
| GET | `/api/orac/orac_assessments/:assessment_id/:uploader_user_id/:assessment_status_id` | — |

---

## 7. ORAC assessment status (`requireAuth`)

`PK: assessment_status_id`

`/api/orac/orac_assessments_status` — GET/POST/PUT/DELETE same CRUD pattern; POST body = valid columns.

---

## 8. ORAC participants (`requireAuth`)

`PK: assessment_id`, `participant_user_id`

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/orac_participants` | — |
| GET | `/api/orac/orac_participants?assessment_id=101` | — |
| POST | `/api/orac/orac_participants` | `{ "assessment_id": 101, "participant_user_id": 8 }` |
| PUT | `/api/orac/orac_participants/:assessment_id/:participant_user_id` | partial |
| DELETE | `/api/orac/orac_participants/:assessment_id/:participant_user_id` | — |

---

## 9. ORAC form & section maps (`requireAuth`)

### 9.1 `orac_form_section_map` — PK: `form_id`, `section_id`

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/orac_form_section_map` | — |
| GET | `/api/orac/orac_form_section_map/default-form-id` | — |
| GET | `/api/orac/orac_form_section_map/by-location/:location_id` | — |
| GET | `/api/orac/orac_form_section_map/form/:form_id` | — |
| POST | `/api/orac/orac_form_section_map` | `{ "form_id": 1, "section_id": 2 }` |
| GET | `/api/orac/orac_form_section_map/:form_id/:section_id` | — |
| PUT | `/api/orac/orac_form_section_map/:form_id/:section_id` | partial |
| DELETE | `/api/orac/orac_form_section_map/:form_id/:section_id` | — |

### 9.2 `orac_section_question_map` — PK: `section_id`, `question_id`

Also mounted under typo alias: **`/api/orac/orac_section_question_map`** (same routes).

| Method | Path | Body |
|--------|------|------|
| GET | `/api/orac/orac_section_question_map` | — |
| GET | `/api/orac/orac_section_question_map/section/:section_id` | — |
| POST | `/api/orac/orac_section_question_map` | `{ "section_id": 1, "question_id": 5 }` |
| PUT | `/api/orac/orac_section_question_map/:section_id/:question_id` | partial |
| DELETE | `/api/orac/orac_section_question_map/:section_id/:question_id` | — |

---

## 10. ORAC form & section entities (`requireAuth`)

Resources (each CRUD under `/api/orac/<table_name>` with PK as in DB):

- `orac_form_details` — PK `form_id`  
  - **POST** `/api/orac/orac_form_details/:form_id/fork` — optional body: `{ "created_by": 10 }` (or omit; uses JWT / parent)
- `orac_archive_form` — PK `form_id`
- `orac_form_logs` — PK `user_id`
- `orac_section_details` — PK `section_id`
- `orac_archive_section` — PK `section_id`
- `orac_section_logs` — PK `user_id`
- `orac_location_forms_details` — PK `form_id`, `location_id`
- `orac_combined_question` — PK `main_question_id`, `child_question_id`
- `orac_question_type` — PK `question_type_id`
- `orac_question_options` — PK `question_options_id`, `question_id`

**`orac_questions`** — custom list + CRUD; PK `question_id`, `question_type_id`  
- `GET /api/orac/orac_questions` (enriched list)  
- Other verbs as per CRUD on same path pattern.

---

## 11. ORAC submissions & answers (`requireAuth`)

### 11.1 Create submission (custom — **POST** `/api/orac/orac_submissions`)

```json
{
  "assessment_id": 101,
  "snap_id": 3,
  "form_id": 12,
  "answers": [
    {
      "question_id": 55,
      "answer_value": "Yes"
    },
    {
      "question_id": 56,
      "answer_value": "3",
      "is_media": false
    }
  ]
}
```

- `form_id` optional (inferred from questions if omitted).  
- `submitter_id` comes from JWT.  
- Each answer needs valid `question_id` and either `answer_value` or `is_media`.

### 11.2 Generic CRUD on `orac_submissions`

`PK: submission_id`, `assessment_id`, `submitter_id`, `snap_id`

Paths under `/api/orac/orac_submissions/...`

### 11.3 `orac_answers` — PK: `answers_id`, `submission_id`, `question_id`

`/api/orac/orac_answers` — standard CRUD.

---

## 12. ORAC snaps (`requireAuth`)

Base: `/api/orac/orac_snaps`  
`PK: snap_id`, `assessment_id`

**POST** `/api/orac/orac_snaps/` — JSON; must include `assessment_id`; `snap` = base64 image (optional data URL prefix stripped server-side); `snap_timing` = JSON string metadata.

```json
{
  "assessment_id": 101,
  "snap": "<base64 JPEG/PNG without data URL prefix or with data:image/...;base64,>",
  "snap_timing": "{\"risk_violation_time\":\"2025-01-01T12:00:00Z\",\"marks\":[]}"
}
```

**PUT** `/api/orac/orac_snaps/:snap_id/:assessment_id` — partial JSON (e.g. `{ "snap_timing": "..." }`).

**GET** `/api/orac/orac_snaps/:snap_id/:assessment_id/image` — returns **raw image bytes** (not JSON).

**DELETE** `/api/orac/orac_snaps/:snap_id/:assessment_id` — no body.

---

## 13. ORAC verification flow (`requireAuth`)

`PK: assessment_id`, `occurrence` (check DB for exact PK)

`/api/orac/orac_verification_flow` — standard CRUD; POST body = valid columns.

---

## 14. Tickets (`requireAuth`)

### 14.1 `tickets_status` — PK: `status_id`

`/api/orac/tickets_status`

### 14.2 `tickets_type` — PK: `type_id`

`/api/orac/tickets_type`

### 14.3 `tickets` — PK: `id`, `user_id`, `ticket_type_id`, `status_id`

`/api/orac/tickets`

### 14.4 `tickets_logs` — PK: `id`, `ticket_id`, `status_id`, `ticket_type_id`

`/api/orac/tickets_logs`

---

## 15. List / filter helpers (generic CRUD)

For **GET** list endpoints, query params:

- Exact: `?column=value`
- LIKE: `?column_like=value`

---

## Postman collection tips

1. Create variable **`baseUrl`** = `http://localhost:3000`.
2. After login, save **`token`** from JSON; set collection auth to **Bearer Token** = `{{token}}`.
3. For protected calls use full path: `{{baseUrl}}/api/orac/...`.
4. Import this file as reference or copy requests manually; for **upload**, use **form-data** with key `video` (type: File).

---

*Generated from `src/routes/*` and controllers. Table columns must match your MySQL schema (`migrations/`, `Dump*.sql`).*
