Skip to content

feat(profile): add profile module with tenant-scoped user profiles#274

Merged
danielhe4rt merged 6 commits into
he4rt:4.xfrom
BrunoSFreschi:4.x
May 23, 2026
Merged

feat(profile): add profile module with tenant-scoped user profiles#274
danielhe4rt merged 6 commits into
he4rt:4.xfrom
BrunoSFreschi:4.x

Conversation

@BrunoSFreschi
Copy link
Copy Markdown
Contributor

@BrunoSFreschi BrunoSFreschi commented May 21, 2026

Principais pontos:

  • Novo pacote he4rt/profile registrado em composer.json e composer.lock.
  • Migration user_profiles com UUID, escopo por tenant, unique(user_id, tenant_id) e índice parcial para available_for_proposals = true.
  • Model Profile com HasUuids, factory, relacionamentos, casts de enum/date/bool/array e validação das chaves de social_links.
  • Enums SeniorityLevel, StartAvailability e SocialPlatform com labels pt-BR.
  • ProfileServiceProvider registrando migrations, morph map e criação eager quando há insert em tenant_users via attach.
  • Testes cobrindo criação automática, não duplicação, múltiplos tenants, factory, labels e validação de social_links.

Description

This PR introduces a new he4rt/profile module providing tenant-scoped user profiles with automatic creation when users join tenants. It includes database migrations with UUID primary keys, Eloquent models with relationships and validation, enums for seniority levels and job availability, factories, comprehensive tests, and localized translations. The PR also refactors console commands across multiple modules to use PHP 8 attributes for metadata declarations, and relocates the TenantUserObserver to the identity module with proper observer registration.

References

  • Related to ongoing modularization efforts (see commits: refactor(profile): move TenantUserObserver to identity module)
  • Complements recent integration modules: Twitch (#272), Admin Panel (#206), Discord ETL (#205)
  • Code quality improvements (#276)

Dependencies & Requirements

  • New dependency added: he4rt/profile (>=1)
  • Updated dependencies:
    • filament/filament: ^5.6.4 → ^5.6.5
    • filament/spatie-laravel-media-library-plugin: ^5.6.4 → ^5.6.5
    • guzzlehttp/guzzle: ^7.10.3 → ^7.10.4
    • driftingly/rector-laravel: ^2.3.0 → ^2.4.0 (dev)

Contributor Summary

Contributor Lines Added Lines Removed Files Changed
BrunoSFreschi 510+ 95+ 40+

Changes Summary

File Path Change Description
app-modules/profile/composer.json New profile module package with PSR-4 autoloading and service provider registration
app-modules/profile/src/Models/Profile.php Profile model with tenant relationships, social links validation, enum casting
app-modules/profile/database/migrations/2026_05_21_000000_create_user_profiles_table.php user_profiles table with UUID PK, composite unique constraint, partial index
app-modules/profile/database/factories/ProfileFactory.php ProfileFactory with definition and complete states
app-modules/profile/src/Enums/SeniorityLevel.php Enum for professional levels (Junior-Lead) with Filament integration
app-modules/profile/src/Enums/SocialPlatform.php Enum for social platforms with icon/label support
app-modules/profile/src/Enums/StartAvailability.php Enum for job availability with Filament contracts
app-modules/profile/src/ProfileServiceProvider.php Service provider for migrations, translations, morph maps
app-modules/profile/tests/Feature/ProfileCreationTest.php Feature tests for automatic profile creation
app-modules/profile/tests/Unit/ProfileEnumTest.php Unit tests for enum implementations
app-modules/profile/lang/en/enums.php, pt_BR/enums.php Enum label translations
app-modules/identity/src/Tenant/Models/TenantUser.php Pivot model with ObservedBy attribute
app-modules/identity/src/Tenant/Observers/TenantUserObserver.php Observer for automatic profile creation
Multiple console commands (10+ files) Converted to #[Signature] and #[Description] attributes
composer.json Updated dependencies including he4rt/profile

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR introduces a complete Profile module as a reusable Laravel package component alongside changes to tenant membership via a custom pivot model. The Profile module defines three Filament-integrated enums for seniority level, social platform, and start availability; an Eloquent model with relationships and validation for user profiles scoped to tenants; a migration establishing the underlying user_profiles table; and tests validating creation, duplication prevention, and multi-tenancy. A new TenantUser pivot model with an observer automatically creates profile records when users are attached to tenants. The identity module relationships are updated to use this pivot model. Additionally, 12 console commands across multiple modules are refactored to use PHP 8 attribute-based metadata instead of protected properties, and external identities display now uses badge styling. Root composer and package dependencies are updated.

Possibly related issues

  • he4rt/heartdevs.com#251: Main issue requesting the Profile module implementation (model, enums, factory, migration, service provider) with TenantUser pivot and observer for auto-creating profiles on tenant join — directly addressed by this PR.
  • he4rt/heartdevs.com#250: PRD describing the Profile module specification (models, enums, migration, service provider, tenant-user observer, tests, and composer package) — directly implemented in this PR.

Possibly related PRs

  • he4rt/heartdevs.com#187: The ProfileServiceProvider in this PR registers an Eloquent Relation::morphMap entry for polymorphic type aliases (profileHe4rt\Profile\Models\Profile), which aligns with that PR's refactor toward morph alias mappings instead of fully qualified class names in model_type fields.

Suggested reviewers

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

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.42% 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 pull request title clearly and specifically describes the main change: adding a new profile module with tenant-scoped user profiles, which is the primary focus of the changeset.
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.

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: 2

🤖 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/profile/src/ProfileServiceProvider.php`:
- Around line 25-26: The SQL matching is too strict: update the INSERT detection
in ProfileServiceProvider (the preg_match that checks $event->sql) to accept
optional leading whitespace, optional schema qualification, and either backtick
or double-quote quoting around identifiers (tenant_users), e.g. allow
`schema`.`tenant_users`, "schema"."tenant_users", or tenant_users; similarly,
harden insertColumns() to strip/normalize backticks and double-quotes and to
handle schema-qualified table names before extracting column lists — normalize
the SQL (lowercase for matching, remove/replace surrounding quotes on
identifiers) then apply relaxed regexes so schema-qualified and backtick-quoted
INSERTs are correctly detected and parsed.

In `@app-modules/profile/tests/Feature/ProfileCreationTest.php`:
- Around line 68-77: The test is relying on ordered tenant_id values which is
flaky with UUIDs; remove the explicit orderBy('tenant_id') on the
Profile::query() call and change the assertion that checks tenant IDs (the
expect(...)->toHaveCount(2) and ->and($profiles->pluck('tenant_id')->all())
portion) to assert membership regardless of order (e.g., compare as unordered
sets or use an assertion that canonicalizes/sorts both arrays) so the test
verifies the two tenant IDs are present without depending on their order.
🪄 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: c1bc62ca-283d-42d9-bc68-ea5b7468afff

📥 Commits

Reviewing files that changed from the base of the PR and between efd05ff and a27371f.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • app-modules/profile/composer.json
  • app-modules/profile/database/factories/ProfileFactory.php
  • app-modules/profile/database/migrations/2026_05_21_000000_create_user_profiles_table.php
  • app-modules/profile/phpstan.ignore.neon
  • app-modules/profile/phpstan.neon
  • app-modules/profile/src/Enums/SeniorityLevel.php
  • app-modules/profile/src/Enums/SocialPlatform.php
  • app-modules/profile/src/Enums/StartAvailability.php
  • app-modules/profile/src/Listeners/CreateProfileForTenantMember.php
  • app-modules/profile/src/Models/Profile.php
  • app-modules/profile/src/ProfileServiceProvider.php
  • app-modules/profile/tests/Feature/ProfileCreationTest.php
  • app-modules/profile/tests/Unit/ProfileEnumTest.php
  • app-modules/profile/tests/Unit/ProfileSocialLinksTest.php
  • composer.json

Comment thread app-modules/profile/src/ProfileServiceProvider.php Outdated
Comment thread app-modules/profile/tests/Feature/ProfileCreationTest.php Outdated
@Hadzab Hadzab requested a review from a team May 22, 2026 13:51
Copy link
Copy Markdown
Contributor Author

@BrunoSFreschi BrunoSFreschi left a comment

Choose a reason for hiding this comment

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

Acho que bugo tudo aqui, não aparecem as alterações para mim!

Copy link
Copy Markdown
Contributor

@danielhe4rt danielhe4rt left a comment

Choose a reason for hiding this comment

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

Primo, obrigado pelo PR! Acho valido algumas coisas pra te ajudar na refatoração:

  • Rode "php artisan boost:update" pra instalar as guidelines de Laravel no seu agent.
  • use o /laravel-best-practices pra te orientar no desenvolvimento.

Assim que terminar essas mudanças, mergeamos!

Comment thread app-modules/profile/src/Enums/SeniorityLevel.php Outdated
Comment thread app-modules/profile/src/Enums/SeniorityLevel.php Outdated
Comment thread app-modules/profile/src/Enums/SocialPlatform.php Outdated
Comment thread app-modules/profile/src/Enums/StartAvailability.php Outdated
Comment thread app-modules/profile/src/ProfileServiceProvider.php Outdated
Comment thread app-modules/profile/src/ProfileServiceProvider.php Outdated
Comment thread app-modules/profile/src/Listeners/CreateProfileForTenantMember.php Outdated
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: 2

🤖 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/profile/tests/Unit/ProfileEnumTest.php`:
- Around line 18-22: The test currently only checks that
SeniorityLevel::Junior->getLabel(), ::Mid, ::Senior, ::Specialist, and ::Lead
return non-empty strings but doesn't verify translations resolved; update the
assertions to also assert each returned label is not equal to its translation
key (e.g., compare getLabel() != 'profile.seniority_level.junior' for Junior,
similarly for Mid, Senior, Specialist, Lead) so the test fails when the
translator returns the raw key; use the same enum case symbols
(SeniorityLevel::Junior->getLabel(), ::Mid->getLabel(), ::Senior->getLabel(),
::Specialist->getLabel(), ::Lead->getLabel()) to locate and modify the
assertions.
- Around line 48-53: The test "all seniority level cases have distinct colors
and icons" currently only checks counts; change it to verify uniqueness by
comparing the number of unique color and icon values to the number of
SeniorityLevel::cases(). For the arrays produced from SeniorityLevel::cases()
via getColor() and getIcon(), replace the simple count assertions with checks
that count(array_unique($colors)) === count(SeniorityLevel::cases()) and
count(array_unique($icons)) === count(SeniorityLevel::cases()) (or use the
collection unique() method and count()), so duplicate colors/icons will fail the
test.
🪄 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: efa960cf-2b72-4dd2-9dbb-1252a4488d2e

📥 Commits

Reviewing files that changed from the base of the PR and between a27371f and d7f8fe4.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • app-modules/identity/src/Tenant/Concerns/InteractsWithTenants.php
  • app-modules/identity/src/Tenant/Models/Tenant.php
  • app-modules/identity/src/Tenant/Models/TenantUser.php
  • app-modules/profile/lang/en/enums.php
  • app-modules/profile/lang/pt_BR/enums.php
  • app-modules/profile/src/Enums/SeniorityLevel.php
  • app-modules/profile/src/Enums/SocialPlatform.php
  • app-modules/profile/src/Enums/StartAvailability.php
  • app-modules/profile/src/Observers/TenantUserObserver.php
  • app-modules/profile/src/ProfileServiceProvider.php
  • app-modules/profile/tests/Feature/ProfileCreationTest.php
  • app-modules/profile/tests/Unit/ProfileEnumTest.php
✅ Files skipped from review due to trivial changes (3)
  • app-modules/identity/src/Tenant/Models/TenantUser.php
  • app-modules/profile/lang/en/enums.php
  • app-modules/profile/lang/pt_BR/enums.php

Comment thread app-modules/profile/tests/Unit/ProfileEnumTest.php
Comment thread app-modules/profile/tests/Unit/ProfileEnumTest.php
BrunoSFreschi and others added 3 commits May 23, 2026 15:07
- Rename SeniorityLevel::Pleno to Mid with value 'mid'
- Implement Filament enum interfaces (HasLabel, HasColor, HasIcon) on
  all profile enums following project conventions
- Add i18n support with en/pt_BR translation files for enum labels
- Replace hacky DB::listen SQL interception with proper TenantUser
  pivot model + Observer pattern for profile auto-creation
- Remove CreateProfileForTenantMember listener (logic moved to observer)
- Fix flaky UUID-ordering assertion in multi-tenant test
- Update tests for new enum API and observer-based creation
@danielhe4rt danielhe4rt changed the title app-profile feat(profile): add profile module with tenant-scoped user profiles May 23, 2026
- Add @Property annotations to TenantUser pivot for $user_id and $tenant_id
- Suppress PHPStan return.type on Profile::socialLinks() set-only Attribute
…d table names

Apply Rector rules: SignaturePropertyToSignatureAttributeRector,
DescriptionPropertyToDescriptionAttributeRector, TablePropertyToTableAttributeRector
@danielhe4rt danielhe4rt merged commit 3571307 into he4rt:4.x May 23, 2026
5 of 6 checks passed
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