feat: add Plaid transaction handling and async queue processing

- introduced new migration to add Cursor column to AccountMetadata.
- updated AppDbContext model snapshot to reflect changes in the database schema.
- implemented async queue processing with ChannelAsyncQueue and AsyncQueueHostedService.
- created Plaid transaction handlers for added, modified, and removed transactions.
- developed PlaidTransactionService and PlaidTransactionSyncer for syncing transactions.
- added SyncUpdatesProcessor to handle sync updates from Plaid.
- updated tests to accommodate changes in institution and account metadata handling.
This commit is contained in:
Stevan Freeborn
2026-03-09 04:29:01 -05:00
parent 48e95e5242
commit a9f1ced0d5
62 changed files with 3625 additions and 68 deletions
@@ -0,0 +1,46 @@
using Account = FiscalOS.Core.Accounts.Account;
namespace FiscalOS.Infra.Transactions.Plaid;
internal interface IPlaidTransactionProcessor
{
Task ProcessAsync(
Account account,
TransactionsSyncResponse syncResponse,
CancellationToken cancellationToken
);
}
internal sealed class PlaidTransactionProcessor : IPlaidTransactionProcessor
{
private readonly IPlaidAddedTransactionHandler _addedHandler;
private readonly IPlaidModifiedTransactionHandler _modifiedHandler;
private readonly IPlaidRemovedTransactionHandler _removedHandler;
private PlaidTransactionProcessor(
IPlaidAddedTransactionHandler addedHandler,
IPlaidModifiedTransactionHandler modifiedHandler,
IPlaidRemovedTransactionHandler removedHandler
)
{
_addedHandler = addedHandler;
_modifiedHandler = modifiedHandler;
_removedHandler = removedHandler;
}
internal static PlaidTransactionProcessor From(IServiceProvider provider)
{
return new(
provider.GetRequiredService<IPlaidAddedTransactionHandler>(),
provider.GetRequiredService<IPlaidModifiedTransactionHandler>(),
provider.GetRequiredService<IPlaidRemovedTransactionHandler>()
);
}
public async Task ProcessAsync(Account account, TransactionsSyncResponse syncResponse, CancellationToken cancellationToken)
{
_addedHandler.Handle(account, syncResponse.Added);
_modifiedHandler.Handle(account, syncResponse.Modified);
await _removedHandler.HandleAsync(syncResponse.Removed, cancellationToken).ConfigureAwait(false);
}
}