# Document Verification

To build a robust KYC/KYB document verification interface, you need a "split-view" layout. On one side, the Analyst views the raw evidence (Passport, Utility Bill, or Articles of Incorporation); on the other, they validate the data against your system's records.

Here is how to structure this core component in your Vue/Astro stack.

***

### 1. The Document Verification UI Component

In an ERP for compliance, the Analyst should never have to toggle between tabs. The UI must be a single, cohesive "Comparison Engine."

#### Key UI Features:

* The Document Viewer: Supports PDF, PNG, and JPG. Needs zoom, rotate, and "Invert Colors" (useful for reading faint stamps on old documents).
* Data Matching Form: Fields pre-filled by OCR (if you use a service like AWS Textract or Google Document AI) that the Analyst must "Confirm" or "Fix."
* The "Four-Eyes" Actions: Approve, Reject (with reason), or Request Information (RFI).

***

### 2. Vue Component Structure (The "Verification Page")

You can use a library like `vue-pdf-embed` for the viewer and standard Vue 3 composition for the state logic.

Code snippet

```
<template>
  <div class="flex h-screen overflow-hidden">
    <div class="w-1/2 bg-gray-900 p-4 flex flex-col">
      <div class="flex justify-between mb-4 text-white">
        <h3>Passport_JohnDoe.pdf</h3>
        <div class="flex gap-2">
          <button @click="rotate">Rotate</button>
          <button @click="zoomIn">+</button>
        </div>
      </div>
      <div class="flex-grow overflow-auto border border-gray-700">
        <DocumentViewer :src="documentUrl" :zoom="currentZoom" />
      </div>
    </div>

    <div class="w-1/2 p-6 overflow-y-auto bg-white">
      <h2 class="text-xl font-bold mb-6">Verify Identity Data</h2>
      
      <div class="space-y-4">
        <div v-for="field in kycFields" :key="field.key" class="p-3 border rounded">
          <label class="text-xs uppercase text-gray-500">{{ field.label }}</label>
          <div class="flex gap-2 mt-1">
            <input 
              v-model="field.value" 
              class="flex-grow border p-2 rounded"
              :class="{ 'bg-yellow-50': field.isOcrGuessed }"
            />
            <button @click="field.verified = true" :class="field.verified ? 'text-green-600' : 'text-gray-300'">
              <CheckCircleIcon class="w-6 h-6" />
            </button>
          </div>
        </div>
      </div>

      <div class="mt-10 pt-6 border-t flex gap-4">
        <button @click="handleAction('approve')" class="btn-approve">Approve Document</button>
        <button @click="showRejectModal = true" class="btn-reject">Reject / RFI</button>
      </div>
    </div>
  </div>
</template>
```

***

### 3. AdonisJS Backend Integration (The "Workflow" Controller)

In a financial relay/KYC system, you don't just "Save" data. You move a Case through a State Machine.

The Workflow Controller logic:

TypeScript

```
// app/Controllers/Http/KycWorkflowsController.ts
export default class KycWorkflowsController {
  public async approveDocument({ auth, params, request }: HttpContextContract) {
    const caseId = params.id
    const analyst = auth.user!

    // 1. Check Permissions (Bouncer)
    await bouncer.with('KycPolicy').authorize('approveDocument')

    // 2. Start Transaction
    return await Database.transaction(async (trx) => {
      const kycCase = await KycCase.findOrFail(caseId, { client: trx })

      // 3. Update Status and Record Audit Trail
      kycCase.status = 'VERIFIED'
      kycCase.verifiedBy = analyst.id
      kycCase.verifiedAt = DateTime.now()
      await kycCase.save()

      await AuditLog.create({
        userId: analyst.id,
        action: 'DOCUMENT_APPROVED',
        metadata: { caseId, documentId: request.input('documentId') }
      }, { client: trx })

      return { message: 'Document verified successfully' }
    })
  }
}
```

***

### 4. Why this "Maker-Checker" approach is essential:

* Accountability: If a sanctioned person is accidentally approved, you need the Audit Log to show which Analyst verified the Passport and which Senior Officer gave the final "OK."
* Data Integrity: By tracking `isOcrGuessed`, you can run reports later to see how accurate your automated tools are vs. your human staff.
* Tenant Separation: The Global Scope middleware we discussed ensures an Analyst at "Bank A" can never even attempt to fetch a document from "Bank B."

***

### Summary of the Component Stack

| **Layer**         | **Responsibility**                                                       |
| ----------------- | ------------------------------------------------------------------------ |
| Astro Layout      | Fetches the specific "KYC Workflow Menu" for the Analyst role.           |
| Vue Component     | Manages the side-by-side view and UI state (Zoom, Verification toggles). |
| Adonis Controller | Validates the permission to change the case status.                      |
| Adonis Middleware | Ensures the `tenant_id` matches the document's ownership.                |

Would you like me to show you how to handle the "Rejection Reasons" logic? (In KYC, you must give a specific reason like *"Blurry Image"* or *"Name Mismatch"* so the customer knows how to fix it).
