AlejoTallerScan is composed of discrete feature modules, each following the same layered structure —Documentation Index
Fetch the complete documentation index at: https://mintlify.com/danielitoCode/AlejoTaller/llms.txt
Use this file to discover all available pages before exploring further.
data, domain, and presentation. This page walks through each feature, the key domain classes behind it, and how they connect to the broader monorepo flow.
Authentication
Operators log in throughOperatorAuthViewModel, which delegates to AuthOperatorUserCaseUse from the shared-auth module. After login, access is gated by the hasOperatorAccess() extension function defined in OperatorAccess.kt:
OperatorAccess.kt contains no class — hasOperatorAccess() and normalizeBusinessRole() are plain Kotlin extension functions on String?.
QR Code Scanning
TheOperatorQrScannerSection composable hosts a CameraX preview bound to ML Kit Barcode Scanning. When a barcode frame is decoded, the raw string is forwarded to ParseSaleScanPayloadCaseUse, which attempts to extract a saleId using several strategies in order:
ParsedSaleQrPayload carries saleId, optional userId, optional amount, and a list of ParsedSaleQrItem records (each with productId, quantity, and optional unitPrice). On a successful parse, OperatorSalesViewModel.loadSaleByCode() fetches the full sale from Appwrite and caches it locally in Room.
Manual Order Loading
When a QR code is unavailable or unreadable, operators can search for reservations directly from theOperatorReservationsScreen. SearchReservationsCaseUse queries SaleNetRepository using one of four ReservationSearchField values:
ReservationStatusFilter:
OperatorSalesViewModel.selectSale(), which loads it into OperatorSalesUiState.selectedSale and navigates to the confirmation screen — the same path taken after a successful QR scan.
Sale Verification Flow
Once a sale is loaded, the operator reviews its details on the confirmation screen and chooses to confirm or reject. TheOperatorSalesViewModel executes the following sequence for either decision:
- Guard check — if
sale.verified != BuyState.UNVERIFIED, the sale was already processed; a notice is shown and no remote call is made. - Appwrite update —
UpdateSaleVerificationFromRealtimeCaseUse(shared-sale) writes the newbuy_state:VERIFIEDfor confirmation,DELETEDfor rejection. - Remote state verification — the app re-fetches the sale from Appwrite and asserts the remote
buy_statematches the expected value. If it does not match, the local record is rolled back and an error is surfaced. - Publisher call —
NotifyOperatorSaleDecisionCaseUseinvokesPublisherSaleRealtimeNotifier, which sends an HTTPPOSTtoalejo_publisher:
- Local record —
RegisterOperatorSaleRecordCaseUsewrites anOperatorSaleRecordto the Room database with the resulting action (CONFIRMEDorREJECTED).
OperatorPaymentMethod:
Local Operator History
Every completed confirm or reject action is persisted locally in Room viaRegisterOperatorSaleRecordCaseUse. The domain entity stored is:
ObserveOperatorSaleRecordsCaseUse exposes these records as a Flow consumed by OperatorSaleRecordsViewModel and displayed in OperatorSaleRecordsScreen. The history is fully local and persists across sessions and app restarts — it is never cleared automatically.
Pending Sync
SyncPendingOperatorSalesCaseUse runs on the IO dispatcher and handles the case where locally cached sales still show UNVERIFIED — which can happen if a prior sync attempt was interrupted by a connectivity failure:
VERIFIED, a local notification is posted.
SyncPendingOperatorSalesCaseUse is distinct from SyncSalesCaseUse (shared-sale). The shared use case syncs the general sale list for the customer-facing apps; the operator-specific version focuses on locally cached UNVERIFIED sales that belong to the operator’s session.Local Notifications
OperatorSaleSyncNotificationService (implementing OperatorSyncNotificationService) posts a local Android notification when SyncPendingOperatorSalesCaseUse detects that a locally pending sale has already been verified remotely — typically because another operator processed the same reservation first.
The app requests POST_NOTIFICATIONS permission at the manifest level. On first launch on Android 13+, the user is prompted for notification permission. The notification informs the operator of the saleId and the customer name, preventing them from attempting to re-process a sale that is no longer UNVERIFIED.
Realtime Publishing
The operator app does not subscribe to any Pusher channel. Instead, after verifying a sale in Appwrite, it callsalejo_publisher over HTTP to trigger a sale:confirmed or sale:rejected event on the appropriate Pusher channel. The publisher service — not the operator app — holds the Pusher server credentials and signs the event. This keeps secrets out of the APK and avoids clock-skew signature failures from mobile devices.
The customer-facing Android app and the web client are the Pusher subscribers; they receive the events and update their UI accordingly.