Skip to content

feat(integration-discord): normalize Discord entities for community health metrics#261

Merged
danielhe4rt merged 7 commits into
4.xfrom
feat/discord-integration
May 20, 2026
Merged

feat(integration-discord): normalize Discord entities for community health metrics#261
danielhe4rt merged 7 commits into
4.xfrom
feat/discord-integration

Conversation

@danielhe4rt
Copy link
Copy Markdown
Contributor

@danielhe4rt danielhe4rt commented May 20, 2026

Summary

  • Adds 6 normalized tables (discord_guilds, discord_channels, discord_roles, discord_members, discord_member_roles, discord_member_role_history) to replace JSONB-only storage of Discord entities
  • Implements full API sync via php artisan discord:sync that fetches guild state from Discord REST API (channels, roles, paginated members)
  • Adds real-time event-driven updates via DiscordEventLogObserver that normalizes gateway events (GUILD_MEMBER_ADD/REMOVE/UPDATE, GUILD_AUDIT_LOG_ENTRY_CREATE, VOICE_STATE_UPDATE) into relational tables as they arrive
  • Tracks both current role state (pivot table) and role change history (append-only log) for trend analysis
  • Links discord_guilds to tenants and discord_members to external_identities via optional FKs

Motivation

The discord_event_logs table stores raw JSONB payloads — great for a data lake, but impossible to query efficiently for community health dashboards (e.g., "messages per channel", "role growth trends", "member retention funnels"). These normalized tables enable SQL-native analytics without JSON parsing at query time.

New files

Layer Files
Migrations 6 tables with FKs, indexes, composite keys
Enums DiscordChannelType (12 types), RoleHistoryAction (assigned/removed)
Models DiscordGuild, DiscordChannel, DiscordRole, DiscordMember, DiscordMemberRoleHistory
Factories 4 factories with states (voice(), category(), bot(), pending(), left())
Transport GetGuild, ListGuildChannels, ListGuildRoles, ListGuildMembers (paginated)
Sync SyncDiscordGuildAction, SyncDiscordGuildCommand, DiscordEventLogObserver, 5 event handlers

Test plan

  • Run php artisan discord:sync against the He4rt guild and verify tables are populated
  • Verify gateway events (member join/leave/update, role changes) update normalized tables in real-time
  • Verify --fresh flag truncates and re-imports cleanly
  • Confirm existing tests still pass (183 tests, 452 assertions)
  • PHPStan passes at configured level

Review Change Stack

…ation

Tables: discord_guilds, discord_channels, discord_roles, discord_members,
discord_member_roles (pivot), discord_member_role_history (append-only log).
Models: DiscordGuild, DiscordChannel, DiscordRole, DiscordMember,
DiscordMemberRoleHistory with full relationships and PHPDoc annotations.
Factories with useful states (voice/category channels, bot/pending/left members).
Also adds @Property annotations to DiscordEventLog for PHPStan.
GetGuild, ListGuildChannels, ListGuildRoles, ListGuildMembers (paginated).
…mmand

SyncDiscordGuildAction: full API sync (guild, channels, roles, members).
SyncDiscordGuildCommand: `php artisan discord:sync {guild_id?} --fresh`.
DiscordEventLogObserver: routes gateway events to normalize tables in real-time.
Handlers: HandleMemberAdd, HandleMemberRemove, HandleMemberUpdate,
HandleAuditLogEntry (role changes), HandleVoiceStateUpdate.
@danielhe4rt danielhe4rt merged commit 49dcb37 into 4.x May 20, 2026
5 of 6 checks passed
@danielhe4rt danielhe4rt deleted the feat/discord-integration branch May 20, 2026 00:18
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR implements normalized Discord entity storage for the integration-discord module. It creates a relational schema (guilds, channels, roles, members) with junction and history tables, defines corresponding Eloquent models and factories, and establishes dual-path synchronization: batch full-sync via a console command and event-driven incremental sync via observer-handler dispatch of DiscordEventLog entries. The change includes transport request classes for Discord API calls, a sync orchestration action, five event handlers for member/role/audit changes, and design documentation.

Possibly related PRs

  • he4rt/heartdevs.com#259: Adds RawGatewayEvent writes to DiscordEventLog in bot-discord module; this PR consumes those logs via the new DiscordEventLogObserver and event handlers.
  • he4rt/heartdevs.com#207: Extends Artisan command registration in IntegrationDiscordServiceProvider; this PR similarly registers SyncDiscordGuildCommand in the same command list.

Suggested reviewers

  • davicbtoliveira
  • gvieira18
  • 1pride
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.05% 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 summarizes the main change: normalizing Discord entities to enable community health metrics. It accurately reflects the primary objective of the PR, which is to transform JSONB-only storage into normalized relational tables.
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.


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.

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.

3 participants