feat: registration form fields, section preferences, tag sync & schema updates
Implement EAV system for dynamic event-specific registration fields with organisation-level templates, person section preferences with priority ranking, and TagSyncService for deferred tag_picker sync. New tables: registration_field_templates, registration_form_fields, person_field_values, person_section_preferences. New columns: persons.remarks, events.registration_show_section_preferences, events.registration_show_availability. 58 tests, 126 assertions — all 432 tests pass (zero regressions). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('persons', function (Blueprint $table) {
|
||||
$table->text('remarks')->nullable()->after('admin_notes');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('persons', function (Blueprint $table) {
|
||||
$table->dropColumn('remarks');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('events', function (Blueprint $table) {
|
||||
$table->boolean('registration_show_section_preferences')->default(true)->after('registration_logo_url');
|
||||
$table->boolean('registration_show_availability')->default(true)->after('registration_show_section_preferences');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('events', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'registration_show_section_preferences',
|
||||
'registration_show_availability',
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('registration_field_templates', function (Blueprint $table) {
|
||||
$table->ulid('id')->primary();
|
||||
$table->foreignUlid('organisation_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('label');
|
||||
$table->string('slug', 100);
|
||||
$table->string('field_type', 50);
|
||||
$table->json('options')->nullable();
|
||||
$table->string('tag_category', 50)->nullable();
|
||||
$table->boolean('is_required')->default(false);
|
||||
$table->boolean('is_filterable')->default(false);
|
||||
$table->boolean('is_portal_visible')->default(true);
|
||||
$table->boolean('is_admin_only')->default(false);
|
||||
$table->string('section', 100)->nullable();
|
||||
$table->text('help_text')->nullable();
|
||||
$table->integer('sort_order')->default(0);
|
||||
$table->boolean('is_system')->default(false);
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['organisation_id', 'slug'], 'rft_org_slug_unique');
|
||||
$table->index(['organisation_id', 'is_active', 'sort_order'], 'rft_org_active_order_index');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('registration_field_templates');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('registration_form_fields', function (Blueprint $table) {
|
||||
$table->ulid('id')->primary();
|
||||
$table->foreignUlid('event_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('label');
|
||||
$table->string('slug', 100);
|
||||
$table->string('field_type', 50);
|
||||
$table->json('options')->nullable();
|
||||
$table->string('tag_category', 50)->nullable();
|
||||
$table->boolean('is_required')->default(false);
|
||||
$table->boolean('is_portal_visible')->default(true);
|
||||
$table->boolean('is_admin_only')->default(false);
|
||||
$table->boolean('is_filterable')->default(false);
|
||||
$table->string('section', 100)->nullable();
|
||||
$table->text('help_text')->nullable();
|
||||
$table->integer('sort_order')->default(0);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['event_id', 'slug'], 'rff_event_slug_unique');
|
||||
$table->index(['event_id', 'sort_order'], 'rff_event_order_index');
|
||||
$table->index(['event_id', 'is_portal_visible', 'sort_order'], 'rff_event_visible_order_index');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('registration_form_fields');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('person_field_values', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignUlid('person_id')->constrained('persons')->cascadeOnDelete();
|
||||
$table->foreignUlid('registration_form_field_id')->nullable()->constrained('registration_form_fields')->nullOnDelete();
|
||||
$table->text('value')->nullable();
|
||||
$table->json('selected_options')->nullable();
|
||||
|
||||
$table->unique(['person_id', 'registration_form_field_id'], 'pfv_person_field_unique');
|
||||
$table->index('registration_form_field_id', 'pfv_field_index');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('person_field_values');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('person_section_preferences', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignUlid('person_id')->constrained('persons')->cascadeOnDelete();
|
||||
$table->foreignUlid('festival_section_id')->constrained('festival_sections')->cascadeOnDelete();
|
||||
$table->tinyInteger('priority');
|
||||
|
||||
$table->unique(['person_id', 'festival_section_id'], 'psp_person_section_unique');
|
||||
$table->index(['festival_section_id', 'priority']);
|
||||
$table->index('person_id', 'psp_person_index');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('person_section_preferences');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user