companies: Zusammenführung im Bestand, rückabwickelbar (Roadmap 1a.3)
companies:merge führt Firmen mit derselben Firmen-E-Mail zu einem Newsroom zusammen — nur über Adressen, die 1a.2 als Dublette oder Namensvariante klassifiziert hat. Es bleibt die Firma mit den meisten jemals veröffentlichten Meldungen; Meldungen, Kontakte, Nutzer- und Zahlungsverknüpfungen wandern per company_id, jede Bewegung steht in company_merge_moves. companies:unmerge spielt sie rückwärts ab. 77 % der Gruppen sind dieselbe Firma auf beiden Portalen (Altsystem: eine Firma je Portal). Der Überlebende wird dann `both`; die Meldungen behalten ihr Portal. Der alte Newsroom-Slug führt per 301 zum Überlebenden. Slug-Kollisionen auf dem anderen Portal werden übersprungen, nicht umbenannt. Company::slugExists() kennt jetzt `both`. Dev-DB: 14 142 Adressen, 16 194 Firmen, 13 297 Meldungen in 2 min; Rückabwicklung in 1:15 min exakt auf den Stand davor. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
66d8398e97
commit
2aebb9d27e
17 changed files with 1508 additions and 7 deletions
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Protokoll der Newsroom-Zusammenführung (Roadmap 1a.3).
|
||||
*
|
||||
* `company_merges` ist ein Vorgang je Adresse: welche Firma geblieben ist und
|
||||
* welches Portal sie vorher trug. `company_merge_moves` hält je verschobenem
|
||||
* Datensatz fest, woher er kam — das ist die gespeicherte Ursprungszuordnung,
|
||||
* über die `companies:unmerge` den Vorgang exakt rückabwickelt.
|
||||
*
|
||||
* Bewusst zwei eigene Tabellen statt einer Spalte `merged_from_company_id` an
|
||||
* `press_releases`: Die ist über 1 GB groß, ein ADD COLUMN dort nur für einen
|
||||
* einmaligen Vorgang lohnt nicht, und Kontakte, Nutzer-Verknüpfungen und
|
||||
* Zahlungsoptionen bräuchten dieselbe Spalte noch einmal. Hier landen alle in
|
||||
* einer Liste.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('company_merges', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('batch', 36)->index();
|
||||
$table->string('email', 190)->index();
|
||||
$table->foreignId('survivor_company_id')->constrained('companies')->restrictOnDelete();
|
||||
$table->string('survivor_portal_before', 32);
|
||||
$table->unsignedInteger('merged_companies_count');
|
||||
$table->unsignedInteger('moved_press_releases_count');
|
||||
$table->timestamp('reverted_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('company_merge_moves', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('company_merge_id')->constrained('company_merges')->cascadeOnDelete();
|
||||
$table->string('subject', 32);
|
||||
$table->unsignedBigInteger('subject_id')->nullable();
|
||||
$table->foreignId('from_company_id')->constrained('companies')->restrictOnDelete();
|
||||
$table->string('field', 64)->nullable();
|
||||
$table->text('previous_value')->nullable();
|
||||
$table->boolean('dropped')->default(false);
|
||||
|
||||
$table->index(['subject', 'subject_id'], 'company_merge_moves_subject_idx');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('company_merge_moves');
|
||||
Schema::dropIfExists('company_merges');
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue