# Story 3.11: Vhost Validation Middleware

Status: done

## Story

As a developer,
I want all topology operations to validate vhost existence before execution,
so that operations fail fast with clear errors instead of obscure HTTP 404 responses.

## Acceptance Criteria

1. **Given** any topology operation (queues, exchanges, bindings) **When** operation is executed with vhost="/invalid" **Then** validation occurs before HTTP API call
2. **And** non-existent vhost returns error: "Virtual host '/invalid' does not exist. Available vhosts: [/, /staging, /prod]"
3. **And** validation check completes in <50ms
4. **And** validation result is cached (TTL: 5 minutes) to avoid repeated checks
5. **And** vhost existence check uses: GET /api/vhosts
6. **And** vhost list is refreshed when creation/deletion operations occur

## Tasks / Subtasks

- [ ] **Task 1: Create VhostValidator Middleware Class** (AC: #1, #3, #4)
  - [ ] Create `VhostValidator` class in `src/rabbitmq_mcp_connection/middleware/vhost_validator.py`
  - [ ] Implement singleton pattern for shared cache across operations
  - [ ] Add cached vhost list with TTL (5 minutes default, configurable)
  - [ ] Implement `validate_vhost(vhost: str, http_client: HTTPClientManager) -> None` async method
  - [ ] Raise `VhostNotFoundError` with helpful message listing available vhosts
  - [ ] Add `_fetch_vhosts()` private method to query GET /api/vhosts
  - [ ] Add `clear_cache()` method for manual cache invalidation
  - [ ] Write unit tests with mocked HTTP responses (15+ tests)

- [ ] **Task 2: Implement Vhost Caching with TTL** (AC: #4)
  - [ ] Use `asyncio` TTLCache or custom implementation with timestamp tracking
  - [ ] Store vhost list with expiry timestamp: `{"vhosts": [...], "expires_at": timestamp}`
  - [ ] Check cache on every validation: if expired, refetch; else use cached list
  - [ ] Add cache hit/miss metrics for monitoring
  - [ ] Add configurable TTL parameter (default: 300 seconds)
  - [ ] Write unit tests for cache expiration behavior (10+ tests)

- [ ] **Task 3: Create VhostNotFoundError Exception** (AC: #2)
  - [ ] Create custom exception `VhostNotFoundError` in `src/rabbitmq_mcp_connection/exceptions.py`
  - [ ] Inherit from `RabbitMQOperationError` (or base exception class)
  - [ ] Include vhost name and available vhosts list in exception message
  - [ ] Format message: "Virtual host '{vhost}' does not exist. Available vhosts: {available_list}"
  - [ ] Add error_code: "VHOST_NOT_FOUND"
  - [ ] Write unit tests for exception creation and message formatting (5+ tests)

- [ ] **Task 4: Integrate Validation into Topology Operations** (AC: #1, #6)
  - [ ] Add `@validate_vhost` decorator OR call `VhostValidator.validate_vhost()` at start of each operation
  - [ ] Update all topology operations in `src/rabbitmq_mcp_connection/operations/topology.py`:
    - [ ] ListQueuesOperation
    - [ ] CreateQueueOperation
    - [ ] DeleteQueueOperation
    - [ ] PurgeQueueOperation
    - [ ] ListExchangesOperation
    - [ ] CreateExchangeOperation
    - [ ] DeleteExchangeOperation
    - [ ] ListBindingsOperation
    - [ ] CreateBindingOperation
    - [ ] DeleteBindingOperation
  - [ ] Validation should occur BEFORE parameter validation (fail fast)
  - [ ] Pass HTTPClientManager instance to validator
  - [ ] Write unit tests verifying validation call in each operation (20+ tests)

- [ ] **Task 5: Implement Cache Refresh on Vhost Mutations** (AC: #6)
  - [ ] Identify vhost mutation operations: vhost create, vhost delete (if implemented, or planned for future stories)
  - [ ] Call `VhostValidator.clear_cache()` after successful vhost creation/deletion
  - [ ] If vhost operations not yet implemented, document for future epic (Epic 4 or later)
  - [ ] Add note in dev notes: "Cache invalidation for vhost mutations will be added when vhost management operations are implemented"
  - [ ] Write unit tests for cache invalidation behavior (5+ tests)

- [ ] **Task 6: Add Structured Logging for Validation Events** (AC: #3)
  - [ ] Log validation start: `{"event": "vhost.validation.start", "vhost": vhost, "correlation_id": correlation_id}`
  - [ ] Log cache hit: `{"event": "vhost.validation.cache_hit", "vhost": vhost, "cached_vhosts_count": count}`
  - [ ] Log cache miss: `{"event": "vhost.validation.cache_miss", "vhost": vhost, "refetch": true}`
  - [ ] Log validation success: `{"event": "vhost.validation.success", "vhost": vhost, "duration_ms": duration}`
  - [ ] Log validation failure: `{"event": "vhost.validation.failed", "vhost": vhost, "available_vhosts": available_list, "duration_ms": duration}`
  - [ ] Use structlog for structured JSON logging following ADR-009 patterns
  - [ ] Write tests to verify log output structure and correlation_id presence (8+ tests)

- [ ] **Task 7: Add Performance Monitoring** (AC: #3)
  - [ ] Track validation duration (target: <50ms)
  - [ ] Log warning if validation exceeds threshold: `{"event": "vhost.validation.slow", "duration_ms": duration, "threshold_ms": 50}`
  - [ ] Add metrics: vhost_validation_duration_ms, vhost_validation_cache_hit_ratio
  - [ ] Monitor cache effectiveness: log cache hit ratio periodically
  - [ ] Write tests to verify performance monitoring and slow validation warnings (5+ tests)

- [ ] **Task 8: Integration Testing** (AC: #1, #2, #3, #4, #5, #6)
  - [ ] Write integration tests in `tests/integration/test_vhost_validator.py`
  - [ ] Test successful validation with existing vhost (e.g., "/" default vhost)
  - [ ] Test validation failure with non-existent vhost (verify error message format)
  - [ ] Test cache behavior: first call fetches, second call uses cache (verify via log inspection)
  - [ ] Test cache expiration: wait for TTL, verify refetch on next validation
  - [ ] Test performance: verify validation completes in <50ms (cache hit and miss scenarios)
  - [ ] Test integration with topology operations: create queue with invalid vhost, verify VhostNotFoundError
  - [ ] Use real RabbitMQ instance (testcontainers) for integration tests
  - [ ] Verify all integration tests pass (10+ tests)

- [ ] **Task 9: Update Operation Documentation** (AC: #2)
  - [ ] Update docstrings in topology operations to mention vhost validation
  - [ ] Document VhostNotFoundError in operation error handling sections
  - [ ] Add example error messages to operation documentation
  - [ ] Update README or API reference with vhost validation behavior
  - [ ] Document cache TTL configuration option

## Dev Notes

### Architecture Patterns and Constraints

**From Epic 3 Tech Spec [Source: docs-bmad/sprint-artifacts/tech-spec-epic-3.md#VhostValidator]:**
- HTTP GET /api/vhosts endpoint returns list of all virtual hosts: `[{"name": "/"}, {"name": "/staging"}, ...]`
- Vhost names can contain: letters, digits, hyphen, underscore, period
- Special encoding for vhost in URLs: "/" becomes "%2F" (URL encoding)
- Common vhosts: "/" (default), "/staging", "/prod", "/dev"
- Vhost validation should be transparent to operations (middleware pattern)

**Middleware Design Pattern [Source: docs-bmad/architecture/implementation-patterns.md]:**
- Implement as reusable middleware component (VhostValidator class)
- Can be applied as decorator (@validate_vhost) OR called explicitly at operation start
- Centralized validation logic reduces duplication across 10+ topology operations
- Singleton pattern ensures shared cache across all operations
- Follows ADR-002 semantic discovery pattern for operation integration

**Caching Strategy [Source: tech-spec-epic-3.md#Performance-Requirements]:**
- TTL-based cache (5 minutes default) balances freshness vs performance
- Vhost list changes infrequently in production environments
- Cache miss penalty: single HTTP GET request (~50-100ms)
- Cache hit: validation in <1ms (in-memory lookup)
- Cache invalidation on vhost mutations follows ADR pattern for data freshness

**Performance Requirements [Source: tech-spec-epic-3.md#Non-Functional-Constraints]:**
- Validation target: <50ms (includes cache miss + HTTP roundtrip)
- Typical cache hit: <1ms (in-memory check)
- Cache miss: <100ms (HTTP GET /api/vhosts + parsing)
- Background refresh could be added later to eliminate cache miss latency

### Project Structure Notes

**From Unified Project Structure [Source: docs-bmad/architecture/project-structure.md]:**

**New Files to Create:**
- `src/rabbitmq_mcp_connection/middleware/__init__.py` - New middleware package
- `src/rabbitmq_mcp_connection/middleware/vhost_validator.py` - VhostValidator class
- `src/rabbitmq_mcp_connection/exceptions.py` - Add VhostNotFoundError (if not exists, create file)
- `tests/unit/rabbitmq_mcp_connection/middleware/__init__.py`
- `tests/unit/rabbitmq_mcp_connection/middleware/test_vhost_validator.py` - Unit tests for validator
- `tests/integration/test_vhost_validator.py` - Integration tests with real RabbitMQ

**Files to Modify:**
- `src/rabbitmq_mcp_connection/operations/topology.py` - Add vhost validation to all 10 topology operations
- `src/rabbitmq_mcp_connection/__init__.py` - Export VhostValidator and VhostNotFoundError

**Dependencies:**
- HTTPClientManager (Story 2.3) - HTTP API client for GET /api/vhosts [Source: tech-spec-epic-2.md]
- structlog (Epic 7) - Structured logging with correlation_id tracking [Source: ADR-009]
- asyncio - For async/await and TTL cache implementation
- pytest and pytest-asyncio for testing [Source: architecture/implementation-patterns.md#Testing]

### Testing Strategy

**From Testing Architecture [Source: docs-bmad/architecture/implementation-patterns.md#Testing-Strategy]:**

**Unit Tests (50+ tests total):**
- VhostValidator class: cache logic, TTL expiration, validation logic
- VhostNotFoundError: exception creation, message formatting
- Decorator/integration: verify validation is called in operations
- Edge cases: empty vhost list, malformed API responses, network errors
- Follow pytest patterns with mocked HTTPClientManager responses
- Test coverage target: >90% for new middleware code

**Integration Tests (10+ tests):**
- Real RabbitMQ instance with testcontainers (docker-based testing)
- Test validation with default "/" vhost (success case)
- Test validation with non-existent vhost (error case)
- Test cache behavior: verify cache hit after first fetch
- Test cache expiration: wait for TTL, verify refetch
- Test performance: <50ms validation time (NFR-Performance)
- Test integration with operations: verify operations fail fast with VhostNotFoundError
- Use structured log assertions to verify ADR-009 compliance (correlation_id present)

**Performance Tests [Source: tech-spec-epic-3.md#Performance-Requirements]:**
- Measure validation latency (cache hit: <1ms, cache miss: <100ms)
- Stress test: 1000+ validation calls to verify cache effectiveness
- Monitor memory usage with large vhost lists (edge case: 1000+ vhosts)
- Performance monitoring follows NFR-Performance requirements from architecture

### Learnings from Previous Story

**From Story 3-10-delete-binding-operation (Status: done)**

**Reusable Patterns:**
- Follow structured logging pattern: `{resource}.{action}.{status}` event naming convention [Source: ADR-009]
- Use same HTTPClientManager instance from Story 2.3 with connection pooling
- Follow Operation base class interface pattern (if creating decorator, ensure compatibility)
- Performance monitoring with threshold warnings (50ms for validation vs 100ms for operations)
- Correlation ID propagation for distributed tracing (ADR-009 compliance)

**Implementation Lessons:**
- Pre-validation pattern works well: check before executing expensive operation
- User-friendly error messages are critical: "Verify X exists" vs generic "404 Not Found"
- Reuse existing schemas and exceptions (don't duplicate)
- Comprehensive unit tests prevent integration test failures (229 unit tests in 3.10)

**Testing Patterns to Follow:**
- Mock HTTPClientManager responses for unit tests (avoid real network calls)
- Use testcontainers with real RabbitMQ for integration tests
- Test edge cases: empty lists, non-existent resources, network timeouts
- Verify structured log output in tests (assert on event names and correlation_id)

**Technical Debt Notes:**
- None from Story 3.10 - clean implementation
- All acceptance criteria met, no deferred items

**Key Files to Reference:**
- `src/rabbitmq_mcp_connection/operations/topology.py` - Location where validation will be integrated
- `tests/integration/test_binding_operations.py` - Integration test patterns with testcontainers
- `src/rabbitmq_mcp_connection/schemas/topology.py` - Schema patterns for requests/responses

**Unresolved Review Items from Story 3-10:**
- Review section shows ✅ APPROVED with zero high/medium/low severity issues
- All 7 acceptance criteria fully implemented
- All 8 tasks completed and verified
- No pending action items or follow-ups requiring attention in this story
- Story 3.10 provides excellent baseline for middleware patterns

[Source: stories/3-10-delete-binding-operation.md#Dev-Agent-Record]
[Source: stories/3-10-delete-binding-operation.md#Senior-Developer-Review]

### Implementation Strategy

**Phase 1: Core Validator (Tasks 1-3)**
1. Create VhostValidator class with caching logic
2. Implement TTL-based cache with asyncio
3. Create VhostNotFoundError exception
4. Write comprehensive unit tests (30+ tests)

**Phase 2: Integration (Tasks 4-5)**
5. Integrate validation into all topology operations
6. Add cache refresh hooks (document for future vhost operations)
7. Write integration tests for operations (20+ tests)

**Phase 3: Observability (Tasks 6-7)**
8. Add structured logging for validation events
9. Add performance monitoring and metrics
10. Write tests for logging and metrics (13+ tests)

**Phase 4: Documentation and Validation (Tasks 8-9)**
11. Integration testing with real RabbitMQ
12. Update operation documentation
13. Performance testing and optimization

### References

- [Source: docs-bmad/epics/epic-3-topology-operations.md#Story-3.11] - Story origin and acceptance criteria
- [Source: docs-bmad/sprint-artifacts/tech-spec-epic-3.md#Vhost-Validation] - Technical specification for vhost validation middleware
- [Source: docs-bmad/sprint-artifacts/tech-spec-epic-3.md#VhostValidator-Component] - Component architecture details
- [Source: docs-bmad/sprint-artifacts/tech-spec-epic-3.md#Performance-Requirements] - Performance constraints and targets
- [Source: docs-bmad/sprint-artifacts/3-10-delete-binding-operation.md#Dev-Agent-Record] - Previous story patterns and completion notes
- [Source: docs-bmad/sprint-artifacts/3-10-delete-binding-operation.md#Senior-Developer-Review] - Review findings and recommendations
- [Source: docs-bmad/architecture/architecture-decision-records-adrs.md#ADR-009] - Structured Logging with structlog and correlation_id
- [Source: docs-bmad/architecture/implementation-patterns.md#Middleware-Pattern] - Middleware implementation patterns
- [Source: docs-bmad/architecture/implementation-patterns.md#Testing-Strategy] - Testing patterns and coverage requirements
- [Source: docs-bmad/architecture/performance-considerations.md#Caching-Strategies] - Caching patterns and TTL recommendations
- [Source: RabbitMQ Management API Documentation - GET /api/vhosts](https://www.rabbitmq.com/docs/management-http-api#get-vhosts) - API endpoint reference

## Dev Agent Record

### Context Reference

<!-- Path(s) to story context XML will be added here by context workflow -->

### Agent Model Used

{{agent_model_name_version}}

### Debug Log References

### Completion Notes List

**Completed:** 2026-02-12
**Definition of Done:** All acceptance criteria met, code reviewed, tests passing

### File List
