A serverless IoT sensor data ingestion and aggregation system built with AWS CDK (TypeScript). This system provides real-time sensor data collection through REST API and automatic hourly aggregation using DynamoDB Streams.
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Sensors │───▶│ API Gateway │───▶│ Lambda │───▶│ DynamoDB │
│ │ │ │ │ (Ingest) │ │ SensorEvents│
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ DynamoDB │◀───│ Lambda │◀───│ DynamoDB │ │ │
│SensorAggr.. │ │(Aggregate) │ │ Streams │ │ │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
Professional architecture diagrams following AWS best practices:
- System Overview - High-level component relationships
- Detailed Flow - Technical implementation details
- Well-Architected - AWS Well-Architected Framework implementation
For comprehensive architecture documentation including AWS best practices, security implementation, and cost optimization, see ARCHITECTURE.md.
Key Architectural Principles:
- ✅ Serverless-First: No server management, automatic scaling
- ✅ Event-Driven: Real-time processing with DynamoDB Streams
- ✅ Security by Design: Least privilege IAM, encryption, secrets management
- ✅ Well-Architected: Follows all 5 pillars of AWS Well-Architected Framework
- ✅ Infrastructure as Code: Complete automation with AWS CDK
- REST API endpoint for sensor data collection
- JSON schema validation
- Automatic timestamp generation
- Error handling and validation
- Real-time stream processing with DynamoDB Streams
- Hourly aggregation buckets
- Statistical calculations (avg, min, max, count)
- Automatic updates for existing aggregates
- Least privilege IAM permissions
- AWS Secrets Manager integration
- Environment-based configuration
- CloudWatch logging and monitoring
- AWS CDK with TypeScript
- Environment-specific deployments
- Automated bundling with esbuild
- Idempotent deployments
- Node.js 18+ and npm
- AWS CLI configured with appropriate permissions
- AWS CDK CLI installed (
npm install -g aws-cdk)
- Clone and setup the project:
cd /home/cash/Documents/codes/iot-sensor-aggregator
npm install- Configure environment (optional):
cp .env.example .env
# Edit .env with your preferred settings- Deploy the stack:
# Using the deployment script
./scripts/deploy.sh
# Or manually
npm run build
npx cdk bootstrap # First time only
npx cdk deploy- Test the API:
# Get the API endpoint from stack outputs
API_ENDPOINT=$(aws cloudformation describe-stacks \
--stack-name IoTSensorAggregatorStack \
--query 'Stacks[0].Outputs[?OutputKey==`ApiEndpoint`].OutputValue' \
--output text)
# Run tests
./scripts/test-api.sh $API_ENDPOINTPOST /sensor/data
{
"sensor_id": "sensor-123",
"type": "temperature",
"value": 24.5,
"location": "lab-1"
}{
"message": "Sensor data ingested successfully",
"data": {
"sensor_id": "sensor-123",
"timestamp": "2025-07-13T14:00:00.000Z",
"type": "temperature",
"location": "lab-1"
}
}curl -X POST \
-H "Content-Type: application/json" \
-d '{
"sensor_id": "temp-001",
"type": "temperature",
"value": 23.5,
"location": "office-a"
}' \
https://your-api-id.execute-api.region.amazonaws.com/dev/sensor/data- Partition Key:
sensor_id(String) - Sort Key:
timestamp(String, ISO format) - Attributes:
type,value,location,environment - Stream: Enabled (NEW_AND_OLD_IMAGES)
- Partition Key:
sensor_id(String) - Sort Key:
hour_bucket(String, format: "2025-07-13T14:00") - Attributes:
avg,min,max,count,last_updated,sensor_type,location
The system supports multiple environments through environment variables:
export ENVIRONMENT=dev|staging|prod
export CDK_DEFAULT_REGION=us-east-1
export CDK_DEFAULT_ACCOUNT=123456789012/aws/lambda/iot-sensor-ingest-{env}/aws/lambda/iot-sensor-aggregate-{env}
- API Gateway request/error metrics
- Lambda invocation/duration/error metrics
- DynamoDB read/write capacity metrics
# Example: Create alarm for Lambda errors
aws cloudwatch put-metric-alarm \
--alarm-name "IoT-Ingest-Lambda-Errors" \
--alarm-description "Lambda function errors" \
--metric-name Errors \
--namespace AWS/Lambda \
--statistic Sum \
--period 300 \
--threshold 1 \
--comparison-operator GreaterThanOrEqualToThreshold \
--dimensions Name=FunctionName,Value=iot-sensor-ingest-dev├── bin/ # CDK app entry point
├── lib/ # CDK stack definitions
├── lambda/ # Lambda function code
│ ├── ingest/ # Data ingestion Lambda
│ └── aggregate/ # Data aggregation Lambda
├── scripts/ # Deployment and testing scripts
├── test/ # Unit tests
└── README.md
# Install dependencies
npm install
# Build TypeScript
npm run build
# Run tests
npm test
# Watch for changes
npm run watch
# Synthesize CloudFormation
npm run synth# Run unit tests
npm test
# Test API endpoints
./scripts/test-api.sh <API_ENDPOINT>
# View logs
aws logs tail /aws/lambda/iot-sensor-ingest-dev --follownpm run build
npx cdk deploy --require-approval never./scripts/deploy.shENVIRONMENT=staging ./scripts/deploy.sh- Uses on-demand billing for variable workloads
- Point-in-time recovery enabled for data protection
- Consider switching to provisioned capacity for predictable workloads
- Right-sized memory allocation (256MB ingest, 512MB aggregate)
- Efficient bundling with esbuild reduces cold start times
- Connection reuse for AWS SDK clients
- Request/response caching can be enabled for read-heavy workloads
- Consider usage plans for rate limiting
- Least privilege access for all resources
- Separate roles for each Lambda function
- No wildcard permissions
- Secrets stored in AWS Secrets Manager
- CloudWatch Logs retention configured
- DynamoDB encryption at rest (default)
- API Gateway with CORS configured
- Lambda functions in default VPC (consider custom VPC for production)
-
Deployment Failures
# Check CDK bootstrap npx cdk bootstrap # Verify AWS credentials aws sts get-caller-identity
-
Lambda Timeout Errors
# Check CloudWatch Logs aws logs tail /aws/lambda/iot-sensor-ingest-dev --follow -
DynamoDB Throttling
# Monitor metrics aws cloudwatch get-metric-statistics \ --namespace AWS/DynamoDB \ --metric-name ConsumedReadCapacityUnits \ --dimensions Name=TableName,Value=SensorEvents-dev
Set ENVIRONMENT=dev for detailed error messages in API responses.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
For issues and questions:
- Check the troubleshooting section
- Review CloudWatch Logs
- Create an issue in the repository