Showing preview only (7,832K chars total). Download the full file or copy to clipboard to get everything.
Repository: Relaticle/relaticle
Branch: main
Commit: 6ab18e87f8da
Files: 911
Total size: 7.3 MB
Directory structure:
gitextract_xr43z_zf/
├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .githooks/
│ └── pre-commit
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── 1-bug_report.yml
│ │ └── config.yml
│ ├── copilot-instructions.md
│ └── workflows/
│ ├── docker-publish.yml
│ ├── filament-view-monitor-simple.yml
│ └── tests.yml
├── .gitignore
├── CLAUDE.md
├── Dockerfile
├── LICENSE
├── README.md
├── TODOS.md
├── app/
│ ├── Actions/
│ │ ├── Company/
│ │ │ ├── CreateCompany.php
│ │ │ ├── DeleteCompany.php
│ │ │ ├── ListCompanies.php
│ │ │ └── UpdateCompany.php
│ │ ├── Fortify/
│ │ │ ├── CreateNewSocialUser.php
│ │ │ ├── PasswordValidationRules.php
│ │ │ ├── ResetUserPassword.php
│ │ │ ├── UpdateUserPassword.php
│ │ │ └── UpdateUserProfileInformation.php
│ │ ├── Jetstream/
│ │ │ ├── AddTeamMember.php
│ │ │ ├── CreateTeam.php
│ │ │ ├── DeleteTeam.php
│ │ │ ├── DeleteUser.php
│ │ │ ├── InviteTeamMember.php
│ │ │ ├── RemoveTeamMember.php
│ │ │ └── UpdateTeamName.php
│ │ ├── Note/
│ │ │ ├── CreateNote.php
│ │ │ ├── DeleteNote.php
│ │ │ ├── ListNotes.php
│ │ │ └── UpdateNote.php
│ │ ├── Opportunity/
│ │ │ ├── CreateOpportunity.php
│ │ │ ├── DeleteOpportunity.php
│ │ │ ├── ListOpportunities.php
│ │ │ └── UpdateOpportunity.php
│ │ ├── People/
│ │ │ ├── CreatePeople.php
│ │ │ ├── DeletePeople.php
│ │ │ ├── ListPeople.php
│ │ │ └── UpdatePeople.php
│ │ └── Task/
│ │ ├── CreateTask.php
│ │ ├── DeleteTask.php
│ │ ├── ListTasks.php
│ │ ├── NotifyTaskAssignees.php
│ │ └── UpdateTask.php
│ ├── Concerns/
│ │ └── DetectsTeamInvitation.php
│ ├── Console/
│ │ └── Commands/
│ │ ├── BackfillCustomFieldColorsCommand.php
│ │ ├── CleanupExpiredInvitationsCommand.php
│ │ ├── CreateSystemAdminCommand.php
│ │ ├── GenerateSitemapCommand.php
│ │ └── InstallCommand.php
│ ├── Contracts/
│ │ └── User/
│ │ └── CreatesNewSocialUsers.php
│ ├── Data/
│ │ └── SubscriberData.php
│ ├── Enums/
│ │ ├── CreationSource.php
│ │ ├── CustomFieldType.php
│ │ ├── CustomFields/
│ │ │ ├── CompanyField.php
│ │ │ ├── CustomFieldTrait.php
│ │ │ ├── NoteField.php
│ │ │ ├── OpportunityField.php
│ │ │ ├── PeopleField.php
│ │ │ └── TaskField.php
│ │ ├── SocialiteProvider.php
│ │ └── SubscriberTagEnum.php
│ ├── Filament/
│ │ ├── Actions/
│ │ │ └── GenerateRecordSummaryAction.php
│ │ ├── Components/
│ │ │ └── Infolists/
│ │ │ └── AvatarName.php
│ │ ├── Exports/
│ │ │ ├── BaseExporter.php
│ │ │ ├── CompanyExporter.php
│ │ │ ├── NoteExporter.php
│ │ │ ├── OpportunityExporter.php
│ │ │ ├── PeopleExporter.php
│ │ │ └── TaskExporter.php
│ │ ├── Pages/
│ │ │ ├── AccessTokens.php
│ │ │ ├── Auth/
│ │ │ │ ├── Login.php
│ │ │ │ └── Register.php
│ │ │ ├── CreateTeam.php
│ │ │ ├── EditProfile.php
│ │ │ ├── EditTeam.php
│ │ │ ├── OpportunitiesBoard.php
│ │ │ └── TasksBoard.php
│ │ └── Resources/
│ │ ├── CompanyResource/
│ │ │ ├── Pages/
│ │ │ │ ├── ListCompanies.php
│ │ │ │ └── ViewCompany.php
│ │ │ └── RelationManagers/
│ │ │ ├── NotesRelationManager.php
│ │ │ ├── PeopleRelationManager.php
│ │ │ └── TasksRelationManager.php
│ │ ├── CompanyResource.php
│ │ ├── NoteResource/
│ │ │ ├── Forms/
│ │ │ │ └── NoteForm.php
│ │ │ └── Pages/
│ │ │ └── ManageNotes.php
│ │ ├── NoteResource.php
│ │ ├── OpportunityResource/
│ │ │ ├── Forms/
│ │ │ │ └── OpportunityForm.php
│ │ │ ├── Pages/
│ │ │ │ ├── ListOpportunities.php
│ │ │ │ └── ViewOpportunity.php
│ │ │ └── RelationManagers/
│ │ │ ├── NotesRelationManager.php
│ │ │ └── TasksRelationManager.php
│ │ ├── OpportunityResource.php
│ │ ├── PeopleResource/
│ │ │ ├── Pages/
│ │ │ │ ├── ListPeople.php
│ │ │ │ └── ViewPeople.php
│ │ │ └── RelationManagers/
│ │ │ ├── NotesRelationManager.php
│ │ │ └── TasksRelationManager.php
│ │ ├── PeopleResource.php
│ │ ├── TaskResource/
│ │ │ ├── Forms/
│ │ │ │ └── TaskForm.php
│ │ │ └── Pages/
│ │ │ └── ManageTasks.php
│ │ └── TaskResource.php
│ ├── Health/
│ │ └── AnthropicModelCheck.php
│ ├── Http/
│ │ ├── Controllers/
│ │ │ ├── AcceptTeamInvitationController.php
│ │ │ ├── Api/
│ │ │ │ └── V1/
│ │ │ │ ├── CompaniesController.php
│ │ │ │ ├── CustomFieldsController.php
│ │ │ │ ├── NotesController.php
│ │ │ │ ├── OpportunitiesController.php
│ │ │ │ ├── PeopleController.php
│ │ │ │ └── TasksController.php
│ │ │ ├── Auth/
│ │ │ │ ├── CallbackController.php
│ │ │ │ └── RedirectController.php
│ │ │ ├── ContactController.php
│ │ │ ├── HomeController.php
│ │ │ ├── PrivacyPolicyController.php
│ │ │ └── TermsOfServiceController.php
│ │ ├── Middleware/
│ │ │ ├── ApplyTenantScopes.php
│ │ │ ├── EnsureTokenHasAbility.php
│ │ │ ├── ForceJsonResponse.php
│ │ │ ├── SetApiTeamContext.php
│ │ │ ├── SubdomainRootResponse.php
│ │ │ └── ValidateSignature.php
│ │ ├── Requests/
│ │ │ ├── Api/
│ │ │ │ └── V1/
│ │ │ │ ├── IndexCustomFieldsRequest.php
│ │ │ │ ├── IndexRequest.php
│ │ │ │ ├── StoreCompanyRequest.php
│ │ │ │ ├── StoreNoteRequest.php
│ │ │ │ ├── StoreOpportunityRequest.php
│ │ │ │ ├── StorePeopleRequest.php
│ │ │ │ ├── StoreTaskRequest.php
│ │ │ │ ├── UpdateCompanyRequest.php
│ │ │ │ ├── UpdateNoteRequest.php
│ │ │ │ ├── UpdateOpportunityRequest.php
│ │ │ │ ├── UpdatePeopleRequest.php
│ │ │ │ └── UpdateTaskRequest.php
│ │ │ └── ContactRequest.php
│ │ ├── Resources/
│ │ │ └── V1/
│ │ │ ├── CompanyResource.php
│ │ │ ├── Concerns/
│ │ │ │ └── FormatsCustomFields.php
│ │ │ ├── CustomFieldResource.php
│ │ │ ├── NoteResource.php
│ │ │ ├── OpportunityResource.php
│ │ │ ├── PeopleResource.php
│ │ │ ├── TaskResource.php
│ │ │ └── UserResource.php
│ │ └── Responses/
│ │ └── LoginResponse.php
│ ├── Jobs/
│ │ ├── Email/
│ │ │ ├── CreateSubscriberJob.php
│ │ │ └── UpdateSubscriberJob.php
│ │ └── FetchFaviconForCompany.php
│ ├── Listeners/
│ │ ├── CreateTeamCustomFields.php
│ │ ├── Email/
│ │ │ └── NewSubscriberListener.php
│ │ └── SwitchTeam.php
│ ├── Livewire/
│ │ ├── App/
│ │ │ ├── AccessTokens/
│ │ │ │ ├── CreateAccessToken.php
│ │ │ │ └── ManageAccessTokens.php
│ │ │ ├── Profile/
│ │ │ │ ├── DeleteAccount.php
│ │ │ │ ├── LogoutOtherBrowserSessions.php
│ │ │ │ ├── UpdatePassword.php
│ │ │ │ └── UpdateProfileInformation.php
│ │ │ └── Teams/
│ │ │ ├── AddTeamMember.php
│ │ │ ├── DeleteTeam.php
│ │ │ ├── PendingTeamInvitations.php
│ │ │ ├── TeamMembers.php
│ │ │ └── UpdateTeamName.php
│ │ ├── BaseLivewireComponent.php
│ │ └── UpdateProfileInformationForm.php
│ ├── Mail/
│ │ └── NewContactSubmissionMail.php
│ ├── Mcp/
│ │ ├── Filters/
│ │ │ ├── CustomFieldFilter.php
│ │ │ └── CustomFieldSort.php
│ │ ├── Prompts/
│ │ │ └── CrmOverviewPrompt.php
│ │ ├── Resources/
│ │ │ ├── CompanySchemaResource.php
│ │ │ ├── Concerns/
│ │ │ │ └── ResolvesEntitySchema.php
│ │ │ ├── CrmSummaryResource.php
│ │ │ ├── NoteSchemaResource.php
│ │ │ ├── OpportunitySchemaResource.php
│ │ │ ├── PeopleSchemaResource.php
│ │ │ └── TaskSchemaResource.php
│ │ ├── Schema/
│ │ │ └── CustomFieldFilterSchema.php
│ │ ├── Servers/
│ │ │ └── RelaticleServer.php
│ │ └── Tools/
│ │ ├── BaseAttachTool.php
│ │ ├── BaseCreateTool.php
│ │ ├── BaseDeleteTool.php
│ │ ├── BaseDetachTool.php
│ │ ├── BaseListTool.php
│ │ ├── BaseShowTool.php
│ │ ├── BaseUpdateTool.php
│ │ ├── Company/
│ │ │ ├── CreateCompanyTool.php
│ │ │ ├── DeleteCompanyTool.php
│ │ │ ├── GetCompanyTool.php
│ │ │ ├── ListCompaniesTool.php
│ │ │ └── UpdateCompanyTool.php
│ │ ├── Concerns/
│ │ │ ├── BuildsRelationshipResponse.php
│ │ │ ├── ChecksTokenAbility.php
│ │ │ └── SerializesRelatedModels.php
│ │ ├── Note/
│ │ │ ├── AttachNoteToEntitiesTool.php
│ │ │ ├── CreateNoteTool.php
│ │ │ ├── DeleteNoteTool.php
│ │ │ ├── DetachNoteFromEntitiesTool.php
│ │ │ ├── GetNoteTool.php
│ │ │ ├── ListNotesTool.php
│ │ │ └── UpdateNoteTool.php
│ │ ├── Opportunity/
│ │ │ ├── CreateOpportunityTool.php
│ │ │ ├── DeleteOpportunityTool.php
│ │ │ ├── GetOpportunityTool.php
│ │ │ ├── ListOpportunitiesTool.php
│ │ │ └── UpdateOpportunityTool.php
│ │ ├── People/
│ │ │ ├── CreatePeopleTool.php
│ │ │ ├── DeletePeopleTool.php
│ │ │ ├── GetPeopleTool.php
│ │ │ ├── ListPeopleTool.php
│ │ │ └── UpdatePeopleTool.php
│ │ ├── Task/
│ │ │ ├── AttachTaskToEntitiesTool.php
│ │ │ ├── CreateTaskTool.php
│ │ │ ├── DeleteTaskTool.php
│ │ │ ├── DetachTaskFromEntitiesTool.php
│ │ │ ├── GetTaskTool.php
│ │ │ ├── ListTasksTool.php
│ │ │ └── UpdateTaskTool.php
│ │ └── WhoAmiTool.php
│ ├── Models/
│ │ ├── AiSummary.php
│ │ ├── Company.php
│ │ ├── Concerns/
│ │ │ ├── BelongsToTeamCreator.php
│ │ │ ├── HasAiSummary.php
│ │ │ ├── HasCreator.php
│ │ │ ├── HasNotes.php
│ │ │ ├── HasProfilePhoto.php
│ │ │ ├── HasTeam.php
│ │ │ └── InvalidatesRelatedAiSummaries.php
│ │ ├── CustomField.php
│ │ ├── CustomFieldOption.php
│ │ ├── CustomFieldSection.php
│ │ ├── CustomFieldValue.php
│ │ ├── Export.php
│ │ ├── Membership.php
│ │ ├── Note.php
│ │ ├── Opportunity.php
│ │ ├── People.php
│ │ ├── PersonalAccessToken.php
│ │ ├── Scopes/
│ │ │ └── TeamScope.php
│ │ ├── Task.php
│ │ ├── Team.php
│ │ ├── TeamInvitation.php
│ │ ├── User.php
│ │ └── UserSocialAccount.php
│ ├── Observers/
│ │ ├── CompanyObserver.php
│ │ ├── NoteObserver.php
│ │ ├── OpportunityObserver.php
│ │ ├── PeopleObserver.php
│ │ └── TaskObserver.php
│ ├── Policies/
│ │ ├── CompanyPolicy.php
│ │ ├── NotePolicy.php
│ │ ├── OpportunityPolicy.php
│ │ ├── PeoplePolicy.php
│ │ ├── TaskPolicy.php
│ │ └── TeamPolicy.php
│ ├── Providers/
│ │ ├── AppServiceProvider.php
│ │ ├── FaviconServiceProvider.php
│ │ ├── Filament/
│ │ │ └── AppPanelProvider.php
│ │ ├── FortifyServiceProvider.php
│ │ ├── HealthServiceProvider.php
│ │ ├── HorizonServiceProvider.php
│ │ ├── JetstreamServiceProvider.php
│ │ └── MacroServiceProvider.php
│ ├── Rules/
│ │ ├── ValidCustomFields.php
│ │ └── ValidTeamSlug.php
│ ├── Scribe/
│ │ └── Strategies/
│ │ └── GetFromSpatieQueryBuilder.php
│ ├── Services/
│ │ ├── AI/
│ │ │ ├── RecordContextBuilder.php
│ │ │ └── RecordSummaryService.php
│ │ ├── AvatarService.php
│ │ ├── Favicon/
│ │ │ └── Drivers/
│ │ │ ├── GoogleHighResDriver.php
│ │ │ └── HighQualityDriver.php
│ │ └── GitHubService.php
│ ├── Support/
│ │ └── CustomFieldMerger.php
│ └── View/
│ └── Components/
│ └── GuestLayout.php
├── artisan
├── bootstrap/
│ ├── app.php
│ ├── cache/
│ │ └── .gitignore
│ └── providers.php
├── compose.dev.yml
├── compose.yml
├── composer.json
├── config/
│ ├── app.php
│ ├── auth.php
│ ├── avatar.php
│ ├── blade-icons.php
│ ├── cache.php
│ ├── custom-fields.php
│ ├── data.php
│ ├── database.php
│ ├── eloquent-sortable.php
│ ├── favicon-fetcher.php
│ ├── filament.php
│ ├── filesystems.php
│ ├── fortify.php
│ ├── health.php
│ ├── horizon-watcher.php
│ ├── horizon.php
│ ├── jetstream.php
│ ├── logging.php
│ ├── login-link.php
│ ├── mail.php
│ ├── mailcoach-sdk.php
│ ├── markdown-response.php
│ ├── markdown.php
│ ├── media-library.php
│ ├── prism.php
│ ├── queue.php
│ ├── relaticle.php
│ ├── sanctum.php
│ ├── scribe.php
│ ├── sentry.php
│ ├── services.php
│ ├── session.php
│ └── sitemap.php
├── database/
│ ├── .gitignore
│ ├── factories/
│ │ ├── CompanyFactory.php
│ │ ├── CustomFieldFactory.php
│ │ ├── NoteFactory.php
│ │ ├── OpportunityFactory.php
│ │ ├── PeopleFactory.php
│ │ ├── SystemAdministratorFactory.php
│ │ ├── TaskFactory.php
│ │ ├── TeamFactory.php
│ │ ├── TeamInvitationFactory.php
│ │ ├── UserFactory.php
│ │ └── UserSocialAccountFactory.php
│ ├── migrations/
│ │ ├── 0001_01_01_000000_create_users_table.php
│ │ ├── 0001_01_01_000001_create_cache_table.php
│ │ ├── 0001_01_01_000002_create_jobs_table.php
│ │ ├── 2024_08_23_110718_create_teams_table.php
│ │ ├── 2024_08_23_110719_create_team_user_table.php
│ │ ├── 2024_08_23_110720_create_team_invitations_table.php
│ │ ├── 2024_08_24_133803_create_companies_table.php
│ │ ├── 2024_09_11_114549_create_tasks_table.php
│ │ ├── 2024_09_22_084119_create_notes_table.php
│ │ ├── 2024_09_22_091034_create_people_table.php
│ │ ├── 2024_09_22_092300_create_task_user_table.php
│ │ ├── 2024_09_22_110651_add_two_factor_columns_to_users_table.php
│ │ ├── 2024_09_22_110718_create_personal_access_tokens_table.php
│ │ ├── 2024_09_22_114735_create_opportunities_table.php
│ │ ├── 2024_09_26_160649_create_user_social_accounts_table.php
│ │ ├── 2024_09_26_170133_create_notifications_table.php
│ │ ├── 2025_02_07_192236_create_custom_fields_table.php
│ │ ├── 2025_03_15_180559_create_taskables_table.php
│ │ ├── 2025_03_15_192334_create_notables_table.php
│ │ ├── 2025_03_17_180206_create_media_table.php
│ │ ├── 2025_04_30_143551_add_creation_source_to_entity_tables.php
│ │ ├── 2025_05_08_112613_create_imports_table.php
│ │ ├── 2025_05_08_112614_create_exports_table.php
│ │ ├── 2025_05_08_112615_create_failed_import_rows_table.php
│ │ ├── 2025_07_05_093310_update_opportunity_amount_field_type_to_currency.php
│ │ ├── 2025_08_12_202409_add_settings_to_custom_field_options_table.php
│ │ ├── 2025_08_25_173222_update_order_column_to_flowforge_position_for_tasks_and_opportunities.php
│ │ ├── 2025_08_26_124042_create_system_administrators_table.php
│ │ ├── 2025_11_30_202612_create_ai_summaries_table.php
│ │ ├── 2025_12_10_191207_update_people_emails_field_type_to_email.php
│ │ ├── 2025_12_11_000001_update_company_domain_name_settings.php
│ │ ├── 2025_12_20_000000_migrate_to_ulid.php
│ │ ├── 2025_12_27_122241_convert_order_column_to_decimal_and_regenerate_positions.php
│ │ ├── 2026_01_02_152157_update_phone_number_custom_fields_type.php
│ │ ├── 2026_01_12_225824_upgrade_custom_fields_to_v3.php
│ │ ├── 2026_02_11_232804_add_slug_to_teams_table.php
│ │ ├── 2026_02_12_222910_expand_imports_table.php
│ │ ├── 2026_02_13_002721_cleanup_imports_table.php
│ │ ├── 2026_02_15_214730_drop_sessions_user_id_foreign_key.php
│ │ ├── 2026_02_20_212853_add_team_id_to_personal_access_tokens_table.php
│ │ ├── 2026_02_25_124942_add_team_id_indexes_to_entity_tables.php
│ │ ├── 2026_03_15_201741_add_custom_field_value_filtering_indexes.php
│ │ └── 2026_03_18_202956_add_expires_at_to_team_invitations_table.php
│ └── seeders/
│ ├── DatabaseSeeder.php
│ ├── LocalSeeder.php
│ └── SystemAdministratorSeeder.php
├── lang/
│ └── en/
│ ├── access-tokens.php
│ ├── profile.php
│ └── teams.php
├── package.json
├── packages/
│ ├── Documentation/
│ │ ├── README.md
│ │ ├── config/
│ │ │ └── documentation.php
│ │ ├── resources/
│ │ │ ├── css/
│ │ │ │ └── documentation.css
│ │ │ ├── js/
│ │ │ │ └── documentation.js
│ │ │ ├── markdown/
│ │ │ │ ├── developer-guide.md
│ │ │ │ ├── getting-started.md
│ │ │ │ ├── import-guide.md
│ │ │ │ ├── mcp-guide.md
│ │ │ │ └── self-hosting-guide.md
│ │ │ └── views/
│ │ │ ├── components/
│ │ │ │ ├── card.blade.php
│ │ │ │ ├── layout.blade.php
│ │ │ │ └── search-form.blade.php
│ │ │ ├── index.blade.php
│ │ │ ├── search.blade.php
│ │ │ └── show.blade.php
│ │ ├── routes/
│ │ │ └── web.php
│ │ └── src/
│ │ ├── Components/
│ │ │ └── Card.php
│ │ ├── Data/
│ │ │ ├── DocumentData.php
│ │ │ ├── DocumentSearchRequest.php
│ │ │ └── DocumentSearchResultData.php
│ │ ├── DocumentationServiceProvider.php
│ │ ├── Http/
│ │ │ └── Controllers/
│ │ │ └── DocumentationController.php
│ │ └── Services/
│ │ └── DocumentationService.php
│ ├── ImportWizard/
│ │ ├── config/
│ │ │ └── import-wizard.php
│ │ ├── resources/
│ │ │ ├── lang/
│ │ │ │ └── en/
│ │ │ │ └── validation.php
│ │ │ └── views/
│ │ │ ├── components/
│ │ │ │ ├── field-select.blade.php
│ │ │ │ ├── multi-value-input.blade.php
│ │ │ │ ├── select-menu.blade.php
│ │ │ │ └── value-row-actions.blade.php
│ │ │ ├── filament/
│ │ │ │ └── pages/
│ │ │ │ ├── import-history.blade.php
│ │ │ │ └── import-page.blade.php
│ │ │ └── livewire/
│ │ │ ├── import-wizard.blade.php
│ │ │ ├── partials/
│ │ │ │ └── step-indicator.blade.php
│ │ │ └── steps/
│ │ │ ├── mapping-step.blade.php
│ │ │ ├── partials/
│ │ │ │ ├── value-row-choice.blade.php
│ │ │ │ ├── value-row-date.blade.php
│ │ │ │ ├── value-row-multi-value.blade.php
│ │ │ │ ├── value-row-number.blade.php
│ │ │ │ ├── value-row-skipped.blade.php
│ │ │ │ └── value-row-text.blade.php
│ │ │ ├── preview-step.blade.php
│ │ │ ├── review-step.blade.php
│ │ │ └── upload-step.blade.php
│ │ ├── routes/
│ │ │ └── web.php
│ │ └── src/
│ │ ├── Commands/
│ │ │ └── CleanupImportsCommand.php
│ │ ├── Data/
│ │ │ ├── ColumnData.php
│ │ │ ├── EntityLink.php
│ │ │ ├── ImportField.php
│ │ │ ├── ImportFieldCollection.php
│ │ │ ├── InferenceResult.php
│ │ │ ├── MatchableField.php
│ │ │ └── RelationshipMatch.php
│ │ ├── Enums/
│ │ │ ├── DateFormat.php
│ │ │ ├── EntityLinkSource.php
│ │ │ ├── EntityLinkStorage.php
│ │ │ ├── ImportEntityType.php
│ │ │ ├── ImportStatus.php
│ │ │ ├── MatchBehavior.php
│ │ │ ├── NumberFormat.php
│ │ │ ├── ReviewFilter.php
│ │ │ ├── RowMatchAction.php
│ │ │ ├── SortDirection.php
│ │ │ └── SortField.php
│ │ ├── Filament/
│ │ │ └── Pages/
│ │ │ ├── ImportCompanies.php
│ │ │ ├── ImportHistory.php
│ │ │ ├── ImportNotes.php
│ │ │ ├── ImportOpportunities.php
│ │ │ ├── ImportPage.php
│ │ │ ├── ImportPeople.php
│ │ │ └── ImportTasks.php
│ │ ├── Http/
│ │ │ └── Controllers/
│ │ │ └── DownloadFailedRowsController.php
│ │ ├── ImportWizardNewServiceProvider.php
│ │ ├── Importers/
│ │ │ ├── BaseImporter.php
│ │ │ ├── CompanyImporter.php
│ │ │ ├── Contracts/
│ │ │ │ └── ImporterContract.php
│ │ │ ├── NoteImporter.php
│ │ │ ├── OpportunityImporter.php
│ │ │ ├── PeopleImporter.php
│ │ │ └── TaskImporter.php
│ │ ├── Jobs/
│ │ │ ├── ExecuteImportJob.php
│ │ │ ├── ResolveMatchesJob.php
│ │ │ └── ValidateColumnJob.php
│ │ ├── Livewire/
│ │ │ ├── Concerns/
│ │ │ │ └── WithImportStore.php
│ │ │ ├── ImportWizard.php
│ │ │ └── Steps/
│ │ │ ├── MappingStep.php
│ │ │ ├── PreviewStep.php
│ │ │ ├── ReviewStep.php
│ │ │ └── UploadStep.php
│ │ ├── Models/
│ │ │ ├── FailedImportRow.php
│ │ │ └── Import.php
│ │ ├── Rules/
│ │ │ ├── ImportChoiceRule.php
│ │ │ ├── ImportDateRule.php
│ │ │ └── ImportNumberRule.php
│ │ ├── Store/
│ │ │ ├── ImportRow.php
│ │ │ └── ImportStore.php
│ │ └── Support/
│ │ ├── DataTypeInferencer.php
│ │ ├── EntityLinkResolver.php
│ │ ├── EntityLinkStorage/
│ │ │ ├── CustomFieldValueStorage.php
│ │ │ ├── EntityLinkStorageInterface.php
│ │ │ ├── ForeignKeyStorage.php
│ │ │ └── MorphToManyStorage.php
│ │ ├── EntityLinkValidator.php
│ │ ├── MatchResolver.php
│ │ └── Validation/
│ │ ├── ColumnValidator.php
│ │ └── ValidationError.php
│ ├── OnboardSeed/
│ │ ├── README.md
│ │ ├── resources/
│ │ │ ├── fixtures/
│ │ │ │ ├── companies/
│ │ │ │ │ ├── airbnb.yaml
│ │ │ │ │ ├── apple.yaml
│ │ │ │ │ ├── figma.yaml
│ │ │ │ │ └── notion.yaml
│ │ │ │ ├── notes/
│ │ │ │ │ ├── airbnb_note.yaml
│ │ │ │ │ ├── apple_note.yaml
│ │ │ │ │ ├── dylan_note.yaml
│ │ │ │ │ ├── figma_note.yaml
│ │ │ │ │ └── notion_note.yaml
│ │ │ │ ├── opportunities/
│ │ │ │ │ ├── airbnb_analytics.yaml
│ │ │ │ │ ├── apple_partnership.yaml
│ │ │ │ │ ├── figma_enterprise.yaml
│ │ │ │ │ └── notion_integration.yaml
│ │ │ │ ├── people/
│ │ │ │ │ ├── brian.yaml
│ │ │ │ │ ├── dylan.yaml
│ │ │ │ │ ├── ivan.yaml
│ │ │ │ │ └── tim.yaml
│ │ │ │ └── tasks/
│ │ │ │ ├── brian_call.yaml
│ │ │ │ ├── dylan_followup.yaml
│ │ │ │ ├── ivan_meeting.yaml
│ │ │ │ └── tim_proposal.yaml
│ │ │ └── templates/
│ │ │ └── entity_template.yaml
│ │ └── src/
│ │ ├── Contracts/
│ │ │ └── ModelSeederInterface.php
│ │ ├── ModelSeeders/
│ │ │ ├── CompanySeeder.php
│ │ │ ├── NoteSeeder.php
│ │ │ ├── OpportunitySeeder.php
│ │ │ ├── PeopleSeeder.php
│ │ │ └── TaskSeeder.php
│ │ ├── OnboardSeedManager.php
│ │ ├── OnboardSeeder.php
│ │ └── Support/
│ │ ├── BaseModelSeeder.php
│ │ ├── BulkCustomFieldValueWriter.php
│ │ ├── FixtureLoader.php
│ │ └── FixtureRegistry.php
│ └── SystemAdmin/
│ └── src/
│ ├── Enums/
│ │ └── SystemAdministratorRole.php
│ ├── Filament/
│ │ ├── Exports/
│ │ │ └── CompanyExporter.php
│ │ ├── Pages/
│ │ │ ├── Dashboard.php
│ │ │ └── EngagementDashboard.php
│ │ ├── Resources/
│ │ │ ├── CompanyResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── CreateCompany.php
│ │ │ │ ├── EditCompany.php
│ │ │ │ ├── ListCompanies.php
│ │ │ │ └── ViewCompany.php
│ │ │ ├── CompanyResource.php
│ │ │ ├── ImportResource/
│ │ │ │ ├── Pages/
│ │ │ │ │ ├── ListImports.php
│ │ │ │ │ └── ViewImport.php
│ │ │ │ └── RelationManagers/
│ │ │ │ └── FailedRowsRelationManager.php
│ │ │ ├── ImportResource.php
│ │ │ ├── NoteResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── CreateNote.php
│ │ │ │ ├── EditNote.php
│ │ │ │ ├── ListNotes.php
│ │ │ │ └── ViewNote.php
│ │ │ ├── NoteResource.php
│ │ │ ├── OpportunityResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── CreateOpportunity.php
│ │ │ │ ├── EditOpportunity.php
│ │ │ │ ├── ListOpportunities.php
│ │ │ │ └── ViewOpportunity.php
│ │ │ ├── OpportunityResource.php
│ │ │ ├── PeopleResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── CreatePeople.php
│ │ │ │ ├── EditPeople.php
│ │ │ │ ├── ListPeople.php
│ │ │ │ └── ViewPeople.php
│ │ │ ├── PeopleResource.php
│ │ │ ├── SystemAdministrators/
│ │ │ │ ├── Pages/
│ │ │ │ │ ├── CreateSystemAdministrator.php
│ │ │ │ │ ├── EditSystemAdministrator.php
│ │ │ │ │ ├── ListSystemAdministrators.php
│ │ │ │ │ └── ViewSystemAdministrator.php
│ │ │ │ ├── Schemas/
│ │ │ │ │ ├── SystemAdministratorForm.php
│ │ │ │ │ └── SystemAdministratorInfolist.php
│ │ │ │ ├── SystemAdministratorResource.php
│ │ │ │ └── Tables/
│ │ │ │ └── SystemAdministratorsTable.php
│ │ │ ├── TaskResource/
│ │ │ │ └── Pages/
│ │ │ │ ├── CreateTask.php
│ │ │ │ ├── EditTask.php
│ │ │ │ ├── ListTasks.php
│ │ │ │ └── ViewTask.php
│ │ │ ├── TaskResource.php
│ │ │ ├── TeamResource/
│ │ │ │ ├── Pages/
│ │ │ │ │ ├── CreateTeam.php
│ │ │ │ │ ├── EditTeam.php
│ │ │ │ │ ├── ListTeams.php
│ │ │ │ │ └── ViewTeam.php
│ │ │ │ └── RelationManagers/
│ │ │ │ ├── CompaniesRelationManager.php
│ │ │ │ ├── MembersRelationManager.php
│ │ │ │ ├── NotesRelationManager.php
│ │ │ │ ├── OpportunitiesRelationManager.php
│ │ │ │ ├── PeopleRelationManager.php
│ │ │ │ └── TasksRelationManager.php
│ │ │ ├── TeamResource.php
│ │ │ ├── UserResource/
│ │ │ │ ├── Pages/
│ │ │ │ │ ├── CreateUser.php
│ │ │ │ │ ├── EditUser.php
│ │ │ │ │ ├── ListUsers.php
│ │ │ │ │ └── ViewUser.php
│ │ │ │ └── RelationManagers/
│ │ │ │ ├── OwnedTeamsRelationManager.php
│ │ │ │ └── TeamsRelationManager.php
│ │ │ └── UserResource.php
│ │ └── Widgets/
│ │ ├── ActivationRateWidget.php
│ │ ├── Concerns/
│ │ │ └── HasPeriodComparison.php
│ │ ├── PlatformGrowthStatsWidget.php
│ │ ├── RecordDistributionChartWidget.php
│ │ ├── SignupTrendChartWidget.php
│ │ ├── TopTeamsTableWidget.php
│ │ └── UserRetentionChartWidget.php
│ ├── Models/
│ │ └── SystemAdministrator.php
│ ├── Policies/
│ │ ├── CompanyPolicy.php
│ │ ├── FailedImportRowPolicy.php
│ │ ├── ImportPolicy.php
│ │ ├── NotePolicy.php
│ │ ├── OpportunityPolicy.php
│ │ ├── PeoplePolicy.php
│ │ ├── SystemAdministratorPolicy.php
│ │ ├── TaskPolicy.php
│ │ ├── TeamPolicy.php
│ │ └── UserPolicy.php
│ └── SystemAdminPanelProvider.php
├── phpstan.neon
├── phpunit.ci.xml
├── phpunit.xml
├── pint.json
├── public/
│ ├── .htaccess
│ ├── css/
│ │ ├── asmit/
│ │ │ └── resized-column/
│ │ │ └── resized-column.css
│ │ ├── filament/
│ │ │ ├── filament/
│ │ │ │ └── app.css
│ │ │ ├── forms/
│ │ │ │ └── forms.css
│ │ │ └── support/
│ │ │ └── support.css
│ │ └── relaticle/
│ │ ├── custom-fields/
│ │ │ └── custom-fields.css
│ │ └── flowforge/
│ │ └── flowforge.css
│ ├── fonts/
│ │ └── filament/
│ │ └── filament/
│ │ └── inter/
│ │ └── index.css
│ ├── index.php
│ ├── js/
│ │ ├── asmit/
│ │ │ └── resized-column/
│ │ │ └── resized-column.js
│ │ ├── filament/
│ │ │ ├── actions/
│ │ │ │ └── actions.js
│ │ │ ├── filament/
│ │ │ │ ├── app.js
│ │ │ │ └── echo.js
│ │ │ ├── forms/
│ │ │ │ └── components/
│ │ │ │ ├── checkbox-list.js
│ │ │ │ ├── code-editor.js
│ │ │ │ ├── color-picker.js
│ │ │ │ ├── date-time-picker.js
│ │ │ │ ├── file-upload.js
│ │ │ │ ├── key-value.js
│ │ │ │ ├── markdown-editor.js
│ │ │ │ ├── rich-editor.js
│ │ │ │ ├── select.js
│ │ │ │ ├── slider.js
│ │ │ │ ├── tags-input.js
│ │ │ │ └── textarea.js
│ │ │ ├── notifications/
│ │ │ │ └── notifications.js
│ │ │ ├── schemas/
│ │ │ │ ├── components/
│ │ │ │ │ ├── actions.js
│ │ │ │ │ ├── tabs.js
│ │ │ │ │ └── wizard.js
│ │ │ │ └── schemas.js
│ │ │ ├── support/
│ │ │ │ ├── async-alpine.js
│ │ │ │ └── support.js
│ │ │ ├── tables/
│ │ │ │ ├── components/
│ │ │ │ │ ├── columns/
│ │ │ │ │ │ ├── checkbox.js
│ │ │ │ │ │ ├── select.js
│ │ │ │ │ │ ├── text-input.js
│ │ │ │ │ │ └── toggle.js
│ │ │ │ │ └── table.js
│ │ │ │ └── tables.js
│ │ │ └── widgets/
│ │ │ └── components/
│ │ │ ├── chart.js
│ │ │ └── stats-overview/
│ │ │ └── stat/
│ │ │ └── chart.js
│ │ └── relaticle/
│ │ └── flowforge/
│ │ ├── components/
│ │ │ └── flowforge.js
│ │ └── flowforge.js
│ ├── manifest.webmanifest
│ ├── robots.txt
│ └── site.webmanifest
├── rector.php
├── resources/
│ ├── css/
│ │ ├── app.css
│ │ ├── filament/
│ │ │ ├── admin/
│ │ │ │ └── theme.css
│ │ │ └── app/
│ │ │ └── theme.css
│ │ ├── fonts.css
│ │ └── theme.css
│ ├── js/
│ │ ├── app.js
│ │ └── motion.js
│ ├── markdown/
│ │ ├── brand-assets.md
│ │ ├── font-sources.md
│ │ ├── policy.md
│ │ └── terms.md
│ └── views/
│ ├── api/
│ │ └── api-token-manager.blade.php
│ ├── components/
│ │ ├── action-message.blade.php
│ │ ├── action-section.blade.php
│ │ ├── application-logo.blade.php
│ │ ├── application-mark.blade.php
│ │ ├── authentication-card-logo.blade.php
│ │ ├── authentication-card.blade.php
│ │ ├── banner.blade.php
│ │ ├── brand/
│ │ │ ├── logo-lockup.blade.php
│ │ │ ├── logomark.blade.php
│ │ │ └── wordmark.blade.php
│ │ ├── browser-sessions.blade.php
│ │ ├── button.blade.php
│ │ ├── checkbox.blade.php
│ │ ├── confirmation-modal.blade.php
│ │ ├── confirms-password.blade.php
│ │ ├── danger-button.blade.php
│ │ ├── dialog-modal.blade.php
│ │ ├── dropdown-link.blade.php
│ │ ├── dropdown.blade.php
│ │ ├── form-section.blade.php
│ │ ├── input-error.blade.php
│ │ ├── input.blade.php
│ │ ├── label.blade.php
│ │ ├── layout/
│ │ │ ├── footer.blade.php
│ │ │ ├── header.blade.php
│ │ │ └── mobile-menu.blade.php
│ │ ├── legal-document.blade.php
│ │ ├── marketing/
│ │ │ ├── button.blade.php
│ │ │ ├── input.blade.php
│ │ │ └── textarea.blade.php
│ │ ├── modal.blade.php
│ │ ├── nav-link.blade.php
│ │ ├── responsive-nav-link.blade.php
│ │ ├── secondary-button.blade.php
│ │ ├── section-border.blade.php
│ │ ├── section-title.blade.php
│ │ ├── switchable-team.blade.php
│ │ ├── theme-switcher.blade.php
│ │ ├── validation-errors.blade.php
│ │ └── welcome.blade.php
│ ├── contact.blade.php
│ ├── emails/
│ │ └── team-invitation.blade.php
│ ├── filament/
│ │ ├── actions/
│ │ │ └── ai-summary.blade.php
│ │ ├── app/
│ │ │ ├── analytics.blade.php
│ │ │ ├── import-preview-alpine.blade.php
│ │ │ ├── import-value-reviewer-alpine.blade.php
│ │ │ ├── logo-empty.blade.php
│ │ │ └── logo.blade.php
│ │ ├── auth/
│ │ │ └── social_login_buttons.blade.php
│ │ ├── components/
│ │ │ └── infolists/
│ │ │ └── avatar-name.blade.php
│ │ ├── pages/
│ │ │ ├── access-tokens.blade.php
│ │ │ ├── create-team.blade.php
│ │ │ ├── dashboard.blade.php
│ │ │ ├── edit-profile.blade.php
│ │ │ └── edit-team.blade.php
│ │ └── tables/
│ │ └── columns/
│ │ ├── avatar-name-column.blade.php
│ │ └── logo-name-column.blade.php
│ ├── home/
│ │ ├── index.blade.php
│ │ └── partials/
│ │ ├── community.blade.php
│ │ ├── faq.blade.php
│ │ ├── features.blade.php
│ │ ├── hero-agent-preview.blade.php
│ │ ├── hero.blade.php
│ │ └── start-building.blade.php
│ ├── layouts/
│ │ └── guest.blade.php
│ ├── livewire/
│ │ └── app/
│ │ ├── access-tokens/
│ │ │ ├── create-access-token.blade.php
│ │ │ └── manage-access-tokens.blade.php
│ │ ├── profile/
│ │ │ ├── delete-account.blade.php
│ │ │ ├── logout-other-browser-sessions.blade.php
│ │ │ ├── update-password.blade.php
│ │ │ └── update-profile-information.blade.php
│ │ └── teams/
│ │ ├── add-team-member.blade.php
│ │ ├── delete-team.blade.php
│ │ ├── pending-team-invitations.blade.php
│ │ ├── team-members.blade.php
│ │ └── update-team-name.blade.php
│ ├── mail/
│ │ └── new-contact-submission.blade.php
│ ├── policy.blade.php
│ ├── pricing.blade.php
│ ├── profile/
│ │ ├── delete-user-form.blade.php
│ │ ├── logout-other-browser-sessions-form.blade.php
│ │ ├── two-factor-authentication-form.blade.php
│ │ ├── update-password-form.blade.php
│ │ └── update-profile-information-form.blade.php
│ ├── teams/
│ │ ├── create-team-form.blade.php
│ │ ├── delete-team-form.blade.php
│ │ ├── invitation-expired.blade.php
│ │ ├── team-member-manager.blade.php
│ │ └── update-team-name-form.blade.php
│ ├── terms.blade.php
│ └── vendor/
│ ├── filament-panels/
│ │ └── components/
│ │ └── layout/
│ │ └── index.blade.php
│ ├── mail/
│ │ ├── html/
│ │ │ ├── button.blade.php
│ │ │ ├── footer.blade.php
│ │ │ ├── header.blade.php
│ │ │ ├── layout.blade.php
│ │ │ ├── message.blade.php
│ │ │ ├── panel.blade.php
│ │ │ ├── subcopy.blade.php
│ │ │ ├── table.blade.php
│ │ │ └── themes/
│ │ │ └── default.css
│ │ └── text/
│ │ ├── button.blade.php
│ │ ├── footer.blade.php
│ │ ├── header.blade.php
│ │ ├── layout.blade.php
│ │ ├── message.blade.php
│ │ ├── panel.blade.php
│ │ ├── subcopy.blade.php
│ │ └── table.blade.php
│ └── scribe/
│ ├── components/
│ │ ├── badges/
│ │ │ ├── auth.blade.php
│ │ │ ├── base.blade.php
│ │ │ ├── deprecated.blade.php
│ │ │ └── http-method.blade.php
│ │ ├── field-details.blade.php
│ │ └── nested-fields.blade.php
│ ├── external/
│ │ ├── elements.blade.php
│ │ ├── rapidoc.blade.php
│ │ └── scalar.blade.php
│ ├── markdown/
│ │ ├── auth.blade.php
│ │ └── intro.blade.php
│ ├── partials/
│ │ └── example-requests/
│ │ ├── bash.md.blade.php
│ │ ├── javascript.md.blade.php
│ │ ├── php.md.blade.php
│ │ └── python.md.blade.php
│ └── themes/
│ ├── default/
│ │ ├── endpoint.blade.php
│ │ ├── groups.blade.php
│ │ ├── index.blade.php
│ │ └── sidebar.blade.php
│ └── elements/
│ ├── components/
│ │ ├── field-details.blade.php
│ │ └── nested-fields.blade.php
│ ├── endpoint.blade.php
│ ├── groups.blade.php
│ ├── index.blade.php
│ ├── sidebar.blade.php
│ └── try_it_out.blade.php
├── routes/
│ ├── ai.php
│ ├── api.php
│ └── web.php
├── storage/
│ ├── app/
│ │ └── .gitignore
│ ├── clockwork/
│ │ └── .gitignore
│ ├── framework/
│ │ ├── .gitignore
│ │ ├── cache/
│ │ │ └── .gitignore
│ │ ├── sessions/
│ │ │ └── .gitignore
│ │ ├── testing/
│ │ │ └── .gitignore
│ │ └── views/
│ │ └── .gitignore
│ ├── logs/
│ │ └── .gitignore
│ └── pail/
│ └── .gitignore
├── stubs/
│ └── Mailcoach.stub
├── tests/
│ ├── Arch/
│ │ └── ArchTest.php
│ ├── Browser/
│ │ ├── Auth/
│ │ │ ├── LoginBrowserTest.php
│ │ │ └── PasswordResetBrowserTest.php
│ │ ├── CRM/
│ │ │ └── CompanyBrowserTest.php
│ │ ├── ImportWizard/
│ │ │ └── ImportWizardBrowserTest.php
│ │ ├── Onboarding/
│ │ │ └── OnboardingBrowserTest.php
│ │ ├── SmokeBrowserTest.php
│ │ └── Teams/
│ │ └── TeamBrowserTest.php
│ ├── Feature/
│ │ ├── AI/
│ │ │ └── RecordSummaryServiceTest.php
│ │ ├── AccessTokens/
│ │ │ ├── AccessTokenPermissionsTest.php
│ │ │ ├── CreateAccessTokenTest.php
│ │ │ └── DeleteAccessTokenTest.php
│ │ ├── Api/
│ │ │ └── V1/
│ │ │ ├── ApiMiddlewareTest.php
│ │ │ ├── ApiTeamScopingTest.php
│ │ │ ├── CompaniesApiTest.php
│ │ │ ├── CustomFieldsApiTest.php
│ │ │ ├── NotesApiTest.php
│ │ │ ├── OpportunitiesApiTest.php
│ │ │ ├── PeopleApiTest.php
│ │ │ ├── TasksApiTest.php
│ │ │ ├── TokenAbilitiesApiTest.php
│ │ │ └── UserEndpointTest.php
│ │ ├── Auth/
│ │ │ ├── AuthenticationTest.php
│ │ │ ├── PasswordResetTest.php
│ │ │ ├── RegistrationTest.php
│ │ │ ├── SocialiteLoginTest.php
│ │ │ ├── TwoFactorAuthenticationSettingsTest.php
│ │ │ └── UserModelTest.php
│ │ ├── CRM/
│ │ │ └── CompanyModelTest.php
│ │ ├── Commands/
│ │ │ └── InstallCommandTest.php
│ │ ├── ContactFormTest.php
│ │ ├── Filament/
│ │ │ └── App/
│ │ │ ├── Exports/
│ │ │ │ ├── CompanyExporterTest.php
│ │ │ │ ├── NoteExporterTest.php
│ │ │ │ ├── OpportunityExporterTest.php
│ │ │ │ ├── PeopleExporterTest.php
│ │ │ │ └── TaskExporterTest.php
│ │ │ ├── Pages/
│ │ │ │ ├── OpportunitiesBoardTest.php
│ │ │ │ └── TasksBoardTest.php
│ │ │ └── Resources/
│ │ │ ├── CompanyResourceTest.php
│ │ │ ├── NoteResourceTest.php
│ │ │ ├── OpportunityResourceTest.php
│ │ │ ├── PeopleResourceTest.php
│ │ │ └── TaskResourceTest.php
│ │ ├── HealthChecks/
│ │ │ └── HealthServiceProviderTest.php
│ │ ├── ImportWizard/
│ │ │ ├── Commands/
│ │ │ │ └── CleanupImportsCommandTest.php
│ │ │ ├── Components/
│ │ │ │ ├── MultiValueInputTest.php
│ │ │ │ └── SelectMenuInvalidOptionsTest.php
│ │ │ ├── Jobs/
│ │ │ │ ├── ExecuteImportJobTest.php
│ │ │ │ ├── ResolveMatchesJobTest.php
│ │ │ │ └── ValidateColumnJobTest.php
│ │ │ ├── Livewire/
│ │ │ │ ├── ImportWizardTest.php
│ │ │ │ ├── MappingStepTest.php
│ │ │ │ ├── PreviewStepTest.php
│ │ │ │ ├── ReviewStepTest.php
│ │ │ │ └── UploadStepTest.php
│ │ │ ├── Support/
│ │ │ │ └── EntityLinkResolverTest.php
│ │ │ └── Validation/
│ │ │ ├── ColumnValidatorTest.php
│ │ │ └── EntityLinkValidatorTest.php
│ │ ├── Mcp/
│ │ │ ├── CompanyToolsTest.php
│ │ │ ├── CrmSummaryResourceTest.php
│ │ │ ├── Filters/
│ │ │ │ ├── CustomFieldFilterTest.php
│ │ │ │ └── CustomFieldSortTest.php
│ │ │ ├── McpToolFeaturesTest.php
│ │ │ ├── NoteToolsTest.php
│ │ │ ├── OpportunityToolsTest.php
│ │ │ ├── PeopleToolsTest.php
│ │ │ ├── RelaticleServerTest.php
│ │ │ ├── SchemaResourcesTest.php
│ │ │ ├── TaskToolsTest.php
│ │ │ ├── TokenAbilitiesMcpTest.php
│ │ │ └── WhoAmiToolTest.php
│ │ ├── Migrations/
│ │ │ └── UlidMigrationTest.php
│ │ ├── Models/
│ │ │ └── Scopes/
│ │ │ └── TeamScopeTest.php
│ │ ├── Onboarding/
│ │ │ └── CreateTeamOnboardingTest.php
│ │ ├── PersonalAccessToken/
│ │ │ └── TeamIdImmutabilityTest.php
│ │ ├── Profile/
│ │ │ ├── AvatarServiceTest.php
│ │ │ ├── BrowserSessionsTest.php
│ │ │ ├── DeleteAccountTest.php
│ │ │ ├── GitHubServiceTest.php
│ │ │ ├── UpdatePasswordTest.php
│ │ │ └── UpdateUserProfileInformationTest.php
│ │ ├── Public/
│ │ │ └── PublicPagesTest.php
│ │ ├── Routing/
│ │ │ ├── AppPanelRoutingTest.php
│ │ │ └── SubdomainRoutingTest.php
│ │ ├── SystemAdmin/
│ │ │ ├── ActivationRateWidgetTest.php
│ │ │ ├── SystemAdminResourceTest.php
│ │ │ ├── SystemAdminSecurityTest.php
│ │ │ └── UserRetentionChartWidgetTest.php
│ │ ├── Teams/
│ │ │ ├── AcceptTeamInvitationTest.php
│ │ │ ├── CreateTeamTest.php
│ │ │ ├── DeleteTeamTest.php
│ │ │ ├── InvitationUxTest.php
│ │ │ ├── InviteTeamMemberTest.php
│ │ │ ├── LeaveTeamTest.php
│ │ │ ├── ManageTeamInvitationsTest.php
│ │ │ ├── RemoveTeamMemberTest.php
│ │ │ ├── TeamModelTest.php
│ │ │ ├── UpdateTeamMemberRoleTest.php
│ │ │ └── UpdateTeamNameTest.php
│ │ └── ValidTeamSlugTest.php
│ ├── Pest.php
│ ├── Smoke/
│ │ └── RouteTest.php
│ ├── TestCase.php
│ └── fixtures/
│ └── imports/
│ ├── companies.csv
│ ├── companies.xlsx
│ └── people.xlsx
└── vite.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
# Git
.git
.gitignore
.gitattributes
.githooks
# IDE
.idea
.vscode
*.swp
*.swo
# Dependencies (will be installed during build)
/vendor
/node_modules
# Build artifacts
/public/build
/public/hot
/public/storage
# Local environment files
.env
.env.local
.env.*.local
.env.backup
# Testing
.env.testing
.env.ci
/coverage
/.phpunit.cache
/phpunit.xml
/phpunit.ci.xml
/tests
# Development tools
.editorconfig
.styleci.yml
compose.dev.yml
Makefile
# Documentation
*.md
!README.md
CLAUDE.md
# Cache and logs
/storage/app/*
!/storage/app/.gitignore
!/storage/app/public
/storage/framework/cache/*
!/storage/framework/cache/.gitignore
/storage/framework/sessions/*
!/storage/framework/sessions/.gitignore
/storage/framework/views/*
!/storage/framework/views/.gitignore
/storage/logs/*
!/storage/logs/.gitignore
/storage/clockwork
/storage/pail
# Laravel specific
/bootstrap/cache/*.php
# Other
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.DS_Store
Thumbs.db
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[compose.{yml,dev.yml}]
indent_size = 4
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore
================================================
FILE: .githooks/pre-commit
================================================
#!/bin/sh
composer lint
composer test
================================================
FILE: .github/ISSUE_TEMPLATE/1-bug_report.yml
================================================
name: Bug report
description: Report a problem you're experiencing with Relaticle
labels: ["bug", "unconfirmed"]
projects: ["Relaticle/1"]
body:
- type: markdown
attributes:
value: |
Before opening a bug report, please search the existing issues (both open and closed).
---
Thank you for taking the time to file a bug report. To address this bug as fast as possible, we need some information.
- type: input
id: relaticle-version
attributes:
label: Relaticle Version
description: What version of Relaticle are you running?
placeholder: v2.0.8
validations:
required: true
- type: input
id: php-version
attributes:
label: PHP Version
description: What PHP version are you using?
placeholder: 8.4.16
validations:
required: true
- type: dropdown
id: database
attributes:
label: Database
description: Which database are you using?
options:
- PostgreSQL 17+
- Other
validations:
required: true
- type: dropdown
id: deployment
attributes:
label: Deployment Method
description: How are you running Relaticle?
options:
- Laravel Herd (local)
- Docker (compose.yml)
- Manual installation
- Other
- type: textarea
id: description
attributes:
label: Problem description
description: What happened when you experienced the problem?
validations:
required: true
- type: textarea
id: expectation
attributes:
label: Expected behavior
description: What did you expect to happen instead?
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: |
Which steps do we need to take to reproduce the problem?
Any code examples need to be **as short as possible**, remove any code that is unrelated to the bug.
placeholder: |
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant log output
description: If applicable, provide relevant log output from `storage/logs/laravel.log` or browser console. No need for backticks here.
render: shell
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our Code of Conduct
options:
- label: I agree to follow this project's Code of Conduct
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Feature request or idea
url: https://github.com/Relaticle/relaticle/discussions/new?category=ideas
about: Share ideas for new features or improvements
- name: Support question
url: https://github.com/Relaticle/relaticle/discussions/new?category=q-a
about: Ask the community for help
- name: Discord Community
url: https://discord.gg/jSfdU9zxTt
about: Join our Discord server for quick help and community chat
================================================
FILE: .github/copilot-instructions.md
================================================
# Relaticle Code Review Guidelines
## Repository Context
Multi-tenant SaaS CRM with paying customers. Tenant isolation is the highest-priority concern — a single cross-tenant data leak is a critical security incident. The app uses Filament panels with a per-request `TeamScope` global scope applied via middleware, not in model boot. `Model::unguard()` is enabled globally.
Stack: PHP 8.4, Laravel 12, Filament 5, Livewire 4, Pest 4, Tailwind CSS 4.
CI enforces: PHPStan level 7, Pint formatting, Rector, 99.9% type coverage, full test suite. CI does **not** enforce: code coverage percentage, mutation testing, or required reviewer count.
## Tenant Isolation — Flag These
This app scopes data via `ApplyTenantScopes` middleware which registers `TeamScope` on: Company, People, Opportunity, Task, Note. Scoping happens per-request inside the Filament panel. Code running outside that middleware context (jobs, commands, API routes) has no automatic tenant filter.
Flag any of these patterns:
- `DB::table()` or `DB::select()` on a team-scoped table without a `WHERE team_id` clause
- `withoutGlobalScopes()` that removes all scopes instead of only `SoftDeletingScope`
- New Eloquent model on a team-scoped table missing the `HasTeam` trait
- New model with `HasTeam` not added to `ApplyTenantScopes` middleware
- New routes, Livewire components, or jobs that query team-scoped models without ensuring tenant context
- Queries using `->toBase()` which strips all Eloquent scopes
```php
// Correct: only strips soft delete scope, TeamScope remains active
return parent::getEloquentQuery()
->withoutGlobalScopes([SoftDeletingScope::class]);
// Dangerous: strips ALL scopes including TeamScope
return parent::getEloquentQuery()
->withoutGlobalScopes();
```
## Authorization — Flag These
Policies exist for Company, People, Opportunity, Task, Note. They check `$user->belongsToTeam($record->team)`.
- New controller action or Livewire method without `$this->authorize()` or policy check
- New Filament resource without a corresponding policy
- Livewire actions that modify records without verifying the record belongs to the current team
- Mass assignment from user-supplied request data — `Model::unguard()` is global, so `$fillable` is the only guard
```php
// Correct: authorize before acting
public function delete(string $id): void
{
$record = Company::findOrFail($id);
$this->authorize('delete', $record);
$record->delete();
}
// Dangerous: no authorization, any authenticated user can delete any record
public function delete(string $id): void
{
Company::findOrFail($id)->delete();
}
```
## Data Safety — Flag These
- Raw SQL with interpolated variables instead of parameter bindings (`?`)
- `DB::table()->upsert()` or `DB::table()->insert()` on team-scoped tables without a `team_id` in the data payload
- Export logic that doesn't filter data rows by `team_id`
- New public routes without auth middleware
- File uploads without MIME type and size validation
- `env()` calls outside of `config/` files
```php
// Correct: parameterized binding
DB::select('SELECT * FROM companies WHERE team_id = ?', [$teamId]);
// Dangerous: interpolated variable in SQL
DB::select("SELECT * FROM companies WHERE team_id = {$teamId}");
```
## Test Coverage — Flag These
New features or modified behavior should include corresponding Pest tests. There is no coverage gate in CI, so this must be caught in review.
- New Filament resource, Livewire component, or controller action without tests
- Modified business logic without updated tests
- Tests that only check the happy path — also cover validation failures and authorization denials
- Tests that create records without scoping to a specific team (relying on implicit scope rather than explicit `->for($team)`)
## PHP Standards
- Every file: `declare(strict_types=1);`
- Typed properties, explicit return types (including `void`), parameter type hints
- Constructor property promotion: `public function __construct(private UserService $service) {}`
- No empty zero-parameter constructors
- Short nullable: `?string` not `string|null`
- Always use curly braces, even single-line bodies
- PHPDoc over inline comments; only comment genuinely complex logic
- Enum keys: TitleCase (`FavoritePerson`, `Monthly`)
## Code Style
- Happy path last — handle errors first, return early
- Avoid `else` — use early returns
- String interpolation over concatenation
- Descriptive names: `$failedChecks` not `$checks` with a comment
## Laravel Conventions
- `Model::query()` not `DB::` for team-scoped data
- Eager load relationships to prevent N+1
- Form Request classes for validation, not inline
- `config()` not `env()` outside config files
- Named routes with `route()`
- Policies and gates for authorization
- Queued jobs with `ShouldQueue` for expensive operations
- `casts()` method, not `$casts` property
- Middleware in `bootstrap/app.php`, not a Kernel class
- **PostgreSQL exclusively** — no SQLite/MySQL compatibility layers, driver checks, or conditional SQL
- Migrations: only `up()` methods — no `down()` methods
## Filament 5
- Form fields: `Filament\Forms\Components\`
- Layout (Grid, Section, Tabs): `Filament\Schemas\Components\`
- Infolist entries: `Filament\Infolists\Components\`
- Utilities (Get, Set): `Filament\Schemas\Components\Utilities\`
- All actions: `Filament\Actions\` — no `Filament\Tables\Actions\`
- Icons: `Heroicon` enum, not strings
- File visibility: `private` by default
- `Grid`, `Section`, `Fieldset` no longer span all columns by default
- `deferFilters()` is now the default table behavior
## Livewire 4
- `wire:model` is deferred by default; `wire:model.live` for real-time
- Namespace: `App\Livewire`
- Events: `$this->dispatch()`
- Validate and authorize in actions
- `wire:key` in loops
## Testing
- All tests use Pest with factories and factory states
- `mutates(ClassName::class)` to declare coverage intent
- Named assertions: `assertForbidden()` not `assertStatus(403)`
- Datasets for repetitive validation tests
## Tailwind CSS 4
- No deprecated utilities: `bg-opacity-*` is `bg-black/*`, `flex-shrink-*` is `shrink-*`
- Gap utilities for spacing, not margins between siblings
- `dark:` variants when existing components support dark mode
- CSS-first config with `@theme`, not `tailwind.config.js`
================================================
FILE: .github/workflows/docker-publish.yml
================================================
name: Build and Push Docker Image
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
DOCKERHUB_IMAGE: manukminasyan/relaticle
jobs:
build:
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
${{ env.DOCKERHUB_IMAGE }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}
- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
context: .
target: production
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
${{ env.DOCKERHUB_IMAGE }}
cache-from: type=gha,scope=${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=${{ matrix.platform }}
outputs: ${{ github.event_name != 'pull_request' && 'type=image,push-by-digest=true,name-canonical=true,push=true' || '' }}
- name: Export digest
if: github.event_name != 'pull_request'
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
needs: build
permissions:
contents: read
packages: write
steps:
- name: Prepare
run: echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
- name: Download digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata for GHCR
id: meta-ghcr
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}
- name: Extract metadata for Docker Hub
id: meta-dockerhub
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKERHUB_IMAGE }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}
- name: Create manifest list and push to GHCR
working-directory: ${{ runner.temp }}/digests
env:
DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta-ghcr.outputs.json }}
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
- name: Create manifest list and push to Docker Hub
working-directory: ${{ runner.temp }}/digests
env:
DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta-dockerhub.outputs.json }}
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.DOCKERHUB_IMAGE }}@sha256:%s ' *)
- name: Inspect GHCR image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta-ghcr.outputs.version }}
- name: Inspect Docker Hub image
run: |
docker buildx imagetools inspect ${{ env.DOCKERHUB_IMAGE }}:${{ steps.meta-dockerhub.outputs.version }}
================================================
FILE: .github/workflows/filament-view-monitor-simple.yml
================================================
name: Monitor Filament View Updates (Simple)
on:
schedule:
# Run daily at 9 AM UTC
- cron: '0 9 * * *'
workflow_dispatch: # Allow manual trigger
jobs:
check-filament-updates:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
coverage: none
- name: Install dependencies
run: composer install --no-interaction --no-progress
- name: Check for Filament view changes
id: check
run: |
# Define the files we're monitoring
FILES=(
"vendor/filament/filament/resources/views/components/layout/index.blade.php"
"vendor/filament/filament/resources/views/livewire/topbar.blade.php"
)
# Calculate hash of current files
CURRENT_HASH=""
for FILE in "${FILES[@]}"; do
if [ -f "$FILE" ]; then
CURRENT_HASH="${CURRENT_HASH}$(sha256sum "$FILE" | cut -d' ' -f1)"
fi
done
# Hash the combined hashes
FINAL_HASH=$(echo -n "$CURRENT_HASH" | sha256sum | cut -d' ' -f1)
echo "Current hash: $FINAL_HASH"
# Compare with stored hash
HASH_FILE=".github/filament-views-hash.txt"
if [ -f "$HASH_FILE" ]; then
STORED_HASH=$(cat "$HASH_FILE")
echo "Stored hash: $STORED_HASH"
if [ "$FINAL_HASH" != "$STORED_HASH" ]; then
echo "changes_detected=true" >> $GITHUB_OUTPUT
echo "🔔 Filament views have changed!"
# Update the hash file
echo "$FINAL_HASH" > "$HASH_FILE"
else
echo "changes_detected=false" >> $GITHUB_OUTPUT
echo "✅ No changes detected"
fi
else
# First run - save the hash
echo "$FINAL_HASH" > "$HASH_FILE"
echo "changes_detected=false" >> $GITHUB_OUTPUT
echo "📝 Initial hash saved"
fi
- name: Get Filament version
id: version
if: steps.check.outputs.changes_detected == 'true'
run: |
VERSION=$(composer show filament/filament | grep "versions" | cut -d':' -f2 | xargs)
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Create issue notification
if: steps.check.outputs.changes_detected == 'true'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const today = new Date().toISOString().split('T')[0];
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `🔔 Filament Views Updated - ${today}`,
body: `## Filament view files have been updated!
**Filament Version:** ${{ steps.version.outputs.version }}
**Date:** ${today}
The following Filament view files that you've published have been updated in the package:
- \`components/layout/index.blade.php\`
- \`livewire/topbar.blade.php\`
### What to do:
1. Check the [Filament changelog](https://github.com/filamentphp/filament/releases)
2. Review what changed in the views
3. Decide if you need to update your published versions
### How to review changes:
\`\`\`bash
# Compare your published views with the vendor versions
diff -u resources/views/vendor/filament-panels/components/layout/index.blade.php \\
vendor/filament/filament/resources/views/components/layout/index.blade.php
diff -u resources/views/vendor/filament-panels/livewire/topbar.blade.php \\
vendor/filament/filament/resources/views/livewire/topbar.blade.php
\`\`\``,
labels: ['filament-update', 'vendor-views']
});
console.log('✅ Issue created for Filament view updates');
- name: Commit hash update
if: steps.check.outputs.changes_detected == 'true'
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add .github/filament-views-hash.txt
git diff --staged --quiet || git commit -m "Update Filament views hash [skip ci]"
git push
================================================
FILE: .github/workflows/tests.yml
================================================
name: Tests
on: [push]
jobs:
lint-and-static-analysis:
runs-on: ubuntu-latest
name: Code Quality Checks
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Cache Dependencies
uses: actions/cache@v4
with:
path: |
~/.composer/cache
vendor
key: ${{ runner.os }}-php-8.4-composer-${{ hashFiles('composer.lock') }}
restore-keys: |
${{ runner.os }}-php-8.4-composer-
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.4
extensions: json, dom, curl, libxml, mbstring, zip
tools: composer:v2
- name: Install PHP dependencies
run: composer install --no-interaction --no-progress --ansi --prefer-dist --optimize-autoloader
- name: Prepare Laravel Application
run: |
cp .env.ci .env
php artisan key:generate
- name: Run Lint
run: composer test:lint
- name: Run Refactor Check
run: composer test:refactor
- name: Run Type Coverage
run: composer test:type-coverage
- name: Run Static Analysis
run: composer test:types
- name: Architecture Tests
run: composer test:arch
tests:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: [8.4]
shard: [1, 2, 3, 4, 5]
name: Tests (Shard ${{ matrix.shard }}/5)
services:
postgres:
image: postgres:alpine
env:
POSTGRES_DB: relaticle_testing
POSTGRES_PASSWORD: postgres
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Cache Dependencies
uses: actions/cache@v4
with:
path: |
~/.composer/cache
vendor
key: ${{ runner.os }}-php-8.4-composer-${{ hashFiles('composer.lock') }}
restore-keys: |
${{ runner.os }}-php-8.4-composer-
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: json, dom, curl, libxml, mbstring, zip
tools: composer:v2
coverage: none
- name: Set up Node & NPM
uses: actions/setup-node@v5
with:
node-version: '22.x'
- name: Setup Problem Matches
run: |
echo "::add-matcher::${{ runner.tool_cache }}/php.json"
echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
- name: Install PHP dependencies
run: composer install --no-interaction --no-progress --ansi --prefer-dist --optimize-autoloader
- name: Get NPM cache directory
id: npm-cache-dir
shell: bash
run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT}
- name: Cache dependencies
id: npm-cache
uses: actions/cache@v4
with:
path: ${{ steps.npm-cache-dir.outputs.dir }}
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
- name: Build dependencies
run: npm run build
- name: Prepare Laravel
run: |
cp .env.ci .env
php artisan key:generate
- name: Tests
run: composer test:pest:ci
env:
SHARD: ${{ matrix.shard }}/5
browser-tests:
runs-on: ubuntu-latest
name: Browser Tests
services:
postgres:
image: postgres:alpine
env:
POSTGRES_DB: relaticle_testing
POSTGRES_PASSWORD: postgres
POSTGRES_PORT: 5432
POSTGRES_USER: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Cache Dependencies
uses: actions/cache@v4
with:
path: |
~/.composer/cache
vendor
key: ${{ runner.os }}-php-8.4-composer-${{ hashFiles('composer.lock') }}
restore-keys: |
${{ runner.os }}-php-8.4-composer-
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.4
extensions: json, dom, curl, libxml, mbstring, zip
tools: composer:v2
coverage: none
- name: Set up Node & NPM
uses: actions/setup-node@v5
with:
node-version: '22.x'
- name: Install PHP dependencies
run: composer install --no-interaction --no-progress --ansi --prefer-dist --optimize-autoloader
- name: Get NPM cache directory
id: npm-cache-dir
shell: bash
run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT}
- name: Cache NPM dependencies
uses: actions/cache@v4
with:
path: ${{ steps.npm-cache-dir.outputs.dir }}
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Prepare Laravel
run: |
cp .env.ci .env
php artisan key:generate
- name: Install NPM dependencies
run: npm ci
- name: Build assets
run: npm run build
- name: Install Playwright
run: npx playwright install --with-deps chromium
- name: Browser Tests
run: vendor/bin/pest tests/Browser/ --configuration phpunit.ci.xml
================================================
FILE: .gitignore
================================================
.DS_Store
.superpowers
/.phpunit.cache
.scribe
/node_modules
/public/build
/public/hot
/public/storage
/public/sitemap.xml
/storage/*.key
/vendor
.env
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
/coverage-html/
coverage.xml
Homestead.json
Homestead.yaml
auth.json
npm-debug.log
yarn-error.log
AGENTS.md
boost.json
.mcp.json
/.ai/*
!/.ai/guidelines/
/.ai/guidelines/*
!/.ai/guidelines/relaticle/
/.github/skills
/.fleet
/.idea
/.vscode
/.claude
/.superset
/.cursor
/.junie
/.playwright-mcp
/docs
api.json
.scribe/
/public/vendor/scribe
/resources/views/scribe
/storage/app/scribe
/tests/Feature/Scribe
.context
polyscope.json
/bin/setup-preview.sh
.gstack/
================================================
FILE: CLAUDE.md
================================================
<laravel-boost-guidelines>
=== .ai/core rules ===
# Project
This is production code for a commercial SaaS product with paying customers.
Bugs directly impact revenue and user trust.
Treat every change like it's going through senior code review:
- No lazy shortcuts or placeholder code
- Handle errors and edge cases properly
- Write code that won't embarrass you in 6 months
## Database
- This project uses **PostgreSQL exclusively** — do not add SQLite/MySQL compatibility layers, driver checks, or conditional SQL
- Migrations must only have `up()` methods — do not write `down()` methods
## Pre-Commit Quality Checks
Before committing any changes, always run these checks in order:
1. `vendor/bin/pint --dirty --format agent` — fix code style
2. `vendor/bin/rector --dry-run` — if rector suggests changes, apply them with `vendor/bin/rector`
3. `vendor/bin/phpstan analyse` — ensure no new static analysis errors
4. `composer test:type-coverage` — ensure type coverage stays at or above 99.9%
5. `php artisan test --compact` — run relevant tests (use `--filter` for targeted runs)
Do not add new PHPStan errors to the baseline without approval. All parameters and return types must be explicitly typed — untyped closures/parameters will fail type coverage in CI.
## Icons (Remix Icon)
- **Brand/social icons** (GitHub, Discord, Twitter, LinkedIn) → always `fill` variant
- **UI/functional icons** (arrows, chevrons, checks, close) → always `line` variant
- **Feature/section icons** → `line` variant, stay consistent within a section
- **Status/emphasis icons** (success checkmarks, alerts) → `fill` variant
## Scheduling
- All scheduled commands go in `bootstrap/app.php` via `withSchedule()` — not in `routes/console.php`
## Actions
- All write operations (create, update, delete) must go through action classes in `app/Actions/` -- never inline business logic in controllers, MCP tools, Livewire components, or Filament resources
- Actions are the single source of truth for business logic and side effects (notifications, syncs, etc.)
- Filament CRUD may use native `CreateAction`/`EditAction` when the action only does `Model::create()`/`->update()` with no extra logic -- but side effects (e.g., notifications) must still be triggered via `->after()` hooks calling the appropriate action
- When reviewing or refactoring code, extract inline business logic into action classes
## Testing
- Do not write isolated unit tests for action classes, services, or similar internal code -- test them through their real entry points (API endpoints, Filament resources, Livewire components). Unit tests for internal classes create maintenance burden without catching real bugs.
- Use `mutates(ClassName::class)` in test files to declare which source classes each test covers
- Run mutation testing per-class: `php -d xdebug.mode=coverage vendor/bin/pest --mutate --class='App\MyClass' tests/path/`
- No enforced `--min` threshold — use mutation testing as a code review tool, not a CI gate
- Use `$this->travelTo()` in tests that depend on day-of-week or weekly intervals to avoid flaky boundary failures
## Custom Fields
- Models using the `UsesCustomFields` trait handle `custom_fields` automatically — do NOT manually extract, strip, or call `saveCustomFields()` in actions
- The trait merges `'custom_fields'` into `$fillable`, intercepts it during `saving`, and persists values during `saved` — just pass `custom_fields` through in the `$data` array to `create()`/`update()`
- Tenant context for the custom-fields package is set in `SetApiTeamContext` middleware via `TenantContextService::setTenantId()` — actions don't need `withTenant()` wrappers
- In Filament, the package's own `SetTenantContextMiddleware` handles tenant context — no action-level code needed there either
- `CustomFieldValidationService` intentionally uses explicit `where('tenant_id', ...)` with `withoutGlobalScopes()` — this is defensive and correct, don't change it to rely on ambient state
=== .ai/v4 rules ===
## Filament 4
### Important Version 4 Changes
- File visibility is now `private` by default.
- The `deferFilters` method from Filament v3 is now the default behavior in Filament v4, so users must click a button before the filters are applied to the table. To disable this behavior, you can use the `deferFilters(false)` method.
- The `Grid`, `Section`, and `Fieldset` layout components no longer span all columns by default.
- The `all` pagination page method is not available for tables by default.
- All action classes extend `Filament\Actions\Action`. No action classes exist in `Filament\Tables\Actions`.
- The `Form` & `Infolist` layout components have been moved to `Filament\Schemas\Components`, for example `Grid`, `Section`, `Fieldset`, `Tabs`, `Wizard`, etc.
- A new `Repeater` component for Forms has been added.
- Icons now use the `Filament\Support\Icons\Heroicon` Enum by default. Other options are available and documented.
### Organize Component Classes Structure
- Schema components: `Schemas/Components/`
- Table columns: `Tables/Columns/`
- Table filters: `Tables/Filters/`
- Actions: `Actions/`
### Form Components in v4
- Use `Filament\Forms\Components` for form fields like TextInput, Select, Textarea, etc.
- Use `Filament\Schemas\Components` for layout components like Grid, Section, Fieldset, Tabs, Wizard.
### Actions in v4
```php
use Filament\Actions\Action;
Action::make('send')
->label('Send Email')
->icon(Heroicon::OutlinedPaperAirplane)
->requiresConfirmation()
->action(fn (Model $record) => $record->sendEmail());
```
### Table Actions in v4
```php
use Filament\Actions\Action;
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
public static function table(Table $table): Table
{
return $table
->actions([
EditAction::make(),
DeleteAction::make(),
Action::make('approve')
->action(fn (Model $record) => $record->approve()),
]);
}
```
### Icons in v4
```php
use Filament\Support\Icons\Heroicon;
// Instead of string icons
->icon(Heroicon::OutlinedHome)
->icon(Heroicon::SolidUser)
```
### Testing Filament 4 Resources
```php
use function Pest\Livewire\livewire;
it('can list records', function () {
$records = Model::factory()->count(5)->create();
livewire(ListModels::class)
->assertCanSeeTableRecords($records);
});
it('can create a record', function () {
livewire(CreateModel::class)
->fillForm([
'name' => 'Test Name',
])
->call('create')
->assertHasNoFormErrors();
expect(Model::query()->where('name', 'Test Name')->exists())->toBeTrue();
});
it('can edit a record', function () {
$record = Model::factory()->create();
livewire(EditModel::class, ['record' => $record->getRouteKey()])
->fillForm([
'name' => 'Updated Name',
])
->call('save')
->assertHasNoFormErrors();
expect($record->refresh()->name)->toBe('Updated Name');
});
```
=== foundation rules ===
# Laravel Boost Guidelines
The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to ensure the best experience when building Laravel applications.
## Foundational Context
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
- php - 8.4
- filament/filament (FILAMENT) - v5
- laravel/fortify (FORTIFY) - v1
- laravel/framework (LARAVEL) - v12
- laravel/horizon (HORIZON) - v5
- laravel/mcp (MCP) - v0
- laravel/prompts (PROMPTS) - v0
- laravel/sanctum (SANCTUM) - v4
- laravel/socialite (SOCIALITE) - v5
- livewire/livewire (LIVEWIRE) - v4
- larastan/larastan (LARASTAN) - v3
- laravel/boost (BOOST) - v2
- laravel/pail (PAIL) - v1
- laravel/pint (PINT) - v1
- laravel/sail (SAIL) - v1
- pestphp/pest (PEST) - v4
- phpunit/phpunit (PHPUNIT) - v12
- rector/rector (RECTOR) - v2
- tailwindcss (TAILWINDCSS) - v4
## Skills Activation
This project has domain-specific skills available. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
- `laravel-best-practices` — Apply this skill whenever writing, reviewing, or refactoring Laravel PHP code. This includes creating or modifying controllers, models, migrations, form requests, policies, jobs, scheduled commands, service classes, and Eloquent queries. Triggers for N+1 and query performance issues, caching strategies, authorization and security patterns, validation, error handling, queue and job configuration, route definitions, and architectural decisions. Also use for Laravel code reviews and refactoring existing Laravel code to follow best practices. Covers any task involving Laravel backend PHP code patterns.
- `configuring-horizon` — Use this skill whenever the user mentions Horizon by name in a Laravel context. Covers the full Horizon lifecycle: installing Horizon (horizon:install, Sail setup), configuring config/horizon.php (supervisor blocks, queue assignments, balancing strategies, minProcesses/maxProcesses), fixing the dashboard (authorization via Gate::define viewHorizon, blank metrics, horizon:snapshot scheduling), and troubleshooting production issues (worker crashes, timeout chain ordering, LongWaitDetected notifications, waits config). Also covers job tagging and silencing. Do not use for generic Laravel queues without Horizon, SQS or database drivers, standalone Redis setup, Linux supervisord, Telescope, or job batching.
- `mcp-development` — Use this skill for Laravel MCP development only. Trigger when creating or editing MCP tools, resources, prompts, or servers in Laravel projects. Covers: artisan make:mcp-* generators, mcp:inspector, routes/ai.php, Tool/Resource/Prompt classes, schema validation, shouldRegister(), OAuth setup, URI templates, read-only attributes, and MCP debugging. Do not use for non-Laravel MCP projects or generic AI features without MCP.
- `socialite-development` — Manages OAuth social authentication with Laravel Socialite. Activate when adding social login providers; configuring OAuth redirect/callback flows; retrieving authenticated user details; customizing scopes or parameters; setting up community providers; testing with Socialite fakes; or when the user mentions social login, OAuth, Socialite, or third-party authentication.
- `livewire-development` — Use for any task or question involving Livewire. Activate if user mentions Livewire, wire: directives, or Livewire-specific concepts like wire:model, wire:click, wire:sort, or islands, invoke this skill. Covers building new components, debugging reactivity issues, real-time form validation, drag-and-drop, loading states, migrating from Livewire 3 to 4, converting component formats (SFC/MFC/class-based), and performance optimization. Do not use for non-Livewire reactive UI (React, Vue, Alpine-only, Inertia.js) or standard Laravel forms without Livewire.
- `pest-testing` — Use this skill for Pest PHP testing in Laravel projects only. Trigger whenever any test is being written, edited, fixed, or refactored — including fixing tests that broke after a code change, adding assertions, converting PHPUnit to Pest, adding datasets, and TDD workflows. Always activate when the user asks how to write something in Pest, mentions test files or directories (tests/Feature, tests/Unit, tests/Browser), or needs browser testing, smoke testing multiple pages for JS errors, or architecture tests. Covers: it()/expect() syntax, datasets, mocking, browser testing (visit/click/fill), smoke testing, arch(), Livewire component tests, RefreshDatabase, and all Pest 4 features. Do not use for factories, seeders, migrations, controllers, models, or non-test PHP code.
- `tailwindcss-development` — Always invoke when the user's message includes 'tailwind' in any form. Also invoke for: building responsive grid layouts (multi-column card grids, product grids), flex/grid page structures (dashboards with sidebars, fixed topbars, mobile-toggle navs), styling UI components (cards, tables, navbars, pricing sections, forms, inputs, badges), adding dark mode variants, fixing spacing or typography, and Tailwind v3/v4 work. The core use case: writing or fixing Tailwind utility classes in HTML templates (Blade, JSX, Vue). Skip for backend PHP logic, database queries, API routes, JavaScript with no HTML/CSS component, CSS file audits, build tool configuration, and vanilla CSS.
- `custom-fields-development` — Adds dynamic custom fields to Eloquent models without migrations using Filament integration. Use when adding the UsesCustomFields trait to models, integrating custom fields in Filament forms/tables/infolists, configuring field types, working with field validation, or managing feature flags for conditional visibility, encryption, and multi-tenancy.
- `flowforge-development` — Builds Kanban board interfaces for Eloquent models with drag-and-drop functionality. Use when creating board pages, configuring columns and cards, implementing drag-and-drop positioning, working with Filament board pages or standalone Livewire boards, or troubleshooting position-related issues.
- `laravel-query-builder` — Build filtered, sorted, and included API endpoints using spatie/laravel-query-builder. Activates when working with QueryBuilder, AllowedFilter, AllowedSort, AllowedInclude, or when the user mentions query parameters, API filtering, sorting, includes, or spatie/laravel-query-builder.
- `spatie-laravel-php-standards` — Apply Spatie's Laravel and PHP coding standards for any task that creates, edits, reviews, refactors, or formats Laravel/PHP code or Blade templates; use for controllers, Eloquent models, routes, config, validation, migrations, tests, and related files to align with Laravel conventions and PSR-12.
## Conventions
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, and naming.
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
- Check for existing components to reuse before writing a new one.
## Verification Scripts
- Do not create verification scripts or tinker when tests cover that functionality and prove they work. Unit and feature tests are more important.
## Application Structure & Architecture
- Stick to existing directory structure; don't create new base folders without approval.
- Do not change the application's dependencies without approval.
## Frontend Bundling
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
## Documentation Files
- You must only create documentation files if explicitly requested by the user.
## Replies
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
=== boost rules ===
# Laravel Boost
## Tools
- Laravel Boost is an MCP server with tools designed specifically for this application. Prefer Boost tools over manual alternatives like shell commands or file reads.
- Use `database-query` to run read-only queries against the database instead of writing raw SQL in tinker.
- Use `database-schema` to inspect table structure before writing migrations or models.
- Use `get-absolute-url` to resolve the correct scheme, domain, and port for project URLs. Always use this before sharing a URL with the user.
- Use `browser-logs` to read browser logs, errors, and exceptions. Only recent logs are useful, ignore old entries.
## Searching Documentation (IMPORTANT)
- Always use `search-docs` before making code changes. Do not skip this step. It returns version-specific docs based on installed packages automatically.
- Pass a `packages` array to scope results when you know which packages are relevant.
- Use multiple broad, topic-based queries: `['rate limiting', 'routing rate limiting', 'routing']`. Expect the most relevant results first.
- Do not add package names to queries because package info is already shared. Use `test resource table`, not `filament 4 test resource table`.
### Search Syntax
1. Use words for auto-stemmed AND logic: `rate limit` matches both "rate" AND "limit".
2. Use `"quoted phrases"` for exact position matching: `"infinite scroll"` requires adjacent words in order.
3. Combine words and phrases for mixed queries: `middleware "rate limit"`.
4. Use multiple queries for OR logic: `queries=["authentication", "middleware"]`.
## Artisan
- Run Artisan commands directly via the command line (e.g., `php artisan route:list`). Use `php artisan list` to discover available commands and `php artisan [command] --help` to check parameters.
- Inspect routes with `php artisan route:list`. Filter with: `--method=GET`, `--name=users`, `--path=api`, `--except-vendor`, `--only-vendor`.
- Read configuration values using dot notation: `php artisan config:show app.name`, `php artisan config:show database.default`. Or read config files directly from the `config/` directory.
- To check environment variables, read the `.env` file directly.
## Tinker
- Execute PHP in app context for debugging and testing code. Do not create models without user approval, prefer tests with factories instead. Prefer existing Artisan commands over custom tinker code.
- Always use single quotes to prevent shell expansion: `php artisan tinker --execute 'Your::code();'`
- Double quotes for PHP strings inside: `php artisan tinker --execute 'User::where("active", true)->count();'`
=== php rules ===
# PHP
- Always declare `declare(strict_types=1);` at the top of every `.php` file.
- Always use curly braces for control structures, even for single-line bodies.
- Use PHP 8 constructor property promotion: `public function __construct(public GitHub $github) { }`. Do not leave empty zero-parameter `__construct()` methods unless the constructor is private.
- Use explicit return type declarations and type hints for all method parameters: `function isAccessible(User $user, ?string $path = null): bool`
- Use TitleCase for Enum keys: `FavoritePerson`, `BestLake`, `Monthly`.
- Prefer PHPDoc blocks over inline comments. Only add inline comments for exceptionally complex logic.
- Use array shape type definitions in PHPDoc blocks.
=== herd rules ===
# Laravel Herd
- The application is served by Laravel Herd at `https?://[kebab-case-project-dir].test`. Use the `get-absolute-url` tool to generate valid URLs. Never run commands to serve the site. It is always available.
- Use the `herd` CLI to manage services, PHP versions, and sites (e.g. `herd sites`, `herd services:start <service>`, `herd php:list`). Run `herd list` to discover all available commands.
=== tests rules ===
# Test Enforcement
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test --compact` with a specific filename or filter.
=== laravel/core rules ===
# Do Things the Laravel Way
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using `php artisan list` and check their parameters with `php artisan [command] --help`.
- If you're creating a generic PHP class, use `php artisan make:class`.
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
### Model Creation
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `php artisan make:model --help` to check the available options.
## APIs & Eloquent Resources
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
## URL Generation
- When generating links to other pages, prefer named routes and the `route()` function.
## Testing
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
- When creating tests, make use of `php artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
## Vite Error
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
=== laravel/v12 rules ===
# Laravel 12
- CRITICAL: ALWAYS use `search-docs` tool for version-specific Laravel documentation and updated code examples.
- Since Laravel 11, Laravel has a new streamlined file structure which this project uses.
## Laravel 12 Structure
- In Laravel 12, middleware are no longer registered in `app/Http/Kernel.php`.
- Middleware are configured declaratively in `bootstrap/app.php` using `Application::configure()->withMiddleware()`.
- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files.
- `bootstrap/providers.php` contains application specific service providers.
- The `app/Console/Kernel.php` file no longer exists; use `bootstrap/app.php` or `routes/console.php` for console configuration.
- Console commands in `app/Console/Commands/` are automatically available and do not require manual registration.
## Database
- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost.
- Laravel 12 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`.
### Models
- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models.
=== livewire/core rules ===
# Livewire
- Livewire allow to build dynamic, reactive interfaces in PHP without writing JavaScript.
- You can use Alpine.js for client-side interactions instead of JavaScript frameworks.
- Keep state server-side so the UI reflects it. Validate and authorize in actions as you would in HTTP requests.
=== pint/core rules ===
# Laravel Pint Code Formatter
- If you have modified any PHP files, you must run `vendor/bin/pint --dirty --format agent` before finalizing changes to ensure your code matches the project's expected style.
- Do not run `vendor/bin/pint --test --format agent`, simply run `vendor/bin/pint --format agent` to fix any formatting issues.
=== pest/core rules ===
## Pest
- This project uses Pest for testing. Create tests: `php artisan make:test --pest {name}`.
- Run tests: `php artisan test --compact` or filter: `php artisan test --compact --filter=testName`.
- Do NOT delete tests without approval.
=== filament/filament rules ===
## Filament
- Filament is used by this application. Follow the existing conventions for how and where it is implemented.
- Filament is a Server-Driven UI (SDUI) framework for Laravel that lets you define user interfaces in PHP using structured configuration objects. Built on Livewire, Alpine.js, and Tailwind CSS.
- Use the `search-docs` tool for official documentation on Artisan commands, code examples, testing, relationships, and idiomatic practices. If `search-docs` is unavailable, refer to https://filamentphp.com/docs.
### Artisan
- Always use Filament-specific Artisan commands to create files. Find available commands with the `list-artisan-commands` tool, or run `php artisan --help`.
- Always inspect required options before running a command, and always pass `--no-interaction`.
### Patterns
Always use static `make()` methods to initialize components. Most configuration methods accept a `Closure` for dynamic values.
Use `Get $get` to read other form field values for conditional logic:
<code-snippet name="Conditional form field visibility" lang="php">
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Utilities\Get;
Select::make('type')
->options(CompanyType::class)
->required()
->live(),
TextInput::make('company_name')
->required()
->visible(fn (Get $get): bool => $get('type') === 'business'),
</code-snippet>
Use `state()` with a `Closure` to compute derived column values:
<code-snippet name="Computed table column value" lang="php">
use Filament\Tables\Columns\TextColumn;
TextColumn::make('full_name')
->state(fn (User $record): string => "{$record->first_name} {$record->last_name}"),
</code-snippet>
Actions encapsulate a button with an optional modal form and logic:
<code-snippet name="Action with modal form" lang="php">
use Filament\Actions\Action;
use Filament\Forms\Components\TextInput;
Action::make('updateEmail')
->schema([
TextInput::make('email')
->email()
->required(),
])
->action(fn (array $data, User $record) => $record->update($data))
</code-snippet>
### Testing
Always authenticate before testing panel functionality. Filament uses Livewire, so use `Livewire::test()` or `livewire()` (available when `pestphp/pest-plugin-livewire` is in `composer.json`):
<code-snippet name="Table test" lang="php">
use function Pest\Livewire\livewire;
livewire(ListUsers::class)
->assertCanSeeTableRecords($users)
->searchTable($users->first()->name)
->assertCanSeeTableRecords($users->take(1))
->assertCanNotSeeTableRecords($users->skip(1));
</code-snippet>
<code-snippet name="Create resource test" lang="php">
use function Pest\Laravel\assertDatabaseHas;
use function Pest\Livewire\livewire;
livewire(CreateUser::class)
->fillForm([
'name' => 'Test',
'email' => 'test@example.com',
])
->call('create')
->assertNotified()
->assertRedirect();
assertDatabaseHas(User::class, [
'name' => 'Test',
'email' => 'test@example.com',
]);
</code-snippet>
<code-snippet name="Testing validation" lang="php">
use function Pest\Livewire\livewire;
livewire(CreateUser::class)
->fillForm([
'name' => null,
'email' => 'invalid-email',
])
->call('create')
->assertHasFormErrors([
'name' => 'required',
'email' => 'email',
])
->assertNotNotified();
</code-snippet>
<code-snippet name="Calling actions in pages" lang="php">
use Filament\Actions\DeleteAction;
use function Pest\Livewire\livewire;
livewire(EditUser::class, ['record' => $user->id])
->callAction(DeleteAction::class)
->assertNotified()
->assertRedirect();
</code-snippet>
<code-snippet name="Calling actions in tables" lang="php">
use Filament\Actions\Testing\TestAction;
use function Pest\Livewire\livewire;
livewire(ListUsers::class)
->callAction(TestAction::make('promote')->table($user), [
'role' => 'admin',
])
->assertNotified();
</code-snippet>
### Correct Namespaces
- Form fields (`TextInput`, `Select`, etc.): `Filament\Forms\Components\`
- Infolist entries (`TextEntry`, `IconEntry`, etc.): `Filament\Infolists\Components\`
- Layout components (`Grid`, `Section`, `Fieldset`, `Tabs`, `Wizard`, etc.): `Filament\Schemas\Components\`
- Schema utilities (`Get`, `Set`, etc.): `Filament\Schemas\Components\Utilities\`
- Actions (`DeleteAction`, `CreateAction`, etc.): `Filament\Actions\`. Never use `Filament\Tables\Actions\`, `Filament\Forms\Actions\`, or any other sub-namespace for actions.
- Icons: `Filament\Support\Icons\Heroicon` enum (e.g., `Heroicon::PencilSquare`)
### Common Mistakes
- **Never assume public file visibility.** File visibility is `private` by default. Always use `->visibility('public')` when public access is needed.
- **Never assume full-width layout.** `Grid`, `Section`, and `Fieldset` do not span all columns by default. Explicitly set column spans when needed.
=== spatie/boost-spatie-guidelines rules ===
# Project Coding Guidelines
- This codebase follows Spatie's Laravel & PHP guidelines.
- Always activate the `spatie-laravel-php-standards` skill whenever writing, editing, reviewing, or formatting Laravel or PHP code.
</laravel-boost-guidelines>
================================================
FILE: Dockerfile
================================================
# syntax=docker/dockerfile:1
###########################################
# Stage 1: Composer dependencies
###########################################
FROM composer:2 AS composer
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install \
--no-dev \
--no-interaction \
--no-scripts \
--no-autoloader \
--prefer-dist \
--ignore-platform-reqs
###########################################
# Stage 2: Build frontend assets
###########################################
FROM node:22-alpine AS frontend
WORKDIR /app
# Copy package files and install
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts
# Copy source files needed for build
COPY vite.config.js ./
COPY resources ./resources
COPY public ./public
COPY packages ./packages
# Copy vendor for Filament theme CSS
COPY --from=composer /app/vendor ./vendor
RUN npm run build
###########################################
# Stage 3: Production image
###########################################
FROM serversideup/php:8.4-fpm-nginx AS production
LABEL org.opencontainers.image.title="Relaticle CRM"
LABEL org.opencontainers.image.description="Modern, open-source CRM platform"
LABEL org.opencontainers.image.source="https://github.com/Relaticle/relaticle"
# Switch to root to install dependencies
USER root
# Install required PHP extensions
RUN install-php-extensions intl exif gd imagick bcmath
# Install PostgreSQL client for health checks
RUN apt-get update \
&& apt-get install -y --no-install-recommends postgresql-client \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Switch back to www-data
USER www-data
WORKDIR /var/www/html
# Copy application source
COPY --chown=www-data:www-data . .
# Copy vendor from composer stage
COPY --chown=www-data:www-data --from=composer /app/vendor ./vendor
# Copy built frontend assets
COPY --chown=www-data:www-data --from=frontend /app/public/build ./public/build
# Generate optimized autoloader
RUN composer dump-autoload --optimize --no-dev
# Create storage directories
RUN mkdir -p \
storage/app/public \
storage/framework/cache/data \
storage/framework/sessions \
storage/framework/views \
storage/logs \
bootstrap/cache
# Default environment for serversideup/php Laravel automations
ENV AUTORUN_ENABLED=true
ENV AUTORUN_LARAVEL_STORAGE_LINK=true
ENV AUTORUN_LARAVEL_MIGRATION=true
ENV AUTORUN_LARAVEL_MIGRATION_ISOLATION=true
ENV AUTORUN_LARAVEL_CONFIG_CACHE=true
ENV AUTORUN_LARAVEL_ROUTE_CACHE=true
ENV AUTORUN_LARAVEL_VIEW_CACHE=true
ENV AUTORUN_LARAVEL_EVENT_CACHE=true
ENV AUTORUN_LARAVEL_OPTIMIZE=false
ENV PHP_OPCACHE_ENABLE=1
ENV SSL_MODE=off
EXPOSE 8080
================================================
FILE: LICENSE
================================================
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.
================================================
FILE: README.md
================================================
<p align="center">
<a href="https://relaticle.com">
<img src="https://relaticle.com/brand/logomark.svg" width="100px" alt="Relaticle logo" />
</a>
</p>
<h1 align="center">The Open-Source CRM Built for AI Agents</h1>
<p align="center">
<a href="https://github.com/Relaticle/relaticle/actions"><img src="https://img.shields.io/github/actions/workflow/status/Relaticle/relaticle/tests.yml?branch=main&style=for-the-badge&label=tests" alt="Tests"></a>
<a href="https://relaticle.com/docs/mcp"><img src="https://img.shields.io/badge/MCP_Tools-30-8A2BE2?style=for-the-badge" alt="30 MCP Tools"></a>
<a href="https://laravel.com/docs/12.x"><img src="https://img.shields.io/badge/Laravel-12.x-FF2D20?style=for-the-badge&logo=laravel" alt="Laravel 12"></a>
<a href="https://php.net"><img src="https://img.shields.io/badge/PHP-8.4-777BB4?style=for-the-badge&logo=php" alt="PHP 8.4"></a>
<a href="https://github.com/Relaticle/relaticle/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-AGPL--3.0-blue.svg?style=for-the-badge" alt="License"></a>
</p>
<p align="center">
<a href="https://relaticle.com">Website</a> ·
<a href="https://relaticle.com/docs">Documentation</a> ·
<a href="https://relaticle.com/docs/mcp">MCP Server</a> ·
<a href="https://github.com/orgs/Relaticle/projects/1/views/1">Roadmap</a> ·
<a href="https://github.com/Relaticle/relaticle/discussions">Discussions</a>
</p>
<p align="center">
<img src="https://relaticle.com/images/github-preview-light.png?v=3" alt="Relaticle Dashboard - Manage contacts, companies, and opportunities in a modern interface" />
<br>
<sub>Clean, modern interface built with Filament 5 and Livewire 4</sub>
</p>
---
# About Relaticle
Relaticle is a self-hosted CRM with a production-grade MCP server. Connect any AI agent -- Claude, GPT, or open-source models -- with 30 tools for full CRM operations. 22 custom field types, REST API, and multi-team isolation.
**Perfect for:** Developer-led teams, AI-forward startups, and SMBs who want AI agent integration without vendor lock-in.
**Core Strengths:**
- **Agent-Native Infrastructure** - MCP server with 30 tools, REST API with full CRUD, schema discovery for AI agents
- **Customizable Data Model** - 22 field types including entity relationships, conditional visibility, and per-field encryption. No migrations needed.
- **Multi-Team Isolation** - 5-layer authorization with team-scoped data and workspaces
- **Modern Tech Stack** - Laravel 12, Filament 5, PHP 8.4, 1,100+ automated tests
- **Privacy-First** - Self-hosted, AGPL-3.0, your data stays on your server
**vs Other CRMs:**
| | Self-Hosted | Open Source | MCP Tools | Custom Fields | Per-Seat Pricing |
|---|---|---|---|---|---|
| **Relaticle** | Yes | AGPL-3.0 | 30 | 22 types | No |
| **HubSpot** | No | No | 9 | Limited | Yes |
| **Salesforce** | No | No | 0 | Yes (complex) | Yes |
| **Attio** | No | No | 0 | Yes | Yes |
# Requirements
- PHP 8.4+
- PostgreSQL 17+
- Composer 2 and Node.js 20+
- Redis for queues (optional for development)
# Installation
```bash
git clone https://github.com/Relaticle/relaticle.git
cd relaticle && composer app-install
```
# Development
```bash
# Start everything (server, queue, vite)
composer dev
# Run tests
composer test
# Format code
composer lint
```
# Self-Hosting
See the [Self-Hosting Guide](https://relaticle.com/docs/self-hosting) for Docker and manual deployment instructions.
# Documentation
Visit our [documentation](https://relaticle.com/docs) for guides on business usage, technical architecture, MCP server setup, REST API integration, and more.
# Community & Support
- [Report Issues](https://github.com/Relaticle/relaticle/issues)
- [Request Features](https://github.com/Relaticle/relaticle/discussions/categories/ideas)
- [Ask Questions](https://github.com/Relaticle/relaticle/discussions/categories/q-a)
- [Discord](https://discord.gg/relaticle)
- [Star us on GitHub](https://github.com/Relaticle/relaticle) to support the project
# License
Relaticle is open-source software licensed under the [AGPL-3.0 license](LICENSE).
# Star History
[](https://www.star-history.com/#Relaticle/relaticle&Date)
================================================
FILE: TODOS.md
================================================
# TODOs
Deferred work from plan reviews. Each item includes context and reasoning so it can be picked up without the original conversation.
---
## Centralize Marketing Numbers
**What:** Extract hardcoded marketing numbers (MCP tools count, custom field types, test count, authorization layers) into a single config or constants file. All marketing surfaces (hero, features, FAQ, pricing, schema markup, README) should reference this source of truth.
**Why:** The MCP tools count drifted from 20 to 30 as tools were added, but marketing copy wasn't updated. This was caught during a manual audit but could happen again with any number.
**Where numbers appear:** hero.blade.php, features.blade.php, faq.blade.php, community.blade.php, pricing.blade.php, index.blade.php (schema markup + OG description), layout.blade.php (documentation meta), mcp-guide.md, README.md.
**Approach:** Create a `config/marketing.php` with keys like `mcp_tools_count`, `field_types_count`, `test_count`. Reference via `config('marketing.mcp_tools_count')` in Blade templates. For README.md (not rendered by Laravel), keep manual but add a comment noting the config source.
**Effort:** S (CC: ~15min) | **Priority:** P2 | **Depends on:** Nothing
---
## Document the 5-Layer Authorization Model
**What:** The marketing claim "5-layer authorization" is used across multiple surfaces but the actual 5 layers are never explicitly defined. Based on code analysis, the layers appear to be: (1) User authentication (Sanctum/Fortify), (2) Team membership, (3) Team roles, (4) Eloquent policies, (5) Multi-tenancy scoping. This should be documented.
**Why:** If a technical evaluator asks "what are the 5 layers?", there's no answer in the docs. Undocumented marketing claims erode trust with developer audiences.
**Where to document:** Either the developer guide (developer-guide.md) or a dedicated security/architecture section in the getting-started guide.
**Effort:** S (CC: ~10min) | **Priority:** P2 | **Depends on:** Nothing
================================================
FILE: app/Actions/Company/CreateCompany.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Company;
use App\Enums\CreationSource;
use App\Models\Company;
use App\Models\User;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
final readonly class CreateCompany
{
/**
* @param array<string, mixed> $data
*/
public function execute(User $user, array $data, CreationSource $source = CreationSource::WEB): Company
{
abort_unless($user->can('create', Company::class), 403);
$attributes = Arr::only($data, ['name', 'custom_fields']);
$attributes['creation_source'] = $source;
$company = DB::transaction(fn (): Company => Company::query()->create($attributes));
return $company->load('customFieldValues.customField.options');
}
}
================================================
FILE: app/Actions/Company/DeleteCompany.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Company;
use App\Models\Company;
use App\Models\User;
final readonly class DeleteCompany
{
public function execute(User $user, Company $company): void
{
abort_unless($user->can('delete', $company), 403);
$company->delete();
}
}
================================================
FILE: app/Actions/Company/ListCompanies.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Company;
use App\Mcp\Filters\CustomFieldFilter;
use App\Mcp\Schema\CustomFieldFilterSchema;
use App\Models\Company;
use App\Models\User;
use Illuminate\Contracts\Pagination\CursorPaginator;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Http\Request;
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\AllowedInclude;
use Spatie\QueryBuilder\QueryBuilder;
final readonly class ListCompanies
{
/**
* @param array<string, mixed> $filters
* @return CursorPaginator<int, Company>|LengthAwarePaginator<int, Company>
*/
public function execute(
User $user,
int $perPage = 15,
bool $useCursor = false,
array $filters = [],
?int $page = null,
?Request $request = null,
): CursorPaginator|LengthAwarePaginator {
abort_unless($user->can('viewAny', Company::class), 403);
$request ??= new Request(['filter' => $filters]);
$filterSchema = new CustomFieldFilterSchema;
$query = QueryBuilder::for(Company::query()->withCustomFieldValues(), $request)
->allowedFilters(
AllowedFilter::partial('name'),
AllowedFilter::custom('custom_fields', new CustomFieldFilter('company')),
)
->allowedFields('id', 'name', 'creator_id', 'account_owner_id', 'created_at', 'updated_at')
->allowedIncludes(
'creator', 'accountOwner', 'people', 'opportunities',
AllowedInclude::count('peopleCount', 'people'),
AllowedInclude::count('opportunitiesCount', 'opportunities'),
AllowedInclude::count('tasksCount', 'tasks'),
AllowedInclude::count('notesCount', 'notes'),
)
->allowedSorts(
'name', 'created_at', 'updated_at',
...$filterSchema->allowedSorts($user, 'company'),
)
->defaultSort('-created_at')
->orderBy('id');
if ($useCursor) {
return $query->cursorPaginate($perPage);
}
return $query->paginate($perPage, ['*'], 'page', $page);
}
}
================================================
FILE: app/Actions/Company/UpdateCompany.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Company;
use App\Models\Company;
use App\Models\User;
use App\Support\CustomFieldMerger;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
final readonly class UpdateCompany
{
/**
* @param array<string, mixed> $data
*/
public function execute(User $user, Company $company, array $data): Company
{
abort_unless($user->can('update', $company), 403);
$attributes = Arr::only($data, ['name', 'custom_fields']);
$attributes = CustomFieldMerger::merge($company, $attributes);
return DB::transaction(function () use ($company, $attributes): Company {
$company->update($attributes);
return $company->refresh()->load('customFieldValues.customField.options');
});
}
}
================================================
FILE: app/Actions/Fortify/CreateNewSocialUser.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Fortify;
use App\Contracts\User\CreatesNewSocialUsers;
use App\Models\User;
use Filament\Auth\Events\Registered;
use Illuminate\Auth\Events\Verified;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Throwable;
final readonly class CreateNewSocialUser implements CreatesNewSocialUsers
{
/**
* Create a newly registered user.
*
* @param array<string, string> $input
*
* @throws Throwable
*/
public function create(array $input): User
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
])->validate();
return DB::transaction(fn () => tap(User::query()->create([
'name' => $input['name'],
'email' => $input['email'],
]), function (User $user): void {
event(new Registered($user));
if ($user->markEmailAsVerified()) {
event(new Verified($user));
}
}));
}
}
================================================
FILE: app/Actions/Fortify/PasswordValidationRules.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Fortify;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Validation\Rules\Password;
trait PasswordValidationRules
{
/**
* Get the validation rules used to validate passwords.
*
* @return array<int, Rule|array<mixed>|string>
*/
protected function passwordRules(): array
{
return ['required', 'string', Password::default(), 'confirmed'];
}
}
================================================
FILE: app/Actions/Fortify/ResetUserPassword.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\ResetsUserPasswords;
final readonly class ResetUserPassword implements ResetsUserPasswords
{
use PasswordValidationRules;
/**
* Validate and reset the user's forgotten password.
*
* @param array<string, string> $input
*/
public function reset(User $user, array $input): void
{
Validator::make($input, [
'password' => $this->passwordRules(),
])->validate();
$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}
================================================
FILE: app/Actions/Fortify/UpdateUserPassword.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
final readonly class UpdateUserPassword implements UpdatesUserPasswords
{
use PasswordValidationRules;
/**
* Validate and update the user's password.
*
* @param array<string, string> $input
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'current_password' => ['required', 'string', 'current_password:web'],
'password' => $this->passwordRules(),
], [
'current_password.current_password' => __('The provided password does not match your current password.'),
])->validateWithBag('updatePassword');
$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}
================================================
FILE: app/Actions/Fortify/UpdateUserProfileInformation.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
final readonly class UpdateUserProfileInformation implements UpdatesUserProfileInformation
{
/**
* Validate and update the given user's profile information.
*
* @param array<string, mixed> $input
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)],
'profile_photo_path' => ['nullable', 'string', 'max:255'],
])->validateWithBag('updateProfileInformation');
if (array_key_exists('profile_photo_path', $input)) {
if ($input['profile_photo_path']) {
$user->updateProfilePhoto($input['profile_photo_path']);
} else {
$user->deleteProfilePhoto();
}
}
if ($input['email'] !== $user->email) {
$this->updateVerifiedUser($user, $input);
} else {
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
])->save();
}
}
/**
* Update the given verified user's profile information.
*
* @param array<string, string> $input
*/
private function updateVerifiedUser(User $user, array $input): void
{
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
'email_verified_at' => null,
])->save();
$user->sendEmailVerificationNotification();
}
}
================================================
FILE: app/Actions/Jetstream/AddTeamMember.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Models\Team;
use App\Models\User;
use Closure;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Laravel\Jetstream\Contracts\AddsTeamMembers;
use Laravel\Jetstream\Events\AddingTeamMember;
use Laravel\Jetstream\Events\TeamMemberAdded;
use Laravel\Jetstream\Jetstream;
use Laravel\Jetstream\Rules\Role;
final readonly class AddTeamMember implements AddsTeamMembers
{
/**
* Add a new team member to the given team.
*/
public function add(User $user, Team $team, string $email, ?string $role = null): void
{
Gate::forUser($user)->authorize('addTeamMember', $team);
$this->validate($team, $email, $role);
$newTeamMember = Jetstream::findUserByEmailOrFail($email);
event(new AddingTeamMember($team, $newTeamMember));
$team->users()->attach(
$newTeamMember, ['role' => $role]
);
event(new TeamMemberAdded($team, $newTeamMember));
}
/**
* Validate the add member operation.
*/
private function validate(Team $team, string $email, ?string $role): void
{
Validator::make([
'email' => $email,
'role' => $role,
], $this->rules(), [
'email.exists' => __('We were unable to find a registered user with this email address.'),
])->after(
$this->ensureUserIsNotAlreadyOnTeam($team, $email)
)->validateWithBag('addTeamMember');
}
/**
* Get the validation rules for adding a team member.
*
* @return array<string, array<int, string|Rule>>
*/
private function rules(): array
{
return [
'email' => ['required', 'email', 'exists:users'],
'role' => ['required', 'string', new Role],
];
}
/**
* Ensure that the user is not already on the team.
*/
private function ensureUserIsNotAlreadyOnTeam(Team $team, string $email): Closure
{
return function ($validator) use ($team, $email): void { // @pest-ignore-type
$validator->errors()->addIf(
$team->hasUserWithEmail($email),
'email',
__('This user already belongs to the team.')
);
};
}
}
================================================
FILE: app/Actions/Jetstream/CreateTeam.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Models\Team;
use App\Models\User;
use App\Rules\ValidTeamSlug;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Laravel\Jetstream\Contracts\CreatesTeams;
use Laravel\Jetstream\Events\AddingTeam;
use Laravel\Jetstream\Jetstream;
final readonly class CreateTeam implements CreatesTeams
{
/**
* Validate and create a new team for the given user.
*
* @param array<string, string> $input
*/
public function create(User $user, array $input): Team
{
Gate::forUser($user)->authorize('create', Jetstream::newTeamModel());
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'slug' => ['required', 'string', 'max:255', new ValidTeamSlug, 'unique:teams,slug'],
])->validateWithBag('createTeam');
$isFirstTeam = ! $user->ownedTeams()->exists();
event(new AddingTeam($user));
$user->switchTeam($team = $user->ownedTeams()->create([
'name' => $input['name'],
'slug' => $input['slug'],
'personal_team' => $isFirstTeam,
]));
/** @var Team $team */
return $team;
}
}
================================================
FILE: app/Actions/Jetstream/DeleteTeam.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Models\Team;
use Laravel\Jetstream\Contracts\DeletesTeams;
final readonly class DeleteTeam implements DeletesTeams
{
/**
* Delete the given team.
*/
public function delete(Team $team): void
{
$team->purge();
}
}
================================================
FILE: app/Actions/Jetstream/DeleteUser.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Models\Team;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Laravel\Jetstream\Contracts\DeletesTeams;
use Laravel\Jetstream\Contracts\DeletesUsers;
final readonly class DeleteUser implements DeletesUsers
{
/**
* Create a new action instance.
*/
public function __construct(private DeletesTeams $deletesTeams) {}
/**
* Delete the given user.
*/
public function delete(User $user): void
{
DB::transaction(function () use ($user): void {
$this->deleteTeams($user);
$user->deleteProfilePhoto();
$user->tokens->each->delete();
$user->delete();
});
}
/**
* Delete the teams and team associations attached to the user.
*/
private function deleteTeams(User $user): void
{
$user->teams()->detach();
$user->ownedTeams->each(function (Model $team): void {
/** @var Team $team */
$this->deletesTeams->delete($team);
});
}
}
================================================
FILE: app/Actions/Jetstream/InviteTeamMember.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Models\Team;
use App\Models\User;
use Closure;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Unique;
use Laravel\Jetstream\Contracts\InvitesTeamMembers;
use Laravel\Jetstream\Events\InvitingTeamMember;
use Laravel\Jetstream\Jetstream;
use Laravel\Jetstream\Mail\TeamInvitation;
use Laravel\Jetstream\Rules\Role;
use Laravel\Jetstream\TeamInvitation as TeamInvitationModel;
final readonly class InviteTeamMember implements InvitesTeamMembers
{
/**
* Invite a new team member to the given team.
*/
public function invite(User $user, Team $team, string $email, ?string $role = null): void
{
Gate::forUser($user)->authorize('addTeamMember', $team);
$this->validate($team, $email, $role);
event(new InvitingTeamMember($team, $email, $role));
$expiryDays = (int) config('jetstream.invitation_expiry_days', 7);
$invitation = $team->teamInvitations()->create([
'email' => $email,
'role' => $role,
'expires_at' => now()->addDays($expiryDays),
]);
/** @var TeamInvitationModel $invitation */
Mail::to($email)->send(new TeamInvitation($invitation));
}
/**
* Validate the invite member operation.
*/
private function validate(Team $team, string $email, ?string $role): void
{
Validator::make([
'email' => $email,
'role' => $role,
], $this->rules($team), [
'email.unique' => __('This user has already been invited to the team.'),
])->after(
$this->ensureUserIsNotAlreadyOnTeam($team, $email)
)->validateWithBag('addTeamMember');
}
/**
* Get the validation rules for inviting a team member.
*
* @return array<string, list<Unique|Role|string>>
*/
private function rules(Team $team): array
{
return [
'email' => [
'required', 'email',
Rule::unique(Jetstream::teamInvitationModel())->where(function (Builder $query) use ($team): void {
$query->where('team_id', $team->id);
}),
],
'role' => ['required', 'string', new Role],
];
}
/**
* Ensure that the user is not already on the team.
*/
private function ensureUserIsNotAlreadyOnTeam(Team $team, string $email): Closure
{
return function ($validator) use ($team, $email): void { // @pest-ignore-type
$validator->errors()->addIf(
$team->hasUserWithEmail($email),
'email',
__('This user already belongs to the team.')
);
};
}
}
================================================
FILE: app/Actions/Jetstream/RemoveTeamMember.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Models\Team;
use App\Models\User;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Support\Facades\Gate;
use Illuminate\Validation\ValidationException;
use Laravel\Jetstream\Contracts\RemovesTeamMembers;
use Laravel\Jetstream\Events\TeamMemberRemoved;
final readonly class RemoveTeamMember implements RemovesTeamMembers
{
/**
* Remove the team member from the given team.
*/
public function remove(User $user, Team $team, User $teamMember): void
{
$this->authorize($user, $team, $teamMember);
$this->ensureUserDoesNotOwnTeam($teamMember, $team);
$team->removeUser($teamMember);
event(new TeamMemberRemoved($team, $teamMember));
}
/**
* Authorize that the user can remove the team member.
*/
private function authorize(User $user, Team $team, User $teamMember): void
{
throw_if(! Gate::forUser($user)->check('removeTeamMember', $team) &&
$user->id !== $teamMember->id, AuthorizationException::class);
}
/**
* Ensure that the currently authenticated user does not own the team.
*/
private function ensureUserDoesNotOwnTeam(User $teamMember, Team $team): void
{
/** @var User $owner */
$owner = $team->owner;
if ($teamMember->id === $owner->id) {
throw ValidationException::withMessages([
'team' => [__('You may not leave a team that you created.')],
])->errorBag('removeTeamMember');
}
}
}
================================================
FILE: app/Actions/Jetstream/UpdateTeamName.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Jetstream;
use App\Models\Team;
use App\Models\User;
use App\Rules\ValidTeamSlug;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Validator;
use Laravel\Jetstream\Contracts\UpdatesTeamNames;
final readonly class UpdateTeamName implements UpdatesTeamNames
{
/**
* Validate and update the given team's name.
*
* @param array<string, string> $input
*/
public function update(User $user, Team $team, array $input): void
{
Gate::forUser($user)->authorize('update', $team);
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'slug' => ['required', 'string', 'max:255', new ValidTeamSlug(ignoreValue: $team->slug), "unique:teams,slug,{$team->id}"],
])->validateWithBag('updateTeamName');
$team->update([
'name' => $input['name'],
'slug' => $input['slug'],
]);
}
}
================================================
FILE: app/Actions/Note/CreateNote.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Note;
use App\Enums\CreationSource;
use App\Models\Note;
use App\Models\User;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
final readonly class CreateNote
{
/**
* @param array<string, mixed> $data
*/
public function execute(User $user, array $data, CreationSource $source = CreationSource::WEB): Note
{
abort_unless($user->can('create', Note::class), 403);
$companyIds = Arr::pull($data, 'company_ids');
$peopleIds = Arr::pull($data, 'people_ids');
$opportunityIds = Arr::pull($data, 'opportunity_ids');
$attributes = Arr::only($data, ['title', 'custom_fields']);
$attributes['creation_source'] = $source;
$note = DB::transaction(function () use ($attributes, $companyIds, $peopleIds, $opportunityIds): Note {
$note = Note::query()->create($attributes);
if ($companyIds !== null) {
$note->companies()->sync($companyIds);
}
if ($peopleIds !== null) {
$note->people()->sync($peopleIds);
}
if ($opportunityIds !== null) {
$note->opportunities()->sync($opportunityIds);
}
return $note;
});
return $note->load('customFieldValues.customField.options');
}
}
================================================
FILE: app/Actions/Note/DeleteNote.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Note;
use App\Models\Note;
use App\Models\User;
final readonly class DeleteNote
{
public function execute(User $user, Note $note): void
{
abort_unless($user->can('delete', $note), 403);
$note->delete();
}
}
================================================
FILE: app/Actions/Note/ListNotes.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Note;
use App\Mcp\Filters\CustomFieldFilter;
use App\Mcp\Schema\CustomFieldFilterSchema;
use App\Models\Note;
use App\Models\User;
use Illuminate\Contracts\Pagination\CursorPaginator;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Http\Request;
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\AllowedInclude;
use Spatie\QueryBuilder\QueryBuilder;
final readonly class ListNotes
{
/**
* @param array<string, mixed> $filters
* @return CursorPaginator<int, Note>|LengthAwarePaginator<int, Note>
*/
public function execute(
User $user,
int $perPage = 15,
bool $useCursor = false,
array $filters = [],
?int $page = null,
?Request $request = null,
): CursorPaginator|LengthAwarePaginator {
abort_unless($user->can('viewAny', Note::class), 403);
$request ??= new Request(['filter' => $filters]);
$filterSchema = new CustomFieldFilterSchema;
$query = QueryBuilder::for(Note::query()->withCustomFieldValues(), $request)
->allowedFilters(
AllowedFilter::partial('title'),
AllowedFilter::scope('notable_type', 'forNotableType'),
AllowedFilter::scope('notable_id', 'forNotableId'),
AllowedFilter::custom('custom_fields', new CustomFieldFilter('note')),
)
->allowedFields('id', 'title', 'creator_id', 'created_at', 'updated_at')
->allowedIncludes(
'creator', 'companies', 'people', 'opportunities',
AllowedInclude::count('companiesCount', 'companies'),
AllowedInclude::count('peopleCount', 'people'),
AllowedInclude::count('opportunitiesCount', 'opportunities'),
)
->allowedSorts(
'title', 'created_at', 'updated_at',
...$filterSchema->allowedSorts($user, 'note'),
)
->defaultSort('-created_at')
->orderBy('id');
if ($useCursor) {
return $query->cursorPaginate($perPage);
}
return $query->paginate($perPage, ['*'], 'page', $page);
}
}
================================================
FILE: app/Actions/Note/UpdateNote.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Note;
use App\Models\Note;
use App\Models\User;
use App\Support\CustomFieldMerger;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
final readonly class UpdateNote
{
/**
* @param array<string, mixed> $data
*/
public function execute(User $user, Note $note, array $data): Note
{
abort_unless($user->can('update', $note), 403);
$attributes = Arr::only($data, ['title', 'custom_fields']);
$attributes = CustomFieldMerger::merge($note, $attributes);
return DB::transaction(function () use ($note, $attributes, $data): Note {
$note->update($attributes);
if (array_key_exists('company_ids', $data)) {
$note->companies()->sync($data['company_ids']);
}
if (array_key_exists('people_ids', $data)) {
$note->people()->sync($data['people_ids']);
}
if (array_key_exists('opportunity_ids', $data)) {
$note->opportunities()->sync($data['opportunity_ids']);
}
return $note->refresh()->load('customFieldValues.customField.options');
});
}
}
================================================
FILE: app/Actions/Opportunity/CreateOpportunity.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Opportunity;
use App\Enums\CreationSource;
use App\Models\Opportunity;
use App\Models\User;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
final readonly class CreateOpportunity
{
/**
* @param array<string, mixed> $data
*/
public function execute(User $user, array $data, CreationSource $source = CreationSource::WEB): Opportunity
{
abort_unless($user->can('create', Opportunity::class), 403);
$attributes = Arr::only($data, ['name', 'company_id', 'contact_id', 'custom_fields']);
$attributes['creation_source'] = $source;
$opportunity = DB::transaction(fn (): Opportunity => Opportunity::query()->create($attributes));
return $opportunity->load('customFieldValues.customField.options');
}
}
================================================
FILE: app/Actions/Opportunity/DeleteOpportunity.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Opportunity;
use App\Models\Opportunity;
use App\Models\User;
final readonly class DeleteOpportunity
{
public function execute(User $user, Opportunity $opportunity): void
{
abort_unless($user->can('delete', $opportunity), 403);
$opportunity->delete();
}
}
================================================
FILE: app/Actions/Opportunity/ListOpportunities.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Opportunity;
use App\Mcp\Filters\CustomFieldFilter;
use App\Mcp\Schema\CustomFieldFilterSchema;
use App\Models\Opportunity;
use App\Models\User;
use Illuminate\Contracts\Pagination\CursorPaginator;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Http\Request;
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\AllowedInclude;
use Spatie\QueryBuilder\QueryBuilder;
final readonly class ListOpportunities
{
/**
* @param array<string, mixed> $filters
* @return CursorPaginator<int, Opportunity>|LengthAwarePaginator<int, Opportunity>
*/
public function execute(
User $user,
int $perPage = 15,
bool $useCursor = false,
array $filters = [],
?int $page = null,
?Request $request = null,
): CursorPaginator|LengthAwarePaginator {
abort_unless($user->can('viewAny', Opportunity::class), 403);
$request ??= new Request(['filter' => $filters]);
$filterSchema = new CustomFieldFilterSchema;
$query = QueryBuilder::for(Opportunity::query()->withCustomFieldValues(), $request)
->allowedFilters(
AllowedFilter::partial('name'),
AllowedFilter::exact('company_id'),
AllowedFilter::exact('contact_id'),
AllowedFilter::custom('custom_fields', new CustomFieldFilter('opportunity')),
)
->allowedFields('id', 'name', 'company_id', 'contact_id', 'creator_id', 'created_at', 'updated_at')
->allowedIncludes(
'creator', 'company', 'contact',
AllowedInclude::count('tasksCount', 'tasks'),
AllowedInclude::count('notesCount', 'notes'),
)
->allowedSorts(
'name', 'created_at', 'updated_at',
...$filterSchema->allowedSorts($user, 'opportunity'),
)
->defaultSort('-created_at')
->orderBy('id');
if ($useCursor) {
return $query->cursorPaginate($perPage);
}
return $query->paginate($perPage, ['*'], 'page', $page);
}
}
================================================
FILE: app/Actions/Opportunity/UpdateOpportunity.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Opportunity;
use App\Models\Opportunity;
use App\Models\User;
use App\Support\CustomFieldMerger;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
final readonly class UpdateOpportunity
{
/**
* @param array<string, mixed> $data
*/
public function execute(User $user, Opportunity $opportunity, array $data): Opportunity
{
abort_unless($user->can('update', $opportunity), 403);
$attributes = Arr::only($data, ['name', 'company_id', 'contact_id', 'custom_fields']);
$attributes = CustomFieldMerger::merge($opportunity, $attributes);
return DB::transaction(function () use ($opportunity, $attributes): Opportunity {
$opportunity->update($attributes);
return $opportunity->refresh()->load('customFieldValues.customField.options');
});
}
}
================================================
FILE: app/Actions/People/CreatePeople.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\People;
use App\Enums\CreationSource;
use App\Models\People;
use App\Models\User;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
final readonly class CreatePeople
{
/**
* @param array<string, mixed> $data
*/
public function execute(User $user, array $data, CreationSource $source = CreationSource::WEB): People
{
abort_unless($user->can('create', People::class), 403);
$attributes = Arr::only($data, ['name', 'company_id', 'custom_fields']);
$attributes['creation_source'] = $source;
$person = DB::transaction(fn (): People => People::query()->create($attributes));
return $person->load('customFieldValues.customField.options');
}
}
================================================
FILE: app/Actions/People/DeletePeople.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\People;
use App\Models\People;
use App\Models\User;
final readonly class DeletePeople
{
public function execute(User $user, People $people): void
{
abort_unless($user->can('delete', $people), 403);
$people->delete();
}
}
================================================
FILE: app/Actions/People/ListPeople.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\People;
use App\Mcp\Filters\CustomFieldFilter;
use App\Mcp\Schema\CustomFieldFilterSchema;
use App\Models\People;
use App\Models\User;
use Illuminate\Contracts\Pagination\CursorPaginator;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Http\Request;
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\AllowedInclude;
use Spatie\QueryBuilder\QueryBuilder;
final readonly class ListPeople
{
/**
* @param array<string, mixed> $filters
* @return CursorPaginator<int, People>|LengthAwarePaginator<int, People>
*/
public function execute(
User $user,
int $perPage = 15,
bool $useCursor = false,
array $filters = [],
?int $page = null,
?Request $request = null,
): CursorPaginator|LengthAwarePaginator {
abort_unless($user->can('viewAny', People::class), 403);
$request ??= new Request(['filter' => $filters]);
$filterSchema = new CustomFieldFilterSchema;
$query = QueryBuilder::for(People::query()->withCustomFieldValues(), $request)
->allowedFilters(
AllowedFilter::partial('name'),
AllowedFilter::exact('company_id'),
AllowedFilter::custom('custom_fields', new CustomFieldFilter('people')),
)
->allowedFields('id', 'name', 'company_id', 'creator_id', 'created_at', 'updated_at')
->allowedIncludes(
'creator', 'company',
AllowedInclude::count('tasksCount', 'tasks'),
AllowedInclude::count('notesCount', 'notes'),
)
->allowedSorts(
'name', 'created_at', 'updated_at',
...$filterSchema->allowedSorts($user, 'people'),
)
->defaultSort('-created_at')
->orderBy('id');
if ($useCursor) {
return $query->cursorPaginate($perPage);
}
return $query->paginate($perPage, ['*'], 'page', $page);
}
}
================================================
FILE: app/Actions/People/UpdatePeople.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\People;
use App\Models\People;
use App\Models\User;
use App\Support\CustomFieldMerger;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
final readonly class UpdatePeople
{
/**
* @param array<string, mixed> $data
*/
public function execute(User $user, People $people, array $data): People
{
abort_unless($user->can('update', $people), 403);
$attributes = Arr::only($data, ['name', 'company_id', 'custom_fields']);
$attributes = CustomFieldMerger::merge($people, $attributes);
return DB::transaction(function () use ($people, $attributes): People {
$people->update($attributes);
return $people->refresh()->load('customFieldValues.customField.options');
});
}
}
================================================
FILE: app/Actions/Task/CreateTask.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Task;
use App\Enums\CreationSource;
use App\Models\Task;
use App\Models\User;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
final readonly class CreateTask
{
public function __construct(
private NotifyTaskAssignees $notifyAssignees,
) {}
/**
* @param array<string, mixed> $data
*/
public function execute(User $user, array $data, CreationSource $source = CreationSource::WEB): Task
{
abort_unless($user->can('create', Task::class), 403);
$companyIds = Arr::pull($data, 'company_ids');
$peopleIds = Arr::pull($data, 'people_ids');
$opportunityIds = Arr::pull($data, 'opportunity_ids');
$assigneeIds = Arr::pull($data, 'assignee_ids');
$attributes = Arr::only($data, ['title', 'custom_fields']);
$attributes['creation_source'] = $source;
$task = DB::transaction(function () use ($attributes, $companyIds, $peopleIds, $opportunityIds, $assigneeIds): Task {
$task = Task::query()->create($attributes);
if ($companyIds !== null) {
$task->companies()->sync($companyIds);
}
if ($peopleIds !== null) {
$task->people()->sync($peopleIds);
}
if ($opportunityIds !== null) {
$task->opportunities()->sync($opportunityIds);
}
if ($assigneeIds !== null) {
$task->assignees()->sync($assigneeIds);
}
return $task;
});
$this->notifyAssignees->execute($task);
return $task->load('customFieldValues.customField.options');
}
}
================================================
FILE: app/Actions/Task/DeleteTask.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Task;
use App\Models\Task;
use App\Models\User;
final readonly class DeleteTask
{
public function execute(User $user, Task $task): void
{
abort_unless($user->can('delete', $task), 403);
$task->delete();
}
}
================================================
FILE: app/Actions/Task/ListTasks.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Task;
use App\Mcp\Filters\CustomFieldFilter;
use App\Mcp\Schema\CustomFieldFilterSchema;
use App\Models\Task;
use App\Models\User;
use Illuminate\Contracts\Pagination\CursorPaginator;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\AllowedInclude;
use Spatie\QueryBuilder\QueryBuilder;
final readonly class ListTasks
{
/**
* @param array<string, mixed> $filters
* @return CursorPaginator<int, Task>|LengthAwarePaginator<int, Task>
*/
public function execute(
User $user,
int $perPage = 15,
bool $useCursor = false,
array $filters = [],
?int $page = null,
?Request $request = null,
): CursorPaginator|LengthAwarePaginator {
abort_unless($user->can('viewAny', Task::class), 403);
$request ??= new Request(['filter' => $filters]);
$filterSchema = new CustomFieldFilterSchema;
$query = QueryBuilder::for(Task::query()->withCustomFieldValues(), $request)
->allowedFilters(
AllowedFilter::partial('title'),
AllowedFilter::callback('assigned_to_me', function (Builder $query, mixed $value) use ($user): void {
if (filter_var($value, FILTER_VALIDATE_BOOLEAN)) {
$query->whereHas('assignees', fn (Builder $q) => $q->where('users.id', $user->getKey()));
}
}),
AllowedFilter::scope('company_id', 'forCompany'),
AllowedFilter::scope('people_id', 'forPerson'),
AllowedFilter::scope('opportunity_id', 'forOpportunity'),
AllowedFilter::custom('custom_fields', new CustomFieldFilter('task')),
)
->allowedFields('id', 'title', 'creator_id', 'created_at', 'updated_at')
->allowedIncludes(
'creator', 'assignees', 'companies', 'people', 'opportunities',
AllowedInclude::count('assigneesCount', 'assignees'),
AllowedInclude::count('companiesCount', 'companies'),
AllowedInclude::count('peopleCount', 'people'),
AllowedInclude::count('opportunitiesCount', 'opportunities'),
)
->allowedSorts(
'title', 'created_at', 'updated_at',
...$filterSchema->allowedSorts($user, 'task'),
)
->defaultSort('-created_at')
->orderBy('id');
if ($useCursor) {
return $query->cursorPaginate($perPage);
}
return $query->paginate($perPage, ['*'], 'page', $page);
}
}
================================================
FILE: app/Actions/Task/NotifyTaskAssignees.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Task;
use App\Filament\Resources\TaskResource\Pages\ManageTasks;
use App\Models\Task;
use App\Models\User;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Support\Icons\Heroicon;
final readonly class NotifyTaskAssignees
{
/**
* @param array<int> $previousAssigneeIds
*/
public function execute(Task $task, array $previousAssigneeIds = []): void
{
$currentIds = $task->assignees()->pluck('users.id')->all();
$newIds = array_diff($currentIds, $previousAssigneeIds);
if ($newIds === []) {
return;
}
$taskTitle = $task->title;
$taskId = $task->id;
$taskUrl = $this->resolveTaskUrl($task);
defer(function () use ($newIds, $taskTitle, $taskId, $taskUrl): void {
User::query()
->whereIn('id', $newIds)
->get()
->each(function (User $recipient) use ($taskTitle, $taskId, $taskUrl): void {
Notification::make()
->title("New Task Assignment: {$taskTitle}")
->actions([
Action::make('view')
->button()
->label('View Task')
->url($taskUrl)
->markAsRead(),
])
->icon(Heroicon::OutlinedCheckCircle)
->iconColor('primary')
->viewData(['task_id' => $taskId])
->sendToDatabase($recipient);
});
});
}
private function resolveTaskUrl(Task $task): string
{
try {
return ManageTasks::getUrl(['record' => $task]);
} catch (\Throwable) {
return '#';
}
}
}
================================================
FILE: app/Actions/Task/UpdateTask.php
================================================
<?php
declare(strict_types=1);
namespace App\Actions\Task;
use App\Models\Task;
use App\Models\User;
use App\Support\CustomFieldMerger;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
final readonly class UpdateTask
{
public function __construct(
private NotifyTaskAssignees $notifyAssignees,
) {}
/**
* @param array<string, mixed> $data
*
* @throws \Throwable
*/
public function execute(User $user, Task $task, array $data): Task
{
abort_unless($user->can('update', $task), 403);
$attributes = Arr::only($data, ['title', 'custom_fields']);
$attributes = CustomFieldMerger::merge($task, $attributes);
$previousAssigneeIds = $task->assignees()->pluck('users.id')->all();
$task = DB::transaction(function () use ($task, $attributes, $data): Task {
$task->update($attributes);
if (array_key_exists('company_ids', $data)) {
$task->companies()->sync($data['company_ids']);
}
if (array_key_exists('people_ids', $data)) {
$task->people()->sync($data['people_ids']);
}
if (array_key_exists('opportunity_ids', $data)) {
$task->opportunities()->sync($data['opportunity_ids']);
}
if (array_key_exists('assignee_ids', $data)) {
$task->assignees()->sync($data['assignee_ids']);
}
return $task->refresh();
});
$this->notifyAssignees->execute($task, $previousAssigneeIds);
return $task->load('customFieldValues.customField.options');
}
}
================================================
FILE: app/Concerns/DetectsTeamInvitation.php
================================================
<?php
declare(strict_types=1);
namespace App\Concerns;
use App\Models\TeamInvitation;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\HtmlString;
trait DetectsTeamInvitation
{
protected function getTeamInvitationFromSession(): ?TeamInvitation
{
$intendedUrl = session('url.intended', '');
if (! str_contains((string) $intendedUrl, '/team-invitations/')) {
return null;
}
$path = parse_url((string) $intendedUrl, PHP_URL_PATH);
if (! $path) {
return null;
}
$segments = explode('/', trim($path, '/'));
$invitationIndex = array_search('team-invitations', $segments, true);
if ($invitationIndex === false || ! isset($segments[$invitationIndex + 1])) {
return null;
}
return TeamInvitation::query()
->whereKey($segments[$invitationIndex + 1])
->first();
}
protected function getTeamInvitationSubheading(): ?Htmlable
{
$invitation = $this->getTeamInvitationFromSession();
if (! $invitation || $invitation->isExpired()) {
return null;
}
return new HtmlString(
__('You\'ve been invited to join <strong>:team</strong>', [
'team' => e($invitation->team->name),
])
);
}
protected function getInvitationContentHtml(): string
{
$subheading = $this->getTeamInvitationSubheading();
if ($subheading === null) {
return '';
}
return '<p class="text-center text-sm text-gray-500 dark:text-gray-400">'.$subheading->toHtml().'</p>';
}
}
================================================
FILE: app/Console/Commands/BackfillCustomFieldColorsCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Enums\CustomFields\OpportunityField as OpportunityCustomField;
use App\Enums\CustomFields\TaskField as TaskCustomField;
use App\Models\CustomField;
use App\Models\Opportunity;
use App\Models\Task;
use Illuminate\Console\Command;
use Relaticle\CustomFields\Data\CustomFieldOptionSettingsData;
use Relaticle\CustomFields\Data\CustomFieldSettingsData;
final class BackfillCustomFieldColorsCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'custom-fields:backfill-colors
{--team= : Specific team ID to backfill (optional)}
{--dry-run : Show what would be updated without making changes}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Backfill colors for existing custom field options (Task status/priority and Opportunity stages)';
/**
* Execute the console command.
*/
public function handle(): int
{
$this->info('🎨 Backfilling custom field colors...');
$dryRun = $this->option('dry-run');
$specificTeam = $this->option('team');
if ($dryRun) {
$this->warn('🔍 DRY RUN MODE - No changes will be made');
}
// Get fields to update
$query = CustomField::with('options')
->whereIn('name', ['Status', 'Priority', 'Stage'])
->whereIn('entity_type', [Task::class, Opportunity::class])
->where('type', 'select');
if ($specificTeam) {
$query->where('tenant_id', $specificTeam);
}
$fields = $query->get();
$this->info("Found {$fields->count()} fields to process");
$updatedFields = 0;
$updatedOptions = 0;
foreach ($fields as $field) {
$colorMapping = $this->getColorMappingForField($field);
if ($colorMapping === null) {
continue;
}
$this->info("Processing: {$field->name} for {$field->entity_type} (Team {$field->tenant_id})");
// Enable colors on the field if not already enabled
if (! $field->settings->enable_option_colors) {
if (! $dryRun) {
$field->update([
'settings' => new CustomFieldSettingsData(
visible_in_list: $field->settings->visible_in_list ?? true,
list_toggleable_hidden: $field->settings->list_toggleable_hidden,
visible_in_view: $field->settings->visible_in_view ?? true,
searchable: $field->settings->searchable ?? false,
encrypted: $field->settings->encrypted ?? false,
enable_option_colors: true,
visibility: $field->settings->visibility ?? null,
additional: $field->settings->additional ?? [],
),
]);
}
$this->line(' ✓ Enabled color options for field');
$updatedFields++;
} else {
$this->line(' ℹ Field already has color options enabled');
}
// Apply colors to options
foreach ($field->options as $option) {
$color = $colorMapping[$option->name] ?? null;
if ($color !== null) {
$currentColor = $option->settings->color ?? null;
if ($currentColor !== $color) {
if (! $dryRun) {
$option->update([
'settings' => new CustomFieldOptionSettingsData(color: $color),
]);
}
$this->line(" ✓ Set color for '{$option->name}': $color");
$updatedOptions++;
} else {
$this->line(" ℹ '{$option->name}' already has correct color: $color");
}
} else {
$this->line(" ⚠ No color mapping found for option: '{$option->name}'");
}
}
}
if ($dryRun) {
$this->info('🔍 DRY RUN COMPLETE:');
$this->info(" - Would enable colors on $updatedFields fields");
$this->info(" - Would update colors on $updatedOptions options");
} else {
$this->info('✅ BACKFILL COMPLETE:');
$this->info(" - Enabled colors on $updatedFields fields");
$this->info(" - Updated colors on $updatedOptions options");
}
return self::SUCCESS;
}
/**
* Get color mapping for a field based on its configuration
*/
/**
* @return array<int|string, string>|null
*/
private function getColorMappingForField(CustomField $field): ?array
{
return match ([$field->entity_type, $field->name]) {
[Task::class, 'Status'] => TaskCustomField::STATUS->getOptionColors(),
[Task::class, 'Priority'] => TaskCustomField::PRIORITY->getOptionColors(),
[Opportunity::class, 'Stage'] => OpportunityCustomField::STAGE->getOptionColors(),
default => null,
};
}
}
================================================
FILE: app/Console/Commands/CleanupExpiredInvitationsCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Models\TeamInvitation;
use Illuminate\Console\Command;
use Illuminate\Contracts\Database\Query\Builder;
final class CleanupExpiredInvitationsCommand extends Command
{
/**
* @var string
*/
protected $signature = 'invitations:cleanup
{--days=30 : Delete invitations expired more than this many days ago}';
/**
* @var string
*/
protected $description = 'Delete team invitations that have been expired for a specified number of days';
public function handle(): void
{
$days = (int) $this->option('days');
$cutoff = now()->subDays($days);
$deleted = TeamInvitation::query()
->where(function (Builder $query) use ($cutoff): void {
$query->where('expires_at', '<', $cutoff)
->orWhere(function (Builder $query) use ($cutoff): void {
$query->whereNull('expires_at')
->where('created_at', '<', $cutoff);
});
})
->delete();
$this->info("Purged {$deleted} expired invitation(s).");
}
}
================================================
FILE: app/Console/Commands/CreateSystemAdminCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Relaticle\SystemAdmin\Enums\SystemAdministratorRole;
use Relaticle\SystemAdmin\Models\SystemAdministrator;
use Throwable;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\password;
use function Laravel\Prompts\text;
final class CreateSystemAdminCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'sysadmin:create
{--name= : The name of the system administrator}
{--email= : The email address of the system administrator}
{--password= : The password for the system administrator}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new system administrator account';
/**
* Execute the console command.
*/
public function handle(): int
{
$this->info('Create System Administrator Account');
$this->line('────────────────────────────────────');
$this->newLine();
try {
// Check if any system administrators exist
$existingCount = SystemAdministrator::query()->count();
if ($existingCount > 0) {
$this->warn("There are currently {$existingCount} system administrator(s).");
if (! $this->option('no-interaction')) {
$continue = confirm(
label: 'Do you want to create another system administrator?',
default: true
);
if (! $continue) {
$this->info('Operation cancelled.');
return self::SUCCESS;
}
}
}
// Get administrator details
$name = $this->option('name') ?? text(
label: 'Name',
placeholder: 'John Doe',
required: true,
validate: fn (string $value): ?string => strlen($value) < 2 ? 'Name must be at least 2 characters' : null
);
$email = $this->option('email') ?? text(
label: 'Email address',
placeholder: 'admin@example.com',
required: true,
validate: function (string $value): ?string {
if (! filter_var($value, FILTER_VALIDATE_EMAIL)) {
return 'Please enter a valid email address';
}
if (SystemAdministrator::query()->where('email', $value)->exists()) {
return "An administrator with email '{$value}' already exists";
}
return null;
}
);
// Validate email from command option
if ($this->option('email')) {
if (! filter_var($email, FILTER_VALIDATE_EMAIL)) {
$this->error('Invalid email address provided.');
return self::FAILURE;
}
if (SystemAdministrator::query()->where('email', $email)->exists()) {
$this->error("An administrator with email '{$email}' already exists.");
return self::FAILURE;
}
}
$password = $this->option('password') ?? password(
label: 'Password',
placeholder: 'Minimum 8 characters',
required: true,
validate: fn (string $value): ?string => strlen($value) < 8 ? 'Password must be at least 8 characters' : null
);
// Validate password from command option
if ($this->option('password') && strlen($password) < 8) {
$this->error('Password must be at least 8 characters.');
return self::FAILURE;
}
// Show summary
if (! $this->option('no-interaction') && ! ($this->option('name') && $this->option('email') && $this->option('password'))) {
$this->newLine();
$this->info('Summary:');
$this->line(" Name: {$name}");
$this->line(" Email: {$email}");
$this->line(' Role: Super Administrator');
$this->newLine();
$confirmed = confirm(
label: 'Create this system administrator?',
default: true
);
if (! $confirmed) {
$this->info('Operation cancelled.');
return self::SUCCESS;
}
}
// Create the system administrator
$admin = SystemAdministrator::query()->create([
'name' => $name,
'email' => $email,
'password' => bcrypt($password),
'email_verified_at' => now(),
'role' => SystemAdministratorRole::SuperAdministrator,
]);
$this->newLine();
$this->info('✅ System Administrator created successfully!');
$this->newLine();
$this->line(' Details:');
$this->line(" ├─ Name: {$admin->name}");
$this->line(" ├─ Email: {$admin->email}");
$this->line(' ├─ Role: Super Administrator');
$this->line(' └─ Panel: /sysadmin');
$this->newLine();
$this->line(' You can now log in at: '.url('/sysadmin'));
$this->newLine();
return self::SUCCESS;
} catch (Throwable $e) {
$this->error('Failed to create system administrator:');
$this->line($e->getMessage());
if ($this->option('verbose')) {
$this->newLine();
$this->line($e->getTraceAsString());
}
return self::FAILURE;
}
}
}
================================================
FILE: app/Console/Commands/GenerateSitemapCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Spatie\Sitemap\SitemapGenerator;
final class GenerateSitemapCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:generate-sitemap';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate the sitemap';
/**
* Execute the console command.
*/
public function handle(): void
{
SitemapGenerator::create(config('app.url'))
->writeToFile(public_path('sitemap.xml'));
}
}
================================================
FILE: app/Console/Commands/InstallCommand.php
================================================
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Process;
use Relaticle\SystemAdmin\Enums\SystemAdministratorRole;
use Relaticle\SystemAdmin\Models\SystemAdministrator;
use Throwable;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\select;
use function Laravel\Prompts\spin;
use function Laravel\Prompts\text;
use function Laravel\Prompts\warning;
final class InstallCommand extends Command
{
protected $signature = 'relaticle:install
{--force : Force installation even if already configured}
{--env-file= : Custom path to .env file (for testing)}';
protected $description = 'Install and configure Relaticle';
public function handle(): int
{
$this->displayWelcome();
if (! $this->shouldProceed()) {
return self::SUCCESS;
}
$config = $this->getConfiguration();
return $this->runInstallation($config);
}
private function displayWelcome(): void
{
$this->output->write(PHP_EOL.' <fg=cyan>
____ _ _ _ _
| _ \ ___| | __ _| |_(_) ___| | ___
| |_) / _ \ |/ _` | __| |/ __| |/ _ \
| _ < __/ | (_| | |_| | (__| | __/
|_| \_\___|_|\__,_|\__|_|\___|_|\___|</>'.PHP_EOL.PHP_EOL);
}
private function shouldProceed(): bool
{
if (! $this->option('force') && $this->isAlreadyInstalled()) {
warning('Relaticle appears to be already installed.');
return confirm(
label: 'Do you want to continue anyway?',
default: false,
hint: 'This may overwrite existing configuration'
);
}
return true;
}
private function isAlreadyInstalled(): bool
{
return File::exists($this->envPath()) &&
config('app.key') &&
File::exists(public_path('storage'));
}
/** @return array<string, mixed> */
private function getConfiguration(): array
{
$this->info('Let\'s configure your Relaticle installation...');
$database = select(
label: 'Which database would you like to use?',
options: [
'sqlite' => 'SQLite (Recommended for local development)',
'pgsql' => 'PostgreSQL (Recommended for production)',
],
default: 'sqlite',
hint: 'SQLite requires no additional setup'
);
$installDemoData = confirm(
label: 'Install demo data?',
default: true,
hint: 'Includes sample companies, contacts, and more'
);
$createSysAdmin = confirm(
label: 'Create system administrator account?',
default: true,
hint: 'You can create one later using: php artisan sysadmin:create'
);
return [
'database' => $database,
'demo_data' => $installDemoData,
'sysadmin_user' => $createSysAdmin,
];
}
/** @param array<string, mixed> $config */
private function runInstallation(array $config): int
{
/** @var array<string, callable(): bool> */
$installationSteps = [
'System Requirements' => $this->checkSystemRequirements(...),
'Environment Setup' => fn (): bool => $this->setupEnvironment($config),
'Dependencies' => $this->installDependencies(...),
'Database' => $this->setupDatabase(...),
'Assets' => $this->buildAssets(...),
'Storage' => $this->setupStorage(...),
'Demo Data' => fn (): bool => $config['demo_data'] ? $this->seedDemoData() : true,
];
$this->info('🚀 Starting installation process...');
// Process non-interactive steps with spinner
foreach ($installationSteps as $stepName => $stepFunction) {
$success = spin(
callback: fn (): mixed => $stepFunction(),
message: "Installing {$stepName}..."
);
if (! $success) {
$this->newLine();
$this->error("❌ Installation failed during: {$stepName}");
$this->newLine();
$this->line('<comment>Check the error messages above for more details.</comment>');
$this->line('<comment>You can re-run the installer with --force to retry.</comment>');
return self::FAILURE;
}
$this->line(" ✅ {$stepName} completed");
}
// Handle System Administrator creation separately (requires user interaction)
if ($config['sysadmin_user']) {
$this->newLine();
$this->info('Creating System Administrator account...');
if (! $this->createSystemAdministrator()) {
$this->newLine();
$this->error('❌ Installation failed during: System Administrator creation');
$this->newLine();
$this->line('<comment>You can create a system administrator later using: php artisan sysadmin:create</comment>');
return self::FAILURE;
}
$this->line(' ✅ System Administrator created');
}
$this->newLine();
$this->displaySuccessMessage($config);
return self::SUCCESS;
}
private function checkSystemRequirements(): bool
{
$requirements = [
'PHP 8.4+' => version_compare(PHP_VERSION, '8.3.0', '>='),
'Composer' => $this->commandExists('composer'),
'Node.js' => $this->commandExists('node'),
'NPM' => $this->commandExists('npm'),
];
$extensions = [
'pdo_sqlite', 'gd', 'bcmath', 'ctype', 'fileinfo',
'json', 'mbstring', 'openssl', 'tokenizer', 'xml',
];
foreach ($extensions as $extension) {
$requirements["PHP {$extension}"] = extension_loaded($extension);
}
$failed = array_filter($requirements, fn (bool $passed): bool => ! $passed);
if ($failed !== []) {
$this->newLine();
$this->error('✗ Missing system requirements:');
foreach (array_keys($failed) as $requirement) {
$this->line(" • {$requirement}");
}
$this->newLine();
$this->line('<comment>Please install the missing requirements and try again.</comment>');
return false;
}
return true;
}
private function commandExists(string $command): bool
{
return Process::run("which {$command} 2>/dev/null")->successful();
}
/** @param array<string, mixed> $config */
private function setupEnvironment(array $config): bool
{
// Create .env file
if (! File::exists($this->envPath())) {
if (! File::exists(base_path('.env.example'))) {
return false;
}
File::copy(base_path('.env.example'), $this->envPath());
}
// Generate app key
if (! config('app.key')) {
Artisan::call('key:generate', ['--force' => true]);
}
// Configure database
return $this->configureDatabaseConnection($config['database']);
}
private function configureDatabaseConnection(string $type): bool
{
$envContent = File::get($this->envPath());
if ($type === 'sqlite') {
if (! File::exists(database_path())) {
File::makeDirectory(database_path(), 0755, true);
}
$dbPath = database_path('database.sqlite');
if (! File::exists($dbPath)) {
File::put($dbPath, '');
}
$config = [
'DB_CONNECTION=sqlite',
"DB_DATABASE={$dbPath}",
'DB_HOST=',
'DB_PORT=',
'DB_USERNAME=',
'DB_PASSWORD=',
];
} else {
// For non-SQLite, we'll use the existing .env values or prompt if needed
return true;
}
foreach ($config as $line) {
[$key, $value] = explode('=', $line, 2);
$envContent = preg_replace("/^{$key}=.*/m", $line, (string) $envContent);
}
File::put($this->envPath(), $envContent);
return true;
}
private function installDependencies(): bool
{
$composerResult = Process::run('composer install --no-interaction --prefer-dist --optimize-autoloader');
if (! $composerResult->successful()) {
$this->error('Composer install failed:');
$this->line($composerResult->errorOutput());
return false;
}
$npmResult = Process::run('npm ci --silent');
if (! $npmResult->successful()) {
$this->error('NPM install failed:');
$this->line($npmResult->errorOutput());
return false;
}
return true;
}
private function setupDatabase(): bool
{
try {
Artisan::call('migrate', ['--force' => true]);
return true;
} catch (Throwable $e) {
$this->error('Database migration failed:');
$this->line($e->getMessage());
return false;
}
}
private function buildAssets(): bool
{
$result = Process::run('npm run build');
if (! $result->successful()) {
$this->error('Asset compilation failed:');
$this->line($result->errorOutput());
return false;
}
return true;
}
private function setupStorage(): bool
{
try {
Artisan::call('storage:link', ['--force' => true]);
return true;
} catch (Throwable $e) {
$this->error('Storage link failed:');
$this->line($e->getMessage());
return false;
}
}
private function seedDemoData(): bool
{
try {
// When using --force, we might be re-running installation
// Use migrate:fresh to reset the database cleanly
if ($this->option('force')) {
Artisan::call('migrate:fresh', ['--force' => true]);
}
Artisan::call('db:seed', ['--force' => true]);
return true;
} catch (Throwable $e) {
$this->error('Demo data seeding failed:');
$this->line($e->getMessage());
return false;
}
}
private function createSystemAdministrator(): bool
{
try {
// Check if system administrator already exists
if (SystemAdministrator::query()->exists()) {
$this->warn('A System Administrator already exists.');
$overwrite = confirm(
label: 'Do you want to create another one?',
default: false,
hint: 'You can have multiple system administrators'
);
if (! $overwrite) {
return true;
}
}
$name = text(
label: 'System Administrator name',
default: 'System Admin',
required: true
);
$email = text(
label: 'System Administrator email address',
default: 'sysadmin@relaticle.local',
required: true,
validate: fn (string $value): ?string => filter_var($value, FILTER_VALIDATE_EMAIL) ? null : 'Please enter a valid email address'
);
// Check if email already exists
if (SystemAdministrator::query()->where('email', $email)->exists()) {
$this->error("A System Administrator with email '{$email}' already exists.");
return false;
}
$password = text(
label: 'System Administrator password (min. 8 characters)',
default: 'password123',
required: true,
validate: fn (string $value): ?string => strlen($value) >= 8 ? null : 'Password must be at least 8 characters'
);
// Create the system administrator
SystemAdministrator::query()->create([
'name' => $name,
'email' => $email,
'password' => bcrypt($password),
'email_verified_at' => now(),
'role' => SystemAdministratorRole::SuperAdministrator,
]);
$this->info(' System Administrator created successfully!');
$this->line(" Email: {$email}");
$this->line(' Access panel at: /sysadmin');
return true;
} catch (Throwable $e) {
$this->error('System Administrator creation failed:');
$this->line($e->getMessage());
return false;
}
}
/** @param array<string, mixed> $config */
private function displaySuccessMessage(array $config): void
{
$this->newLine();
$this->info('🎉 Relaticle installed successfully!');
$this->newLine();
$this->line(' <options=bold>Start all development services:</>');
$this->line(' composer run dev');
$this->newLine();
$this->line(' <options=bold>Your application:</>');
$this->line(' http://localhost:8000');
if ($config['sysadmin_user'] ?? false) {
$this->newLine();
$this->line(' <options=bold>System Admin panel:</>');
$this->line(' http://localhost:8000/sysadmin');
}
if ($config['demo_data']) {
$this->newLine();
$this->line(' <options=bold>Demo data included:</>');
$this->line(' • Sample companies and contacts');
$this->line(' • Example opportunities and tasks');
$this->line(' • Pre-configured custom fields');
}
$this->newLine();
$this->line(' <options=bold>Development services:</>');
$this->line(' • Laravel development server');
$this->line(' • Vite asset watcher with HMR');
$this->line(' • Queue worker (Horizon)');
$this->line(' • Real-time logs (Pail)');
$this->newLine();
$this->line(' Documentation: https://relaticle.com/documentation');
$this->newLine();
$this->info('Happy CRM-ing! 🚀');
}
private function envPath(): string
{
return $this->option('env-file') ?: base_path('.env');
}
}
================================================
FILE: app/Contracts/User/CreatesNewSocialUsers.php
================================================
<?php
declare(strict_types=1);
namespace App\Contracts\User;
use App\Models\User;
interface CreatesNewSocialUsers
{
/**
* Create a new social user.
*
* @param array<string, string> $input
*/
public function create(array $input): User;
}
================================================
FILE: app/Data/SubscriberData.php
================================================
<?php
declare(strict_types=1);
namespace App\Data;
use Spatie\LaravelData\Data;
final class SubscriberData extends Data
{
public function __construct(
public string $email,
public ?string $first_name = '',
public ?string $last_name = '',
/** @var array<string> */
public ?array $tags = [],
public bool $skip_confirmation = true,
) {}
}
================================================
FILE: app/Enums/CreationSource.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
use Filament\Support\Contracts\HasColor;
use Filament\Support\Contracts\HasLabel;
enum CreationSource: string implements HasColor, HasLabel
{
/**
* Created through the web application interface by a user.
* This includes records created through forms, dashboards, and
* admin interfaces where a user directly inputs the data.
*/
case WEB = 'web';
/**
* Created by automated system processes without direct user action.
* Examples include scheduled jobs, event-triggered workflows,
* and background processes that generate records automatically.
*/
case SYSTEM = 'system';
/**
* Created through bulk data import functionality.
* This applies to records generated when users upload files
* (CSV, Excel, etc.) through import tools or when data is
* migrated from another system in bulk operations.
*/
case IMPORT = 'import';
/**
* Created through the REST API.
* This applies to records created by external integrations
* and third-party applications using API tokens.
*/
case API = 'api';
/**
* Created through the MCP server by AI agents.
* This applies to records created via Model Context Protocol
* tools, typically by AI assistants interacting with the system.
*/
case MCP = 'mcp';
public function getColor(): string
{
return match ($this) {
self::WEB => 'info',
self::SYSTEM => 'warning',
self::IMPORT => 'success',
self::API => 'purple',
self::MCP => 'gray',
};
}
public function getLabel(): string
{
return match ($this) {
self::WEB => 'Web Interface',
self::SYSTEM => 'System Process',
self::IMPORT => 'Data Import',
self::API => 'API',
self::MCP => 'MCP Agent',
};
}
}
================================================
FILE: app/Enums/CustomFieldType.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums;
/**
* ABOUTME: Maps to the field types available in the relaticle/custom-fields package
* ABOUTME: Provides type-safe references to custom field types for maintainability
*/
enum CustomFieldType: string
{
case TEXT = 'text';
case NUMBER = 'number';
case EMAIL = 'email';
case PHONE = 'phone';
case LINK = 'link';
case TEXTAREA = 'textarea';
case CHECKBOX = 'checkbox';
case CHECKBOX_LIST = 'checkbox-list';
case RADIO = 'radio';
case RICH_EDITOR = 'rich-editor';
case MARKDOWN_EDITOR = 'markdown-editor';
case TAGS_INPUT = 'tags-input';
case COLOR_PICKER = 'color-picker';
case TOGGLE = 'toggle';
case TOGGLE_BUTTONS = 'toggle-buttons';
case CURRENCY = 'currency';
case DATE = 'date';
case DATE_TIME = 'date-time';
case SELECT = 'select';
case MULTI_SELECT = 'multi-select';
case FILE_UPLOAD = 'file-upload';
case RECORD = 'record';
}
================================================
FILE: app/Enums/CustomFields/CompanyField.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums\CustomFields;
use App\Enums\CustomFieldType;
enum CompanyField: string
{
use CustomFieldTrait;
/**
* Ideal Customer Profile: Indicates whether the company is the most suitable customer for you
*/
case ICP = 'icp';
/**
* Domains: Website domains of the company (system field)
*/
case DOMAINS = 'domains';
/**
* LinkedIn: The LinkedIn profile URL of the company
*/
case LINKEDIN = 'linkedin';
public function getDisplayName(): string
{
return match ($this) {
self::ICP => 'ICP',
self::DOMAINS => 'Domains',
self::LINKEDIN => 'LinkedIn',
};
}
public function getFieldType(): string
{
return match ($this) {
self::ICP => CustomFieldType::TOGGLE->value,
self::DOMAINS, self::LINKEDIN => CustomFieldType::LINK->value,
};
}
public function isSystemDefined(): bool
{
return match ($this) {
self::DOMAINS => true,
default => false,
};
}
public function isListToggleableHidden(): bool
{
return match ($this) {
self::ICP, self::DOMAINS => false,
default => true,
};
}
public function getDescription(): string
{
return match ($this) {
self::ICP => 'Indicates whether this company is an Ideal Customer Profile',
self::DOMAINS => 'Website domains of the company (e.g., example.com)',
self::LINKEDIN => 'URL to the company\'s LinkedIn profile',
};
}
public function allowsMultipleValues(): bool
{
return match ($this) {
self::DOMAINS => true,
default => false,
};
}
public function isUniquePerEntityType(): bool
{
return match ($this) {
self::DOMAINS => true,
default => false,
};
}
}
================================================
FILE: app/Enums/CustomFields/CustomFieldTrait.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums\CustomFields;
use Illuminate\Support\Str;
use Relaticle\CustomFields\Enums\CustomFieldWidth;
/**
* Trait for custom field enums to provide configuration data
*
* This trait provides a standardized interface for custom field enums
* and default implementations for optional methods.
*/
trait CustomFieldTrait
{
/**
* Get the display name for the field
*
* @return string The human-readable name of the field
*/
public function getDisplayName(): string
{
return Str::title($this->name);
}
/**
* Get the field type
*
* @return string The type of form field to use
*/
abstract public function getFieldType(): string;
/**
* Get whether this field is system defined
*
* System-defined fields cannot be deleted by users, only deactivated.
*
* @return bool True if the field is system defined
*/
public function isSystemDefined(): bool
{
return true;
}
/**
* Get whether the field is hidden in list toggle
*
* Fields that aren't toggleable hidden are always shown in lists.
*
* @return bool True if the field can be hidden in list view
*/
public function isListToggleableHidden(): bool
{
return true;
}
/**
* Get the field width
*
* @return CustomFieldWidth The width of the field or null for default width
*/
public function getWidth(): CustomFieldWidth
{
return CustomFieldWidth::_100;
}
/**
* Get options for select fields
*
* @return array<int|string, string>|null Array of options for select/multi-select fields or null if not applicable
*/
public function getOptions(): ?array
{
return null;
}
/**
* Get field description (tooltip)
*
* @return string|null The field description or null if not provided
*/
public function getDescription(): ?string
{
return null;
}
/**
* Get color mapping for select field options
*
* @return array<int|string, string>|null Array of option => color mappings or null if not applicable
*/
public function getOptionColors(): ?array
{
return null;
}
/**
* Get whether this field should have color options enabled
*
* @return bool True if color options should be enabled
*/
public function hasColorOptions(): bool
{
return $this->getOptionColors() !== null;
}
/**
* Get whether this field allows multiple values
*
* @return bool True if multiple values are allowed
*/
public function allowsMultipleValues(): bool
{
return false;
}
/**
* Get the maximum number of values allowed for this field
*
* @return int Maximum values (1 for single value fields)
*/
public function getMaxValues(): int
{
return $this->allowsMultipleValues() ? 5 : 1;
}
/**
* Get whether this field value must be unique per entity type
*
* @return bool True if values must be unique across all records of this entity type
*/
public function isUniquePerEntityType(): bool
{
return false;
}
/**
* Get complete field configuration
*
* @return array{
* name: string,
* type: string,
* systemDefined: bool,
* listToggleableHidden: bool,
* width: CustomFieldWidth|null,
* options: array<int|string, string>|null,
* description: string|null,
* optionColors: array<int|string, string>|null,
* hasColorOptions: bool,
* allowsMultipleValues: bool
* } The complete field configuration
*/
public function getConfiguration(): array
{
return [
'name' => $this->getDisplayName(),
'type' => $this->getFieldType(),
'systemDefined' => $this->isSystemDefined(),
'listToggleableHidden' => $this->isListToggleableHidden(),
'width' => $this->getWidth(),
'options' => $this->getOptions(),
'description' => $this->getDescription(),
'optionColors' => $this->getOptionColors(),
'hasColorOptions' => $this->hasColorOptions(),
'allowsMultipleValues' => $this->allowsMultipleValues(),
];
}
}
================================================
FILE: app/Enums/CustomFields/NoteField.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums\CustomFields;
use App\Enums\CustomFieldType;
/**
* Note custom field codes
*/
enum NoteField: string
{
use CustomFieldTrait;
case BODY = 'body';
public function getFieldType(): string
{
return match ($this) {
self::BODY => CustomFieldType::RICH_EDITOR->value,
};
}
public function getDisplayName(): string
{
return match ($this) {
self::BODY => 'Body',
};
}
public function isListToggleableHidden(): bool
{
return match ($this) {
self::BODY => true,
};
}
}
================================================
FILE: app/Enums/CustomFields/OpportunityField.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums\CustomFields;
use App\Enums\CustomFieldType;
enum OpportunityField: string
{
use CustomFieldTrait;
case AMOUNT = 'amount';
case CLOSE_DATE = 'close_date';
case STAGE = 'stage';
/**
* @return string[]|null
*/
public function getOptions(): ?array
{
return match ($this) {
self::STAGE => [
'Prospecting',
'Qualification',
'Needs Analysis',
'Value Proposition',
'Id. Decision Makers',
'Perception Analysis',
'Proposal/Price Quote',
'Negotiation/Review',
'Closed Won',
'Closed Lost',
],
default => null,
};
}
public function getFieldType(): string
{
return match ($this) {
self::AMOUNT => CustomFieldType::CURRENCY->value,
self::CLOSE_DATE => CustomFieldType::DATE->value,
self::STAGE => CustomFieldType::SELECT->value,
};
}
public function getDisplayName(): string
{
return match ($this) {
self::AMOUNT => 'Amount',
self::CLOSE_DATE => 'Close Date',
self::STAGE => 'Stage',
};
}
public function isListToggleableHidden(): bool
{
return false;
}
/**
* Get color mapping for select field options
*
* 2024 Sophisticated Sales Journey - A unique emotional progression through the
* pipeline using earth-inspired, professional colors that tell the story of
* building energy, trust, and momentum from first contact to final outcome.
* Based on latest color psychology and 2024 design sophistication trends.
*
* @return array<int|string, string>|null Array of option => color mappings or null if not applicable
*/
public function getOptionColors(): ?array
{
return match ($this) {
self::STAGE => [
'Prospecting' => '#a5b4fc', // Misty Dawn - Soft exploration of possibilities
'Qualification' => '#1e40af', // Ocean Depth - Deep analytical thinking
'Needs Analysis' => '#0d9488', // Teal Understanding - Empathy & insight
'Value Proposition' => '#eab308', // Golden Clarity - Bright ideas & value
'Id. Decision Makers' => '#7c3aed', // Royal Authority - Power & influence
'Perception Analysis' => '#f59e0b', // Warm Amber - Comfortable evaluation
'Proposal/Price Quote' => '#1e293b', // Professional Navy - Serious business
'Negotiation/Review' => '#f97316', // Electric Coral - Dynamic energy
'Closed Won' => '#059669', // Victory Emerald - Success celebration
'Closed Lost' => '#6b7280', // Silver Acceptance - Respectful closure
],
default => null,
};
}
}
================================================
FILE: app/Enums/CustomFields/PeopleField.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums\CustomFields;
use App\Enums\CustomFieldType;
/**
* People custom field codes
*/
enum PeopleField: string
{
use CustomFieldTrait;
case EMAILS = 'emails';
case PHONE_NUMBER = 'phone_number';
case JOB_TITLE = 'job_title';
case LINKEDIN = 'linkedin';
public function getFieldType(): string
{
return match ($this) {
self::EMAILS => CustomFieldType::EMAIL->value,
self::PHONE_NUMBER => CustomFieldType::PHONE->value,
self::JOB_TITLE => CustomFieldType::TEXT->value,
self::LINKEDIN => CustomFieldType::LINK->value,
};
}
public function getDisplayName(): string
{
return match ($this) {
self::EMAILS => 'Emails',
self::PHONE_NUMBER => 'Phone Number',
self::JOB_TITLE => 'Job Title',
self::LINKEDIN => 'LinkedIn',
};
}
public function isListToggleableHidden(): bool
{
return match ($this) {
self::JOB_TITLE, self::EMAILS => false,
default => true,
};
}
public function isSystemDefined(): bool
{
return match ($this) {
self::EMAILS => true,
default => false,
};
}
public function allowsMultipleValues(): bool
{
return match ($this) {
self::EMAILS => true,
default => false,
};
}
public function isUniquePerEntityType(): bool
{
return match ($this) {
self::EMAILS => true,
default => false,
};
}
}
================================================
FILE: app/Enums/CustomFields/TaskField.php
================================================
<?php
declare(strict_types=1);
namespace App\Enums\CustomFields;
use App\Enums\CustomFieldType;
use Relaticle\CustomFields\Enums\CustomFieldWidth;
enum TaskField: string
{
use CustomFieldTrait;
/**
* Task status tracking
*/
case STATUS = 'status';
/**
* Task priority level
*/
case PRIORITY = 'priority';
/**
* Detailed task description
*/
case DESCRIPTION = 'description';
/**
* Task due date and time
*/
case DUE_DATE = 'due_date';
/**
* Get the display name for the field
*
* @return string The human-readable field name
*/
public function getDisplayName(): string
{
return match ($this) {
self::STATUS => 'Status',
self::PRIORITY => 'Priority',
self::DESCRIPTION => 'Description',
self::DUE_DATE => 'Due Date',
};
}
/**
* Get the field type
*
* @return string The type of form control to use
*/
public function getFieldType(): string
{
return match ($this) {
self::STATUS, self::PRIORITY => CustomFieldType::SELECT->value,
self::DESCRIPTION => CustomFieldType::RICH_EDITOR->value,
self::DUE_DATE => CustomFieldType::DATE_TIME->value,
};
}
/**
* Get whether this field is system defined
*
* @return bool True if the field is system defined
*/
public function isSystemDefined(): bool
{
return match ($this) {
self::STATUS, self::PRIORITY => true,
default => false,
};
}
/**
* Get whether the field is hidden in list toggle
*
* @return bool True if the field can be hidden in list view
*/
public function isListToggleableHidden(): bool
{
return match ($this) {
self::STATUS, self::PRIORITY, self::DUE_DATE => false,
default => true,
};
}
/**
* Get the field width
*
* @return CustomFieldWidth The width of the field or null for default width
*/
public function getWidth(): CustomFieldWidth
{
return match ($this) {
self::STATUS, self::PRIORITY => CustomFieldWidth::_50,
default => CustomFieldWidth::_100,
};
}
/**
* Get available options for this field
*
* @return array<int|string, string>|null Array of options for select/multi-select fields or null if not applicable
*/
public function getOptions(): ?array
{
return match ($this) {
self::STATUS => [
'To do',
'In progress',
'Done',
],
self::PRIORITY => [
'Low',
'Medium',
'High',
],
default => null,
};
}
/**
* Get color mapping for select field options
*
* 2024 sophisticated color psychology system - completely unique colors designed for
* emotional resonance and semantic meaning. Based on latest color trends including
* Digital Lavender, Mocha Mousse sophistication, and retro-futuristic aesthetics.
*
* @return array<int|string, string>|null Array of option => color mappings or null if not applicable
*/
public function getOptionColors(): ?array
{
return match ($this) {
self::STATUS => [
'To do' => '#c4b5fd', // Soft Periwinkle - Digital Lavender inspired calm potential
'In progress' => '#0A80EA', // Professional Blue - Clear active progress state
'Done' => '#2A9764', // Success Green - Confident completion achievement
],
self::PRIORITY => [
'Low' => '#94a3b8', // Sage Whisper - Natural earth tone, subtle presence
'Medium' => '#d4a574', // Burnished Gold - Mocha Mousse warmth & confidence
'High' => '#dc2626', // Crimson Velvet - Sophisticated urgent co
gitextract_xr43z_zf/ ├── .dockerignore ├── .editorconfig ├── .gitattributes ├── .githooks/ │ └── pre-commit ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── 1-bug_report.yml │ │ └── config.yml │ ├── copilot-instructions.md │ └── workflows/ │ ├── docker-publish.yml │ ├── filament-view-monitor-simple.yml │ └── tests.yml ├── .gitignore ├── CLAUDE.md ├── Dockerfile ├── LICENSE ├── README.md ├── TODOS.md ├── app/ │ ├── Actions/ │ │ ├── Company/ │ │ │ ├── CreateCompany.php │ │ │ ├── DeleteCompany.php │ │ │ ├── ListCompanies.php │ │ │ └── UpdateCompany.php │ │ ├── Fortify/ │ │ │ ├── CreateNewSocialUser.php │ │ │ ├── PasswordValidationRules.php │ │ │ ├── ResetUserPassword.php │ │ │ ├── UpdateUserPassword.php │ │ │ └── UpdateUserProfileInformation.php │ │ ├── Jetstream/ │ │ │ ├── AddTeamMember.php │ │ │ ├── CreateTeam.php │ │ │ ├── DeleteTeam.php │ │ │ ├── DeleteUser.php │ │ │ ├── InviteTeamMember.php │ │ │ ├── RemoveTeamMember.php │ │ │ └── UpdateTeamName.php │ │ ├── Note/ │ │ │ ├── CreateNote.php │ │ │ ├── DeleteNote.php │ │ │ ├── ListNotes.php │ │ │ └── UpdateNote.php │ │ ├── Opportunity/ │ │ │ ├── CreateOpportunity.php │ │ │ ├── DeleteOpportunity.php │ │ │ ├── ListOpportunities.php │ │ │ └── UpdateOpportunity.php │ │ ├── People/ │ │ │ ├── CreatePeople.php │ │ │ ├── DeletePeople.php │ │ │ ├── ListPeople.php │ │ │ └── UpdatePeople.php │ │ └── Task/ │ │ ├── CreateTask.php │ │ ├── DeleteTask.php │ │ ├── ListTasks.php │ │ ├── NotifyTaskAssignees.php │ │ └── UpdateTask.php │ ├── Concerns/ │ │ └── DetectsTeamInvitation.php │ ├── Console/ │ │ └── Commands/ │ │ ├── BackfillCustomFieldColorsCommand.php │ │ ├── CleanupExpiredInvitationsCommand.php │ │ ├── CreateSystemAdminCommand.php │ │ ├── GenerateSitemapCommand.php │ │ └── InstallCommand.php │ ├── Contracts/ │ │ └── User/ │ │ └── CreatesNewSocialUsers.php │ ├── Data/ │ │ └── SubscriberData.php │ ├── Enums/ │ │ ├── CreationSource.php │ │ ├── CustomFieldType.php │ │ ├── CustomFields/ │ │ │ ├── CompanyField.php │ │ │ ├── CustomFieldTrait.php │ │ │ ├── NoteField.php │ │ │ ├── OpportunityField.php │ │ │ ├── PeopleField.php │ │ │ └── TaskField.php │ │ ├── SocialiteProvider.php │ │ └── SubscriberTagEnum.php │ ├── Filament/ │ │ ├── Actions/ │ │ │ └── GenerateRecordSummaryAction.php │ │ ├── Components/ │ │ │ └── Infolists/ │ │ │ └── AvatarName.php │ │ ├── Exports/ │ │ │ ├── BaseExporter.php │ │ │ ├── CompanyExporter.php │ │ │ ├── NoteExporter.php │ │ │ ├── OpportunityExporter.php │ │ │ ├── PeopleExporter.php │ │ │ └── TaskExporter.php │ │ ├── Pages/ │ │ │ ├── AccessTokens.php │ │ │ ├── Auth/ │ │ │ │ ├── Login.php │ │ │ │ └── Register.php │ │ │ ├── CreateTeam.php │ │ │ ├── EditProfile.php │ │ │ ├── EditTeam.php │ │ │ ├── OpportunitiesBoard.php │ │ │ └── TasksBoard.php │ │ └── Resources/ │ │ ├── CompanyResource/ │ │ │ ├── Pages/ │ │ │ │ ├── ListCompanies.php │ │ │ │ └── ViewCompany.php │ │ │ └── RelationManagers/ │ │ │ ├── NotesRelationManager.php │ │ │ ├── PeopleRelationManager.php │ │ │ └── TasksRelationManager.php │ │ ├── CompanyResource.php │ │ ├── NoteResource/ │ │ │ ├── Forms/ │ │ │ │ └── NoteForm.php │ │ │ └── Pages/ │ │ │ └── ManageNotes.php │ │ ├── NoteResource.php │ │ ├── OpportunityResource/ │ │ │ ├── Forms/ │ │ │ │ └── OpportunityForm.php │ │ │ ├── Pages/ │ │ │ │ ├── ListOpportunities.php │ │ │ │ └── ViewOpportunity.php │ │ │ └── RelationManagers/ │ │ │ ├── NotesRelationManager.php │ │ │ └── TasksRelationManager.php │ │ ├── OpportunityResource.php │ │ ├── PeopleResource/ │ │ │ ├── Pages/ │ │ │ │ ├── ListPeople.php │ │ │ │ └── ViewPeople.php │ │ │ └── RelationManagers/ │ │ │ ├── NotesRelationManager.php │ │ │ └── TasksRelationManager.php │ │ ├── PeopleResource.php │ │ ├── TaskResource/ │ │ │ ├── Forms/ │ │ │ │ └── TaskForm.php │ │ │ └── Pages/ │ │ │ └── ManageTasks.php │ │ └── TaskResource.php │ ├── Health/ │ │ └── AnthropicModelCheck.php │ ├── Http/ │ │ ├── Controllers/ │ │ │ ├── AcceptTeamInvitationController.php │ │ │ ├── Api/ │ │ │ │ └── V1/ │ │ │ │ ├── CompaniesController.php │ │ │ │ ├── CustomFieldsController.php │ │ │ │ ├── NotesController.php │ │ │ │ ├── OpportunitiesController.php │ │ │ │ ├── PeopleController.php │ │ │ │ └── TasksController.php │ │ │ ├── Auth/ │ │ │ │ ├── CallbackController.php │ │ │ │ └── RedirectController.php │ │ │ ├── ContactController.php │ │ │ ├── HomeController.php │ │ │ ├── PrivacyPolicyController.php │ │ │ └── TermsOfServiceController.php │ │ ├── Middleware/ │ │ │ ├── ApplyTenantScopes.php │ │ │ ├── EnsureTokenHasAbility.php │ │ │ ├── ForceJsonResponse.php │ │ │ ├── SetApiTeamContext.php │ │ │ ├── SubdomainRootResponse.php │ │ │ └── ValidateSignature.php │ │ ├── Requests/ │ │ │ ├── Api/ │ │ │ │ └── V1/ │ │ │ │ ├── IndexCustomFieldsRequest.php │ │ │ │ ├── IndexRequest.php │ │ │ │ ├── StoreCompanyRequest.php │ │ │ │ ├── StoreNoteRequest.php │ │ │ │ ├── StoreOpportunityRequest.php │ │ │ │ ├── StorePeopleRequest.php │ │ │ │ ├── StoreTaskRequest.php │ │ │ │ ├── UpdateCompanyRequest.php │ │ │ │ ├── UpdateNoteRequest.php │ │ │ │ ├── UpdateOpportunityRequest.php │ │ │ │ ├── UpdatePeopleRequest.php │ │ │ │ └── UpdateTaskRequest.php │ │ │ └── ContactRequest.php │ │ ├── Resources/ │ │ │ └── V1/ │ │ │ ├── CompanyResource.php │ │ │ ├── Concerns/ │ │ │ │ └── FormatsCustomFields.php │ │ │ ├── CustomFieldResource.php │ │ │ ├── NoteResource.php │ │ │ ├── OpportunityResource.php │ │ │ ├── PeopleResource.php │ │ │ ├── TaskResource.php │ │ │ └── UserResource.php │ │ └── Responses/ │ │ └── LoginResponse.php │ ├── Jobs/ │ │ ├── Email/ │ │ │ ├── CreateSubscriberJob.php │ │ │ └── UpdateSubscriberJob.php │ │ └── FetchFaviconForCompany.php │ ├── Listeners/ │ │ ├── CreateTeamCustomFields.php │ │ ├── Email/ │ │ │ └── NewSubscriberListener.php │ │ └── SwitchTeam.php │ ├── Livewire/ │ │ ├── App/ │ │ │ ├── AccessTokens/ │ │ │ │ ├── CreateAccessToken.php │ │ │ │ └── ManageAccessTokens.php │ │ │ ├── Profile/ │ │ │ │ ├── DeleteAccount.php │ │ │ │ ├── LogoutOtherBrowserSessions.php │ │ │ │ ├── UpdatePassword.php │ │ │ │ └── UpdateProfileInformation.php │ │ │ └── Teams/ │ │ │ ├── AddTeamMember.php │ │ │ ├── DeleteTeam.php │ │ │ ├── PendingTeamInvitations.php │ │ │ ├── TeamMembers.php │ │ │ └── UpdateTeamName.php │ │ ├── BaseLivewireComponent.php │ │ └── UpdateProfileInformationForm.php │ ├── Mail/ │ │ └── NewContactSubmissionMail.php │ ├── Mcp/ │ │ ├── Filters/ │ │ │ ├── CustomFieldFilter.php │ │ │ └── CustomFieldSort.php │ │ ├── Prompts/ │ │ │ └── CrmOverviewPrompt.php │ │ ├── Resources/ │ │ │ ├── CompanySchemaResource.php │ │ │ ├── Concerns/ │ │ │ │ └── ResolvesEntitySchema.php │ │ │ ├── CrmSummaryResource.php │ │ │ ├── NoteSchemaResource.php │ │ │ ├── OpportunitySchemaResource.php │ │ │ ├── PeopleSchemaResource.php │ │ │ └── TaskSchemaResource.php │ │ ├── Schema/ │ │ │ └── CustomFieldFilterSchema.php │ │ ├── Servers/ │ │ │ └── RelaticleServer.php │ │ └── Tools/ │ │ ├── BaseAttachTool.php │ │ ├── BaseCreateTool.php │ │ ├── BaseDeleteTool.php │ │ ├── BaseDetachTool.php │ │ ├── BaseListTool.php │ │ ├── BaseShowTool.php │ │ ├── BaseUpdateTool.php │ │ ├── Company/ │ │ │ ├── CreateCompanyTool.php │ │ │ ├── DeleteCompanyTool.php │ │ │ ├── GetCompanyTool.php │ │ │ ├── ListCompaniesTool.php │ │ │ └── UpdateCompanyTool.php │ │ ├── Concerns/ │ │ │ ├── BuildsRelationshipResponse.php │ │ │ ├── ChecksTokenAbility.php │ │ │ └── SerializesRelatedModels.php │ │ ├── Note/ │ │ │ ├── AttachNoteToEntitiesTool.php │ │ │ ├── CreateNoteTool.php │ │ │ ├── DeleteNoteTool.php │ │ │ ├── DetachNoteFromEntitiesTool.php │ │ │ ├── GetNoteTool.php │ │ │ ├── ListNotesTool.php │ │ │ └── UpdateNoteTool.php │ │ ├── Opportunity/ │ │ │ ├── CreateOpportunityTool.php │ │ │ ├── DeleteOpportunityTool.php │ │ │ ├── GetOpportunityTool.php │ │ │ ├── ListOpportunitiesTool.php │ │ │ └── UpdateOpportunityTool.php │ │ ├── People/ │ │ │ ├── CreatePeopleTool.php │ │ │ ├── DeletePeopleTool.php │ │ │ ├── GetPeopleTool.php │ │ │ ├── ListPeopleTool.php │ │ │ └── UpdatePeopleTool.php │ │ ├── Task/ │ │ │ ├── AttachTaskToEntitiesTool.php │ │ │ ├── CreateTaskTool.php │ │ │ ├── DeleteTaskTool.php │ │ │ ├── DetachTaskFromEntitiesTool.php │ │ │ ├── GetTaskTool.php │ │ │ ├── ListTasksTool.php │ │ │ └── UpdateTaskTool.php │ │ └── WhoAmiTool.php │ ├── Models/ │ │ ├── AiSummary.php │ │ ├── Company.php │ │ ├── Concerns/ │ │ │ ├── BelongsToTeamCreator.php │ │ │ ├── HasAiSummary.php │ │ │ ├── HasCreator.php │ │ │ ├── HasNotes.php │ │ │ ├── HasProfilePhoto.php │ │ │ ├── HasTeam.php │ │ │ └── InvalidatesRelatedAiSummaries.php │ │ ├── CustomField.php │ │ ├── CustomFieldOption.php │ │ ├── CustomFieldSection.php │ │ ├── CustomFieldValue.php │ │ ├── Export.php │ │ ├── Membership.php │ │ ├── Note.php │ │ ├── Opportunity.php │ │ ├── People.php │ │ ├── PersonalAccessToken.php │ │ ├── Scopes/ │ │ │ └── TeamScope.php │ │ ├── Task.php │ │ ├── Team.php │ │ ├── TeamInvitation.php │ │ ├── User.php │ │ └── UserSocialAccount.php │ ├── Observers/ │ │ ├── CompanyObserver.php │ │ ├── NoteObserver.php │ │ ├── OpportunityObserver.php │ │ ├── PeopleObserver.php │ │ └── TaskObserver.php │ ├── Policies/ │ │ ├── CompanyPolicy.php │ │ ├── NotePolicy.php │ │ ├── OpportunityPolicy.php │ │ ├── PeoplePolicy.php │ │ ├── TaskPolicy.php │ │ └── TeamPolicy.php │ ├── Providers/ │ │ ├── AppServiceProvider.php │ │ ├── FaviconServiceProvider.php │ │ ├── Filament/ │ │ │ └── AppPanelProvider.php │ │ ├── FortifyServiceProvider.php │ │ ├── HealthServiceProvider.php │ │ ├── HorizonServiceProvider.php │ │ ├── JetstreamServiceProvider.php │ │ └── MacroServiceProvider.php │ ├── Rules/ │ │ ├── ValidCustomFields.php │ │ └── ValidTeamSlug.php │ ├── Scribe/ │ │ └── Strategies/ │ │ └── GetFromSpatieQueryBuilder.php │ ├── Services/ │ │ ├── AI/ │ │ │ ├── RecordContextBuilder.php │ │ │ └── RecordSummaryService.php │ │ ├── AvatarService.php │ │ ├── Favicon/ │ │ │ └── Drivers/ │ │ │ ├── GoogleHighResDriver.php │ │ │ └── HighQualityDriver.php │ │ └── GitHubService.php │ ├── Support/ │ │ └── CustomFieldMerger.php │ └── View/ │ └── Components/ │ └── GuestLayout.php ├── artisan ├── bootstrap/ │ ├── app.php │ ├── cache/ │ │ └── .gitignore │ └── providers.php ├── compose.dev.yml ├── compose.yml ├── composer.json ├── config/ │ ├── app.php │ ├── auth.php │ ├── avatar.php │ ├── blade-icons.php │ ├── cache.php │ ├── custom-fields.php │ ├── data.php │ ├── database.php │ ├── eloquent-sortable.php │ ├── favicon-fetcher.php │ ├── filament.php │ ├── filesystems.php │ ├── fortify.php │ ├── health.php │ ├── horizon-watcher.php │ ├── horizon.php │ ├── jetstream.php │ ├── logging.php │ ├── login-link.php │ ├── mail.php │ ├── mailcoach-sdk.php │ ├── markdown-response.php │ ├── markdown.php │ ├── media-library.php │ ├── prism.php │ ├── queue.php │ ├── relaticle.php │ ├── sanctum.php │ ├── scribe.php │ ├── sentry.php │ ├── services.php │ ├── session.php │ └── sitemap.php ├── database/ │ ├── .gitignore │ ├── factories/ │ │ ├── CompanyFactory.php │ │ ├── CustomFieldFactory.php │ │ ├── NoteFactory.php │ │ ├── OpportunityFactory.php │ │ ├── PeopleFactory.php │ │ ├── SystemAdministratorFactory.php │ │ ├── TaskFactory.php │ │ ├── TeamFactory.php │ │ ├── TeamInvitationFactory.php │ │ ├── UserFactory.php │ │ └── UserSocialAccountFactory.php │ ├── migrations/ │ │ ├── 0001_01_01_000000_create_users_table.php │ │ ├── 0001_01_01_000001_create_cache_table.php │ │ ├── 0001_01_01_000002_create_jobs_table.php │ │ ├── 2024_08_23_110718_create_teams_table.php │ │ ├── 2024_08_23_110719_create_team_user_table.php │ │ ├── 2024_08_23_110720_create_team_invitations_table.php │ │ ├── 2024_08_24_133803_create_companies_table.php │ │ ├── 2024_09_11_114549_create_tasks_table.php │ │ ├── 2024_09_22_084119_create_notes_table.php │ │ ├── 2024_09_22_091034_create_people_table.php │ │ ├── 2024_09_22_092300_create_task_user_table.php │ │ ├── 2024_09_22_110651_add_two_factor_columns_to_users_table.php │ │ ├── 2024_09_22_110718_create_personal_access_tokens_table.php │ │ ├── 2024_09_22_114735_create_opportunities_table.php │ │ ├── 2024_09_26_160649_create_user_social_accounts_table.php │ │ ├── 2024_09_26_170133_create_notifications_table.php │ │ ├── 2025_02_07_192236_create_custom_fields_table.php │ │ ├── 2025_03_15_180559_create_taskables_table.php │ │ ├── 2025_03_15_192334_create_notables_table.php │ │ ├── 2025_03_17_180206_create_media_table.php │ │ ├── 2025_04_30_143551_add_creation_source_to_entity_tables.php │ │ ├── 2025_05_08_112613_create_imports_table.php │ │ ├── 2025_05_08_112614_create_exports_table.php │ │ ├── 2025_05_08_112615_create_failed_import_rows_table.php │ │ ├── 2025_07_05_093310_update_opportunity_amount_field_type_to_currency.php │ │ ├── 2025_08_12_202409_add_settings_to_custom_field_options_table.php │ │ ├── 2025_08_25_173222_update_order_column_to_flowforge_position_for_tasks_and_opportunities.php │ │ ├── 2025_08_26_124042_create_system_administrators_table.php │ │ ├── 2025_11_30_202612_create_ai_summaries_table.php │ │ ├── 2025_12_10_191207_update_people_emails_field_type_to_email.php │ │ ├── 2025_12_11_000001_update_company_domain_name_settings.php │ │ ├── 2025_12_20_000000_migrate_to_ulid.php │ │ ├── 2025_12_27_122241_convert_order_column_to_decimal_and_regenerate_positions.php │ │ ├── 2026_01_02_152157_update_phone_number_custom_fields_type.php │ │ ├── 2026_01_12_225824_upgrade_custom_fields_to_v3.php │ │ ├── 2026_02_11_232804_add_slug_to_teams_table.php │ │ ├── 2026_02_12_222910_expand_imports_table.php │ │ ├── 2026_02_13_002721_cleanup_imports_table.php │ │ ├── 2026_02_15_214730_drop_sessions_user_id_foreign_key.php │ │ ├── 2026_02_20_212853_add_team_id_to_personal_access_tokens_table.php │ │ ├── 2026_02_25_124942_add_team_id_indexes_to_entity_tables.php │ │ ├── 2026_03_15_201741_add_custom_field_value_filtering_indexes.php │ │ └── 2026_03_18_202956_add_expires_at_to_team_invitations_table.php │ └── seeders/ │ ├── DatabaseSeeder.php │ ├── LocalSeeder.php │ └── SystemAdministratorSeeder.php ├── lang/ │ └── en/ │ ├── access-tokens.php │ ├── profile.php │ └── teams.php ├── package.json ├── packages/ │ ├── Documentation/ │ │ ├── README.md │ │ ├── config/ │ │ │ └── documentation.php │ │ ├── resources/ │ │ │ ├── css/ │ │ │ │ └── documentation.css │ │ │ ├── js/ │ │ │ │ └── documentation.js │ │ │ ├── markdown/ │ │ │ │ ├── developer-guide.md │ │ │ │ ├── getting-started.md │ │ │ │ ├── import-guide.md │ │ │ │ ├── mcp-guide.md │ │ │ │ └── self-hosting-guide.md │ │ │ └── views/ │ │ │ ├── components/ │ │ │ │ ├── card.blade.php │ │ │ │ ├── layout.blade.php │ │ │ │ └── search-form.blade.php │ │ │ ├── index.blade.php │ │ │ ├── search.blade.php │ │ │ └── show.blade.php │ │ ├── routes/ │ │ │ └── web.php │ │ └── src/ │ │ ├── Components/ │ │ │ └── Card.php │ │ ├── Data/ │ │ │ ├── DocumentData.php │ │ │ ├── DocumentSearchRequest.php │ │ │ └── DocumentSearchResultData.php │ │ ├── DocumentationServiceProvider.php │ │ ├── Http/ │ │ │ └── Controllers/ │ │ │ └── DocumentationController.php │ │ └── Services/ │ │ └── DocumentationService.php │ ├── ImportWizard/ │ │ ├── config/ │ │ │ └── import-wizard.php │ │ ├── resources/ │ │ │ ├── lang/ │ │ │ │ └── en/ │ │ │ │ └── validation.php │ │ │ └── views/ │ │ │ ├── components/ │ │ │ │ ├── field-select.blade.php │ │ │ │ ├── multi-value-input.blade.php │ │ │ │ ├── select-menu.blade.php │ │ │ │ └── value-row-actions.blade.php │ │ │ ├── filament/ │ │ │ │ └── pages/ │ │ │ │ ├── import-history.blade.php │ │ │ │ └── import-page.blade.php │ │ │ └── livewire/ │ │ │ ├── import-wizard.blade.php │ │ │ ├── partials/ │ │ │ │ └── step-indicator.blade.php │ │ │ └── steps/ │ │ │ ├── mapping-step.blade.php │ │ │ ├── partials/ │ │ │ │ ├── value-row-choice.blade.php │ │ │ │ ├── value-row-date.blade.php │ │ │ │ ├── value-row-multi-value.blade.php │ │ │ │ ├── value-row-number.blade.php │ │ │ │ ├── value-row-skipped.blade.php │ │ │ │ └── value-row-text.blade.php │ │ │ ├── preview-step.blade.php │ │ │ ├── review-step.blade.php │ │ │ └── upload-step.blade.php │ │ ├── routes/ │ │ │ └── web.php │ │ └── src/ │ │ ├── Commands/ │ │ │ └── CleanupImportsCommand.php │ │ ├── Data/ │ │ │ ├── ColumnData.php │ │ │ ├── EntityLink.php │ │ │ ├── ImportField.php │ │ │ ├── ImportFieldCollection.php │ │ │ ├── InferenceResult.php │ │ │ ├── MatchableField.php │ │ │ └── RelationshipMatch.php │ │ ├── Enums/ │ │ │ ├── DateFormat.php │ │ │ ├── EntityLinkSource.php │ │ │ ├── EntityLinkStorage.php │ │ │ ├── ImportEntityType.php │ │ │ ├── ImportStatus.php │ │ │ ├── MatchBehavior.php │ │ │ ├── NumberFormat.php │ │ │ ├── ReviewFilter.php │ │ │ ├── RowMatchAction.php │ │ │ ├── SortDirection.php │ │ │ └── SortField.php │ │ ├── Filament/ │ │ │ └── Pages/ │ │ │ ├── ImportCompanies.php │ │ │ ├── ImportHistory.php │ │ │ ├── ImportNotes.php │ │ │ ├── ImportOpportunities.php │ │ │ ├── ImportPage.php │ │ │ ├── ImportPeople.php │ │ │ └── ImportTasks.php │ │ ├── Http/ │ │ │ └── Controllers/ │ │ │ └── DownloadFailedRowsController.php │ │ ├── ImportWizardNewServiceProvider.php │ │ ├── Importers/ │ │ │ ├── BaseImporter.php │ │ │ ├── CompanyImporter.php │ │ │ ├── Contracts/ │ │ │ │ └── ImporterContract.php │ │ │ ├── NoteImporter.php │ │ │ ├── OpportunityImporter.php │ │ │ ├── PeopleImporter.php │ │ │ └── TaskImporter.php │ │ ├── Jobs/ │ │ │ ├── ExecuteImportJob.php │ │ │ ├── ResolveMatchesJob.php │ │ │ └── ValidateColumnJob.php │ │ ├── Livewire/ │ │ │ ├── Concerns/ │ │ │ │ └── WithImportStore.php │ │ │ ├── ImportWizard.php │ │ │ └── Steps/ │ │ │ ├── MappingStep.php │ │ │ ├── PreviewStep.php │ │ │ ├── ReviewStep.php │ │ │ └── UploadStep.php │ │ ├── Models/ │ │ │ ├── FailedImportRow.php │ │ │ └── Import.php │ │ ├── Rules/ │ │ │ ├── ImportChoiceRule.php │ │ │ ├── ImportDateRule.php │ │ │ └── ImportNumberRule.php │ │ ├── Store/ │ │ │ ├── ImportRow.php │ │ │ └── ImportStore.php │ │ └── Support/ │ │ ├── DataTypeInferencer.php │ │ ├── EntityLinkResolver.php │ │ ├── EntityLinkStorage/ │ │ │ ├── CustomFieldValueStorage.php │ │ │ ├── EntityLinkStorageInterface.php │ │ │ ├── ForeignKeyStorage.php │ │ │ └── MorphToManyStorage.php │ │ ├── EntityLinkValidator.php │ │ ├── MatchResolver.php │ │ └── Validation/ │ │ ├── ColumnValidator.php │ │ └── ValidationError.php │ ├── OnboardSeed/ │ │ ├── README.md │ │ ├── resources/ │ │ │ ├── fixtures/ │ │ │ │ ├── companies/ │ │ │ │ │ ├── airbnb.yaml │ │ │ │ │ ├── apple.yaml │ │ │ │ │ ├── figma.yaml │ │ │ │ │ └── notion.yaml │ │ │ │ ├── notes/ │ │ │ │ │ ├── airbnb_note.yaml │ │ │ │ │ ├── apple_note.yaml │ │ │ │ │ ├── dylan_note.yaml │ │ │ │ │ ├── figma_note.yaml │ │ │ │ │ └── notion_note.yaml │ │ │ │ ├── opportunities/ │ │ │ │ │ ├── airbnb_analytics.yaml │ │ │ │ │ ├── apple_partnership.yaml │ │ │ │ │ ├── figma_enterprise.yaml │ │ │ │ │ └── notion_integration.yaml │ │ │ │ ├── people/ │ │ │ │ │ ├── brian.yaml │ │ │ │ │ ├── dylan.yaml │ │ │ │ │ ├── ivan.yaml │ │ │ │ │ └── tim.yaml │ │ │ │ └── tasks/ │ │ │ │ ├── brian_call.yaml │ │ │ │ ├── dylan_followup.yaml │ │ │ │ ├── ivan_meeting.yaml │ │ │ │ └── tim_proposal.yaml │ │ │ └── templates/ │ │ │ └── entity_template.yaml │ │ └── src/ │ │ ├── Contracts/ │ │ │ └── ModelSeederInterface.php │ │ ├── ModelSeeders/ │ │ │ ├── CompanySeeder.php │ │ │ ├── NoteSeeder.php │ │ │ ├── OpportunitySeeder.php │ │ │ ├── PeopleSeeder.php │ │ │ └── TaskSeeder.php │ │ ├── OnboardSeedManager.php │ │ ├── OnboardSeeder.php │ │ └── Support/ │ │ ├── BaseModelSeeder.php │ │ ├── BulkCustomFieldValueWriter.php │ │ ├── FixtureLoader.php │ │ └── FixtureRegistry.php │ └── SystemAdmin/ │ └── src/ │ ├── Enums/ │ │ └── SystemAdministratorRole.php │ ├── Filament/ │ │ ├── Exports/ │ │ │ └── CompanyExporter.php │ │ ├── Pages/ │ │ │ ├── Dashboard.php │ │ │ └── EngagementDashboard.php │ │ ├── Resources/ │ │ │ ├── CompanyResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── CreateCompany.php │ │ │ │ ├── EditCompany.php │ │ │ │ ├── ListCompanies.php │ │ │ │ └── ViewCompany.php │ │ │ ├── CompanyResource.php │ │ │ ├── ImportResource/ │ │ │ │ ├── Pages/ │ │ │ │ │ ├── ListImports.php │ │ │ │ │ └── ViewImport.php │ │ │ │ └── RelationManagers/ │ │ │ │ └── FailedRowsRelationManager.php │ │ │ ├── ImportResource.php │ │ │ ├── NoteResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── CreateNote.php │ │ │ │ ├── EditNote.php │ │ │ │ ├── ListNotes.php │ │ │ │ └── ViewNote.php │ │ │ ├── NoteResource.php │ │ │ ├── OpportunityResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── CreateOpportunity.php │ │ │ │ ├── EditOpportunity.php │ │ │ │ ├── ListOpportunities.php │ │ │ │ └── ViewOpportunity.php │ │ │ ├── OpportunityResource.php │ │ │ ├── PeopleResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── CreatePeople.php │ │ │ │ ├── EditPeople.php │ │ │ │ ├── ListPeople.php │ │ │ │ └── ViewPeople.php │ │ │ ├── PeopleResource.php │ │ │ ├── SystemAdministrators/ │ │ │ │ ├── Pages/ │ │ │ │ │ ├── CreateSystemAdministrator.php │ │ │ │ │ ├── EditSystemAdministrator.php │ │ │ │ │ ├── ListSystemAdministrators.php │ │ │ │ │ └── ViewSystemAdministrator.php │ │ │ │ ├── Schemas/ │ │ │ │ │ ├── SystemAdministratorForm.php │ │ │ │ │ └── SystemAdministratorInfolist.php │ │ │ │ ├── SystemAdministratorResource.php │ │ │ │ └── Tables/ │ │ │ │ └── SystemAdministratorsTable.php │ │ │ ├── TaskResource/ │ │ │ │ └── Pages/ │ │ │ │ ├── CreateTask.php │ │ │ │ ├── EditTask.php │ │ │ │ ├── ListTasks.php │ │ │ │ └── ViewTask.php │ │ │ ├── TaskResource.php │ │ │ ├── TeamResource/ │ │ │ │ ├── Pages/ │ │ │ │ │ ├── CreateTeam.php │ │ │ │ │ ├── EditTeam.php │ │ │ │ │ ├── ListTeams.php │ │ │ │ │ └── ViewTeam.php │ │ │ │ └── RelationManagers/ │ │ │ │ ├── CompaniesRelationManager.php │ │ │ │ ├── MembersRelationManager.php │ │ │ │ ├── NotesRelationManager.php │ │ │ │ ├── OpportunitiesRelationManager.php │ │ │ │ ├── PeopleRelationManager.php │ │ │ │ └── TasksRelationManager.php │ │ │ ├── TeamResource.php │ │ │ ├── UserResource/ │ │ │ │ ├── Pages/ │ │ │ │ │ ├── CreateUser.php │ │ │ │ │ ├── EditUser.php │ │ │ │ │ ├── ListUsers.php │ │ │ │ │ └── ViewUser.php │ │ │ │ └── RelationManagers/ │ │ │ │ ├── OwnedTeamsRelationManager.php │ │ │ │ └── TeamsRelationManager.php │ │ │ └── UserResource.php │ │ └── Widgets/ │ │ ├── ActivationRateWidget.php │ │ ├── Concerns/ │ │ │ └── HasPeriodComparison.php │ │ ├── PlatformGrowthStatsWidget.php │ │ ├── RecordDistributionChartWidget.php │ │ ├── SignupTrendChartWidget.php │ │ ├── TopTeamsTableWidget.php │ │ └── UserRetentionChartWidget.php │ ├── Models/ │ │ └── SystemAdministrator.php │ ├── Policies/ │ │ ├── CompanyPolicy.php │ │ ├── FailedImportRowPolicy.php │ │ ├── ImportPolicy.php │ │ ├── NotePolicy.php │ │ ├── OpportunityPolicy.php │ │ ├── PeoplePolicy.php │ │ ├── SystemAdministratorPolicy.php │ │ ├── TaskPolicy.php │ │ ├── TeamPolicy.php │ │ └── UserPolicy.php │ └── SystemAdminPanelProvider.php ├── phpstan.neon ├── phpunit.ci.xml ├── phpunit.xml ├── pint.json ├── public/ │ ├── .htaccess │ ├── css/ │ │ ├── asmit/ │ │ │ └── resized-column/ │ │ │ └── resized-column.css │ │ ├── filament/ │ │ │ ├── filament/ │ │ │ │ └── app.css │ │ │ ├── forms/ │ │ │ │ └── forms.css │ │ │ └── support/ │ │ │ └── support.css │ │ └── relaticle/ │ │ ├── custom-fields/ │ │ │ └── custom-fields.css │ │ └── flowforge/ │ │ └── flowforge.css │ ├── fonts/ │ │ └── filament/ │ │ └── filament/ │ │ └── inter/ │ │ └── index.css │ ├── index.php │ ├── js/ │ │ ├── asmit/ │ │ │ └── resized-column/ │ │ │ └── resized-column.js │ │ ├── filament/ │ │ │ ├── actions/ │ │ │ │ └── actions.js │ │ │ ├── filament/ │ │ │ │ ├── app.js │ │ │ │ └── echo.js │ │ │ ├── forms/ │ │ │ │ └── components/ │ │ │ │ ├── checkbox-list.js │ │ │ │ ├── code-editor.js │ │ │ │ ├── color-picker.js │ │ │ │ ├── date-time-picker.js │ │ │ │ ├── file-upload.js │ │ │ │ ├── key-value.js │ │ │ │ ├── markdown-editor.js │ │ │ │ ├── rich-editor.js │ │ │ │ ├── select.js │ │ │ │ ├── slider.js │ │ │ │ ├── tags-input.js │ │ │ │ └── textarea.js │ │ │ ├── notifications/ │ │ │ │ └── notifications.js │ │ │ ├── schemas/ │ │ │ │ ├── components/ │ │ │ │ │ ├── actions.js │ │ │ │ │ ├── tabs.js │ │ │ │ │ └── wizard.js │ │ │ │ └── schemas.js │ │ │ ├── support/ │ │ │ │ ├── async-alpine.js │ │ │ │ └── support.js │ │ │ ├── tables/ │ │ │ │ ├── components/ │ │ │ │ │ ├── columns/ │ │ │ │ │ │ ├── checkbox.js │ │ │ │ │ │ ├── select.js │ │ │ │ │ │ ├── text-input.js │ │ │ │ │ │ └── toggle.js │ │ │ │ │ └── table.js │ │ │ │ └── tables.js │ │ │ └── widgets/ │ │ │ └── components/ │ │ │ ├── chart.js │ │ │ └── stats-overview/ │ │ │ └── stat/ │ │ │ └── chart.js │ │ └── relaticle/ │ │ └── flowforge/ │ │ ├── components/ │ │ │ └── flowforge.js │ │ └── flowforge.js │ ├── manifest.webmanifest │ ├── robots.txt │ └── site.webmanifest ├── rector.php ├── resources/ │ ├── css/ │ │ ├── app.css │ │ ├── filament/ │ │ │ ├── admin/ │ │ │ │ └── theme.css │ │ │ └── app/ │ │ │ └── theme.css │ │ ├── fonts.css │ │ └── theme.css │ ├── js/ │ │ ├── app.js │ │ └── motion.js │ ├── markdown/ │ │ ├── brand-assets.md │ │ ├── font-sources.md │ │ ├── policy.md │ │ └── terms.md │ └── views/ │ ├── api/ │ │ └── api-token-manager.blade.php │ ├── components/ │ │ ├── action-message.blade.php │ │ ├── action-section.blade.php │ │ ├── application-logo.blade.php │ │ ├── application-mark.blade.php │ │ ├── authentication-card-logo.blade.php │ │ ├── authentication-card.blade.php │ │ ├── banner.blade.php │ │ ├── brand/ │ │ │ ├── logo-lockup.blade.php │ │ │ ├── logomark.blade.php │ │ │ └── wordmark.blade.php │ │ ├── browser-sessions.blade.php │ │ ├── button.blade.php │ │ ├── checkbox.blade.php │ │ ├── confirmation-modal.blade.php │ │ ├── confirms-password.blade.php │ │ ├── danger-button.blade.php │ │ ├── dialog-modal.blade.php │ │ ├── dropdown-link.blade.php │ │ ├── dropdown.blade.php │ │ ├── form-section.blade.php │ │ ├── input-error.blade.php │ │ ├── input.blade.php │ │ ├── label.blade.php │ │ ├── layout/ │ │ │ ├── footer.blade.php │ │ │ ├── header.blade.php │ │ │ └── mobile-menu.blade.php │ │ ├── legal-document.blade.php │ │ ├── marketing/ │ │ │ ├── button.blade.php │ │ │ ├── input.blade.php │ │ │ └── textarea.blade.php │ │ ├── modal.blade.php │ │ ├── nav-link.blade.php │ │ ├── responsive-nav-link.blade.php │ │ ├── secondary-button.blade.php │ │ ├── section-border.blade.php │ │ ├── section-title.blade.php │ │ ├── switchable-team.blade.php │ │ ├── theme-switcher.blade.php │ │ ├── validation-errors.blade.php │ │ └── welcome.blade.php │ ├── contact.blade.php │ ├── emails/ │ │ └── team-invitation.blade.php │ ├── filament/ │ │ ├── actions/ │ │ │ └── ai-summary.blade.php │ │ ├── app/ │ │ │ ├── analytics.blade.php │ │ │ ├── import-preview-alpine.blade.php │ │ │ ├── import-value-reviewer-alpine.blade.php │ │ │ ├── logo-empty.blade.php │ │ │ └── logo.blade.php │ │ ├── auth/ │ │ │ └── social_login_buttons.blade.php │ │ ├── components/ │ │ │ └── infolists/ │ │ │ └── avatar-name.blade.php │ │ ├── pages/ │ │ │ ├── access-tokens.blade.php │ │ │ ├── create-team.blade.php │ │ │ ├── dashboard.blade.php │ │ │ ├── edit-profile.blade.php │ │ │ └── edit-team.blade.php │ │ └── tables/ │ │ └── columns/ │ │ ├── avatar-name-column.blade.php │ │ └── logo-name-column.blade.php │ ├── home/ │ │ ├── index.blade.php │ │ └── partials/ │ │ ├── community.blade.php │ │ ├── faq.blade.php │ │ ├── features.blade.php │ │ ├── hero-agent-preview.blade.php │ │ ├── hero.blade.php │ │ └── start-building.blade.php │ ├── layouts/ │ │ └── guest.blade.php │ ├── livewire/ │ │ └── app/ │ │ ├── access-tokens/ │ │ │ ├── create-access-token.blade.php │ │ │ └── manage-access-tokens.blade.php │ │ ├── profile/ │ │ │ ├── delete-account.blade.php │ │ │ ├── logout-other-browser-sessions.blade.php │ │ │ ├── update-password.blade.php │ │ │ └── update-profile-information.blade.php │ │ └── teams/ │ │ ├── add-team-member.blade.php │ │ ├── delete-team.blade.php │ │ ├── pending-team-invitations.blade.php │ │ ├── team-members.blade.php │ │ └── update-team-name.blade.php │ ├── mail/ │ │ └── new-contact-submission.blade.php │ ├── policy.blade.php │ ├── pricing.blade.php │ ├── profile/ │ │ ├── delete-user-form.blade.php │ │ ├── logout-other-browser-sessions-form.blade.php │ │ ├── two-factor-authentication-form.blade.php │ │ ├── update-password-form.blade.php │ │ └── update-profile-information-form.blade.php │ ├── teams/ │ │ ├── create-team-form.blade.php │ │ ├── delete-team-form.blade.php │ │ ├── invitation-expired.blade.php │ │ ├── team-member-manager.blade.php │ │ └── update-team-name-form.blade.php │ ├── terms.blade.php │ └── vendor/ │ ├── filament-panels/ │ │ └── components/ │ │ └── layout/ │ │ └── index.blade.php │ ├── mail/ │ │ ├── html/ │ │ │ ├── button.blade.php │ │ │ ├── footer.blade.php │ │ │ ├── header.blade.php │ │ │ ├── layout.blade.php │ │ │ ├── message.blade.php │ │ │ ├── panel.blade.php │ │ │ ├── subcopy.blade.php │ │ │ ├── table.blade.php │ │ │ └── themes/ │ │ │ └── default.css │ │ └── text/ │ │ ├── button.blade.php │ │ ├── footer.blade.php │ │ ├── header.blade.php │ │ ├── layout.blade.php │ │ ├── message.blade.php │ │ ├── panel.blade.php │ │ ├── subcopy.blade.php │ │ └── table.blade.php │ └── scribe/ │ ├── components/ │ │ ├── badges/ │ │ │ ├── auth.blade.php │ │ │ ├── base.blade.php │ │ │ ├── deprecated.blade.php │ │ │ └── http-method.blade.php │ │ ├── field-details.blade.php │ │ └── nested-fields.blade.php │ ├── external/ │ │ ├── elements.blade.php │ │ ├── rapidoc.blade.php │ │ └── scalar.blade.php │ ├── markdown/ │ │ ├── auth.blade.php │ │ └── intro.blade.php │ ├── partials/ │ │ └── example-requests/ │ │ ├── bash.md.blade.php │ │ ├── javascript.md.blade.php │ │ ├── php.md.blade.php │ │ └── python.md.blade.php │ └── themes/ │ ├── default/ │ │ ├── endpoint.blade.php │ │ ├── groups.blade.php │ │ ├── index.blade.php │ │ └── sidebar.blade.php │ └── elements/ │ ├── components/ │ │ ├── field-details.blade.php │ │ └── nested-fields.blade.php │ ├── endpoint.blade.php │ ├── groups.blade.php │ ├── index.blade.php │ ├── sidebar.blade.php │ └── try_it_out.blade.php ├── routes/ │ ├── ai.php │ ├── api.php │ └── web.php ├── storage/ │ ├── app/ │ │ └── .gitignore │ ├── clockwork/ │ │ └── .gitignore │ ├── framework/ │ │ ├── .gitignore │ │ ├── cache/ │ │ │ └── .gitignore │ │ ├── sessions/ │ │ │ └── .gitignore │ │ ├── testing/ │ │ │ └── .gitignore │ │ └── views/ │ │ └── .gitignore │ ├── logs/ │ │ └── .gitignore │ └── pail/ │ └── .gitignore ├── stubs/ │ └── Mailcoach.stub ├── tests/ │ ├── Arch/ │ │ └── ArchTest.php │ ├── Browser/ │ │ ├── Auth/ │ │ │ ├── LoginBrowserTest.php │ │ │ └── PasswordResetBrowserTest.php │ │ ├── CRM/ │ │ │ └── CompanyBrowserTest.php │ │ ├── ImportWizard/ │ │ │ └── ImportWizardBrowserTest.php │ │ ├── Onboarding/ │ │ │ └── OnboardingBrowserTest.php │ │ ├── SmokeBrowserTest.php │ │ └── Teams/ │ │ └── TeamBrowserTest.php │ ├── Feature/ │ │ ├── AI/ │ │ │ └── RecordSummaryServiceTest.php │ │ ├── AccessTokens/ │ │ │ ├── AccessTokenPermissionsTest.php │ │ │ ├── CreateAccessTokenTest.php │ │ │ └── DeleteAccessTokenTest.php │ │ ├── Api/ │ │ │ └── V1/ │ │ │ ├── ApiMiddlewareTest.php │ │ │ ├── ApiTeamScopingTest.php │ │ │ ├── CompaniesApiTest.php │ │ │ ├── CustomFieldsApiTest.php │ │ │ ├── NotesApiTest.php │ │ │ ├── OpportunitiesApiTest.php │ │ │ ├── PeopleApiTest.php │ │ │ ├── TasksApiTest.php │ │ │ ├── TokenAbilitiesApiTest.php │ │ │ └── UserEndpointTest.php │ │ ├── Auth/ │ │ │ ├── AuthenticationTest.php │ │ │ ├── PasswordResetTest.php │ │ │ ├── RegistrationTest.php │ │ │ ├── SocialiteLoginTest.php │ │ │ ├── TwoFactorAuthenticationSettingsTest.php │ │ │ └── UserModelTest.php │ │ ├── CRM/ │ │ │ └── CompanyModelTest.php │ │ ├── Commands/ │ │ │ └── InstallCommandTest.php │ │ ├── ContactFormTest.php │ │ ├── Filament/ │ │ │ └── App/ │ │ │ ├── Exports/ │ │ │ │ ├── CompanyExporterTest.php │ │ │ │ ├── NoteExporterTest.php │ │ │ │ ├── OpportunityExporterTest.php │ │ │ │ ├── PeopleExporterTest.php │ │ │ │ └── TaskExporterTest.php │ │ │ ├── Pages/ │ │ │ │ ├── OpportunitiesBoardTest.php │ │ │ │ └── TasksBoardTest.php │ │ │ └── Resources/ │ │ │ ├── CompanyResourceTest.php │ │ │ ├── NoteResourceTest.php │ │ │ ├── OpportunityResourceTest.php │ │ │ ├── PeopleResourceTest.php │ │ │ └── TaskResourceTest.php │ │ ├── HealthChecks/ │ │ │ └── HealthServiceProviderTest.php │ │ ├── ImportWizard/ │ │ │ ├── Commands/ │ │ │ │ └── CleanupImportsCommandTest.php │ │ │ ├── Components/ │ │ │ │ ├── MultiValueInputTest.php │ │ │ │ └── SelectMenuInvalidOptionsTest.php │ │ │ ├── Jobs/ │ │ │ │ ├── ExecuteImportJobTest.php │ │ │ │ ├── ResolveMatchesJobTest.php │ │ │ │ └── ValidateColumnJobTest.php │ │ │ ├── Livewire/ │ │ │ │ ├── ImportWizardTest.php │ │ │ │ ├── MappingStepTest.php │ │ │ │ ├── PreviewStepTest.php │ │ │ │ ├── ReviewStepTest.php │ │ │ │ └── UploadStepTest.php │ │ │ ├── Support/ │ │ │ │ └── EntityLinkResolverTest.php │ │ │ └── Validation/ │ │ │ ├── ColumnValidatorTest.php │ │ │ └── EntityLinkValidatorTest.php │ │ ├── Mcp/ │ │ │ ├── CompanyToolsTest.php │ │ │ ├── CrmSummaryResourceTest.php │ │ │ ├── Filters/ │ │ │ │ ├── CustomFieldFilterTest.php │ │ │ │ └── CustomFieldSortTest.php │ │ │ ├── McpToolFeaturesTest.php │ │ │ ├── NoteToolsTest.php │ │ │ ├── OpportunityToolsTest.php │ │ │ ├── PeopleToolsTest.php │ │ │ ├── RelaticleServerTest.php │ │ │ ├── SchemaResourcesTest.php │ │ │ ├── TaskToolsTest.php │ │ │ ├── TokenAbilitiesMcpTest.php │ │ │ └── WhoAmiToolTest.php │ │ ├── Migrations/ │ │ │ └── UlidMigrationTest.php │ │ ├── Models/ │ │ │ └── Scopes/ │ │ │ └── TeamScopeTest.php │ │ ├── Onboarding/ │ │ │ └── CreateTeamOnboardingTest.php │ │ ├── PersonalAccessToken/ │ │ │ └── TeamIdImmutabilityTest.php │ │ ├── Profile/ │ │ │ ├── AvatarServiceTest.php │ │ │ ├── BrowserSessionsTest.php │ │ │ ├── DeleteAccountTest.php │ │ │ ├── GitHubServiceTest.php │ │ │ ├── UpdatePasswordTest.php │ │ │ └── UpdateUserProfileInformationTest.php │ │ ├── Public/ │ │ │ └── PublicPagesTest.php │ │ ├── Routing/ │ │ │ ├── AppPanelRoutingTest.php │ │ │ └── SubdomainRoutingTest.php │ │ ├── SystemAdmin/ │ │ │ ├── ActivationRateWidgetTest.php │ │ │ ├── SystemAdminResourceTest.php │ │ │ ├── SystemAdminSecurityTest.php │ │ │ └── UserRetentionChartWidgetTest.php │ │ ├── Teams/ │ │ │ ├── AcceptTeamInvitationTest.php │ │ │ ├── CreateTeamTest.php │ │ │ ├── DeleteTeamTest.php │ │ │ ├── InvitationUxTest.php │ │ │ ├── InviteTeamMemberTest.php │ │ │ ├── LeaveTeamTest.php │ │ │ ├── ManageTeamInvitationsTest.php │ │ │ ├── RemoveTeamMemberTest.php │ │ │ ├── TeamModelTest.php │ │ │ ├── UpdateTeamMemberRoleTest.php │ │ │ └── UpdateTeamNameTest.php │ │ └── ValidTeamSlugTest.php │ ├── Pest.php │ ├── Smoke/ │ │ └── RouteTest.php │ ├── TestCase.php │ └── fixtures/ │ └── imports/ │ ├── companies.csv │ ├── companies.xlsx │ └── people.xlsx └── vite.config.js
Showing preview only (1,047K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (10898 symbols across 520 files)
FILE: app/Actions/Company/CreateCompany.php
class CreateCompany (line 13) | final readonly class CreateCompany
method execute (line 18) | public function execute(User $user, array $data, CreationSource $sourc...
FILE: app/Actions/Company/DeleteCompany.php
class DeleteCompany (line 10) | final readonly class DeleteCompany
method execute (line 12) | public function execute(User $user, Company $company): void
FILE: app/Actions/Company/ListCompanies.php
class ListCompanies (line 18) | final readonly class ListCompanies
method execute (line 24) | public function execute(
FILE: app/Actions/Company/UpdateCompany.php
class UpdateCompany (line 13) | final readonly class UpdateCompany
method execute (line 18) | public function execute(User $user, Company $company, array $data): Co...
FILE: app/Actions/Fortify/CreateNewSocialUser.php
class CreateNewSocialUser (line 15) | final readonly class CreateNewSocialUser implements CreatesNewSocialUsers
method create (line 24) | public function create(array $input): User
FILE: app/Actions/Fortify/PasswordValidationRules.php
type PasswordValidationRules (line 10) | trait PasswordValidationRules
method passwordRules (line 17) | protected function passwordRules(): array
FILE: app/Actions/Fortify/ResetUserPassword.php
class ResetUserPassword (line 12) | final readonly class ResetUserPassword implements ResetsUserPasswords
method reset (line 21) | public function reset(User $user, array $input): void
FILE: app/Actions/Fortify/UpdateUserPassword.php
class UpdateUserPassword (line 12) | final readonly class UpdateUserPassword implements UpdatesUserPasswords
method update (line 21) | public function update(User $user, array $input): void
FILE: app/Actions/Fortify/UpdateUserProfileInformation.php
class UpdateUserProfileInformation (line 12) | final readonly class UpdateUserProfileInformation implements UpdatesUser...
method update (line 19) | public function update(User $user, array $input): void
method updateVerifiedUser (line 50) | private function updateVerifiedUser(User $user, array $input): void
FILE: app/Actions/Jetstream/AddTeamMember.php
class AddTeamMember (line 19) | final readonly class AddTeamMember implements AddsTeamMembers
method add (line 24) | public function add(User $user, Team $team, string $email, ?string $ro...
method validate (line 44) | private function validate(Team $team, string $email, ?string $role): void
method rules (line 61) | private function rules(): array
method ensureUserIsNotAlreadyOnTeam (line 72) | private function ensureUserIsNotAlreadyOnTeam(Team $team, string $emai...
FILE: app/Actions/Jetstream/CreateTeam.php
class CreateTeam (line 16) | final readonly class CreateTeam implements CreatesTeams
method create (line 23) | public function create(User $user, array $input): Team
FILE: app/Actions/Jetstream/DeleteTeam.php
class DeleteTeam (line 10) | final readonly class DeleteTeam implements DeletesTeams
method delete (line 15) | public function delete(Team $team): void
FILE: app/Actions/Jetstream/DeleteUser.php
class DeleteUser (line 14) | final readonly class DeleteUser implements DeletesUsers
method __construct (line 19) | public function __construct(private DeletesTeams $deletesTeams) {}
method delete (line 24) | public function delete(User $user): void
method deleteTeams (line 37) | private function deleteTeams(User $user): void
FILE: app/Actions/Jetstream/InviteTeamMember.php
class InviteTeamMember (line 23) | final readonly class InviteTeamMember implements InvitesTeamMembers
method invite (line 28) | public function invite(User $user, Team $team, string $email, ?string ...
method validate (line 51) | private function validate(Team $team, string $email, ?string $role): void
method rules (line 68) | private function rules(Team $team): array
method ensureUserIsNotAlreadyOnTeam (line 84) | private function ensureUserIsNotAlreadyOnTeam(Team $team, string $emai...
FILE: app/Actions/Jetstream/RemoveTeamMember.php
class RemoveTeamMember (line 15) | final readonly class RemoveTeamMember implements RemovesTeamMembers
method remove (line 20) | public function remove(User $user, Team $team, User $teamMember): void
method authorize (line 34) | private function authorize(User $user, Team $team, User $teamMember): ...
method ensureUserDoesNotOwnTeam (line 43) | private function ensureUserDoesNotOwnTeam(User $teamMember, Team $team...
FILE: app/Actions/Jetstream/UpdateTeamName.php
class UpdateTeamName (line 14) | final readonly class UpdateTeamName implements UpdatesTeamNames
method update (line 21) | public function update(User $user, Team $team, array $input): void
FILE: app/Actions/Note/CreateNote.php
class CreateNote (line 13) | final readonly class CreateNote
method execute (line 18) | public function execute(User $user, array $data, CreationSource $sourc...
FILE: app/Actions/Note/DeleteNote.php
class DeleteNote (line 10) | final readonly class DeleteNote
method execute (line 12) | public function execute(User $user, Note $note): void
FILE: app/Actions/Note/ListNotes.php
class ListNotes (line 18) | final readonly class ListNotes
method execute (line 24) | public function execute(
FILE: app/Actions/Note/UpdateNote.php
class UpdateNote (line 13) | final readonly class UpdateNote
method execute (line 18) | public function execute(User $user, Note $note, array $data): Note
FILE: app/Actions/Opportunity/CreateOpportunity.php
class CreateOpportunity (line 13) | final readonly class CreateOpportunity
method execute (line 18) | public function execute(User $user, array $data, CreationSource $sourc...
FILE: app/Actions/Opportunity/DeleteOpportunity.php
class DeleteOpportunity (line 10) | final readonly class DeleteOpportunity
method execute (line 12) | public function execute(User $user, Opportunity $opportunity): void
FILE: app/Actions/Opportunity/ListOpportunities.php
class ListOpportunities (line 18) | final readonly class ListOpportunities
method execute (line 24) | public function execute(
FILE: app/Actions/Opportunity/UpdateOpportunity.php
class UpdateOpportunity (line 13) | final readonly class UpdateOpportunity
method execute (line 18) | public function execute(User $user, Opportunity $opportunity, array $d...
FILE: app/Actions/People/CreatePeople.php
class CreatePeople (line 13) | final readonly class CreatePeople
method execute (line 18) | public function execute(User $user, array $data, CreationSource $sourc...
FILE: app/Actions/People/DeletePeople.php
class DeletePeople (line 10) | final readonly class DeletePeople
method execute (line 12) | public function execute(User $user, People $people): void
FILE: app/Actions/People/ListPeople.php
class ListPeople (line 18) | final readonly class ListPeople
method execute (line 24) | public function execute(
FILE: app/Actions/People/UpdatePeople.php
class UpdatePeople (line 13) | final readonly class UpdatePeople
method execute (line 18) | public function execute(User $user, People $people, array $data): People
FILE: app/Actions/Task/CreateTask.php
class CreateTask (line 13) | final readonly class CreateTask
method __construct (line 15) | public function __construct(
method execute (line 22) | public function execute(User $user, array $data, CreationSource $sourc...
FILE: app/Actions/Task/DeleteTask.php
class DeleteTask (line 10) | final readonly class DeleteTask
method execute (line 12) | public function execute(User $user, Task $task): void
FILE: app/Actions/Task/ListTasks.php
class ListTasks (line 19) | final readonly class ListTasks
method execute (line 25) | public function execute(
FILE: app/Actions/Task/NotifyTaskAssignees.php
class NotifyTaskAssignees (line 14) | final readonly class NotifyTaskAssignees
method execute (line 19) | public function execute(Task $task, array $previousAssigneeIds = []): ...
method resolveTaskUrl (line 54) | private function resolveTaskUrl(Task $task): string
FILE: app/Actions/Task/UpdateTask.php
class UpdateTask (line 13) | final readonly class UpdateTask
method __construct (line 15) | public function __construct(
method execute (line 24) | public function execute(User $user, Task $task, array $data): Task
FILE: app/Concerns/DetectsTeamInvitation.php
type DetectsTeamInvitation (line 11) | trait DetectsTeamInvitation
method getTeamInvitationFromSession (line 13) | protected function getTeamInvitationFromSession(): ?TeamInvitation
method getTeamInvitationSubheading (line 39) | protected function getTeamInvitationSubheading(): ?Htmlable
method getInvitationContentHtml (line 54) | protected function getInvitationContentHtml(): string
FILE: app/Console/Commands/BackfillCustomFieldColorsCommand.php
class BackfillCustomFieldColorsCommand (line 16) | final class BackfillCustomFieldColorsCommand extends Command
method handle (line 37) | public function handle(): int
method getColorMappingForField (line 137) | private function getColorMappingForField(CustomField $field): ?array
FILE: app/Console/Commands/CleanupExpiredInvitationsCommand.php
class CleanupExpiredInvitationsCommand (line 11) | final class CleanupExpiredInvitationsCommand extends Command
method handle (line 24) | public function handle(): void
FILE: app/Console/Commands/CreateSystemAdminCommand.php
class CreateSystemAdminCommand (line 16) | final class CreateSystemAdminCommand extends Command
method handle (line 38) | public function handle(): int
FILE: app/Console/Commands/GenerateSitemapCommand.php
class GenerateSitemapCommand (line 10) | final class GenerateSitemapCommand extends Command
method handle (line 29) | public function handle(): void
FILE: app/Console/Commands/InstallCommand.php
class InstallCommand (line 21) | final class InstallCommand extends Command
method handle (line 29) | public function handle(): int
method displayWelcome (line 42) | private function displayWelcome(): void
method shouldProceed (line 52) | private function shouldProceed(): bool
method isAlreadyInstalled (line 67) | private function isAlreadyInstalled(): bool
method getConfiguration (line 75) | private function getConfiguration(): array
method runInstallation (line 109) | private function runInstallation(array $config): int
method checkSystemRequirements (line 167) | private function checkSystemRequirements(): bool
method commandExists (line 202) | private function commandExists(string $command): bool
method setupEnvironment (line 208) | private function setupEnvironment(array $config): bool
method configureDatabaseConnection (line 227) | private function configureDatabaseConnection(string $type): bool
method installDependencies (line 264) | private function installDependencies(): bool
method setupDatabase (line 285) | private function setupDatabase(): bool
method buildAssets (line 299) | private function buildAssets(): bool
method setupStorage (line 313) | private function setupStorage(): bool
method seedDemoData (line 327) | private function seedDemoData(): bool
method createSystemAdministrator (line 347) | private function createSystemAdministrator(): bool
method displaySuccessMessage (line 414) | private function displaySuccessMessage(array $config): void
method envPath (line 456) | private function envPath(): string
FILE: app/Contracts/User/CreatesNewSocialUsers.php
type CreatesNewSocialUsers (line 9) | interface CreatesNewSocialUsers
method create (line 16) | public function create(array $input): User;
FILE: app/Data/SubscriberData.php
class SubscriberData (line 9) | final class SubscriberData extends Data
method __construct (line 11) | public function __construct(
FILE: app/Enums/CreationSource.php
method getColor (line 48) | public function getColor(): string
method getLabel (line 59) | public function getLabel(): string
FILE: app/Enums/CustomFields/CompanyField.php
method getDisplayName (line 28) | public function getDisplayName(): string
method getFieldType (line 37) | public function getFieldType(): string
method isSystemDefined (line 45) | public function isSystemDefined(): bool
method isListToggleableHidden (line 53) | public function isListToggleableHidden(): bool
method getDescription (line 61) | public function getDescription(): string
method allowsMultipleValues (line 70) | public function allowsMultipleValues(): bool
method isUniquePerEntityType (line 78) | public function isUniquePerEntityType(): bool
FILE: app/Enums/CustomFields/CustomFieldTrait.php
type CustomFieldTrait (line 16) | trait CustomFieldTrait
method getDisplayName (line 23) | public function getDisplayName(): string
method getFieldType (line 33) | abstract public function getFieldType(): string;
method isSystemDefined (line 42) | public function isSystemDefined(): bool
method isListToggleableHidden (line 54) | public function isListToggleableHidden(): bool
method getWidth (line 64) | public function getWidth(): CustomFieldWidth
method getOptions (line 74) | public function getOptions(): ?array
method getDescription (line 84) | public function getDescription(): ?string
method getOptionColors (line 94) | public function getOptionColors(): ?array
method hasColorOptions (line 104) | public function hasColorOptions(): bool
method allowsMultipleValues (line 114) | public function allowsMultipleValues(): bool
method getMaxValues (line 124) | public function getMaxValues(): int
method isUniquePerEntityType (line 134) | public function isUniquePerEntityType(): bool
method getConfiguration (line 155) | public function getConfiguration(): array
FILE: app/Enums/CustomFields/NoteField.php
method getFieldType (line 18) | public function getFieldType(): string
method getDisplayName (line 25) | public function getDisplayName(): string
method isListToggleableHidden (line 32) | public function isListToggleableHidden(): bool
FILE: app/Enums/CustomFields/OpportunityField.php
method getOptions (line 20) | public function getOptions(): ?array
method getFieldType (line 39) | public function getFieldType(): string
method getDisplayName (line 48) | public function getDisplayName(): string
method isListToggleableHidden (line 57) | public function isListToggleableHidden(): bool
method getOptionColors (line 72) | public function getOptionColors(): ?array
FILE: app/Enums/CustomFields/PeopleField.php
method getFieldType (line 21) | public function getFieldType(): string
method getDisplayName (line 31) | public function getDisplayName(): string
method isListToggleableHidden (line 41) | public function isListToggleableHidden(): bool
method isSystemDefined (line 49) | public function isSystemDefined(): bool
method allowsMultipleValues (line 57) | public function allowsMultipleValues(): bool
method isUniquePerEntityType (line 65) | public function isUniquePerEntityType(): bool
FILE: app/Enums/CustomFields/TaskField.php
method getDisplayName (line 39) | public function getDisplayName(): string
method getFieldType (line 54) | public function getFieldType(): string
method isSystemDefined (line 68) | public function isSystemDefined(): bool
method isListToggleableHidden (line 81) | public function isListToggleableHidden(): bool
method getWidth (line 94) | public function getWidth(): CustomFieldWidth
method getOptions (line 107) | public function getOptions(): ?array
method getOptionColors (line 133) | public function getOptionColors(): ?array
method getDescription (line 155) | public function getDescription(): string
FILE: app/Filament/Actions/GenerateRecordSummaryAction.php
class GenerateRecordSummaryAction (line 16) | final class GenerateRecordSummaryAction extends Action
method getDefaultName (line 18) | public static function getDefaultName(): string
method setUp (line 23) | protected function setUp(): void
method makeRegenerateAction (line 41) | private function makeRegenerateAction(): Action
method makeCopyAction (line 50) | private function makeCopyAction(): Action
method getSummaryView (line 66) | private function getSummaryView(Model $record): View
method getCachedSummary (line 73) | private function getCachedSummary(Model $record): ?AiSummary
method regenerateSummary (line 82) | private function regenerateSummary(Model $record): void
method summaryService (line 100) | private function summaryService(): RecordSummaryService
FILE: app/Filament/Components/Infolists/AvatarName.php
class AvatarName (line 10) | final class AvatarName extends Entry
method avatar (line 24) | public function avatar(string $path): static
method name (line 31) | public function name(string $path): static
method avatarSize (line 38) | public function avatarSize(string $size): static
method textSize (line 45) | public function textSize(string $size): static
method square (line 52) | public function square(): static
method circular (line 59) | public function circular(): static
method getState (line 69) | public function getState(): array
method resolvePath (line 95) | private function resolvePath(mixed $record, string $path): mixed
FILE: app/Filament/Exports/BaseExporter.php
class BaseExporter (line 14) | abstract class BaseExporter extends Exporter
method __construct (line 20) | public function __construct(
method modifyQuery (line 41) | public static function modifyQuery(Builder $query): Builder
FILE: app/Filament/Exports/CompanyExporter.php
class CompanyExporter (line 13) | final class CompanyExporter extends BaseExporter
method getColumns (line 17) | public static function getColumns(): array
method getCompletedNotificationBody (line 51) | public static function getCompletedNotificationBody(Export $export): s...
FILE: app/Filament/Exports/NoteExporter.php
class NoteExporter (line 13) | final class NoteExporter extends BaseExporter
method getColumns (line 17) | public static function getColumns(): array
method getCompletedNotificationBody (line 35) | public static function getCompletedNotificationBody(Export $export): s...
FILE: app/Filament/Exports/OpportunityExporter.php
class OpportunityExporter (line 13) | final class OpportunityExporter extends BaseExporter
method getColumns (line 17) | public static function getColumns(): array
method getCompletedNotificationBody (line 53) | public static function getCompletedNotificationBody(Export $export): s...
FILE: app/Filament/Exports/PeopleExporter.php
class PeopleExporter (line 13) | final class PeopleExporter extends BaseExporter
method getColumns (line 17) | public static function getColumns(): array
method getCompletedNotificationBody (line 37) | public static function getCompletedNotificationBody(Export $export): s...
FILE: app/Filament/Exports/TaskExporter.php
class TaskExporter (line 13) | final class TaskExporter extends BaseExporter
method getColumns (line 17) | public static function getColumns(): array
method getCompletedNotificationBody (line 34) | public static function getCompletedNotificationBody(Export $export): s...
FILE: app/Filament/Pages/AccessTokens.php
class AccessTokens (line 14) | final class AccessTokens extends Page
method shouldRegisterNavigation (line 20) | #[Override]
method form (line 26) | public function form(Schema $schema): Schema
method getLabel (line 34) | public static function getLabel(): string
FILE: app/Filament/Pages/Auth/Login.php
class Login (line 15) | final class Login extends \Filament\Auth\Pages\Login
method content (line 19) | public function content(Schema $schema): Schema
method getAuthenticateFormAction (line 31) | protected function getAuthenticateFormAction(): Action
FILE: app/Filament/Pages/Auth/Register.php
class Register (line 18) | final class Register extends BaseRegister
method content (line 22) | public function content(Schema $schema): Schema
method getEmailFormComponent (line 33) | protected function getEmailFormComponent(): TextInput
method getRegisterFormAction (line 44) | public function getRegisterFormAction(): Action
method handleRegistration (line 55) | protected function handleRegistration(array $data): Model
FILE: app/Filament/Pages/CreateTeam.php
class CreateTeam (line 22) | final class CreateTeam extends RegisterTenant
method getLabel (line 24) | #[Override]
method getHeading (line 30) | #[Override]
method getSubheading (line 36) | #[Override]
method form (line 42) | #[Override]
method getRedirectUrl (line 80) | #[Override]
method handleRegistration (line 86) | #[Override]
FILE: app/Filament/Pages/EditProfile.php
class EditProfile (line 15) | final class EditProfile extends Page
method shouldRegisterNavigation (line 25) | public static function shouldRegisterNavigation(): bool
method form (line 30) | public function form(Schema $schema): Schema
method getLabel (line 40) | public static function getLabel(): string
FILE: app/Filament/Pages/EditTeam.php
class EditTeam (line 17) | final class EditTeam extends EditTenantProfile
method form (line 25) | public function form(Schema $schema): Schema
method getLabel (line 45) | public static function getLabel(): string
FILE: app/Filament/Pages/OpportunitiesBoard.php
class OpportunitiesBoard (line 40) | final class OpportunitiesBoard extends BoardPage
method board (line 52) | public function board(Board $board): Board
method moveCard (line 209) | public function moveCard(
method getColumns (line 250) | private function getColumns(): array
method formatCloseDateBadge (line 258) | private function formatCloseDateBadge(?string $state): string
method stageCustomField (line 274) | private function stageCustomField(): ?CustomField
method stages (line 286) | private function stages(): Collection
method canAccess (line 304) | public static function canAccess(): bool
FILE: app/Filament/Pages/TasksBoard.php
class TasksBoard (line 36) | final class TasksBoard extends BoardPage
method board (line 51) | public function board(Board $board): Board
method moveCard (line 188) | public function moveCard(
method getColumns (line 232) | private function getColumns(): array
method formatDueDateBadge (line 246) | private function formatDueDateBadge(?string $state): string
method statusCustomField (line 262) | private function statusCustomField(): ?CustomField
method statuses (line 274) | private function statuses(): Collection
method canAccess (line 293) | public static function canAccess(): bool
FILE: app/Filament/Resources/CompanyResource.php
class CompanyResource (line 35) | final class CompanyResource extends Resource
method form (line 47) | public static function form(Schema $schema): Schema
method table (line 64) | public static function table(Table $table): Table
method getPages (line 130) | public static function getPages(): array
method getGloballySearchableAttributes (line 138) | public static function getGloballySearchableAttributes(): array
method getEloquentQuery (line 143) | public static function getEloquentQuery(): Builder
FILE: app/Filament/Resources/CompanyResource/Pages/ListCompanies.php
class ListCompanies (line 20) | final class ListCompanies extends ListRecords
method getHeaderActions (line 31) | #[Override]
FILE: app/Filament/Resources/CompanyResource/Pages/ViewCompany.php
class ViewCompany (line 26) | final class ViewCompany extends ViewRecord
method getHeaderActions (line 30) | protected function getHeaderActions(): array
method infolist (line 71) | public function infolist(Schema $schema): Schema
method getRelationManagers (line 116) | public function getRelationManagers(): array
FILE: app/Filament/Resources/CompanyResource/RelationManagers/NotesRelationManager.php
class NotesRelationManager (line 23) | final class NotesRelationManager extends RelationManager
method form (line 29) | public function form(Schema $schema): Schema
method table (line 34) | public function table(Table $table): Table
FILE: app/Filament/Resources/CompanyResource/RelationManagers/PeopleRelationManager.php
class PeopleRelationManager (line 21) | final class PeopleRelationManager extends RelationManager
method form (line 29) | public function form(Schema $schema): Schema
method table (line 43) | public function table(Table $table): Table
FILE: app/Filament/Resources/CompanyResource/RelationManagers/TasksRelationManager.php
class TasksRelationManager (line 22) | final class TasksRelationManager extends RelationManager
method form (line 28) | public function form(Schema $schema): Schema
method table (line 33) | public function table(Table $table): Table
FILE: app/Filament/Resources/NoteResource.php
class NoteResource (line 32) | final class NoteResource extends Resource
method form (line 44) | public static function form(Schema $schema): Schema
method table (line 49) | public static function table(Table $table): Table
method getPages (line 111) | #[Override]
method getEloquentQuery (line 119) | public static function getEloquentQuery(): Builder
FILE: app/Filament/Resources/NoteResource/Forms/NoteForm.php
class NoteForm (line 12) | final class NoteForm
method get (line 20) | public static function get(Schema $schema, array $excludeFields = []):...
FILE: app/Filament/Resources/NoteResource/Pages/ManageNotes.php
class ManageNotes (line 20) | final class ManageNotes extends ManageRecords
method getHeaderActions (line 27) | #[Override]
FILE: app/Filament/Resources/OpportunityResource.php
class OpportunityResource (line 36) | final class OpportunityResource extends Resource
method form (line 48) | public static function form(Schema $schema): Schema
method table (line 53) | public static function table(Table $table): Table
method getRelations (line 106) | public static function getRelations(): array
method getPages (line 114) | #[Override]
method getEloquentQuery (line 123) | public static function getEloquentQuery(): Builder
FILE: app/Filament/Resources/OpportunityResource/Forms/OpportunityForm.php
class OpportunityForm (line 12) | final class OpportunityForm
method get (line 14) | public static function get(Schema $schema): Schema
FILE: app/Filament/Resources/OpportunityResource/Pages/ListOpportunities.php
class ListOpportunities (line 20) | final class ListOpportunities extends ListRecords
method getHeaderActions (line 27) | #[Override]
FILE: app/Filament/Resources/OpportunityResource/Pages/ViewOpportunity.php
class ViewOpportunity (line 24) | final class ViewOpportunity extends ViewRecord
method getHeaderActions (line 28) | protected function getHeaderActions(): array
method infolist (line 69) | public function infolist(Schema $schema): Schema
FILE: app/Filament/Resources/OpportunityResource/RelationManagers/NotesRelationManager.php
class NotesRelationManager (line 24) | final class NotesRelationManager extends RelationManager
method form (line 30) | public function form(Schema $schema): Schema
method table (line 35) | public function table(Table $table): Table
FILE: app/Filament/Resources/OpportunityResource/RelationManagers/TasksRelationManager.php
class TasksRelationManager (line 24) | final class TasksRelationManager extends RelationManager
method form (line 30) | public function form(Schema $schema): Schema
method table (line 35) | public function table(Table $table): Table
FILE: app/Filament/Resources/PeopleResource.php
class PeopleResource (line 42) | final class PeopleResource extends Resource
method form (line 56) | public static function form(Schema $schema): Schema
method table (line 100) | public static function table(Table $table): Table
method getRelations (line 162) | public static function getRelations(): array
method getPages (line 170) | public static function getPages(): array
method getEloquentQuery (line 178) | public static function getEloquentQuery(): Builder
FILE: app/Filament/Resources/PeopleResource/Pages/ListPeople.php
class ListPeople (line 20) | final class ListPeople extends ListRecords
method getHeaderActions (line 27) | #[Override]
FILE: app/Filament/Resources/PeopleResource/Pages/ViewPeople.php
class ViewPeople (line 25) | final class ViewPeople extends ViewRecord
method getHeaderActions (line 29) | protected function getHeaderActions(): array
method infolist (line 70) | public function infolist(Schema $schema): Schema
FILE: app/Filament/Resources/PeopleResource/RelationManagers/NotesRelationManager.php
class NotesRelationManager (line 20) | final class NotesRelationManager extends RelationManager
method form (line 26) | public function form(Schema $schema): Schema
method table (line 31) | public function table(Table $table): Table
FILE: app/Filament/Resources/PeopleResource/RelationManagers/TasksRelationManager.php
class TasksRelationManager (line 20) | final class TasksRelationManager extends RelationManager
method form (line 26) | public function form(Schema $schema): Schema
method table (line 31) | public function table(Table $table): Table
FILE: app/Filament/Resources/TaskResource.php
class TaskResource (line 36) | final class TaskResource extends Resource
method form (line 50) | public static function form(Schema $schema): Schema
method table (line 55) | public static function table(Table $table): Table
method getPages (line 142) | public static function getPages(): array
method makeCustomFieldGroup (line 152) | private static function makeCustomFieldGroup(string $fieldCode, Collec...
method getEloquentQuery (line 192) | public static function getEloquentQuery(): Builder
FILE: app/Filament/Resources/TaskResource/Forms/TaskForm.php
class TaskForm (line 12) | final class TaskForm
method get (line 19) | public static function get(Schema $schema, array $excludeFields = []):...
FILE: app/Filament/Resources/TaskResource/Pages/ManageTasks.php
class ManageTasks (line 22) | final class ManageTasks extends ManageRecords
method getHeaderActions (line 29) | #[Override]
FILE: app/Health/AnthropicModelCheck.php
class AnthropicModelCheck (line 13) | final class AnthropicModelCheck extends Check
method run (line 15) | public function run(): Result
FILE: app/Http/Controllers/AcceptTeamInvitationController.php
class AcceptTeamInvitationController (line 15) | final readonly class AcceptTeamInvitationController
method __invoke (line 17) | public function __invoke(Request $request, string $invitationId): Redi...
FILE: app/Http/Controllers/Api/V1/CompaniesController.php
class CompaniesController (line 31) | final readonly class CompaniesController
method index (line 33) | #[ResponseFromApiResource(CompanyResource::class, Company::class, coll...
method store (line 44) | #[ResponseFromApiResource(CompanyResource::class, Company::class, stat...
method show (line 54) | #[ResponseFromApiResource(CompanyResource::class, Company::class)]
method update (line 64) | #[ResponseFromApiResource(CompanyResource::class, Company::class)]
method destroy (line 72) | #[Response(status: 204)]
FILE: app/Http/Controllers/Api/V1/CustomFieldsController.php
class CustomFieldsController (line 20) | final readonly class CustomFieldsController
method index (line 22) | #[ResponseFromApiResource(CustomFieldResource::class, CustomField::cla...
FILE: app/Http/Controllers/Api/V1/NotesController.php
class NotesController (line 31) | final readonly class NotesController
method index (line 33) | #[ResponseFromApiResource(NoteResource::class, Note::class, collection...
method store (line 44) | #[ResponseFromApiResource(NoteResource::class, Note::class, status: 201)]
method show (line 54) | #[ResponseFromApiResource(NoteResource::class, Note::class)]
method update (line 64) | #[ResponseFromApiResource(NoteResource::class, Note::class)]
method destroy (line 72) | #[Response(status: 204)]
FILE: app/Http/Controllers/Api/V1/OpportunitiesController.php
class OpportunitiesController (line 32) | final readonly class OpportunitiesController
method index (line 34) | #[ResponseFromApiResource(OpportunityResource::class, Opportunity::cla...
method store (line 45) | #[ResponseFromApiResource(OpportunityResource::class, Opportunity::cla...
method show (line 58) | #[ResponseFromApiResource(OpportunityResource::class, Opportunity::cla...
method update (line 68) | #[ResponseFromApiResource(OpportunityResource::class, Opportunity::cla...
method destroy (line 79) | #[Response(status: 204)]
FILE: app/Http/Controllers/Api/V1/PeopleController.php
class PeopleController (line 32) | final readonly class PeopleController
method index (line 34) | #[ResponseFromApiResource(PeopleResource::class, People::class, collec...
method store (line 45) | #[ResponseFromApiResource(PeopleResource::class, People::class, status...
method show (line 57) | #[ResponseFromApiResource(PeopleResource::class, People::class)]
method update (line 67) | #[ResponseFromApiResource(PeopleResource::class, People::class)]
method destroy (line 77) | #[Response(status: 204)]
FILE: app/Http/Controllers/Api/V1/TasksController.php
class TasksController (line 31) | final readonly class TasksController
method index (line 33) | #[ResponseFromApiResource(TaskResource::class, Task::class, collection...
method store (line 44) | #[ResponseFromApiResource(TaskResource::class, Task::class, status: 201)]
method show (line 54) | #[ResponseFromApiResource(TaskResource::class, Task::class)]
method update (line 64) | #[ResponseFromApiResource(TaskResource::class, Task::class)]
method destroy (line 72) | #[Response(status: 204)]
FILE: app/Http/Controllers/Auth/CallbackController.php
class CallbackController (line 20) | final readonly class CallbackController
method __invoke (line 22) | public function __invoke(
method retrieveSocialUser (line 49) | private function retrieveSocialUser(string $provider): SocialiteUser
method resolveUser (line 54) | private function resolveUser(
method createUser (line 83) | private function createUser(
method linkSocialAccount (line 95) | private function linkSocialAccount(User $user, string $provider, strin...
method extractName (line 105) | private function extractName(SocialiteUser $socialUser): string
method extractEmail (line 112) | private function extractEmail(SocialiteUser $socialUser, string $provi...
method parseProviderError (line 118) | private function parseProviderError(string $exceptionMessage, string $...
method handleError (line 134) | private function handleError(string $message): RedirectResponse
method loginAndRedirect (line 148) | private function loginAndRedirect(User $user): RedirectResponse
FILE: app/Http/Controllers/Auth/RedirectController.php
class RedirectController (line 12) | final readonly class RedirectController
method __invoke (line 14) | public function __invoke(SocialiteProvider $provider): RedirectResponse
FILE: app/Http/Controllers/ContactController.php
class ContactController (line 13) | final readonly class ContactController
method show (line 15) | public function show(): View
method store (line 20) | public function store(ContactRequest $request): RedirectResponse
FILE: app/Http/Controllers/HomeController.php
class HomeController (line 9) | final readonly class HomeController
method __invoke (line 11) | public function __invoke(): View
FILE: app/Http/Controllers/PrivacyPolicyController.php
class PrivacyPolicyController (line 11) | final readonly class PrivacyPolicyController
method __invoke (line 13) | public function __invoke(): View
FILE: app/Http/Controllers/TermsOfServiceController.php
class TermsOfServiceController (line 11) | final readonly class TermsOfServiceController
method __invoke (line 13) | public function __invoke(): View
FILE: app/Http/Middleware/ApplyTenantScopes.php
class ApplyTenantScopes (line 19) | final readonly class ApplyTenantScopes
method handle (line 21) | public function handle(Request $request, Closure $next): mixed
FILE: app/Http/Middleware/EnsureTokenHasAbility.php
class EnsureTokenHasAbility (line 13) | final readonly class EnsureTokenHasAbility
method handle (line 18) | public function handle(Request $request, Closure $next): Response
method resolveAbility (line 36) | private function resolveAbility(string $method): string
FILE: app/Http/Middleware/ForceJsonResponse.php
class ForceJsonResponse (line 11) | final readonly class ForceJsonResponse
method handle (line 13) | public function handle(Request $request, Closure $next): Response
FILE: app/Http/Middleware/SetApiTeamContext.php
class SetApiTeamContext (line 35) | final readonly class SetApiTeamContext
method handle (line 47) | public function handle(Request $request, Closure $next): Response
method terminate (line 81) | public function terminate(): void
method resolveTeam (line 90) | private function resolveTeam(Request $request, User $user): ?Team
method applyTenantScopes (line 107) | private function applyTenantScopes(Team $team): void
FILE: app/Http/Middleware/SubdomainRootResponse.php
class SubdomainRootResponse (line 12) | final readonly class SubdomainRootResponse
method handle (line 14) | public function handle(Request $request, Closure $next): Response
FILE: app/Http/Middleware/ValidateSignature.php
class ValidateSignature (line 26) | final readonly class ValidateSignature
method __construct (line 28) | public function __construct(
method handle (line 33) | public function handle(Request $request, Closure $next, mixed ...$args...
method hasValidNormalizedSignature (line 52) | private function hasValidNormalizedSignature(Request $request, array $...
FILE: app/Http/Requests/Api/V1/IndexCustomFieldsRequest.php
class IndexCustomFieldsRequest (line 10) | final class IndexCustomFieldsRequest extends FormRequest
method rules (line 19) | public function rules(): array
FILE: app/Http/Requests/Api/V1/IndexRequest.php
class IndexRequest (line 9) | final class IndexRequest extends FormRequest
method rules (line 14) | public function rules(): array
FILE: app/Http/Requests/Api/V1/StoreCompanyRequest.php
class StoreCompanyRequest (line 11) | final class StoreCompanyRequest extends FormRequest
method rules (line 16) | public function rules(): array
FILE: app/Http/Requests/Api/V1/StoreNoteRequest.php
class StoreNoteRequest (line 12) | final class StoreNoteRequest extends FormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/Api/V1/StoreOpportunityRequest.php
class StoreOpportunityRequest (line 12) | final class StoreOpportunityRequest extends FormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/Api/V1/StorePeopleRequest.php
class StorePeopleRequest (line 12) | final class StorePeopleRequest extends FormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/Api/V1/StoreTaskRequest.php
class StoreTaskRequest (line 12) | final class StoreTaskRequest extends FormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/Api/V1/UpdateCompanyRequest.php
class UpdateCompanyRequest (line 11) | final class UpdateCompanyRequest extends FormRequest
method rules (line 16) | public function rules(): array
FILE: app/Http/Requests/Api/V1/UpdateNoteRequest.php
class UpdateNoteRequest (line 12) | final class UpdateNoteRequest extends FormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/Api/V1/UpdateOpportunityRequest.php
class UpdateOpportunityRequest (line 12) | final class UpdateOpportunityRequest extends FormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/Api/V1/UpdatePeopleRequest.php
class UpdatePeopleRequest (line 12) | final class UpdatePeopleRequest extends FormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/Api/V1/UpdateTaskRequest.php
class UpdateTaskRequest (line 12) | final class UpdateTaskRequest extends FormRequest
method rules (line 17) | public function rules(): array
FILE: app/Http/Requests/ContactRequest.php
class ContactRequest (line 11) | final class ContactRequest extends FormRequest
method rules (line 14) | public function rules(): array
FILE: app/Http/Resources/V1/CompanyResource.php
class CompanyResource (line 15) | final class CompanyResource extends JsonApiResource
method toAttributes (line 22) | public function toAttributes(Request $request): array
method toRelationships (line 40) | public function toRelationships(Request $request): array
FILE: app/Http/Resources/V1/Concerns/FormatsCustomFields.php
type FormatsCustomFields (line 12) | trait FormatsCustomFields
method formatCustomFields (line 14) | protected function formatCustomFields(Model $record): \stdClass
method resolveFieldValue (line 31) | private function resolveFieldValue(CustomFieldValue $fieldValue): mixed
method resolveSingleChoiceValue (line 50) | private function resolveSingleChoiceValue(CustomField $customField, mi...
method resolveMultiChoiceValue (line 67) | private function resolveMultiChoiceValue(CustomField $customField, mix...
FILE: app/Http/Resources/V1/CustomFieldResource.php
class CustomFieldResource (line 20) | final class CustomFieldResource extends JsonApiResource
method toAttributes (line 25) | public function toAttributes(Request $request): array
FILE: app/Http/Resources/V1/NoteResource.php
class NoteResource (line 15) | final class NoteResource extends JsonApiResource
method toAttributes (line 22) | public function toAttributes(Request $request): array
method toRelationships (line 39) | public function toRelationships(Request $request): array
FILE: app/Http/Resources/V1/OpportunityResource.php
class OpportunityResource (line 15) | final class OpportunityResource extends JsonApiResource
method toAttributes (line 22) | public function toAttributes(Request $request): array
method toRelationships (line 40) | public function toRelationships(Request $request): array
FILE: app/Http/Resources/V1/PeopleResource.php
class PeopleResource (line 15) | final class PeopleResource extends JsonApiResource
method toAttributes (line 22) | public function toAttributes(Request $request): array
method toRelationships (line 39) | public function toRelationships(Request $request): array
FILE: app/Http/Resources/V1/TaskResource.php
class TaskResource (line 15) | final class TaskResource extends JsonApiResource
method toAttributes (line 22) | public function toAttributes(Request $request): array
method toRelationships (line 40) | public function toRelationships(Request $request): array
FILE: app/Http/Resources/V1/UserResource.php
class UserResource (line 14) | final class UserResource extends JsonApiResource
method toAttributes (line 19) | public function toAttributes(Request $request): array
FILE: app/Http/Responses/LoginResponse.php
class LoginResponse (line 12) | final readonly class LoginResponse implements \Filament\Auth\Http\Respon...
method toResponse (line 15) | public function toResponse($request): RedirectResponse|Redirector // @...
FILE: app/Jobs/Email/CreateSubscriberJob.php
class CreateSubscriberJob (line 16) | final class CreateSubscriberJob implements ShouldQueue
method __construct (line 20) | public function __construct(private readonly SubscriberData $data) {}
method handle (line 25) | public function handle(): void
FILE: app/Jobs/Email/UpdateSubscriberJob.php
class UpdateSubscriberJob (line 18) | final class UpdateSubscriberJob implements ShouldQueue
method __construct (line 22) | public function __construct(private readonly SubscriberData $data) {}
method handle (line 24) | public function handle(): void
method uniqueId (line 42) | public function uniqueId(): string
method middleware (line 52) | public function middleware(): array
method retryUntil (line 60) | public function retryUntil(): \DateTime
FILE: app/Jobs/FetchFaviconForCompany.php
class FetchFaviconForCompany (line 17) | final class FetchFaviconForCompany implements ShouldBeUnique, ShouldQueue
method __construct (line 24) | public function __construct(public readonly Company $company) {}
method handle (line 26) | public function handle(): void
method uniqueId (line 78) | public function uniqueId(): string
FILE: app/Listeners/CreateTeamCustomFields.php
class CreateTeamCustomFields (line 30) | final readonly class CreateTeamCustomFields
method __construct (line 41) | public function __construct(
method handle (line 46) | public function handle(TeamCreated $event): void
method createCustomField (line 70) | private function createCustomField(string $model, CompanyCustomField|O...
method applyColorsToOptions (line 107) | private function applyColorsToOptions(CustomField $customField, Compan...
FILE: app/Listeners/Email/NewSubscriberListener.php
class NewSubscriberListener (line 20) | final class NewSubscriberListener implements ShouldHandleEventsAfterComm...
method handle (line 28) | public function handle(Verified $event): void
FILE: app/Listeners/SwitchTeam.php
class SwitchTeam (line 10) | final readonly class SwitchTeam
method handle (line 15) | public function handle(TenantSet $event): void
FILE: app/Livewire/App/AccessTokens/CreateAccessToken.php
class CreateAccessToken (line 23) | final class CreateAccessToken extends BaseLivewireComponent
method mount (line 30) | public function mount(): void
method form (line 38) | public function form(Schema $schema): Schema
method showTokenAction (line 94) | public function showTokenAction(): Action
method createToken (line 121) | public function createToken(): void
method permissionsCheckboxList (line 173) | public static function permissionsCheckboxList(): CheckboxList
method render (line 190) | public function render(): View
FILE: app/Livewire/App/AccessTokens/ManageAccessTokens.php
class ManageAccessTokens (line 21) | final class ManageAccessTokens extends BaseLivewireComponent implements ...
method refreshTokenList (line 25) | #[On('tokenCreated')]
method table (line 31) | public function table(Table $table): Table
method render (line 110) | public function render(): View
FILE: app/Livewire/App/Profile/DeleteAccount.php
class DeleteAccount (line 24) | final class DeleteAccount extends BaseLivewireComponent
method form (line 26) | public function form(Schema $schema): Schema
method deleteAccount (line 67) | public function deleteAccount(?string $password = null): Redirector|Re...
method render (line 101) | public function render(): View
FILE: app/Livewire/App/Profile/LogoutOtherBrowserSessions.php
class LogoutOtherBrowserSessions (line 22) | final class LogoutOtherBrowserSessions extends BaseLivewireComponent
method form (line 24) | public function form(Schema $schema): Schema
method logoutOtherBrowserSessions (line 65) | public function logoutOtherBrowserSessions(?string $password): void
method browserSessions (line 103) | public function browserSessions(): Collection
method render (line 127) | public function render(): View
FILE: app/Livewire/App/Profile/UpdatePassword.php
class UpdatePassword (line 20) | final class UpdatePassword extends BaseLivewireComponent
method mount (line 25) | public function mount(): void
method form (line 30) | public function form(Schema $schema): Schema
method updatePassword (line 77) | public function updatePassword(): void
method render (line 105) | public function render(): View
FILE: app/Livewire/App/Profile/UpdateProfileInformation.php
class UpdateProfileInformation (line 24) | final class UpdateProfileInformation extends BaseLivewireComponent
method mount (line 29) | public function mount(): void
method form (line 36) | public function form(Schema $schema): Schema
method updateProfile (line 73) | public function updateProfile(): void
method sendEmailChangeVerification (line 99) | private function sendEmailChangeVerification(array $data): void
method render (line 132) | public function render(): View
FILE: app/Livewire/App/Teams/AddTeamMember.php
class AddTeamMember (line 26) | final class AddTeamMember extends BaseLivewireComponent
method mount (line 33) | public function mount(Team $team): void
method form (line 40) | public function form(Schema $schema): Schema
method addTeamMember (line 82) | public function addTeamMember(Team $team): void
method render (line 115) | public function render(): View
FILE: app/Livewire/App/Teams/DeleteTeam.php
class DeleteTeam (line 20) | final class DeleteTeam extends BaseLivewireComponent
method mount (line 24) | public function mount(Team $team): void
method form (line 29) | public function form(Schema $schema): Schema
method render (line 56) | public function render(): View
method deleteTeam (line 61) | public function deleteTeam(Team $team): void
FILE: app/Livewire/App/Teams/PendingTeamInvitations.php
class PendingTeamInvitations (line 22) | final class PendingTeamInvitations extends BaseLivewireComponent impleme...
method mount (line 28) | public function mount(Team $team): void
method table (line 33) | public function table(Table $table): Table
method extendTeamInvitation (line 82) | public function extendTeamInvitation(Model $invitation): void
method copyInviteLink (line 95) | public function copyInviteLink(Model $invitation): void
method resendTeamInvitation (line 106) | public function resendTeamInvitation(Model $invitation): void
method cancelTeamInvitation (line 128) | public function cancelTeamInvitation(Team $team, Model $invitation): void
method render (line 137) | public function render(): View
FILE: app/Livewire/App/Teams/TeamMembers.php
class TeamMembers (line 26) | final class TeamMembers extends BaseLivewireComponent implements Tables\...
method mount (line 32) | public function mount(Team $team): void
method table (line 37) | public function table(Table $table): Table
method updateTeamRole (line 115) | public function updateTeamRole(Team $team, Membership $teamMember, arr...
method removeTeamMember (line 135) | public function removeTeamMember(Team $team, Membership $teamMember): ...
method leaveTeam (line 156) | public function leaveTeam(Team $team): void
method render (line 179) | public function render(): View
FILE: app/Livewire/App/Teams/UpdateTeamName.php
class UpdateTeamName (line 22) | final class UpdateTeamName extends BaseLivewireComponent
method mount (line 31) | public function mount(Team $team): void
method form (line 38) | public function form(Schema $schema): Schema
method updateTeamName (line 82) | public function updateTeamName(Team $team): void
method render (line 106) | public function render(): View
FILE: app/Livewire/BaseLivewireComponent.php
class BaseLivewireComponent (line 22) | abstract class BaseLivewireComponent extends Component implements HasAct...
method authUser (line 28) | public function authUser(): User
method sendRateLimitedNotification (line 36) | protected function sendRateLimitedNotification(TooManyRequestsExceptio...
method sendNotification (line 45) | protected function sendNotification(string $title = 'Saved', ?string $...
FILE: app/Livewire/UpdateProfileInformationForm.php
class UpdateProfileInformationForm (line 15) | final class UpdateProfileInformationForm extends Component
method mount (line 39) | public function mount(): void
method updateProfileInformation (line 51) | public function updateProfileInformation(UpdatesUserProfileInformation...
method deleteProfilePhoto (line 70) | public function deleteProfilePhoto(): void
method sendEmailVerification (line 80) | public function sendEmailVerification(): void
method user (line 90) | #[Computed]
method render (line 99) | public function render(): View
FILE: app/Mail/NewContactSubmissionMail.php
class NewContactSubmissionMail (line 14) | final class NewContactSubmissionMail extends Mailable implements ShouldQ...
method __construct (line 19) | public function __construct(
method envelope (line 23) | public function envelope(): Envelope
method content (line 31) | public function content(): Content
FILE: app/Mcp/Filters/CustomFieldFilter.php
class CustomFieldFilter (line 18) | final readonly class CustomFieldFilter implements Filter
method __construct (line 30) | public function __construct(
method __invoke (line 34) | public function __invoke(Builder $query, mixed $value, string $propert...
method applyCondition (line 65) | private function applyCondition(
method resolveFields (line 89) | private function resolveFields(array $fieldCodes): Collection
FILE: app/Mcp/Filters/CustomFieldSort.php
class CustomFieldSort (line 16) | final readonly class CustomFieldSort implements Sort
method __construct (line 18) | public function __construct(
method __invoke (line 25) | public function __invoke(Builder $query, bool $descending, string $pro...
method resolveField (line 47) | private function resolveField(string $code): ?CustomField
method resolveAllFields (line 55) | private function resolveAllFields(): Collection
FILE: app/Mcp/Prompts/CrmOverviewPrompt.php
class CrmOverviewPrompt (line 20) | #[Description('Get an overview of the CRM data for the current team, inc...
method shouldRegister (line 25) | public function shouldRegister(): bool
method handle (line 38) | public function handle(Request $request): Response
FILE: app/Mcp/Resources/CompanySchemaResource.php
class CompanySchemaResource (line 17) | #[Description('Schema for companies including available custom fields. R...
method shouldRegister (line 24) | public function shouldRegister(): bool
method handle (line 37) | public function handle(Request $request): Response
FILE: app/Mcp/Resources/Concerns/ResolvesEntitySchema.php
type ResolvesEntitySchema (line 14) | trait ResolvesEntitySchema
method resolveCustomFields (line 19) | protected function resolveCustomFields(User $user, string $entityType)...
method resolveFilterableFields (line 41) | protected function resolveFilterableFields(User $user, string $entityT...
method formatCustomFields (line 52) | private function formatCustomFields(Collection $fields): array
method fieldFormatHint (line 89) | private function fieldFormatHint(string $type): ?array
FILE: app/Mcp/Resources/CrmSummaryResource.php
class CrmSummaryResource (line 26) | #[Description('CRM summary with record counts, pipeline breakdown by sta...
method shouldRegister (line 31) | public function shouldRegister(): bool
method handle (line 44) | public function handle(Request $request): Response
method opportunitySummary (line 66) | private function opportunitySummary(mixed $teamId): array
method taskSummary (line 126) | private function taskSummary(mixed $teamId): array
method resolveFieldId (line 153) | private function resolveFieldId(mixed $teamId, string $entityType, str...
FILE: app/Mcp/Resources/NoteSchemaResource.php
class NoteSchemaResource (line 17) | #[Description('Schema for notes including available custom fields. Read ...
method shouldRegister (line 24) | public function shouldRegister(): bool
method handle (line 37) | public function handle(Request $request): Response
FILE: app/Mcp/Resources/OpportunitySchemaResource.php
class OpportunitySchemaResource (line 17) | #[Description('Schema for opportunities including available custom field...
method shouldRegister (line 24) | public function shouldRegister(): bool
method handle (line 37) | public function handle(Request $request): Response
FILE: app/Mcp/Resources/PeopleSchemaResource.php
class PeopleSchemaResource (line 17) | #[Description('Schema for people (contacts) including available custom f...
method shouldRegister (line 24) | public function shouldRegister(): bool
method handle (line 37) | public function handle(Request $request): Response
FILE: app/Mcp/Resources/TaskSchemaResource.php
class TaskSchemaResource (line 17) | #[Description('Schema for tasks including available custom fields. Read ...
method shouldRegister (line 24) | public function shouldRegister(): bool
method handle (line 37) | public function handle(Request $request): Response
FILE: app/Mcp/Schema/CustomFieldFilterSchema.php
class CustomFieldFilterSchema (line 16) | final readonly class CustomFieldFilterSchema
method build (line 42) | public function build(User $user, string $entityType): array
method allowedSorts (line 67) | public function allowedSorts(User $user, string $entityType): array
method operatorsForType (line 77) | private function operatorsForType(string $type): array
method buildOperators (line 105) | private function buildOperators(array $operators, string $jsonType): a...
method resolveFilterableFields (line 119) | private function resolveFilterableFields(User $user, string $entityTyp...
FILE: app/Mcp/Servers/RelaticleServer.php
class RelaticleServer (line 51) | #[Name('Relaticle CRM')]
FILE: app/Mcp/Tools/BaseAttachTool.php
class BaseAttachTool (line 17) | abstract class BaseAttachTool extends Tool
method modelClass (line 23) | abstract protected function modelClass(): string;
method entityLabel (line 25) | abstract protected function entityLabel(): string;
method resourceClass (line 28) | abstract protected function resourceClass(): string;
method relationshipSchema (line 31) | abstract protected function relationshipSchema(JsonSchema $schema): ar...
method relationshipRules (line 34) | abstract protected function relationshipRules(User $user): array;
method syncRelationships (line 37) | abstract protected function syncRelationships(Model $model, array $dat...
method relationshipsToLoad (line 40) | protected function relationshipsToLoad(): array
method schema (line 45) | public function schema(JsonSchema $schema): array
method handle (line 55) | public function handle(Request $request): Response
FILE: app/Mcp/Tools/BaseCreateTool.php
class BaseCreateTool (line 17) | abstract class BaseCreateTool extends Tool
method actionClass (line 22) | abstract protected function actionClass(): string;
method resourceClass (line 25) | abstract protected function resourceClass(): string;
method entityType (line 27) | abstract protected function entityType(): string;
method entitySchema (line 32) | abstract protected function entitySchema(JsonSchema $schema): array;
method entityRules (line 37) | abstract protected function entityRules(User $user): array;
method schema (line 39) | public function schema(JsonSchema $schema): array
method handle (line 49) | public function handle(Request $request): Response
FILE: app/Mcp/Tools/BaseDeleteTool.php
class BaseDeleteTool (line 15) | abstract class BaseDeleteTool extends Tool
method modelClass (line 20) | abstract protected function modelClass(): string;
method actionClass (line 23) | abstract protected function actionClass(): string;
method entityLabel (line 25) | abstract protected function entityLabel(): string;
method nameAttribute (line 27) | protected function nameAttribute(): string
method schema (line 32) | public function schema(JsonSchema $schema): array
method handle (line 41) | public function handle(Request $request): Response
FILE: app/Mcp/Tools/BaseDetachTool.php
class BaseDetachTool (line 17) | abstract class BaseDetachTool extends Tool
method modelClass (line 23) | abstract protected function modelClass(): string;
method entityLabel (line 25) | abstract protected function entityLabel(): string;
method resourceClass (line 28) | abstract protected function resourceClass(): string;
method relationshipSchema (line 31) | abstract protected function relationshipSchema(JsonSchema $schema): ar...
method relationshipRules (line 34) | abstract protected function relationshipRules(User $user): array;
method detachRelationships (line 37) | abstract protected function detachRelationships(Model $model, array $d...
method relationshipsToLoad (line 40) | protected function relationshipsToLoad(): array
method schema (line 45) | public function schema(JsonSchema $schema): array
method handle (line 55) | public function handle(Request $request): Response
FILE: app/Mcp/Tools/BaseListTool.php
class BaseListTool (line 20) | abstract class BaseListTool extends Tool
method actionClass (line 26) | abstract protected function actionClass(): string;
method resourceClass (line 29) | abstract protected function resourceClass(): string;
method searchFilterName (line 31) | abstract protected function searchFilterName(): string;
method additionalSchema (line 36) | protected function additionalSchema(JsonSchema $schema): array
method additionalFilters (line 44) | protected function additionalFilters(Request $request): array
method schema (line 49) | public function schema(JsonSchema $schema): array
method handle (line 64) | public function handle(Request $request): Response
method buildHttpRequest (line 134) | private function buildHttpRequest(Request $mcpRequest): HttpRequest
FILE: app/Mcp/Tools/BaseShowTool.php
class BaseShowTool (line 19) | #[IsReadOnly]
method modelClass (line 27) | abstract protected function modelClass(): string;
method resourceClass (line 30) | abstract protected function resourceClass(): string;
method entityLabel (line 32) | abstract protected function entityLabel(): string;
method allowedIncludes (line 37) | abstract protected function allowedIncludes(): array;
method schema (line 39) | public function schema(JsonSchema $schema): array
method handle (line 49) | public function handle(Request $request): Response
FILE: app/Mcp/Tools/BaseUpdateTool.php
class BaseUpdateTool (line 17) | abstract class BaseUpdateTool extends Tool
method modelClass (line 22) | abstract protected function modelClass(): string;
method actionClass (line 25) | abstract protected function actionClass(): string;
method resourceClass (line 28) | abstract protected function resourceClass(): string;
method entityType (line 30) | abstract protected function entityType(): string;
method entityLabel (line 32) | abstract protected function entityLabel(): string;
method entitySchema (line 37) | abstract protected function entitySchema(JsonSchema $schema): array;
method entityRules (line 42) | abstract protected function entityRules(User $user): array;
method schema (line 44) | public function schema(JsonSchema $schema): array
method handle (line 57) | public function handle(Request $request): Response
FILE: app/Mcp/Tools/Company/CreateCompanyTool.php
class CreateCompanyTool (line 14) | #[Description('Create a new company in the CRM. Use the crm-schema resou...
method actionClass (line 17) | protected function actionClass(): string
method resourceClass (line 22) | protected function resourceClass(): string
method entityType (line 27) | protected function entityType(): string
method entitySchema (line 32) | protected function entitySchema(JsonSchema $schema): array
method entityRules (line 39) | protected function entityRules(User $user): array
FILE: app/Mcp/Tools/Company/DeleteCompanyTool.php
class DeleteCompanyTool (line 13) | #[Description('Delete a company from the CRM (soft delete).')]
method modelClass (line 17) | protected function modelClass(): string
method actionClass (line 22) | protected function actionClass(): string
method entityLabel (line 27) | protected function entityLabel(): string
FILE: app/Mcp/Tools/Company/GetCompanyTool.php
class GetCompanyTool (line 13) | #[Description('Get a single company by ID with full details and relation...
method modelClass (line 16) | protected function modelClass(): string
method resourceClass (line 22) | protected function resourceClass(): string
method entityLabel (line 27) | protected function entityLabel(): string
method allowedIncludes (line 33) | protected function allowedIncludes(): array
FILE: app/Mcp/Tools/Company/ListCompaniesTool.php
class ListCompaniesTool (line 14) | #[Description('List companies in the CRM with optional search and pagina...
method actionClass (line 19) | protected function actionClass(): string
method resourceClass (line 24) | protected function resourceClass(): string
method searchFilterName (line 29) | protected function searchFilterName(): string
FILE: app/Mcp/Tools/Company/UpdateCompanyTool.php
class UpdateCompanyTool (line 16) | #[Description('Update an existing company in the CRM. Use the crm-schema...
method modelClass (line 20) | protected function modelClass(): string
method actionClass (line 25) | protected function actionClass(): string
method resourceClass (line 30) | protected function resourceClass(): string
method entityType (line 35) | protected function entityType(): string
method entityLabel (line 40) | protected function entityLabel(): string
method entitySchema (line 45) | protected function entitySchema(JsonSchema $schema): array
method entityRules (line 52) | protected function entityRules(User $user): array
FILE: app/Mcp/Tools/Concerns/BuildsRelationshipResponse.php
type BuildsRelationshipResponse (line 12) | trait BuildsRelationshipResponse
method buildRelationshipResponse (line 14) | protected function buildRelationshipResponse(Model $model): Response
FILE: app/Mcp/Tools/Concerns/ChecksTokenAbility.php
type ChecksTokenAbility (line 10) | trait ChecksTokenAbility
method ensureTokenCan (line 15) | protected function ensureTokenCan(string $ability): void
FILE: app/Mcp/Tools/Concerns/SerializesRelatedModels.php
type SerializesRelatedModels (line 12) | trait SerializesRelatedModels
method resolveRelationshipMap (line 20) | private function resolveRelationshipMap(string $resourceClass, Model $...
method serializeRelatedModel (line 37) | private function serializeRelatedModel(Model $model, string $relation,...
method serializeRelation (line 70) | private function serializeRelation(
FILE: app/Mcp/Tools/Note/AttachNoteToEntitiesTool.php
class AttachNoteToEntitiesTool (line 16) | #[Description('Attach a note to companies, people, or opportunities. Add...
method modelClass (line 19) | protected function modelClass(): string
method entityLabel (line 24) | protected function entityLabel(): string
method resourceClass (line 29) | protected function resourceClass(): string
method relationshipsToLoad (line 35) | protected function relationshipsToLoad(): array
method relationshipSchema (line 40) | public function relationshipSchema(JsonSchema $schema): array
method relationshipRules (line 49) | public function relationshipRules(User $user): array
method syncRelationships (line 63) | public function syncRelationships(Model $model, array $data): void
FILE: app/Mcp/Tools/Note/CreateNoteTool.php
class CreateNoteTool (line 15) | #[Description('Create a new note in the CRM. Use the crm-schema resource...
method actionClass (line 18) | protected function actionClass(): string
method resourceClass (line 23) | protected function resourceClass(): string
method entityType (line 28) | protected function entityType(): string
method entitySchema (line 33) | protected function entitySchema(JsonSchema $schema): array
method entityRules (line 43) | protected function entityRules(User $user): array
FILE: app/Mcp/Tools/Note/DeleteNoteTool.php
class DeleteNoteTool (line 13) | #[Description('Delete a note from the CRM (soft delete).')]
method modelClass (line 17) | protected function modelClass(): string
method actionClass (line 22) | protected function actionClass(): string
method entityLabel (line 27) | protected function entityLabel(): string
method nameAttribute (line 32) | protected function nameAttribute(): string
FILE: app/Mcp/Tools/Note/DetachNoteFromEntitiesTool.php
class DetachNoteFromEntitiesTool (line 16) | #[Description('Detach a note from companies, people, or opportunities. R...
method modelClass (line 19) | protected function modelClass(): string
method entityLabel (line 24) | protected function entityLabel(): string
method resourceClass (line 29) | protected function resourceClass(): string
method relationshipsToLoad (line 35) | protected function relationshipsToLoad(): array
method relationshipSchema (line 40) | public function relationshipSchema(JsonSchema $schema): array
method relationshipRules (line 49) | public function relationshipRules(User $user): array
method detachRelationships (line 63) | public function detachRelationships(Model $model, array $data): void
FILE: app/Mcp/Tools/Note/GetNoteTool.php
class GetNoteTool (line 13) | #[Description('Get a single note by ID with full details and relationshi...
method modelClass (line 16) | protected function modelClass(): string
method resourceClass (line 22) | protected function resourceClass(): string
method entityLabel (line 27) | protected function entityLabel(): string
method allowedIncludes (line 33) | protected function allowedIncludes(): array
FILE: app/Mcp/Tools/Note/ListNotesTool.php
class ListNotesTool (line 16) | #[Description('List notes in the CRM with optional search and pagination...
method actionClass (line 21) | protected function actionClass(): string
method resourceClass (line 26) | protected function resourceClass(): string
method searchFilterName (line 31) | protected function searchFilterName(): string
method additionalSchema (line 36) | protected function additionalSchema(JsonSchema $schema): array
method additionalFilters (line 44) | protected function additionalFilters(Request $request): array
FILE: app/Mcp/Tools/Note/UpdateNoteTool.php
class UpdateNoteTool (line 17) | #[Description('Update an existing note in the CRM. Use the crm-schema re...
method modelClass (line 21) | protected function modelClass(): string
method actionClass (line 26) | protected function actionClass(): string
method resourceClass (line 31) | protected function resourceClass(): string
method entityType (line 36) | protected function entityType(): string
method entityLabel (line 41) | protected function entityLabel(): string
method entitySchema (line 46) | protected function entitySchema(JsonSchema $schema): array
method entityRules (line 56) | protected function entityRules(User $user): array
FILE: app/Mcp/Tools/Opportunity/CreateOpportunityTool.php
class CreateOpportunityTool (line 15) | #[Description('Create a new opportunity (deal) in the CRM. Use the crm-s...
method actionClass (line 18) | protected function actionClass(): string
method resourceClass (line 23) | protected function resourceClass(): string
method entityType (line 28) | protected function entityType(): string
method entitySchema (line 33) | protected function entitySchema(JsonSchema $schema): array
method entityRules (line 42) | protected function entityRules(User $user): array
FILE: app/Mcp/Tools/Opportunity/DeleteOpportunityTool.php
class DeleteOpportunityTool (line 13) | #[Description('Delete an opportunity (deal) from the CRM (soft delete).')]
method modelClass (line 17) | protected function modelClass(): string
method actionClass (line 22) | protected function actionClass(): string
method entityLabel (line 27) | protected function entityLabel(): string
FILE: app/Mcp/Tools/Opportunity/GetOpportunityTool.php
class GetOpportunityTool (line 13) | #[Description('Get a single opportunity by ID with full details and rela...
method modelClass (line 16) | protected function modelClass(): string
method resourceClass (line 22) | protected function resourceClass(): string
method entityLabel (line 27) | protected function entityLabel(): string
method allowedIncludes (line 33) | protected function allowedIncludes(): array
FILE: app/Mcp/Tools/Opportunity/ListOpportunitiesTool.php
class ListOpportunitiesTool (line 16) | #[Description('List opportunities (deals) in the CRM with optional searc...
method actionClass (line 21) | protected function actionClass(): string
method resourceClass (line 26) | protected function resourceClass(): string
method searchFilterName (line 31) | protected function searchFilterName(): string
method additionalSchema (line 36) | protected function additionalSchema(JsonSchema $schema): array
method additionalFilters (line 44) | protected function additionalFilters(Request $request): array
FILE: app/Mcp/Tools/Opportunity/UpdateOpportunityTool.php
class UpdateOpportunityTool (line 17) | #[Description('Update an existing opportunity (deal) in the CRM. Use the...
method modelClass (line 21) | protected function modelClass(): string
method actionClass (line 26) | protected function actionClass(): string
method resourceClass (line 31) | protected function resourceClass(): string
method entityType (line 36) | protected function entityType(): string
method entityLabel (line 41) | protected function entityLabel(): string
method entitySchema (line 46) | protected function entitySchema(JsonSchema $schema): array
method entityRules (line 55) | protected function entityRules(User $user): array
FILE: app/Mcp/Tools/People/CreatePeopleTool.php
class CreatePeopleTool (line 15) | #[Description('Create a new person (contact) in the CRM. Use the crm-sch...
method actionClass (line 18) | protected function actionClass(): string
method resourceClass (line 23) | protected function resourceClass(): string
method entityType (line 28) | protected function entityType(): string
method entitySchema (line 33) | protected function entitySchema(JsonSchema $schema): array
method entityRules (line 41) | protected function entityRules(User $user): array
FILE: app/Mcp/Tools/People/DeletePeopleTool.php
class DeletePeopleTool (line 13) | #[Description('Delete a person (contact) from the CRM (soft delete).')]
method modelClass (line 17) | protected function modelClass(): string
method actionClass (line 22) | protected function actionClass(): string
method entityLabel (line 27) | protected function entityLabel(): string
FILE: app/Mcp/Tools/People/GetPeopleTool.php
class GetPeopleTool (line 13) | #[Description('Get a single person by ID with full details and relations...
method modelClass (line 16) | protected function modelClass(): string
method resourceClass (line 22) | protected function resourceClass(): string
method entityLabel (line 27) | protected function entityLabel(): string
method allowedIncludes (line 33) | protected function allowedIncludes(): array
FILE: app/Mcp/Tools/People/ListPeopleTool.php
class ListPeopleTool (line 16) | #[Description('List people (contacts) in the CRM with optional search an...
method actionClass (line 21) | protected function actionClass(): string
method resourceClass (line 26) | protected function resourceClass(): string
method searchFilterName (line 31) | protected function searchFilterName(): string
method additionalSchema (line 36) | protected function additionalSchema(JsonSchema $schema): array
method additionalFilters (line 43) | protected function additionalFilters(Request $request): array
FILE: app/Mcp/Tools/People/UpdatePeopleTool.php
class UpdatePeopleTool (line 17) | #[Description('Update an existing person (contact) in the CRM. Use the c...
method modelClass (line 21) | protected function modelClass(): string
method actionClass (line 26) | protected function actionClass(): string
method resourceClass (line 31) | protected function resourceClass(): string
method entityType (line 36) | protected function entityType(): string
method entityLabel (line 41) | protected function entityLabel(): string
method entitySchema (line 46) | protected function entitySchema(JsonSchema $schema): array
method entityRules (line 54) | protected function entityRules(User $user): array
FILE: app/Mcp/Tools/Task/AttachTaskToEntitiesTool.php
class AttachTaskToEntitiesTool (line 17) | #[Description('Attach a task to companies, people, opportunities, or ass...
method modelClass (line 20) | protected function modelClass(): string
method entityLabel (line 25) | protected function entityLabel(): string
method resourceClass (line 30) | protected function resourceClass(): string
method relationshipsToLoad (line 36) | protected function relationshipsToLoad(): array
method relationshipSchema (line 41) | public function relationshipSchema(JsonSchema $schema): array
method relationshipRules (line 51) | public function relationshipRules(User $user): array
method syncRelationships (line 70) | public function syncRelationships(Model $model, array $data): void
FILE: app/Mcp/Tools/Task/CreateTaskTool.php
class CreateTaskTool (line 16) | #[Description('Create a new task in the CRM. Use the crm-schema resource...
method actionClass (line 19) | protected function actionClass(): string
method resourceClass (line 24) | protected function resourceClass(): string
method entityType (line 29) | protected function entityType(): string
method entitySchema (line 34) | protected function entitySchema(JsonSchema $schema): array
method entityRules (line 45) | protected function entityRules(User $user): array
FILE: app/Mcp/Tools/Task/DeleteTaskTool.php
class DeleteTaskTool (line 13) | #[Description('Delete a task from the CRM (soft delete).')]
method modelClass (line 17) | protected function modelClass(): string
method actionClass (line 22) | protected function actionClass(): string
method entityLabel (line 27) | protected function entityLabel(): string
method nameAttribute (line 32) | protected function nameAttribute(): string
FILE: app/Mcp/Tools/Task/DetachTaskFromEntitiesTool.php
class DetachTaskFromEntitiesTool (line 17) | #[Description('Detach a task from companies, people, opportunities, or u...
method modelClass (line 20) | protected function modelClass(): string
method entityLabel (line 25) | protected function entityLabel(): string
method resourceClass (line 30) | protected function resourceClass(): string
method relationshipsToLoad (line 36) | protected function relationshipsToLoad(): array
method relationshipSchema (line 41) | public function relationshipSchema(JsonSchema $schema): array
method relationshipRules (line 51) | public function relationshipRules(User $user): array
method detachRelationships (line 70) | public function detachRelationships(Model $model, array $data): void
FILE: app/Mcp/Tools/Task/GetTaskTool.php
class GetTaskTool (line 13) | #[Description('Get a single task by ID with full details and relationshi...
method modelClass (line 16) | protected function modelClass(): string
method resourceClass (line 22) | protected function resourceClass(): string
method entityLabel (line 27) | protected function entityLabel(): string
method allowedIncludes (line 33) | protected function allowedIncludes(): array
FILE: app/Mcp/Tools/Task/ListTasksTool.php
class ListTasksTool (line 16) | #[Description('List tasks in the CRM with optional search and pagination...
method actionClass (line 21) | protected function actionClass(): string
method resourceClass (line 26) | protected function resourceClass(): string
method searchFilterName (line 31) | protected function searchFilterName(): string
method additionalSchema (line 36) | protected function additionalSchema(JsonSchema $schema): array
method additionalFilters (line 46) | protected function additionalFilters(Request $request): array
FILE: app/Mcp/Tools/Task/UpdateTaskTool.php
class UpdateTaskTool (line 18) | #[Description('Update an existing task in the CRM. Use the crm-schema re...
method modelClass (line 22) | protected function modelClass(): string
method actionClass (line 27) | protected function actionClass(): string
method resourceClass (line 32) | protected function resourceClass(): string
method entityType (line 37) | protected function entityType(): string
method entityLabel (line 42) | protected function entityLabel(): string
method entitySchema (line 47) | protected function entitySchema(JsonSchema $schema): array
method entityRules (line 58) | protected function entityRules(User $user): array
FILE: app/Mcp/Tools/WhoAmiTool.php
class WhoAmiTool (line 19) | #[Description('Get information about the authenticated user, current tea...
method schema (line 26) | public function schema(JsonSchema $schema): array
method handle (line 31) | public function handle(Request $request): Response
FILE: app/Models/AiSummary.php
class AiSummary (line 14) | final class AiSummary extends Model
method casts (line 38) | protected function casts(): array
method summarizable (line 49) | public function summarizable(): MorphTo
FILE: app/Models/Company.php
class Company (line 36) | #[ObservedBy(CompanyObserver::class)]
method casts (line 73) | protected function casts(): array
method getLogoAttribute (line 80) | protected function getLogoAttribute(): string
method accountOwner (line 92) | public function accountOwner(): BelongsTo
method people (line 100) | public function people(): HasMany
method opportunities (line 108) | public function opportunities(): HasMany
method tasks (line 116) | public function tasks(): MorphToMany
FILE: app/Models/Concerns/BelongsToTeamCreator.php
type BelongsToTeamCreator (line 16) | trait BelongsToTeamCreator
method bootBelongsToTeamCreator (line 18) | public static function bootBelongsToTeamCreator(): void
FILE: app/Models/Concerns/HasAiSummary.php
type HasAiSummary (line 13) | trait HasAiSummary
method aiSummary (line 20) | public function aiSummary(): MorphOne
method invalidateAiSummary (line 28) | public function invalidateAiSummary(): void
FILE: app/Models/Concerns/HasCreator.php
type HasCreator (line 15) | trait HasCreator
method creator (line 20) | public function creator(): BelongsTo
method isSystemCreated (line 28) | public function isSystemCreated(): bool
method createdBy (line 36) | protected function createdBy(): Attribute
FILE: app/Models/Concerns/HasNotes.php
type HasNotes (line 10) | trait HasNotes
method notes (line 15) | public function notes(): MorphToMany
FILE: app/Models/Concerns/HasProfilePhoto.php
type HasProfilePhoto (line 11) | trait HasProfilePhoto
method updateProfilePhoto (line 16) | public function updateProfilePhoto(string $photo): void
method deleteProfilePhoto (line 30) | public function deleteProfilePhoto(): void
method profilePhotoUrl (line 48) | protected function profilePhotoUrl(): Attribute
method defaultProfilePhotoUrl (line 58) | protected function defaultProfilePhotoUrl(): string
method profilePhotoDisk (line 70) | protected function profilePhotoDisk(): string
method getAvatarAttribute (line 75) | protected function getAvatarAttribute(): string
method getFilamentAvatarUrl (line 80) | public function getFilamentAvatarUrl(): string
FILE: app/Models/Concerns/HasTeam.php
type HasTeam (line 10) | trait HasTeam
method team (line 15) | public function team(): BelongsTo
FILE: app/Models/Concerns/InvalidatesRelatedAiSummaries.php
type InvalidatesRelatedAiSummaries (line 11) | trait InvalidatesRelatedAiSummaries
method invalidateRelatedSummaries (line 16) | public function invalidateRelatedSummaries(): void
FILE: app/Models/CustomField.php
class CustomField (line 20) | #[ScopedBy([TenantScope::class, SortOrderScope::class])]
method newFactory (line 27) | protected static function newFactory(): Factory
FILE: app/Models/CustomFieldOption.php
class CustomFieldOption (line 13) | #[ScopedBy([TenantScope::class, SortOrderScope::class])]
FILE: app/Models/CustomFieldSection.php
class CustomFieldSection (line 15) | #[ScopedBy([TenantScope::class, SortOrderScope::class])]
FILE: app/Models/CustomFieldValue.php
class CustomFieldValue (line 12) | #[ScopedBy([TenantScope::class])]
FILE: app/Models/Export.php
class Export (line 12) | final class Export extends FilamentExport
FILE: app/Models/Membership.php
class Membership (line 13) | final class Membership extends JetstreamMembership
method user (line 28) | public function user(): BelongsTo
method team (line 36) | public function team(): BelongsTo
method getRoleNameAttribute (line 41) | protected function getRoleNameAttribute(): string
FILE: app/Models/Note.php
class Note (line 30) | #[ObservedBy(NoteObserver::class)]
method casts (line 66) | protected function casts(): array
method companies (line 76) | public function companies(): MorphToMany
method people (line 84) | public function people(): MorphToMany
method opportunities (line 92) | public function opportunities(): MorphToMany
method forNotableType (line 98) | #[Scope]
method forNotableId (line 115) | #[Scope]
FILE: app/Models/Opportunity.php
class Opportunity (line 31) | #[ObservedBy(OpportunityObserver::class)]
method casts (line 69) | protected function casts(): array
method company (line 79) | public function company(): BelongsTo
method contact (line 87) | public function contact(): BelongsTo
method tasks (line 95) | public function tasks(): MorphToMany
FILE: app/Models/People.php
class People (line 31) | #[ObservedBy(PeopleObserver::class)]
method casts (line 69) | protected function casts(): array
method getAvatarAttribute (line 76) | protected function getAvatarAttribute(): string
method company (line 84) | public function company(): BelongsTo
method tasks (line 92) | public function tasks(): MorphToMany
FILE: app/Models/PersonalAccessToken.php
class PersonalAccessToken (line 12) | class PersonalAccessToken extends SanctumPersonalAccessToken
method booted (line 22) | protected static function booted(): void
method team (line 50) | public function team(): BelongsTo
FILE: app/Models/Scopes/TeamScope.php
class TeamScope (line 15) | final class TeamScope implements Scope
method apply (line 22) | public function apply(Builder $builder, Model $model): void
FILE: app/Models/Task.php
class Task (line 36) | #[ObservedBy(TaskObserver::class)]
method casts (line 70) | protected function casts(): array
method assignees (line 88) | public function assignees(): BelongsToMany
method companies (line 96) | public function companies(): MorphToMany
method opportunities (line 104) | public function opportunities(): MorphToMany
method people (line 112) | public function people(): MorphToMany
method forCompany (line 118) | #[Scope]
method forPerson (line 125) | #[Scope]
method forOpportunity (line 132) | #[Scope]
FILE: app/Models/Team.php
class Team (line 25) | final class Team extends JetstreamTeam implements HasAvatar
method casts (line 119) | protected function casts(): array
method getSlugOptions (line 126) | public function getSlugOptions(): SlugOptions
method otherRecordExistsWithSlug (line 143) | protected function otherRecordExistsWithSlug(string $slug): bool
method isPersonalTeam (line 159) | public function isPersonalTeam(): bool
method getFilamentAvatarUrl (line 164) | public function getFilamentAvatarUrl(): string
method people (line 172) | public function people(): HasMany
method companies (line 180) | public function companies(): HasMany
method tasks (line 188) | public function tasks(): HasMany
method opportunities (line 196) | public function opportunities(): HasMany
method notes (line 204) | public function notes(): HasMany
FILE: app/Models/TeamInvitation.php
class TeamInvitation (line 14) | final class TeamInvitation extends JetstreamTeamInvitation
method team (line 35) | public function team(): BelongsTo
method isExpired (line 40) | public function isExpired(): bool
method casts (line 55) | protected function casts(): array
FILE: app/Models/User.php
class User (line 41) | final class User extends Authenticatable implements FilamentUser, HasAva...
method casts (line 91) | protected function casts(): array
method socialAccounts (line 102) | public function socialAccounts(): HasMany
method hasPassword (line 107) | public function hasPassword(): bool
method tasks (line 115) | public function tasks(): BelongsToMany
method opportunities (line 123) | public function opportunities(): HasMany
method getDefaultTenant (line 128) | public function getDefaultTenant(Panel $panel): ?Model
method canAccessPanel (line 136) | public function canAccessPanel(Panel $panel): bool
method getTenants (line 144) | public function getTenants(Panel $panel): Collection
method canAccessTenant (line 149) | public function canAccessTenant(Model $tenant): bool
FILE: app/Models/UserSocialAccount.php
class UserSocialAccount (line 13) | final class UserSocialAccount extends Model
method user (line 23) | public function user(): BelongsTo
FILE: app/Observers/CompanyObserver.php
class CompanyObserver (line 11) | final readonly class CompanyObserver
method saved (line 13) | public function saved(Company $company): void
method dispatchFaviconFetchIfNeeded (line 19) | private function dispatchFaviconFetchIfNeeded(Company $company): void
FILE: app/Observers/NoteObserver.php
class NoteObserver (line 9) | final readonly class NoteObserver
method saved (line 11) | public function saved(Note $note): void
method deleted (line 16) | public function deleted(Note $note): void
FILE: app/Observers/OpportunityObserver.php
class OpportunityObserver (line 9) | final readonly class OpportunityObserver
method saved (line 15) | public function saved(Opportunity $opportunity): void
FILE: app/Observers/PeopleObserver.php
class PeopleObserver (line 9) | final readonly class PeopleObserver
method saved (line 15) | public function saved(People $people): void
FILE: app/Observers/TaskObserver.php
class TaskObserver (line 9) | final readonly class TaskObserver
method saved (line 11) | public function saved(Task $task): void
method deleted (line 16) | public function deleted(Task $task): void
FILE: app/Policies/CompanyPolicy.php
class CompanyPolicy (line 12) | final readonly class CompanyPolicy
method viewAny (line 16) | public function viewAny(User $user): bool
method view (line 21) | public function view(User $user, Company $company): bool
method create (line 26) | public function create(User $user): bool
method update (line 31) | public function update(User $user, Company $company): bool
method delete (line 36) | public function delete(User $user, Company $company): bool
method deleteAny (line 41) | public function deleteAny(User $user): bool
method restore (line 46) | public function restore(User $user, Company $company): bool
method restoreAny (line 51) | public function restoreAny(User $user): bool
method forceDelete (line 56) | public function forceDelete(User $user): bool
method forceDeleteAny (line 61) | public function forceDeleteAny(User $user): bool
FILE: app/Policies/NotePolicy.php
class NotePolicy (line 12) | final readonly class NotePolicy
method viewAny (line 16) | public function viewAny(User $user): bool
method view (line 21) | public function view(User $user, Note $note): bool
method create (line 26) | public function create(User $user): bool
method update (line 31) | public function update(User $user, Note $note): bool
method delete (line 36) | public function delete(User $user, Note $note): bool
method deleteAny (line 41) | public function deleteAny(User $user): bool
method restore (line 46) | public function restore(User $user, Note $note): bool
method restoreAny (line 51) | public function restoreAny(User $user): bool
method forceDelete (line 56) | public function forceDelete(User $user): bool
method forceDeleteAny (line 61) | public function forceDeleteAny(User $user): bool
FILE: app/Policies/OpportunityPolicy.php
class OpportunityPolicy (line 12) | final readonly class OpportunityPolicy
method viewAny (line 16) | public function viewAny(User $user): bool
method view (line 21) | public function view(User $user, Opportunity $opportunity): bool
method create (line 26) | public function create(User $user): bool
method update (line 31) | public function update(User $user, Opportunity $opportunity): bool
method delete (line 36) | public function delete(User $user, Opportunity $opportunity): bool
method deleteAny (line 41) | public function deleteAny(User $user): bool
method restore (line 46) | public function restore(User $user, Opportunity $opportunity): bool
method restoreAny (line 51) | public function restoreAny(User $user): bool
method forceDelete (line 56) | public function forceDelete(User $user): bool
method forceDeleteAny (line 61) | public function forceDeleteAny(User $user): bool
FILE: app/Policies/PeoplePolicy.php
class PeoplePolicy (line 12) | final readonly class PeoplePolicy
method viewAny (line 16) | public function viewAny(User $user): bool
method view (line 21) | public function view(User $user, People $people): bool
method create (line 26) | public function create(User $user): bool
method update (line 31) | public function update(User $user, People $people): bool
method delete (line 36) | public function delete(User $user, People $people): bool
method deleteAny (line 41) | public function deleteAny(User $user): bool
method restore (line 46) | public function restore(User $user, People $people): bool
method restoreAny (line 51) | public function restoreAny(User $user): bool
method forceDelete (line 56) | public function forceDelete(User $user, People $people): bool
method forceDeleteAny (line 61) | public function forceDeleteAny(User $user): bool
FILE: app/Policies/TaskPolicy.php
class TaskPolicy (line 12) | final readonly class TaskPolicy
method viewAny (line 16) | public function viewAny(User $user): bool
method view (line 21) | public function view(User $user, Task $task): bool
method create (line 26) | public function create(User $user): bool
method update (line 31) | public function update(User $user, Task $task): bool
method delete (line 36) | public function delete(User $user, Task $task): bool
method deleteAny (line 41) | public function deleteAny(User $user): bool
method restore (line 46) | public function restore(User $user, Task $task): bool
method restoreAny (line 51) | public function restoreAny(User $user): bool
method forceDelete (line 56) | public function forceDelete(User $user, Task $task): bool
method forceDeleteAny (line 61) | public function forceDeleteAny(User $user): bool
FILE: app/Policies/TeamPolicy.php
class TeamPolicy (line 11) | final readonly class TeamPolicy
method viewAny (line 18) | public function viewAny(User $user): bool
method view (line 26) | public function view(User $user, Team $team): bool
method create (line 34) | public function create(User $user): bool
method update (line 42) | public function update(User $user, Team $team): bool
method addTeamMember (line 50) | public function addTeamMember(User $user, Team $team): bool
method updateTeamMember (line 58) | public function updateTeamMember(User $user, Team $team): bool
method removeTeamMember (line 66) | public function removeTeamMember(User $user, Team $team): bool
method delete (line 74) | public function delete(User $user, Team $team): bool
method deleteAny (line 79) | public function deleteAny(): bool
method restore (line 84) | public function restore(User $user, Team $team): bool
method restoreAny (line 89) | public function restoreAny(): bool
method forceDelete (line 94) | public function forceDelete(User $user, Team $team): bool
method forceDeleteAny (line 99) | public function forceDeleteAny(): bool
FILE: app/Providers/AppServiceProvider.php
class AppServiceProvider (line 39) | final class AppServiceProvider extends ServiceProvider
method register (line 44) | public function register(): void
method boot (line 53) | public function boot(): void
method configurePolicies (line 66) | private function configurePolicies(): void
method getDefaultLaravelPolicyName (line 90) | private function getDefaultLaravelPolicyName(string $modelClass): ?string
method configureLivewire (line 122) | private function configureLivewire(): void
method configureRateLimiting (line 127) | private function configureRateLimiting(): void
method configureScribe (line 152) | private function configureScribe(): void
method configureModels (line 190) | private function configureModels(): void
method configureFilament (line 216) | private function configureFilament(): void
method configureGitHubStars (line 232) | private function configureGitHubStars(): void
FILE: app/Providers/FaviconServiceProvider.php
class FaviconServiceProvider (line 12) | final class FaviconServiceProvider extends ServiceProvider
method boot (line 14) | public function boot(): void
FILE: app/Providers/Filament/AppPanelProvider.php
class AppPanelProvider (line 51) | final class AppPanelProvider extends PanelProvider
method boot (line 56) | public function boot(): void
method panel (line 77) | public function panel(Panel $panel): Panel
method shouldRegisterMenuItem (line 217) | public function shouldRegisterMenuItem(): bool
FILE: app/Providers/FortifyServiceProvider.php
class FortifyServiceProvider (line 19) | final class FortifyServiceProvider extends ServiceProvider
method register (line 24) | public function register(): void
method boot (line 32) | public function boot(): void
FILE: app/Providers/HealthServiceProvider.php
class HealthServiceProvider (line 26) | final class HealthServiceProvider extends ServiceProvider
method boot (line 28) | public function boot(): void
method isEnabled (line 93) | private function isEnabled(): bool
FILE: app/Providers/HorizonServiceProvider.php
class HorizonServiceProvider (line 12) | final class HorizonServiceProvider extends HorizonApplicationServiceProv...
method boot (line 17) | #[Override]
method gate (line 32) | protected function gate(): void
FILE: app/Providers/JetstreamServiceProvider.php
class JetstreamServiceProvider (line 19) | final class JetstreamServiceProvider extends ServiceProvider
method register (line 24) | public function register(): void
method boot (line 32) | public function boot(): void
method configureModels (line 42) | private function configureModels(): void
method configureActions (line 51) | private function configureActions(): void
method configurePermissions (line 65) | private function configurePermissions(): void
FILE: app/Providers/MacroServiceProvider.php
class MacroServiceProvider (line 10) | final class MacroServiceProvider extends ServiceProvider
method boot (line 12) | public function boot(): void
FILE: app/Rules/ValidCustomFields.php
class ValidCustomFields (line 18) | final readonly class ValidCustomFields implements ValidationRule
method __construct (line 20) | public function __construct(
method toRules (line 30) | public function toRules(mixed $submittedFields = null): array
method validate (line 69) | public function validate(string $attribute, mixed $value, Closure $fai...
method ensureNullableForDateFields (line 103) | private function ensureNullableForDateFields(string $fieldType, array ...
method addChoiceFieldOptionRules (line 127) | private function addChoiceFieldOptionRules(BaseCustomField $customFiel...
method resolveCustomFields (line 163) | private function resolveCustomFields(array $submittedCodes): EloquentC...
FILE: app/Rules/ValidTeamSlug.php
class ValidTeamSlug (line 12) | final readonly class ValidTeamSlug implements ValidationRule
method __construct (line 14) | public function __construct(
method validate (line 21) | public function validate(string $attribute, mixed $value, Closure $fai...
FILE: app/Scribe/Strategies/GetFromSpatieQueryBuilder.php
class GetFromSpatieQueryBuilder (line 20) | final class GetFromSpatieQueryBuilder extends Strategy
method __invoke (line 26) | public function __invoke(ExtractedEndpointData $endpointData, array $r...
method isIndexMethod (line 41) | private function isIndexMethod(ExtractedEndpointData $endpointData): bool
method findActionClass (line 51) | private function findActionClass(ExtractedEndpointData $endpointData):...
method extractQueryParams (line 78) | private function extractQueryParams(string $actionClass): array
method getMethodSource (line 98) | private function getMethodSource(ReflectionMethod $method): string
method extractFilters (line 121) | private function extractFilters(string $source, array &$params): void
method extractSorts (line 138) | private function extractSorts(string $source, array &$params): void
method extractIncludes (line 159) | private function extractIncludes(string $source, array &$params): void
method addPaginationParams (line 180) | private function addPaginationParams(array &$params): void
FILE: app/Services/AI/RecordContextBuilder.php
class RecordContextBuilder (line 25) | final readonly class RecordContextBuilder
method buildContext (line 34) | public function buildContext(Model $record): array
method buildCompanyContext (line 47) | private function buildCompanyContext(Company $company): array
method buildPeopleContext (line 78) | private function buildPeopleContext(People $person): array
method buildOpportunityContext (line 104) | private function buildOpportunityContext(Opportunity $opportunity): array
method recentWithCustomFields (line 129) | private function recentWithCustomFields(string $table): Closure
method getCompanyBasicInfo (line 140) | private function getCompanyBasicInfo(Company $company): array
method getPeopleBasicInfo (line 154) | private function getPeopleBasicInfo(People $person): array
method getOpportunityBasicInfo (line 167) | private function getOpportunityBasicInfo(Opportunity $opportunity): array
method getOpportunityName (line 179) | private function getOpportunityName(Opportunity $opportunity): string
method formatNotes (line 190) | private function formatNotes(Collection $notes, int $totalCount): array
method formatTasks (line 205) | private function formatTasks(Collection $tasks, int $totalCount): array
method formatOpportunities (line 221) | private function formatOpportunities(Collection $opportunities, int $t...
method withPaginationInfo (line 239) | private function withPaginationInfo(array $items, int $totalCount): array
method getCustomFieldValue (line 251) | private function getCustomFieldValue(Model $model, string $code): mixed
method formatDate (line 269) | private function formatDate(mixed $date): ?string
method stripHtml (line 280) | private function stripHtml(string $html): string
FILE: app/Services/AI/RecordSummaryService.php
class RecordSummaryService (line 17) | final readonly class RecordSummaryService
method __construct (line 19) | public function __construct(
method model (line 23) | private function model(): string
method getSummary (line 31) | public function getSummary(Model $record, bool $regenerate = false): A...
method generateAndCacheSummary (line 44) | private function generateAndCacheSummary(Model $record): AiSummary
method cacheSummary (line 58) | private function cacheSummary(Model $record, string $summary, Usage $u...
method getSystemPrompt (line 79) | private function getSystemPrompt(): string
method formatPrompt (line 99) | private function formatPrompt(array $context): string
method addBasicInfo (line 121) | private function addBasicInfo(Collection $parts, array $context): void
method addRelationships (line 146) | private function addRelationships(Collection $parts, array $context): ...
method addOpportunities (line 162) | private function addOpportunities(Collection $parts, array $context): ...
method addNotes (line 188) | private function addNotes(Collection $parts, array $context): void
method addTasks (line 215) | private function addTasks(Collection $parts, array $context): void
method formatTaskLine (line 238) | private function formatTaskLine(array $task): string
method addTimestamps (line 259) | private function addTimestamps(Collection $parts, array $context): void
method formatLabel (line 268) | private function formatLabel(string $key): string
FILE: app/Services/AvatarService.php
class AvatarService (line 10) | final readonly class AvatarService
method __construct (line 20) | public function __construct(
method generate (line 38) | public function generate(
method generateAuto (line 68) | public function generateAuto(string $name, int $size = 64, int $initia...
method createSvgDataUrl (line 104) | private function createSvgDataUrl(
method validateColor (line 128) | public function validateColor(?string $color): bool
method getInitials (line 151) | private function getInitials(string $name, int $initialCount = 2): string
method getBackgroundColor (line 222) | private function getBackgroundColor(string $name): string
method generateSvg (line 244) | private function generateSvg(string $initials, string $bgColor, string...
method getHueFromName (line 264) | private function getHueFromName(string $name): int
method generateContrastingTextColor (line 282) | private function generateContrastingTextColor(string $bgColor): string
method hslToHex (line 303) | private function hslToHex(int $h, float $s, float $l): string
method hexToHsl (line 329) | private function hexToHsl(string $hexColor): array
method hueToRgb (line 381) | private function hueToRgb(float $p, float $q, float $t): float
method calculateContrastRatio (line 405) | private function calculateContrastRatio(string $color1, string $color2...
method getRelativeLuminance (line 419) | private function getRelativeLuminance(string $hexColor): float
method hasEnoughContrast (line 446) | private function hasEnoughContrast(string $color1, string $color2): bool
method analyzeNameCharacteristics (line 454) | private function analyzeNameCharacteristics(string $name): array
method calculateUniquenessScore (line 504) | private function calculateUniquenessScore(string $name): float
FILE: app/Services/Favicon/Drivers/GoogleHighResDriver.php
class GoogleHighResDriver (line 15) | final class GoogleHighResDriver implements Fetcher
method __construct (line 23) | public function __construct(private readonly int $size = 256) {}
method fetch (line 25) | public function fetch(string $url): ?Favicon
method fetchAll (line 45) | public function fetchAll(string $url): FaviconCollection
FILE: app/Services/Favicon/Drivers/HighQualityDriver.php
class HighQualityDriver (line 16) | final class HighQualityDriver implements Fetcher
method fetch (line 31) | public function fetch(string $url): ?Favicon
method fetchAll (line 57) | public function fetchAll(string $url): FaviconCollection
method tryAppleTouchIcon (line 62) | private function tryAppleTouchIcon(string $url): ?Favicon
method tryHighResFavicon (line 106) | private function tryHighResFavicon(string $url): ?Favicon
method tryGoogleHighRes (line 156) | private function tryGoogleHighRes(string $url): ?Favicon
method tryDuckDuckGo (line 182) | private function tryDuckDuckGo(string $url): ?Favicon
method faviconIsAccessible (line 207) | private function faviconIsAccessible(Favicon $favicon): bool
method convertToAbsoluteUrl (line 219) | private function convertToAbsoluteUrl(string $baseUrl, string $path): ...
method stripPathFromUrl (line 240) | private function stripPathFromUrl(string $url): string
FILE: app/Services/GitHubService.php
class GitHubService (line 14) | final readonly class GitHubService
method getStarsCount (line 23) | public function getStarsCount(string $owner = 'Relaticle', string $rep...
method getFormattedStarsCount (line 56) | public function getFormattedStarsCount(string $owner = 'Relaticle', st...
FILE: app/Support/CustomFieldMerger.php
class CustomFieldMerger (line 19) | final readonly class CustomFieldMerger
method merge (line 25) | public static function merge(Model $model, array $attributes): array
method normalizeValue (line 59) | private static function normalizeValue(mixed $value): mixed
FILE: app/View/Components/GuestLayout.php
class GuestLayout (line 11) | final class GuestLayout extends Component
method __construct (line 16) | public function __construct(
method render (line 27) | #[Override]
FILE: database/factories/CompanyFactory.php
class CompanyFactory (line 17) | final class CompanyFactory extends Factory
method definition (line 26) | public function definition(): array
method configure (line 35) | public function configure(): Factory
FILE: database/factories/CustomFieldFactory.php
class CustomFieldFactory (line 14) | final class CustomFieldFactory extends Factory
method definition (line 18) | public function definition(): array
method configure (line 35) | public function configure(): static
FILE: database/factories/NoteFactory.php
class NoteFactory (line 16) | final class NoteFactory extends Factory
method definition (line 23) | public function definition(): array
method configure (line 31) | public function configure(): Factory
FILE: database/factories/OpportunityFactory.php
class OpportunityFactory (line 16) | final class OpportunityFactory extends Factory
method definition (line 20) | public function definition(): array
method configure (line 28) | public function configure(): Factory
FILE: database/factories/PeopleFactory.php
class PeopleFactory (line 16) | final class PeopleFactory extends Factory
method definition (line 23) | public function definition(): array
method configure (line 31) | public function configure(): Factory
FILE: database/factories/SystemAdministratorFactory.php
class SystemAdministratorFactory (line 17) | final class SystemAdministratorFactory extends Factory
method definition (line 26) | public function definition(): array
method unverified (line 41) | public function unverified(): static
method configure (line 48) | public function configure(): Factory
FILE: database/factories/TaskFactory.php
class TaskFactory (line 17) | final class TaskFactory extends Factory
method definition (line 21) | public function definition(): array
method configure (line 31) | public function configure(): Factory
FILE: database/factories/TeamFactory.php
class TeamFactory (line 16) | final class TeamFactory extends Factory
method definition (line 23) | public function definition(): array
method configure (line 32) | public function configure(): static
FILE: database/factories/TeamInvitationFactory.php
class TeamInvitationFactory (line 14) | final class TeamInvitationFactory extends Factory
method definition (line 21) | public function definition(): array
method expired (line 31) | public function expired(): static
method expiresIn (line 38) | public function expiresIn(int $days): static
method withoutExpiry (line 45) | public function withoutExpiry(): static
FILE: database/factories/UserFactory.php
class UserFactory (line 17) | final class UserFactory extends Factory
method definition (line 29) | #[\Override]
method unverified (line 48) | public function unverified(): static
method withPersonalTeam (line 58) | public function withPersonalTeam(?callable $callback = null): UserFactory
method withTeam (line 79) | public function withTeam(?callable $callback = null): static
method socialOnly (line 97) | public function socialOnly(): static
method configure (line 104) | public function configure(): Factory
FILE: database/factories/UserSocialAccountFactory.php
class UserSocialAccountFactory (line 15) | final class UserSocialAccountFactory extends Factory
method definition (line 24) | public function definition(): array
method configure (line 33) | public function configure(): Factory
FILE: database/migrations/0001_01_01_000000_create_users_table.php
method up (line 14) | public function up(): void
method down (line 47) | public function down(): void
FILE: database/migrations/0001_01_01_000001_create_cache_table.php
method up (line 14) | public function up(): void
method down (line 32) | public function down(): void
FILE: database/migrations/0001_01_01_000002_create_jobs_table.php
method up (line 14) | public function up(): void
method down (line 53) | public function down(): void
FILE: database/migrations/2024_08_23_110718_create_teams_table.php
method up (line 14) | public function up(): void
method down (line 28) | public function down(): void
FILE: database/migrations/2024_08_23_110719_create_team_user_table.php
method up (line 14) | public function up(): void
method down (line 30) | public function down(): void
FILE: database/migrations/2024_08_23_110720_create_team_invitations_table.php
method up (line 14) | public function up(): void
method down (line 30) | public function down(): void
FILE: database/migrations/2024_08_24_133803_create_companies_table.php
method up (line 11) | public function up(): void
FILE: database/migrations/2024_09_11_114549_create_tasks_table.php
method up (line 11) | public function up(): void
FILE: database/migrations/2024_09_22_084119_create_notes_table.php
method up (line 11) | public function up(): void
FILE: database/migrations/2024_09_22_091034_create_people_table.php
method up (line 11) | public function up(): void
FILE: database/migrations/2024_09_22_092300_create_task_user_table.php
method up (line 14) | public function up(): void
method down (line 29) | public function down(): void
FILE: database/migrations/2024_09_22_110651_add_two_factor_columns_to_users_table.php
method up (line 15) | public function up(): void
method down (line 37) | public function down(): void
FILE: database/migrations/2024_09_22_110718_create_personal_access_tokens_table.php
method up (line 14) | public function up(): void
method down (line 31) | public function down(): void
FILE: database/migrations/2024_09_22_114735_create_opportunities_table.php
method up (line 11) | public function up(): void
FILE: database/migrations/2024_09_26_160649_create_user_social_accounts_table.php
method up (line 14) | public function up(): void
method down (line 35) | public function down(): void
FILE: database/migrations/2024_09_26_170133_create_notifications_table.php
method up (line 14) | public function up(): void
method down (line 29) | public function down(): void
FILE: database/migrations/2025_02_07_192236_create_custom_fields_table.php
method up (line 13) | public function up(): void
method down (line 159) | public function down(): void
FILE: database/migrations/2025_03_15_180559_create_taskables_table.php
method up (line 14) | public function up(): void
method down (line 30) | public function down(): void
FILE: database/migrations/2025_03_15_192334_create_notables_table.php
method up (line 14) | public function up(): void
method down (line 30) | public function down(): void
FILE: database/migrations/2025_03_17_180206_create_media_table.php
method up (line 11) | public function up(): void
FILE: database/migrations/2025_04_30_143551_add_creation_source_to_entity_tables.php
method up (line 22) | public function up(): void
FILE: database/migrations/2025_05_08_112613_create_imports_table.php
method up (line 14) | public function up(): void
method down (line 36) | public function down(): void
FILE: database/migrations/2025_05_08_112614_create_exports_table.php
method up (line 14) | public function up(): void
method down (line 36) | public function down(): void
FILE: database/migrations/2025_05_08_112615_create_failed_import_rows_table.php
method up (line 14) | public function up(): void
method down (line 31) | public function down(): void
FILE: database/migrations/2025_07_05_093310_update_opportunity_amount_field_type_to_currency.php
method up (line 13) | public function up(): void
method shouldRun (line 42) | public function shouldRun(): bool
FILE: database/migrations/2025_08_12_202409_add_settings_to_custom_field_options_table.php
method up (line 14) | public function up(): void
method shouldRun (line 24) | public function shouldRun(): bool
method down (line 32) | public function down(): void
FILE: database/migrations/2025_08_25_173222_update_order_column_to_flowforge_position_for_tasks_and_opportunities.php
method up (line 16) | public function up(): void
method setTaskOrderColumns (line 46) | private function setTaskOrderColumns(): void
method setOpportunityOrderColumns (line 83) | private function setOpportunityOrderColumns(): void
method setPositionsForGroup (line 123) | private function setPositionsForGroup(array $records, string $table): void
method down (line 168) | public function down(): void
FILE: database/migrations/2025_08_26_124042_create_system_administrators_table.php
method up (line 14) | public function up(): void
method down (line 36) | public function down(): void
FILE: database/migrations/2025_11_30_202612_create_ai_summaries_table.php
method up (line 14) | public function up(): void
method down (line 33) | public function down(): void
FILE: database/migrations/2025_12_10_191207_update_people_emails_field_type_to_email.php
method up (line 19) | public function up(): void
FILE: database/migrations/2025_12_11_000001_update_company_domain_name_settings.php
method up (line 20) | public function up(): void
FILE: database/migrations/2025_12_20_000000_migrate_to_ulid.php
method up (line 107) | public function up(): void
method migrateForRelationalDb (line 138) | private function migrateForRelationalDb(): void
method phaseA_addUlidToCoreTables (line 223) | private function phaseA_addUlidToCoreTables(): void
method phaseA_addForeignUlidsToCoreTablesAndPopulate (line 246) | private function phaseA_addForeignUlidsToCoreTablesAndPopulate(): void
method phaseA_addUlidsToOtherEntityTables (line 282) | private function phaseA_addUlidsToOtherEntityTables(): void
method phaseA_addUlidsToPivotTables (line 321) | private function phaseA_addUlidsToPivotTables(): void
method phaseA_addUlidsToPolymorphicTables (line 344) | private function phaseA_addUlidsToPolymorphicTables(): void
method phaseA_addUlidsToTenantScopedTables (line 365) | private function phaseA_addUlidsToTenantScopedTables(): void
method phaseA_addUlidsToCustomFieldTables (line 386) | private function phaseA_addUlidsToCustomFieldTables(): void
method phaseA7b_migrateOptionValueReferences (line 411) | private function phaseA7b_migrateOptionValueReferences(): void
method phaseA8_migrateEmailFieldValues (line 457) | private function phaseA8_migrateEmailFieldValues(): void
method phaseA9_migrateDomainFieldValues (line 509) | private function phaseA9_migrateDomainFieldValues(): void
method phaseB_dropAllForeignKeyConstraints (line 574) | private function phaseB_dropAllForeignKeyConstraints(): void
method phaseB_cutoverCorePrimaryKeys (line 646) | private function phaseB_cutoverCorePrimaryKeys(): void
method phaseB_cutoverCoreForeignKeys (line 656) | private function phaseB_cutoverCoreForeignKeys(): void
method phaseB_cutoverOtherEntityTables (line 692) | private function phaseB_cutoverOtherEntityTables(): void
method phaseB_cutoverPivotTables (line 718) | private function phaseB_cutoverPivotTables(): void
method phaseB_cutoverPolymorphicTables (line 740) | private function phaseB_cutoverPolymorphicTables(): void
method phaseB_cutoverTenantScopedTables (line 752) | private function phaseB_cutoverTenantScopedTables(): void
method phaseB_cutoverCustomFieldTables (line 764) | private function phaseB_cutoverCustomFieldTables(): void
method phaseB_recreateUniqueIndexes (line 779) | private function phaseB_recreateUniqueIndexes(): void
method phaseB9_recreateForeignKeyConstraints (line 823) | private function phaseB9_recreateForeignKeyConstraints(): void
method addUlidPrimaryKeyColumn (line 945) | private function addUlidPrimaryKeyColumn(string $tableName): void
method addAndPopulateForeignUlid (line 964) | private function addAndPopulateForeignUlid(string $tableName, string $fk...
method addAndPopulateMorphUlid (line 988) | private function addAndPopulateMorphUlid(string $tableName, string $morp...
method cutoverPrimaryKey (line 1058) | private function cutoverPrimaryKey(string $table): void
method cutoverForeignKeyColumn (line 1088) | private function cutoverForeignKeyColumn(string $tableName, string $fkCo...
method cutoverMorphColumn (line 1106) | private function cutoverMorphColumn(string $tableName, string $morphName...
method migrateForSqlite (line 1145) | private function migrateForSqlite(): void
method rebuildTableWithUlidPrimarySqlite (line 1188) | private function rebuildTableWithUlidPrimarySqlite(string $tableName): void
method rebuildPivotTableSqlite (line 1238) | private function rebuildPivotTableSqlite(string $tableName, array $forei...
method rebuildPivotWithMorphSqlite (line 1267) | private function rebuildPivotWithMorphSqlite(string $tableName, string $...
method rebuildMorphTableSqlite (line 1291) | private function rebuildMorphTableSqlite(string $tableName, string $morp...
method rebuildForeignKeysSqlite (line 1317) | private function rebuildForeignKeysSqlite(string $tableName, array $fore...
method isAlreadyUlid (line 1345) | private function isAlreadyUlid(string $table, string $column): bool
FILE: database/migrations/2025_12_27_122241_convert_order_column_to_decimal_and_regenerate_positions.php
method up (line 16) | public function up(): void
method regenerateTaskPositions (line 46) | private function regenerateTaskPositions(): void
method regenerateOpportunityPositions (line 84) | private function regenerateOpportunityPositions(): void
method setPositionsForGroup (line 125) | private function setPositionsForGroup(array $records, string $table): void
method down (line 147) | public function down(): void
FILE: database/migrations/2026_01_02_152157_update_phone_number_custom_fields_type.php
method up (line 11) | public function up(): void
FILE: database/migrations/2026_01_12_225824_upgrade_custom_fields_to_v3.php
method up (line 10) | public function up(): void
FILE: database/migrations/2026_02_11_232804_add_slug_to_teams_table.php
method up (line 13) | public function up(): void
method backfillSlugs (line 26) | private function backfillSlugs(): void
FILE: database/migrations/2026_02_12_222910_expand_imports_table.php
method up (line 11) | public function up(): void
FILE: database/migrations/2026_02_13_002721_cleanup_imports_table.php
method up (line 11) | public function up(): void
FILE: database/migrations/2026_02_15_214730_drop_sessions_user_id_foreign_key.php
method up (line 11) | public function up(): void
FILE: database/migrations/2026_02_20_212853_add_team_id_to_personal_access_tokens_table.php
method up (line 12) | public function up(): void
method ensureTeamsPrimaryKey (line 25) | private function ensureTeamsPrimaryKey(): void
FILE: database/migrations/2026_02_25_124942_add_team_id_indexes_to_entity_tables.php
method up (line 14) | public function up(): void
FILE: database/migrations/2026_03_15_201741_add_custom_field_value_filtering_indexes.php
method up (line 11) | public function up(): void
FILE: database/migrations/2026_03_18_202956_add_expires_at_to_team_invitations_table.php
method up (line 11) | public function up(): void
FILE: database/seeders/DatabaseSeeder.php
class DatabaseSeeder (line 10) | final class DatabaseSeeder extends Seeder
method run (line 15) | public function run(): void
FILE: database/seeders/LocalSeeder.php
class LocalSeeder (line 17) | final class LocalSeeder extends Seeder
method run (line 19) | public function run(): void
FILE: database/seeders/SystemAdministratorSeeder.php
class SystemAdministratorSeeder (line 11) | final class SystemAdministratorSeeder extends Seeder
method run (line 16) | public function run(): void
FILE: packages/Documentation/resources/js/documentation.js
function addCopyButtons (line 2) | function addCopyButtons() {
function adjustSidebarHeights (line 150) | function adjustSidebarHeights() {
FILE: packages/Documentation/src/Components/Card.php
class Card (line 10) | final class Card extends Component
method __construct (line 15) | public function __construct(
method render (line 29) | public function render(): View
FILE: packages/Documentation/src/Data/DocumentData.php
class DocumentData (line 11) | final class DocumentData extends Data
method __construct (line 13) | public function __construct(
method fromType (line 32) | public static function fromType(string $type): self
method extractTableOfContents (line 75) | private static function extractTableOfContents(string $contents): array
method getMarkdownPath (line 91) | private static function getMarkdownPath(string $file): string
FILE: packages/Documentation/src/Data/DocumentSearchRequest.php
class DocumentSearchRequest (line 13) | final class DocumentSearchRequest extends Data
method __construct (line 15) | public function __construct(
method rules (line 27) | public static function rules(): array
FILE: packages/Documentation/src/Data/DocumentSearchResultData.php
class DocumentSearchResultData (line 12) | final class DocumentSearchResultData extends Data
method __construct (line 14) | public function __construct(
method generateUrl (line 35) | public static function generateUrl(string $type): string
FILE: packages/Documentation/src/DocumentationServiceProvider.php
class DocumentationServiceProvider (line 12) | final class DocumentationServiceProvider extends ServiceProvider
method register (line 17) | public function register(): void
method boot (line 27) | public function boot(): void
method registerRoutes (line 38) | private function registerRoutes(): void
method registerViews (line 49) | private function registerViews(): void
method registerComponents (line 57) | private function registerComponents(): void
method registerPublishing (line 69) | private function registerPublishing(): void
FILE: packages/Documentation/src/Http/Controllers/DocumentationController.php
class DocumentationController (line 12) | final readonly class DocumentationController
method __construct (line 14) | public function __construct(
method index (line 21) | public function index(): View
method show (line 31) | public function show(string $type = 'business'): View
method search (line 48) | public function search(Request $request): View
FILE: packages/Documentation/src/Services/DocumentationService.php
class DocumentationService (line 14) | final class DocumentationService
method getDocument (line 19) | public function getDocument(string $type): DocumentData
method getAllDocumentTypes (line 37) | public function getAllDocumentTypes(): array
method search (line 47) | public function search(DocumentSearchRequest $searchRequest): Collection
method generateExcerpt (line 108) | private function generateExcerpt(string $content, string $query): string
method calculateRelevance (line 141) | private function calculateRelevance(string $content, string $query): f...
method getMarkdownPath (line 165) | private function getMarkdownPath(string $file): string
FILE: packages/ImportWizard/src/Commands/CleanupImportsCommand.php
class CleanupImportsCommand (line 13) | final class CleanupImportsCommand extends Command
method handle (line 21) | public function handle(): void
method cleanupTerminalImportFiles (line 34) | private function cleanupTerminalImportFiles(int $completedHours): int
method cleanupAbandonedImports (line 58) | private function cleanupAbandonedImports(int $staleHours): int
method cleanupOrphanedDirectories (line 77) | private function cleanupOrphanedDirectories(): int
FILE: packages/ImportWizard/src/Data/ColumnData.php
class ColumnData (line 28) | final class ColumnData extends Data implements Wireable
method __construct (line 38) | public function __construct(
method toField (line 46) | public static function toField(string $source, string $target): self
method toEntityLink (line 54) | public static function toEntityLink(
method getType (line 66) | public function getType(): FieldDataType
method isMultiChoicePredefined (line 77) | public function isMultiChoicePredefined(): bool
method isSingleChoicePredefined (line 82) | public function isSingleChoicePredefined(): bool
method isMultiChoiceArbitrary (line 87) | public function isMultiChoiceArbitrary(): bool
method getRules (line 93) | public function getRules(): array
method getLabel (line 98) | public function getLabel(): string
method getIcon (line 107) | public function getIcon(): string
method getMatcher (line 116) | public function getMatcher(): ?MatchableField
method isFieldMapping (line 125) | public function isFieldMapping(): bool
method isEntityLinkMapping (line 130) | public function isEntityLinkMapping(): bool
method resolveEntityLinkContext (line 142) | public function resolveEntityLinkContext(BaseImporter $importer): ?array
method toArray (line 165) | public function toArray(): array
method withDateFormat (line 176) | public function withDateFormat(DateFormat $format): self
method withNumberFormat (line 181) | public function withNumberFormat(NumberFormat $format): self
method cloneWith (line 186) | private function cloneWith(?DateFormat $dateFormat = null, ?NumberForm...
FILE: packages/ImportWizard/src/Data/EntityLink.php
class EntityLink (line 23) | final class EntityLink extends Data
method __construct (line 40) | public function __construct(
method cloneWith (line 61) | private function cloneWith(array $overrides): self
method belongsTo (line 81) | public static function belongsTo(string $name, string $modelClass): self
method morphToMany (line 94) | public static function morphToMany(string $name, string $modelClass): ...
method fromCustomField (line 108) | public static function fromCustomField(CustomField $customField): self
method company (line 135) | public static function company(): self
method contact (line 150) | public static function contact(): self
method polymorphicCompanies (line 166) | public static function polymorphicCompanies(): self
method polymorphicPeople (line 179) | public static function polymorphicPeople(): self
method polymorphicOpportunities (line 193) | public static function polymorphicOpportunities(): self
method matchableFields (line 205) | public function matchableFields(array $matchableFields): self
method foreignKey (line 210) | public function foreignKey(string $foreignKey): self
method morphRelation (line 215) | public function morphRelation(string $relation): self
method guess (line 221) | public function guess(array $guesses): self
method label (line 226) | public function label(string $label): self
method getHighestPriorityMatcher (line 231) | public function getHighestPriorityMatcher(): ?MatchableField
method getMatcher (line 242) | public function getMatcher(string $field): ?MatchableField
method matchesHeader (line 248) | public function matchesHeader(string $header): bool
method normalizeHeader (line 257) | private function normalizeHeader(string $value): string
method icon (line 262) | public function icon(): string
method isForeignKey (line 267) | public function isForeignKey(): bool
method isMorphToMany (line 272) | public function isMorphToMany(): bool
method isCustomFieldValue (line 277) | public function isCustomFieldValue(): bool
method isFromRelationship (line 282) | public function isFromRelationship(): bool
method isFromCustomField (line 287) | public function isFromCustomField(): bool
method getStorageStrategy (line 292) | public function getStorageStrategy(): EntityLinkStorageInterface
method getEntityAliasForModel (line 302) | private static function getEntityAliasForModel(string $modelClass): st...
method getUniqueMatchableFieldsForEntity (line 316) | private static function getUniqueMatchableFieldsForEntity(string $mode...
FILE: packages/ImportWizard/src/Data/ImportField.php
class ImportField (line 15) | final class ImportField extends Data
method __construct (line 31) | public function __construct(
method make (line 49) | public static function make(string $key): self
method id (line 60) | public static function id(): self
method label (line 76) | public function label(string $label): self
method required (line 84) | public function required(bool $required = true): self
method rules (line 94) | public function rules(array $rules): self
method guess (line 104) | public function guess(array $aliases): self
method example (line 112) | public function example(string $example): self
method asCustomField (line 120) | public function asCustomField(bool $isCustomField = true): self
method type (line 128) | public function type(?FieldDataType $type): self
method icon (line 136) | public function icon(?string $icon): self
method sortOrder (line 144) | public function sortOrder(?int $sortOrder): self
method acceptsArbitraryValues (line 152) | public function acceptsArbitraryValues(bool $accepts = true): self
method options (line 162) | public function options(?array $options): self
method cloneWith (line 172) | private function cloneWith(array $overrides): self
method matchesHeader (line 195) | public function matchesHeader(string $header): bool
method normalizeHeader (line 204) | private function normalizeHeader(string $value): string
FILE: packages/ImportWizard/src/Data/ImportFieldCollection.php
class ImportFieldCollection (line 17) | final class ImportFieldCollection extends Collection
method get (line 20) | public function get(mixed $key, mixed $default = null): ?ImportField
method hasKey (line 28) | public function hasKey(string $key): bool
method guessFor (line 41) | public function guessFor(string $header): ?ImportField
method required (line 49) | public function required(): static
method optional (line 57) | public function optional(): static
method standard (line 65) | public function standard(): static
method custom (line 73) | public function custom(): static
FILE: packages/ImportWizard/src/Data/InferenceResult.php
class InferenceResult (line 12) | final class InferenceResult extends Data
method __construct (line 19) | public function __construct(
FILE: packages/ImportWizard/src/Data/MatchableField.php
class MatchableField (line 10) | final class MatchableField extends Data
method __construct (line 12) | public function __construct(
method id (line 20) | public static function id(): self
method email (line 30) | public static function email(
method domain (line 43) | public static function domain(
method phone (line 56) | public static function phone(
method name (line 69) | public static function name(): self
method description (line 79) | public function description(): string
method isCreate (line 84) | public function isCreate(): bool
FILE: packages/ImportWizard/src/Data/RelationshipMatch.php
class RelationshipMatch (line 11) | final class RelationshipMatch extends Data
method __construct (line 13) | public function __construct(
method existing (line 22) | public static function existing(string $relationship, string $id, ?Mat...
method create (line 33) | public static function create(string $relationship, string $name, ?Mat...
method isExisting (line 44) | public function isExisting(): bool
method isCreate (line 49) | public function isCreate(): bool
FILE: packages/ImportWizard/src/Enums/DateFormat.php
method getLabel (line 23) | public function getLabel(): string
method getExamples (line 37) | public function getExamples(bool $withTime = false): array
method format (line 57) | public function format(Carbon $date, bool $withTime = false): string
method toOptions (line 77) | public static function toOptions(bool $withTime = false): array
method parse (line 97) | public function parse(string $value, bool $withTime = false): ?Carbon
method toPickerValue (line 123) | public function toPickerValue(Carbon $date, bool $withTime = false): string
method getParseFormats (line 133) | private function getParseFormats(bool $withTime): array
FILE: packages/ImportWizard/src/Enums/ImportEntityType.php
method label (line 22) | public function label(): string
method singular (line 33) | public function singular(): string
method importerClass (line 49) | public function importerClass(): string
method icon (line 60) | public function icon(): string
method importer (line 71) | public function importer(string $teamId): BaseImporter
FILE: packages/ImportWizard/src/Enums/MatchBehavior.php
method description (line 13) | public function description(): string
method performsLookup (line 22) | public function performsLookup(): bool
method createsOnNoMatch (line 27) | public function createsOnNoMatch(): bool
FILE: packages/ImportWizard/src/Enums/NumberFormat.php
method getLabel (line 20) | public function getLabel(): string
method getExample (line 31) | public function getExample(): string
method parse (line 45) | public function parse(string $value): ?float
method format (line 80) | public function format(float $value, int $decimals = 2): string
method toOptions (line 93) | public static function toOptions(): array
FILE: packages/ImportWizard/src/Enums/ReviewFilter.php
method getLabel (line 17) | public function getLabel(): string
method getIcon (line 27) | public function getIcon(): ?string
FILE: packages/ImportWizard/src/Enums/RowMatchAction.php
method icon (line 13) | public function icon(): string
method color (line 22) | public function color(): string
FILE: packages/ImportWizard/src/Enums/SortDirection.php
method getLabel (line 15) | public function getLabel(): string
method getIcon (line 23) | public function getIcon(): string
FILE: packages/ImportWizard/src/Enums/SortField.php
method getLabel (line 15) | public function getLabel(): string
method getIcon (line 23) | public function getIcon(): string
FILE: packages/ImportWizard/src/Filament/Pages/ImportCompanies.php
class ImportCompanies (line 13) | final class ImportCompanies extends ImportPage
method getEntityType (line 17) | public static function getEntityType(): ImportEntityType
method getResourceClass (line 22) | public static function getResourceClass(): string
FILE: packages/ImportWizard/src/Filament/Pages/ImportHistory.php
class ImportHistory (line 21) | final class ImportHistory extends Page implements HasTable
method table (line 37) | public function table(Table $table): Table
FILE: packages/ImportWizard/src/Filament/Pages/ImportNotes.php
class ImportNotes (line 10) | final class ImportNotes extends ImportPage
method getEntityType (line 14) | public static function getEntityType(): ImportEntityType
method getResourceClass (line 19) | public static function getResourceClass(): string
FILE: packages/ImportWizard/src/Filament/Pages/ImportOpportunities.php
class ImportOpportunities (line 10) | final class ImportOpportunities extends ImportPage
method getEntityType (line 14) | public static function getEntityType(): ImportEntityType
method getResourceClass (line 19) | public static function getResourceClass(): string
FILE: packages/ImportWizard/src/Filament/Pages/ImportPage.php
class ImportPage (line 16) | abstract class ImportPage extends Page
method canAccess (line 31) | public static function canAccess(): bool
method getEntityType (line 45) | abstract public static function getEntityType(): ImportEntityType;
method getResourceClass (line 52) | abstract public static function getResourceClass(): string;
method getTitle (line 54) | #[Override]
method getSubheading (line 60) | #[Override]
method getBreadcrumbs (line 71) | public function getBreadcrumbs(): array
method getReturnUrl (line 89) | public function getReturnUrl(): string
FILE: packages/ImportWizard/src/Filament/Pages/ImportPeople.php
class ImportPeople (line 10) | final class ImportPeople extends ImportPage
method getEntityType (line 14) | public static function getEntityType(): ImportEntityType
method getResourceClass (line 19) | public static function getResourceClass(): string
FILE: packages/ImportWizard/src/Filament/Pages/ImportTasks.php
class ImportTasks (line 13) | final class ImportTasks extends ImportPage
method getEntityType (line 17) | public static function getEntityType(): ImportEntityType
method getResourceClass (line 22) | public static function getResourceClass(): string
FILE: packages/ImportWizard/src/Http/Controllers/DownloadFailedRowsController.php
class DownloadFailedRowsController (line 13) | final class DownloadFailedRowsController
method __invoke (line 15) | public function __invoke(Request $request, Import $import): StreamedRe...
FILE: packages/ImportWizard/src/ImportWizardNewServiceProvider.php
class ImportWizardNewServiceProvider (line 17) | final class ImportWizardNewServiceProvider extends ServiceProvider
method register (line 19) | public function register(): void
method boot (line 24) | public function boot(): void
method registerCommands (line 33) | private function registerCommands(): void
method registerRoutes (line 40) | private function registerRoutes(): void
method registerViews (line 48) | private function registerViews(): void
method registerTranslations (line 53) | private function registerTranslations(): void
method registerLivewireComponents (line 58) | private function registerLivewireComponents(): void
FILE: packages/ImportWizard/src/Importers/BaseImporter.php
class BaseImporter (line 28) | abstract class BaseImporter implements ImporterContract
method __construct (line 37) | public function __construct(
method getTeamId (line 41) | public function getTeamId(): string
method getTeam (line 46) | public function getTeam(): ?Team
method allFields (line 57) | public function allFields(): ImportFieldCollection
method entityLinks (line 71) | public function entityLinks(): array
method defineEntityLinks (line 94) | protected function defineEntityLinks(): array
method getRecordCustomFields (line 100) | protected function getRecordCustomFields(): EloquentCollection
method matchableFields (line 119) | public function matchableFields(): array
method prepareForSave (line 136) | public function prepareForSave(array $data, ?Model $existing, array &$...
method afterSave (line 150) | public function afterSave(Model $record, array $context): void
method customFields (line 161) | protected function customFields(): ImportFieldCollection
method shouldLoadOptions (line 209) | private function shouldLoadOptions(CustomField $customField): bool
method buildCustomFieldGuesses (line 218) | private function buildCustomFieldGuesses(string $code, string $name): ...
method initializeNewRecordData (line 243) | protected function initializeNewRecordData(array $data, ?string $creat...
method saveCustomFieldValues (line 252) | protected function saveCustomFieldValues(Model $record): void
method getMatchFieldForMappedColumns (line 266) | public function getMatchFieldForMappedColumns(array $mappedFields): ?M...
FILE: packages/ImportWizard/src/Importers/CompanyImporter.php
class CompanyImporter (line 16) | final class CompanyImporter extends BaseImporter
method modelClass (line 18) | public function modelClass(): string
method entityName (line 23) | public function entityName(): string
method fields (line 28) | public function fields(): ImportFieldCollection
method defineEntityLinks (line 50) | protected function defineEntityLinks(): array
method matchableFields (line 70) | public function matchableFields(): array
method prepareForSave (line 83) | public function prepareForSave(array $data, ?Model $existing, array &$...
FILE: packages/ImportWizard/src/Importers/Contracts/ImporterContract.php
type ImporterContract (line 18) | interface ImporterContract
method getTeamId (line 23) | public function getTeamId(): string;
method modelClass (line 30) | public function modelClass(): string;
method entityName (line 35) | public function entityName(): string;
method fields (line 40) | public function fields(): ImportFieldCollection;
method allFields (line 45) | public function allFields(): ImportFieldCollection;
method entityLinks (line 52) | public function entityLinks(): array;
method matchableFields (line 59) | public function matchableFields(): array;
method getMatchFieldForMappedColumns (line 66) | public function getMatchFieldForMappedColumns(array $mappedFields): ?M...
method prepareForSave (line 79) | public function prepareForSave(array $data, ?Model $existing, array &$...
method afterSave (line 90) | public function afterSave(Model $record, array $context): void;
FILE: packages/ImportWizard/src/Importers/NoteImporter.php
class NoteImporter (line 20) | final class NoteImporter extends BaseImporter
method modelClass (line 22) | public function modelClass(): string
method entityName (line 27) | public function entityName(): string
method fields (line 32) | public function fields(): ImportFieldCollection
method defineEntityLinks (line 53) | protected function defineEntityLinks(): array
method matchableFields (line 67) | public function matchableFields(): array
method prepareForSave (line 77) | public function prepareForSave(array $data, ?Model $existing, array &$...
FILE: packages/ImportWizard/src/Importers/OpportunityImporter.php
class OpportunityImporter (line 20) | final class OpportunityImporter extends BaseImporter
method modelClass (line 22) | public function modelClass(): string
method entityName (line 27) | public function entityName(): string
method fields (line 32) | public function fields(): ImportFieldCollection
method defineEntityLinks (line 54) | protected function defineEntityLinks(): array
method matchableFields (line 65) | public function matchableFields(): array
method prepareForSave (line 77) | public function prepareForSave(array $data, ?Model $existing, array &$...
FILE: packages/ImportWizard/src/Importers/PeopleImporter.php
class PeopleImporter (line 19) | final class PeopleImporter extends BaseImporter
method modelClass (line 21) | public function modelClass(): string
method entityName (line 26) | public function entityName(): string
method fields (line 31) | public function fields(): ImportFieldCollection
method defineEntityLinks (line 54) | protected function defineEntityLinks(): array
method matchableFields (line 64) | public function matchableFields(): array
method prepareForSave (line 78) | public function prepareForSave(array $data, ?Model $existing, array &$...
FILE: packages/ImportWizard/src/Importers/TaskImporter.php
class TaskImporter (line 22) | final class TaskImporter extends BaseImporter
method modelClass (line 24) | public function modelClass(): string
method entityName (line 29) | public function entityName(): string
method fields (line 34) | public function fields(): ImportFieldCollection
method defineEntityLinks (line 56) | protected function defineEntityLinks(): array
method matchableFields (line 78) | public function matchableFields(): array
method prepareForSave (line 90) | public function prepareForSave(array $data, ?Model $existing, array &$...
FILE: packages/ImportWizard/src/Jobs/ExecuteImportJob.php
class ExecuteImportJob (line 46) | final class ExecuteImportJob implements ShouldQueue
method __construct (line 81) | public function __construct(
method handle (line 88) | public function handle(): void
method failed (line 168) | public function failed(\Throwable $exception): void
method processRow (line 202) | private function processRow(
method loadCustomFieldDefinitions (line 306) | private function loadCustomFieldDefinitions(BaseImporter $importer): C...
method collectCustomFieldValues (line 325) | private function collectCustomFieldValues(
method mergeWithExistingMultiChoiceValues (line 382) | private function mergeWithExistingMultiChoiceValues(
method flushCustomFieldValues (line 425) | private function flushCustomFieldValues(): void
method markProcessed (line 453) | private function markProcessed(ImportRow $row): void
method flushProcessedRows (line 458) | private function flushProcessedRows(ImportStore $store): void
method preloadExistingRecords (line 483) | private function preloadExistingRecords(Collection $rows, BaseImporter...
method recordFailedRow (line 506) | private function recordFailedRow(int $rowNumber, array $rawData, \Thro...
method persistResults (line 516) | private function persistResults(Import $import, array $results): void
method flushFailedRows (line 526) | private function flushFailedRows(Import $import): void
method buildDataFromRow (line 555) | private function buildDataFromRow(ImportRow $row, Collection $fieldMap...
method extractCustomFieldData (line 568) | private function extractCustomFieldData(array &$prepared): array
method buildCustomFieldFormatMap (line 595) | private function buildCustomFieldFormatMap(Collection $fieldMappings):...
method convertCustomFieldValue (line 608) | private function convertCustomFieldValue(mixed $value, CustomField $cf...
method resolveChoiceValue (line 646) | private function resolveChoiceValue(CustomField $cf, string $value): i...
method resolveMultiChoiceValue (line 674) | private function resolveMultiChoiceValue(CustomField $cf, string $valu...
method allowedAttributeKeys (line 692) | private function allowedAttributeKeys(BaseImporter $importer): array
method findExistingRecord (line 709) | private function findExistingRecord(BaseImporter $importer, ?string $m...
method resolveMatchField (line 729) | private function resolveMatchField(BaseImporter $importer, Collection ...
method findMatchSourceColumn (line 746) | private function findMatchSourceColumn(MatchableField $matchField, Col...
method lookupMatchableValueCache (line 755) | private function lookupMatchableValueCache(ImportRow $row, MatchableFi...
method registerInMatchableValueCache (line 766) | private function registerInMatchableValueCache(ImportRow $row, Matchab...
method normalizeMatchableValues (line 781) | private function normalizeMatchableValues(ImportRow $row, MatchableFie...
method resolveEntityLinkRelationships (line 804) | private function resolveEntityLinkRelationships(
method resolveGroupedMatches (line 849) | private function resolveGroupedMatches(
method resolveCreationMatch (line 901) | private function resolveCreationMatch(Collection $matches): ?Relations...
method populateMatchingCustomField (line 913) | private function populateMatchingCustomField(
method resolveRecordFieldByName (line 970) | private function resolveRecordFieldByName(
method notifyUser (line 992) | private function notifyUser(Import $import, array $results, bool $fail...
method storeEntityLinkRelationships (line 1018) | private function storeEntityLinkRelationships(
FILE: packages/ImportWizard/src/Jobs/ResolveMatchesJob.php
class ResolveMatchesJob (line 17) | final class ResolveMatchesJob implements ShouldQueue
method __construct (line 29) | public function __construct(
method handle (line 35) | public function handle(): void
FILE: packages/ImportWizard/src/Jobs/ValidateColumnJob.php
class ValidateColumnJob (line 23) | final class ValidateColumnJob implements ShouldQueue
method __construct (line 35) | public function __construct(
method handle (line 42) | public function handle(): void
method validateEntityLink (line 77) | private function validateEntityLink(Import $import, ImportStore $store...
method writeEntityLinkRelationships (line 104) | private function writeEntityLinkRelationships(
method clearValidationForCorrectedDateFields (line 173) | private function clearValidationForCorrectedDateFields(
method fetchUncorrectedUniqueValues (line 189) | private function fetchUncorrectedUniqueValues(ImportStore $store, stri...
method validateValues (line 203) | private function validateValues(Import $import, array $uniqueValues): ...
method hydrateColumnField (line 221) | private function hydrateColumnField(Import $import): void
method updateValidationErrors (line 236) | private function updateValidationErrors(
FILE: packages/ImportWizard/src/Livewire/Concerns/WithImportStore.php
type WithImportStore (line 13) | trait WithImportStore
method mountWithImportStore (line 25) | public function mountWithImportStore(string $storeId, ImportEntityType...
method import (line 31) | protected function import(): Import
method refreshImport (line 42) | protected function refreshImport(): Import
method store (line 49) | protected function store(): ImportStore
method getCurrentTeamId (line 58) | private function getCurrentTeamId(): ?string
method headers (line 66) | protected function headers(): array
method rowCount (line 71) | protected function rowCount(): int
FILE: packages/ImportWizard/src/Livewire/ImportWizard.php
class ImportWizard (line 24) | final class ImportWizard extends Component implements HasActions, HasForms
method mount (line 54) | public function mount(ImportEntityType $entityType, ?string $returnUrl...
method render (line 62) | public function render(): View
method onUploadCompleted (line 67) | public function onUploadCompleted(string $storeId, int $rowCount, int ...
method nextStep (line 75) | public function nextStep(): void
method goBack (line 80) | public function goBack(): void
method goToStep (line 90) | public function goToStep(int $step): void
method getStepTitle (line 110) | public function getStepTitle(): string
method getStepDescription (line 121) | public function getStepDescription(): string
method cancelImport (line 135) | public function cancelImport(): void
method onImportStarted (line 146) | #[On('import-started')]
method startOverAction (line 152) | public function startOverAction(): Action
method startOver (line 166) | public function startOver(): void
method restoreFromStore (line 179) | private function restoreFromStore(): void
method syncStepStatus (line 199) | private function syncStepStatus(): void
method findCurrentImport (line 205) | private function findCurrentImport(): ?Import
method statusForStep (line 224) | private function statusForStep(int $step): ImportStatus
method stepFromStatus (line 234) | private function stepFromStatus(ImportStatus $status): int
method destroyImportAndStore (line 244) | private function destroyImportAndStore(string $importId): void
method sanitizeReturnUrl (line 260) | private function sanitizeReturnUrl(?string $url): ?string
method getCurrentTeamId (line 273) | private function getCurrentTeamId(): ?string
FILE: packages/ImportWizard/src/Livewire/Steps/MappingStep.php
class MappingStep (line 28) | final class MappingStep extends Component implements HasActions, HasForms
method mount (line 39) | public function mount(string $storeId, ImportEntityType $entityType): ...
method render (line 49) | public function render(): View
method allFields (line 57) | #[Computed]
method entityLinks (line 64) | #[Computed]
method unmappedRequired (line 70) | #[Computed]
method hasEntityLinks (line 80) | #[Computed]
method mappedFieldKeys (line 87) | #[Computed]
method isMapped (line 98) | public function isMapped(string $source): bool
method isTargetMapped (line 103) | public function isTargetMapped(string $target): bool
method getMapping (line 109) | public function getMapping(string $source): ?ColumnData
method getSourceForTarget (line 118) | public function getSourceForTarget(string $target): ?string
method getFieldForSource (line 126) | public function getFieldForSource(string $source): ?ImportField
method getEntityLinkForSource (line 138) | public function getEntityLinkForSource(string $source): ?array
method previewValues (line 156) | public function previewValues(string $column, int $limit = 5): array
method canProceed (line 166) | public function canProceed(): bool
method autoMap (line 171) | public function autoMap(): void
method autoMapByHeaders (line 178) | private function autoMapByHeaders(): void
method autoMapEntityLinks (line 195) | private function autoMapEntityLinks(): void
method isEntityLinkMapped (line 225) | public function isEntityLinkMapped(string $linkKey): bool
method getMappedEntityLinkMatchers (line 232) | public function getMappedEntityLinkMatchers(): array
method inferDataTypes (line 242) | private function inferDataTypes(): void
method mapToField (line 272) | public function mapToField(string $source, string $target): void
method mapToEntityLink (line 285) | public function mapToEntityLink(string $source, string $matcherKey, st...
method unmapColumn (line 290) | public function unmapColumn(string $source): void
method continueAction (line 295) | public function continueAction(): Action
method hasMatchableFieldMapped (line 324) | public function hasMatchableFieldMapped(): bool
method buildMatchWarningDescription (line 339) | private function buildMatchWarningDescription(): string
method saveMappings (line 356) | private function saveMappings(): void
method loadMappings (line 365) | private function loadMappings(): void
method getImporter (line 373) | private function getImporter(): BaseImporter
FILE: packages/ImportWizard/src/Livewire/Steps/PreviewStep.php
class PreviewStep (line 32) | final class PreviewStep extends Component implements HasActions, HasForms
method mount (line 47) | public function mount(string $storeId, ImportEntityType $entityType): ...
method setActiveTab (line 54) | public function setActiveTab(string $tab): void
method createCount (line 60) | #[Computed]
method updateCount (line 66) | #[Computed]
method skipCount (line 72) | #[Computed]
method errorCount (line 78) | #[Computed]
method isImporting (line 87) | #[Computed]
method progressPercent (line 98) | #[Computed]
method processedCount (line 115) | #[Computed]
method matchField (line 121) | #[Computed]
method totalRowCount (line 134) | #[Computed]
method columns (line 141) | #[Computed]
method previewRows (line 148) | #[Computed]
method relationshipTabs (line 166) | #[Computed]
method relationshipSummary (line 192) | #[Computed]
method relationshipStats (line 240) | #[Computed]
method results (line 271) | #[Computed]
method startImportAction (line 284) | public function startImportAction(): Action
method downloadFailedRowsAction (line 298) | public function downloadFailedRowsAction(): Action
method downloadFailedRows (line 308) | public function downloadFailedRows(): StreamedResponse
method checkMatchResolution (line 340) | public function checkMatchResolution(): void
method startImport (line 349) | public function startImport(): void
method checkImportProgress (line 371) | public function checkImportProgress(): void
method render (line 383) | public function render(): View
method syncCompletionState (line 388) | private function syncCompletionState(): void
method syncMatchResolutionState (line 396) | private function syncMatchResolutionState(): void
method relationshipGroupByClause (line 421) | private function relationshipGroupByClause(): string
method uniqueRelationshipSubquery (line 429) | private function uniqueRelationshipSubquery(): string
FILE: packages/ImportWizard/src/Livewire/Steps/ReviewStep.php
class ReviewStep (line 33) | final class ReviewStep extends Component
method connection (line 54) | private function connection(): Connection
method selectedColumnJsonPath (line 59) | private function selectedColumnJsonPath(): string
method validateValue (line 64) | private function validateValue(ColumnData $column, string $value, bool...
method validateEntityLinkValue (line 79) | private function validateEntityLinkValue(ColumnData $column, string $v...
method updateValidationForRawValue (line 86) | private function updateValidationForRawValue(string $jsonPath, string ...
method validateColumnAsync (line 105) | private function validateColumnAsync(ColumnData $column): string
method clearRelationshipsForReentry (line 116) | private function clearRelationshipsForReentry(): void
method dispatchMatchResolution (line 121) | private function dispatchMatchResolution(): string
method mount (line 134) | public function mount(): void
method hydrate (line 160) | public function hydrate(): void
method render (line 166) | public function render(): View
method selectedColumnRows (line 172) | #[Computed]
method filterCounts (line 186) | #[Computed]
method selectColumn (line 195) | public function selectColumn(string $columnSource): void
method choiceOptions (line 202) | #[Computed]
method setFilter (line 212) | public function setFilter(string $filter): void
method setSortField (line 218) | public function setSortField(string $field): void
method setSortDirection (line 224) | public function setSortDirection(string $direction): void
method clearFilters (line 230) | public function clearFilters(): void
method updatedSearch (line 237) | public function updatedSearch(): void
method setColumnFormat (line 242) | public function setColumnFormat(string $type, string $value): void
method updateMappedValue (line 279) | public function updateMappedValue(string $rawValue, string $newValue):...
method undoCorrection (line 309) | public function undoCorrection(string $rawValue): void
method skipValue (line 325) | public function skipValue(string $rawValue): void
method unskipValue (line 342) | public function unskipValue(string $rawValue): void
method checkProgress (line 355) | public function checkProgress(): void
method isSelectedColumnValidating (line 377) | #[Computed]
method isValidating (line 383) | #[Computed]
method columnErrorStatuses (line 393) | #[Computed(persist: true, seconds: 60)]
method continueToPreview (line 401) | public function continueToPreview(): void
method currentMappingsHash (line 421) | private function currentMappingsHash(): string
method validationCacheKey (line 428) | private function validationCacheKey(): string
method cacheValidationState (line 433) | private function cacheValidationState(string $hash): void
method filterRunningBatches (line 445) | private function filterRunningBatches(array $batchIds): array
method cancelOldBatches (line 455) | private function cancelOldBatches(?array $cached): void
FILE: packages/ImportWizard/src/Livewire/Steps/UploadStep.php
class UploadStep (line 23) | final class UploadStep extends Component implements HasForms
method mount (line 48) | public function mount(ImportEntityType $entityType, ?string $storeId =...
method getCurrentTeamId (line 70) | private function getCurrentTeamId(): ?string
method render (line 77) | public function render(): View
method updatedUploadedFile (line 82) | public function updatedUploadedFile(): void
method validateFile (line 88) | private function validateFile(): void
method continueToMapping (line 139) | public function continueToMapping(): void
method processHeaders (line 227) | private function processHeaders(array $rawHeaders): ?array
method normalizeRow (line 250) | private function normalizeRow(array $row): array
method removeFile (line 258) | public function removeFile(): void
method cleanupExisting (line 264) | private function cleanupExisting(): void
method maxRows (line 277) | private function maxRows(): int
method chunkSize (line 282) | private function chunkSize(): int
FILE: packages/ImportWizard/src/Models/FailedImportRow.php
class FailedImportRow (line 20) | final class FailedImportRow extends Model
method casts (line 33) | protected function casts(): array
method import (line 41) | public function import(): BelongsTo
method prunable (line 47) | public function prunable(): Builder
FILE: packages/ImportWizard/src/Models/Import.php
class Import (line 39) | final class Import extends Model
method casts (line 62) | protected function casts(): array
method user (line 79) | public function user(): BelongsTo
method team (line 85) | public function team(): BelongsTo
method failedRows (line 91) | public function failedRows(): HasMany
method completed (line 97) | #[Scope]
method failed (line 104) | #[Scope]
method forTeam (line 111) | #[Scope]
method storagePath (line 117) | public function storagePath(): string
method getImporter (line 122) | public function getImporter(): BaseImporter
method columnMappings (line 130) | public function columnMappings(): Collection
method setColumnMappings (line 151) | public function setColumnMappings(iterable $mappings): void
method getColumnMapping (line 161) | public function getColumnMapping(string $source): ?ColumnData
method updateColumnMapping (line 166) | public function updateColumnMapping(string $source, ColumnData $newMap...
method transitionToImporting (line 174) | public function transitionToImporting(): bool
FILE: packages/ImportWizard/src/Rules/ImportChoiceRule.php
class ImportChoiceRule (line 17) | final readonly class ImportChoiceRule implements ValidationRule
method __construct (line 23) | public function __construct(
method validate (line 35) | public function validate(string $attribute, mixed $value, Closure $fai...
FILE: packages/ImportWizard/src/Rules/ImportDateRule.php
class ImportDateRule (line 20) | final readonly class ImportDateRule implements ValidationRule
method __construct (line 22) | public function __construct(
method validate (line 33) | public function validate(string $attribute, mixed $value, Closure $fai...
FILE: packages/ImportWizard/src/Rules/ImportNumberRule.php
class ImportNumberRule (line 15) | final readonly class ImportNumberRule implements ValidationRule
method __construct (line 17) | public function __construct(
method validate (line 26) | public function validate(string $attribute, mixed $value, Closure $fai...
FILE: packages/ImportWizard/src/Store/ImportRow.php
class ImportRow (line 46) | final class ImportRow extends Model
method casts (line 75) | protected function casts(): array
method withErrors (line 91) | #[Scope]
method withCorrections (line 100) | #[Scope]
method withSkipped (line 109) | #[Scope]
method valid (line 118) | #[Scope]
method toCreate (line 129) | #[Scope]
method toUpdate (line 138) | #[Scope]
method toSkip (line 147) | #[Scope]
method uniqueValuesFor (line 156) | #[Scope]
method searchValue (line 176) | #[Scope]
method forFilter (line 186) | #[Scope]
method countUniqueValuesByFilter (line 205) | public static function countUniqueValuesByFilter(Builder $query, strin...
method getColumnErrorStatuses (line 242) | public static function getColumnErrorStatuses(Builder $query, array $c...
method hasErrors (line 267) | public function hasErrors(): bool
method hasCorrections (line 272) | public function hasCorrections(): bool
method getFinalValue (line 277) | public function getFinalValue(string $column): mixed
method isValueSkipped (line 294) | public function isValueSkipped(string $column): bool
method hasValidationError (line 299) | public function hasValidationError(string $column): bool
method getFinalData (line 305) | public function getFinalData(): array
method isCreate (line 310) | public function isCreate(): bool
method isUpdate (line 315) | public function isUpdate(): bool
method isSkip (line 320) | public function isSkip(): bool
FILE: packages/ImportWizard/src/Store/ImportStore.php
class ImportStore (line 16) | final class ImportStore
method __construct (line 20) | public function __construct(
method create (line 24) | public static function create(string $importId): self
method load (line 35) | public static function load(string $importId): ?self
method id (line 52) | public function id(): string
method path (line 57) | public function path(): string
method sqlitePath (line 62) | public function sqlitePath(): string
method connectionName (line 67) | public function connectionName(): string
method connection (line 72) | public function connection(): Connection
method query (line 78) | public function query(): EloquentBuilder
method ensureProcessedColumn (line 85) | public function ensureProcessedColumn(): void
method bulkUpdateMatches (line 101) | public function bulkUpdateMatches(string $jsonPath, array $resolvedMap...
method destroy (line 144) | public function destroy(): void
method createConnection (line 150) | private function createConnection(): Connection
method createTableSafely (line 164) | private function createTableSafely(): void
FILE: packages/ImportWizard/src/Support/DataTypeInferencer.php
class DataTypeInferencer (line 20) | final class DataTypeInferencer
method __construct (line 30) | public function __construct(
method infer (line 40) | public function infer(array $values): InferenceResult
method initialize (line 89) | private function initialize(): void
method extractValidationKey (line 127) | private function extractValidationKey(string $rule): ?string
method detectType (line 144) | private function detectType(string $value): string
method passesValidation (line 174) | private function passesValidation(string $value, string $validationKey...
method isCurrency (line 190) | private function isCurrency(string $value): bool
method isNumber (line 195) | private function isNumber(string $value): bool
method getSuggestedFieldsForType (line 207) | private function getSuggestedFieldsForType(string $fieldTypeKey): array
FILE: packages/ImportWizard/src/Support/EntityLinkResolver.php
class EntityLinkResolver (line 14) | final class EntityLinkResolver
method __construct (line 21) | public function __construct(
method resolve (line 25) | public function resolve(EntityLink $link, MatchableField $matcher, mix...
method resolveMany (line 48) | public function resolveMany(EntityLink $link, MatchableField $matcher,...
method batchResolve (line 81) | public function batchResolve(EntityLink $link, MatchableField $matcher...
method normalizeUniqueValues (line 116) | private function normalizeUniqueValues(array $values): array
method isCustomField (line 126) | private function isCustomField(string $field): bool
method getCustomFieldCode (line 131) | private function getCustomFieldCode(string $field): string
method resolveViaColumn (line 140) | private function resolveViaColumn(EntityLink $link, string $field, arr...
method resolveViaTeamMember (line 155) | private function resolveViaTeamMember(string $field, array $uniqueValu...
method resolveViaCustomField (line 171) | private function resolveViaCustomField(EntityLink $link, string $field...
method resolveViaJsonColumn (line 206) | private function resolveViaJsonColumn(string $entityType, int|string $...
method preloadCache (line 275) | public function preloadCache(EntityLink $link, MatchableField $matcher...
method getCachedId (line 286) | public function getCachedId(EntityLink $link, MatchableField $matcher,...
method clearCache (line 294) | public function clearCache(): void
method getCacheKey (line 299) | private function getCacheKey(EntityLink $link, MatchableField $matcher...
method normalizeValue (line 304) | private function normalizeValue(mixed $value): ?string
method normalizeForComparison (line 315) | private function normalizeForComparison(string $value): string
FILE: packages/ImportWizard/src/Support/EntityLinkStorage/CustomFieldValueStorage.php
class CustomFieldValueStorage (line 16) | final class CustomFieldValueStorage implements EntityLinkStorageInterface
method store (line 18) | public function store(Model $record, EntityLink $link, array $resolved...
method prepareData (line 23) | public function prepareData(array $data, EntityLink $link, array $reso...
FILE: packages/ImportWizard/src/Support/EntityLinkStorage/EntityLinkStorageInterface.php
type EntityLinkStorageInterface (line 16) | interface EntityLinkStorageInterface
method store (line 28) | public function store(Model $record, EntityLink $link, array $resolved...
method prepareData (line 40) | public function prepareData(array $data, EntityLink $link, array $reso...
FILE: packages/ImportWizard/src/Support/EntityLinkStorage/ForeignKeyStorage.php
class ForeignKeyStorage (line 15) | final class ForeignKeyStorage implements EntityLinkStorageInterface
method store (line 17) | public function store(Model $record, EntityLink $link, array $resolved...
method prepareData (line 22) | public function prepareData(array $data, EntityLink $link, array $reso...
FILE: packages/ImportWizard/src/Support/EntityLinkStorage/MorphToManyStorage.php
class MorphToManyStorage (line 15) | final class MorphToManyStorage implements EntityLinkStorageInterface
method store (line 17) | public function store(Model $record, EntityLink $link, array $resolved...
method prepareData (line 33) | public function prepareData(array $data, EntityLink $link, array $reso...
FILE: packages/ImportWizard/src/Support/EntityLinkValidator.php
class EntityLinkValidator (line 16) | final class EntityLinkValidator
method __construct (line 26) | public function __construct(private readonly string $teamId)
method validate (line 31) | public function validate(EntityLink $link, MatchableField $matcher, mi...
method batchValidate (line 54) | public function batchValidate(EntityLink $link, MatchableField $matche...
method validateFromColumn (line 104) | public function validateFromColumn(ColumnData $column, BaseImporter $i...
method batchValidateFromColumn (line 117) | public function batchValidateFromColumn(ColumnData $column, BaseImport...
method preloadCache (line 127) | public function preloadCache(EntityLink $link, MatchableField $matcher...
method getResolvedId (line 132) | public function getResolvedId(EntityLink $link, MatchableField $matche...
method getResolver (line 144) | public function getResolver(): EntityLinkResolver
method getLastFormatErrors (line 150) | public function getLastFormatErrors(): array
method getMatchFieldFormatRules (line 158) | private function getMatchFieldFormatRules(EntityLink $link, MatchableF...
method validateFormat (line 195) | private function validateFormat(string $value, MatchableField $matcher...
method buildErrorMessage (line 216) | private function buildErrorMessage(EntityLink $link, MatchableField $m...
FILE: packages/ImportWizard/src/Support/MatchResolver.php
class MatchResolver (line 19) | final readonly class MatchResolver
method __construct (line 21) | public function __construct(
method resolve (line 27) | public function resolve(): void
method resetPreviousResolutions (line 45) | private function resetPreviousResolutions(): void
method markRemainingAs (line 54) | private function markRemainingAs(RowMatchAction $action): void
method resolveWithLookup (line 64) | private function resolveWithLookup(MatchableField $matchField, Collect...
method findSourceColumn (line 89) | private function findSourceColumn(MatchableField $matchField, Collecti...
method extractUniqueValues (line 97) | private function extractUniqueValues(string $jsonPath): array
method resolveMatchIds (line 112) | private function resolveMatchIds(MatchableField $matchField, array $un...
method resolveMultiValueField (line 131) | private function resolveMultiValueField(
FILE: packages/ImportWizard/src/Support/Validation/ColumnValidator.php
class ColumnValidator (line 14) | final class ColumnValidator
method validate (line 16) | public function validate(ColumnData $column, string $value): ?Validati...
method validateDate (line 31) | private function validateDate(ColumnData $column, string $value): ?Val...
method validateNumber (line 42) | private function validateNumber(ColumnData $column, string $value): ?V...
method validateSingleChoice (line 53) | private function validateSingleChoice(ColumnData $column, string $valu...
method validateMultiChoicePredefined (line 65) | private function validateMultiChoicePredefined(ColumnData $column, str...
method validateMultiChoiceArbitrary (line 81) | private function validateMultiChoiceArbitrary(ColumnData $column, stri...
method validateBoolean (line 101) | private function validateBoolean(string $value): ?ValidationError
method validateText (line 112) | private function validateText(ColumnData $column, string $value): ?Val...
method parseCommaSeparated (line 130) | private function parseCommaSeparated(string $value): Collection
method getChoiceValues (line 140) | private function getChoiceValues(ColumnData $column): array
method lowercaseValues (line 151) | private function lowercaseValues(array $values): array
method formatInvalidChoiceMessage (line 157) | private function formatInvalidChoiceMessage(array $validValues): string
method getPreviewRules (line 166) | private function getPreviewRules(ColumnData $column): array
method runValidator (line 175) | private function runValidator(string $value, array $rules): ?string
FILE: packages/ImportWizard/src/Support/Validation/ValidationError.php
class ValidationError (line 13) | final readonly class ValidationError
method __construct (line 19) | private function __construct(
method message (line 27) | public static function message(string $message): self
method itemErrors (line 37) | public static function itemErrors(array $errors): self
method fromStorageFormat (line 47) | public static function fromStorageFormat(?string $stored): ?self
method toStorageFormat (line 67) | public function toStorageFormat(): string
method hasItemErrors (line 76) | public function hasItemErrors(): bool
method getMessage (line 81) | public function getMessage(): ?string
method getItemErrors (line 89) | public function getItemErrors(): array
FILE: packages/OnboardSeed/src/Contracts/ModelSeederInterface.php
type ModelSeederInterface (line 11) | interface ModelSeederInterface
method seed (line 13) | public function seed(Team $team, Authenticatable $user): void;
method customFields (line 20) | public function customFields(): Collection;
method initialize (line 27) | public function initialize(): self;
FILE: packages/OnboardSeed/src/ModelSeeders/CompanySeeder.php
class CompanySeeder (line 13) | final class CompanySeeder extends BaseModelSeeder
method createEntitiesFromFixtures (line 25) | protected function createEntitiesFromFixtures(Team $team, Authenticata...
method createCompanyFromFixture (line 39) | private function createCompanyFromFixture(Team $team, Authenticatable ...
FILE: packages/OnboardSeed/src/ModelSeeders/NoteSeeder.php
class NoteSeeder (line 17) | final class NoteSeeder extends BaseModelSeeder
method createEntitiesFromFixtures (line 38) | protected function createEntitiesFromFixtures(Team $team, Authenticata...
method getPluralEntityType (line 65) | private function getPluralEntityType(string $singularType): string
method createNoteFromFixture (line 71) | private function createNoteFromFixture(
FILE: packages/OnboardSeed/src/ModelSeeders/OpportunitySeeder.php
class OpportunitySeeder (line 16) | final class OpportunitySeeder extends BaseModelSeeder
method createEntitiesFromFixtures (line 28) | protected function createEntitiesFromFixtures(Team $team, Authenticata...
method createOpportunityFromFixture (line 58) | private function createOpportunityFromFixture(
FILE: packages/OnboardSeed/src/ModelSeeders/PeopleSeeder.php
class PeopleSeeder (line 16) | final class PeopleSeeder extends BaseModelSeeder
method createEntitiesFromFixtures (line 29) | protected function createEntitiesFromFixtures(Team $team, Authenticata...
method createPersonFromFixture (line 55) | private function createPersonFromFixture(Company $company, Team $team,...
FILE: packages/OnboardSeed/src/ModelSeeders/TaskSeeder.php
class TaskSeeder (line 18) | final class TaskSeeder extends BaseModelSeeder
method createEntitiesFromFixtures (line 31) | protected function createEntitiesFromFixtures(Team $team, Authenticata...
method assignPeopleToTask (line 49) | private function assignPeopleToTask(Task $task, array $peopleKeys): void
method createTaskFromFixture (line 73) | private function createTaskFromFixture(
method formatDate (line 108) | private function formatDate(mixed $dateValue): string
FILE: packages/OnboardSeed/src/OnboardSeedManager.php
class OnboardSeedManager (line 20) | final class OnboardSeedManager
method generateFor (line 34) | public function generateFor(Authenticatable $user, ?Team $team = null)...
method initializeSeeders (line 60) | private function initializeSeeders(): void
FILE: packages/OnboardSeed/src/OnboardSeeder.php
class OnboardSeeder (line 11) | final class OnboardSeeder extends Seeder
method __construct (line 13) | public function __construct(private readonly OnboardSeedManager $manag...
method run (line 15) | public function run(Authenticatable $user, ?Team $team = null): void
FILE: packages/OnboardSeed/src/Support/BaseModelSeeder.php
class BaseModelSeeder (line 20) | abstract class BaseModelSeeder implements ModelSeederInterface
method initialize (line 38) | public function initialize(): self
method setTeamId (line 48) | protected function setTeamId(string $teamId): void
method customFields (line 54) | public function customFields(): Collection
method prepareForSeed (line 69) | protected function prepareForSeed(Team $team): void
method seed (line 76) | public function seed(Team $team, Authenticatable $user): void
method createEntitiesFromFixtures (line 85) | abstract protected function createEntitiesFromFixtures(Team $team, Aut...
method applyCustomFields (line 88) | protected function applyCustomFields(HasCustomFields&Model $model, arr...
method getBulkWriter (line 107) | protected function getBulkWriter(): BulkCustomFieldValueWriter
method flushCustomFieldValues (line 112) | protected function flushCustomFieldValues(): int
method getOptionId (line 117) | protected function getOptionId(string $fieldCode, string $optionLabel)...
method getGlobalAttributes (line 137) | protected function getGlobalAttributes(): array
method loadEntityFixtures (line 145) | protected function loadEntityFixtures(): array
method evaluateTemplateExpression (line 150) | protected function evaluateTemplateExpression(string $template): mixed
method processCustomFieldValues (line 189) | protected function processCustomFieldValues(array $customFields, array...
method registerEntityFromFixture (line 218) | protected function registerEntityFromFixture(string $key, array $attri...
FILE: packages/OnboardSeed/src/Support/BulkCustomFieldValueWriter.php
class BulkCustomFieldValueWriter (line 13) | final class BulkCustomFieldValueWriter
method queue (line 18) | public function queue(
method flush (line 42) | public function flush(): int
method pending (line 71) | public function pending(): int
FILE: packages/OnboardSeed/src/Support/FixtureLoader.php
class FixtureLoader (line 11) | final class FixtureLoader
method setBasePath (line 21) | public static function setBasePath(string $path): void
method getBasePath (line 29) | public static function getBasePath(): string
method load (line 46) | public static function load(string $type): array
FILE: packages/OnboardSeed/src/Support/FixtureRegistry.php
class FixtureRegistry (line 9) | final class FixtureRegistry
method register (line 25) | public static function register(string $type, string $key, Model $enti...
method get (line 41) | public static function get(string $type, string $key): ?Model
method clear (line 46) | public static function clear(): void
FILE: packages/SystemAdmin/src/Enums/SystemAdministratorRole.php
method getLabel (line 11) | public function getLabel(): string
FILE: packages/SystemAdmin/src/Filament/Exports/CompanyExporter.php
class CompanyExporter (line 15) | final class CompanyExporter extends Exporter
method getColumns (line 23) | public static function getColumns(): array
method getCompletedNotificationBody (line 42) | public static function getCompletedNotificationBody(Export $export): s...
FILE: packages/SystemAdmin/src/Filament/Pages/Dashboard.php
class Dashboard (line 18) | final class Dashboard extends BaseDashboard
method getWidgets (line 35) | public function getWidgets(): array
method getColumns (line 45) | public function getColumns(): array
method getHeaderActions (line 53) | protected function getHeaderActions(): array
FILE: packages/SystemAdmin/src/Filament/Pages/EngagementDashboard.php
class EngagementDashboard (line 15) | final class EngagementDashboard extends BaseDashboard
method getWidgets (line 36) | public function getWidgets(): array
method getColumns (line 44) | public function getColumns(): array
method getHeaderActions (line 52) | protected function getHeaderActions(): array
FILE: packages/SystemAdmin/src/Filament/Resources/CompanyResource.php
class CompanyResource (line 27) | final class CompanyResource extends Resource
method getNavigationBadge (line 43) | public static function getNavigationBadge(): ?string
method form (line 50) | #[Override]
method table (line 71) | #[Override]
method getRelations (line 129) | #[Override]
method getPages (line 135) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/CompanyResource/Pages/CreateCompany.php
class CreateCompany (line 10) | final class CreateCompany extends CreateRecord
FILE: packages/SystemAdmin/src/Filament/Resources/CompanyResource/Pages/EditCompany.php
class EditCompany (line 13) | final class EditCompany extends EditRecord
method getHeaderActions (line 17) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/CompanyResource/Pages/ListCompanies.php
class ListCompanies (line 12) | final class ListCompanies extends ListRecords
method getHeaderActions (line 16) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/CompanyResource/Pages/ViewCompany.php
class ViewCompany (line 12) | final class ViewCompany extends ViewRecord
method getHeaderActions (line 16) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/ImportResource.php
class ImportResource (line 23) | final class ImportResource extends Resource
method getNavigationBadge (line 39) | public static function getNavigationBadge(): ?string
method infolist (line 46) | #[Override]
method table (line 74) | #[Override]
method getRelations (line 132) | #[Override]
method getPages (line 140) | #[Override]
method statusColor (line 149) | private static function statusColor(ImportStatus $state): string
FILE: packages/SystemAdmin/src/Filament/Resources/ImportResource/Pages/ListImports.php
class ListImports (line 10) | final class ListImports extends ListRecords
FILE: packages/SystemAdmin/src/Filament/Resources/ImportResource/Pages/ViewImport.php
class ViewImport (line 10) | final class ViewImport extends ViewRecord
FILE: packages/SystemAdmin/src/Filament/Resources/ImportResource/RelationManagers/FailedRowsRelationManager.php
class FailedRowsRelationManager (line 13) | final class FailedRowsRelationManager extends RelationManager
method getBadge (line 19) | public static function getBadge(Model $ownerRecord, string $pageClass)...
method table (line 26) | public function table(Table $table): Table
FILE: packages/SystemAdmin/src/Filament/Resources/NoteResource.php
class NoteResource (line 27) | final class NoteResource extends Resource
method getNavigationBadge (line 43) | public static function getNavigationBadge(): ?string
method form (line 50) | #[Override]
method table (line 67) | #[Override]
method getRelations (line 122) | #[Override]
method getPages (line 128) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/NoteResource/Pages/CreateNote.php
class CreateNote (line 10) | final class CreateNote extends CreateRecord
FILE: packages/SystemAdmin/src/Filament/Resources/NoteResource/Pages/EditNote.php
class EditNote (line 13) | final class EditNote extends EditRecord
method getHeaderActions (line 17) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/NoteResource/Pages/ListNotes.php
class ListNotes (line 12) | final class ListNotes extends ListRecords
method getHeaderActions (line 16) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/NoteResource/Pages/ViewNote.php
class ViewNote (line 12) | final class ViewNote extends ViewRecord
method getHeaderActions (line 16) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/OpportunityResource.php
class OpportunityResource (line 27) | final class OpportunityResource extends Resource
method getNavigationBadge (line 43) | public static function getNavigationBadge(): ?string
method form (line 50) | #[Override]
method table (line 74) | #[Override]
method getRelations (line 139) | #[Override]
method getPages (line 145) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/OpportunityResource/Pages/CreateOpportunity.php
class CreateOpportunity (line 10) | final class CreateOpportunity extends CreateRecord
FILE: packages/SystemAdmin/src/Filament/Resources/OpportunityResource/Pages/EditOpportunity.php
class EditOpportunity (line 13) | final class EditOpportunity extends EditRecord
method getHeaderActions (line 17) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/OpportunityResource/Pages/ListOpportunities.php
class ListOpportunities (line 12) | final class ListOpportunities extends ListRecords
method getHeaderActions (line 16) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/OpportunityResource/Pages/ViewOpportunity.php
class ViewOpportunity (line 12) | final class ViewOpportunity extends ViewRecord
method getHeaderActions (line 16) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/PeopleResource.php
class PeopleResource (line 27) | final class PeopleResource extends Resource
method getNavigationBadge (line 43) | public static function getNavigationBadge(): ?string
method form (line 50) | #[Override]
method table (line 71) | #[Override]
method getRelations (line 133) | #[Override]
method getPages (line 139) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/PeopleResource/Pages/CreatePeople.php
class CreatePeople (line 10) | final class CreatePeople extends CreateRecord
FILE: packages/SystemAdmin/src/Filament/Resources/PeopleResource/Pages/EditPeople.php
class EditPeople (line 13) | final class EditPeople extends EditRecord
method getHeaderActions (line 17) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/PeopleResource/Pages/ListPeople.php
class ListPeople (line 12) | final class ListPeople extends ListRecords
method getHeaderActions (line 16) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/PeopleResource/Pages/ViewPeople.php
class ViewPeople (line 11) | final class ViewPeople extends ViewRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: packages/SystemAdmin/src/Filament/Resources/SystemAdministrators/Pages/CreateSystemAdministrator.php
class CreateSystemAdministrator (line 11) | final class CreateSystemAdministrator extends CreateRecord
method getFormActions (line 15) | protected function getFormActions(): array
method getCancelAction (line 23) | private function getCancelAction(): Action
FILE: packages/SystemAdmin/src/Filament/Resources/SystemAdministrators/Pages/EditSystemAdministrator.php
class EditSystemAdministrator (line 12) | final class EditSystemAdministrator extends EditRecord
method getHeaderActions (line 16) | protected function getHeaderActions(): array
FILE: packages/SystemAdmin/src/Filament/Resources/SystemAdministrators/Pages/ListSystemAdministrators.php
class ListSystemAdministrators (line 11) | final class ListSystemAdministrators extends ListRecords
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: packages/SystemAdmin/src/Filament/Resources/SystemAdministrators/Pages/ViewSystemAdministrator.php
class ViewSystemAdministrator (line 11) | final class ViewSystemAdministrator extends ViewRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: packages/SystemAdmin/src/Filament/Resources/SystemAdministrators/Schemas/SystemAdministratorForm.php
class SystemAdministratorForm (line 16) | final class SystemAdministratorForm
method configure (line 18) | public static function configure(Schema $schema): Schema
FILE: packages/SystemAdmin/src/Filament/Resources/SystemAdministrators/Schemas/SystemAdministratorInfolist.php
class SystemAdministratorInfolist (line 10) | final class SystemAdministratorInfolist
method configure (line 12) | public static function configure(Schema $schema): Schema
FILE: packages/SystemAdmin/src/Filament/Resources/SystemAdministrators/SystemAdministratorResource.php
class SystemAdministratorResource (line 23) | final class SystemAdministratorResource extends Resource
method form (line 33) | public static function form(Schema $schema): Schema
method infolist (line 38) | public static function infolist(Schema $schema): Schema
method table (line 43) | public static function table(Table $table): Table
method getRelations (line 48) | public static function getRelations(): array
method getPages (line 55) | public static function getPages(): array
method getEloquentQuery (line 65) | public static function getEloquentQuery(): Builder
FILE: packages/SystemAdmin/src/Filament/Resources/SystemAdministrators/Tables/SystemAdministratorsTable.php
class SystemAdministratorsTable (line 18) | final class SystemAdministratorsTable
method configure (line 20) | public static function configure(Table $table): Table
FILE: packages/SystemAdmin/src/Filament/Resources/TaskResource.php
class TaskResource (line 27) | final class TaskResource extends Resource
method getNavigationBadge (line 43) | public static function getNavigationBadge(): ?string
method form (line 50) | #[Override]
method table (line 68) | #[Override]
method getRelations (line 122) | #[Override]
method getPages (line 128) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/TaskResource/Pages/CreateTask.php
class CreateTask (line 10) | final class CreateTask extends CreateRecord
FILE: packages/SystemAdmin/src/Filament/Resources/TaskResource/Pages/EditTask.php
class EditTask (line 13) | final class EditTask extends EditRecord
method getHeaderActions (line 17) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/TaskResource/Pages/ListTasks.php
class ListTasks (line 12) | final class ListTasks extends ListRecords
method getHeaderActions (line 16) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/TaskResource/Pages/ViewTask.php
class ViewTask (line 12) | final class ViewTask extends ViewRecord
method getHeaderActions (line 16) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/TeamResource.php
class TeamResource (line 37) | final class TeamResource extends Resource
method getNavigationBadge (line 53) | public static function getNavigationBadge(): ?string
method form (line 60) | #[Override]
method infolist (line 83) | #[Override]
method table (line 104) | #[Override]
method getRelations (line 146) | #[Override]
method getPages (line 159) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/TeamResource/Pages/CreateTeam.php
class CreateTeam (line 10) | final class CreateTeam extends CreateRecord
FILE: packages/SystemAdmin/src/Filament/Resources/TeamResource/Pages/EditTeam.php
class EditTeam (line 11) | final class EditTeam extends EditRecord
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: packages/SystemAdmin/src/Filament/Resources/TeamResource/Pages/ListTeams.php
class ListTeams (line 11) | final class ListTeams extends ListRecords
method getHeaderActions (line 15) | protected function getHeaderActions(): array
FILE: packages/SystemAdmin/src/Filament/Resources/TeamResource/Pages/ViewTeam.php
class ViewTeam (line 12) | final class ViewTeam extends ViewRecord
method getHeaderActions (line 16) | #[Override]
FILE: packages/SystemAdmin/src/Filament/Resources/TeamResource/RelationManagers/CompaniesRelationManager.php
class CompaniesRelationManager (line 12) | final class CompaniesRelationManager extends RelationManager
method getBadge (line 18) | public static function getBadge(Model $ownerRecord, string $pageClass)...
method table (line 25) | public function table(Table $table): Table
FILE: packages/SystemAdmin/src/Filament/Resources/TeamResource/RelationManagers/MembersRelationManager.php
class MembersRelationManager (line 12) | final class MembersRelationM
Condensed preview — 911 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (7,895K chars).
[
{
"path": ".dockerignore",
"chars": 967,
"preview": "# Git\n.git\n.gitignore\n.gitattributes\n.githooks\n\n# IDE\n.idea\n.vscode\n*.swp\n*.swo\n\n# Dependencies (will be installed durin"
},
{
"path": ".editorconfig",
"chars": 261,
"preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = space\ninsert_final_newline = true\ntrim_"
},
{
"path": ".gitattributes",
"chars": 186,
"preview": "* text=auto eol=lf\n\n*.blade.php diff=html\n*.css diff=css\n*.html diff=html\n*.md diff=markdown\n*.php diff=php\n\n/.github ex"
},
{
"path": ".githooks/pre-commit",
"chars": 38,
"preview": "#!/bin/sh\ncomposer lint\ncomposer test\n"
},
{
"path": ".github/ISSUE_TEMPLATE/1-bug_report.yml",
"chars": 2648,
"preview": "name: Bug report\ndescription: Report a problem you're experiencing with Relaticle\nlabels: [\"bug\", \"unconfirmed\"]\nproject"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 490,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Feature request or idea\n url: https://github.com/Relaticle/relat"
},
{
"path": ".github/copilot-instructions.md",
"chars": 6337,
"preview": "# Relaticle Code Review Guidelines\n\n## Repository Context\n\nMulti-tenant SaaS CRM with paying customers. Tenant isolation"
},
{
"path": ".github/workflows/docker-publish.yml",
"chars": 6114,
"preview": "name: Build and Push Docker Image\n\non:\n push:\n branches: [main]\n tags: ['v*']\n pull_request:\n branches: [main"
},
{
"path": ".github/workflows/filament-view-monitor-simple.yml",
"chars": 4541,
"preview": "name: Monitor Filament View Updates (Simple)\n\non:\n schedule:\n # Run daily at 9 AM UTC\n - cron: '0 9 * * *'\n work"
},
{
"path": ".github/workflows/tests.yml",
"chars": 5863,
"preview": "name: Tests\n\non: [push]\n\njobs:\n lint-and-static-analysis:\n runs-on: ubuntu-latest\n name: Code Quality Checks\n\n "
},
{
"path": ".gitignore",
"chars": 677,
"preview": ".DS_Store\n.superpowers\n/.phpunit.cache\n.scribe\n/node_modules\n/public/build\n/public/hot\n/public/storage\n/public/sitemap.x"
},
{
"path": "CLAUDE.md",
"chars": 28619,
"preview": "<laravel-boost-guidelines>\n=== .ai/core rules ===\n\n# Project\n\nThis is production code for a commercial SaaS product with"
},
{
"path": "Dockerfile",
"chars": 2668,
"preview": "# syntax=docker/dockerfile:1\n\n###########################################\n# Stage 1: Composer dependencies\n#############"
},
{
"path": "LICENSE",
"chars": 34523,
"preview": " GNU AFFERO GENERAL PUBLIC LICENSE\n Version 3, 19 November 2007\n\n Copyright (C)"
},
{
"path": "README.md",
"chars": 4275,
"preview": "<p align=\"center\">\n <a href=\"https://relaticle.com\">\n <img src=\"https://relaticle.com/brand/logomark.svg\" width=\"100"
},
{
"path": "TODOS.md",
"chars": 2013,
"preview": "# TODOs\n\nDeferred work from plan reviews. Each item includes context and reasoning so it can be picked up without the or"
},
{
"path": "app/Actions/Company/CreateCompany.php",
"chars": 772,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Company;\n\nuse App\\Enums\\CreationSource;\nuse App\\Models\\Company;\nu"
},
{
"path": "app/Actions/Company/DeleteCompany.php",
"chars": 314,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Company;\n\nuse App\\Models\\Company;\nuse App\\Models\\User;\n\nfinal rea"
},
{
"path": "app/Actions/Company/ListCompanies.php",
"chars": 2203,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Company;\n\nuse App\\Mcp\\Filters\\CustomFieldFilter;\nuse App\\Mcp\\Sche"
},
{
"path": "app/Actions/Company/UpdateCompany.php",
"chars": 824,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Company;\n\nuse App\\Models\\Company;\nuse App\\Models\\User;\nuse App\\Su"
},
{
"path": "app/Actions/Fortify/CreateNewSocialUser.php",
"chars": 1123,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Fortify;\n\nuse App\\Contracts\\User\\CreatesNewSocialUsers;\nuse App\\M"
},
{
"path": "app/Actions/Fortify/PasswordValidationRules.php",
"chars": 450,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Fortify;\n\nuse Illuminate\\Contracts\\Validation\\Rule;\nuse Illuminat"
},
{
"path": "app/Actions/Fortify/ResetUserPassword.php",
"chars": 734,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Fortify;\n\nuse App\\Models\\User;\nuse Illuminate\\Support\\Facades\\Has"
},
{
"path": "app/Actions/Fortify/UpdateUserPassword.php",
"chars": 965,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Fortify;\n\nuse App\\Models\\User;\nuse Illuminate\\Support\\Facades\\Has"
},
{
"path": "app/Actions/Fortify/UpdateUserProfileInformation.php",
"chars": 1816,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Fortify;\n\nuse App\\Models\\User;\nuse Illuminate\\Support\\Facades\\Val"
},
{
"path": "app/Actions/Jetstream/AddTeamMember.php",
"chars": 2362,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Models\\Team;\nuse App\\Models\\User;\nuse Closure"
},
{
"path": "app/Actions/Jetstream/CreateTeam.php",
"chars": 1254,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Models\\Team;\nuse App\\Models\\User;\nuse App\\Rul"
},
{
"path": "app/Actions/Jetstream/DeleteTeam.php",
"chars": 322,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Models\\Team;\nuse Laravel\\Jetstream\\Contracts\\"
},
{
"path": "app/Actions/Jetstream/DeleteUser.php",
"chars": 1126,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Models\\Team;\nuse App\\Models\\User;\nuse Illumin"
},
{
"path": "app/Actions/Jetstream/InviteTeamMember.php",
"chars": 2917,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Models\\Team;\nuse App\\Models\\User;\nuse Closure"
},
{
"path": "app/Actions/Jetstream/RemoveTeamMember.php",
"chars": 1588,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Models\\Team;\nuse App\\Models\\User;\nuse Illumin"
},
{
"path": "app/Actions/Jetstream/UpdateTeamName.php",
"chars": 982,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Jetstream;\n\nuse App\\Models\\Team;\nuse App\\Models\\User;\nuse App\\Rul"
},
{
"path": "app/Actions/Note/CreateNote.php",
"chars": 1376,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Note;\n\nuse App\\Enums\\CreationSource;\nuse App\\Models\\Note;\nuse App"
},
{
"path": "app/Actions/Note/DeleteNote.php",
"chars": 293,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Note;\n\nuse App\\Models\\Note;\nuse App\\Models\\User;\n\nfinal readonly "
},
{
"path": "app/Actions/Note/ListNotes.php",
"chars": 2241,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Note;\n\nuse App\\Mcp\\Filters\\CustomFieldFilter;\nuse App\\Mcp\\Schema\\"
},
{
"path": "app/Actions/Note/UpdateNote.php",
"chars": 1212,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Note;\n\nuse App\\Models\\Note;\nuse App\\Models\\User;\nuse App\\Support\\"
},
{
"path": "app/Actions/Opportunity/CreateOpportunity.php",
"chars": 836,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Opportunity;\n\nuse App\\Enums\\CreationSource;\nuse App\\Models\\Opport"
},
{
"path": "app/Actions/Opportunity/DeleteOpportunity.php",
"chars": 342,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Opportunity;\n\nuse App\\Models\\Opportunity;\nuse App\\Models\\User;\n\nf"
},
{
"path": "app/Actions/Opportunity/ListOpportunities.php",
"chars": 2188,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Opportunity;\n\nuse App\\Mcp\\Filters\\CustomFieldFilter;\nuse App\\Mcp\\"
},
{
"path": "app/Actions/Opportunity/UpdateOpportunity.php",
"chars": 900,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Opportunity;\n\nuse App\\Models\\Opportunity;\nuse App\\Models\\User;\nus"
},
{
"path": "app/Actions/People/CreatePeople.php",
"chars": 777,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\People;\n\nuse App\\Enums\\CreationSource;\nuse App\\Models\\People;\nuse"
},
{
"path": "app/Actions/People/DeletePeople.php",
"chars": 307,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\People;\n\nuse App\\Models\\People;\nuse App\\Models\\User;\n\nfinal reado"
},
{
"path": "app/Actions/People/ListPeople.php",
"chars": 2064,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\People;\n\nuse App\\Mcp\\Filters\\CustomFieldFilter;\nuse App\\Mcp\\Schem"
},
{
"path": "app/Actions/People/UpdatePeople.php",
"chars": 826,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\People;\n\nuse App\\Models\\People;\nuse App\\Models\\User;\nuse App\\Supp"
},
{
"path": "app/Actions/Task/CreateTask.php",
"chars": 1704,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Task;\n\nuse App\\Enums\\CreationSource;\nuse App\\Models\\Task;\nuse App"
},
{
"path": "app/Actions/Task/DeleteTask.php",
"chars": 293,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Task;\n\nuse App\\Models\\Task;\nuse App\\Models\\User;\n\nfinal readonly "
},
{
"path": "app/Actions/Task/ListTasks.php",
"chars": 2775,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Task;\n\nuse App\\Mcp\\Filters\\CustomFieldFilter;\nuse App\\Mcp\\Schema\\"
},
{
"path": "app/Actions/Task/NotifyTaskAssignees.php",
"chars": 1921,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Task;\n\nuse App\\Filament\\Resources\\TaskResource\\Pages\\ManageTasks;"
},
{
"path": "app/Actions/Task/UpdateTask.php",
"chars": 1653,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Actions\\Task;\n\nuse App\\Models\\Task;\nuse App\\Models\\User;\nuse App\\Support\\"
},
{
"path": "app/Concerns/DetectsTeamInvitation.php",
"chars": 1671,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Concerns;\n\nuse App\\Models\\TeamInvitation;\nuse Illuminate\\Contracts\\Suppor"
},
{
"path": "app/Console/Commands/BackfillCustomFieldColorsCommand.php",
"chars": 5436,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands;\n\nuse App\\Enums\\CustomFields\\OpportunityField as Opportu"
},
{
"path": "app/Console/Commands/CleanupExpiredInvitationsCommand.php",
"chars": 1206,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands;\n\nuse App\\Models\\TeamInvitation;\nuse Illuminate\\Console\\"
},
{
"path": "app/Console/Commands/CreateSystemAdminCommand.php",
"chars": 6043,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands;\n\nuse Illuminate\\Console\\Command;\nuse Relaticle\\SystemAd"
},
{
"path": "app/Console/Commands/GenerateSitemapCommand.php",
"chars": 681,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands;\n\nuse Illuminate\\Console\\Command;\nuse Spatie\\Sitemap\\Sit"
},
{
"path": "app/Console/Commands/InstallCommand.php",
"chars": 14702,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Console\\Commands;\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Support"
},
{
"path": "app/Contracts/User/CreatesNewSocialUsers.php",
"chars": 271,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Contracts\\User;\n\nuse App\\Models\\User;\n\ninterface CreatesNewSocialUsers\n{\n"
},
{
"path": "app/Data/SubscriberData.php",
"chars": 396,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Data;\n\nuse Spatie\\LaravelData\\Data;\n\nfinal class SubscriberData extends D"
},
{
"path": "app/Enums/CreationSource.php",
"chars": 1960,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nuse Filament\\Support\\Contracts\\HasColor;\nuse Filament\\Support\\Con"
},
{
"path": "app/Enums/CustomFieldType.php",
"chars": 981,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\n/**\n * ABOUTME: Maps to the field types available in the relaticl"
},
{
"path": "app/Enums/CustomFields/CompanyField.php",
"chars": 1981,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums\\CustomFields;\n\nuse App\\Enums\\CustomFieldType;\n\nenum CompanyField: s"
},
{
"path": "app/Enums/CustomFields/CustomFieldTrait.php",
"chars": 4430,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums\\CustomFields;\n\nuse Illuminate\\Support\\Str;\nuse Relaticle\\CustomFiel"
},
{
"path": "app/Enums/CustomFields/NoteField.php",
"chars": 646,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums\\CustomFields;\n\nuse App\\Enums\\CustomFieldType;\n\n/**\n * Note custom f"
},
{
"path": "app/Enums/CustomFields/OpportunityField.php",
"chars": 3041,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums\\CustomFields;\n\nuse App\\Enums\\CustomFieldType;\n\nenum OpportunityFiel"
},
{
"path": "app/Enums/CustomFields/PeopleField.php",
"chars": 1631,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums\\CustomFields;\n\nuse App\\Enums\\CustomFieldType;\n\n/**\n * People custom"
},
{
"path": "app/Enums/CustomFields/TaskField.php",
"chars": 4614,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums\\CustomFields;\n\nuse App\\Enums\\CustomFieldType;\nuse Relaticle\\CustomF"
},
{
"path": "app/Enums/SocialiteProvider.php",
"chars": 146,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nenum SocialiteProvider: string\n{\n case GOOGLE = 'google';\n "
},
{
"path": "app/Enums/SubscriberTagEnum.php",
"chars": 122,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Enums;\n\nenum SubscriberTagEnum: string\n{\n case VERIFIED = 'verified';\n"
},
{
"path": "app/Filament/Actions/GenerateRecordSummaryAction.php",
"chars": 3160,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Actions;\n\nuse App\\Models\\AiSummary;\nuse App\\Services\\AI\\RecordSu"
},
{
"path": "app/Filament/Components/Infolists/AvatarName.php",
"chars": 2557,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Components\\Infolists;\n\nuse Filament\\Infolists\\Components\\Entry;\n"
},
{
"path": "app/Filament/Exports/BaseExporter.php",
"chars": 1473,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Exports;\n\nuse App\\Models\\Team;\nuse Filament\\Actions\\Exports\\Expo"
},
{
"path": "app/Filament/Exports/CompanyExporter.php",
"chars": 2419,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Exports;\n\nuse App\\Models\\Company;\nuse Carbon\\Carbon;\nuse Filamen"
},
{
"path": "app/Filament/Exports/NoteExporter.php",
"chars": 1492,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Exports;\n\nuse App\\Models\\Note;\nuse Filament\\Actions\\Exports\\Expo"
},
{
"path": "app/Filament/Exports/OpportunityExporter.php",
"chars": 2515,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Exports;\n\nuse App\\Models\\Opportunity;\nuse Carbon\\Carbon;\nuse Fil"
},
{
"path": "app/Filament/Exports/PeopleExporter.php",
"chars": 1629,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Exports;\n\nuse App\\Models\\People;\nuse Filament\\Actions\\Exports\\Ex"
},
{
"path": "app/Filament/Exports/TaskExporter.php",
"chars": 1485,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Exports;\n\nuse App\\Models\\Task;\nuse Filament\\Actions\\Exports\\Expo"
},
{
"path": "app/Filament/Pages/AccessTokens.php",
"chars": 899,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Pages;\n\nuse App\\Livewire\\App\\AccessTokens\\CreateAccessToken;\nuse"
},
{
"path": "app/Filament/Pages/Auth/Login.php",
"chars": 1169,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Pages\\Auth;\n\nuse App\\Concerns\\DetectsTeamInvitation;\nuse Filamen"
},
{
"path": "app/Filament/Pages/Auth/Register.php",
"chars": 1992,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Pages\\Auth;\n\nuse App\\Concerns\\DetectsTeamInvitation;\nuse Filamen"
},
{
"path": "app/Filament/Pages/CreateTeam.php",
"chars": 2858,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Pages;\n\nuse App\\Actions\\Jetstream\\CreateTeam as CreateTeamAction"
},
{
"path": "app/Filament/Pages/EditProfile.php",
"chars": 1183,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Pages;\n\nuse App\\Livewire\\App\\Profile\\DeleteAccount;\nuse App\\Live"
},
{
"path": "app/Filament/Pages/EditTeam.php",
"chars": 1448,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Pages;\n\nuse App\\Livewire\\App\\Teams\\AddTeamMember;\nuse App\\Livewi"
},
{
"path": "app/Filament/Pages/OpportunitiesBoard.php",
"chars": 11963,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Pages;\n\nuse App\\Enums\\CustomFields\\OpportunityField as Opportuni"
},
{
"path": "app/Filament/Pages/TasksBoard.php",
"chars": 11169,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Pages;\n\nuse App\\Enums\\CustomFields\\TaskField as TaskCustomField;"
},
{
"path": "app/Filament/Resources/CompanyResource/Pages/ListCompanies.php",
"chars": 1558,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\CompanyResource\\Pages;\n\nuse App\\Filament\\Exports\\Compa"
},
{
"path": "app/Filament/Resources/CompanyResource/Pages/ViewCompany.php",
"chars": 5150,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\CompanyResource\\Pages;\n\nuse App\\Filament\\Actions\\Gener"
},
{
"path": "app/Filament/Resources/CompanyResource/RelationManagers/NotesRelationManager.php",
"chars": 2175,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\CompanyResource\\RelationManagers;\n\nuse App\\Filament\\Re"
},
{
"path": "app/Filament/Resources/CompanyResource/RelationManagers/PeopleRelationManager.php",
"chars": 2042,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\CompanyResource\\RelationManagers;\n\nuse Filament\\Action"
},
{
"path": "app/Filament/Resources/CompanyResource/RelationManagers/TasksRelationManager.php",
"chars": 2326,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\CompanyResource\\RelationManagers;\n\nuse App\\Filament\\Re"
},
{
"path": "app/Filament/Resources/CompanyResource.php",
"chars": 5096,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Enums\\CreationSource;\nuse App\\Filament\\Expor"
},
{
"path": "app/Filament/Resources/NoteResource/Forms/NoteForm.php",
"chars": 1468,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\NoteResource\\Forms;\n\nuse Filament\\Forms\\Components\\Sel"
},
{
"path": "app/Filament/Resources/NoteResource/Pages/ManageNotes.php",
"chars": 1408,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\NoteResource\\Pages;\n\nuse App\\Filament\\Exports\\NoteExpo"
},
{
"path": "app/Filament/Resources/NoteResource.php",
"chars": 4210,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Enums\\CreationSource;\nuse App\\Filament\\Expor"
},
{
"path": "app/Filament/Resources/OpportunityResource/Forms/OpportunityForm.php",
"chars": 1095,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OpportunityResource\\Forms;\n\nuse Filament\\Forms\\Compone"
},
{
"path": "app/Filament/Resources/OpportunityResource/Pages/ListOpportunities.php",
"chars": 1469,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OpportunityResource\\Pages;\n\nuse App\\Filament\\Exports\\O"
},
{
"path": "app/Filament/Resources/OpportunityResource/Pages/ViewOpportunity.php",
"chars": 3758,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OpportunityResource\\Pages;\n\nuse App\\Filament\\Actions\\G"
},
{
"path": "app/Filament/Resources/OpportunityResource/RelationManagers/NotesRelationManager.php",
"chars": 1974,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OpportunityResource\\RelationManagers;\n\nuse App\\Filamen"
},
{
"path": "app/Filament/Resources/OpportunityResource/RelationManagers/TasksRelationManager.php",
"chars": 1974,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\OpportunityResource\\RelationManagers;\n\nuse App\\Filamen"
},
{
"path": "app/Filament/Resources/OpportunityResource.php",
"chars": 4465,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Enums\\CreationSource;\nuse App\\Filament\\Expor"
},
{
"path": "app/Filament/Resources/PeopleResource/Pages/ListPeople.php",
"chars": 1416,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\PeopleResource\\Pages;\n\nuse App\\Filament\\Exports\\People"
},
{
"path": "app/Filament/Resources/PeopleResource/Pages/ViewPeople.php",
"chars": 3635,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\PeopleResource\\Pages;\n\nuse App\\Filament\\Actions\\Genera"
},
{
"path": "app/Filament/Resources/PeopleResource/RelationManagers/NotesRelationManager.php",
"chars": 1629,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\PeopleResource\\RelationManagers;\n\nuse App\\Filament\\Res"
},
{
"path": "app/Filament/Resources/PeopleResource/RelationManagers/TasksRelationManager.php",
"chars": 1628,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\PeopleResource\\RelationManagers;\n\nuse App\\Filament\\Res"
},
{
"path": "app/Filament/Resources/PeopleResource.php",
"chars": 7199,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Enums\\CreationSource;\nuse App\\Filament\\Expor"
},
{
"path": "app/Filament/Resources/TaskResource/Forms/TaskForm.php",
"chars": 1506,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TaskResource\\Forms;\n\nuse Filament\\Forms\\Components\\Sel"
},
{
"path": "app/Filament/Resources/TaskResource/Pages/ManageTasks.php",
"chars": 1685,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources\\TaskResource\\Pages;\n\nuse App\\Actions\\Task\\NotifyTaskAs"
},
{
"path": "app/Filament/Resources/TaskResource.php",
"chars": 7766,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Filament\\Resources;\n\nuse App\\Actions\\Task\\UpdateTask;\nuse App\\Enums\\Creat"
},
{
"path": "app/Health/AnthropicModelCheck.php",
"chars": 840,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Health;\n\nuse Prism\\Prism\\Enums\\Provider;\nuse Prism\\Prism\\Facades\\Prism;\nu"
},
{
"path": "app/Http/Controllers/AcceptTeamInvitationController.php",
"chars": 1798,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\TeamInvitation;\nuse App\\Models\\User;\nus"
},
{
"path": "app/Http/Controllers/Api/V1/CompaniesController.php",
"chars": 2734,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Actions\\Company\\CreateCompany;\nuse App\\"
},
{
"path": "app/Http/Controllers/Api/V1/CustomFieldsController.php",
"chars": 1325,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Http\\Requests\\Api\\V1\\IndexCustomFieldsR"
},
{
"path": "app/Http/Controllers/Api/V1/NotesController.php",
"chars": 2579,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Actions\\Note\\CreateNote;\nuse App\\Action"
},
{
"path": "app/Http/Controllers/Api/V1/OpportunitiesController.php",
"chars": 3433,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Actions\\Opportunity\\CreateOpportunity;\n"
},
{
"path": "app/Http/Controllers/Api/V1/PeopleController.php",
"chars": 3022,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Actions\\People\\CreatePeople;\nuse App\\Ac"
},
{
"path": "app/Http/Controllers/Api/V1/TasksController.php",
"chars": 2579,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Api\\V1;\n\nuse App\\Actions\\Task\\CreateTask;\nuse App\\Action"
},
{
"path": "app/Http/Controllers/Auth/CallbackController.php",
"chars": 4731,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Auth;\n\nuse App\\Contracts\\User\\CreatesNewSocialUsers;\nuse"
},
{
"path": "app/Http/Controllers/Auth/RedirectController.php",
"chars": 514,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers\\Auth;\n\nuse App\\Enums\\SocialiteProvider;\nuse Laravel\\Soci"
},
{
"path": "app/Http/Controllers/ContactController.php",
"chars": 790,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Http\\Requests\\ContactRequest;\nuse App\\Mail\\New"
},
{
"path": "app/Http/Controllers/HomeController.php",
"chars": 217,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\View\\View;\n\nfinal readonly class HomeCo"
},
{
"path": "app/Http/Controllers/PrivacyPolicyController.php",
"chars": 443,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Support\\Str;\nuse Illuminate\\View\\View;\n"
},
{
"path": "app/Http/Controllers/TermsOfServiceController.php",
"chars": 439,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Support\\Str;\nuse Illuminate\\View\\View;\n"
},
{
"path": "app/Http/Middleware/ApplyTenantScopes.php",
"chars": 1130,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Middleware;\n\nuse App\\Models\\Company;\nuse App\\Models\\Note;\nuse App\\Mo"
},
{
"path": "app/Http/Middleware/EnsureTokenHasAbility.php",
"chars": 1277,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Middleware;\n\nuse App\\Models\\PersonalAccessToken;\nuse Closure;\nuse Il"
},
{
"path": "app/Http/Middleware/ForceJsonResponse.php",
"chars": 375,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Middleware;\n\nuse Closure;\nuse Illuminate\\Http\\Request;\nuse Symfony\\C"
},
{
"path": "app/Http/Middleware/SetApiTeamContext.php",
"chars": 4147,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Middleware;\n\nuse App\\Models\\Company;\nuse App\\Models\\Note;\nuse App\\Mo"
},
{
"path": "app/Http/Middleware/SubdomainRootResponse.php",
"chars": 959,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Middleware;\n\nuse Closure;\nuse Illuminate\\Http\\JsonResponse;\nuse Illu"
},
{
"path": "app/Http/Middleware/ValidateSignature.php",
"chars": 2917,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Middleware;\n\nuse Closure;\nuse Illuminate\\Http\\Request;\nuse Illuminat"
},
{
"path": "app/Http/Requests/Api/V1/IndexCustomFieldsRequest.php",
"chars": 656,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse Illuminate\\Foundation\\Http\\FormRequest;\nuse Il"
},
{
"path": "app/Http/Requests/Api/V1/IndexRequest.php",
"chars": 481,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse Illuminate\\Foundation\\Http\\FormRequest;\n\nfinal"
},
{
"path": "app/Http/Requests/Api/V1/StoreCompanyRequest.php",
"chars": 628,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse App\\Models\\User;\nuse App\\Rules\\ValidCustomFiel"
},
{
"path": "app/Http/Requests/Api/V1/StoreNoteRequest.php",
"chars": 1127,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse App\\Models\\User;\nuse App\\Rules\\ValidCustomFiel"
},
{
"path": "app/Http/Requests/Api/V1/StoreOpportunityRequest.php",
"chars": 889,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse App\\Models\\User;\nuse App\\Rules\\ValidCustomFiel"
},
{
"path": "app/Http/Requests/Api/V1/StorePeopleRequest.php",
"chars": 770,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse App\\Models\\User;\nuse App\\Rules\\ValidCustomFiel"
},
{
"path": "app/Http/Requests/Api/V1/StoreTaskRequest.php",
"chars": 1372,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse App\\Models\\User;\nuse App\\Rules\\ValidCustomFiel"
},
{
"path": "app/Http/Requests/Api/V1/UpdateCompanyRequest.php",
"chars": 658,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse App\\Models\\User;\nuse App\\Rules\\ValidCustomFiel"
},
{
"path": "app/Http/Requests/Api/V1/UpdateNoteRequest.php",
"chars": 1157,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse App\\Models\\User;\nuse App\\Rules\\ValidCustomFiel"
},
{
"path": "app/Http/Requests/Api/V1/UpdateOpportunityRequest.php",
"chars": 919,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse App\\Models\\User;\nuse App\\Rules\\ValidCustomFiel"
},
{
"path": "app/Http/Requests/Api/V1/UpdatePeopleRequest.php",
"chars": 800,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse App\\Models\\User;\nuse App\\Rules\\ValidCustomFiel"
},
{
"path": "app/Http/Requests/Api/V1/UpdateTaskRequest.php",
"chars": 1402,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests\\Api\\V1;\n\nuse App\\Models\\User;\nuse App\\Rules\\ValidCustomFiel"
},
{
"path": "app/Http/Requests/ContactRequest.php",
"chars": 736,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Requests;\n\nuse Illuminate\\Contracts\\Validation\\ValidationRule;\nuse I"
},
{
"path": "app/Http/Resources/V1/CompanyResource.php",
"chars": 1394,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Resources\\V1;\n\nuse App\\Http\\Resources\\V1\\Concerns\\FormatsCustomField"
},
{
"path": "app/Http/Resources/V1/Concerns/FormatsCustomFields.php",
"chars": 2787,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Resources\\V1\\Concerns;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse "
},
{
"path": "app/Http/Resources/V1/CustomFieldResource.php",
"chars": 1237,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Resources\\V1;\n\nuse App\\Models\\CustomField;\nuse App\\Models\\CustomFiel"
},
{
"path": "app/Http/Resources/V1/NoteResource.php",
"chars": 1335,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Resources\\V1;\n\nuse App\\Http\\Resources\\V1\\Concerns\\FormatsCustomField"
},
{
"path": "app/Http/Resources/V1/OpportunityResource.php",
"chars": 1302,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Resources\\V1;\n\nuse App\\Http\\Resources\\V1\\Concerns\\FormatsCustomField"
},
{
"path": "app/Http/Resources/V1/PeopleResource.php",
"chars": 1192,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Resources\\V1;\n\nuse App\\Http\\Resources\\V1\\Concerns\\FormatsCustomField"
},
{
"path": "app/Http/Resources/V1/TaskResource.php",
"chars": 1451,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Resources\\V1;\n\nuse App\\Http\\Resources\\V1\\Concerns\\FormatsCustomField"
},
{
"path": "app/Http/Resources/V1/UserResource.php",
"chars": 471,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Resources\\V1;\n\nuse App\\Models\\User;\nuse Illuminate\\Http\\Request;\nuse"
},
{
"path": "app/Http/Responses/LoginResponse.php",
"chars": 1039,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Responses;\n\nuse App\\Filament\\Resources\\CompanyResource;\nuse Filament"
},
{
"path": "app/Jobs/Email/CreateSubscriberJob.php",
"chars": 862,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Jobs\\Email;\n\nuse App\\Data\\SubscriberData;\nuse Illuminate\\Bus\\Queueable;\nu"
},
{
"path": "app/Jobs/Email/UpdateSubscriberJob.php",
"chars": 1856,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Jobs\\Email;\n\nuse App\\Data\\SubscriberData;\nuse Illuminate\\Bus\\Queueable;\nu"
},
{
"path": "app/Jobs/FetchFaviconForCompany.php",
"chars": 2535,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Jobs;\n\nuse App\\Enums\\CustomFields\\CompanyField;\nuse App\\Models\\Company;\nu"
},
{
"path": "app/Listeners/CreateTeamCustomFields.php",
"chars": 5334,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listeners;\n\nuse App\\Enums\\CustomFields\\CompanyField as CompanyCustomField"
},
{
"path": "app/Listeners/Email/NewSubscriberListener.php",
"chars": 1685,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listeners\\Email;\n\nuse App\\Data\\SubscriberData;\nuse App\\Enums\\SubscriberTa"
},
{
"path": "app/Listeners/SwitchTeam.php",
"chars": 410,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Listeners;\n\nuse App\\Models\\User;\nuse Filament\\Events\\TenantSet;\n\nfinal re"
},
{
"path": "app/Livewire/App/AccessTokens/CreateAccessToken.php",
"chars": 6881,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire\\App\\AccessTokens;\n\nuse App\\Livewire\\BaseLivewireComponent;\nuse D"
},
{
"path": "app/Livewire/App/AccessTokens/ManageAccessTokens.php",
"chars": 4165,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire\\App\\AccessTokens;\n\nuse App\\Livewire\\BaseLivewireComponent;\nuse A"
},
{
"path": "app/Livewire/App/Profile/DeleteAccount.php",
"chars": 4042,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire\\App\\Profile;\n\nuse App\\Actions\\Jetstream\\DeleteTeam;\nuse App\\Live"
},
{
"path": "app/Livewire/App/Profile/LogoutOtherBrowserSessions.php",
"chars": 5275,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire\\App\\Profile;\n\nuse App\\Livewire\\BaseLivewireComponent;\nuse Filame"
},
{
"path": "app/Livewire/App/Profile/UpdatePassword.php",
"chars": 4032,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire\\App\\Profile;\n\nuse App\\Livewire\\BaseLivewireComponent;\nuse DanHar"
},
{
"path": "app/Livewire/App/Profile/UpdateProfileInformation.php",
"chars": 4983,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire\\App\\Profile;\n\nuse App\\Actions\\Fortify\\UpdateUserProfileInformati"
},
{
"path": "app/Livewire/App/Teams/AddTeamMember.php",
"chars": 4042,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire\\App\\Teams;\n\nuse App\\Actions\\Jetstream\\InviteTeamMember;\nuse App\\"
},
{
"path": "app/Livewire/App/Teams/DeleteTeam.php",
"chars": 2444,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire\\App\\Teams;\n\nuse App\\Actions\\Jetstream\\DeleteTeam as DeleteTeamAc"
},
{
"path": "app/Livewire/App/Teams/PendingTeamInvitations.php",
"chars": 5129,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire\\App\\Teams;\n\nuse App\\Livewire\\BaseLivewireComponent;\nuse App\\Mode"
},
{
"path": "app/Livewire/App/Teams/TeamMembers.php",
"chars": 6977,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire\\App\\Teams;\n\nuse App\\Actions\\Jetstream\\RemoveTeamMember as Remove"
},
{
"path": "app/Livewire/App/Teams/UpdateTeamName.php",
"chars": 3802,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire\\App\\Teams;\n\nuse App\\Actions\\Jetstream\\UpdateTeamName as UpdateTe"
},
{
"path": "app/Livewire/BaseLivewireComponent.php",
"chars": 1463,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire;\n\nuse App\\Models\\User;\nuse DanHarrin\\LivewireRateLimiting\\Except"
},
{
"path": "app/Livewire/UpdateProfileInformationForm.php",
"chars": 2271,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Livewire;\n\nuse Illuminate\\Contracts\\Auth\\Authenticatable;\nuse Illuminate\\"
},
{
"path": "app/Mail/NewContactSubmissionMail.php",
"chars": 902,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mail;\n\nuse Illuminate\\Bus\\Queueable;\nuse Illuminate\\Contracts\\Queue\\Shoul"
},
{
"path": "app/Mcp/Filters/CustomFieldFilter.php",
"chars": 3143,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Filters;\n\nuse App\\Models\\CustomField;\nuse App\\Models\\User;\nuse Illumi"
},
{
"path": "app/Mcp/Filters/CustomFieldSort.php",
"chars": 2070,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Filters;\n\nuse App\\Models\\CustomField;\nuse App\\Models\\User;\nuse Illumi"
},
{
"path": "app/Mcp/Prompts/CrmOverviewPrompt.php",
"chars": 2383,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Prompts;\n\nuse App\\Models\\Company;\nuse App\\Models\\Note;\nuse App\\Models"
},
{
"path": "app/Mcp/Resources/CompanySchemaResource.php",
"chars": 2304,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Resources;\n\nuse App\\Mcp\\Resources\\Concerns\\ResolvesEntitySchema;\nuse "
},
{
"path": "app/Mcp/Resources/Concerns/ResolvesEntitySchema.php",
"chars": 3750,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Resources\\Concerns;\n\nuse App\\Mcp\\Schema\\CustomFieldFilterSchema;\nuse "
},
{
"path": "app/Mcp/Resources/CrmSummaryResource.php",
"chars": 5855,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Resources;\n\nuse App\\Enums\\CustomFields\\OpportunityField;\nuse App\\Enum"
},
{
"path": "app/Mcp/Resources/NoteSchemaResource.php",
"chars": 2942,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Resources;\n\nuse App\\Mcp\\Resources\\Concerns\\ResolvesEntitySchema;\nuse "
},
{
"path": "app/Mcp/Resources/OpportunitySchemaResource.php",
"chars": 2297,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Resources;\n\nuse App\\Mcp\\Resources\\Concerns\\ResolvesEntitySchema;\nuse "
},
{
"path": "app/Mcp/Resources/PeopleSchemaResource.php",
"chars": 2146,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Resources;\n\nuse App\\Mcp\\Resources\\Concerns\\ResolvesEntitySchema;\nuse "
},
{
"path": "app/Mcp/Resources/TaskSchemaResource.php",
"chars": 3308,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Resources;\n\nuse App\\Mcp\\Resources\\Concerns\\ResolvesEntitySchema;\nuse "
},
{
"path": "app/Mcp/Schema/CustomFieldFilterSchema.php",
"chars": 4694,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Schema;\n\nuse App\\Enums\\CustomFieldType;\nuse App\\Mcp\\Filters\\CustomFie"
},
{
"path": "app/Mcp/Servers/RelaticleServer.php",
"chars": 3768,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Servers;\n\nuse App\\Mcp\\Prompts\\CrmOverviewPrompt;\nuse App\\Mcp\\Resource"
},
{
"path": "app/Mcp/Tools/BaseAttachTool.php",
"chars": 2698,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools;\n\nuse App\\Mcp\\Tools\\Concerns\\BuildsRelationshipResponse;\nuse Ap"
},
{
"path": "app/Mcp/Tools/BaseCreateTool.php",
"chars": 2286,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools;\n\nuse App\\Enums\\CreationSource;\nuse App\\Mcp\\Tools\\Concerns\\Chec"
},
{
"path": "app/Mcp/Tools/BaseDeleteTool.php",
"chars": 1898,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools;\n\nuse App\\Mcp\\Tools\\Concerns\\ChecksTokenAbility;\nuse App\\Models"
},
{
"path": "app/Mcp/Tools/BaseDetachTool.php",
"chars": 2702,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools;\n\nuse App\\Mcp\\Tools\\Concerns\\BuildsRelationshipResponse;\nuse Ap"
},
{
"path": "app/Mcp/Tools/BaseListTool.php",
"chars": 5525,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools;\n\nuse App\\Mcp\\Tools\\Concerns\\ChecksTokenAbility;\nuse App\\Mcp\\To"
},
{
"path": "app/Mcp/Tools/BaseShowTool.php",
"chars": 3635,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools;\n\nuse App\\Mcp\\Tools\\Concerns\\ChecksTokenAbility;\nuse App\\Mcp\\To"
},
{
"path": "app/Mcp/Tools/BaseUpdateTool.php",
"chars": 3101,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools;\n\nuse App\\Mcp\\Tools\\Concerns\\ChecksTokenAbility;\nuse App\\Models"
},
{
"path": "app/Mcp/Tools/Company/CreateCompanyTool.php",
"chars": 1092,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Company;\n\nuse App\\Actions\\Company\\CreateCompany;\nuse App\\Http\\R"
},
{
"path": "app/Mcp/Tools/Company/DeleteCompanyTool.php",
"chars": 671,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Company;\n\nuse App\\Actions\\Company\\DeleteCompany;\nuse App\\Mcp\\To"
},
{
"path": "app/Mcp/Tools/Company/GetCompanyTool.php",
"chars": 948,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Company;\n\nuse App\\Http\\Resources\\V1\\CompanyResource;\nuse App\\Mc"
},
{
"path": "app/Mcp/Tools/Company/ListCompaniesTool.php",
"chars": 782,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Company;\n\nuse App\\Actions\\Company\\ListCompanies;\nuse App\\Http\\R"
},
{
"path": "app/Mcp/Tools/Company/UpdateCompanyTool.php",
"chars": 1354,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Company;\n\nuse App\\Actions\\Company\\UpdateCompany;\nuse App\\Http\\R"
},
{
"path": "app/Mcp/Tools/Concerns/BuildsRelationshipResponse.php",
"chars": 1360,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Concerns;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illumina"
},
{
"path": "app/Mcp/Tools/Concerns/ChecksTokenAbility.php",
"chars": 595,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Concerns;\n\nuse App\\Models\\PersonalAccessToken;\nuse Laravel\\Sanc"
},
{
"path": "app/Mcp/Tools/Concerns/SerializesRelatedModels.php",
"chars": 3016,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Concerns;\n\nuse Illuminate\\Database\\Eloquent\\Collection as Eloqu"
},
{
"path": "app/Mcp/Tools/Note/AttachNoteToEntitiesTool.php",
"chars": 2495,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Note;\n\nuse App\\Http\\Resources\\V1\\NoteResource;\nuse App\\Mcp\\Tool"
},
{
"path": "app/Mcp/Tools/Note/CreateNoteTool.php",
"chars": 1918,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Note;\n\nuse App\\Actions\\Note\\CreateNote;\nuse App\\Http\\Resources\\"
},
{
"path": "app/Mcp/Tools/Note/DeleteNoteTool.php",
"chars": 728,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Note;\n\nuse App\\Actions\\Note\\DeleteNote;\nuse App\\Mcp\\Tools\\BaseD"
},
{
"path": "app/Mcp/Tools/Note/DetachNoteFromEntitiesTool.php",
"chars": 2447,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Note;\n\nuse App\\Http\\Resources\\V1\\NoteResource;\nuse App\\Mcp\\Tool"
},
{
"path": "app/Mcp/Tools/Note/GetNoteTool.php",
"chars": 911,
"preview": "<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Mcp\\Tools\\Note;\n\nuse App\\Http\\Resources\\V1\\NoteResource;\nuse App\\Mcp\\Tool"
}
]
// ... and 711 more files (download for full content)
About this extraction
This page contains the full source code of the Relaticle/relaticle GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 911 files (7.3 MB), approximately 2.0M tokens, and a symbol index with 10898 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.