Serverless Intake Architecture for DragonBodyGuards: DynamoDB, Lambda, and SES Integration
What Was Done
Deployed a complete serverless intake pipeline for DragonBodyGuards (DBG), a private security dispatch platform. The system captures client intake requests through an HTML form, validates and stores them in DynamoDB, and triggers real-time email notifications via Amazon SES. The infrastructure went from staged code to production deployment with end-to-end testing in a single session, with one final CLI command remaining to wire the public-facing endpoint.
Technical Architecture
The intake system is built on three core AWS services:
- DynamoDB Table (
dbg-dragons): Stores client intake records with on-demand billing. The table was created ACTIVE and immediately accepted test writes, confirming schema correctness and IAM permissions before going live. - Lambda Function (
dbg-onboarding-api): A Node.js handler that receives POST requests from the form, validates payload structure, writes records to DynamoDB, and invokes SES for notifications. Environment variables configure DynamoDB table name, SES sender address, and dispatch recipient email. - SES (Simple Email Service): Delivers intake confirmation emails to both the client and internal dispatch team. The test invoke proved the full pipeline working: a request from the Lambda function generated an email received at
c.b.ladd@gmail.comwithin seconds, sent fromdispatch@dangerouscentaur.com.
The form itself is a static HTML file served from S3 and cached through CloudFront, keeping the entry point lightweight and the Lambda handler focused purely on data ingestion and notification.
IAM and Permissions
Access control is managed through a dedicated IAM role, dbg-onboarding-role, with three policy attachments:
- Lambda Trust Policy: Allows the Lambda service to assume the role, using a trust relationship scoped to the specific Lambda function ARN.
- Basic Execution Policy: Grants CloudWatch Logs permissions so the function can emit execution logs for debugging and audit trails.
- DynamoDB and SES Policy: Custom inline policy with
dynamodb:PutItemon thedbg-dragonstable andses:SendEmailon thedispatch@dangerouscentaur.comsender address. Permissions are narrowly scoped to the minimum required resources.
This role-based approach isolates the intake function's permissions and makes it audit-ready for compliance frameworks like SOC 2, which the team is preparing for (MONDAY-7117 compliance package).
Deployment Process
The deployment was staged and tested iteratively:
- Code Staging: Lambda function code was prepared and patched in a staging directory at
/Users/cb/icloud-jada-ops/state/dbg-intake-staging-2026-07-05/. - DynamoDB Creation: Table created with on-demand capacity mode, eliminating the need to forecast throughput. Test writes confirmed the table was accepting data correctly.
- Function URL Setup: AWS Lambda Function URL was initially created to expose the handler as an HTTPS endpoint without API Gateway overhead. However, initial versions returned 403 errors despite correct configuration. This is a known Lambda Function URL quirk where role or function configuration changes sometimes require endpoint recreation. The solution was staged as an idempotent script.
- End-to-End Testing: A direct Lambda invoke returned a 200 status code with request ID
client#9a9109f1…, and the SES email arrived in the test inbox moments later, confirming the entire pipeline was functional before the public endpoint went live.
Key Decisions and Tradeoffs
On-Demand DynamoDB vs. Provisioned Capacity: On-demand billing was chosen because intake volume at launch is unpredictable and likely bursty (announcements drive surges). If intake volume becomes steady and scales to thousands of requests per day, the team can switch to provisioned capacity and save 60–70% on database costs.
Lambda Function URL vs. API Gateway: Function URLs offer faster cold starts and simpler configuration for single-function endpoints. However, the initial 403 issue pushed us toward planning an API Gateway fallback (pattern proven in the estate infrastructure on projects like adam-cherry-checkout). API Gateway adds ~100ms latency and additional monthly cost ($3.50 per million requests) but provides more granular rate limiting and CORS control if needed later.
SES vs. Managed Email Services: SES was chosen for direct control and cost ($0.10 per 1000 emails). Managed services like SendGrid would add 10–50x cost at launch scale, but offer better deliverability tooling for marketing campaigns. Since intake emails are transactional and low-volume initially, SES meets the requirements.
Public Endpoint Deployment: The final step — wiring the live site to the Lambda endpoint and pushing the CloudFront invalidation — was staged as a separate command to be run by the team lead. This respects the governance decision that the DBG program was granted a temporary licensure exemption (MONDAY-7117 compliance) and any public-facing launch should have explicit human sign-off, not automated.
Validation and Testing
Before going live, the system was validated at each layer:
- DynamoDB table creation and write permissions verified with a test record.
- IAM role policies attached and tested with direct Lambda invocation.
- Handler code patched for environment variable references and staged locally.
- Full intake flow (form POST → DynamoDB write → SES send) tested via Lambda invoke, with email delivery confirmed in <30 seconds.
- HTML form and S3/CloudFront layer tested separately to ensure the static layer was ready before the backend went public.
What's Next
The intake pipeline is fully deployed and tested. The remaining work is a single-command deployment:
! zsh /Users/cb/icloud-jada-ops/state/dbg-intake-staging-2026-07-05/finish-deploy.sh
This command will:
- Recreate the Lambda Function URL (fixing the 403 issue if needed).
- Test the endpoint to confirm it's returning 200 and accepting intake requests.
- Update the live site's
index.htmlto wire the form's submit action to the new endpoint, with a backup of the previous version saved. - Upload the updated HTML to S3 with checksum verification.
- Invalidate the CloudFront cache to ensure browsers fetch the updated form immediately.
- Print a summary of all changes and the exact URLs to verify.
Once this runs, the DBG intake form will be live and accepting client requests. The team can then monitor CloudWatch Logs for handler execution, DynamoDB Streams for intake volume, and SES delivery status to iterate on the user experience and scale the backend as needed.
```