press-releases/jobs: Scheduler respektiert manuelle Prüfung und kommt an Blockaden vorbei, Newsletter-Versand per Schalter gesperrt, kurze Scheduler-Sperren (Umsetzungsaudit 29.09.: K-01, K-02, K-05, K-06, K-09, E9, OPT-8, OPT-9; 02.10.: O06)
- K-01: publish-scheduled filtert manual_review_required_at; publish() prüft für ki/scheduler unter der Sperre (ManualReviewRequiredException) - K-02: Kontingent- und Bildsperre sind fachliche Ausgänge (Exit 0, einmaliger Verlaufseintrag); KI-Job ohne Retry bei Bildsperre - O06: Kandidaten per Cursor (scheduled_at, id), Limit zählt bearbeitete Meldungen, Blockaden nur ein Scan-Budget - K-05: KI-Job lädt vor dem Routing neu, überholter Status ohne Retry; backoff - K-06: Admin-Aktionen mit Permission-Prüfung und Fehlermeldung statt 500 - K-09: withoutOverlapping() mit kurzer Sperrdauer, purge-events 03:50, neuer Wochenlauf press-release-images:sweep-orphan-originals (So 04:45) - E9: NEWSLETTER_SENDING_ENABLED (Standard aus) sperrt Start, Resume und Job - OPT-9: ExpireGrandfathering prüft die Queue-Voraussetzung aus E18 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d6e49c11c3
commit
c82f279fef
20 changed files with 927 additions and 89 deletions
|
|
@ -30,11 +30,26 @@ class CampaignSender
|
|||
{
|
||||
public function __construct(private readonly CampaignRecipients $recipients) {}
|
||||
|
||||
/**
|
||||
* Versand per Konfiguration freigegeben (E9-Schalter).
|
||||
*/
|
||||
public static function sendingEnabled(): bool
|
||||
{
|
||||
return (bool) config('newsletter.sending_enabled', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int Anzahl der eingeplanten Empfänger.
|
||||
*
|
||||
* @throws NewsletterSendingDisabledException Versand gesperrt; der Entwurf
|
||||
* bleibt unverändert.
|
||||
*/
|
||||
public function start(NewsletterCampaign $campaign): int
|
||||
{
|
||||
if (! self::sendingEnabled()) {
|
||||
throw new NewsletterSendingDisabledException;
|
||||
}
|
||||
|
||||
if (! $this->claimDraft($campaign)) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Newsletter;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Kampagnen-Versand ist per Konfiguration gesperrt (`newsletter.sending_enabled`,
|
||||
* E9-Schalter, Umsetzungsaudit 29.09.2026) — bis U05–U07 umgesetzt sind.
|
||||
*/
|
||||
class NewsletterSendingDisabledException extends RuntimeException
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(__('Der Newsletter-Versand ist derzeit gesperrt (NEWSLETTER_SENDING_ENABLED). Entwürfe und Test-Mails bleiben möglich.'));
|
||||
}
|
||||
}
|
||||
19
app/Services/PressRelease/ManualReviewRequiredException.php
Normal file
19
app/Services/PressRelease/ManualReviewRequiredException.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\PressRelease;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Automatische Veröffentlichung (`ki`, `scheduler`) einer Meldung, die auf
|
||||
* eine menschliche Entscheidung wartet (E3, `manual_review_required_at`) —
|
||||
* Umsetzungsaudit 29.09.2026, K-01. Fachlicher Ausgang, kein Fehler: Die
|
||||
* Meldung bleibt unverändert in `review`, nur ein Admin gibt sie frei.
|
||||
*/
|
||||
class ManualReviewRequiredException extends RuntimeException
|
||||
{
|
||||
public function __construct(public readonly int $pressReleaseId)
|
||||
{
|
||||
parent::__construct(sprintf('PM #%d wartet auf eine manuelle Prüfung und wird nicht automatisch veröffentlicht.', $pressReleaseId));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue