feat(Production): Complete production deployment infrastructure

- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
This commit is contained in:
2025-10-25 19:18:37 +02:00
parent caa85db796
commit fc3d7e6357
83016 changed files with 378904 additions and 20919 deletions

View File

@@ -0,0 +1,144 @@
<?php
declare(strict_types=1);
use App\Application\LiveComponents\Dashboard\QueueStatsComponent;
use App\Application\LiveComponents\Dashboard\QueueStatsState;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\Queue\Queue;
use App\Framework\Queue\Services\JobMetricsManagerInterface;
use App\Framework\Queue\ValueObjects\JobMetrics;
use App\Framework\Core\ValueObjects\Duration;
describe('QueueStatsComponent', function () {
beforeEach(function () {
// Mock Queue
$this->queue = Mockery::mock(Queue::class);
// Mock JobMetricsManager
$this->metricsManager = Mockery::mock(JobMetricsManagerInterface::class);
$this->componentId = ComponentId::create('queue-stats', 'test');
$this->initialState = QueueStatsState::empty();
});
afterEach(function () {
Mockery::close();
});
it('polls and updates state with queue statistics', function () {
// Mock queue stats
$this->queue->shouldReceive('getStats')
->once()
->andReturn([
'total_size' => 42,
'priority_breakdown' => ['high' => 10, 'medium' => 20, 'low' => 12],
]);
$this->queue->shouldReceive('size')
->once()
->andReturn(42);
// Mock metrics
$jobMetrics = new JobMetrics(
totalJobs: 1000,
successfulJobs: 950,
failedJobs: 50,
avgExecutionTime: Duration::fromMilliseconds(123.45),
successRate: 95.0
);
$this->metricsManager->shouldReceive('getAllQueueMetrics')
->once()
->with('1 hour')
->andReturn([$jobMetrics]);
$component = new QueueStatsComponent(
id: $this->componentId,
state: $this->initialState,
queue: $this->queue,
metricsManager: $this->metricsManager
);
$newState = $component->poll();
expect($newState)->toBeInstanceOf(QueueStatsState::class);
expect($newState->currentQueueSize)->toBe(42);
expect($newState->totalJobs)->toBe(1000);
expect($newState->successfulJobs)->toBe(950);
expect($newState->failedJobs)->toBe(50);
expect($newState->successRate)->toBe(95.0);
expect($newState->avgExecutionTimeMs)->toBe(123.45);
expect($newState->lastUpdated)->not->toBe($this->initialState->lastUpdated);
});
it('has correct poll interval', function () {
$component = new QueueStatsComponent(
id: $this->componentId,
state: $this->initialState,
queue: $this->queue,
metricsManager: $this->metricsManager
);
expect($component->getPollInterval())->toBe(5000);
});
it('returns correct render data', function () {
$state = new QueueStatsState(
currentQueueSize: 10,
totalJobs: 100,
successfulJobs: 90,
failedJobs: 10,
successRate: 90.0,
avgExecutionTimeMs: 50.0,
lastUpdated: '2024-01-15 12:00:00'
);
$component = new QueueStatsComponent(
id: $this->componentId,
state: $state,
queue: $this->queue,
metricsManager: $this->metricsManager
);
$renderData = $component->getRenderData();
expect($renderData->templatePath)->toBe('livecomponent-queue-stats');
expect($renderData->data)->toHaveKey('componentId');
expect($renderData->data)->toHaveKey('stateJson');
expect($renderData->data)->toHaveKey('pollInterval');
expect($renderData->data['pollInterval'])->toBe(5000);
expect($renderData->data['currentQueueSize'])->toBe(10);
expect($renderData->data['totalJobs'])->toBe(100);
expect($renderData->data['successRate'])->toBe(90.0);
});
it('handles empty metrics gracefully', function () {
$this->queue->shouldReceive('getStats')
->once()
->andReturn(['total_size' => 0]);
$this->queue->shouldReceive('size')
->once()
->andReturn(0);
$this->metricsManager->shouldReceive('getAllQueueMetrics')
->once()
->with('1 hour')
->andReturn([]);
$component = new QueueStatsComponent(
id: $this->componentId,
state: $this->initialState,
queue: $this->queue,
metricsManager: $this->metricsManager
);
$newState = $component->poll();
expect($newState->currentQueueSize)->toBe(0);
expect($newState->totalJobs)->toBe(0);
expect($newState->successfulJobs)->toBe(0);
expect($newState->failedJobs)->toBe(0);
});
});