using Dapper;
using KArtSell.BuildingBlocks.Data;
using KArtSell.Modules.IdentityAccess.ManageIdentityAndRoles.Events;
using Microsoft.Extensions.Logging;
using Npgsql;
namespace KArtSell.Host.Consumers;
///
/// Logs identity creation events to audit trail.
/// Appends immutable record to audit.identity_audit_log for compliance.
/// Idempotent: Upserts based on (event_id, event_type) to prevent duplicates.
///
public sealed class IdentityAuditConsumer(
IDbConnectionFactory connectionFactory,
ILogger logger)
: IInboxConsumer
{
public async Task HandleAsync(IdentityCreated message, CancellationToken cancellationToken = default)
{
try
{
var conn = await connectionFactory.OpenAsync(cancellationToken) as NpgsqlConnection
?? throw new InvalidOperationException("Failed to open connection");
await using (conn)
{
const string sql = """
INSERT INTO public.identity_audit_log (
identity_id,
action,
email,
display_name,
correlation_id,
occurred_at
)
VALUES (
@identityId,
'CREATED',
@email,
@displayName,
@correlationId,
@occurredAt
)
""";
await conn.ExecuteAsync(sql, new
{
identityId = message.IdentityId,
email = message.Email,
displayName = message.DisplayName,
correlationId = message.CorrelationId,
occurredAt = message.OccurredAt
});
logger.LogInformation(
"Identity {IdentityId} ({Email}) creation logged to audit trail (CorrelationId: {CorrelationId})",
message.IdentityId,
message.Email,
message.CorrelationId);
}
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to log identity creation to audit trail for {IdentityId}", message.IdentityId);
throw;
}
}
}