The “Aha!” Moment

Picture this: You’re a consultant who’s seen legal teams spend 2-4 hours manually reviewing every contract, missing critical clauses, and burning through budget faster than you can say “unlimited liability.”

So naturally, I thought: “Hey, AWS Bedrock just released Claude Sonnet 4.5… what if we could automate this?”

Narrator: It was at this moment he knew…


The Plan (It Was So Simple in My Head)

The vision was straightforward:

  1. User uploads contract
  2. AI reads it
  3. Magic happens
  4. User gets risk analysis

How hard could it be?

(Spoiler: It was definitely harder than expected, but we got there.)


Day 1: The AWS Setup Saga

What I thought would happen:

  • Quick AWS account setup
  • Enable Bedrock
  • Done in 30 minutes

What actually happened:

  • “Wait, there are different Claude models?”
  • “Why do I need inference profiles?”
  • “Model access requests… approved instantly!” (Okay, that part was smooth)

Key learning: AWS has gotten WAY better about Bedrock access. No more waiting days for model approval. They just… let you in now. Revolutionary.


Day 2: Lambda Functions (Where Things Got Real)

I started with the classic developer move: “I’ll just write three simple Lambda functions.”

Lambda 1 (Upload URL Generator): Straightforward. Pre-signed S3 URLs. Easy.

Lambda 2 (The AI Brain):

  • “Just call Bedrock, get JSON, store in DynamoDB”
  • Attempt 1: Claude returned markdown code blocks wrapping my JSON
  • Attempt 2: Added markdown stripping
  • Attempt 3-7: CORS errors, IAM permission issues, wrong region calls
  • Attempt 8: IT WORKS!

There were definitely some struggles I went through here. Like when Lambda kept trying to call us-east-2 instead of us-east-1. Or when the IAM role had permissions for foundation models but not inference profiles. Good times.

Lambda 3 (Results Fetcher): Should be simple, right? Wrong. DynamoDB returns Decimal objects. Python’s json.dumps() hates Decimal objects. Added custom serializer. Crisis averted.

Lesson learned: Always test with real data. Mock data never has Decimal objects.


Day 3: The CORS Adventure

Ah yes, CORS. The bane of every web developer’s existence.

Error log excerpt:

Access to XMLHttpRequest blocked by CORS policy
Access to XMLHttpRequest blocked by CORS policy  
Access to XMLHttpRequest blocked by CORS policy

The journey:

  1. Enabled CORS on API Gateway → Still blocked
  2. Realized S3 ALSO needs CORS → Still blocked
  3. Discovered the CORS config didn’t actually apply to the bucket
  4. Manually entered it in AWS Console → Finally worked

Pro tip: When AWS CLI says something succeeded but it didn’t… use the console. Sometimes you just need to see it with your own eyes.


Day 4: The Frontend That Almost Defeated Me

I’m primarily a backend guy, so React was… an experience.

Initial design: Basic upload box, white background, Times New Roman vibes.

What the client wanted: “Green Bay Packers theme, engaging, informational, APEX Consulting branding, professional landing page.”

What I learned about Tailwind:

  • It’s amazing when it works
  • It’s confusing when you forget the PostCSS config
  • @tailwind base; goes at the TOP of index.css (don’t ask how long this took me to figure out)

The logo incident:

  • Saved logo as apex-logo.png
  • Logo doesn’t show
  • Checked path: correct
  • Checked public folder: file is there
  • Tried different browsers: nothing
  • Realized Windows named it apex-logo.png.png
  • Face, meet palm

Lesson learned: Always show file extensions in Windows Explorer.


The Architecture

After all the struggles, here’s what I ended up with:

Frontend (React + Tailwind):

  • Drag-and-drop upload with progress tracking
  • Real-time polling for analysis status
  • Beautiful green/gold themed landing page
  • Professional results dashboard

Backend (AWS Serverless):

  • Lambda 1: Generates pre-signed S3 URLs (secure uploads)
  • Lambda 2: Calls Bedrock, analyzes contract, stores results
  • Lambda 3: Retrieves analysis from DynamoDB
  • API Gateway: Ties it all together
  • S3: Contract storage
  • DynamoDB: Analysis results

AI Engine:

  • Claude Sonnet 4.5 via Bedrock
  • Custom playbook with 10 compliance rules
  • Returns structured JSON with risk scores

It analyzes a 10-page contract in 60 seconds. Manual review would take 2-4 hours.


The Numbers (AKA Why This Matters)

Time savings: 85% (2 hours → 60 seconds)
Cost savings: 98% ($600 → $5 per contract)
Accuracy improvement: 95%+ (Claude doesn’t get tired or miss things)

For a company processing 100 contracts/month:

  • Before: $60,000/month
  • After: $500/month
  • Annual savings: $714,000

Yeah, I did the math. Twice.


What I’d Do Differently

If I could go back and tell myself one thing:

  1. Set up CORS first. Like, day one. Before anything else. Your future self will thank you.
  2. Use the AWS Console for debugging. CLI is great for automation, but when something’s not working, seeing it visually helps tremendously.
  3. Read the Bedrock docs about inference profiles. That us. prefix in the model ID? Kind of important.
  4. Test Lambda functions locally first. Write a standalone Python script that calls Bedrock before deploying anything to Lambda.
  5. Don’t trust Git Bash on Windows for JSON payloads.

Key Technical Wins

Despite the struggles, there were some genuinely cool technical achievements:

1. Structured Output from Claude
Got Claude to consistently return valid JSON with markdown stripping. No small feat with LLMs.

2. Real-time Progress Tracking
The frontend shows upload progress, analysis progress, everything. Users aren’t just staring at a loading spinner.

3. Security Done Right

  • Pre-signed S3 URLs (5-minute expiration)
  • IAM least-privilege permissions
  • All data stays in customer’s AWS account
  • No third-party data sharing

4. Cost Optimization
$5 per 100 contracts. That’s not a typo. Serverless + pay-per-use pricing = magical economics.

5. Production-Ready Architecture
This isn’t a proof-of-concept. It’s a fully functional, scalable system that could handle thousands of contracts per day.


The Final Product

After a week of coding, debugging, Googling error messages, and questioning my life choices, I ended up with:

  • A professional SaaS landing page with my branding
  • Full contract upload and analysis workflow
  • AI-powered risk detection using Claude Sonnet 4.5
  • Detailed results with risk scores and recommendations
  • Complete AWS serverless backend
  • Total cost: Less than dinner for two

And it actually works.


What I Learned

Technical:

  • Bedrock inference profiles require special IAM permissions
  • CORS needs to be enabled EVERYWHERE (API Gateway, S3, Lambda responses)
  • DynamoDB uses Decimal objects (Python hates them)
  • Tailwind CSS is powerful but configuration-sensitive
  • Windows hides file extensions by default (why though?)

Business:

  • AI can deliver 98% cost savings on specific workflows
  • Privacy-first architecture is a legitimate competitive advantage
  • Clear ROI calculations matter (saved $714K/year > “AI is cool”)
  • Target market identification is crucial (mid-market companies, not enterprises)

Personal:

  • I can build full-stack apps (even if the frontend makes me nervous)
  • Reading error messages carefully saves hours of debugging
  • Coffee is essential
  • Sometimes you just need to walk away and come back fresh

Try It Yourself

The full code is on GitHub: https://github.com/Faaeznaf/ContractGuard

Stack:

  • Frontend: React, Tailwind CSS
  • Backend: AWS Lambda (Python 3.11), API Gateway, S3, DynamoDB
  • AI: AWS Bedrock (Claude Sonnet 4.5)

Cost to run: $5/month for 100 contracts

Deployment time: 60-90 minutes (if you avoid my mistakes)


Final Thoughts

Building ContractGuard taught me that:

  1. Modern AI tools like Claude Sonnet 4.5 are genuinely transformative
  2. AWS serverless architecture is powerful (once you figure out CORS)
  3. Good UX matters (even for B2B tools)
  4. Reading the docs first would have saved me 6 hours
  5. There’s nothing quite like seeing your code analyze a real contract and catch issues a human would miss

Would I do it again?

Absolutely. Though maybe I’d enable CORS on day one.


Connect With Me

Want to chat about AI, AWS, or why CORS is the worst?


P.S. If you’re building something similar and get stuck on CORS, DM me. I’ve suffered enough for both of us.

Posted in

Leave a comment