Skip to content

feat(events): add database migrations for event management infrastructure#225

Open
GabrielFVDev wants to merge 4 commits into
he4rt:4.xfrom
GabrielFVDev:4.x
Open

feat(events): add database migrations for event management infrastructure#225
GabrielFVDev wants to merge 4 commits into
he4rt:4.xfrom
GabrielFVDev:4.x

Conversation

@GabrielFVDev
Copy link
Copy Markdown

@GabrielFVDev GabrielFVDev commented May 15, 2026

O módulo de events já tinha a tabela events base, mas sem suporte a inscrições gerenciadas, check-in, referrals ou networking. Esta PR
adiciona toda a estrutura de banco necessária para o fluxo completo de gestão de eventos, migrando também a tabela events para UUID
como chave primária.

O que foi implementado

Migração da tabela events para UUID

A tabela foi recriada com id do tipo UUID. As relações existentes (events_talks, events_attendees, events_sponsors,
events_agenda) tiveram suas FKs derrubadas e recriadas apontando para UUID.

Inscrições

Tabela Descrição
event_enrollment_policies Regras por evento: método, capacidade, fila de espera, formulário, XP por ação
event_enrollments Inscrição do usuário com status, posição na fila e timestamps por transição
enrollment_transitions Histórico auditável de mudanças de status por inscrição

Check-in

Tabela Descrição
check_in_codes Códigos de check-in por evento com janela de validade e limite de usos
event_check_ins Registro do check-in: método usado e quem verificou
qr_tokens Token de QR code individual por inscrição
magic_links Link de acesso sem senha enviado por email ao inscrito

Referrals

Tabela Descrição
event_referrals Link de indicação por usuário+evento com cliques, conversões e XP
event_referral_clicks Log de cada clique num link de indicação

XP e recompensas

Tabela Descrição
event_xp_rewards XP por inscrição, check-in ou indicação — único por (enrollment_id, reason)

Networking

Tabela Descrição
networking_profiles Perfil de networking do inscrito: bio, skills, interesses
networking_connections Conexões entre participantes de um mesmo evento

Fix na migration de external_identities

A conversão de metadata de json para jsonb agora é condicional ao driver pgsql, evitando falha em ambientes com SQLite.

Arquivos alterados

Migrations em app-modules/events/database/migrations/ salvo onde indicado.

Arquivo Tipo Descrição
recreate_events_table_with_uuid.php Novo Recria events com UUID
create_event_enrollment_policies_table.php Novo Políticas de inscrição
create_event_enrollments_table.php Novo Inscrições
create_check_in_codes_table.php Novo Códigos de check-in
create_enrollment_transitions_table.php Novo Histórico de status
create_event_check_ins_table.php Novo Check-ins realizados
create_event_xp_rewards_table.php Novo Recompensas de XP
create_magic_links_table.php Novo Magic links por email
create_qr_tokens_table.php Novo QR tokens individuais
create_event_referrals_table.php Novo Links de indicação
create_networking_connections_table.php Novo Conexões de networking
create_networking_profiles_table.php Novo Perfis de networking
create_event_referral_clicks_table.php Novo Log de cliques em referrals
add_referral_foreign_key_to_event_enrollments_table.php Novo FK referral_id em enrollments
identity/…/change_external_identities_metadata_to_jsonb.php Alterado Fix: condicional para pgsql

Como testar

  1. Rode php artisan migrate:fresh e confirme que todas as migrations executam sem erro
  2. Verifique que events.id é do tipo UUID no banco
  3. Confirme as FKs das tabelas dependentes (events_talks, etc.) apontando para UUID
  4. Confirme a FK circular: event_enrollments.referral_id → event_referrals.id
  5. Rode php artisan migrate:fresh --env=testing para garantir que não quebra em SQLite

Description

This PR introduces comprehensive database migration infrastructure for event management, converting the events table primary key to UUID and adding 13 new tables to support event enrollments, check-ins, referrals, XP rewards, and networking features. Additionally, a migration in the identity module conditionally converts external_identities.metadata to JSONB for PostgreSQL compatibility.

References

Related prior work:

Dependencies & Requirements

No new external dependencies added. No environment variables or configuration updates required. The migrations are compatible with both PostgreSQL and SQLite (conditional JSONB conversion for PostgreSQL).

Contributor Summary

Contributor Lines Added Lines Removed Files Changed
GabrielFVDev 908 0 20

Changes Summary

File Path Change Description
app-modules/events/database/migrations/2026_05_13_224916_recreate_events_table_with_uuid.php Converts events.id to UUID primary key, recreates table with full schema, re-establishes foreign keys to dependent tables
app-modules/events/database/migrations/2026_05_13_225144_create_event_enrollment_policies_table.php Creates table for enrollment rules per event with capacity, waitlist, approval, and XP reward configuration
app-modules/events/database/migrations/2026_05_13_225145_create_check_in_codes_table.php Creates table for event check-in codes with validity window and usage limits
app-modules/events/database/migrations/2026_05_13_225145_create_event_enrollments_table.php Creates table for event registrations with status tracking, waitlist position, and lifecycle timestamps
app-modules/events/database/migrations/2026_05_13_225146_create_enrollment_transitions_table.php Creates audit table for enrollment status transitions with actor tracking
app-modules/events/database/migrations/2026_05_13_225146_create_event_check_ins_table.php Creates table for recording event check-ins with method and verification tracking
app-modules/events/database/migrations/2026_05_13_225146_create_event_xp_rewards_table.php Creates table for XP rewards with unique constraint on (enrollment_id, reason)
app-modules/events/database/migrations/2026_05_13_225146_create_magic_links_table.php Creates table for magic link enrollment verification with expiration and usage tracking
app-modules/events/database/migrations/2026_05_13_225146_create_qr_tokens_table.php Creates table for QR code tokens for check-in with expiration support
app-modules/events/database/migrations/2026_05_13_225147_create_event_referrals_table.php Creates table for event referral tracking with click and conversion counters
app-modules/events/database/migrations/2026_05_13_225147_create_networking_connections_table.php Creates table for networking connections between event participants with status and messaging
app-modules/events/database/migrations/2026_05_13_225147_create_networking_profiles_table.php Creates table for participant networking profiles with skills and interests metadata
app-modules/events/database/migrations/2026_05_13_225148_create_event_referral_clicks_table.php Creates table for tracking event referral link clicks with IP and user agent data
app-modules/events/database/migrations/2026_05_13_225149_add_referral_foreign_key_to_event_enrollments_table.php Adds foreign key from event_enrollments.referral_id to event_referrals.id with null-on-delete
app-modules/identity/database/migrations/2026_04_19_000001_change_external_identities_metadata_to_jsonb.php Conditionally converts external_identities.metadata column from JSON to JSONB for PostgreSQL only

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

📝 Walkthrough

Walkthrough

This PR introduces a comprehensive database schema rebuild for event management, centered on converting the events table from integer to UUID primary keys. It establishes a complete enrollment infrastructure with status tracking, check-in mechanisms (codes, QR tokens, verification), gamification through XP rewards, a referral system with click tracking, and networking features for attendee connections. An independent identity migration update makes schema alterations conditional on the PostgreSQL database driver, improving cross-database compatibility.

Suggested reviewers

  • gvieira18
  • Clintonrocha98
  • thalesmengue
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and directly describes the main change: adding database migrations for event management infrastructure. It matches the primary objective of the PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (1)
app-modules/events/database/migrations/2026_05_13_225148_create_event_referral_clicks_table.php (1)

20-20: 💤 Low value

Consider using created_at instead of a separate clicked_at column.

The timestamps() call on line 15 already creates a created_at column that captures when the click record is inserted. Having a separate clicked_at column appears redundant unless:

  • There's a processing delay between the actual click and record insertion
  • You need to explicitly document the click time for business logic

If clicked_at always equals created_at, consider removing it to simplify the schema.

🤖 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_225148_create_event_referral_clicks_table.php`
at line 20, The migration currently adds a redundant clicked_at column; remove
the $table->timestamp('clicked_at') line in the
create_event_referral_clicks_table migration and rely on the existing
$table->timestamps() (created_at) to record the click time, or if you truly need
an explicit click time different from insertion time, instead make clicked_at
nullable and document in the migration why it differs from created_at; update
the migration name create_event_referral_clicks_table and any related model/seed
code to use created_at (or the nullable clicked_at) accordingly.
🤖 Prompt for all review comments with 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.

Inline comments:
In
`@app-modules/events/database/migrations/2026_05_13_224916_recreate_events_table_with_uuid.php`:
- Around line 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.
- Around line 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.

In
`@app-modules/events/database/migrations/2026_05_13_225144_create_event_enrollment_policies_table.php`:
- 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).

In
`@app-modules/events/database/migrations/2026_05_13_225146_create_event_check_ins_table.php`:
- 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.

In
`@app-modules/events/database/migrations/2026_05_13_225146_create_event_xp_rewards_table.php`:
- Around line 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.

In
`@app-modules/events/database/migrations/2026_05_13_225147_create_networking_connections_table.php`:
- Around line 17-18: Add a CHECK constraint to the
create_networking_connections_table migration so a row cannot have the same
value for initiator_user_id and target_user_id; specifically, after defining the
foreignUuid columns (initiator_user_id and target_user_id) add a schema-level
CHECK (initiator_user_id <> target_user_id) constraint (or issue an ALTER TABLE
... ADD CONSTRAINT no_self_connection CHECK (...) via DB::statement) to block
self-connections.
- Around line 16-21: The migration currently only ensures initiator_user_id and
target_user_id exist in users, not that they are attendees of the event; update
the schema so each user reference is constrained together with event_id against
the attendees table (e.g. event_attendees or attendees). Replace the
single-column foreignUuid->constrained('users') for initiator_user_id and
target_user_id with composite foreign keys: (event_id, initiator_user_id)
references attendees(event_id, user_id) ON DELETE CASCADE and (event_id,
target_user_id) references attendees(event_id, user_id) ON DELETE CASCADE
(ensure the attendees table has a composite PK/unique on (event_id, user_id) to
allow this). Keep the event_id foreign key and the
unique(['event_id','initiator_user_id','target_user_id']) constraint.

---

Nitpick comments:
In
`@app-modules/events/database/migrations/2026_05_13_225148_create_event_referral_clicks_table.php`:
- Line 20: The migration currently adds a redundant clicked_at column; remove
the $table->timestamp('clicked_at') line in the
create_event_referral_clicks_table migration and rely on the existing
$table->timestamps() (created_at) to record the click time, or if you truly need
an explicit click time different from insertion time, instead make clicked_at
nullable and document in the migration why it differs from created_at; update
the migration name create_event_referral_clicks_table and any related model/seed
code to use created_at (or the nullable clicked_at) accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 93bd298c-e795-42ea-812b-33aaf97d5f42

📥 Commits

Reviewing files that changed from the base of the PR and between 0c624a7 and cb75eec.

📒 Files selected for processing (15)
  • app-modules/events/database/migrations/2026_05_13_224916_recreate_events_table_with_uuid.php
  • app-modules/events/database/migrations/2026_05_13_225144_create_event_enrollment_policies_table.php
  • app-modules/events/database/migrations/2026_05_13_225145_create_check_in_codes_table.php
  • app-modules/events/database/migrations/2026_05_13_225145_create_event_enrollments_table.php
  • app-modules/events/database/migrations/2026_05_13_225146_create_enrollment_transitions_table.php
  • app-modules/events/database/migrations/2026_05_13_225146_create_event_check_ins_table.php
  • app-modules/events/database/migrations/2026_05_13_225146_create_event_xp_rewards_table.php
  • app-modules/events/database/migrations/2026_05_13_225146_create_magic_links_table.php
  • app-modules/events/database/migrations/2026_05_13_225146_create_qr_tokens_table.php
  • app-modules/events/database/migrations/2026_05_13_225147_create_event_referrals_table.php
  • app-modules/events/database/migrations/2026_05_13_225147_create_networking_connections_table.php
  • app-modules/events/database/migrations/2026_05_13_225147_create_networking_profiles_table.php
  • app-modules/events/database/migrations/2026_05_13_225148_create_event_referral_clicks_table.php
  • app-modules/events/database/migrations/2026_05_13_225149_add_referral_foreign_key_to_event_enrollments_table.php
  • app-modules/identity/database/migrations/2026_04_19_000001_change_external_identities_metadata_to_jsonb.php

Comment on lines +13 to +67
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->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();
});
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.

Comment on lines +13 to +31
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');
});
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.

$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).

$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.

Comment on lines +21 to +22
$table->string('source_type');
$table->uuid('source_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

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.

Comment on lines +16 to +21
$table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete();
$table->foreignUuid('initiator_user_id')->constrained('users')->cascadeOnDelete();
$table->foreignUuid('target_user_id')->constrained('users')->cascadeOnDelete();
$table->string('status');
$table->text('message')->nullable();
$table->unique(['event_id', 'initiator_user_id', 'target_user_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

Enforce attendee membership at the DB level for both users.

Right now, Line 17 and Line 18 only ensure the users exist, not that they are enrolled attendees of Line 16’s event. This allows invalid cross-event/non-attendee connections.

Suggested migration direction
 Schema::create('networking_connections', function (Blueprint $table): void {
     $table->uuid('id')->primary();
     $table->timestamps();
     $table->foreignUuid('event_id')->constrained('events')->cascadeOnDelete();
     $table->foreignUuid('initiator_user_id')->constrained('users')->cascadeOnDelete();
     $table->foreignUuid('target_user_id')->constrained('users')->cascadeOnDelete();
     $table->string('status');
     $table->text('message')->nullable();
     $table->unique(['event_id', 'initiator_user_id', 'target_user_id']);
+
+    // enforce both users are attendees of this event
+    $table->foreign(['event_id', 'initiator_user_id'])
+        ->references(['event_id', 'user_id'])
+        ->on('event_enrollments')
+        ->cascadeOnDelete();
+
+    $table->foreign(['event_id', 'target_user_id'])
+        ->references(['event_id', 'user_id'])
+        ->on('event_enrollments')
+        ->cascadeOnDelete();
 });
🤖 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_225147_create_networking_connections_table.php`
around lines 16 - 21, The migration currently only ensures initiator_user_id and
target_user_id exist in users, not that they are attendees of the event; update
the schema so each user reference is constrained together with event_id against
the attendees table (e.g. event_attendees or attendees). Replace the
single-column foreignUuid->constrained('users') for initiator_user_id and
target_user_id with composite foreign keys: (event_id, initiator_user_id)
references attendees(event_id, user_id) ON DELETE CASCADE and (event_id,
target_user_id) references attendees(event_id, user_id) ON DELETE CASCADE
(ensure the attendees table has a composite PK/unique on (event_id, user_id) to
allow this). Keep the event_id foreign key and the
unique(['event_id','initiator_user_id','target_user_id']) constraint.

Comment on lines +17 to +18
$table->foreignUuid('initiator_user_id')->constrained('users')->cascadeOnDelete();
$table->foreignUuid('target_user_id')->constrained('users')->cascadeOnDelete();
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 | 🟡 Minor | ⚡ Quick win

Block self-connections with a check constraint.

Line 17 and Line 18 currently allow a user to connect to themselves, which is usually invalid for networking flows.

Suggested constraint
 Schema::create('networking_connections', function (Blueprint $table): void {
@@
     $table->foreignUuid('initiator_user_id')->constrained('users')->cascadeOnDelete();
     $table->foreignUuid('target_user_id')->constrained('users')->cascadeOnDelete();
@@
+    $table->check('initiator_user_id <> target_user_id');
 });
🤖 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_225147_create_networking_connections_table.php`
around lines 17 - 18, Add a CHECK constraint to the
create_networking_connections_table migration so a row cannot have the same
value for initiator_user_id and target_user_id; specifically, after defining the
foreignUuid columns (initiator_user_id and target_user_id) add a schema-level
CHECK (initiator_user_id <> target_user_id) constraint (or issue an ALTER TABLE
... ADD CONSTRAINT no_self_connection CHECK (...) via DB::statement) to block
self-connections.

@YuriSouzaDev
Copy link
Copy Markdown
Contributor

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants