Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?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_talks', function (Blueprint $table): void {
$table->dropForeign('events_talks_event_id_foreign');
$table->dropColumn('event_id');
});

Schema::table('events_attendees', function (Blueprint $table): void {
$table->dropForeign('events_attendees_event_id_foreign');
$table->dropColumn('event_id');
});

Schema::table('events_sponsors', function (Blueprint $table): void {
$table->dropForeign('events_sponsors_event_id_foreign');
$table->dropColumn('event_id');
});

Schema::table('events_agenda', function (Blueprint $table): void {
$table->dropForeign('events_agenda_event_id_foreign');
$table->dropColumn('event_id');
});
Comment on lines +13 to +31
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "*recreate_events_table_with_uuid*" 2>/dev/null

Repository: he4rt/heartdevs.com

Length of output: 158


🏁 Script executed:

cat -n ./app-modules/events/database/migrations/2026_05_13_224916_recreate_events_table_with_uuid.php

Repository: he4rt/heartdevs.com

Length of output: 5909


🏁 Script executed:

find . -type f -name "database.php" -o -name "*.php" -path "*/config/*" | grep -E "(database|config)" | head -20

Repository: he4rt/heartdevs.com

Length of output: 695


🏁 Script executed:

cat -n ./config/database.php

Repository: he4rt/heartdevs.com

Length of output: 8354


Use disableForeignKeyConstraints() to handle SQLite FK operations safely.

This migration manually drops foreign keys before altering the parent events table, which technically works on SQLite. However, it bypasses Laravel's built-in Schema::disableForeignKeyConstraints()/enableForeignKeyConstraints() wrapper, which properly manages database-specific foreign key pragmas. Wrapping the entire migration logic (both up() and down() methods) with these methods would be more robust and maintainable, especially since the project uses SQLite as the default database with foreign_key_constraints enabled by default.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app-modules/events/database/migrations/2026_05_13_224916_recreate_events_table_with_uuid.php`
around lines 13 - 31, Wrap the migration's foreign-key-modifying logic in calls
to Schema::disableForeignKeyConstraints() and
Schema::enableForeignKeyConstraints() so SQLite pragmas are handled correctly:
inside both the up() and down() methods, call
Schema::disableForeignKeyConstraints() before any Schema::table(...) operations
that drop foreign keys (e.g., events_talks/event_id, events_attendees/event_id,
events_sponsors/event_id, events_agenda/event_id) and call
Schema::enableForeignKeyConstraints() after those operations complete to restore
normal FK enforcement.

Comment on lines +12 to +31
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Você pode inicialmente só criar uma migration pra dropar toda a estrutura de events antiga. Fica mais limpo pra darmos track e limpar no futuro.

Também tem o ponto que usamos o prefixo de módulo pras tabelas:

  • "events" (aceitavel)
  • "check_in_codes" (não aceitável)

O prefixo é pra facilitar tanto pra gente que está desenvolvendo, quando pra qualquer agente entender os limites de cada módulo, logo:

  • "**events_**check_in_codes" (aceitável)
  • etc...

Faça esse refactor e vamos tentando entender o que se encaixaria por aqui.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blz


Schema::dropIfExists('events');

Schema::create('events', function (Blueprint $table): void {
$table->uuid('id')->primary();
$table->foreignId('tenant_id')->nullable()->constrained('tenants')->nullOnDelete();
$table->string('event_type');
$table->boolean('active')->default(true);
$table->string('slug')->unique();
$table->string('title');
$table->text('description');
$table->timestamp('event_at');
$table->timestamp('start_at');
$table->timestamp('end_at');
$table->string('location');
$table->integer('max_attendees');
$table->integer('attendees_count')->default(0);
$table->integer('waitlist_count')->default(0);
$table->timestamps();
});

Schema::table('events_talks', function (Blueprint $table): void {
$table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete();
});

Schema::table('events_attendees', function (Blueprint $table): void {
$table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete();
});

Schema::table('events_sponsors', function (Blueprint $table): void {
$table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete();
});

Schema::table('events_agenda', function (Blueprint $table): void {
$table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete();
});
Comment on lines +13 to +67
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Avoid destructive UUID conversion that drops existing event links.

Line 13 through Line 67 removes all existing event_id values and drops events before any ID mapping/backfill. This permanently loses relational data and can fail when adding back a non-null event_id to non-empty dependent tables.

Safer migration strategy (non-destructive)
  1. Add a new nullable UUID column to events (e.g., uuid_id) and backfill it for all existing rows.
  2. Add nullable UUID shadow FKs on dependent tables (e.g., event_uuid_id) and backfill via join on old int IDs.
  3. Switch constraints/indexes and PK/FKs to UUID after backfill is complete.
  4. Only then drop old int columns.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app-modules/events/database/migrations/2026_05_13_224916_recreate_events_table_with_uuid.php`
around lines 13 - 67, The migration is destructive: it drops event_id
FKs/columns and the events table before preserving/mapping existing integer IDs
to UUIDs, which will lose relations; instead implement a non-destructive
conversion: add a nullable uuid column on events (e.g., uuid_id) and backfill it
for each existing row, add nullable shadow FK columns on dependents
(events_talks.event_uuid_id, events_attendees.event_uuid_id,
events_sponsors.event_uuid_id, events_agenda.event_uuid_id) and backfill them by
joining on the old event_id, then create UUID constraints/indexes (make
events.id the uuid PK or swap PKs) and update the dependent tables to use
foreignUuid('event_id')->constrained('events')->cascadeOnDelete(), finally drop
the old integer event_id columns and any temporary uuid_id/old id columns after
verification; search for Schema::table(...)->dropColumn('event_id'),
Schema::dropIfExists('events'), Schema::create('events'), and the
foreignUuid(...) calls to update the migration flow accordingly.

}

public function down(): void
{
Schema::table('events_talks', function (Blueprint $table): void {
$table->dropForeign('events_talks_event_id_foreign');
$table->dropColumn('event_id');
});

Schema::table('events_attendees', function (Blueprint $table): void {
$table->dropForeign('events_attendees_event_id_foreign');
$table->dropColumn('event_id');
});

Schema::table('events_sponsors', function (Blueprint $table): void {
$table->dropForeign('events_sponsors_event_id_foreign');
$table->dropColumn('event_id');
});

Schema::table('events_agenda', function (Blueprint $table): void {
$table->dropForeign('events_agenda_event_id_foreign');
$table->dropColumn('event_id');
});

Schema::dropIfExists('events');

Schema::create('events', function (Blueprint $table): void {
$table->id();
$table->foreignId('tenant_id')->nullable()->constrained('tenants')->nullOnDelete();
$table->string('event_type');
$table->boolean('active');
$table->string('slug');
$table->string('title');
$table->text('description');
$table->timestamp('event_at');
$table->timestamp('start_at');
$table->timestamp('end_at');
$table->string('location');
$table->integer('max_attendees');
$table->integer('attendees_count')->default(0);
$table->integer('waitlist_count')->default(0);
$table->timestamps();
});

Schema::table('events_talks', function (Blueprint $table): void {
$table->foreignId('event_id')->constrained('events')->cascadeOnDelete();
});

Schema::table('events_attendees', function (Blueprint $table): void {
$table->foreignId('event_id')->constrained('events')->cascadeOnDelete();
});

Schema::table('events_sponsors', function (Blueprint $table): void {
$table->foreignId('event_id')->constrained('events')->cascadeOnDelete();
});

Schema::table('events_agenda', function (Blueprint $table): void {
$table->foreignId('event_id')->constrained('events')->cascadeOnDelete();
});
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?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('event_enrollment_policies', function (Blueprint $table): void {
$table->uuid('id')->primary();
$table->timestamps();
$table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete();
$table->unique('event_id');
$table->string('enrollment_method');
$table->string('check_in_method');
$table->integer('capacity');
$table->boolean('has_waitlist')->default(false);
$table->integer('cancellation_deadline_h');
$table->jsonb('application_form')->nullable();
$table->boolean('requires_approval')->default(false);
$table->integer('xp_reward_rsvp')->default(0);
$table->integer('xp_reward_checkin')->default(0);
$table->integer('xp_reward_referral')->default(0);
$table->decimal('venue_lat', 11, 7)->nullable();
$table->decimal('venue_lng', 12, 10)->nullable();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix longitude precision/scale to support full valid range.

Line 29 uses decimal(12, 10), which only supports up to ±99.9999999999. Valid longitude needs up to ±180, so many real locations cannot be stored.

Suggested fix
-            $table->decimal('venue_lng', 12, 10)->nullable();
+            $table->decimal('venue_lng', 13, 10)->nullable();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$table->decimal('venue_lng', 12, 10)->nullable();
$table->decimal('venue_lng', 13, 10)->nullable();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app-modules/events/database/migrations/2026_05_13_225144_create_event_enrollment_policies_table.php`
at line 29, The longitude column definition uses $table->decimal('venue_lng',
12, 10)->nullable() which cannot represent values up to ±180; update the
migration to use a precision/scale that allows three integer digits plus desired
fractional digits (for example $table->decimal('venue_lng', 11, 8)->nullable())
so valid longitudes are stored; modify the same pattern wherever venue_lng is
defined (and consider doing the same check for venue_lat if present).

});
}

public function down(): void
{
Schema::dropIfExists('event_enrollment_policies');
}
};
Original file line number Diff line number Diff line change
@@ -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('check_in_codes', function (Blueprint $table): void {
$table->uuid('id')->primary();
$table->timestamps();
$table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete();
$table->string('code');
$table->timestamp('valid_from')->nullable();
$table->timestamp('valid_until')->nullable();
$table->integer('max_uses')->nullable();
$table->unique(['event_id', 'code']);
});
}

public function down(): void
{
Schema::dropIfExists('check_in_codes');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?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('event_enrollments', function (Blueprint $table): void {
$table->uuid('id')->primary();
$table->timestamps();
$table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete();
$table->foreignUuid('user_id')->constrained('users')->cascadeOnDelete();
$table->string('status')->index();
$table->integer('waitlist_position')->nullable();
$table->string('source')->nullable();
$table->uuid('referral_id')->nullable();
$table->jsonb('application_data')->nullable();
$table->boolean('is_public')->default(false);
$table->string('rejection_reason')->nullable();
$table->timestamp('enrolled_at')->nullable();
$table->timestamp('approved_at')->nullable();
$table->timestamp('confirmed_at')->nullable();
$table->timestamp('cancelled_at')->nullable();
$table->timestamp('checked_in_at')->nullable();
$table->timestamp('completed_at')->nullable();
$table->unique(['event_id', 'user_id']);
});
}

public function down(): void
{
Schema::dropIfExists('event_enrollments');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?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('enrollment_transitions', function (Blueprint $table): void {
$table->uuid('id')->primary();
$table->timestamps();
$table->foreignUuid('enrollment_id')->constrained('event_enrollments')->cascadeOnDelete();
$table->string('from_status')->nullable();
$table->string('to_status');
$table->string('triggered_by');
$table->foreignUuid('actor_user_id')->nullable()->constrained('users')->nullOnDelete();
$table->text('reason')->nullable();
$table->index(['enrollment_id', 'created_at']);
});
}

public function down(): void
{
Schema::dropIfExists('enrollment_transitions');
}
};
Original file line number Diff line number Diff line change
@@ -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::create('event_check_ins', function (Blueprint $table): void {
$table->uuid('id')->primary();
$table->timestamps();
$table->foreignUuid('enrollment_id')->constrained('event_enrollments')->cascadeOnDelete();
$table->string('method');
$table->jsonb('payload')->nullable();
$table->foreignUuid('verified_by_user_id')->nullable()->constrained('users')->nullOnDelete();
$table->unique('enrollment_id');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Unique constraint on enrollment_id prevents multiple check-in records.

The unique constraint means each enrollment can have only one check-in record. This design prevents tracking:

  • Multiple check-in attempts (for retry scenarios)
  • Re-entries if the event spans multiple days
  • Failed verification attempts followed by successful ones

If the business requirement truly enforces "one check-in per enrollment ever," this is correct. However, most event systems track all check-in attempts for audit and analytics.

Consider removing this constraint to allow multiple check-in records per enrollment, or clarify in a comment that only the most recent/valid check-in is stored.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app-modules/events/database/migrations/2026_05_13_225146_create_event_check_ins_table.php`
at line 20, The migration adds a unique constraint on enrollment_id (the line
$table->unique('enrollment_id')) which prevents multiple EventCheckIn records
per enrollment; remove that uniqueness or replace it with a non-unique index so
multiple check-ins can be recorded (or, if the intent is to keep only one
record, add a clarifying comment and enforce deduplication in application
logic). Locate the CreateEventCheckIns migration and remove or change
$table->unique('enrollment_id') to $table->index('enrollment_id') (or delete the
line) and, if needed, add a short comment explaining the chosen behavior for
EventCheckIn records.

});
}

public function down(): void
{
Schema::dropIfExists('event_check_ins');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?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('event_xp_rewards', function (Blueprint $table): void {
$table->uuid('id')->primary();
$table->timestamps();
$table->foreignUuid('user_id')->constrained('users')->cascadeOnDelete();
$table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete();
$table->foreignUuid('enrollment_id')->constrained('event_enrollments')->cascadeOnDelete();
$table->string('reason');
$table->integer('xp_amount');
$table->string('source_type');
$table->uuid('source_id');
Comment on lines +21 to +22
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Polymorphic relationship without referential integrity.

The source_type/source_id columns implement a polymorphic relationship pattern, but source_id has no foreign key constraint. This creates a data integrity risk:

  • source_id can reference deleted records
  • No database-level enforcement prevents orphaned references
  • Application code must manually maintain consistency

While polymorphic foreign keys are not directly supported in SQL, consider:

  1. Adding application-level validation to ensure source_id references exist before insert/update
  2. Adding database triggers if supported
  3. Documenting this constraint clearly
  4. Implementing regular cleanup jobs to detect/fix orphaned references

Consider adding monitoring/alerts for orphaned source_id references to catch data integrity violations early.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app-modules/events/database/migrations/2026_05_13_225146_create_event_xp_rewards_table.php`
around lines 21 - 22, The migration creates polymorphic columns source_type and
source_id in the EventXpRewards table without referential integrity; add
safeguards by implementing application-level validation in the EventXpRewards
model/repository to verify the referenced record exists for the given
source_type/source_id before insert/update, add a documented contract in the
migration/class comment (create_event_xp_rewards_table / EventXpRewards)
describing the expected source types and lifecycle, and optionally add a DB
trigger or scheduled cleanup/monitoring job to detect and remediate orphaned
source_id entries and emit alerts when mismatches are found.

$table->unique(['enrollment_id', 'reason']);
});
}

public function down(): void
{
Schema::dropIfExists('event_xp_rewards');
}
};
Original file line number Diff line number Diff line change
@@ -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::create('magic_links', function (Blueprint $table): void {
$table->uuid('id')->primary();
$table->timestamps();
$table->foreignUuid('enrollment_id')->constrained('event_enrollments')->cascadeOnDelete();
$table->string('token')->unique();
$table->timestamp('expires_at')->nullable();
$table->timestamp('used_at')->nullable();
$table->string('sent_to_email');
});
}

public function down(): void
{
Schema::dropIfExists('magic_links');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?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('qr_tokens', function (Blueprint $table): void {
$table->uuid('id')->primary();
$table->timestamps();
$table->foreignUuid('enrollment_id')->constrained('event_enrollments')->cascadeOnDelete();
$table->string('token')->unique();
$table->timestamp('expires_at')->nullable();
$table->timestamp('used_at')->nullable();
});
Comment on lines +13 to +20
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pensando melhor: QR Tokens é uma abstração "fraca" creio eu.

No final, se tivermos algum app de leitura ou algo do tipo, só precisamos ler o "uuid" da entrada dessa pessoa no evento e marcar como check-in, logo isso não é tão necessário.

}

public function down(): void
{
Schema::dropIfExists('qr_tokens');
}
};
Loading