A .NET 8 AWS Lambda function that consumes lead creation events from SQS (published by a PHP Laravel CRM Gateway) and persists them to MySQL RDS using Clean Architecture principles.
This project implements Clean Architecture with the following layers:
- Domain - Core business entities and interfaces
- Application - MediatR handlers, DTOs, and FluentValidation validators (CQRS pattern)
- Infrastructure - EF Core, AWS SDK integrations, and repository implementations
- Lambda - AWS Lambda function entry point
src/
├── LeadProcessor.Domain/ # Domain entities & interfaces
├── LeadProcessor.Application/ # MediatR handlers, DTOs, validators
├── LeadProcessor.Infrastructure/ # EF Core, AWS SDK, repositories
└── LeadProcessor.Lambda/ # Lambda function entry point
tests/
├── LeadProcessor.UnitTests/ # Unit tests for handlers & validators
├── LeadProcessor.IntegrationTests/ # Integration tests with Testcontainers
└── LeadProcessor.TestHelpers/ # Shared test utilities
This solution uses Central Package Management (CPM) via Directory.Packages.props for consistent package versioning across all projects.
- ✅ Single source of truth for all package versions
- ✅ Easy to update versions across entire solution
- ✅ Prevents version conflicts between projects
- ✅ Cleaner project files without inline versions
All package versions are defined in Directory.Packages.props:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="MediatR" Version="12.4.1" />
<PackageVersion Include="FluentValidation" Version="11.10.0" />
<!-- ... other packages -->
</ItemGroup>
</Project>Individual projects reference packages without version attributes:
<ItemGroup>
<PackageReference Include="MediatR" />
<PackageReference Include="FluentValidation" />
</ItemGroup>To update a package version, simply modify Directory.Packages.props and all projects automatically use the new version.
- .NET 8 - Runtime platform
- AWS Lambda - Serverless compute
- AWS SQS - Message queue
- MySQL (RDS) - Relational database
- MediatR - CQRS pattern implementation
- FluentValidation - Input validation
- Entity Framework Core - ORM
- Pomelo.EntityFrameworkCore.MySql - MySQL provider
- xUnit - Unit testing framework
- Testcontainers - Integration testing with Docker
- .NET 8 SDK
- AWS CLI (for deployment)
- Docker (for integration tests with Testcontainers)
dotnet restore
dotnet build# Run all tests
dotnet test
# Run only unit tests
dotnet test --filter "Category=Unit"
# Run only integration tests
dotnet test --filter "Category=Integration"dotnet publish src/LeadProcessor.Lambda/LeadProcessor.Lambda.csproj \
--configuration Release \
--runtime linux-x64 \
--self-contained false \
--output ./publish
cd ./publish
zip -r ../lambda-deployment.zip .This Lambda function consumes lead events from the PHP CRM Gateway.
{
"tenant_id": "1",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000",
"email": "[email protected]",
"first_name": "John",
"last_name": "Doe",
"phone": "+61412345678",
"company": "Acme Corp",
"source": "website",
"metadata": {
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "summer-sale"
}
}| Attribute | Type | Description |
|---|---|---|
| EventType | String | "LeadCreated" |
| CorrelationId | String | Unique message ID (UUID) |
| TenantId | String | Tenant/User identifier |
| Timestamp | String | ISO 8601 timestamp |
Uses correlation_id as a unique constraint to prevent duplicate lead creation when SQS delivers the same message multiple times.
- Validation Errors - Logged and moved to DLQ immediately
- Transient Errors - Automatic Lambda retry (max 3 attempts)
- Unknown Errors - Logged and moved to DLQ after retries exhausted
Failed messages are moved to a DLQ after 3 retry attempts for manual investigation and reprocessing.
The project uses GitHub Actions for continuous integration:
- Builds on every push and pull request
- Runs unit and integration tests
- Packages Lambda deployment artifact
- Uploads deployment package for main/develop branches
See .github/workflows/ci.yml for details.
This project follows strict coding conventions:
- Clean Architecture - Dependencies point inward (Lambda → Application → Domain)
- CQRS - Commands and queries separated via MediatR
- Async/Await - All I/O operations are async with
CancellationTokensupport - Dependency Injection - Constructor injection throughout
IDateTimeProvider- For testable time-dependent code- Structured Logging - Using
ILogger<T>with correlation IDs - XML Documentation - All public APIs documented
See .cursor/rules/ai-agent.mdc for complete coding standards.
- Configure EF Core DbContext
- Implement repository pattern
- Set up AWS Secrets Manager service
- Implement SQS event handler
- Configure dependency injection
- Add error handling and DLQ logic
- Create initial migration for Leads table
- Add indexes for performance
- Write unit tests with mocked dependencies
- Create integration tests with Testcontainers
- Build test helper utilities
- Create AWS SAM template
- Configure IAM permissions
- Set up CloudWatch monitoring
- SQS Queue -
leads-queue(event source) - SQS DLQ -
leads-queue-dlq(failed messages) - RDS MySQL - Database for storing leads
- Secrets Manager - RDS credentials
- Lambda Function - Lead processor function
- IAM Role - With permissions for SQS, RDS, Secrets Manager
AWS_REGION- AWS regionAWS_SECRET_NAME- Secrets Manager secret name for RDS credentials
MIT
- PHP CRM Gateway - Laravel API that publishes lead events to SQS