Olá Uriel,
Você pode seguir usando a estratégia que citou acima - armazenando o fluxo do usuário em memória ou em um banco de dados. No caso da Letsia, usamos as duas estratégias...
CACHE: quando o usuário não completou o fluxo e as informações não são relevantes para serem salvas. Consequentemente, a sessão expira e não tenho os registros do fluxo. Ponto crítico; você precisa ter uma aplicação estável para que nenhum bug aconteça e você percar os caches no caminho.
BD: quando cada ação do usuário é relevante ou quando de fato finaliza todo o fluxo. Consequentemente, você poderá consultar o status de cada user em um dashboard a qualquer momento.
Sobre a lógica de construção, pense o seguinte:
cacheObject -> "numero_whatsapp"(primaryKey) -> array[step1, step2, step3, ok]