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,168 @@
<?php
declare(strict_types=1);
namespace Tests\Unit\Framework\Logging;
use App\Framework\Logging\ValueObjects\CorrelationId;
use PHPUnit\Framework\TestCase;
final class CorrelationIdTest extends TestCase
{
public function test_creates_from_string(): void
{
$id = CorrelationId::fromString('test-correlation-id-123');
$this->assertEquals('test-correlation-id-123', $id->toString());
$this->assertEquals('test-correlation-id-123', (string) $id);
}
public function test_generates_uuid_format(): void
{
$id = CorrelationId::generate();
$this->assertTrue($id->isUuid());
$this->assertFalse($id->isUlid());
$this->assertMatchesRegularExpression(
'/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i',
$id->toString()
);
}
public function test_generates_ulid_format(): void
{
$id = CorrelationId::generateUlid();
$this->assertTrue($id->isUlid());
$this->assertFalse($id->isUuid());
$this->assertEquals(26, strlen($id->toString()));
}
public function test_rejects_empty_string(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('cannot be empty');
CorrelationId::fromString('');
}
public function test_rejects_too_long_string(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('too long');
CorrelationId::fromString(str_repeat('a', 256));
}
public function test_rejects_invalid_characters(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('invalid characters');
CorrelationId::fromString('test-id-with-invalid-chars-äöü');
}
public function test_allows_valid_characters(): void
{
$validIds = [
'simple-id-123',
'UPPERCASE-ID-456',
'mixed_Case-ID_789',
'12345-67890',
'a_b-c_d-e_f',
];
foreach ($validIds as $validId) {
$id = CorrelationId::fromString($validId);
$this->assertEquals($validId, $id->toString());
}
}
public function test_to_short_string(): void
{
$id = CorrelationId::fromString('very-long-correlation-id-123456789');
$this->assertEquals('very-lon', $id->toShortString());
}
public function test_equals(): void
{
$id1 = CorrelationId::fromString('test-123');
$id2 = CorrelationId::fromString('test-123');
$id3 = CorrelationId::fromString('test-456');
$this->assertTrue($id1->equals($id2));
$this->assertFalse($id1->equals($id3));
}
public function test_json_serializable(): void
{
$id = CorrelationId::fromString('test-json-123');
$json = json_encode(['id' => $id]);
$this->assertEquals('{"id":"test-json-123"}', $json);
}
public function test_from_globals_with_correlation_header(): void
{
$_SERVER['HTTP_X_CORRELATION_ID'] = 'header-correlation-123';
$id = CorrelationId::fromGlobals();
$this->assertEquals('header-correlation-123', $id->toString());
unset($_SERVER['HTTP_X_CORRELATION_ID']);
}
public function test_from_globals_fallback_to_request_id(): void
{
$_SERVER['HTTP_X_REQUEST_ID'] = 'request-id-456';
$id = CorrelationId::fromGlobals('X-Correlation-ID');
$this->assertEquals('request-id-456', $id->toString());
unset($_SERVER['HTTP_X_REQUEST_ID']);
}
public function test_from_globals_generates_when_no_header(): void
{
unset($_SERVER['HTTP_X_CORRELATION_ID'], $_SERVER['HTTP_X_REQUEST_ID']);
$id = CorrelationId::fromGlobals();
$this->assertTrue($id->isUuid());
}
public function test_from_globals_generates_when_invalid_header(): void
{
$_SERVER['HTTP_X_CORRELATION_ID'] = 'invalid-chars-äöü';
$id = CorrelationId::fromGlobals();
// Should generate new valid ID instead of using invalid one
$this->assertTrue($id->isUuid());
$this->assertNotEquals('invalid-chars-äöü', $id->toString());
unset($_SERVER['HTTP_X_CORRELATION_ID']);
}
public function test_creates_from_uuid(): void
{
$uuid = \Ramsey\Uuid\Uuid::uuid4();
$id = CorrelationId::fromUuid($uuid);
$this->assertEquals($uuid->toString(), $id->toString());
$this->assertTrue($id->isUuid());
}
public function test_creates_from_ulid(): void
{
$ulid = \App\Framework\Ulid\Ulid::generate();
$id = CorrelationId::fromUlid($ulid);
$this->assertEquals((string) $ulid, $id->toString());
$this->assertTrue($id->isUlid());
}
}