diff --git a/apps/mobile/packages/features/staff/profile_sections/compliance/documents/IMPLEMENTATION_WORKFLOW.md b/apps/mobile/packages/features/staff/profile_sections/compliance/documents/IMPLEMENTATION_WORKFLOW.md new file mode 100644 index 00000000..9734fcb8 --- /dev/null +++ b/apps/mobile/packages/features/staff/profile_sections/compliance/documents/IMPLEMENTATION_WORKFLOW.md @@ -0,0 +1,68 @@ +# Document Upload & Verification Workflow + +This document outlines the standardized workflow for handling file uploads, verification, and persistence within the Krow mobile application. This pattern is based on the `attire` module and should be used as a reference for the `certificates` module. + +## 1. Overview +The workflow follows a 4-step lifecycle: +1. **Selection**: Picking or capturing a file (PDF/Image) locally. +2. **Preview**: Allowing the user to review the document/photo before submission. +3. **Upload & Verification**: Pushing the file to storage and initiating a background verification job. +4. **Persistence**: Saving the record with its verification status to the database. + +--- + +## 2. Technical Stack +- **`FilePickerService`**: Handles PDF/File selection from the device. +- **`CameraService` / `GalleryService`**: Handles image capturing (if applicable). +- **`FileUploadService`**: Uploads raw files to our secure cloud storage. +- **`SignedUrlService`**: Generates secure internal/public links for viewing. +- **`VerificationService`**: Orchestrates the automated (AI) or manual verification of the document. +- **`DataConnect` (Firebase)**: Persists the structured data and verification metadata. + +--- + +## 3. Implementation Steps + +### A. UI Layer +1. **Selection**: + - Use `FilePickerService.pickFile(allowedExtensions: ['pdf'])`. + - Store the `localPath` in the widget state. +2. **Stateless Preview**: + - Provide an inline previewer (e.g., `PdfPreviewWidget`) so the user can verify the file contents. +3. **Submission**: + - Trigger a Cubit/Bloc event which calls the `UploadDocumentUseCase`. + - Show a global or inline progress indicator during the "Upload -> Verify -> Save" sequence. + +### B. Domain Layer +1. **UseCase**: + - Manage the sequence of repository calls. + - Handle domain-specific validation (e.g., checking if the document is mandatory). + +### C. Data Layer (The Repository Pattern) +The `Repository.uploadDocument` method should perform the following: +1. **Upload**: Call `FileUploadService` to get a `fileUri`. +2. **Link**: Call `SignedUrlService.createSignedUrl` to generate a `documentUrl`. +3. **Verify**: Call `VerificationService.createVerification` with the `fileUri` and relevant rules (e.g., `documentType`). +4. **Poll (Optional but Recommended)**: Poll the `VerificationService` for status updates for ~10 seconds to provide immediate feedback to the user. +5. **Persist**: Call Data Connect's `upsertStaffDocument` mutation with: + - `documentId` + - `documentUrl` + - `verificationId` + - `verificationStatus` (e.g., `PENDING` or `APPROVED`) + +--- + +## 4. State Management (Cubit/Bloc) +- **`status`**: Track `loading`, `uploading`, `success`, and `failure`. +- **`errorMessage`**: Store localized error keys from `BlocErrorHandler`. +- **`verificationId`**: Store the ID returned from the server to allow later manual refreshes. + +--- + +## 5. Metadata Mapping +Ensure the `DocumentStatus` or `VerificationStatus` enum aligns with the backend definition: +- `PENDING`: Waiting for job to start. +- `PROCESSING`: AI is currently analyzing. +- `APPROVED`: Document is valid. +- `REJECTED`: Document is invalid (should check `rejectionReason`). +- `NEEDS_REVIEW`: AI is unsure, manual check required. diff --git a/backend/dataconnect/schema/document.gql b/backend/dataconnect/schema/document.gql index b0657b10..2d1b6cd0 100644 --- a/backend/dataconnect/schema/document.gql +++ b/backend/dataconnect/schema/document.gql @@ -14,6 +14,7 @@ type Document @table(name: "documents") { name: String! description: String documentType: DocumentType! + isMandatory: Boolean @default(expr: "false") createdAt: Timestamp @default(expr: "request.time") updatedAt: Timestamp @default(expr: "request.time") createdBy: String diff --git a/backend/dataconnect/schema/staffDocument.gql b/backend/dataconnect/schema/staffDocument.gql index 65c26058..35a803ab 100644 --- a/backend/dataconnect/schema/staffDocument.gql +++ b/backend/dataconnect/schema/staffDocument.gql @@ -1,6 +1,13 @@ enum DocumentStatus { - UPLOADED PENDING + PROCESSING + AUTO_PASS + AUTO_FAIL + NEEDS_REVIEW + APPROVED + REJECTED + ERROR + UPLOADED EXPIRING MISSING VERIFIED @@ -12,9 +19,16 @@ type StaffDocument @table(name: "staff_documents", key: ["staffId", "documentId" staffName: String! documentId: UUID! document: Document! @ref(fields: "documentId", references: "id") - status: DocumentStatus! + + status: DocumentStatus! @default(expr: "'PENDING'") documentUrl: String expiryDate: Timestamp + + # Verification Metadata (Align with Attire flow) + verificationId: String + verifiedAt: Timestamp + rejectionReason: String + createdAt: Timestamp @default(expr: "request.time") updatedAt: Timestamp @default(expr: "request.time") createdBy: String