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

@@ -185,7 +185,7 @@ it('can be created without ProcessorManager', function () {
$logger->info('Test message');
expect($processedRecord)->not->toBeNull();
expect($processedRecord)->toBeInstanceOf(LogRecord::class);
expect($processedRecord->getMessage())->toBe('Test message');
});
@@ -225,11 +225,33 @@ it('logs with LogContext including tags', function () {
it('provides channel loggers for different log channels', function () {
$logger = new DefaultLogger();
expect($logger->security)->not->toBeNull();
expect($logger->cache)->not->toBeNull();
expect($logger->database)->not->toBeNull();
expect($logger->framework)->not->toBeNull();
expect($logger->error)->not->toBeNull();
// Test that channel() method returns Logger & HasChannel instances
$securityLogger = $logger->channel(LogChannel::SECURITY);
expect($securityLogger->channel)->toBe(LogChannel::SECURITY);
$cacheLogger = $logger->channel(LogChannel::CACHE);
expect($cacheLogger->channel)->toBe(LogChannel::CACHE);
$databaseLogger = $logger->channel(LogChannel::DATABASE);
expect($databaseLogger->channel)->toBe(LogChannel::DATABASE);
$frameworkLogger = $logger->channel(LogChannel::FRAMEWORK);
expect($frameworkLogger->channel)->toBe(LogChannel::FRAMEWORK);
$errorLogger = $logger->channel(LogChannel::ERROR);
expect($errorLogger->channel)->toBe(LogChannel::ERROR);
});
it('can get channel loggers using string names', function () {
$logger = new DefaultLogger();
// Test that channel() also accepts string channel names
$securityLogger = $logger->channel('security');
expect($securityLogger->channel)->toBe(LogChannel::SECURITY);
// Test that same channel returns same instance (singleton per channel)
$securityLogger2 = $logger->channel(LogChannel::SECURITY);
expect($securityLogger2)->toBe($securityLogger);
});
it('can log to specific channels using channel loggers', function () {
@@ -259,13 +281,13 @@ it('can log to specific channels using channel loggers', function () {
// Log to security channel with LogContext
$context = LogContext::withData(['ip' => '192.168.1.1'])->addTags('security');
$logger->security->warning('Unauthorized access attempt', $context);
$logger->channel(LogChannel::SECURITY)->warning('Unauthorized access attempt', $context);
expect($capturedChannel)->toBe(LogChannel::SECURITY->value);
expect($capturedMessage)->toBe('Unauthorized access attempt');
// Log to database channel without context
$logger->database->error('Connection failed');
$logger->channel(LogChannel::DATABASE)->error('Connection failed');
expect($capturedChannel)->toBe(LogChannel::DATABASE->value);
expect($capturedMessage)->toBe('Connection failed');
@@ -358,7 +380,7 @@ it('creates log records with correct timestamp', function () {
$logger->info('Test timestamp');
$afterLog = new \DateTimeImmutable('now', new \DateTimeZone('Europe/Berlin'));
expect($capturedRecord)->not->toBeNull();
expect($capturedRecord)->toBeInstanceOf(LogRecord::class);
expect($capturedRecord->getTimestamp())->toBeInstanceOf(\DateTimeImmutable::class);
$timestamp = $capturedRecord->getTimestamp();