I liked the comment at the end:
>> It’s the same bot as we have detailed in the tutorial with the exception that it uses PostGIS instead of a transactional variable to store users.
I am not a Haskell expert (I use Haskell a lot but I consider myself a student) so this is probably horrible advice, but recently I have started using embedded SQLite for transactional data instead of TVars. In some sense it is the same thing since the Simple SQLite wraps the SQLite code in an IO. I always try to minimize impure code. I write as much pure code as I can in a REPL and then study/research how to handle the impure parts.