This is Week 7 of “Building with AI” - a 10-week journey documenting how I use multi-agent AI
workflows to build a production-grade SaaS platform.This week: Applying Week 6’s ADR-driven approach to configuration management. Same pattern:
clear requirements → AI designs solution → human adds operational knowledge. Result: 340 lines
of boilerplate vanish, 99.2% cache hit rate, zero config bugs in production.Previous: Week 6: AWS Runtime Adoption
Watch the 60-Second Summary
Week 7: Middleware patterns and systematic implementation
The Setup: Double Down on What Works
Week 6 proved that AI excels at design when given clear constraints (ADRs, requirements docs). The success formula from Week 6:- Document constraints in structured format
- Let AI design pattern that meets constraints
- Human reviews and adds operational optimizations
- Implement atomically, test thoroughly
- JWT expiration hardcoded in 3 places
- Each crate reading
std::env::var()directly - No tenant-specific overrides
- Zero hierarchy (Platform → Tenant → Capsule)
- 340 lines of manual config lookups across 17 handlers
ConfigService.get() with different error handling patterns. Inconsistent, error-prone, impossible to enforce.
What We Built This Week
The Challenge
Design a configuration system that:- Platform-level defaults (environment variables)
- Tenant-level overrides (stored in DynamoDB)
- Capsule-level overrides (SDLC: dev/staging/prod)
- Zero manual ConfigService calls in handlers (automatic injection)
The Multi-Agent Design Session
I gave the Evaluator agent our requirements (following Week 6’s pattern): Input: Requirements doc with hierarchy and constraints Not: “Build a config system” (too vague, Week 5’s mistake) The Evaluator’s response surprised me: “This is a middleware problem, not a service problem.”- What AI Did
- What Human Did
- Result
The Evaluator analyzed our existing Key insight: Reuse the scope extraction we already built for AWS clients!Builder agent then generated:
CapsuleExtractor middleware (from Week 6’s AWS client work) and proposed chaining:- Single cache lookup per request
- Hierarchical resolution (Platform → Tenant → Capsule)
- Automatic injection via Actix-web extensions
- Graceful degradation for public routes
The Architecture AI Discovered
The pattern has three layers:1. Middleware Chain (Automatic Injection)
config: web::ReqData<ConfigContext>, it won’t compile unless ConfigMiddleware is registered. Zero runtime errors.
2. Hierarchical Resolution
ConfigService resolves configuration with a fallback chain:3. Caching Layer (Performance)
Moka cache sits in front of DynamoDB to prevent hammering:- Cache hit rate: 99.2%
- DynamoDB calls per 1000 requests: 8 (was 17,000)
- P99 latency improvement: 42ms faster
What Went Wrong (And How We Fixed It)
The Migration
We migrated 17 auth handlers from manual config loading to middleware injection: Before: 17 handlers × manual loading = 340 lines of boilerplate- 340 lines of config loading boilerplate
- 17 error handling blocks
- Inconsistent patterns across handlers
- 179 lines of ConfigMiddleware
- Single registration in main.rs
- 100% consistent pattern enforced by compiler
The REST API (Bonus Discovery)
AI also proposed exposing configuration management via REST API (10 endpoints): Platform Config:preview endpoint is brilliant—it shows what config would resolve to without saving:
Week 7 vs Week 6: The Pattern Repeats
- Week 6: AWS Clients
- Week 7: Config Middleware
- The Pattern
Input: ADR-0010 (data isolation)AI Output: 4-scope client factoryHuman Addition: Credential cachingResult: 2,364 lines, 39 tests, 0 bugsTime: 3 days
Key Learnings This Week
Learning 1: Reuse Scope Extraction
Learning 1: Reuse Scope Extraction
What worked: ConfigMiddleware reused the
CapsuleExtractor we built in Week 6 for AWS clients.Why it worked: Both patterns need the same scope information (tenant + capsule). Extract once, use everywhere.New principle: When building infrastructure, design composable pieces that work together. Week 6’s middleware became Week 7’s foundation.Learning 2: Compiler Enforcement > Documentation
Learning 2: Compiler Enforcement > Documentation
What we learned: Making config injection type-safe means handlers can’t compile without it.Why it matters: Documentation can be ignored. Compilation can’t.Example: Handler declares
config: web::ReqData<ConfigContext> → won’t compile unless middleware is registered → zero runtime errors.Contrast: Before, handlers could forget to call ConfigService.get() → runtime errors in production.Learning 3: Preview Endpoints Prevent Misconfigurations
Learning 3: Preview Endpoints Prevent Misconfigurations
AI’s insight: Add a preview endpoint that shows effective config without saving.Why brilliant: Admins can see the full hierarchy (platform → tenant → capsule) before committing changes.Real-world save: Prevented setting dev-level JWT timeout (300s) in production capsule. Preview showed it would override the enterprise tenant config (7200s).
Learning 4: Week 6's Formula Works Again
Learning 4: Week 6's Formula Works Again
Confirmation: The ADR-driven design approach from Week 6 works for config too.The formula:
- Clear inputs (hierarchy requirements)
- AI design (middleware pattern)
- Human optimization (caching, ordering)
- Atomic implementation
- Thorough testing
Metrics: Week 7 By The Numbers
- Code Reduction
- Performance
- Quality
Removed:
- Boilerplate: 340 lines (17 handlers × 20 lines each)
- Manual ConfigService.get() calls: 17
- Inconsistent error handling blocks: 17
- Middleware: 179 lines
- Service layer: 892 lines
- REST API: 456 lines
- Tests: 942 lines (28 tests)
Actionable Takeaways
Based on Week 6 and Week 7’s successes:- Middleware over manual calls - Inject dependencies via middleware so handlers can’t forget. Compiler enforcement beats documentation.
- Cache at the service layer - Put Moka/Redis in front of your config backend. Our 5-min TTL gives 99.2% hit rate.
- Preview before commit - Add preview endpoints that show effective config without saving. Prevents production misconfigurations.
- Reuse scope extraction - If you have tenant/capsule context in one place (Week 6), reuse it everywhere (Week 7).
-
Type-safe injection - Use framework features (Actix
web::ReqData<T>) to make dependencies compile-time checked.
The Consistency: Weeks 6 and 7
Week 6 taught us: AI excels at proactive design given clear constraints Week 7 proved: That wasn’t a fluke. Same formula works again. The emerging pattern:- ❌ “Fix these errors” → Disaster (Week 5)
- ✅ “Design pattern meeting these constraints” → Excellence (Weeks 6-7)
What’s Next
Week 8 Preview: We have patterns (AWS clients, config middleware) that enforce isolation and hierarchy. Next: How do we test these multi-layered systems? The testing infrastructure that validates tenant isolation, config hierarchy, and AWS client scoping. The hypothesis: If ADR-driven design worked for clients and config, it should work for comprehensive testing too.Discuss This Week
How do you handle configuration in multi-tenant systems? Manual lookups or automatic injection?
Share your middleware patterns or ask about the hierarchical config approach.
Disclaimer: All examples are from personal projects. No proprietary code or employer-specific
patterns included.