# Checking the dynamic audit report with Postman

This guide walks one audit through the whole flow: create the report from the CRM, fill it in, submit, approve, and download the PDF. All steps are in the Postman collection `DynamicAuditReport.postman_collection.json` (File > Import). Run the folders in order.

## 1. Before you start

1. Run `migrations/001_create_audit_report_tables.sql` on scheme_dbs and restart the backend with `AuditReportBuilderModule` added to `AppModule`.
2. Pick an audit that exists in `audit_schedule_rows`. Check that the logged-in auditor is its lead auditor or a co-auditor:
   ```sql
   SELECT r.id, r.audit_code, r.audit_type, r.audit_stage, r.lead_auditor_id, r.company_id, GROUP_CONCAT(rs.standard_id) AS standards
   FROM audit_schedule_rows r LEFT JOIN audit_schedule_row_standards rs ON rs.row_id = r.id
   WHERE r.id = 545 GROUP BY r.id;
   ```
3. You need two logins:
   - **Auditor**: the lead auditor of that audit (or a co-auditor, or whoever creates the report).
   - **Scheme approver**: a user with the role `scheme` whose `primary_scheme` equals the company's scheme (QRS or TQS), or an admin / super-admin. A scheme user of the other scheme gets 403.
4. In the collection, open **Variables** and set `base_url` (for example `http://localhost:3000`), `auditor_email`, `scheme_email`, `password`, `row_id` and `standard_id`.
   The default `row_id` 545 / `standard_id` 4 is a Stage 1 audit for ISO 9001:2015 in your dump. Use your own row if you prefer.
   All URLs have the `/api` prefix (your `main.ts` sets it).

## 2. Run the steps

| # | Request | Who | What you should see |
|---|---|---|---|
| 0a | Login as AUDITOR | | 200/201 with `access_token`. The test script stores it. |
| 0b | Login as SCHEME approver | | Same, stored as `scheme_token`. |
| 1 | Seed ISO 9001 clause library | scheme | `{ "inserted": 64, "skipped": 0 }` the first time (18 readiness rows + 30 clauses + 16 effectiveness rows). Run once per standard. An auditor gets 403. |
| 2a | Audit context | auditor | `suggested_stage_type` (`stage1` for audit 545) and the list of booked standards (4, 5, 6). Use one of those ids as `standard_id`. |
| 2b | Create report | auditor | 201. `report_no` like `S1-2026-000001`, `status: draft`, 18 clause rows for Stage 1 (46 for Surveillance / Stage 2 / Recert). `report_id` is stored. |
| 2c | Open editor model | auditor | `fields` already holds company name, address, certificate number, scope, accreditation, lead auditor, audit date. `attendance` is filled from the audit request. |
| 3a | Header | auditor | 200. Employees, man-days, conclusion, ticked declarations. |
| 3b | Save ALL clause rows | auditor | `{ "ok": true, "saved": 18 }`. All rows set to C with an evidence line. |
| 3c | Save ONE clause as NC | auditor | 200. |
| 3d | Raise NC from that clause | auditor | `nc_id`. A second call returns 409. |
| 3e | Text section | auditor | 200. |
| 3f | Attendance | auditor | `{ "count": 2 }`. |
| 4a | HTML preview | auditor | The full report as a web page, with a red DRAFT watermark. Use the Preview tab in Postman, or paste the URL with the token in a browser extension that adds the header. |
| 4b | PDF | auditor | Use **Send and Download**. Draft PDF with watermark. |
| 5a | Submit | auditor | 201, `status: submitted`. If something is missing you get 400 with a `problems` list (for example "1 checkpoint(s) have no status"). After this the auditor can no longer edit (409). |
| 5b | Return (optional) | scheme | `status: returned`. The auditor edits again and submits again. |
| 5c | APPROVE | scheme | `status: approved`, `pdf_path` like `new:stage1/545/<timestamp>_S1-2026-000001-v1.pdf`, `audit_row_column: stg1_audit_report`. |
| 5d | Download FINAL PDF | auditor | PDF without the DRAFT watermark. |
| 5e | Tracker view | auditor | `by-audit/545` shows `approved` and `has_pdf: true`. |
| 5f | Reopen (optional) | scheme | `status: returned`, `version: 2`. The old PDF stays on disk. |

## 3. Check the result in the database and on disk

```sql
-- the report and its frozen data
SELECT id, report_no, stage_type, status, version, pdf_path, approved_by, approved_at FROM audit_reports WHERE audit_schedule_row_id = 545;

-- the audit row now points at the generated PDF and is QAQC approved
SELECT stg1_audit_report, stg2_audit_report, report_qaqc_approved, report_qaqc_approved_by FROM audit_schedule_rows WHERE id = 545;

-- the NC created from the clause
SELECT e.id, e.nc_type, e.criteria_clause, e.ncr_statement FROM ncr_entries e JOIN nc__ncs n ON n.id = e.nc_id WHERE n.audit_id = 545;

-- every approved version
SELECT version, pdf_path, generated_at FROM audit_report_versions WHERE report_id = <report_id>;
```
The PDF file is in the same folder tree the report tracker already uses: `<AUDIT_REPORT_ROOT>/stage1/545/<timestamp>_S1-...-v1.pdf` (Stage 2, Surveillance and Recertification reports go under `stage2/`).

Proof that an approved report is frozen: after approval change the company address in `companies`, then call **Download FINAL PDF** again. The PDF still shows the old address. A draft would show the new one after **Refresh**.

## 4. Things to try on purpose

- Create the report again with the same row and standard: you get the same report back, not a second one.
- Create with a standard that is not booked on the audit (for example 99): 400 with the booked list.
- Create with ISO 14001 (id 5) before seeding it: 400 "clause library is empty for this standard".
- Call any edit after submit: 409. Call approve as the auditor: 403.
- Open the report as an auditor who is not on that audit: 403.
- Client portal (login as a client user): `GET /api/client-portal/audits/<audit_request_id>/reports` lists approved reports of the client's own audits only; `.../reports/<report_id>/pdf` downloads one.

## 5. Common problems

| You see | Cause |
|---|---|
| 401 | Token missing or expired. Run the login request again. |
| 403 on create / edit | The user is not the creator, lead auditor or co-auditor of that audit. |
| 403 on approve | The user is not an admin, and is not a `scheme` user of the same scheme as the company. |
| 400 "Could not tell the stage" | The audit row has no INITIAL / SURVEILLANCE / RECERTIFICATION type. Send `stage_type` in the create body. |
| 400 "clause library is empty" | Run step 1 for that standard. |
| 404 "Report template file not found" | The `templates` folder was not copied into `dist`. Add the `nest-cli.json` assets entry from the README, or set `AUDIT_REPORT_TEMPLATE_DIR`. |
| 500 when making a PDF | Chromium could not start on the server. On Linux install the Chromium libraries (`apt install -y libnss3 libatk-bridge2.0-0 libgbm1 libasound2`), or set `PUPPETEER_EXECUTABLE_PATH`. |
| PDF text looks different from Word | Install the Carlito font: `apt install fonts-crosextra-carlito`. |
