# Yaltopia Tickets Mobile App - UAT Test Cases

This document lists User Acceptance Testing (UAT) scenarios and test cases mapped to the core routes, flows, views, and backend integrations of the Yaltopia Tickets mobile application.

---

## 1. User Onboarding & Authentication
Covers: Registration, Login, OTP verification, persistent session management, and logout.

| Test ID | Scenario | Steps | Expected Result | Status |
|---|---|---|---|---|
| **YT-UAT-001** | User Registration (Success Flow) | 1. Navigate to `/register`. <br>2. Fill in first name, last name, email, password, and confirm password. <br>3. Tap **Register**. | Account is successfully created on backend (`POST /auth/register`); user is redirected to the login or OTP screen with a success toast. | Pass/Fail |
| **YT-UAT-002** | User Registration (Input Validation) | 1. Navigate to `/register`. <br>2. Submit empty form. <br>3. Submit mismatched passwords or a password shorter than 8 characters. | UI prevents submission and displays distinct, clean validation warnings below each input field. | Pass/Fail |
| **YT-UAT-003** | User Registration (Existing Email) | 1. Navigate to `/register`. <br>2. Input an email already associated with an account. <br>3. Tap **Register**. | Error banner appears ("Email already exists") and prevents screen transition. | Pass/Fail |
| **YT-UAT-004** | User Login (Success Flow) | 1. Navigate to `/login`. <br>2. Enter correct email and password. <br>3. Verify "Remember Me" toggle is checked. <br>4. Tap **Sign In**. | Login request succeeds (`POST /auth/login`), JWT credentials are saved securely in secure storage, and user lands on dashboard `/(tabs)/index`. | Pass/Fail |
| **YT-UAT-005** | User Login (Invalid Credentials) | 1. Navigate to `/login`. <br>2. Input wrong password or non-existent email. <br>3. Tap **Sign In**. | Login fails on backend, showing an explicit error dialog or banner, while preserving input text. | Pass/Fail |
| **YT-UAT-006** | Google OAuth Login | 1. Navigate to `/login`. <br>2. Tap the **Google** sign-in button. <br>3. Complete authentication in browser page. | Session is initialized on app, token is received and saved, and user is redirected to the home dashboard. | Pass/Fail |
| **YT-UAT-007** | OTP Verification Flow | 1. Trigger OTP verification on register/login. <br>2. Input valid OTP code received. <br>3. Tap **Verify**. | App validates OTP successfully (`POST /auth/verify-otp`) and routes to the main tab screen. | Pass/Fail |
| **YT-UAT-008** | OTP Resend & Expiry | 1. Wait for OTP timer to expire. <br>2. Tap **Resend OTP**. <br>3. Input expired OTP code. | 1. Resend button triggers a fresh OTP token. <br>2. Expired code entry displays an "OTP Expired" error message. | Pass/Fail |
| **YT-UAT-009** | Sticky Logout Button Execution | 1. From profile settings, scroll down to bottom of view. <br>2. Locate sticky logout button. <br>3. Tap **Logout**. | Token cache is deleted, session is cleared, and navigation guard forces routing back to `/login` immediately. | Pass/Fail |
| **YT-UAT-010** | Persistent Authentication Guard | 1. Close application from active processes list. <br>2. Re-open application. | Session is validated; user bypasses `/login` directly to `/(tabs)/index` (or is prompted to log in if token has expired). | Pass/Fail |

---

## 2. Dashboard (`/(tabs)/index`)
Covers: Earnings summaries, dashboard trends, quick action navigation, and recent invoice list.

| Test ID | Scenario | Steps | Expected Result | Status |
|---|---|---|---|---|
| **YT-UAT-011** | Earnings & Stats Metrics Dashboard | 1. Land on `/(tabs)/index` tab. <br>2. Verify calculated sums of pending and paid invoices. | Metrics dynamically update from `/invoices/stats` and `/dashboard/metrics` with correct totals. | Pass/Fail |
| **YT-UAT-012** | Quick Action Shortcuts Navigation | 1. From Home screen, tap **Scan**, **Create Invoice**, or **Create Proforma**. | Correctly redirects to `/(tabs)/scan`, `/invoices/create`, or `/proforma/create` respectively. | Pass/Fail |
| **YT-UAT-013** | Dashboard Recent Invoices Feed | 1. Scroll through "Recent Invoices" list on Home. <br>2. Pull to refresh dashboard list. <br>3. Tap on any invoice row. | 1. Recent list displays details dynamically. <br>2. Pull-to-refresh fires new fetch. <br>3. Tapping redirects user to `/invoices/[id]`. | Pass/Fail |

---

## 3. Invoice Addition & OCR Prefill (`/invoices/create` & `/invoices/edit`)
Covers: Manual invoice entry, AI OCR extraction pre-fill, dynamic calculations, currency/type modals, and field validations.

| Test ID | Scenario | Steps | Expected Result | Status |
|---|---|---|---|---|
| **YT-UAT-014** | Auto-Generated Invoice Number & Default Due Date | 1. Navigate to `/invoices/create`. <br>2. Observe the initial state of the form fields. | 1. `Invoice Number` is auto-filled with format `INV-YYYY-XXXX`. <br>2. `Issue Date` defaults to today's date. <br>3. `Due Date` defaults to 30 days from now. | Pass/Fail |
| **YT-UAT-015** | Scan From Gallery (OCR Success Flow) | 1. Tap **Scan From Gallery** banner at top. <br>2. Grant media library permission. <br>3. Select a valid invoice image. <br>4. Observe the OCR spinner. | 1. File is uploaded to `${BASE_URL}scan/invoice` via `POST`. <br>2. Success toast "Success! Data extracted successfully." is shown. <br>3. Form fields (Invoice Number, Customer Name, Email, Phone, Project Description, Currency, Issue/Due Dates, Tax, Line Items) auto-populate accurately. | Pass/Fail |
| **YT-UAT-016** | Scan From Gallery (OCR Failure Fallback) | 1. Tap **Scan From Gallery** and select a corrupted file. <br>2. Reject media permission. | 1. Rejecting permission displays "Permission Denied" toast with instructions. <br>2. OCR engine error triggers "Extraction Failed" toast, letting the user enter details manually. | Pass/Fail |
| **YT-UAT-017** | Form Validation (Required Fields) | 1. Clear the `Invoice Number` and `Customer Name` fields. <br>2. Tap **Create Invoice**. | UI displays a "Validation Error" toast ("Invoice Number is required" / "Customer Name is required") and blocks submission. | Pass/Fail |
| **YT-UAT-018** | Selector Modals (Currency, Type, Status) | 1. Tap **Currency** selector. <br>2. Tap **Type** selector. <br>3. Tap **Status** selector. | 1. Currency modal lists USD, ETB, EUR, GBP, KES, ZAR. <br>2. Type modal lists SALES, PURCHASE, SERVICE. <br>3. Status modal lists DRAFT, PENDING, PAID. Selection updates UI correctly. | Pass/Fail |
| **YT-UAT-019** | Dynamic Billable Items Math Calculations | 1. Tap **Add Item** button. <br>2. Enter a description. <br>3. Input Quantity = `3` and Unit Price = `150.00`. <br>4. Set Tax = `15.00` and Discount = `10.00`. | 1. Item total recalculates instantly to `450.00`. <br>2. Subtotal displays `450.00`. <br>3. Total Amount calculates correctly as `Subtotal + Tax - Discount` = `455.00`. | Pass/Fail |
| **YT-UAT-020** | Billable Items Addition & Removal | 1. Add multiple items. <br>2. Tap the red trash icon on "Item 2". | Item is removed from the form, and the invoice subtotals/totals are immediately recalculated. | Pass/Fail |
| **YT-UAT-021** | Discard vs. Create Invoice Submission | 1. Fill in valid Invoice details. <br>2. Tap **Discard**. <br>3. Create another, then tap **Create Invoice**. | 1. Discard navigates back immediately without saving. <br>2. Create Invoice posts JSON payload to `/invoices`, displays "Invoice created successfully!" success toast, and redirects back. | Pass/Fail |

---

## 4. Scan, OCR Extraction & Match (`/(tabs)/scan`)
Covers: Camera viewfinder integrations, invoice photo uploads, OCR results extraction parsing, and matching invoice logic.

| Test ID | Scenario | Steps | Expected Result | Status |
|---|---|---|---|---|
| **YT-UAT-022** | Camera Authorization & Permissions | 1. Navigate to `/scan` tab. <br>2. Decline camera permissions, then try to use scan. <br>3. Revoke then grant camera permission in system settings. | 1. Declining shows a clean message explaining the need for camera access with a settings button. <br>2. Granting loads camera viewfinder dynamically. | Pass/Fail |
| **YT-UAT-023** | Scan Capture and OCR Processing | 1. Frame a paper receipt/invoice inside viewfinder. <br>2. Tap **Capture**. <br>3. Wait for progress tracker/spinner animation. | Capture uploads the image (`POST /scan/invoice`), showing an active loading skeleton until details are analyzed. | Pass/Fail |
| **YT-UAT-024** | Choose Image from System Gallery | 1. On scan screen, tap **Gallery Import** icon. <br>2. Pick a valid receipt JPEG/PNG image. | App successfully parses file details and uploads the binary to the server OCR scan parser. | Pass/Fail |
| **YT-UAT-025** | Scan OCR Result - Save as New | 1. Complete OCR scanning. <br>2. Verify captured total, vendor name, items, and tax on UI. <br>3. Tap **Save as New**. | Extracted fields populate the `/invoices/create` screen form seamlessly for final check and submission. | Pass/Fail |
| **YT-UAT-026** | Scan OCR Result - Match to Existing | 1. Complete OCR scanning. <br>2. Tap **Match to Existing**. <br>3. Select the matching target pending invoice record. | Request links the receipt file data to the pre-existing system invoice, marking invoice state appropriately. | Pass/Fail |
| **YT-UAT-027** | Payment Receipt Image Upload | 1. Navigate to `/scan`. <br>2. Upload payment transaction receipt. | Upload triggers `POST /scan/payment-receipt`, capturing proof of payment in backend DB. | Pass/Fail |

---

## 5. Android SMS Scan & Bank Parser (`/sms-scan`)
Covers: Native SMS permissions, bank keyword filters, CBE/Dashen/Telebirr extraction regex logic, and Development Build native module failure guards.

| Test ID | Scenario | Steps | Expected Result | Status |
|---|---|---|---|---|
| **YT-UAT-028** | Non-Android Device Rejection | 1. Run the app on iOS or Web. <br>2. Attempt to open `/sms-scan`. <br>3. Tap **Scan Now**. | App triggers toast error: "Android Only: SMS reading is only supported on Android." and blocks further execution. | Pass/Fail |
| **YT-UAT-029** | Development Build Module Guard | 1. Open `/sms-scan` on an Android emulator running Expo Go. <br>2. Tap **Scan Now**. | Native check fails since `SmsAndroid` is null (Expo Go fallback). Shows: "Native Module Error: SMS scanning requires a Development Build." toast. | Pass/Fail |
| **YT-UAT-030** | READ_SMS Permissions Flow | 1. Open on Android Development Build. <br>2. Tap **Scan Now**. <br>3. Select "Deny". <br>4. Select "Allow" on retry. | 1. "Deny" triggers "Permission Denied: SMS access was not granted." toast. <br>2. "Allow" grants permission on Android OS level and starts reading. | Pass/Fail |
| **YT-UAT-031** | 20-Minute Time Window Filter | 1. Send test SMS at time T-30 mins and T-10 mins. <br>2. Tap **Scan Now**. | 1. Filter looks back exactly 20 minutes (`Date.now() - 20 * 60 * 1000`). <br>2. Only the message from T-10 mins is listed; T-30 mins message is ignored. | Pass/Fail |
| **YT-UAT-032** | Banking Keyword Filter Match | 1. Send SMS from "Friend" containing general text. <br>2. Send SMS from "CBE" or containing "telebirr". <br>3. Tap **Scan Now**. | List filters out the "Friend" message, matching only texts containing keywords `CBE`, `DashenBank`, `Dashen`, `127`, or `telebirr`. | Pass/Fail |
| **YT-UAT-033** | CBE SMS Bank Parser Verification | 1. Simulate CBE message: `"Your account has been credited with ETB 2,500.00. Ref: CBE987654"` <br>2. Tap **Scan Now**. | 1. Parses bank as **CBE** (displays Green label). <br>2. Extracts Amount = `2,500.00`. <br>3. Extracts Reference = `CBE987654`. <br>4. Renders full SMS body in italics. | Pass/Fail |
| **YT-UAT-034** | Telebirr SMS Bank Parser Verification | 1. Simulate Telebirr message: `"You received Birr 850.50. Trans ID: TXN112233"` <br>2. Tap **Scan Now**. | 1. Parses bank as **Telebirr** (displays Violet label). <br>2. Extracts Amount = `850.50`. <br>3. Extracts Reference = `TXN112233`. <br>4. Renders full SMS body in italics. | Pass/Fail |
| **YT-UAT-035** | Dashen SMS Bank Parser Verification | 1. Simulate Dashen message: `"Transfer ETB 10,000.00. Reference No: DSH445566"` <br>2. Tap **Scan Now**. | 1. Parses bank as **Dashen** (displays Blue label). <br>2. Extracts Amount = `10,000.00`. <br>3. Extracts Reference = `DSH445566`. <br>4. Renders full SMS body in italics. | Pass/Fail |

---

## 6. Proforma Requests (`/proforma/*` & `app/(tabs)/proforma.tsx`)
Covers: Proforma request list, custom proforma requests creation, item editing, contact sharing, bids, and PDFs.

| Test ID | Scenario | Steps | Expected Result | Status |
|---|---|---|---|---|
| **YT-UAT-036** | Proforma Invoices Grid Feed | 1. Select the **Proforma** tab. <br>2. Scroll through lists. <br>3. Toggle status filters (Draft, Open, Closed, Cancelled). | Requests render accurately with correct badges indicating current proforma state. | Pass/Fail |
| **YT-UAT-037** | Create Proforma Request | 1. Navigate to `/proforma/create`. <br>2. Enter request title, select catalog items, add descriptions, select target contacts. <br>3. Tap **Create**. | API registers the new proforma request (`POST /proforma-requests`), updating the tabs grid list. | Pass/Fail |
| **YT-UAT-038** | Modify Proforma Request Items | 1. Open active proforma request detail. <br>2. Tap **Add/Edit Items**. <br>3. Increase quantity, add item descriptions, or delete line items. | Subtotals and totals dynamically recalculate on the UI, and updates sync (`POST/PUT /proforma-requests/{id}/items`). | Pass/Fail |
| **YT-UAT-039** | Send Proforma to Contacts | 1. On proforma detail view `/proforma/[id]`, tap **Send to Contacts**. <br>2. Select recipients list. <br>3. Tap **Send**. | Request initiates, sending deep-links or email invitation notifications to selected customer/vendor contacts. | Pass/Fail |
| **YT-UAT-040** | Proforma Bid Submissions Tracker | 1. View detailed view `/proforma/[id]`. <br>2. Navigate to **Submissions** section. <br>3. Review incoming bids from vendors/partners. | List reflects all submitted prices and proposals associated with the specific request ID. | Pass/Fail |
| **YT-UAT-041** | Download Proforma Request PDF | 1. In proforma detail, tap **Download PDF**. | Requests file generation `GET /proforma-requests/{id}/pdf`, starting system download successfully. | Pass/Fail |
| **YT-UAT-042** | Edit Proforma Details | 1. Open detail view, tap **Edit**. <br>2. Change due date or request title. <br>3. Tap **Save**. | Update call executes (`PUT /proforma-requests/{id}`), refreshing information in the UI components. | Pass/Fail |
| **YT-UAT-043** | Close / Cancel Proforma Request | 1. Open active proforma request. <br>2. Tap **Close Request** or **Cancel Request**. | Changes status on server, transitioning status badge to closed/cancelled, and locking future bid submissions. | Pass/Fail |

---

## 7. Payments & Reconciliation (`/(tabs)/payments` & `/payments/[id]`)
Covers: Bank transactions list, status filters, payment-to-invoice association, and flagging.

| Test ID | Scenario | Steps | Expected Result | Status |
|---|---|---|---|---|
| **YT-UAT-044** | Payments List Feed View | 1. Tap the **Payments** tab. <br>2. Scroll payments list. <br>3. Switch between **Pending Match** and **Reconciled** segments. | UI updates correctly, grouping pending matching payments apart from fully reconciled items. | Pass/Fail |
| **YT-UAT-045** | Search & Filter Payments | 1. Type specific client name or transaction amount inside search bar. <br>2. Apply date range filters. | Grid filters instantly to show matching results without screen reload lag. | Pass/Fail |
| **YT-UAT-046** | Payment Details & Info | 1. Tap a pending match transaction from the payments list. | Routes to `/payments/[id]`, displaying detailed sender bank info, exact timestamp, and amount. | Pass/Fail |
| **YT-UAT-047** | Associate Payment to Invoice | 1. On payment detail `/payments/[id]`, tap **Associate to Invoice**. <br>2. Select matching unpaid invoice from search. <br>3. Tap **Confirm Link**. | Sends matching payload (`POST /payments/{id}/associate`). Payment shifts to Reconciled, and invoice updates to Paid status. | Pass/Fail |
| **YT-UAT-048** | Disputed / Flagged Transactions | 1. From `/payments/[id]`, tap **Flag Transaction**. <br>2. Select reason (e.g., mismatch amount, suspicious sender). <br>3. Save. | Payment status is marked as Flagged/Disputed (`POST /payments/{id}/flag`), rendering a distinct red flag badge in the list. | Pass/Fail |
| **YT-UAT-049** | Manual Payment Record Entry | 1. Tap **Create Payment** button. <br>2. Enter payment source, transaction reference number, target invoice, and confirmation date. <br>3. Submit. | Manual entry posts transaction record `POST /payments` and links the selected invoice successfully. | Pass/Fail |

---

## 8. Reports & Analytics (`/reports`)
Covers: Performance analytics, monthly generated summaries, stats trends, and document exports.

| Test ID | Scenario | Steps | Expected Result | Status |
|---|---|---|---|---|
| **YT-UAT-050** | Analytics Charts Render | 1. Open `/reports` from sidebar/profile. <br>2. Check for earnings, trends, and reconciliation rate bar/line charts. | Visual metrics render correctly using API response data from `/dashboard/revenue-trends` etc. | Pass/Fail |
| **YT-UAT-051** | Reports List View | 1. Scroll through lists of available monthly/quarterly PDF reports on `/reports`. | App lists monthly statements, showing publication dates and file size tags. | Pass/Fail |
| **YT-UAT-052** | Generate Customized Report | 1. From reports screen, tap **Generate Report**. <br>2. Input customized start and end dates. <br>3. Confirm. | Triggers `/reports/generate`, creating a fresh report which appears in the feed list on success. | Pass/Fail |
| **YT-UAT-053** | Download Monthly Report Document | 1. Tap on download icon next to any report row. | Initiates `/reports/{id}/download`, saving PDF statement file straight to the user device downloads directory. | Pass/Fail |

---

## 9. Company & Worker Management (`/company` & `/company-details`)
Covers: Worker listings, worker searching, worker creations, company details display (TIN, logo, contact, addresses).

| Test ID | Scenario | Steps | Expected Result | Status |
|---|---|---|---|---|
| **YT-UAT-054** | Company Details Display Panel | 1. Route to `/company-details` (from profile). <br>2. Verify displayed fields. | 1. Basic Info shows: Name, TIN. <br>2. Contact shows: Phone, Email, Website. <br>3. Address shows: Street, City, State, Zip, Country. <br>4. Logo displays from `company.logoPath`. | Pass/Fail |
| **YT-UAT-055** | Company Details System Timestamps | 1. Open `/company-details`. <br>2. Scroll to the "System Information" card. | Displays the user ID (monospace), and correct locales for `Created` and `Last Updated` date-times. | Pass/Fail |
| **YT-UAT-056** | Workers Feed List View | 1. Navigate to `/company`. <br>2. Verify loading indicator. <br>3. Browse workers list. | 1. Displays loading spinner. <br>2. Loads list via `api.users.getAll()`. <br>3. Cards render avatar/initials, full name, email, and role (e.g. "WORKER"). | Pass/Fail |
| **YT-UAT-057** | Worker Search Filters | 1. Input search query in the search bar. <br>2. Search by name and search by email. | List filters in real-time. Matches are case-insensitive and hide non-matching items immediately. | Pass/Fail |
| **YT-UAT-058** | Worker Empty State & Refresh | 1. Simulate an empty workers response. <br>2. Pull to refresh list. | 1. Shows `EmptyState` component with "No workers found" text. <br>2. Pull-to-refresh triggers new fetch spinner. | Pass/Fail |
| **YT-UAT-059** | Add New Worker Navigation | 1. Open `/company`. <br>2. Tap the floating **+** button. | Navigates the user directly to `/user/create` form screen to add a new employee. | Pass/Fail |

---

## 10. Profile, Documents & App Settings (`/profile`, `/documents`, `/settings`, `/notifications`)
Covers: Profile editing, document hubs, localized translation switches, and support forms.

| Test ID | Scenario | Steps | Expected Result | Status |
|---|---|---|---|---|
| **YT-UAT-060** | Profile Update Edit Form | 1. From profile screen, tap **Edit Profile**. <br>2. Modify first name, last name, phone, or job title. <br>3. Save. | Updates user details via PATCH/PUT requests, updating displayed profile card immediately. | Pass/Fail |
| **YT-UAT-061** | Documents Hub list | 1. Navigate to `/documents`. <br>2. Browse uploaded support files list. | List displays attachments, tax licenses, and contract agreements correctly. | Pass/Fail |
| **YT-UAT-062** | Document Upload integration | 1. On `/documents`, click **Upload Attachment**. <br>2. Choose PDF / JPEG format. <br>3. Upload. | Upload processes via `POST /documents/upload`, showing upload success state and list appends. | Pass/Fail |
| **YT-UAT-063** | App Language Transition | 1. Open `/settings` menu. <br>2. Select language picker. <br>3. Switch language. | All UI headings, descriptions, and tab text instantly update to match selected translation. | Pass/Fail |
| **YT-UAT-064** | Notifications Feed Log & Settings | 1. Navigate to `/notifications`. <br>2. Switch to settings `/notifications/settings`. <br>3. Toggle settings and save. | Feeds load successfully, and toggle settings persist in database on save (`PUT /notifications/settings`). | Pass/Fail |
| **YT-UAT-065** | Contact Support Form & FAQs | 1. Open `/help` and submit support ticket. <br>2. Open `/faq` and search accordion. | 1. Ticket submits successfully to backend. <br>2. FAQs search and accordions expand smoothly on tap. | Pass/Fail |

---

## 11. UI Responsiveness & General Edge Cases
Covers: System interruptions, offline behavior, and responsiveness.

| Test ID | Scenario | Steps | Expected Result | Status |
|---|---|---|---|---|
| **YT-UAT-066** | Offline Mode Warning | 1. Turn off mobile data / Wi-Fi. <br>2. Try performing actions (e.g., search payments, send invoice). | App displays standard elegant offline notice/banner in top bar, avoiding system crashes. | Pass/Fail |
| **YT-UAT-067** | Form Submission Double-Tap Prevention | 1. Open any submit page (Create Invoice/Register). <br>2. Fill details. <br>3. Double-tap/multi-tap **Submit** button very quickly. | App disables the CTA button on first tap to prevent double-post submissions or duplicate records. | Pass/Fail |
| **YT-UAT-068** | App Layout Adaptive Scaling | 1. Open the app on small and large Android/iOS screens (or change font scaling). | Text wraps nicely, inputs do not clip, and layouts remain aligned and readable. | Pass/Fail |
