Skip to content

feat(profile): phase 1 — domain actions, legacy cleanup, and profile edit page#282

Merged
danielhe4rt merged 7 commits into
4.xfrom
feat/profile-phase-1
May 24, 2026
Merged

feat(profile): phase 1 — domain actions, legacy cleanup, and profile edit page#282
danielhe4rt merged 7 commits into
4.xfrom
feat/profile-phase-1

Conversation

@danielhe4rt
Copy link
Copy Markdown
Contributor

@danielhe4rt danielhe4rt commented May 23, 2026

Summary

Profile module phase 1 implementation (PRD #250). Delivers the core domain layer, legacy cleanup, and the full profile edit experience in the User panel.

Issues completed

Highlights

  • Domain actions: UpsertProfile validates about (max 500), headline (max 100), social_links against SocialPlatform enum, years_experience (0-50). ToggleAvailability requires start_availability when activating.
  • Legacy cleanup: Deleted 10 legacy files (Information, Address, actions, DTOs, exceptions, Filament schema). Updated bot commands (EditProfileCommand, IntroductionCommand, ProfileCommand) to use Profile module. Tables preserved as safety net.
  • Profile edit page: Custom Filament page with cover/avatar media header (hover overlay uploads), live preview card (sticky sidebar with XP bar, badges, social links), address section using Filament relationship('address'), availability toggle with conditional start_availability.
  • Security: File upload validation (image, mimes, max size), UUID filenames, tenant guard on getRecord(), null checks on bot command profile access.
  • Address: Polymorphic Address model with country select (18 countries, default BRA), Brazilian state select (27 UFs), city text input. Filament auto-loads/saves via relationship().

What's remaining (future PRs)

Test plan

  • 32 tests pass (24 profile module + 8 panel-app page tests)
  • PHPStan level passes with 0 errors
  • Pint formatting clean
  • Full test suite: 535 tests, 534 passed, 1 skipped (pre-existing)
  • Manual: verify bot commands work in Discord (EditProfile, Introduction, Profile)
  • Manual: verify profile page in User panel — form save, media uploads, address, preview card

Description

  • Phase 1 of the Profile module: adds domain actions (UpsertProfile, ToggleAvailability) with DTO, validation, and tests; migrates Discord bot commands and panel UI to use Profile; removes legacy Identity Information/Address artifacts. Approach: domain-first actions + DTO, Filament page and components, tests, and incremental cleanup while preserving legacy DB tables.

References

Dependencies & Requirements

  • No new composer/npm dependencies detected.
  • No environment variable or config changes required.
  • Database tables user_information and user_address retained as a safety net.
  • Discord bot command verification pending manual testing.

Contributor Summary

Contributor Lines Added Lines Removed Files Changed
danielhe4rt 416 458 18

Changes Summary

File Path Change Description
app-modules/profile/src/Actions/UpsertProfile.php New action to upsert profile with validation (about ≤500, headline ≤100, years_experience 0–50, social_links keys validated)
app-modules/profile/src/Actions/ToggleAvailability.php New action to toggle availability; requires StartAvailability when activating and preserves/deactivates start_availability appropriately
app-modules/profile/src/DTOs/UpsertProfileDTO.php New DTO with fromArray() factory (nickname, birthdate, about, headline, seniority_level, years_experience, social_links)
app-modules/profile/tests/Feature/UpsertProfileTest.php Feature tests for upsert behavior and validations
app-modules/profile/tests/Feature/ToggleAvailabilityTest.php Feature tests for availability flows
app-modules/panel-app/src/Pages/ProfilePage.php New Filament ProfilePage (form, mount/save, media handling, availability, social links)
app-modules/panel-app/resources/views/components/profile-media-header.blade.php New media header component (cover + avatar uploads)
app-modules/panel-app/resources/views/components/profile-preview-card.blade.php New profile preview card component
app-modules/panel-app/resources/views/pages/profile.blade.php New profile editor page view (includes form + preview)
app-modules/panel-app/tests/Feature/ProfilePageTest.php Livewire/Filament tests for ProfilePage
app-modules/panel-app/lang/en/profile.php New English translations for profile UI
app-modules/panel-app/lang/pt_BR/profile.php New Portuguese (pt_BR) translations for profile UI
app-modules/bot-discord/src/SlashCommands/EditProfileCommand.php Bot command migrated to Profile upsert flow; removed GitHub/LinkedIn fields; about max 500
app-modules/bot-discord/src/SlashCommands/IntroductionCommand.php Intro command migrated to UpsertProfile; removed GitHub/LinkedIn fields; about max 500
app-modules/bot-discord/src/SlashCommands/ProfileCommand.php Profile display now reads Profile model (nickname, about) and removes previous social fields
app-modules/bot-discord/src/SlashCommands/AddressCommand.php New /endereco command to collect/persist Brazilian state and city
app/Models/Address.php Added $fillable for mass assignment (addressable_type, addressable_id, country, state, city, zip_code)
tests/Feature/AddressTest.php Tests for user→address updateOrCreate behavior
app-modules/identity/src/User/Models/User.php Removed legacy information() HasOne relationship and updated docblock annotations
app-modules/identity/src/User/Models/Information.php Deleted legacy Information model and factory
app-modules/identity/src/User/Models/Address.php Deleted legacy Address model and factory
app-modules/identity/src/User/Actions/InformationUserAction.php Deleted legacy information persistence action
app-modules/identity/src/User/Actions/UpdateProfile.php Deleted legacy UpdateProfile action
app-modules/identity/src/User/DTOs/UpdateProfileDTO.php Deleted legacy DTO
app-modules/identity/src/User/DTOs/UpsertInformationDTO.php Deleted legacy DTO
app-modules/identity/src/User/Exceptions/ProfileException.php Deleted legacy exception
app-modules/identity/src/Filament/Shared/Schemas/UserInformationForm.php Deleted Filament user information schema
app-modules/identity/src/ExternalIdentity/Actions/CreateAccountByExternalIdentity.php Stopped creating legacy address/information after user creation
app-modules/profile/src/Models/Profile.php Expanded PHPDoc typing (Carbon, enums) — no logic changes
app/Console/Commands/ImportDiscordMembers.php Removed legacy GitHub URL update logic from import flow

Review Change Stack

Domain actions for profile management:
- UpsertProfileDTO with fromArray() factory for Filament/test compatibility
- UpsertProfile action with validation (about max 500, headline max 100, social_links enum check)
- ToggleAvailability action with required start_availability when activating
- Feature tests covering all BDD scenarios from the issue
…254)

- Delete Information and Address models, factories, actions, DTOs, exceptions
- Remove UserInformationForm Filament schema
- Remove information() relationship from User model
- Update EditProfileCommand and IntroductionCommand to use Profile module
- GitHub/LinkedIn fields removed from bot modals (now from OAuth/ExternalIdentity)
- Tables user_information and user_address preserved in database as safety net
@danielhe4rt danielhe4rt requested a review from a team May 23, 2026 20:46
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

📝 Walkthrough

Walkthrough

This PR migrates profile persistence from the Identity information flow to the new Profile module: it adds UpsertProfileDTO, UpsertProfile, and ToggleAvailability with validation and tests; updates Discord EditProfile/Introduction commands and adds AddressCommand; removes the User->information relationship and stops creating legacy information/address on external account creation; and introduces a Filament ProfilePage, Blade components, translations, provider registration, and accompanying tests.

Possibly related issues

Possibly related PRs

  • he4rt/heartdevs.com#274: Introduced foundational Profile models/enums/tenant observer that this PR builds on and integrates into commands and the Panel.
  • he4rt/heartdevs.com#276: Touches identity-domain model mapping and overlaps with deletions/changes to Identity Address/Information handled in this PR.

Suggested reviewers

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

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.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 specifically summarizes the main changes: introducing profile domain actions, cleaning up legacy code, and adding the profile edit page.
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.

🧹 Nitpick comments (4)
app-modules/profile/tests/Feature/UpsertProfileTest.php (1)

83-90: ⚡ Quick win

Add a lower-bound validation test for years_experience (-1).

The range contract is 0–50, but this suite only checks 51. Adding a -1 case closes a regression gap.

Suggested additional test
+test('upsert profile rejects years_experience below 0', function (): void {
+    $profile = Profile::factory()->create();
+    $dto = UpsertProfileDTO::fromArray([
+        'years_experience' => -1,
+    ]);
+
+    resolve(UpsertProfile::class)->handle($profile, $dto);
+})->throws(ValidationException::class);
🤖 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/profile/tests/Feature/UpsertProfileTest.php` around lines 83 -
90, Add a new test in UpsertProfileTest that mirrors the existing "upsert
profile rejects years_experience outside 0-50 range" case but passes
years_experience = -1 to UpsertProfileDTO::fromArray and asserts that
resolve(UpsertProfile::class)->handle($profile, $dto) throws
ValidationException; this ensures the lower bound is validated the same as the
existing upper-bound (51) test.
app-modules/profile/tests/Feature/ToggleAvailabilityTest.php (1)

53-62: ⚡ Quick win

Assert start_availability remains null in the idempotent deactivation case.

This test title says idempotent behavior, but it only asserts available_for_proposals. Add a start_availability assertion to lock the full contract.

Suggested test assertion
 test('deactivate already inactive availability is idempotent', function (): void {
     $profile = Profile::factory()->create([
         'available_for_proposals' => false,
         'start_availability' => null,
     ]);

     $result = resolve(ToggleAvailability::class)->handle($profile, false);

-    expect($result->available_for_proposals)->toBeFalse();
+    expect($result->available_for_proposals)->toBeFalse()
+        ->and($result->start_availability)->toBeNull();
 });
🤖 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/profile/tests/Feature/ToggleAvailabilityTest.php` around lines 53
- 62, The test "deactivate already inactive availability is idempotent"
currently only asserts available_for_proposals; add an assertion that
start_availability stays null to enforce the idempotent contract. After calling
resolve(ToggleAvailability::class)->handle($profile, false) (the $result
variable), add an assertion like expect($result->start_availability)->toBeNull()
so the test verifies both availability and start_availability remain unchanged.
app-modules/bot-discord/src/SlashCommands/IntroductionCommand.php (1)

125-127: 💤 Low value

Consider adding null-safe operator for consistency with EditProfileCommand.

EditProfileCommand uses $components->get(...)?->value with null-safe operator, while this file accesses .value directly. Although these are required fields (unlikely to be null), the inconsistency could lead to confusion or issues if the modal submission behavior changes.

🤖 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/bot-discord/src/SlashCommands/IntroductionCommand.php` around
lines 125 - 127, The three lines in IntroductionCommand that access
$components->get('custom_id', ...)->value should use the null-safe operator like
EditProfileCommand to avoid potential null access; update the calls that set
$name, $nickname, and $about to use $components->get(...)?->value so they
gracefully handle a missing component value while keeping behavior consistent
with EditProfileCommand.
app-modules/bot-discord/src/SlashCommands/EditProfileCommand.php (1)

127-130: 💤 Low value

Consider passing the already-fetched profile to avoid duplicate query.

The profile is queried in handle() (lines 65-68) and again here in persistData(). While functional, this duplicates the database call. You could refactor persistData() to accept the profile as a parameter.

Note: There's also a theoretical race condition where the profile could be deleted between the two queries, causing firstOrFail() to throw an unexpected exception.

♻️ Suggested refactor to avoid duplicate query
-    private function persistData(
+    private function persistData(
         Interaction $interaction,
-        Collection $components
+        Collection $components,
+        Profile $profile
     ): void {
         try {
             $name = $components->get('custom_id', 'name')?->value;
             $nickname = $components->get('custom_id', 'nickname')?->value;
             $about = $components->get('custom_id', 'about')?->value;

             $this->memberProvider->user->update(['name' => $name]);

-            $profile = Profile::query()
-                ->where('user_id', $this->memberProvider->user->id)
-                ->where('tenant_id', $this->memberProvider->tenant_id)
-                ->firstOrFail();
-
             $dto = UpsertProfileDTO::fromArray([

Then update the caller at line 106-109 to pass $profile.

🤖 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/bot-discord/src/SlashCommands/EditProfileCommand.php` around
lines 127 - 130, Change persistData() to accept the already-fetched Profile
instance (e.g., function persistData(Profile $profile, ...)) and remove the
duplicate Profile::query()->where(...)->firstOrFail() call inside persistData;
update the code path that currently invokes persistData() to pass the $profile
returned in handle() instead of letting persistData re-query, and add a concise
guard in persistData (or the caller) to handle the case the profile is
null/deleted before use.
🤖 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.

Nitpick comments:
In `@app-modules/bot-discord/src/SlashCommands/EditProfileCommand.php`:
- Around line 127-130: Change persistData() to accept the already-fetched
Profile instance (e.g., function persistData(Profile $profile, ...)) and remove
the duplicate Profile::query()->where(...)->firstOrFail() call inside
persistData; update the code path that currently invokes persistData() to pass
the $profile returned in handle() instead of letting persistData re-query, and
add a concise guard in persistData (or the caller) to handle the case the
profile is null/deleted before use.

In `@app-modules/bot-discord/src/SlashCommands/IntroductionCommand.php`:
- Around line 125-127: The three lines in IntroductionCommand that access
$components->get('custom_id', ...)->value should use the null-safe operator like
EditProfileCommand to avoid potential null access; update the calls that set
$name, $nickname, and $about to use $components->get(...)?->value so they
gracefully handle a missing component value while keeping behavior consistent
with EditProfileCommand.

In `@app-modules/profile/tests/Feature/ToggleAvailabilityTest.php`:
- Around line 53-62: The test "deactivate already inactive availability is
idempotent" currently only asserts available_for_proposals; add an assertion
that start_availability stays null to enforce the idempotent contract. After
calling resolve(ToggleAvailability::class)->handle($profile, false) (the $result
variable), add an assertion like expect($result->start_availability)->toBeNull()
so the test verifies both availability and start_availability remain unchanged.

In `@app-modules/profile/tests/Feature/UpsertProfileTest.php`:
- Around line 83-90: Add a new test in UpsertProfileTest that mirrors the
existing "upsert profile rejects years_experience outside 0-50 range" case but
passes years_experience = -1 to UpsertProfileDTO::fromArray and asserts that
resolve(UpsertProfile::class)->handle($profile, $dto) throws
ValidationException; this ensures the lower bound is validated the same as the
existing upper-bound (51) test.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: 7a6840a6-3a01-4e55-9e7e-41738e5430f1

📥 Commits

Reviewing files that changed from the base of the PR and between 1a42ff0 and 4a91a13.

📒 Files selected for processing (18)
  • app-modules/bot-discord/src/SlashCommands/EditProfileCommand.php
  • app-modules/bot-discord/src/SlashCommands/IntroductionCommand.php
  • app-modules/identity/database/factories/AddressFactory.php
  • app-modules/identity/database/factories/InformationFactory.php
  • app-modules/identity/src/Filament/Shared/Schemas/UserInformationForm.php
  • app-modules/identity/src/User/Actions/InformationUserAction.php
  • app-modules/identity/src/User/Actions/UpdateProfile.php
  • app-modules/identity/src/User/DTOs/UpdateProfileDTO.php
  • app-modules/identity/src/User/DTOs/UpsertInformationDTO.php
  • app-modules/identity/src/User/Exceptions/ProfileException.php
  • app-modules/identity/src/User/Models/Address.php
  • app-modules/identity/src/User/Models/Information.php
  • app-modules/identity/src/User/Models/User.php
  • app-modules/profile/src/Actions/ToggleAvailability.php
  • app-modules/profile/src/Actions/UpsertProfile.php
  • app-modules/profile/src/DTOs/UpsertProfileDTO.php
  • app-modules/profile/tests/Feature/ToggleAvailabilityTest.php
  • app-modules/profile/tests/Feature/UpsertProfileTest.php
💤 Files with no reviewable changes (11)
  • app-modules/identity/database/factories/InformationFactory.php
  • app-modules/identity/src/Filament/Shared/Schemas/UserInformationForm.php
  • app-modules/identity/src/User/Actions/UpdateProfile.php
  • app-modules/identity/src/User/Models/Information.php
  • app-modules/identity/src/User/Exceptions/ProfileException.php
  • app-modules/identity/src/User/DTOs/UpdateProfileDTO.php
  • app-modules/identity/src/User/DTOs/UpsertInformationDTO.php
  • app-modules/identity/database/factories/AddressFactory.php
  • app-modules/identity/src/User/Actions/InformationUserAction.php
  • app-modules/identity/src/User/Models/Address.php
  • app-modules/identity/src/User/Models/User.php

- Add $fillable to Address model for mass assignment
- New /endereco command with autocomplete for Brazilian states (27 UFs)
- Persists country (BRA default), state (UF), and city via User's polymorphic address
- Add updateOrCreate test for address relationship
- Custom ProfilePage in User panel with cover/avatar media header
- Cover as full-width banner with hover overlay upload, avatar overlapping
- Live preview card (sticky sidebar) updates as fields change
- Gamification data: level, XP progress bar, badges via computed property
- Social links via Repeater with SocialPlatform enum
- Availability toggle with conditional start_availability
- Manual media uploads via WithFileUploads + Spatie Media Library
- Added 'cover' media collection to User model
- Translations in en + pt_BR
- 8 Livewire tests covering form load, save, validation, social links
…ew, media fixes

- Address section using Filament relationship('address') for auto load/save
- Country select with 18 countries (default BRA), state select with 27 UFs for BRA
- State field adapts: shows Brazilian states when BRA, empty select for other countries
- Location shown in preview card with map pin icon
- Hide preview card on mobile (hidden xl:block)
- Fix cover image using bg-cover instead of img tag
- Fix birthdate format (Carbon to Y-m-d for date input)
- Merge media header with personal section fields
…rors

- ProfileCommand: use Profile model instead of information relationship
- CreateAccountByExternalIdentity: remove information()->create() call
- ImportDiscordMembers: remove github_url import via legacy information model
- Profile model: add complete PHPDoc @Property block for all columns
- ProfilePage: fix socialLinks PHPDoc types and redundant operations
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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app-modules/identity/src/User/Models/User.php (1)

56-62: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Breaking API removal: information() is still called downstream.

CreateAccountByExternalIdentity still invokes $user->information()->create() (in app-modules/identity/src/ExternalIdentity/Actions/CreateAccountByExternalIdentity.php, context snippet). Removing this relationship here introduces a runtime fatal on account creation. Please migrate that caller in the same PR (or keep a temporary compatibility shim until migration is complete).

🤖 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/identity/src/User/Models/User.php` around lines 56 - 62, You
removed the User::information() relationship but CreateAccountByExternalIdentity
(in CreateAccountByExternalIdentity.php) still calls
$user->information()->create(), causing a runtime error; either restore a
compatibility shim by re-adding the information() relation on the User model
that proxies to the new providers() morphMany, or update
CreateAccountByExternalIdentity to use the new providers() relationship and its
expected payload (replace $user->information()->create(...) with
$user->providers()->create(...) and adjust attributes accordingly). Ensure both
symbols are updated consistently so CreateAccountByExternalIdentity and
User::providers() remain in sync.
🤖 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/panel-app/resources/views/components/profile-preview-card.blade.php`:
- Around line 99-100: The template profile-preview-card.blade.php contains
hardcoded Portuguese strings like "Disponível" (and similar labels at the other
locations) that bypass localization; replace each hardcoded label with a
translation helper call (e.g. __('panel-app::profile.some_key')) and add
corresponding keys to the panel-app::profile translation file, ensuring you use
descriptive keys (e.g. availability_label, status_online, etc.), then update the
Blade view instances (the span and the other occurrences referenced) to call
__() with those keys so locale switching works correctly.
- Around line 118-119: The Blade conditional is using truthiness so a valid
numeric 0 for $yearsExperience gets hidden; update the conditionals that
currently read things like "`@if` ($seniority || $yearsExperience)" and the
similar block around lines 139-143 to explicitly check for null (e.g., "`@if`
($seniority !== null || $yearsExperience !== null)") and any inner checks that
rely on truthiness to use !== null for $yearsExperience and $seniority so 0
renders correctly.

In `@app-modules/panel-app/src/Pages/ProfilePage.php`:
- Around line 70-78: The Profile properties are accessed dynamically
($profile->nickname, ->birthdate, ->headline, ->seniority_level,
->years_experience, ->about, ->social_links, ->available_for_proposals,
->start_availability) which PHPStan flags as undefined on
He4rt\Profile\Models\Profile; fix by giving the analyzer a concrete type: either
add PHPDoc `@property` annotations with correct types to the
He4rt\Profile\Models\Profile class, or add a local docblock/typed var before use
(/** `@var` \He4rt\Profile\Models\Profile $profile */), or replace dynamic access
with typed getters/getAttribute calls on Profile; ensure birthdate is typed as
?\DateTimeInterface if used with ->format and keep reference to
socialLinksToRepeater when preserving the social_links access.
- Around line 251-254: The match expression in ProfilePage:: (creating
$startAvailability) uses StartAvailability::from(...) which will throw on
invalid strings and cause 500s; change it to
StartAvailability::tryFrom($rawStartAvailability) so invalid input yields null
instead of an exception, keeping the existing match branches and ensuring
ToggleAvailability::handle still receives either a StartAvailability instance or
null/validation flow; update the branch that handles
is_string($rawStartAvailability) to call tryFrom rather than from.

---

Outside diff comments:
In `@app-modules/identity/src/User/Models/User.php`:
- Around line 56-62: You removed the User::information() relationship but
CreateAccountByExternalIdentity (in CreateAccountByExternalIdentity.php) still
calls $user->information()->create(), causing a runtime error; either restore a
compatibility shim by re-adding the information() relation on the User model
that proxies to the new providers() morphMany, or update
CreateAccountByExternalIdentity to use the new providers() relationship and its
expected payload (replace $user->information()->create(...) with
$user->providers()->create(...) and adjust attributes accordingly). Ensure both
symbols are updated consistently so CreateAccountByExternalIdentity and
User::providers() remain in sync.
🪄 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: f62c623b-c8bb-4172-bf6a-6d7d0398a7ed

📥 Commits

Reviewing files that changed from the base of the PR and between ece5f8e and 5d76db9.

📒 Files selected for processing (9)
  • app-modules/identity/src/User/Models/User.php
  • app-modules/panel-app/lang/en/profile.php
  • app-modules/panel-app/lang/pt_BR/profile.php
  • app-modules/panel-app/resources/views/components/profile-media-header.blade.php
  • app-modules/panel-app/resources/views/components/profile-preview-card.blade.php
  • app-modules/panel-app/resources/views/pages/profile.blade.php
  • app-modules/panel-app/src/Pages/ProfilePage.php
  • app-modules/panel-app/tests/Feature/ProfilePageTest.php
  • app/Providers/Filament/AppPanelProvider.php
✅ Files skipped from review due to trivial changes (1)
  • app-modules/panel-app/resources/views/components/profile-media-header.blade.php

Comment thread app-modules/panel-app/src/Pages/ProfilePage.php
Comment thread app-modules/panel-app/src/Pages/ProfilePage.php
- Validate file uploads (image, mimes, max size) via Livewire #[Validate]
- Use UUID filenames instead of client-provided names for media uploads
- Guard against null tenant in ProfilePage::getRecord()
- Null-check on $profile in ProfileCommand before accessing properties
- Fix preview card reading address from nested relationship path
- Replace resolve() with app() for container resolution
- Complete User model PHPDoc with suspended_until, banned_at, nullable timestamps
@danielhe4rt danielhe4rt changed the title feat(profile): phase 1 — domain actions and legacy cleanup feat(profile): phase 1 — domain actions, legacy cleanup, and profile edit page May 23, 2026
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: 1

🤖 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/Console/Commands/ImportDiscordMembers.php`:
- Line 76: Remove the dead --force code path and any stale GitHub overwrite
metrics: delete the call to option('force') in the command execution (search for
option('force') in ImportDiscordMembers class, likely inside handle()) and
remove the related log/output that reports GitHub overwrite/write counters (the
messages and variables that mention GitHub writes/overwrite counts). Also update
the command signature/help/description in the ImportDiscordMembers class to stop
advertising a --force flag so help/output no longer references that option or
GitHub overwrite metrics.
🪄 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: 03575527-810d-4b2e-8f49-ec5f15d2283c

📥 Commits

Reviewing files that changed from the base of the PR and between 5d76db9 and 87dd56f.

📒 Files selected for processing (7)
  • app-modules/bot-discord/src/SlashCommands/ProfileCommand.php
  • app-modules/identity/src/ExternalIdentity/Actions/CreateAccountByExternalIdentity.php
  • app-modules/identity/src/User/Models/User.php
  • app-modules/panel-app/resources/views/components/profile-preview-card.blade.php
  • app-modules/panel-app/src/Pages/ProfilePage.php
  • app-modules/profile/src/Models/Profile.php
  • app/Console/Commands/ImportDiscordMembers.php
💤 Files with no reviewable changes (1)
  • app-modules/identity/src/ExternalIdentity/Actions/CreateAccountByExternalIdentity.php
✅ Files skipped from review due to trivial changes (1)
  • app-modules/profile/src/Models/Profile.php

Comment thread app/Console/Commands/ImportDiscordMembers.php
@danielhe4rt danielhe4rt merged commit 193445f into 4.x May 24, 2026
6 checks passed
@danielhe4rt danielhe4rt deleted the feat/profile-phase-1 branch May 24, 2026 23:55
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