diff --git a/pages/ussd/issues.mdx b/pages/ussd/issues.mdx index 2339d23..dbb5872 100644 --- a/pages/ussd/issues.mdx +++ b/pages/ussd/issues.mdx @@ -1,9 +1,104 @@ -# Issues +# Known Issues -This section contains information about known issues/bugs on USSD and how to resolve them for end users. +This section documents known bugs on the USSD and their resolution steps. -## 1. key `X` not found in any frame +--- + +## 1. `key 'X' not found in any frame` + +### Cause + +A caching bug in go-vise where it attempts to `RELOAD` a symbol that was skipped during the initial `LOAD` operation, resulting in a broken cache state. + +### Resolution + +1. Confirm the issue by checking the relevant session logs on Africa's Talking. +2. In some cases, the issue self-corrects once the session is cleared — verify this before proceeding. +3. If the issue persists, SSH into the server and navigate to the production USSD directory: + +```bash +ssh user@host +cd dev/sarafu-vise/ +``` + +Run the CMD tool to trigger a cache cleanup for the affected user: + +```bash +go run -tags online cmd/main.go -session-id=+254xxxxxxxxx +``` + +This should reproduce the same error the user is seeing. Run the command a second time to confirm the cache has been cleared: + +```bash +go run -tags online cmd/main.go -session-id=+254xxxxxxxxx +``` + +A successful cleanup will display the USSD main menu instead of the error. + +--- + +## 2. `key not found: 'X'` + +### Cause + +Similar to [Issue 1](#1-key-x-not-found-in-any-frame). + +### Resolution + +Follow the same steps as [Issue 1](#1-key-x-not-found-in-any-frame). + +--- + +## 3. Incorrect admin privileges ### Cause -### Resolution steps \ No newline at end of file +The admin flag for a user can occasionally be cleared or incorrectly set on the USSD. The root cause is currently unknown. + +### Resolution + +SSH into the server, navigate to the production USSD directory, and run the following — replacing the session ID and setting the flag value to `1` (grant) or `0` (revoke) as needed: + +```bash +go run -tags logtrace devtools/admin/main.go -session-id=+254xxxxxxxxx admin 1 +``` + +--- + +## 4. Blank responses from the USSD + +### Cause + +After some time, or under heavy loads, postgres ends up having too many connections leading to timeouts on read and write operations. + +This is diagnosed by seeing several "failed" sessions on Africa's Talking logs + +### Resolution + +SSH into the server, navigate to the ussd docker folder, and restart the ussd container + +```bash +cd custodial-docker-stack/ussd/ +docker compose down ussd +docker compose up -d ussd +``` + +--- + +## 5. Replicating a user session for debugging + +### Overview + +Some users may encounter errors on specific menu nodes that cannot be diagnosed remotely. In these cases, the best approach is to replicate the user's session directly on the server to capture the full API responses and go-vise engine output. + +If none of the steps above resolve an issue, examining the full logtrace is the recommended next step. + +### Resolution + +SSH into the server, navigate to the production USSD directory, and run: + +```bash +go run -tags online,logtrace cmd/main.go -session-id=+254xxxxxxxxx +``` + +This produces a detailed logtrace that exposes the exact node, API call, or engine error causing the issue. \ No newline at end of file diff --git a/pages/ussd/overview.mdx b/pages/ussd/overview.mdx index 0aa5d83..acb6116 100644 --- a/pages/ussd/overview.mdx +++ b/pages/ussd/overview.mdx @@ -1 +1,159 @@ -## Overview \ No newline at end of file +## Overview +The Sarafu USSD uses the [go-vise](https://github.com/nolash/go-vise) engine, a constrained size output virtual machine. + +The codebase is found on [sarafu-vise](https://git.grassecon.net/grassrootseconomics/sarafu-vise) + +--- + +## Menu Flow: From main.vis to performing a Withdraw on M-Pesa + +The sections below trace the full navigation path a user takes from the main menu to initiating an M-Pesa withdrawal. + +### 1. `main.vis` - Main menu + +When a user dials the USSD code, they land on the main menu node after passing all checks on `root.vis`. The engine clears any temporary state, loads the user's vouchers and balance, and renders the menu options. + +``` +LOAD clear_temporary_value 2 # trigger external code handler "clear_temporary_value" - Clear any leftover state from a previous session +RELOAD clear_temporary_value # explicitly trigger "clear_temporary_value" every time this code is executed. +LOAD manage_vouchers 160 # trigger external code handler "manage_vouchers" - Load the user's vouchers +RELOAD manage_vouchers # explicitly trigger "manage_vouchers" every time this code is executed. +CATCH api_failure flag_api_call_error 1 # if the "flag_api_call_error" flag has been set, move to "api_failure" +LOAD check_balance 148 # trigger external code handler "check_balance" - Fetch the user's balance +RELOAD check_balance # explicitly trigger "check_balance" every time this code is executed. +MAP check_balance # make the result from "check_balance" available to the template renderer +MOUT send 1 # menu item +MOUT swap 2 # menu item +MOUT vouchers 3 # menu item +MOUT select_pool 4 # menu item +MOUT mpesa 5 # menu item +MOUT account 6 # menu item +MOUT help 7 # menu item +MOUT quit 9 # menu item +HALT # render template and wait for input +INCMP credit_send 1 # match menu selection 1, move to node "credit_send" on match +INCMP swap_to_list 2 # match menu selection 2, move to node "swap_to_list" on match +INCMP my_vouchers 3 # match menu selection 3, move to node "my_vouchers" on match +INCMP select_pool 4 # match menu selection 4, move to node "select_pool" on match +INCMP mpesa 5 # match menu selection 5, move to node "mpesa" on match +INCMP my_account 6 # match menu selection 6, move to node "my_account" on match +INCMP help 7 # match menu selection 7, move to node "help" on match +INCMP quit 9 # match menu selection 9, move to node "quit" on match +INCMP . * # match any other input, and stay on this node +``` + +The user selects **5** to enter the M-Pesa submenu. + +--- + +### 2. `mpesa.vis` — M-Pesa Submenu + +This node loads any outstanding credit/debt information and presents M-Pesa-related actions. + +``` +LOAD calc_credit_debt 150 +RELOAD calc_credit_debt +CATCH api_failure flag_api_call_error 1 +MAP calc_credit_debt +MOUT pay_debt 1 +MOUT deposit 2 +MOUT get_mpesa 3 # Option 3: Withdraw to M-Pesa +MOUT send_mpesa 4 +MOUT back 0 +MOUT quit 9 +HALT +INCMP ^ 0 # match menu selection 0, move to the previous node (in this case, main.vis) +INCMP pay_debt 1 +INCMP pool_deposit 2 +INCMP get_mpesa 3 +INCMP send_mpesa 4 +INCMP quit 9 +INCMP . * +``` + +The user selects **3** to initiate a withdrawal. + +--- + +### 3. `get_mpesa.vis` — Select a Voucher + +The user is presented with a paginated list of their vouchers to select from. The list is formatted to include the user's balance for each. + +``` +CATCH no_voucher flag_no_active_voucher 1 # if the "flag_no_active_voucher" flag has been set, move to "no_voucher.vis" node +LOAD get_ordered_vouchers 0 +MAP get_ordered_vouchers # displays a list of vouchers for the user to select +MOUT back 0 +MOUT quit 99 +MNEXT next 88 # menu choice to display for advancing one page +MPREV prev 98 # menu choice to display for going back to the previous page +HALT +INCMP > 88 # handle the "next" menu choice +INCMP < 98 # handle to "prev" menu choice +INCMP _ 0 +INCMP quit 99 +LOAD get_mpesa_max_limit 89 +RELOAD get_mpesa_max_limit +CATCH . flag_incorrect_voucher 1 +CATCH low_withdraw_mpesa_amount flag_incorrect_pool 1 # a check for a pool related error +CATCH low_withdraw_mpesa_amount flag_low_swap_amount 1 # a check for low swap amounts if the user hasn't selected a stable coin +CATCH low_withdraw_mpesa_amount flag_api_call_error 1 # a check for errors that originate from the API (404 errors when checking swap limits) +INCMP mpesa_max_limit * +``` +Once a valid voucher is selected, the engine checks available swap routes and fetches the maximum withdrawable amount. + +--- + +### 4. `mpesa_max_limit.vis` — Review Withdrawal Limit + +The maximum amount available for withdrawal is displayed to the user, and any pending transaction data from prior sessions is cleared. + +``` +LOAD reset_transaction_amount 10 # reset any pending data from previous transactions +RELOAD reset_transaction_amount +MAP get_mpesa_max_limit # map to display the results of the max limit after the voucher passes checks +MOUT back 0 +MOUT quit 9 +HALT +INCMP _ 0 +INCMP quit 9 +LOAD get_mpesa_preview 90 # get the preview of what the user should get once the transaction is successful +RELOAD get_mpesa_preview +CATCH api_failure flag_api_call_error 1 +CATCH invalid_get_mpesa_amount flag_invalid_amount 1 +INCMP get_mpesa_confirmation * +``` + +The user enters an amount and is taken to a confirmation screen. + +--- + +### 5. `get_mpesa_confirmation.vis` — Preview & PIN Entry + +The user sees a summary of the transaction and is prompted to enter their PIN to authorise it. + +``` +MAP get_mpesa_preview # display the results of the mpesa preview; that also requests the user to input their PIN +MOUT back 0 +MOUT quit 9 +HALT # PIN input, or "0" for back and "9" for close +LOAD authorize_account 6 # check the input to set appropriate flags from valid PIN inputs +RELOAD authorize_account +CATCH incorrect_pin flag_incorrect_pin 1 +INCMP _ 0 +INCMP quit 9 +INCMP initiate_get_mpesa * +``` + +--- + +### 6. `initiate_get_mpesa.vis` — Execute the Withdrawal + +The authorisation flag is checked and the withdrawal is submitted. This is a terminal node — reaching `HALT` here ends the session. + +``` +LOAD reset_incorrect_pin 6 # call the external function to clear any invalid PIN input flags +CATCH _ flag_account_authorized 0 # move back to the previous node if the user isn't authorized to perform the action +LOAD initiate_get_mpesa 0 # call the external function to initiate the mpesa withdrawal +HALT # single halt without any other statement initiates a session termination, as this is the last node +``` \ No newline at end of file