Michael Schiemer 6e1faabdc1 fix(deployment): deploy docker-compose files via scp before SSH execution
The previous 'always sync' approach failed because it tried to copy files
from /workspace/repo/ which doesn't exist on the production server.

The SSH heredoc (<<EOF) executes commands ON the production server, not in
the Gitea Actions workspace. File paths inside heredoc are relative to the
production server's filesystem.

This commit adds an scp step BEFORE the SSH heredoc to transfer
docker-compose.base.yml and docker-compose.production.yml from the Actions
workspace to the production server.

This ensures the build: null overrides (commit 2e539ed) reach production
and services can restart without build context errors.

Changes:
- Added scp command to deploy docker-compose files before SSH deployment
- Changed file sync check from 'cp' to file existence validation
- Updated comments to clarify rsync-based deployment architecture

Related commits:
- 0b342c6: Sequential push strategy
- 08f6f64: Stable git-SHA IMAGE_TAG
- 2e539ed: build: null overrides
- 0db73df: Always-sync docker-compose (incorrect implementation)
- 3091205: Trigger pipeline with source file change
2025-11-04 16:01:11 +01:00
2025-07-17 16:24:20 +02:00
2025-07-17 16:24:20 +02:00
2025-07-17 16:24:20 +02:00
2025-07-17 16:24:20 +02:00
2025-05-24 07:09:22 +02:00
2025-05-18 17:03:57 +02:00
2025-07-17 16:24:20 +02:00
2025-07-17 16:24:20 +02:00

Custom PHP Framework

Ein modulares und erweiterbares PHP-Framework mit API-Client-Integration, Attribut-basiertem Routing und Production-Ready Infrastructure.

🚀 Quick Start

Development Setup

# Repository klonen
git clone https://github.com/username/framework.git
cd framework

# Mit Docker starten
make up

# Oder: Manuelle Installation
composer install
npm install
# Neue Base+Override Struktur: .env.base + .env.local
# Siehe ENV_SETUP.md für Details
# Für Backward Compatibility: cp .env.example .env (wird als Fallback geladen)

Production Deployment

Neu im Projekt? Starte hier:

📖 Quick Start Guide - Deployment in 30 Minuten

Vollständige Deployment-Dokumentation:

Anwendung starten

Das Framework kann entweder mit dem eingebauten PHP-Webserver oder mit einem Webserver wie Apache oder Nginx ausgeführt werden.

Eingebauter PHP-Webserver

php -S localhost:8000 -t public/

Nginx-Konfiguration

server {
    listen 80;
    server_name yourdomain.com;
    root /path/to/framework/public;

    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Production-Ready Features

Monitoring & Health Checks

  • 🏥 Multiple Health Endpoints - /health/summary, /health/detailed, /health/category/{category}
  • 📊 Prometheus Metrics - /metrics endpoint for monitoring integration
  • 🔍 Auto-Discovery - Automatic health check registration via attributes
  • Real-time Monitoring - Grafana dashboards for production visibility

Security

  • 🔒 SSL/TLS - Automatic Let's Encrypt certificate management
  • 🔐 Vault Integration - Encrypted secrets management
  • 🛡️ WAF - Web Application Firewall with OWASP protection
  • 🚨 Security Headers - CSP, HSTS, X-Frame-Options, etc.
  • 🔑 CSRF Protection - Automatic token-based protection

Logging

  • 📝 Structured Logging - JSON-formatted logs with context
  • 🎯 Multiple Strategies - Production, High-Performance, Debug, Staging
  • 📈 Log Aggregation - Reduce log volume by 70-90%
  • 🔄 Log Rotation - Automatic rotation with configurable retention
  • 📊 Performance Metrics - Built-in performance tracking

Deployment

  • 🚀 Zero-Downtime - Blue-green deployment support
  • 🔄 Rollback Support - Safe migration rollback architecture
  • 📦 Docker Compose - Production-ready container orchestration
  • 🤖 Ansible - Optional infrastructure as code
  • Health-Verified - Automated health checks during deployment

Architektur

Das Framework folgt einer modularen Architektur mit den folgenden Hauptkomponenten:

Core

  • Application: Steuert den Anwendungslebenszyklus
  • Container: Dependency Injection Container
  • Router: Attribute-basiertes Routing
  • Middleware: HTTP-Middleware-Chain

HTTP

DateTime-Modul für das Framework

Dieses Modul bietet eine umfassende Unterstützung für DateTime-Operationen im Framework mit einem Fokus auf Testbarkeit, Immutabilität und Zeitzonen-Unterstützung.

Hauptkomponenten

Clock-Interface

Das Clock-Interface abstrahiert den Zugriff auf die aktuelle Zeit und stellt sicher, dass Anwendungscode testbar bleibt:

// Produktionscode verwendet SystemClock
$clock = new SystemClock();
$now = $clock->now();

// Testcode kann FrozenClock verwenden
$clock = new FrozenClock('2021-01-01 00:00:00');
$frozenTime = $clock->now(); // Gibt immer das gleiche Datum zurück

FrozenClock für Tests

Die FrozenClock-Klasse ist besonders nützlich für Tests, bei denen Sie die Zeit kontrollieren müssen:

$clock = new FrozenClock('2021-01-01 00:00:00');

// Zeit vorstellen
$clock->moveForward('PT1H'); // Eine Stunde vorstellen

// Zeit zurückstellen
$clock->moveBackward('P1D'); // Einen Tag zurückstellen

// Zeit direkt setzen
$clock->setTo('2022-01-01 00:00:00');

DateTimeFormatter

Der DateTimeFormatter bietet bequeme Methoden zum konsistenten Formatieren von Datums- und Zeitwerten:

$formatter = new DateTimeFormatter();

// ISO8601-Format (für APIs und JSON)
$iso = $formatter->formatIso8601($date); // 2021-01-01T12:34:56+00:00

// SQL-Format
$sql = $formatter->formatSql($date); // 2021-01-01 12:34:56

// Nur Datum
$dateOnly = $formatter->formatDate($date); // 2021-01-01

// Benutzerdefiniertes Format
$custom = $formatter->format($date, 'd.m.Y H:i'); // 01.01.2021 12:34

DateRange

Die DateRange-Klasse ermöglicht die einfache Arbeit mit Zeiträumen:

// Zeitraum erstellen
$range = DateRange::fromStrings('2021-01-01', '2021-01-31');

// Prüfen, ob ein Datum im Bereich liegt
$isInRange = $range->contains($someDate);

// Prüfen, ob sich Bereiche überschneiden
$doOverlap = $range->overlaps($otherRange);

// Dauer berechnen
$seconds = $range->getDurationInSeconds();

DI-Container Integration

Das Modul lässt sich nahtlos in den DI-Container des Frameworks integrieren:

// In Ihrer Bootstrap-Datei oder Service-Provider
$container->singleton(Clock::class, SystemClock::class);
$container->singleton(DateTimeFormatter::class, DateTimeFormatter::class);

// Oder den bereitgestellten ServiceProvider verwenden
$dateTimeServiceProvider = new DateTimeServiceProvider();
$dateTimeServiceProvider->register($container);

Testunterstützung

Für Tests kann die FrozenClock einfach registriert werden:

// In Ihrem Test-Setup
$frozenClock = new FrozenClock('2021-01-01 00:00:00');
$container->instance(Clock::class, $frozenClock);

// Zeit während des Tests manipulieren
$frozenClock->moveForward('PT1H');
  • Request/Response: HTTP-Nachrichten
  • HttpClient: HTTP-Client für API-Anfragen

API

  • ApiRequestTrait: Hilfsklasse für API-Clients
  • Integrierte Clients: RapidMail, Shopify

Features

  • Attribut-basiertes Routing: Deklaratives Routing mit PHP 8 Attributen
  • Dependency Injection: Automatische Auflösung von Abhängigkeiten
  • Middleware-System: Erweiterbare HTTP-Middleware-Chain
  • API-Clients: Integrierte Clients für gängige APIs
  • Konfigurationsmanagement: Flexible Konfiguration mit Umgebungsvariablen

Beispiele

Controller mit Routing

<?php

namespace App\Application\Example;

use App\Framework\Attributes\Route;
use App\Framework\Router\Result\JsonResult;

final class ExampleController
{
    #[Route(path: '/api/example', method: 'GET')]
    public function getExample(): JsonResult
    {
        return new JsonResult([
            'success' => true,
            'message' => 'Hello World!'
        ]);
    }
}

API-Client verwenden

<?php

namespace App\Application\Newsletter;

use App\Framework\Attributes\Route;use App\Framework\Http\Status;use App\Framework\Router\Result\JsonResult;use App\Infrastructure\Api\RapidMailClient;use Archive\Config\ApiConfig;

final class NewsletterController
{
    private RapidMailClient $client;

    public function __construct()
    {
        $this->client = new RapidMailClient(
            ApiConfig::RAPIDMAIL_USERNAME->value,
            ApiConfig::RAPIDMAIL_PASSWORD->value
        );
    }

    #[Route(path: '/newsletter/register', method: 'POST')]
    public function register(NewsletterRequest $request): JsonResult
    {
        $result = $this->client->addRecipient(
            $request->name,
            $request->email,
            ApiConfig::getRapidmailListId()
        );

        return new JsonResult(
            ['success' => true, 'data' => $result],
            Status::CREATED
        );
    }
}

Erweiterung

Das Framework kann durch eigene Komponenten und Module erweitert werden:

  • Eigene Middleware: Erstellen Sie benutzerdefinierte Middleware-Klassen
  • Attribute: Definieren Sie eigene Attribute und Mapper
  • API-Clients: Integrieren Sie zusätzliche APIs mit dem ApiRequestTrait

Lizenz

MIT

# Starten
make up

# Logs anzeigen
make logs

# Setup-Playbook (Server einmalig vorbereiten)
make setup

# Deployment (Code + Compose auf Server bringen)
make deploy
Description
Main application repository
Readme 89 MiB
Languages
PHP 88.3%
JavaScript 6%
Hack 2.9%
Shell 1.1%
CSS 1.1%
Other 0.4%