Angelopp v2 Flow Map

Backend-driven USSD analysis, surfaced inside the existing Angelopp UI.

This page is derived directly from /opt/angelopp/v2/app.py, /opt/angelopp/v2/core/router.py, /opt/angelopp/v2/core/state.py, /opt/angelopp/v2/core/db.py, /opt/angelopp/v2/core/audit.py, and /opt/angelopp/v2/modules/customer.py. It does not invent extra backend states. It documents the exact current flow and keeps the browser simulator aligned to it.

Backend Snapshot

The backend has a small explicit state machine wrapped around a larger safe-home fallback. Every request touches the user record, reads persisted state, validates state freshness, and writes an append-only audit entry.

2 Persisted states in user_state: ASK_NAME and ASK_PLACE.
300s State TTL. Expired or malformed state rows are cleared before routing continues.
3 Immediate terminal request intents: Ride, Errand, Delivery.
17 Distinct route labels across normal flow, invalid input handling, and exception paths.

Live Flow State

Detected state: HOME Response: idle User mode: unknown Route class: safe_home
Start a session to inspect the current branch of the USSD flow.
Current branch Home router
Likely DB writes No active request yet
Terminal behavior Awaiting session start
Safe fallback Unknown routes return to the safe home branch
Initial branch Empty text starts the flow. New users are sent to ASK_NAME. Returning users land on the personalized menu.

States And Transitions

ASK_NAME

Set for first-time users, name changes, and any request from a user record that exists without a stored name. Empty input repeats the prompt. Non-empty input saves users.name, clears state, and returns the personalized menu.

ASK_PLACE

Set only from menu option 4. Empty input abandons the branch and safely returns home. Non-empty input stores the place in users.last_place_text, writes to place_mentions, clears state, and ends the session.

HOME_MENU

This is not persisted in user_state; it is computed from the user record. Users with a saved place see “From your usual place?” and users without one see “What do you need today?”.

MORE_OPTIONS

Input 0 shows the submenu. 0*1 starts a name-change flow by setting ASK_NAME. 0*2 ends with goodbye. Any other submenu value falls back to the safe home branch.

TERMINAL_OUTCOMES

Request intents 1, 2, and 3 end immediately. Missing phone numbers and unhandled exceptions also return END responses, and every one of those outcomes is still audited.

Transition Matrix

Detected context Input condition Next behavior Route / action
No phone number Missing phoneNumber Immediate terminal error request.invalid / missing_phone
Bad persisted state State not in ALLOWED_STATES Clear state, go through safe home safe.home.menu or safe.home.ask_name
ASK_NAME Current input empty Repeat name prompt state.ask_name.prompt / ask_name
ASK_NAME Current input non-empty Save name, clear state, show menu state.ask_name.submit / set_name
ASK_PLACE Current input empty Clear state and return via safe home safe.home.menu or safe.home.ask_name
ASK_PLACE Current input non-empty Save place and end state.ask_place.submit / set_place
No text, no name text == "" Set ASK_NAME entry.new.ask_name / ask_name
No text, known name text == "" Show personalized home menu entry.returning.menu / show_menu
User record missing name Any non-empty text before naming Clear state, then force ASK_NAME entry.no_name.ask_name / ask_name
More options submenu 0*1 Start name change menu.more.change_name / ask_name
More options submenu 0*2 Exit immediately menu.more.exit / exit
More options submenu Any other 0*<x> Clear state, safe-home fallback safe.home.menu or safe.home.ask_name
Home menu 1 / 2 / 3 Terminal acknowledgement menu.request.* / intent:*
Home menu 4 Set ASK_PLACE menu.set_place.ask / ask_place
Home menu 0 Show submenu menu.more.show / more_options
Fallback Any unrecognized input outside handled branches Clear state, safe-home fallback safe.home.menu or safe.home.ask_name
Unhandled exception Any unexpected runtime error Terminal generic apology exception / exception:...

Feature Inventory

Identity capture gate

touch_user() creates or refreshes the user record on every request, but request intents are blocked until the user has a non-empty stored name.

Contextual home menu

The home copy changes based on users.last_place_text. The backend does not yet use the stored place for dispatch logic; it only changes menu wording and memory.

Pickup memory plus history

Place capture writes both a current value on the user row and a historical record in place_mentions.

State hygiene

Only ASK_NAME and ASK_PLACE are valid persisted states. Expired, invalid, or malformed state data is purged before routing continues.

Append-only audit trail

Each request writes session id, phone, text path, detected state, route, action, response prefix, and response text. SQL triggers explicitly block update and delete on audit_log.

Route And Write Coverage

Safe-home routes

safe.home.ask_name and safe.home.menu are the central recovery branch. Invalid submenu values, invalid stored states, and some abandoned input flows all converge here.

Entry routes

entry.new.ask_name, entry.returning.menu, and entry.no_name.ask_name cover first contact, normal returning users, and incomplete user records.

Action routes

state.ask_name.submit, state.ask_place.submit, menu.more.change_name, menu.more.exit, menu.more.show, and menu.request.{ride|errand|delivery} represent the entire active feature surface.

users

Created or refreshed by touch_user(). Name changes update name. Place capture updates last_place_text. last_seen changes on every request.

user_state

Stores only two active flow checkpoints. State is upserted with an ISO timestamp and deleted on completion, invalid state, timeout, or abandonment.

place_mentions

Receives a new row for every successful free-text place submission. This is the historical place ledger.

audit_log

Receives one append-only record per request. It captures enough to replay branch decisions without mutating prior evidence.

Canonical Paths

New user onboarding

"" → welcome prompt → enter name → personalized home menu.

Returning user request

"" → home menu → 1 or 2 or 3 → terminal acknowledgement.

Pickup place capture

"" → home menu → 4 → enter free-text place → confirmation and session end.

Change name

"" → home menu → 01 → enter new name → return to home menu.

Abandoned place entry

4 → empty current input while in ASK_PLACE → clear state → safe home branch instead of a stuck prompt.

Incomplete user record

Any non-empty text from a user row without name is discarded in favor of forcing the naming flow.

Bad submenu input

0*x where x is not 1 or 2 falls back to the safe home branch.

State timeout

After 300 seconds, persisted state is treated as gone. The next request resolves like a fresh safe-home evaluation.

Session: idle Awaiting start
System Press Start Session to open a live USSD session.
Current text path: ""
Use the buttons for the main actions. When Angelopp asks a question, type your answer here and press Send.

Live Interpretation

The simulator infers the active branch from the response text and current token path.

Awaiting input Start a session, then step through the same path structure the backend expects in text.