This project utilizes the actor model and event sourcing via Akka.NET to build business banking functionality. Event sourcing is implemented with Akka.Persistence via PostgreSQL. Akka.Cluster.Sharding is used for account and employee actors. Future/recurring actor message scheduling with PostgreSQL persistence is set up with Quartz.NET.
- Automatic Balance Management
- Maintain a zero balance after each transaction
- Maintain a daily target balance by allowing a partner account to absorb excess cash or replenish cash to the target account
- Distribute balance among multiple accounts within an org on a per-transaction, daily, or twice-monthly schedule
- Employee Purchases
- Move money between accounts within your organization
- Transfer money immediately or on a future date to other organizations on the platform
- Payment requests between organizations on the platform
- Domestic transfers are sent to a Mock Domestic Transfer Processor service to mock the interaction of sending money to accounts outside the platform, such as an ACH transfer via Plaid. Integration with Akka circuit breaker allows pending transfers to be reprocessed if they previously failed due to intermittent network issues.
- Recurring maintenance fee for each billing cycle unless a qualified deposit found or a daily account balance threshold met.
- Manage daily/monthly employee purchase limits per employee card
- Monitor employee purchases and other activities on the platform
- Billing statements issued for each billing cycle
- Emails sent for account open/close, employee invites, billing statement, purchase declined, transfer deposited, etc.
The UI is built with React libraries for the F# landscape. See Feliz.
SignalR is used to provide feedback from actors to the UI:
- Overall account state
- History of transactions on the account
- Toggling between a transfer sender & receiver account (internal to the bank) demonstrates debits in one account and credits in the other
- A system operations navbar displays circuit breaker open/closed status for domestic transfers to the 3rd party bank mock server
- When the circuit breaker closes, pending domestic transfers are reprocessed & corresponding Approved/Rejected events are interpolated into the table
- Dependencies: .NET 8, minikube, pulumi, Node.js 18
sh build.sh -t RunK8sApp
- Browser opens automatically after all K8s resources start up
- Enable postgres port forwarding if you want to inspect postgres in a local client:
sh postgres-port-forward-k8s.sh
(Server=postgres;Database=akkabank;Uid=testuser;Pwd=testpass) - View Akka cluster and actor info via Petabridge.Cmd:
> minikube kubectl -- exec --stdin --tty account-cluster-0 -- /bin/bash > dotnet tool run pbm > cluster show > actor hierarchy
- Dependencies: .NET 8, Node.js 18
sh build.sh -t RunDockerApp
- Navigate to localhost:3000
- If you want to inspect postgres in a dashboard you can visit localhost:5008 (Server=postgres;Database=akkabank;Uid=postgres;Pwd=password)
- Dependencies: .NET 8, Node.js 18, PostgreSQL & psql
- Create a database (Server=localhost;Database=akkabank;Uid=postgres;Pwd=password)
- Seed the database:
psql postgres < Infrastructure/Migrations/*.sql
cd
into ./Web, ./Account.Service, ./Scheduler.Service, & ./MockThirdPartyBankTransferReceiver &dotnet run
in eachcd
into ./UI andnpm run build
ornpm start
- Dependencies: .NET 8, Azure CLI, Pulumi, Node.js 18
sh build.sh -t DeployAllStaging
(You will be prompted to sign in to Pulumi & Azure CLI)- One pulumi stack of Azure AKS resources and another Pulumi stack for K8s resources will be created. A Pulumi ESC staging environment will be created and app environment configuration will be set. Your local kubeconfig file will be modified to include details needed to connect to the AKS cluster. See
kubectl get all --namespace akkabank
&kubectl get all --namespace app-routing-system
. App images are currently being pulled from my public docker hub repos. Ingress is partially configured - An IP will be exported to the console when Pulumi finishes creating resources.
sh build.sh -t Test
Inspiration for this project stemmed from reading Functional Programming in C# by Enrico Buonanno.
The first iteration of this project (see CSharpWithLanguageExt directory) expands on Enrico Buonanno's banking account example actor and domain logic to include additional business use cases as well as integration with more tech such as EventStoreDB and the de facto library for functional programming in C#, language-ext.
The second iteration (see FSharpWithAkka directory) is close to a one-to-one representation of the CSharpWithLanguageExt directory, with all use cases rewritten in F# and Paul Louth's echo-process actor library replaced with Akka. I saw that F#'s type inference, computation expressions and immutable data structures made writing programs with typed functional programming more second nature than with C# so I decided to continue with it for the final iteration.