From d861c34c26ea470b4662cd63c22a538c5e06431c Mon Sep 17 00:00:00 2001 From: nexxo Date: Mon, 3 Aug 2026 20:32:25 +0200 Subject: [PATCH] Plan berichtigt: der Nachruestbefehl haette nie einen Lauf gefahren MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AdvanceRunJob sucht per uuid, mein Zettel uebergab die Autoincrement-Id. HasUuid erzeugt beide unabhaengig; sie sind nie gleich. In Produktion haette der Auftrag nie eine Zeile gefunden, still geendet, und jeder Lauf waere fuer immer auf running stehengeblieben — waehrend der Befehl "gestartet" meldet. Dazu STATUS_RUNNING statt STATUS_PENDING beim Anlegen. Die eigentliche Luecke war die fehlende Zusicherung: die Pruefungen zaehlten Laufzeilen und sahen nie nach, WAS an den Auftrag ging. Sie ist ergaenzt. Ausserdem zwei Reste in der Spezifikation: mail_smtpauth folgt seit Aufgabe 1 dem Postfach statt einem festen Wert, und der Anzeigename je Kunde entfaellt — `instances` traegt keine Spalte, aus der er kommen koennte. --- .../plans/2026-08-03-mitarbeiterverwaltung.md | 18 ++++++++-- ...2026-08-03-mitarbeiterverwaltung-design.md | 34 +++++++++++++++---- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/docs/superpowers/plans/2026-08-03-mitarbeiterverwaltung.md b/docs/superpowers/plans/2026-08-03-mitarbeiterverwaltung.md index df95a82..c865d1e 100644 --- a/docs/superpowers/plans/2026-08-03-mitarbeiterverwaltung.md +++ b/docs/superpowers/plans/2026-08-03-mitarbeiterverwaltung.md @@ -640,6 +640,13 @@ it('startet je aktiver Instanz einen Lauf', function () { $this->artisan('clupilot:configure-instance-mail')->assertSuccessful(); expect(ProvisioningRun::where('pipeline', 'instance-mail')->count())->toBe(2); + + // Und der Auftrag bekommt die uuid, nicht die Id. Ohne DIESE Zusicherung + // bleibt eine vertauschte Kennung unsichtbar: der Befehl meldet + // "gestartet", die Warteschlange findet nie eine Zeile, und der Lauf + // steht fuer immer auf running. Zeilen zu zaehlen genuegt nicht — es + // zaehlt, WAS uebergeben wird. + Queue::assertPushed(AdvanceRunJob::class, fn ($job) => ProvisioningRun::where('uuid', $job->runUuid)->exists()); }); it('faengt unter --dry-run gar nichts an', function () { @@ -752,7 +759,7 @@ class ConfigureInstanceMail extends Command 'pipeline' => 'instance-mail', 'subject_type' => Instance::class, 'subject_id' => $instance->id, - 'status' => ProvisioningRun::STATUS_RUNNING, + 'status' => ProvisioningRun::STATUS_PENDING, 'current_step' => 0, 'context' => [ 'instance_id' => $instance->id, @@ -761,7 +768,14 @@ class ConfigureInstanceMail extends Command ], ]); - AdvanceRunJob::dispatch($run->id); + // uuid, NICHT id: AdvanceRunJob sucht in handle() per + // where('uuid', ...). HasUuid erzeugt die uuid unabhaengig von + // der Autoincrement-Id; beide sind nie gleich. Mit der Id findet + // der Auftrag in Produktion nie eine Zeile, endet still ohne + // Ausnahme, und der Lauf steht fuer immer auf running — waehrend + // dieser Befehl "gestartet" meldet. Jeder andere Aufrufer im Repo + // macht es so. + AdvanceRunJob::dispatch($run->uuid); $this->info("{$instance->uuid}: Lauf {$run->id} gestartet"); $gestartet++; } diff --git a/docs/superpowers/specs/2026-08-03-mitarbeiterverwaltung-design.md b/docs/superpowers/specs/2026-08-03-mitarbeiterverwaltung-design.md index d245706..3b56e0d 100644 --- a/docs/superpowers/specs/2026-08-03-mitarbeiterverwaltung-design.md +++ b/docs/superpowers/specs/2026-08-03-mitarbeiterverwaltung-design.md @@ -90,19 +90,41 @@ five rows"), die Zugangsdaten je Absender am `Mailbox`-Datensatz. | `mail_smtphost` | z. B. `smtp.…` | `Settings::get('mail.host')` | | `mail_smtpport` | z. B. `587` | `Settings::get('mail.port')` | | `mail_smtpsecure` | `tls` / `ssl` / leer | `Settings::get('mail.encryption')` | -| `mail_smtpauth` | `true` | fest | +| `mail_smtpauth` | `true` / `false` | `Mailbox::$authenticates` | | `mail_smtpname` | Benutzername | `Mailbox::smtpUsername()` | | `mail_smtppassword` | Passwort | `Mailbox` (unter `SECRETS_KEY`) | | `mail_from_address` | `noreply` | linker Teil der Postfachadresse | | `mail_domain` | `clupilot.cloud` | rechter Teil der Postfachadresse | Fehlt der Server (`mail.host` leer) oder das Postfach, wird **nichts** -geschrieben und der Schritt meldet einen klaren Grund. Eine halb eingetragene -Mailkonfiguration ist schlimmer als keine: Nextcloud versucht dann zu senden -und scheitert bei jedem einzelnen Versand still. +geschrieben. Eine halb eingetragene Mailkonfiguration ist schlimmer als keine: +Nextcloud versucht dann zu senden und scheitert bei jedem einzelnen Versand +still. -Der Anzeigename ist der Cloud-Name des Kunden, damit eine Mail aus *seiner* -Cloud kommt und nicht aus einem Produkt, das er nicht kennt. +**Aber der Schritt laesst die Bereitstellung weiterlaufen.** Er protokolliert +den Grund und geht weiter — er scheitert nicht. + +Das ist kein Nachlassen, sondern dieselbe Abwaegung, die dieses Projekt bei der +Ueberwachung schon getroffen hat: eine Nebenfunktion darf keine bezahlte +Bestellung aufhalten. Der Mailserver dieses Produkts wird gerade erst +aufgesetzt; waere dieser Schritt zwingend, bliebe ab dem Ausrollen **jede neue +Bestellung** daran haengen. Der Kunde zahlt und bekommt keine Cloud, weil +Einladungsmails nicht eingerichtet sind — eine Funktion, die er vielleicht nie +benutzt. + +Ohne Versand funktioniert die Cloud vollstaendig. Nur Einladungen und +Freigabe-Benachrichtigungen gehen nicht, und `clupilot:configure-instance-mail` +holt es nach, sobald der Server steht. + +Nicht eingerichtet ist etwas anderes als kaputt: sobald Server und Postfach da +sind, bleibt ein Fehler beim SCHREIBEN ein Fehlschlag wie jeder andere. + +Ein eigener **Anzeigename je Kunde** wird bewusst NICHT geschrieben. Ein +frueherer Entwurfsstand sah ihn vor; beim Bauen stellte sich heraus, dass +`instances` gar keine Spalte traegt, aus der er kommen koennte. Nextcloud +benutzt in diesem Fall den Namen aus seiner eigenen Gestaltung — den der Kunde +in seiner Cloud selbst setzen kann. Das ist der bessere Ort dafuer: es ist +seine Cloud, nicht unsere. ### Das Passwort ist auf der Kundenmaschine nicht zu verstecken