d8d755d4c5
Un user supprimé physiquement laissait des références orphelines (task.assignee, time entries, notifications) car les FK vers "user" ont été créées NOT VALID lors du refactor modular-monolith : elles n'ont jamais nettoyé les orphelins legacy. La sérialisation API Platform d'une tâche embarquant un assignee inexistant levait une EntityNotFoundException non rattrapable (HTTP 500 sur tout PATCH/GET de ces tickets). - User::$archived (bool) + migration (soft delete) - Delete de User -> UserArchiveProcessor : archive (archived=true, apiToken vidé) au lieu de supprimer, préservant l'intégrité référentielle - ArchivedUserChecker : login bloqué pour un user archivé (firewalls login + api) - ExcludeArchivedUserExtension : archivés exclus de GET /api/users (assignation), les références existantes restent sérialisées normalement - Commande app:restore-missing-users : recrée (en archivés) les users encore référencés mais supprimés, restaurant l'intégrité sans perte de données. Idempotente, option --dry-run. À lancer une fois en prod après déploiement.
32 lines
822 B
PHP
32 lines
822 B
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace DoctrineMigrations;
|
|
|
|
use Doctrine\DBAL\Schema\Schema;
|
|
use Doctrine\Migrations\AbstractMigration;
|
|
|
|
/**
|
|
* Adds a soft-delete flag on user. Deleting a user now archives it instead of
|
|
* removing the row, preserving referential integrity (tasks, time entries,
|
|
* notifications…). Existing users are kept active (archived = false).
|
|
*/
|
|
final class Version20260626153721 extends AbstractMigration
|
|
{
|
|
public function getDescription(): string
|
|
{
|
|
return 'Add archived flag on user (soft delete)';
|
|
}
|
|
|
|
public function up(Schema $schema): void
|
|
{
|
|
$this->addSql('ALTER TABLE "user" ADD archived BOOLEAN DEFAULT false NOT NULL');
|
|
}
|
|
|
|
public function down(Schema $schema): void
|
|
{
|
|
$this->addSql('ALTER TABLE "user" DROP archived');
|
|
}
|
|
}
|