Private
Public Access
1
0

Update existing SimpleFIN connections on re-connect instead of creating duplicates

When a user re-connects SimpleFIN (e.g. after a key change), match existing
connections by institution name and update the access token in-place rather
than always creating new SyncConnection records. New linked accounts are
added if discovered, existing mappings are preserved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Catherine Renelle
2026-02-16 15:59:23 -05:00
parent 8b57aee672
commit db878c109c
+57 -19
View File
@@ -191,34 +191,72 @@ public class BankSyncService : IBankSyncService
var accounts = await _simpleFin.GetAccountsAsync(config); var accounts = await _simpleFin.GetAccountsAsync(config);
var encryptedAccessUrl = _encryption.Encrypt(accessUrl); var encryptedAccessUrl = _encryption.Encrypt(accessUrl);
// Load existing SimpleFIN connections for this user to avoid duplicates on re-connect
var existingConnections = await _db.SyncConnections
.Include(c => c.LinkedAccounts)
.Where(c => c.UserId == userId && c.Provider == SyncProvider.SimpleFIN)
.ToListAsync();
var groupedByInstitution = accounts.GroupBy(a => a.Institution ?? "SimpleFIN Connection"); var groupedByInstitution = accounts.GroupBy(a => a.Institution ?? "SimpleFIN Connection");
var connectionIds = new List<Guid>(); var connectionIds = new List<Guid>();
foreach (var group in groupedByInstitution) foreach (var group in groupedByInstitution)
{ {
var connection = new SyncConnection // Check if a connection already exists for this institution
{ var existing = existingConnections.FirstOrDefault(c =>
Id = Guid.NewGuid(), c.InstitutionName == group.Key);
UserId = userId,
Provider = SyncProvider.SimpleFIN,
InstitutionName = group.Key,
EncryptedAccessToken = encryptedAccessUrl
};
_db.SyncConnections.Add(connection); if (existing != null)
connectionIds.Add(connection.Id);
foreach (var account in group)
{ {
_db.LinkedAccounts.Add(new LinkedAccount // Update the existing connection with the new access token
existing.EncryptedAccessToken = encryptedAccessUrl;
existing.IsActive = true;
existing.UpdatedAt = DateTime.UtcNow;
connectionIds.Add(existing.Id);
// Add any new linked accounts not already tracked
foreach (var account in group)
{
if (!existing.LinkedAccounts.Any(la => la.ExternalAccountId == account.ExternalId))
{
_db.LinkedAccounts.Add(new LinkedAccount
{
Id = Guid.NewGuid(),
SyncConnectionId = existing.Id,
ExternalAccountId = account.ExternalId,
ExternalAccountName = account.Name,
ExternalAccountType = account.AccountType,
LastKnownBalance = account.Balance
});
}
}
}
else
{
var connection = new SyncConnection
{ {
Id = Guid.NewGuid(), Id = Guid.NewGuid(),
SyncConnectionId = connection.Id, UserId = userId,
ExternalAccountId = account.ExternalId, Provider = SyncProvider.SimpleFIN,
ExternalAccountName = account.Name, InstitutionName = group.Key,
ExternalAccountType = account.AccountType, EncryptedAccessToken = encryptedAccessUrl
LastKnownBalance = account.Balance };
});
_db.SyncConnections.Add(connection);
connectionIds.Add(connection.Id);
foreach (var account in group)
{
_db.LinkedAccounts.Add(new LinkedAccount
{
Id = Guid.NewGuid(),
SyncConnectionId = connection.Id,
ExternalAccountId = account.ExternalId,
ExternalAccountName = account.Name,
ExternalAccountType = account.AccountType,
LastKnownBalance = account.Balance
});
}
} }
} }