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

@@ -7,7 +7,7 @@ namespace App\Framework\ErrorAggregation\Storage;
use App\Framework\Database\ConnectionInterface;
use App\Framework\ErrorAggregation\ErrorEvent;
use App\Framework\ErrorAggregation\ErrorPattern;
use App\Framework\ErrorAggregation\ErrorSeverity;
use App\Framework\Exception\Core\ErrorSeverity;
use App\Framework\Exception\ErrorCode;
use App\Framework\Ulid\Ulid;

View File

@@ -6,7 +6,7 @@ namespace App\Framework\ErrorAggregation\Storage;
use App\Framework\ErrorAggregation\ErrorEvent;
use App\Framework\ErrorAggregation\ErrorPattern;
use App\Framework\ErrorAggregation\ErrorSeverity;
use App\Framework\Exception\Core\ErrorSeverity;
/**
* Interface for error storage backends

View File

@@ -0,0 +1,220 @@
<?php
declare(strict_types=1);
namespace App\Framework\ErrorAggregation\Storage;
use App\Framework\ErrorAggregation\ErrorEvent;
use App\Framework\ErrorAggregation\ErrorPattern;
use App\Framework\Exception\Core\ErrorSeverity;
/**
* In-memory error storage for testing
*/
final class InMemoryErrorStorage implements ErrorStorageInterface
{
/** @var array<string, ErrorEvent> */
private array $events = [];
/** @var array<string, ErrorPattern> */
private array $patterns = [];
public function storeEvent(ErrorEvent $event): void
{
$this->events[(string) $event->id] = $event;
}
public function storeEventsBatch(array $events): void
{
foreach ($events as $event) {
$this->storeEvent($event);
}
}
public function storePattern(ErrorPattern $pattern): void
{
$this->patterns[(string) $pattern->id] = $pattern;
}
public function getPatternById(string $patternId): ?ErrorPattern
{
return $this->patterns[$patternId] ?? null;
}
public function getPatternByFingerprint(string $fingerprint): ?ErrorPattern
{
foreach ($this->patterns as $pattern) {
if ($pattern->fingerprint === $fingerprint) {
return $pattern;
}
}
return null;
}
public function getActivePatterns(int $limit = 50, int $offset = 0): array
{
$activePatterns = array_filter(
$this->patterns,
fn(ErrorPattern $pattern) => $pattern->isActive
);
return array_slice(array_values($activePatterns), $offset, $limit);
}
public function getPatternsByService(string $service, int $limit = 50): array
{
$servicePatterns = array_filter(
$this->patterns,
fn(ErrorPattern $pattern) => $pattern->service === $service
);
return array_slice(array_values($servicePatterns), 0, $limit);
}
public function getRecentEvents(int $limit = 100, ?ErrorSeverity $severity = null): array
{
$events = $this->events;
if ($severity !== null) {
$events = array_filter(
$events,
fn(ErrorEvent $event) => $event->severity === $severity
);
}
// Sort by occurredAt descending
usort($events, fn(ErrorEvent $a, ErrorEvent $b) =>
$b->occurredAt <=> $a->occurredAt
);
return array_slice($events, 0, $limit);
}
public function getStatistics(\DateTimeImmutable $from, \DateTimeImmutable $to): array
{
$eventsInRange = array_filter(
$this->events,
fn(ErrorEvent $event) =>
$event->occurredAt >= $from && $event->occurredAt <= $to
);
$bySeverity = [];
foreach ($eventsInRange as $event) {
$severity = $event->severity->value;
$bySeverity[$severity] = ($bySeverity[$severity] ?? 0) + 1;
}
$services = array_unique(array_map(
fn(ErrorEvent $event) => $event->service,
$eventsInRange
));
$users = array_unique(array_filter(array_map(
fn(ErrorEvent $event) => $event->userId,
$eventsInRange
)));
$ips = array_unique(array_filter(array_map(
fn(ErrorEvent $event) => $event->clientIp,
$eventsInRange
)));
return [
'total_events' => count($eventsInRange),
'by_severity' => $bySeverity,
'services_affected' => count($services),
'users_affected' => count($users),
'ips_affected' => count($ips),
];
}
public function getErrorTrends(
\DateTimeImmutable $from,
\DateTimeImmutable $to,
string $groupBy = 'hour'
): array {
$eventsInRange = array_filter(
$this->events,
fn(ErrorEvent $event) =>
$event->occurredAt >= $from && $event->occurredAt <= $to
);
$trends = [];
foreach ($eventsInRange as $event) {
$period = $event->occurredAt->format('Y-m-d H:00:00');
$trends[$period] = ($trends[$period] ?? 0) + 1;
}
return $trends;
}
public function getTopPatterns(int $limit = 10, ?string $service = null): array
{
$patterns = $this->patterns;
if ($service !== null) {
$patterns = array_filter(
$patterns,
fn(ErrorPattern $pattern) => $pattern->service === $service
);
}
usort($patterns, fn(ErrorPattern $a, ErrorPattern $b) =>
$b->occurrenceCount <=> $a->occurrenceCount
);
return array_slice($patterns, 0, $limit);
}
public function deleteOldEvents(\DateTimeImmutable $cutoffDate, ErrorSeverity $severity): int
{
$beforeCount = count($this->events);
$this->events = array_filter(
$this->events,
fn(ErrorEvent $event) =>
$event->occurredAt >= $cutoffDate || $event->severity !== $severity
);
return $beforeCount - count($this->events);
}
public function deleteOldPatterns(\DateTimeImmutable $cutoffDate): int
{
$beforeCount = count($this->patterns);
$this->patterns = array_filter(
$this->patterns,
fn(ErrorPattern $pattern) =>
$pattern->lastOccurrence >= $cutoffDate || $pattern->isActive
);
return $beforeCount - count($this->patterns);
}
public function exportEvents(
\DateTimeImmutable $from,
\DateTimeImmutable $to,
array $filters = []
): \Generator {
$eventsInRange = array_filter(
$this->events,
fn(ErrorEvent $event) =>
$event->occurredAt >= $from && $event->occurredAt <= $to
);
foreach ($eventsInRange as $event) {
yield $event->toArray();
}
}
public function getHealthStatus(): array
{
return [
'status' => 'healthy',
'event_count' => count($this->events),
'pattern_count' => count($this->patterns),
];
}
}