fix(form-builder): restore FK on form_schemas.default_crowd_type_id (WS-6)
The original session 2.5 migration had to omit this FK due to an SQLite-only "rebuild on FK add" cascade-delete quirk. Now that the test infrastructure has moved to MySQL (Task 1 of this session), the quirk does not apply and the FK is restored to match every other FK in this table. Changes: - New migration `2026_04_28_100000_restore_default_crowd_type_id_foreign_key` adds a FOREIGN KEY (default_crowd_type_id) REFERENCES crowd_types(id) ON DELETE SET NULL. Deleting a CrowdType nulls the column on dependent schemas instead of cascading the schema delete. - Original migration's comment block rewritten — the SQLite-quirk rationale was demonstrably misleading; replaced with a forward-looking pointer to the FK-restore migration. - PersonProvisioner::resolveCrowdTypeId() docblock updated: the runtime failsafe is now defense in depth alongside the DB-level FK + publish guard, not the sole load-bearing check. New test (`DefaultCrowdTypeForeignKeyTest`) exercises both the ON-DELETE-SET-NULL cascade and the existence of the FK in information_schema.REFERENTIAL_CONSTRAINTS — the second assertion would have been impossible on SQLite, which is exactly the point. Migration step counts in 5 backfill tests bumped +1 because the FK- restore migration sits at the top of the migration stack: - FormFieldBindingMigrationTest: 17→18, 15→16 - ConditionalLogicBackfillTest: 6→7 - FormFieldConfigBackfillAndDropTest: 12→13 - FormFieldOptionsBackfillTest: 2→3 - FormFieldValidationRuleBackfillTest: 15→16 All 1388 tests pass on MySQL (1386 prior + 2 new FK tests). Larastan baseline unchanged. Refs: RFC-WS-6.md v1.1 §3 Q9 addendum, WS-6 session 2.5 deviation #1 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,27 +7,24 @@ use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* RFC-WS-6 v1.1 §3 Q8 addendum — per-schema default CrowdType for
|
||||
* RFC-WS-6.md v1.1 §3 Q9 addendum — per-schema default CrowdType for
|
||||
* Person provisioning. Replaces the silent oldest() heuristic from
|
||||
* WS-6 session 2 with explicit configuration; RequiresDefaultCrowdType
|
||||
* publish guard ensures event_registration schemas declare it.
|
||||
*
|
||||
* No backfill: pre-launch the table is empty. Dev seeders populate
|
||||
* the column when reseeding (FormBuilderDevSeeder).
|
||||
*
|
||||
* The FK constraint is added in a follow-up migration
|
||||
* (2026_04_28_100000_restore_default_crowd_type_id_foreign_key) once
|
||||
* the test database moved off SQLite to MySQL — the original session
|
||||
* 2.5 skipped it due to an SQLite-only "rebuild on FK add" cascade
|
||||
* quirk that does not apply on MySQL.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// Plain nullable ULID column. NO database-level foreign key —
|
||||
// SQLite's rebuild-on-FK-add cascade-deletes form_fields rows
|
||||
// (form_fields.form_schema_id has cascadeOnDelete on
|
||||
// form_schemas), which corrupts running migration tests.
|
||||
// Application-level integrity: FormSchema::defaultCrowdType()
|
||||
// belongsTo loads from CrowdType; CrowdTypeObserver could add
|
||||
// a soft-handle on delete if needed in production. The new
|
||||
// RequiresDefaultCrowdType publish guard plus the runtime
|
||||
// failsafe in PersonProvisioner are the load-bearing checks.
|
||||
Schema::table('form_schemas', function (Blueprint $table): void {
|
||||
$table->ulid('default_crowd_type_id')
|
||||
->nullable()
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* RFC-WS-6.md v1.1 §3 Q9 addendum — restore the FK on
|
||||
* form_schemas.default_crowd_type_id that session 2.5 had to omit
|
||||
* because of an SQLite "rebuild on FK add" cascade-delete quirk.
|
||||
*
|
||||
* Crewli has dropped SQLite entirely (CLAUDE.md: MySQL-only). On
|
||||
* MySQL 8.0 the quirk does not apply, and database-level referential
|
||||
* integrity is restored to match every other FK in this table.
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('form_schemas', function (Blueprint $table): void {
|
||||
$table->foreign('default_crowd_type_id')
|
||||
->references('id')
|
||||
->on('crowd_types')
|
||||
->nullOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('form_schemas', function (Blueprint $table): void {
|
||||
$table->dropForeign(['default_crowd_type_id']);
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user