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,88 @@
<?php
declare(strict_types=1);
namespace App\Framework\Svg\Elements;
use App\Framework\Svg\ValueObjects\Geometry\Position;
use App\Framework\Svg\ValueObjects\Geometry\Radius;
use App\Framework\Svg\ValueObjects\Styling\Fill;
use App\Framework\Svg\ValueObjects\Styling\Stroke;
use App\Framework\Svg\ValueObjects\Transform\Transform;
/**
* Value Object representing SVG circle element
*/
final readonly class CircleElement implements SvgElement
{
public function __construct(
public Position $center,
public Radius $radius,
public Fill $fill,
public ?Stroke $stroke = null,
public ?Transform $transform = null,
public ?string $id = null,
public ?string $class = null
) {
}
public function getElementType(): string
{
return 'circle';
}
public function getAttributes(): array
{
$attributes = [
'cx' => sprintf('%.2f', $this->center->x),
'cy' => sprintf('%.2f', $this->center->y),
'r' => $this->radius->toSvgValue(),
...$this->fill->toSvgAttributes(),
];
if ($this->stroke !== null && $this->stroke->isVisible()) {
$attributes = [...$attributes, ...$this->stroke->toSvgAttributes()];
}
if ($this->transform !== null && $this->transform->hasTransformations()) {
$attributes['transform'] = $this->transform->toSvgValue();
}
if ($this->id !== null) {
$attributes['id'] = $this->id;
}
if ($this->class !== null) {
$attributes['class'] = $this->class;
}
return $attributes;
}
public function hasTransform(): bool
{
return $this->transform !== null && $this->transform->hasTransformations();
}
public function getTransform(): ?Transform
{
return $this->transform;
}
public function toSvg(): string
{
$attributeString = $this->buildAttributeString($this->getAttributes());
return "<circle {$attributeString} />";
}
private function buildAttributeString(array $attributes): string
{
$parts = [];
foreach ($attributes as $key => $value) {
$parts[] = sprintf('%s="%s"', $key, htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'));
}
return implode(' ', $parts);
}
}

View File

@@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
namespace App\Framework\Svg\Elements;
use App\Framework\Svg\ValueObjects\Transform\Transform;
/**
* Value Object representing SVG g (group) element
* Groups multiple elements together for transformation and styling
*/
final readonly class GroupElement implements SvgElement
{
/**
* @param array<SvgElement> $children
*/
public function __construct(
public array $children,
public ?Transform $transform = null,
public ?string $id = null,
public ?string $class = null
) {
}
public function getElementType(): string
{
return 'g';
}
public function getAttributes(): array
{
$attributes = [];
if ($this->transform !== null && $this->transform->hasTransformations()) {
$attributes['transform'] = $this->transform->toSvgValue();
}
if ($this->id !== null) {
$attributes['id'] = $this->id;
}
if ($this->class !== null) {
$attributes['class'] = $this->class;
}
return $attributes;
}
public function hasTransform(): bool
{
return $this->transform !== null && $this->transform->hasTransformations();
}
public function getTransform(): ?Transform
{
return $this->transform;
}
public function toSvg(): string
{
$attributes = $this->getAttributes();
$attributeString = empty($attributes)
? ''
: ' ' . $this->buildAttributeString($attributes);
$childrenSvg = implode("\n ", array_map(
fn (SvgElement $child) => $child->toSvg(),
$this->children
));
if (empty($childrenSvg)) {
return "<g{$attributeString} />";
}
return "<g{$attributeString}>\n {$childrenSvg}\n</g>";
}
private function buildAttributeString(array $attributes): string
{
$parts = [];
foreach ($attributes as $key => $value) {
$parts[] = sprintf('%s="%s"', $key, htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'));
}
return implode(' ', $parts);
}
}

View File

@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace App\Framework\Svg\Elements;
use App\Framework\Svg\ValueObjects\Geometry\Position;
use App\Framework\Svg\ValueObjects\Styling\Stroke;
use App\Framework\Svg\ValueObjects\Transform\Transform;
/**
* Value Object representing SVG line element
*/
final readonly class LineElement implements SvgElement
{
public function __construct(
public Position $start,
public Position $end,
public Stroke $stroke,
public ?Transform $transform = null,
public ?string $id = null,
public ?string $class = null
) {
}
public function getElementType(): string
{
return 'line';
}
public function getAttributes(): array
{
$attributes = [
'x1' => sprintf('%.2f', $this->start->x),
'y1' => sprintf('%.2f', $this->start->y),
'x2' => sprintf('%.2f', $this->end->x),
'y2' => sprintf('%.2f', $this->end->y),
...$this->stroke->toSvgAttributes(),
];
if ($this->transform !== null && $this->transform->hasTransformations()) {
$attributes['transform'] = $this->transform->toSvgValue();
}
if ($this->id !== null) {
$attributes['id'] = $this->id;
}
if ($this->class !== null) {
$attributes['class'] = $this->class;
}
return $attributes;
}
public function hasTransform(): bool
{
return $this->transform !== null && $this->transform->hasTransformations();
}
public function getTransform(): ?Transform
{
return $this->transform;
}
public function toSvg(): string
{
$attributeString = $this->buildAttributeString($this->getAttributes());
return "<line {$attributeString} />";
}
private function buildAttributeString(array $attributes): string
{
$parts = [];
foreach ($attributes as $key => $value) {
$parts[] = sprintf('%s="%s"', $key, htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'));
}
return implode(' ', $parts);
}
}

View File

@@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
namespace App\Framework\Svg\Elements;
use App\Framework\Core\ValueObjects\Dimensions;
use App\Framework\Svg\ValueObjects\Geometry\Position;
use App\Framework\Svg\ValueObjects\Geometry\Radius;
use App\Framework\Svg\ValueObjects\Styling\Fill;
use App\Framework\Svg\ValueObjects\Styling\Stroke;
use App\Framework\Svg\ValueObjects\Transform\Transform;
/**
* Value Object representing SVG rect element
*/
final readonly class RectElement implements SvgElement
{
public function __construct(
public Position $position,
public Dimensions $dimensions,
public Fill $fill,
public ?Stroke $stroke = null,
public ?Radius $rx = null, // Horizontal border radius
public ?Radius $ry = null, // Vertical border radius
public ?Transform $transform = null,
public ?string $id = null,
public ?string $class = null
) {
}
public function getElementType(): string
{
return 'rect';
}
public function getAttributes(): array
{
$attributes = [
'x' => sprintf('%.2f', $this->position->x),
'y' => sprintf('%.2f', $this->position->y),
'width' => (string) $this->dimensions->width,
'height' => (string) $this->dimensions->height,
...$this->fill->toSvgAttributes(),
];
if ($this->stroke !== null && $this->stroke->isVisible()) {
$attributes = [...$attributes, ...$this->stroke->toSvgAttributes()];
}
if ($this->rx !== null) {
$attributes['rx'] = $this->rx->toSvgValue();
}
if ($this->ry !== null) {
$attributes['ry'] = $this->ry->toSvgValue();
}
if ($this->transform !== null && $this->transform->hasTransformations()) {
$attributes['transform'] = $this->transform->toSvgValue();
}
if ($this->id !== null) {
$attributes['id'] = $this->id;
}
if ($this->class !== null) {
$attributes['class'] = $this->class;
}
return $attributes;
}
public function hasTransform(): bool
{
return $this->transform !== null && $this->transform->hasTransformations();
}
public function getTransform(): ?Transform
{
return $this->transform;
}
public function toSvg(): string
{
$attributeString = $this->buildAttributeString($this->getAttributes());
return "<rect {$attributeString} />";
}
private function buildAttributeString(array $attributes): string
{
$parts = [];
foreach ($attributes as $key => $value) {
$parts[] = sprintf('%s="%s"', $key, htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'));
}
return implode(' ', $parts);
}
}

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace App\Framework\Svg\Elements;
use App\Framework\Svg\ValueObjects\Transform\Transform;
/**
* Base interface for all SVG elements
*/
interface SvgElement
{
/**
* Render element to SVG string
*/
public function toSvg(): string;
/**
* Get element type (rect, circle, text, etc.)
*/
public function getElementType(): string;
/**
* Get all attributes as associative array
*/
public function getAttributes(): array;
/**
* Check if element has transform
*/
public function hasTransform(): bool;
/**
* Get transform if present
*/
public function getTransform(): ?Transform;
}

View File

@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace App\Framework\Svg\Elements;
use App\Framework\Svg\ValueObjects\Geometry\Position;
use App\Framework\Svg\ValueObjects\Text\TextContent;
use App\Framework\Svg\ValueObjects\Text\TextStyle;
use App\Framework\Svg\ValueObjects\Transform\Transform;
/**
* Value Object representing SVG text element
*/
final readonly class TextElement implements SvgElement
{
public function __construct(
public TextContent $content,
public Position $position,
public TextStyle $style,
public ?Transform $transform = null,
public ?string $id = null,
public ?string $class = null
) {
}
public function getElementType(): string
{
return 'text';
}
public function getAttributes(): array
{
$attributes = [
'x' => sprintf('%.2f', $this->position->x),
'y' => sprintf('%.2f', $this->position->y),
...$this->style->toSvgAttributes(),
];
if ($this->transform !== null && $this->transform->hasTransformations()) {
$attributes['transform'] = $this->transform->toSvgValue();
}
if ($this->id !== null) {
$attributes['id'] = $this->id;
}
if ($this->class !== null) {
$attributes['class'] = $this->class;
}
return $attributes;
}
public function hasTransform(): bool
{
return $this->transform !== null && $this->transform->hasTransformations();
}
public function getTransform(): ?Transform
{
return $this->transform;
}
public function toSvg(): string
{
$attributeString = $this->buildAttributeString($this->getAttributes());
$textContent = $this->content->toSvgSafeString();
return "<text {$attributeString}>{$textContent}</text>";
}
private function buildAttributeString(array $attributes): string
{
$parts = [];
foreach ($attributes as $key => $value) {
$parts[] = sprintf('%s="%s"', $key, htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'));
}
return implode(' ', $parts);
}
}