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

@@ -13,7 +13,8 @@ final readonly class DependencyEdge
private ClassName $target,
private DependencyRelation $relation,
private int $weight = 1
) {}
) {
}
/**
* Create a dependency edge
@@ -124,6 +125,7 @@ final readonly class DependencyEdge
public function toString(): string
{
$arrow = $this->isStrong() ? ' => ' : ' -> ';
return sprintf(
'%s%s%s (%s, weight: %d)',
$this->source->getShortName(),
@@ -138,4 +140,4 @@ final readonly class DependencyEdge
{
return $this->toString();
}
}
}

View File

@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace App\Framework\Discovery\ValueObjects;
use App\Framework\Core\ValueObjects\ClassName;
use InvalidArgumentException;
final readonly class DependencyGraph
{
@@ -123,7 +122,7 @@ final readonly class DependencyGraph
foreach ($this->nodes as $node) {
$className = $node->getClassName()->toString();
if (!isset($visited[$className])) {
if (! isset($visited[$className])) {
$this->dfsForCycles($node, $visited, $recursionStack, $cycles, []);
}
}
@@ -139,7 +138,7 @@ final readonly class DependencyGraph
public function getHighestDependencyNodes(int $limit = 10): array
{
$nodes = array_values($this->nodes);
usort($nodes, fn($a, $b) => $b->getDependencyCount() <=> $a->getDependencyCount());
usort($nodes, fn ($a, $b) => $b->getDependencyCount() <=> $a->getDependencyCount());
return array_slice($nodes, 0, $limit);
}
@@ -152,7 +151,7 @@ final readonly class DependencyGraph
public function getMostUsedNodes(int $limit = 10): array
{
$nodes = array_values($this->nodes);
usort($nodes, fn($a, $b) => $b->getDependentCount() <=> $a->getDependentCount());
usort($nodes, fn ($a, $b) => $b->getDependentCount() <=> $a->getDependentCount());
return array_slice($nodes, 0, $limit);
}
@@ -164,7 +163,7 @@ final readonly class DependencyGraph
*/
public function getLeafNodes(): array
{
return array_filter($this->nodes, fn(DependencyNode $node) => $node->isLeaf());
return array_filter($this->nodes, fn (DependencyNode $node) => $node->isLeaf());
}
/**
@@ -174,7 +173,7 @@ final readonly class DependencyGraph
*/
public function getRootNodes(): array
{
return array_filter($this->nodes, fn(DependencyNode $node) => $node->isRoot());
return array_filter($this->nodes, fn (DependencyNode $node) => $node->isRoot());
}
/**
@@ -186,7 +185,7 @@ final readonly class DependencyGraph
{
return array_filter(
$this->nodes,
fn(DependencyNode $node) => $node->getType() === $type
fn (DependencyNode $node) => $node->getType() === $type
);
}
@@ -201,6 +200,7 @@ final readonly class DependencyGraph
}
$visited = [];
return $this->calculateDepth($node, $visited);
}
@@ -271,11 +271,11 @@ final readonly class DependencyGraph
return [
'statistics' => $this->getStatistics(),
'nodes' => array_map(
fn(DependencyNode $node) => $node->toArray(),
fn (DependencyNode $node) => $node->toArray(),
array_values($this->nodes)
),
'edges' => array_map(
fn(DependencyEdge $edge) => $edge->toArray(),
fn (DependencyEdge $edge) => $edge->toArray(),
$this->edges
),
'circular_dependencies' => $this->findCircularDependencies(),
@@ -289,13 +289,13 @@ final readonly class DependencyGraph
{
$graph = $this;
if (!$this->hasNode($source)) {
if (! $this->hasNode($source)) {
$sourceType = DependencyType::fromClassName($source->toString());
$sourceNode = DependencyNode::create($source, $sourceType);
$graph = $graph->addNode($sourceNode);
}
if (!$this->hasNode($target)) {
if (! $this->hasNode($target)) {
$targetType = DependencyType::fromClassName($target->toString());
$targetNode = DependencyNode::create($target, $targetType);
$graph = $graph->addNode($targetNode);
@@ -333,7 +333,7 @@ final readonly class DependencyGraph
if ($cycleStart !== false) {
$cycles[] = array_slice($currentPath, $cycleStart);
}
} elseif (!isset($visited[$targetClassName])) {
} elseif (! isset($visited[$targetClassName])) {
$targetNode = $this->getNode($edge->getTarget());
if ($targetNode !== null) {
$this->dfsForCycles($targetNode, $visited, $recursionStack, $cycles, $currentPath);
@@ -370,6 +370,7 @@ final readonly class DependencyGraph
}
unset($visited[$className]);
return $maxDepth;
}
@@ -397,7 +398,7 @@ final readonly class DependencyGraph
foreach ($from->getDependencies() as $edge) {
$nextClassName = $edge->getTarget()->toString();
if (!isset($visited[$nextClassName])) {
if (! isset($visited[$nextClassName])) {
$nextNode = $this->getNode($edge->getTarget());
if ($nextNode !== null && $this->findPath($nextNode, $to, $visited, $path)) {
return true;
@@ -406,6 +407,7 @@ final readonly class DependencyGraph
}
array_pop($path);
return false;
}
@@ -418,6 +420,7 @@ final readonly class DependencyGraph
foreach ($this->nodes as $node) {
$max = max($max, $node->getDependencyCount());
}
return $max;
}
@@ -430,6 +433,7 @@ final readonly class DependencyGraph
foreach ($this->nodes as $node) {
$max = max($max, $node->getDependentCount());
}
return $max;
}
}
}

View File

@@ -122,6 +122,7 @@ final readonly class DependencyNode
return true;
}
}
return false;
}
@@ -160,7 +161,7 @@ final readonly class DependencyNode
public function getDependencyNames(): array
{
return array_map(
fn(DependencyEdge $edge) => $edge->getTarget()->toString(),
fn (DependencyEdge $edge) => $edge->getTarget()->toString(),
$this->dependencies
);
}
@@ -173,7 +174,7 @@ final readonly class DependencyNode
public function getDependentNames(): array
{
return array_map(
fn(DependencyEdge $edge) => $edge->getSource()->toString(),
fn (DependencyEdge $edge) => $edge->getSource()->toString(),
$this->dependents
);
}
@@ -195,11 +196,11 @@ final readonly class DependencyNode
'is_root' => $this->isRoot(),
'has_circular_dependency' => $this->hasCircularDependency(),
'dependencies' => array_map(
fn(DependencyEdge $edge) => $edge->toArray(),
fn (DependencyEdge $edge) => $edge->toArray(),
$this->dependencies
),
'dependents' => array_map(
fn(DependencyEdge $edge) => $edge->toArray(),
fn (DependencyEdge $edge) => $edge->toArray(),
$this->dependents
),
];
@@ -224,4 +225,4 @@ final readonly class DependencyNode
{
return $this->toString();
}
}
}

View File

@@ -150,4 +150,4 @@ enum DependencyRelation: string
{
return $this->value;
}
}
}

View File

@@ -194,4 +194,4 @@ enum DependencyType: string
{
return $this->value;
}
}
}

View File

@@ -7,7 +7,7 @@ namespace App\Framework\Discovery\ValueObjects;
use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Core\ValueObjects\MethodName;
use App\Framework\Filesystem\FilePath;
use App\Framework\Filesystem\ValueObjects\FilePath;
use Attribute;
/**

View File

@@ -6,7 +6,7 @@ namespace App\Framework\Discovery\ValueObjects;
use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Filesystem\File;
use App\Framework\Filesystem\FilePath;
use App\Framework\Filesystem\ValueObjects\FilePath;
/**
* Context information for file processing

View File

@@ -6,7 +6,7 @@ namespace App\Framework\Discovery\ValueObjects;
use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Filesystem\FilePath;
use App\Framework\Filesystem\ValueObjects\FilePath;
/**
* Immutable value object for interface implementation mappings

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace App\Framework\Discovery\ValueObjects;
use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Filesystem\FilePath;
use App\Framework\Filesystem\ValueObjects\FilePath;
use App\Framework\Reflection\WrappedReflectionClass;
/**

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace App\Framework\Discovery\ValueObjects;
use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Filesystem\FilePath;
use App\Framework\Filesystem\ValueObjects\FilePath;
use ArrayIterator;
use Countable;
use IteratorAggregate;

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace App\Framework\Discovery\ValueObjects;
use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Filesystem\FilePath;
use App\Framework\Filesystem\ValueObjects\FilePath;
/**
* Immutable value object for template mappings