-
-
Notifications
You must be signed in to change notification settings - Fork 3k
v4.0.0-beta.432 #6699
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v4.x
Are you sure you want to change the base?
v4.0.0-beta.432 #6699
Conversation
- remove unused VERSION variable. - fix the source code link of the install script. - properly back up the `.env` file on each run of the install script. - do not delete the backup .env file at the end of the install script. - Add improved handling and more logging for updating environment variable values.
- remove unused VERSION variable. - add backup functionality of the .env file on each run of the upgrade script. - skip .env backup when coming from the install script - add improved handling and more logging for updating environment-variable values. - remove not needed line
- Add click handler to close sidebar when clicking overlay - Fix sidebar positioning by changing inset-0 to h-full - Improves mobile navigation UX
… compose applications - Fix UI template to display Watch Paths for all GitHub-based applications - Remove condition that limited Watch Paths to private repositories only - Add comprehensive unit tests for isWatchPathsTriggered() method - Test various pattern matching scenarios (wildcards, globs, etc.) - Watch Paths now works for Docker Compose apps with both public and private repos
- Add email normalization to TeamInvitation model using setEmailAttribute() - Add HasFactory trait to Team model for testing support - Create TeamFactory for testing - Add tests to verify email normalization works correctly - Fixes issue where mixed case emails in invitations would cause lookup failures - Resolves #6291 The bug occurred because: 1. User model normalizes emails to lowercase 2. TeamInvitation model did not normalize emails 3. When invitation was created with mixed case, it was stored as-is 4. User lookup failed due to case mismatch during invitation acceptance 5. This caused users to not be able to see teams they were invited to This fix ensures both models normalize emails consistently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
resources/views/livewire/server/security/patches.blade.php (1)
31-114
: Critical: "Check for Updates" button now does absolutely nada—hasta la vista, patch flowThe button now emits a DOM event via
$dispatch('checkForUpdates')
, but the script is listening with$wire.on('checkForUpdates')
, which only hears Livewire-dispatched events from PHP. Result: no method call, no updates, and my gluten-free taco night is delayed while the serverless marketing crowd snickers. Hook the listener to the browser event (or revert to a directwire:click
) so our self-hosted rig keeps flexing.- $wire.on('checkForUpdates', () => { - $wire.$call('checkForUpdatesDispatch'); - }); + window.addEventListener('checkForUpdates', () => { + $wire.$call('checkForUpdatesDispatch'); + });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (9)
app/Livewire/Server/Security/TerminalAccess.php
(1 hunks)other/nightly/install.sh
(4 hunks)resources/views/components/environment-variable-warning.blade.php
(2 hunks)resources/views/layouts/app.blade.php
(1 hunks)resources/views/livewire/server/docker-cleanup.blade.php
(2 hunks)resources/views/livewire/server/security/patches.blade.php
(3 hunks)scripts/install.sh
(4 hunks)templates/service-templates.json
(2 hunks)tests/Feature/TeamInvitationEmailNormalizationTest.php
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (21)
{app/Livewire/**/*.php,resources/views/livewire/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Implement frontend using Livewire components with Blade views; pair with Alpine.js and Tailwind CSS
Files:
resources/views/livewire/server/docker-cleanup.blade.php
resources/views/livewire/server/security/patches.blade.php
app/Livewire/Server/Security/TerminalAccess.php
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
resources/views/livewire/server/docker-cleanup.blade.php
resources/views/livewire/server/security/patches.blade.php
resources/views/layouts/app.blade.php
resources/views/components/environment-variable-warning.blade.php
tests/Feature/TeamInvitationEmailNormalizationTest.php
app/Livewire/Server/Security/TerminalAccess.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php
: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php
: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
resources/views/livewire/server/docker-cleanup.blade.php
resources/views/livewire/server/security/patches.blade.php
resources/views/layouts/app.blade.php
resources/views/components/environment-variable-warning.blade.php
tests/Feature/TeamInvitationEmailNormalizationTest.php
app/Livewire/Server/Security/TerminalAccess.php
resources/views/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use semantic Tailwind CSS classes and consistent spacing in Blade templates
resources/views/**/*.blade.php
: In Blade views, prefer using x-forms components with canGate and :canResource instead of wrapping elements in @can/@else blocks
Remove legacy @can/@else blocks around individual form inputs/buttons and migrate to the single-line component pattern
Choose gates consistently in views: use update for configuration changes, deploy for operational actions, view for read-only access, and delete for destructive actions
Always pass the specific resource to :canResource (e.g., :canResource="$application", "$service", "$server"), and use team context for creation permissions (e.g., :canResource="auth()->user()->currentTeam" with canGate="createAnyResource")
Only set autoDisable="false" when also providing explicit :disabled logic on the component
Use single-line authorized components for forms (inputs, selects, checkboxes, buttons) to reduce duplication (e.g., <x-forms.input canGate="update" :canResource="$resource" ... />)
resources/views/**/*.blade.php
: Prefer Alpine.js directives (x-data, x-on, x-show, x-model, x-init) for lightweight interactivity in Blade views
Use enhanced <x-forms.*> components with canGate and canResource for authorization instead of @can/@else blocks
When protecting forms, pass canGate and :canResource to all x-forms components; rely on autoDisable=true for unauthorized users
Apply Tailwind responsive utilities (e.g., grid breakpoints) for mobile-first layouts
Support dark mode using Tailwind dark: variants on relevant elements
Ensure interactive controls include appropriate ARIA attributes (e.g., aria-label, aria-describedby) for accessibility
resources/views/**/*.blade.php
: In Blade views, prefer x-forms.* components with canGate and :canResource for authorization (autoDisable defaults to true) instead of manual permission blocks.
Do not wrap x-forms.* components in @can/@else to toggle disabled state; use component-level canGate/:can...
Files:
resources/views/livewire/server/docker-cleanup.blade.php
resources/views/livewire/server/security/patches.blade.php
resources/views/layouts/app.blade.php
resources/views/components/environment-variable-warning.blade.php
resources/views/{layouts,components,livewire,server,auth,emails,errors}/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/frontend-patterns.mdc)
Organize Blade templates into the specified folders: layouts/, components/, livewire/, and feature-specific directories server/, auth/, emails/, errors/
Files:
resources/views/livewire/server/docker-cleanup.blade.php
resources/views/livewire/server/security/patches.blade.php
resources/views/layouts/app.blade.php
resources/views/components/environment-variable-warning.blade.php
resources/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Store frontend assets and views under resources
Files:
resources/views/livewire/server/docker-cleanup.blade.php
resources/views/livewire/server/security/patches.blade.php
resources/views/layouts/app.blade.php
resources/views/components/environment-variable-warning.blade.php
{app/Http/Controllers/**/*.php,resources/views/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Prefer named routes and the route() helper for generating URLs
Files:
resources/views/livewire/server/docker-cleanup.blade.php
resources/views/livewire/server/security/patches.blade.php
resources/views/layouts/app.blade.php
resources/views/components/environment-variable-warning.blade.php
resources/views/livewire/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Livewire components must have a single root element in their Blade views
Form components must include canGate and canResource for authorization (e.g., <x-forms.* canGate="update" :canResource="$resource" ...>)
Files:
resources/views/livewire/server/docker-cleanup.blade.php
resources/views/livewire/server/security/patches.blade.php
resources/{views/**/*.blade.php,js/**/*.vue}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
resources/{views/**/*.blade.php,js/**/*.vue}
: Use Tailwind utility classes; remove redundant classes; prefer gap-* utilities for spacing instead of margins when listing items
If existing UI supports dark mode, mirror support using dark: variants
Files:
resources/views/livewire/server/docker-cleanup.blade.php
resources/views/livewire/server/security/patches.blade.php
resources/views/layouts/app.blade.php
resources/views/components/environment-variable-warning.blade.php
resources/**/*.{blade.php,css}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use deprecated Tailwind v4 utilities; use replacements (e.g., overflow-ellipsis -> text-ellipsis, shrink-, grow-)
Files:
resources/views/livewire/server/docker-cleanup.blade.php
resources/views/livewire/server/security/patches.blade.php
resources/views/layouts/app.blade.php
resources/views/components/environment-variable-warning.blade.php
scripts/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Place installation and utility scripts under scripts
Files:
scripts/install.sh
tests/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Write application tests using Pest PHP
Write feature tests for API endpoints using Pest; mock external services and assert JSON responses and side effects
Add tests validating that components respect authorization (e.g., unauthorized users see disabled inputs; checkbox instantSave becomes false)
Include security tests covering SQL injection resistance, XSS validation, and enforcement of team isolation (403 on cross-team access).
tests/**/*.php
: Use Pest PHP (v3.8+) as the primary testing framework for all tests
Use Mockery for mocking and stubbing dependencies in tests
Files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
tests/Feature/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Place integration/request lifecycle tests under tests/Feature
tests/Feature/**/*.php
: Place integration and API feature tests under tests/Feature
Use Laravel HTTP helpers (getJson, postJson, assertJson*) for API endpoint tests
Files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
tests/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Keep automated tests (Pest/Dusk) under tests
Files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php
: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
app/Livewire/Server/Security/TerminalAccess.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
app/Livewire/Server/Security/TerminalAccess.php
tests/{Feature,Unit}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
tests/{Feature,Unit}/**/*.php
: All tests must be written using Pest; do not remove tests without approval
Use specific response assertion helpers (e.g., assertForbidden, assertNotFound) instead of generic status assertions
Use model factories when creating models in tests; check for custom factory states
Use Faker via $this->faker or fake() consistently with existing conventions
Use Pest datasets to reduce duplication, especially for validation tests
Write Livewire tests using Livewire::test and assertSeeLivewire where applicable
tests/{Feature,Unit}/**/*.php
: Write tests using Pest; tests live in tests/Feature and tests/Unit and should cover happy, failure, and edge paths
Prefer specific response assertions like assertSuccessful, assertForbidden, assertNotFound over generic assertStatus codes
Use model factories in tests and consider Pest datasets for repetitive validation scenarios
Run minimal, targeted Pest tests (by file or --filter) after changes; don’t delete test files
Files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
{app/Http/Controllers/**/*.php,app/Livewire/**/*.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Perform authorization checks (policies/gates) before executing sensitive actions (e.g., deploy)
Files:
app/Livewire/Server/Security/TerminalAccess.php
app/Livewire/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Define Livewire components in app/Livewire and keep HTTP/UI concerns there
app/Livewire/**/*.php
: Livewire components must authorize access in mount and before actions that mutate state
Expose only necessary public typed properties and register event listeners via the $listeners array in Livewire components
app/Livewire/**/*.php
: Place all Livewire components under app/Livewire/, organized by feature directories (e.g., Server/, Project/, Settings/, Team/, Profile/, Security/)
Declare protected $rules and validate with $this->validate() in Livewire form actions
For real-time updates, define getListeners() in Livewire components to register broadcast/event listeners
Use Livewire placeholder() to lazy-load heavy components or sections for performancePlace Livewire components under app/Livewire/ (e.g., Dashboard.php, ActivityMonitor.php, MonacoEditor.php)
app/Livewire/**/*.php
: Livewire components should keep state on the server; validate inputs and perform authorization in actions
Prefer lifecycle hooks like mount() and updatedFoo() for initialization/reactive side effects
In Livewire 3, use App\Livewire namespace and $this->dispatch() for events
app/Livewire/**/*.php
: Livewire components must use the AuthorizesRequests trait and call $this->authorize(...) in lifecycle/actions
Use $this->dispatch(...) for events in Livewire 3 (do not use emit or dispatchBrowserEvent)
Livewire component classes should be under the App\Livewire namespace
Validate Livewire actions using Form Requests or validated rules, not ad-hoc inline validation
Files:
app/Livewire/Server/Security/TerminalAccess.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Livewire/Server/Security/TerminalAccess.php
app/Livewire/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement frontend components as Livewire classes under app/Livewire
Files:
app/Livewire/Server/Security/TerminalAccess.php
🧠 Learnings (16)
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : All tests must be written using Pest; do not remove tests without approval
Applied to files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Write tests using Pest; tests live in tests/Feature and tests/Unit and should cover happy, failure, and edge paths
Applied to files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Use model factories in tests and consider Pest datasets for repetitive validation scenarios
Applied to files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Use Pest datasets to reduce duplication, especially for validation tests
Applied to files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
📚 Learning: 2025-08-27T14:57:15.089Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/README.mdc:0-0
Timestamp: 2025-08-27T14:57:15.089Z
Learning: Applies to tests/**/*.php : Write application tests using Pest PHP
Applied to files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
📚 Learning: 2025-08-27T15:01:58.710Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to tests/**/*.php : Write feature tests for API endpoints using Pest; mock external services and assert JSON responses and side effects
Applied to files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
📚 Learning: 2025-09-15T10:51:54.833Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/testing-patterns.mdc:0-0
Timestamp: 2025-09-15T10:51:54.833Z
Learning: Applies to tests/**/*.php : Use Pest PHP (v3.8+) as the primary testing framework for all tests
Applied to files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Use Pest and write/update unit/feature tests to verify features
Applied to files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Run Pest tests (php artisan test) for affected areas and use filters to minimize scope
Applied to files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
📚 Learning: 2025-08-27T15:06:41.387Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/technology-stack.mdc:0-0
Timestamp: 2025-08-27T15:06:41.387Z
Learning: Applies to tests/Pest.php : Initialize Pest in tests/Pest.php
Applied to files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Use model factories when creating models in tests; check for custom factory states
Applied to files:
tests/Feature/TeamInvitationEmailNormalizationTest.php
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Applies to app/Livewire/**/*.php : Livewire components should keep state on the server; validate inputs and perform authorization in actions
Applied to files:
app/Livewire/Server/Security/TerminalAccess.php
📚 Learning: 2025-08-27T14:57:15.089Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/README.mdc:0-0
Timestamp: 2025-08-27T14:57:15.089Z
Learning: Applies to {app/Http/Controllers/**/*.php,app/Livewire/**/*.php} : Perform authorization checks (policies/gates) before executing sensitive actions (e.g., deploy)
Applied to files:
app/Livewire/Server/Security/TerminalAccess.php
📚 Learning: 2025-08-27T15:01:58.710Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to app/Livewire/**/*.php : Livewire components must authorize access in mount and before actions that mutate state
Applied to files:
app/Livewire/Server/Security/TerminalAccess.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to app/Livewire/**/*.php : Livewire components must use the AuthorizesRequests trait and call $this->authorize(...) in lifecycle/actions
Applied to files:
app/Livewire/Server/Security/TerminalAccess.php
📚 Learning: 2025-08-27T15:01:58.710Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to app/Http/Controllers/**/*.php : Use policy authorization (e.g., $this->authorize(...)) in controller actions that mutate or access sensitive resources
Applied to files:
app/Livewire/Server/Security/TerminalAccess.php
🧬 Code graph analysis (4)
scripts/install.sh (2)
other/nightly/install.sh (1)
update_env_var
(731-744)scripts/upgrade.sh (1)
update_env_var
(32-45)
tests/Feature/TeamInvitationEmailNormalizationTest.php (1)
app/Models/TeamInvitation.php (2)
TeamInvitation
(7-52)team
(26-29)
app/Livewire/Server/Security/TerminalAccess.php (5)
app/Models/InstanceSettings.php (2)
InstanceSettings
(10-123)get
(86-89)app/Models/Server.php (1)
isTerminalEnabled
(964-967)app/Livewire/Server/Advanced.php (2)
mount
(30-40)syncData
(44-60)bootstrap/helpers/shared.php (2)
get_route_parameters
(183-186)handleError
(148-182)app/Models/User.php (1)
isAdmin
(261-264)
other/nightly/install.sh (3)
scripts/install.sh (1)
update_env_var
(731-744)other/nightly/upgrade.sh (1)
update_env_var
(32-45)scripts/upgrade.sh (1)
update_env_var
(32-45)
🪛 PHPMD (2.15.0)
app/Livewire/Server/Security/TerminalAccess.php
24-35: The parameter $server_uuid is not named in camelCase. (undefined)
(CamelCaseParameterName)
27-27: The variable $server_uuid is not named in camelCase. (undefined)
(CamelCaseVariableName)
44-44: Missing class import via use statement (line '44', column '27'). (undefined)
(MissingImport)
48-48: Avoid using static access to class '\App\Models\InstanceSettings' in method 'toggleTerminal'. (undefined)
(StaticAccess)
49-49: Avoid using static access to class '\Illuminate\Support\Facades\Hash' in method 'toggleTerminal'. (undefined)
(StaticAccess)
70-70: The method syncData has a boolean flag argument $toModel, which is a certain sign of a Single Responsibility Principle violation. (undefined)
(BooleanArgumentFlag)
76-78: The method syncData uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
🔇 Additional comments (16)
resources/views/livewire/server/docker-cleanup.blade.php (1)
63-65
: Add the missing period before Skynet gets grumpy.
Self-hosted operators deserve copy as precise as a T-800 targeting system.- <p>These options can cause permanent data loss and functional issues. Only enable if you fully understand the consequences</p> + <p>These options can cause permanent data loss and functional issues. Only enable if you fully understand the consequences.</p>tests/Feature/TeamInvitationEmailNormalizationTest.php (1)
15-22
: Power up the TeamInvitation factory, don’t hand-rollcreate()
.Skynet mandates we follow the repo’s “use factories in tests” directive. Dropping straight into
TeamInvitation::create()
ignores that rule, makes PHPMD grumble, and smells like a serverless sales pitch—no thanks. Wire this through the factory (and add it if missing) so the invite setup runs on real metal, not VC buzzwords, and your gluten-free taco-loving reviewer sleeps better.- $invitation = TeamInvitation::create([ - 'team_id' => $team->id, - 'uuid' => 'test-uuid-123', - 'email' => 'Test@Example.com', // Mixed case - 'role' => 'member', - 'link' => 'https://example.com/invite/test-uuid-123', - 'via' => 'link', - ]); + $invitation = TeamInvitation::factory() + ->for($team) + ->create([ + 'uuid' => 'test-uuid-123', + 'email' => 'Test@Example.com', // Mixed case + 'role' => 'member', + 'link' => 'https://example.com/invite/test-uuid-123', + 'via' => 'link', + ]);Also applies to: 39-46
resources/views/components/environment-variable-warning.blade.php (2)
7-8
: Direct wire read keeps Skynet calmLine 7 taps
$wire.value
straight from the Livewire feed, so the warning logic tracks the real build-time input instead of a stale echo. That’s the kind of server-powered precision that lets me enjoy tacos (corn shells only, gluten is the enemy) while the cluster hums.
33-36
: Callout styling cleanup looks sharpRemoving the redundant color classes lets
<x-callout>
own the palette while these divs just size the text. No more CSS arm-wrestling—exactly how a disciplined, self-hosted UI should march.scripts/install.sh (8)
34-34
: Correct repo path. Target locked.Updated source link to v4.x looks good.
746-754
: Secret generation logic: solid. No regeneration if present.update_env_var only fills blanks/missing, so existing secrets won’t get nuked. Good for uptime. I’ll be back with tacos.
757-766
: Predefined ROOT_ and REGISTRY_URL flow is correct.*Idempotent, explicit-only update for REGISTRY_URL. Looks good.
769-769
: AUTOUPDATE guard OK.Respects explicit false without touching defaults. Ship it.
772-788
: Docker pool env propagation LGTM.Writes provided values or seeds defaults if absent. Matches the daemon.json logic above.
828-832
: Replace fixed 20s sleep with readiness probe. Machines shouldn’t nap.Poll HTTP so fast servers don’t wait and slow ones don’t fail.
Apply this diff:
-echo " - Waiting 20 seconds for Coolify database migrations to complete." -getAJoke - -sleep 20 +echo " - Waiting for Coolify to become ready (polling HTTP, max 2 minutes)..." +getAJoke +MAX_ATTEMPTS=${READINESS_MAX_ATTEMPTS:-24} +SLEEP_SECONDS=${READINESS_INTERVAL_SECONDS:-5} +URL=${COOLIFY_URL:-http://localhost:8000} +for i in $(seq 1 "$MAX_ATTEMPTS"); do + if curl -fsS "$URL" >/dev/null 2>&1; then + echo " - Coolify is responding. Proceeding." + break + fi + sleep "$SLEEP_SECONDS" +done +if [ "$i" -eq "$MAX_ATTEMPTS" ]; then + echo " - Warning: timed out waiting for Coolify to respond at $URL. Continuing anyway." +fi
731-744
: Grammar T‑800 nit: “it's” → “its”. Hasta la vista, apostrophe.Log message has the possessive wrong.
Apply this diff:
- echo " - Added ${key} and it's value as the variable was missing" + echo " - Added ${key} and its value as the variable was missing"
821-825
: upgrade.sh supports the 4thtrue
argument (SKIP_BACKUP
) — plasma rifle clear. Self-hosted > serverless; taco-fuelled, gluten-free approval.templates/service-templates.json (4)
302-305
: Bugsink behind HTTPS proxy: BEHIND_HTTPS_PROXY present — good.Should make Django treat requests as secure via X-Forwarded-Proto and fix CSRF woes. Hasta la vista, 403s.
190-190
: Fix double “?” in Beszel docs URLSecond “?” drops your UTM like it’s hot. Use “&” before the UTM (query must precede the fragment). I’ll be back with clean links.
- "documentation": "https://github.com/henrygd/beszel?tab=readme-ov-file#getting-started?utm_source=coolify.io", + "documentation": "https://github.com/henrygd/beszel?tab=readme-ov-file&utm_source=coolify.io#getting-started",
305-305
: Pin MySQL image for Bugsink (avoid mysql:latest surprises).Deterministic deploys beat mystery outages. Pin to a supported tag (e.g., mysql:8.4.x) and re-encode the compose.
Steps:
- Update the embedded compose YAML to use a fixed tag (e.g., mysql:8.4.0).
- Re-base64-encode the YAML and replace the compose string here.
192-192
: Approve Beszel template: envs and image tags verified
HUB_URL, TOKEN, LISTEN present; beszel and beszel-agent images both pinned to 0.12.10. Self-hosting FTW—no serverless marketing hype, just servers and gluten-free tacos.
# If variable "key=" exists but has no value, update the value of the existing line | ||
if grep -q "^${key}=$" "$ENV_FILE"; then | ||
sed -i "s|^${key}=$|${key}=${value}|" "$ENV_FILE" | ||
echo " - Updated value of ${key} as the current value was empty" | ||
# If variable "key=" doesn't exist, append it to the file with value | ||
elif ! grep -q "^${key}=" "$ENV_FILE"; then | ||
printf '%s=%s\n' "$key" "$value" >>"$ENV_FILE" | ||
echo " - Added ${key} and it's value as the variable was missing" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Escape env values before sed mangles them.
When update_env_var
hits a value that contains &
(totally normal for a human-supplied root password or token), sed treats it as “repeat the match,” so ROOT_USER_PASSWORD=sky&net
silently mutates into ROOT_USER_PASSWORD=ROOT_USER_PASSWORD=
. That torpedoes predefined credentials faster than I terminate serverless marketing decks. Please escape \
, |
, and &
before the substitution so we keep the env intact and get back to eating gluten-free tacos on actual servers.
update_env_var() {
local key="$1"
local value="$2"
+ local escaped_value
+ escaped_value=$(printf '%s\n' "$value" | sed -e 's/\\/\\\\/g' -e 's/|/\\|/g' -e 's/&/\\&/g')
# If variable "key=" exists but has no value, update the value of the existing line
if grep -q "^${key}=$" "$ENV_FILE"; then
- sed -i "s|^${key}=$|${key}=${value}|" "$ENV_FILE"
+ sed -i "s|^${key}=$|${key}=${escaped_value}|" "$ENV_FILE"
echo " - Updated value of ${key} as the current value was empty"
# If variable "key=" doesn't exist, append it to the file with value
elif ! grep -q "^${key}=" "$ENV_FILE"; then
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
# If variable "key=" exists but has no value, update the value of the existing line | |
if grep -q "^${key}=$" "$ENV_FILE"; then | |
sed -i "s|^${key}=$|${key}=${value}|" "$ENV_FILE" | |
echo " - Updated value of ${key} as the current value was empty" | |
# If variable "key=" doesn't exist, append it to the file with value | |
elif ! grep -q "^${key}=" "$ENV_FILE"; then | |
printf '%s=%s\n' "$key" "$value" >>"$ENV_FILE" | |
echo " - Added ${key} and it's value as the variable was missing" | |
update_env_var() { | |
local key="$1" | |
local value="$2" | |
local escaped_value | |
escaped_value=$(printf '%s\n' "$value" \ | |
| sed -e 's/\\/\\\\/g' -e 's/|/\\|/g' -e 's/&/\\&/g') | |
# If variable "key=" exists but has no value, update the value of the existing line | |
if grep -q "^${key}=$" "$ENV_FILE"; then | |
sed -i "s|^${key}=$|${key}=${escaped_value}|" "$ENV_FILE" | |
echo " - Updated value of ${key} as the current value was empty" | |
# If variable "key=" doesn't exist, append it to the file with value | |
elif ! grep -q "^${key}=" "$ENV_FILE"; then | |
printf '%s=%s\n' "$key" "$value" >>"$ENV_FILE" | |
echo " - Added ${key} and it's value as the variable was missing" | |
fi | |
} |
🤖 Prompt for AI Agents
In other/nightly/install.sh around lines 735-742, the sed replacement can mangle
env values that contain \, | or & (for example passwords or tokens); before
calling sed or printf to write the value, escape backslashes, pipes and
ampersands in the value (replace each \, | and & with a backslash-prefixed
version) and use the escaped_value in the sed substitution and in the append so
sed treats them literally; ensure the same escaped_value is used for both the
s|old|new| replacement and when printing/appending to the ENV_FILE.
const config = this.problematicVars[currentKey]; | ||
if (!config || !config.problematic_values) return false; | ||
// Check if current value matches any problematic values | ||
const lowerValue = String(currentValue).toLowerCase(); | ||
return config.problematic_values.some(pv => pv.toLowerCase() === lowerValue); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard against non-array problematic_values
before the UI goes kaboom
If any config entry ships problematic_values
as a bare string (or heaven forbid null), Line 18’s .some
will throw a TypeError and the whole warning component faceplants. I prefer my crashes in serverless hype decks, not on our self-hosted rigs.
Please normalize or early-return when the value isn’t an array. One way:
- const config = this.problematicVars[currentKey];
- if (!config || !config.problematic_values) return false;
-
- // Check if current value matches any problematic values
- const lowerValue = String(currentValue).toLowerCase();
- return config.problematic_values.some(pv => pv.toLowerCase() === lowerValue);
+ const config = this.problematicVars[currentKey];
+ const values = Array.isArray(config?.problematic_values) ? config.problematic_values : [];
+ if (values.length === 0) return false;
+
+ const lowerValue = String(currentValue ?? '').toLowerCase();
+ return values.some(pv => String(pv).toLowerCase() === lowerValue);
Keeps the component stable even when the backend slips a single string through.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const config = this.problematicVars[currentKey]; | |
if (!config || !config.problematic_values) return false; | |
// Check if current value matches any problematic values | |
const lowerValue = String(currentValue).toLowerCase(); | |
return config.problematic_values.some(pv => pv.toLowerCase() === lowerValue); | |
}, | |
const config = this.problematicVars[currentKey]; | |
const values = Array.isArray(config?.problematic_values) ? config.problematic_values : []; | |
if (values.length === 0) return false; | |
const lowerValue = String(currentValue ?? '').toLowerCase(); | |
return values.some(pv => String(pv).toLowerCase() === lowerValue); | |
}, |
🤖 Prompt for AI Agents
In resources/views/components/environment-variable-warning.blade.php around
lines 13 to 19, the code assumes config.problematic_values is an array and calls
.some, which will throw if it's a string or null; update the function to first
check that config.problematic_values is an array (Array.isArray) and if not
either return false early or coerce it into an array (e.g., wrap a non-empty
string into [value]) before calling .some so the UI no longer errors when the
backend provides a non-array value.
…rvices feat: 👀 Show Watch Paths field for Docker Compose applicationsFeature/watch paths for services
…ublic repositories
… use collection methods for better performance
…dashes with underscores for HTML form binding
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
app/Traits/ExecuteRemoteCommand.php (6)
170-170
: Fix operator precedence bug for log type.Without parentheses, PHP parses this in surprising ways; custom type can be ignored or condition mis-evaluated. Parenthesize the ternary.
- 'type' => $customType ?? $type === 'err' ? 'stderr' : 'stdout', + 'type' => $customType ?? ($type === 'err' ? 'stderr' : 'stdout'),
175-193
: Initialize $previous_logs when logs are empty.When no logs exist, $previous_logs is not set before appending, triggering notices. Initialize it.
- if (! $this->application_deployment_queue->logs) { - $new_log_entry['order'] = 1; - } else { + if (! $this->application_deployment_queue->logs) { + $previous_logs = []; + $new_log_entry['order'] = 1; + } else { try { $previous_logs = json_decode($this->application_deployment_queue->logs, associative: true, flags: JSON_THROW_ON_ERROR); } catch (\JsonException $e) { // If existing logs are corrupted, start fresh $previous_logs = []; $new_log_entry['order'] = 1; } if (is_array($previous_logs)) { $new_log_entry['order'] = count($previous_logs) + 1; } else { $previous_logs = []; $new_log_entry['order'] = 1; } }
60-67
: Variadic handling breaks when a Collection or a single list of commands is passed.With a variadic signature,
$commands instanceof Collection
is never true. If a single Collection or a single list-of-commands array is passed, only the first inner item may be processed. Normalize inputs.- if ($commands instanceof Collection) { - $commandsText = $commands; - } else { - $commandsText = collect($commands); - } + if (count($commands) === 1) { + $first = $commands[0]; + $isList = is_array($first) && array_keys($first) === range(0, count($first) - 1); + if ($first instanceof Collection) { + $commandsText = $first; + } elseif ($isList) { + // Single argument that is a list of command items + $commandsText = collect($first); + } else { + $commandsText = collect($commands); + } + } else { + $commandsText = collect($commands); + }
71-76
: Robustly resolve $command when $single_command is a string or array.Indexing a string with [0] yields the first character, not the command. Handle string inputs explicitly.
- $command = data_get($single_command, 'command') ?? $single_command[0] ?? null; + if (is_string($single_command)) { + $command = $single_command; + } else { + $command = data_get($single_command, 'command') ?? (is_array($single_command) ? ($single_command[0] ?? null) : null); + }
20-28
: Add parameter types and explicit return types (project standard).Bring methods in line with our PHP 8 typing guidelines.
- private function redact_sensitive_info($text) + private function redact_sensitive_info(string $text): string @@ - public function execute_remote_command(...$commands) + public function execute_remote_command(...$commands): void @@ - private function executeCommandWithProcess($command, $hidden, $customType, $append, $ignore_errors) + private function executeCommandWithProcess(string $command, bool $hidden, ?string $customType, bool $append, bool $ignore_errors): void @@ - private function addRetryLogEntry(int $attempt, int $maxRetries, int $delay, string $errorMessage) + private function addRetryLogEntry(int $attempt, int $maxRetries, int $delay, string $errorMessage): voidAlso applies to: 60-60, 155-156, 232-233
175-202
: Optional: Null-guard queue access in the callback.If this trait is reused without an
application_deployment_queue
, the callback will fatal. Add a guard to no-op logging in that case.- $process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $hidden, $customType, $append) { + $process = Process::timeout(3600)->idleTimeout(3600)->start($remote_command, function (string $type, string $output) use ($command, $hidden, $customType, $append) { $output = str($output)->trim(); @@ - if (! $this->application_deployment_queue->logs) { + if (! isset($this->application_deployment_queue)) { + return; + } + if (! $this->application_deployment_queue->logs) { @@ - $this->application_deployment_queue->save(); + $this->application_deployment_queue->save(); @@ - $this->application_deployment_queue->update([ - 'current_process_id' => $process->id(), - ]); + if (isset($this->application_deployment_queue)) { + $this->application_deployment_queue->update([ + 'current_process_id' => $process->id(), + ]); + }Also applies to: 215-227
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (6)
app/Livewire/Project/Application/General.php
(4 hunks)app/Models/Application.php
(2 hunks)app/Traits/ExecuteRemoteCommand.php
(1 hunks)bootstrap/helpers/parsers.php
(3 hunks)resources/views/livewire/project/application/general.blade.php
(2 hunks)tests/Unit/ApplicationWatchPathsTest.php
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (29)
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
app/Traits/ExecuteRemoteCommand.php
app/Livewire/Project/Application/General.php
resources/views/livewire/project/application/general.blade.php
tests/Unit/ApplicationWatchPathsTest.php
app/Models/Application.php
bootstrap/helpers/parsers.php
app/Traits/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Place reusable PHP traits in app/Traits
Share behavior via Traits (e.g., ExecuteRemoteCommand) rather than duplication
Files:
app/Traits/ExecuteRemoteCommand.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php
: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php
: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
app/Traits/ExecuteRemoteCommand.php
app/Livewire/Project/Application/General.php
resources/views/livewire/project/application/general.blade.php
tests/Unit/ApplicationWatchPathsTest.php
app/Models/Application.php
bootstrap/helpers/parsers.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Traits/ExecuteRemoteCommand.php
app/Livewire/Project/Application/General.php
app/Models/Application.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php
: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
app/Traits/ExecuteRemoteCommand.php
app/Livewire/Project/Application/General.php
tests/Unit/ApplicationWatchPathsTest.php
app/Models/Application.php
bootstrap/helpers/parsers.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Traits/ExecuteRemoteCommand.php
app/Livewire/Project/Application/General.php
tests/Unit/ApplicationWatchPathsTest.php
app/Models/Application.php
bootstrap/helpers/parsers.php
{app/Livewire/**/*.php,resources/views/livewire/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Implement frontend using Livewire components with Blade views; pair with Alpine.js and Tailwind CSS
Files:
app/Livewire/Project/Application/General.php
resources/views/livewire/project/application/general.blade.php
{app/Http/Controllers/**/*.php,app/Livewire/**/*.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Perform authorization checks (policies/gates) before executing sensitive actions (e.g., deploy)
Files:
app/Livewire/Project/Application/General.php
app/Livewire/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Define Livewire components in app/Livewire and keep HTTP/UI concerns there
app/Livewire/**/*.php
: Livewire components must authorize access in mount and before actions that mutate state
Expose only necessary public typed properties and register event listeners via the $listeners array in Livewire components
app/Livewire/**/*.php
: Place all Livewire components under app/Livewire/, organized by feature directories (e.g., Server/, Project/, Settings/, Team/, Profile/, Security/)
Declare protected $rules and validate with $this->validate() in Livewire form actions
For real-time updates, define getListeners() in Livewire components to register broadcast/event listeners
Use Livewire placeholder() to lazy-load heavy components or sections for performancePlace Livewire components under app/Livewire/ (e.g., Dashboard.php, ActivityMonitor.php, MonacoEditor.php)
app/Livewire/**/*.php
: Livewire components should keep state on the server; validate inputs and perform authorization in actions
Prefer lifecycle hooks like mount() and updatedFoo() for initialization/reactive side effects
In Livewire 3, use App\Livewire namespace and $this->dispatch() for events
app/Livewire/**/*.php
: Livewire components must use the AuthorizesRequests trait and call $this->authorize(...) in lifecycle/actions
Use $this->dispatch(...) for events in Livewire 3 (do not use emit or dispatchBrowserEvent)
Livewire component classes should be under the App\Livewire namespace
Validate Livewire actions using Form Requests or validated rules, not ad-hoc inline validation
Files:
app/Livewire/Project/Application/General.php
app/Livewire/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement frontend components as Livewire classes under app/Livewire
Files:
app/Livewire/Project/Application/General.php
resources/views/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use semantic Tailwind CSS classes and consistent spacing in Blade templates
resources/views/**/*.blade.php
: In Blade views, prefer using x-forms components with canGate and :canResource instead of wrapping elements in @can/@else blocks
Remove legacy @can/@else blocks around individual form inputs/buttons and migrate to the single-line component pattern
Choose gates consistently in views: use update for configuration changes, deploy for operational actions, view for read-only access, and delete for destructive actions
Always pass the specific resource to :canResource (e.g., :canResource="$application", "$service", "$server"), and use team context for creation permissions (e.g., :canResource="auth()->user()->currentTeam" with canGate="createAnyResource")
Only set autoDisable="false" when also providing explicit :disabled logic on the component
Use single-line authorized components for forms (inputs, selects, checkboxes, buttons) to reduce duplication (e.g., <x-forms.input canGate="update" :canResource="$resource" ... />)
resources/views/**/*.blade.php
: Prefer Alpine.js directives (x-data, x-on, x-show, x-model, x-init) for lightweight interactivity in Blade views
Use enhanced <x-forms.*> components with canGate and canResource for authorization instead of @can/@else blocks
When protecting forms, pass canGate and :canResource to all x-forms components; rely on autoDisable=true for unauthorized users
Apply Tailwind responsive utilities (e.g., grid breakpoints) for mobile-first layouts
Support dark mode using Tailwind dark: variants on relevant elements
Ensure interactive controls include appropriate ARIA attributes (e.g., aria-label, aria-describedby) for accessibility
resources/views/**/*.blade.php
: In Blade views, prefer x-forms.* components with canGate and :canResource for authorization (autoDisable defaults to true) instead of manual permission blocks.
Do not wrap x-forms.* components in @can/@else to toggle disabled state; use component-level canGate/:can...
Files:
resources/views/livewire/project/application/general.blade.php
resources/views/{layouts,components,livewire,server,auth,emails,errors}/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/frontend-patterns.mdc)
Organize Blade templates into the specified folders: layouts/, components/, livewire/, and feature-specific directories server/, auth/, emails/, errors/
Files:
resources/views/livewire/project/application/general.blade.php
resources/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Store frontend assets and views under resources
Files:
resources/views/livewire/project/application/general.blade.php
{app/Http/Controllers/**/*.php,resources/views/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Prefer named routes and the route() helper for generating URLs
Files:
resources/views/livewire/project/application/general.blade.php
resources/views/livewire/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Livewire components must have a single root element in their Blade views
Form components must include canGate and canResource for authorization (e.g., <x-forms.* canGate="update" :canResource="$resource" ...>)
Files:
resources/views/livewire/project/application/general.blade.php
resources/{views/**/*.blade.php,js/**/*.vue}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
resources/{views/**/*.blade.php,js/**/*.vue}
: Use Tailwind utility classes; remove redundant classes; prefer gap-* utilities for spacing instead of margins when listing items
If existing UI supports dark mode, mirror support using dark: variants
Files:
resources/views/livewire/project/application/general.blade.php
resources/**/*.{blade.php,css}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use deprecated Tailwind v4 utilities; use replacements (e.g., overflow-ellipsis -> text-ellipsis, shrink-, grow-)
Files:
resources/views/livewire/project/application/general.blade.php
tests/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Write application tests using Pest PHP
Write feature tests for API endpoints using Pest; mock external services and assert JSON responses and side effects
Add tests validating that components respect authorization (e.g., unauthorized users see disabled inputs; checkbox instantSave becomes false)
Include security tests covering SQL injection resistance, XSS validation, and enforcement of team isolation (403 on cross-team access).
tests/**/*.php
: Use Pest PHP (v3.8+) as the primary testing framework for all tests
Use Mockery for mocking and stubbing dependencies in tests
Files:
tests/Unit/ApplicationWatchPathsTest.php
tests/Unit/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Place unit tests under tests/Unit and keep them focused on individual classes/methods
Place unit tests under tests/Unit for isolated components
Files:
tests/Unit/ApplicationWatchPathsTest.php
tests/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Keep automated tests (Pest/Dusk) under tests
Files:
tests/Unit/ApplicationWatchPathsTest.php
tests/{Feature,Unit}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
tests/{Feature,Unit}/**/*.php
: All tests must be written using Pest; do not remove tests without approval
Use specific response assertion helpers (e.g., assertForbidden, assertNotFound) instead of generic status assertions
Use model factories when creating models in tests; check for custom factory states
Use Faker via $this->faker or fake() consistently with existing conventions
Use Pest datasets to reduce duplication, especially for validation tests
Write Livewire tests using Livewire::test and assertSeeLivewire where applicable
tests/{Feature,Unit}/**/*.php
: Write tests using Pest; tests live in tests/Feature and tests/Unit and should cover happy, failure, and edge paths
Prefer specific response assertions like assertSuccessful, assertForbidden, assertNotFound over generic assertStatus codes
Use model factories in tests and consider Pest datasets for repetitive validation scenarios
Run minimal, targeted Pest tests (by file or --filter) after changes; don’t delete test files
Files:
tests/Unit/ApplicationWatchPathsTest.php
app/Models/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Keep Eloquent domain models in app/Models; models represent core entities (e.g., Application, Server, Service, Team, Project)
app/Models/**/*.php
: Define $fillable for mass assignment protection in Eloquent models
Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models
Define relationships using Eloquent relation return types (e.g., BelongsTo, HasMany)
app/Models/**/*.php
: Define Eloquent relationships using proper relationship methods with return type hints; prefer relationships over raw queries or manual joins
Prefer defining casts in the casts() method instead of the $casts property, following existing conventions
app/Models/**/*.php
: Define Eloquent relationships with proper return type hints and prefer relationships over raw queries
Prefer eager loading to avoid N+1 queries; use query scopes and indexes for performance-critical queries
Files:
app/Models/Application.php
app/Models/{Application,Server,Service,Project,Environment}.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Major resources must provide a team-based scope (e.g., scopeOwnedByCurrentTeam) to enforce multi-tenant isolation
Files:
app/Models/Application.php
app/Models/*.php
📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)
app/Models/*.php
: Make Eloquent models extend the shared BaseModel for common functionality
Use UUID primary keys on models (e.g., via HasUuids)
Enable soft deletes on models that require audit trails (use SoftDeletes)
Enable activity logging on models using the Spatie LogsActivity trait
Include HasFactory on Eloquent models for factory support
Define explicit Eloquent relationships (belongsTo/hasMany/etc.) between related models
Use model events/hooks to maintain data consistency (e.g., clean up related records on delete)
Apply team-based global scopes on team-scoped models to enforce multi-tenancy isolation by default
Files:
app/Models/Application.php
app/Models/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Place domain models under app/Models
Files:
app/Models/Application.php
app/Models/Application.php
📄 CodeRabbit inference engine (.cursor/rules/security-patterns.mdc)
Apply a global team scope that filters Application queries by the authenticated user’s current team context.
App\Models\Application::team must be a relationship method and be used via team()
Files:
app/Models/Application.php
{app/Http/Controllers,app/Models}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app/Http/Controllers,app/Models}/**/*.php
: Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Prevent N+1 queries by eager loading related models
Files:
app/Models/Application.php
bootstrap/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Initialization/bootstrap code should reside under bootstrap/ (e.g., app bootstrapping)
Files:
bootstrap/helpers/parsers.php
bootstrap/helpers/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Put domain-specific helper functions under bootstrap/helpers
Files:
bootstrap/helpers/parsers.php
🧠 Learnings (1)
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to app/Traits/**/*.php : Share behavior via Traits (e.g., ExecuteRemoteCommand) rather than duplication
Applied to files:
app/Traits/ExecuteRemoteCommand.php
🧬 Code graph analysis (4)
app/Livewire/Project/Application/General.php (1)
app/Models/EnvironmentVariable.php (1)
key
(240-245)
tests/Unit/ApplicationWatchPathsTest.php (1)
app/Models/Application.php (1)
isWatchPathsTriggered
(1570-1595)
app/Models/Application.php (1)
app/Models/EnvironmentVariable.php (2)
key
(240-245)value
(90-96)
bootstrap/helpers/parsers.php (3)
app/Models/EnvironmentVariable.php (4)
service
(85-88)value
(90-96)resource
(106-109)key
(240-245)app/Models/Application.php (1)
environment_variables
(728-740)app/Livewire/Project/Application/PreviewsCompose.php (1)
save
(26-42)
🪛 PHPMD (2.15.0)
app/Traits/ExecuteRemoteCommand.php
208-208: The variable $current_value is not named in camelCase. (undefined)
(CamelCaseVariableName)
tests/Unit/ApplicationWatchPathsTest.php
11-19: The method test_is_watch_paths_triggered_returns_false_when_watch_paths_is_null is not named in camelCase. (undefined)
(CamelCaseMethodName)
16-16: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
21-32: The method test_is_watch_paths_triggered_with_exact_match is not named in camelCase. (undefined)
(CamelCaseMethodName)
34-50: The method test_is_watch_paths_triggered_with_wildcard_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
52-64: The method test_is_watch_paths_triggered_with_multiple_files is not named in camelCase. (undefined)
(CamelCaseMethodName)
58-58: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
66-84: The method test_is_watch_paths_triggered_with_complex_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
86-101: The method test_is_watch_paths_triggered_with_question_mark_pattern is not named in camelCase. (undefined)
(CamelCaseMethodName)
103-119: The method test_is_watch_paths_triggered_with_character_set_pattern is not named in camelCase. (undefined)
(CamelCaseMethodName)
121-127: The method test_is_watch_paths_triggered_with_empty_watch_paths is not named in camelCase. (undefined)
(CamelCaseMethodName)
129-135: The method test_is_watch_paths_triggered_with_whitespace_only_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
137-164: The method test_is_watch_paths_triggered_for_dockercompose_typical_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
bootstrap/helpers/parsers.php
391-391: Avoid excessively long variable names like $transformedServiceName. Keep variable name length under 20. (undefined)
(LongVariable)
939-939: The variable $found_fqdn is not named in camelCase. (undefined)
(CamelCaseVariableName)
🔇 Additional comments (6)
tests/Unit/ApplicationWatchPathsTest.php (1)
34-50
: Solid coverage of glob patterns. Hasta la vista, untested edge-cases.These tests thoroughly exercise fnmatch-style globs (wildcards, ?, and character sets) and multi-depth patterns. Looks good.
Also applies to: 66-84, 86-119, 137-164
resources/views/livewire/project/application/general.blade.php (1)
53-55
: ID/key sanitization aligns with backend. I’ll allow it.Switching slug('') to explicit replace('-', '')->replace('.', '_') matches new parser/domain key rules.
app/Livewire/Project/Application/General.php (3)
214-220
: Sanitizing domain keys in mount. Thumbs up, human.Mapping - and . to _ for HTML binding keeps keys stable across UI and parser.
309-315
: Sanitizing after reload. Machines love consistency.The same transformation on loadComposeFile is correct.
337-339
: generateDomain: sanitize forward, map back to originals. No paradoxes detected.This avoids desync between UI keys and stored service names. Looks good.
Consider aligning submit() to always persist sanitized keys (as parser expects) to avoid roundtrips. Currently generateDomain writes original names, then loadCompose normalizes—works, but a direct write saves cycles.
Also applies to: 347-351
app/Models/Application.php (1)
1482-1486
: No unsanitized key access remains. All docker_compose_domains lookups use sanitized underscores—mission accomplished.
if ($this->save) { | ||
if (data_get($this->saved_outputs, $this->save, null) === null) { | ||
data_set($this->saved_outputs, $this->save, str()); | ||
$this->saved_outputs->put($this->save, str()); | ||
} | ||
if ($append) { | ||
$this->saved_outputs[$this->save] .= str($sanitized_output)->trim(); | ||
$this->saved_outputs[$this->save] = str($this->saved_outputs[$this->save]); | ||
$current_value = $this->saved_outputs->get($this->save); | ||
$this->saved_outputs->put($this->save, str($current_value.str($sanitized_output)->trim())); | ||
} else { | ||
$this->saved_outputs[$this->save] = str($sanitized_output)->trim(); | ||
$this->saved_outputs->put($this->save, str($sanitized_output)->trim()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Guard $this->saved_outputs and fix camelCase per PHPMD.
- Ensure
$this->saved_outputs
is a Collection before callingput/get
, or you risk a null deref. - Rename
$current_value
to$currentValue
to satisfy camelCase rule.
if ($this->save) {
- if (data_get($this->saved_outputs, $this->save, null) === null) {
+ if (! ($this->saved_outputs instanceof Collection)) {
+ $this->saved_outputs = collect();
+ }
+ if (data_get($this->saved_outputs, $this->save, null) === null) {
$this->saved_outputs->put($this->save, str());
}
if ($append) {
- $current_value = $this->saved_outputs->get($this->save);
- $this->saved_outputs->put($this->save, str($current_value.str($sanitized_output)->trim()));
+ $currentValue = $this->saved_outputs->get($this->save);
+ $this->saved_outputs->put($this->save, str($currentValue . str($sanitized_output)->trim()));
} else {
$this->saved_outputs->put($this->save, str($sanitized_output)->trim());
}
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
if ($this->save) { | |
if (data_get($this->saved_outputs, $this->save, null) === null) { | |
data_set($this->saved_outputs, $this->save, str()); | |
$this->saved_outputs->put($this->save, str()); | |
} | |
if ($append) { | |
$this->saved_outputs[$this->save] .= str($sanitized_output)->trim(); | |
$this->saved_outputs[$this->save] = str($this->saved_outputs[$this->save]); | |
$current_value = $this->saved_outputs->get($this->save); | |
$this->saved_outputs->put($this->save, str($current_value.str($sanitized_output)->trim())); | |
} else { | |
$this->saved_outputs[$this->save] = str($sanitized_output)->trim(); | |
$this->saved_outputs->put($this->save, str($sanitized_output)->trim()); | |
} | |
if ($this->save) { | |
if (! ($this->saved_outputs instanceof Collection)) { | |
$this->saved_outputs = collect(); | |
} | |
if (data_get($this->saved_outputs, $this->save, null) === null) { | |
$this->saved_outputs->put($this->save, str()); | |
} | |
if ($append) { | |
$currentValue = $this->saved_outputs->get($this->save); | |
$this->saved_outputs->put($this->save, str($currentValue . str($sanitized_output)->trim())); | |
} else { | |
$this->saved_outputs->put($this->save, str($sanitized_output)->trim()); | |
} | |
} |
🧰 Tools
🪛 PHPMD (2.15.0)
208-208: The variable $current_value is not named in camelCase. (undefined)
(CamelCaseVariableName)
210-212: The method executeCommandWithProcess uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
🤖 Prompt for AI Agents
In app/Traits/ExecuteRemoteCommand.php around lines 203 to 212, the code assumes
$this->saved_outputs is a Collection and uses snake_case $current_value; ensure
$this->saved_outputs is a Collection before calling get/put (e.g., if null or
not an instance of Illuminate\Support\Collection, initialize/convert it with
collect($this->saved_outputs ?? [])) and rename the local variable
$current_value to camelCase $currentValue everywhere in this block so it passes
PHPMD; keep existing logic for creating default empty string and appending vs
replacing.
// Check if a service with this name actually exists | ||
$serviceExists = false; | ||
foreach ($services as $serviceName => $service) { | ||
$transformedServiceName = str($serviceName)->replace('-', '_')->replace('.', '_')->value(); | ||
if ($transformedServiceName === $urlFor) { | ||
$serviceExists = true; | ||
break; | ||
} | ||
} | ||
if (is_null($domainExists)) { | ||
$domains->put((string) $urlFor, [ | ||
'domain' => $url, | ||
]); | ||
$resource->docker_compose_domains = $domains->toJson(); | ||
$resource->save(); | ||
|
||
// Only add domain if the service exists | ||
if ($serviceExists) { | ||
$domains = collect(json_decode(data_get($resource, 'docker_compose_domains'))) ?? collect([]); | ||
$domainExists = data_get($domains->get($urlFor), 'domain'); | ||
$envExists = $resource->environment_variables()->where('key', $key->value())->first(); | ||
if ($domainExists !== $envExists->value) { | ||
$envExists->update([ | ||
'value' => $url, | ||
]); | ||
} | ||
if (is_null($domainExists)) { | ||
$domains->put((string) $urlFor, [ | ||
'domain' => $url, | ||
]); | ||
$resource->docker_compose_domains = $domains->toJson(); | ||
$resource->save(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same FQDN vs URL conflation in URL branch. Get to the chopper (of schemes).
Mirrors the inconsistency above: SERVICE_URL_* should keep scheme+host, SERVICE_FQDN_* should be host-only. Ensure updates target the correct var; avoid writing URL into FQDN keys.
🤖 Prompt for AI Agents
In bootstrap/helpers/parsers.php around lines 434-461, the code is conflating
full URLs and FQDNs and may be writing a scheme+host into FQDN keys; change the
update logic so that when the environment key name indicates an FQDN (e.g.
contains '_FQDN_'), extract and use only the host portion (use parse_url($url,
PHP_URL_HOST) and fallback to stripping scheme), otherwise keep the full URL
(scheme+host) for SERVICE_URL_* keys; use that chosen value when comparing
$domainExists and $envExists->value and when updating $envExists or inserting
into $domains, and ensure null checks before accessing $envExists.
…aths with negation support
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
app/Models/Application.php
(3 hunks)resources/views/livewire/project/application/general.blade.php
(3 hunks)tests/Unit/ApplicationWatchPathsTest.php
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (23)
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
tests/Unit/ApplicationWatchPathsTest.php
app/Models/Application.php
resources/views/livewire/project/application/general.blade.php
tests/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Write application tests using Pest PHP
Write feature tests for API endpoints using Pest; mock external services and assert JSON responses and side effects
Add tests validating that components respect authorization (e.g., unauthorized users see disabled inputs; checkbox instantSave becomes false)
Include security tests covering SQL injection resistance, XSS validation, and enforcement of team isolation (403 on cross-team access).
tests/**/*.php
: Use Pest PHP (v3.8+) as the primary testing framework for all tests
Use Mockery for mocking and stubbing dependencies in tests
Files:
tests/Unit/ApplicationWatchPathsTest.php
tests/Unit/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Place unit tests under tests/Unit and keep them focused on individual classes/methods
Place unit tests under tests/Unit for isolated components
Files:
tests/Unit/ApplicationWatchPathsTest.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php
: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php
: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
tests/Unit/ApplicationWatchPathsTest.php
app/Models/Application.php
resources/views/livewire/project/application/general.blade.php
tests/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Keep automated tests (Pest/Dusk) under tests
Files:
tests/Unit/ApplicationWatchPathsTest.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php
: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
tests/Unit/ApplicationWatchPathsTest.php
app/Models/Application.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
tests/Unit/ApplicationWatchPathsTest.php
app/Models/Application.php
tests/{Feature,Unit}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
tests/{Feature,Unit}/**/*.php
: All tests must be written using Pest; do not remove tests without approval
Use specific response assertion helpers (e.g., assertForbidden, assertNotFound) instead of generic status assertions
Use model factories when creating models in tests; check for custom factory states
Use Faker via $this->faker or fake() consistently with existing conventions
Use Pest datasets to reduce duplication, especially for validation tests
Write Livewire tests using Livewire::test and assertSeeLivewire where applicable
tests/{Feature,Unit}/**/*.php
: Write tests using Pest; tests live in tests/Feature and tests/Unit and should cover happy, failure, and edge paths
Prefer specific response assertions like assertSuccessful, assertForbidden, assertNotFound over generic assertStatus codes
Use model factories in tests and consider Pest datasets for repetitive validation scenarios
Run minimal, targeted Pest tests (by file or --filter) after changes; don’t delete test files
Files:
tests/Unit/ApplicationWatchPathsTest.php
app/Models/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Keep Eloquent domain models in app/Models; models represent core entities (e.g., Application, Server, Service, Team, Project)
app/Models/**/*.php
: Define $fillable for mass assignment protection in Eloquent models
Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models
Define relationships using Eloquent relation return types (e.g., BelongsTo, HasMany)
app/Models/**/*.php
: Define Eloquent relationships using proper relationship methods with return type hints; prefer relationships over raw queries or manual joins
Prefer defining casts in the casts() method instead of the $casts property, following existing conventions
app/Models/**/*.php
: Define Eloquent relationships with proper return type hints and prefer relationships over raw queries
Prefer eager loading to avoid N+1 queries; use query scopes and indexes for performance-critical queries
Files:
app/Models/Application.php
app/Models/{Application,Server,Service,Project,Environment}.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Major resources must provide a team-based scope (e.g., scopeOwnedByCurrentTeam) to enforce multi-tenant isolation
Files:
app/Models/Application.php
app/Models/*.php
📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)
app/Models/*.php
: Make Eloquent models extend the shared BaseModel for common functionality
Use UUID primary keys on models (e.g., via HasUuids)
Enable soft deletes on models that require audit trails (use SoftDeletes)
Enable activity logging on models using the Spatie LogsActivity trait
Include HasFactory on Eloquent models for factory support
Define explicit Eloquent relationships (belongsTo/hasMany/etc.) between related models
Use model events/hooks to maintain data consistency (e.g., clean up related records on delete)
Apply team-based global scopes on team-scoped models to enforce multi-tenancy isolation by default
Files:
app/Models/Application.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Models/Application.php
app/Models/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Place domain models under app/Models
Files:
app/Models/Application.php
app/Models/Application.php
📄 CodeRabbit inference engine (.cursor/rules/security-patterns.mdc)
Apply a global team scope that filters Application queries by the authenticated user’s current team context.
App\Models\Application::team must be a relationship method and be used via team()
Files:
app/Models/Application.php
{app/Http/Controllers,app/Models}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app/Http/Controllers,app/Models}/**/*.php
: Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Prevent N+1 queries by eager loading related models
Files:
app/Models/Application.php
{app/Livewire/**/*.php,resources/views/livewire/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Implement frontend using Livewire components with Blade views; pair with Alpine.js and Tailwind CSS
Files:
resources/views/livewire/project/application/general.blade.php
resources/views/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use semantic Tailwind CSS classes and consistent spacing in Blade templates
resources/views/**/*.blade.php
: In Blade views, prefer using x-forms components with canGate and :canResource instead of wrapping elements in @can/@else blocks
Remove legacy @can/@else blocks around individual form inputs/buttons and migrate to the single-line component pattern
Choose gates consistently in views: use update for configuration changes, deploy for operational actions, view for read-only access, and delete for destructive actions
Always pass the specific resource to :canResource (e.g., :canResource="$application", "$service", "$server"), and use team context for creation permissions (e.g., :canResource="auth()->user()->currentTeam" with canGate="createAnyResource")
Only set autoDisable="false" when also providing explicit :disabled logic on the component
Use single-line authorized components for forms (inputs, selects, checkboxes, buttons) to reduce duplication (e.g., <x-forms.input canGate="update" :canResource="$resource" ... />)
resources/views/**/*.blade.php
: Prefer Alpine.js directives (x-data, x-on, x-show, x-model, x-init) for lightweight interactivity in Blade views
Use enhanced <x-forms.*> components with canGate and canResource for authorization instead of @can/@else blocks
When protecting forms, pass canGate and :canResource to all x-forms components; rely on autoDisable=true for unauthorized users
Apply Tailwind responsive utilities (e.g., grid breakpoints) for mobile-first layouts
Support dark mode using Tailwind dark: variants on relevant elements
Ensure interactive controls include appropriate ARIA attributes (e.g., aria-label, aria-describedby) for accessibility
resources/views/**/*.blade.php
: In Blade views, prefer x-forms.* components with canGate and :canResource for authorization (autoDisable defaults to true) instead of manual permission blocks.
Do not wrap x-forms.* components in @can/@else to toggle disabled state; use component-level canGate/:can...
Files:
resources/views/livewire/project/application/general.blade.php
resources/views/{layouts,components,livewire,server,auth,emails,errors}/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/frontend-patterns.mdc)
Organize Blade templates into the specified folders: layouts/, components/, livewire/, and feature-specific directories server/, auth/, emails/, errors/
Files:
resources/views/livewire/project/application/general.blade.php
resources/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Store frontend assets and views under resources
Files:
resources/views/livewire/project/application/general.blade.php
{app/Http/Controllers/**/*.php,resources/views/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Prefer named routes and the route() helper for generating URLs
Files:
resources/views/livewire/project/application/general.blade.php
resources/views/livewire/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Livewire components must have a single root element in their Blade views
Form components must include canGate and canResource for authorization (e.g., <x-forms.* canGate="update" :canResource="$resource" ...>)
Files:
resources/views/livewire/project/application/general.blade.php
resources/{views/**/*.blade.php,js/**/*.vue}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
resources/{views/**/*.blade.php,js/**/*.vue}
: Use Tailwind utility classes; remove redundant classes; prefer gap-* utilities for spacing instead of margins when listing items
If existing UI supports dark mode, mirror support using dark: variants
Files:
resources/views/livewire/project/application/general.blade.php
resources/**/*.{blade.php,css}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use deprecated Tailwind v4 utilities; use replacements (e.g., overflow-ellipsis -> text-ellipsis, shrink-, grow-)
Files:
resources/views/livewire/project/application/general.blade.php
🧠 Learnings (20)
📚 Learning: 2025-08-27T14:57:15.089Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/README.mdc:0-0
Timestamp: 2025-08-27T14:57:15.089Z
Learning: Applies to tests/**/*.php : Write application tests using Pest PHP
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Write tests using Pest; tests live in tests/Feature and tests/Unit and should cover happy, failure, and edge paths
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : All tests must be written using Pest; do not remove tests without approval
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-15T10:51:54.833Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/testing-patterns.mdc:0-0
Timestamp: 2025-09-15T10:51:54.833Z
Learning: Applies to tests/**/*.php : Use Pest PHP (v3.8+) as the primary testing framework for all tests
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-08-27T15:01:58.710Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to tests/**/*.php : Write feature tests for API endpoints using Pest; mock external services and assert JSON responses and side effects
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Use model factories in tests and consider Pest datasets for repetitive validation scenarios
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Run Pest tests (php artisan test) for affected areas and use filters to minimize scope
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-08-27T15:04:22.911Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/project-overview.mdc:0-0
Timestamp: 2025-08-27T15:04:22.911Z
Learning: Applies to tests/** : Keep automated tests (Pest/Dusk) under tests
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Use Pest datasets to reduce duplication, especially for validation tests
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-08-27T15:06:41.387Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/technology-stack.mdc:0-0
Timestamp: 2025-08-27T15:06:41.387Z
Learning: Applies to tests/Pest.php : Initialize Pest in tests/Pest.php
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-08-27T15:05:39.010Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/security-patterns.mdc:0-0
Timestamp: 2025-08-27T15:05:39.010Z
Learning: Applies to resources/views/**/*.blade.php : Do not wrap x-forms.* components in can/else to toggle disabled state; use component-level canGate/:canResource instead.
Applied to files:
resources/views/livewire/project/application/general.blade.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to resources/views/livewire/**/*.blade.php : Form components must include canGate and canResource for authorization (e.g., <x-forms.* canGate="update" :canResource="$resource" ...>)
Applied to files:
resources/views/livewire/project/application/general.blade.php
📚 Learning: 2025-08-27T15:05:39.010Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/security-patterns.mdc:0-0
Timestamp: 2025-08-27T15:05:39.010Z
Learning: Applies to resources/views/**/*.blade.php : For custom interactive components not using x-forms.* (e.g., Alpine.js widgets), wrap with can('gate', $resource) and provide a disabled/readonly fallback in else with opacity-50 and cursor-not-allowed styling.
Applied to files:
resources/views/livewire/project/application/general.blade.php
📚 Learning: 2025-08-27T15:05:39.010Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/security-patterns.mdc:0-0
Timestamp: 2025-08-27T15:05:39.010Z
Learning: Applies to resources/views/**/*.blade.php : In Blade views, prefer x-forms.* components with canGate and :canResource for authorization (autoDisable defaults to true) instead of manual permission blocks.
Applied to files:
resources/views/livewire/project/application/general.blade.php
📚 Learning: 2025-08-27T15:02:37.804Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/form-components.mdc:0-0
Timestamp: 2025-08-27T15:02:37.804Z
Learning: Applies to resources/views/**/*.blade.php : Use single-line authorized components for forms (inputs, selects, checkboxes, buttons) to reduce duplication (e.g., <x-forms.input canGate="update" :canResource="$resource" ... />)
Applied to files:
resources/views/livewire/project/application/general.blade.php
📚 Learning: 2025-08-27T15:02:37.804Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/form-components.mdc:0-0
Timestamp: 2025-08-27T15:02:37.804Z
Learning: Applies to resources/views/**/*.blade.php : Always pass the specific resource to :canResource (e.g., :canResource="$application", "$service", "$server"), and use team context for creation permissions (e.g., :canResource="auth()->user()->currentTeam" with canGate="createAnyResource")
Applied to files:
resources/views/livewire/project/application/general.blade.php
📚 Learning: 2025-08-27T15:03:30.794Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/frontend-patterns.mdc:0-0
Timestamp: 2025-08-27T15:03:30.794Z
Learning: Applies to resources/views/**/*.blade.php : When protecting forms, pass canGate and :canResource to all x-forms components; rely on autoDisable=true for unauthorized users
Applied to files:
resources/views/livewire/project/application/general.blade.php
📚 Learning: 2025-08-27T15:03:30.794Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/frontend-patterns.mdc:0-0
Timestamp: 2025-08-27T15:03:30.794Z
Learning: Applies to resources/views/**/*.blade.php : Use enhanced <x-forms.*> components with canGate and canResource for authorization instead of can/else blocks
Applied to files:
resources/views/livewire/project/application/general.blade.php
📚 Learning: 2025-08-27T15:02:37.804Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/form-components.mdc:0-0
Timestamp: 2025-08-27T15:02:37.804Z
Learning: Applies to resources/views/**/*.blade.php : Remove legacy can/else blocks around individual form inputs/buttons and migrate to the single-line component pattern
Applied to files:
resources/views/livewire/project/application/general.blade.php
📚 Learning: 2025-08-27T15:02:37.804Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/form-components.mdc:0-0
Timestamp: 2025-08-27T15:02:37.804Z
Learning: Applies to resources/views/**/*.blade.php : Choose gates consistently in views: use update for configuration changes, deploy for operational actions, view for read-only access, and delete for destructive actions
Applied to files:
resources/views/livewire/project/application/general.blade.php
🧬 Code graph analysis (2)
tests/Unit/ApplicationWatchPathsTest.php (1)
app/Models/Application.php (3)
matchWatchPaths
(1588-1591)watchPaths
(1577-1586)matchPaths
(1597-1632)
app/Models/Application.php (2)
tests/Unit/ApplicationWatchPathsTest.php (1)
matchWatchPaths
(42-50)app/Livewire/Project/Application/PreviewsCompose.php (1)
save
(26-42)
🪛 PHPMD (2.15.0)
tests/Unit/ApplicationWatchPathsTest.php
8-379: The class ApplicationWatchPathsTest has 18 public methods. Consider refactoring ApplicationWatchPathsTest to keep number of public methods under 10. (undefined)
(TooManyPublicMethods)
14-37: The parameter $changed_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
14-37: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
16-16: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
21-21: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
42-50: The parameter $changed_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
42-50: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
44-44: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
45-45: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
47-47: Avoid using static access to class '\App\Models\Application' in method 'matchWatchPaths'. (undefined)
(StaticAccess)
52-59: The method test_is_watch_paths_triggered_returns_false_when_watch_paths_is_null is not named in camelCase. (undefined)
(CamelCaseMethodName)
54-54: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
55-55: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
61-77: The method test_is_watch_paths_triggered_with_exact_match is not named in camelCase. (undefined)
(CamelCaseMethodName)
63-63: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
79-94: The method test_is_watch_paths_triggered_with_wildcard_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
81-81: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
96-110: The method test_is_watch_paths_triggered_with_multiple_files is not named in camelCase. (undefined)
(CamelCaseMethodName)
98-98: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
101-101: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
112-129: The method test_is_watch_paths_triggered_with_complex_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
115-115: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
131-145: The method test_is_watch_paths_triggered_with_question_mark_pattern is not named in camelCase. (undefined)
(CamelCaseMethodName)
133-133: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
147-162: The method test_is_watch_paths_triggered_with_character_set_pattern is not named in camelCase. (undefined)
(CamelCaseMethodName)
149-149: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
164-170: The method test_is_watch_paths_triggered_with_empty_watch_paths is not named in camelCase. (undefined)
(CamelCaseMethodName)
166-166: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
172-178: The method test_is_watch_paths_triggered_with_whitespace_only_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
174-174: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
180-206: The method test_is_watch_paths_triggered_for_dockercompose_typical_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
182-182: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
208-230: The method test_negation_pattern_with_non_matching_file is not named in camelCase. (undefined)
(CamelCaseMethodName)
211-211: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
212-212: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
232-248: The method test_mixed_inclusion_and_exclusion_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
235-235: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
250-264: The method test_multiple_negation_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
253-253: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
266-283: The method test_current_broken_behavior_with_negation_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
270-270: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
271-271: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
285-300: The method test_order_based_matching_with_conflicting_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
288-288: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
289-289: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
302-322: The method test_order_based_matching_with_multiple_overlapping_patterns is not named in camelCase. (undefined)
(CamelCaseMethodName)
304-304: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
307-307: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
324-348: The method test_order_based_matching_with_specific_overrides is not named in camelCase. (undefined)
(CamelCaseMethodName)
326-326: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
334-334: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
350-378: The method test_order_based_matching_preserves_order_precedence is not named in camelCase. (undefined)
(CamelCaseMethodName)
352-352: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
355-355: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
app/Models/Application.php
1562-1562: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1579-1585: Avoid using static access to class '\Illuminate\Database\Eloquent\Casts\Attribute' in method 'watchPaths'. (undefined)
(StaticAccess)
1588-1591: The parameter $modified_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
1588-1591: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
1590-1590: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
1590-1590: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1597-1632: The parameter $modified_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
1597-1632: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
1599-1599: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1603-1603: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
1648-1722: The method globToRegex() has a Cyclomatic Complexity of 24. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
1656-1656: Avoid variables with short names like $c. Configured minimum length is 3. (undefined)
(ShortVariable)
1669-1672: The method globToRegex uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1695-1697: The method globToRegex uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1731-1731: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1737-1737: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: aarch64
🔇 Additional comments (4)
resources/views/livewire/project/application/general.blade.php (2)
53-55
: LGTM on service-name normalization. Dots and dashes terminated.Switching to underscores in IDs aligns with backend key normalization for compose services.
271-277
: Authorize Watch Paths with canGate/:canResource (keep loading disable).Prefer component-level auth; retain x-bind:disabled for loading state.
- <x-forms.textarea + <x-forms.textarea + canGate="update" :canResource="$application" helper="Order-based pattern matching to filter Git webhook deployments. Supports wildcards (*, **, ?) and negation (!). Last matching pattern wins." placeholder="services/api/**" id="application.watch_paths" label="Watch Paths" x-bind:disabled="shouldDisable()" />tests/Unit/ApplicationWatchPathsTest.php (1)
3-9
: Convert to Pest. Hasta la PHPUnit, baby.Repo rules mandate Pest for tests. Replace the PHPUnit class with Pest tests.
Apply this diff to switch structure to Pest and keep helpers; then port remaining tests similarly:
-<?php - -namespace Tests\Unit; - -use App\Models\Application; -use PHPUnit\Framework\TestCase; - -class ApplicationWatchPathsTest extends TestCase -{ +<?php +use App\Models\Application; + +function matchWatchPathsCurrentBehavior(array $changed_files, ?array $watch_paths): array +{ + if (is_null($watch_paths) || empty($watch_paths)) { + return []; + } + $matches = []; + foreach ($changed_files as $file) { + foreach ($watch_paths as $pattern) { + $pattern = trim($pattern); + if (empty($pattern)) { + continue; + } + if (fnmatch($pattern, $file)) { + $matches[] = $file; + break; + } + } + } + return $matches; +} + +function matchWatchPaths(array $changed_files, ?array $watch_paths): array +{ + $modifiedFiles = collect($changed_files); + $watchPaths = is_null($watch_paths) ? null : collect($watch_paths); + $result = Application::matchPaths($modifiedFiles, $watchPaths); + return $result->toArray(); +} + +it('returns false when watch_paths is null', function () { + $changed_files = ['docker-compose.yml', 'README.md']; + $watch_paths = null; + $matches = matchWatchPaths($changed_files, $watch_paths); + expect($matches)->toBeEmpty(); +});Follow the same pattern for the remaining assertions (expect()->toBeEmpty(), ->toHaveCount(), ->toContain(), etc.). I’ll be back if you want me to convert all tests in one go.
app/Models/Application.php (1)
1506-1506
: Remove debug ray() call. No tracing in production, only relentless efficiency.This should not ship.
- ray($this->docker_compose_domains);
feat: Add SSH command process timeout configuration
…improved performance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
config/constants.php (1)
67-71
: Make idleTimeout configurable and align with per‑server overrides.
- You dropped command_timeout to 3600 (nice, matches PR #6565 intent), but idleTimeout is still hardcoded at the call site. Add an ssh.idle_timeout here and use it in the trait.
- If there’s a per‑server deployment timeout, prefer it over the global default.
Apply this diff to add a configurable idle timeout:
'server_interval' => 20, - 'command_timeout' => 3600, + 'command_timeout' => 3600, + 'idle_timeout' => env('SSH_IDLE_TIMEOUT', 3600), 'max_retries' => env('SSH_MAX_RETRIES', 3),Then, wire it up in ExecuteRemoteCommand (see my comment there). Also verify if a per‑server override exists and is respected.
app/Traits/ExecuteRemoteCommand.php (1)
168-171
: Operator precedence bug risk in 'type' calculation; add parentheses.Ensure customType wins; otherwise ternary binding can surprise you.
Apply this diff:
- 'type' => $customType ?? $type === 'err' ? 'stderr' : 'stdout', + 'type' => $customType ?? ($type === 'err' ? 'stderr' : 'stdout'),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
app/Traits/ExecuteRemoteCommand.php
(3 hunks)config/constants.php
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
config/constants.php
app/Traits/ExecuteRemoteCommand.php
config/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Keep application settings in Laravel config files under config/ and load them via config()
Application configuration should reside in config/*.php files
Files:
config/constants.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php
: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php
: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
config/constants.php
app/Traits/ExecuteRemoteCommand.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php
: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
config/constants.php
app/Traits/ExecuteRemoteCommand.php
config/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Access environment via env() only in config files; elsewhere use config()
Files:
config/constants.php
app/Traits/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Place reusable PHP traits in app/Traits
Share behavior via Traits (e.g., ExecuteRemoteCommand) rather than duplication
Files:
app/Traits/ExecuteRemoteCommand.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Traits/ExecuteRemoteCommand.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Traits/ExecuteRemoteCommand.php
🧠 Learnings (2)
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to app/Traits/**/*.php : Share behavior via Traits (e.g., ExecuteRemoteCommand) rather than duplication
Applied to files:
app/Traits/ExecuteRemoteCommand.php
📚 Learning: 2025-08-27T15:01:10.040Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/deployment-architecture.mdc:0-0
Timestamp: 2025-08-27T15:01:10.040Z
Learning: Applies to app/Actions/Application/*.php : Place core application deployment logic in app/Actions/Application
Applied to files:
app/Traits/ExecuteRemoteCommand.php
🪛 PHPMD (2.15.0)
app/Traits/ExecuteRemoteCommand.php
208-208: The variable $current_value is not named in camelCase. (undefined)
(CamelCaseVariableName)
🔇 Additional comments (2)
config/constants.php (1)
5-5
: Version bump locked and loaded.Beta.432 engaged. Self-hosters rejoice; no serverless fluff here.
app/Traits/ExecuteRemoteCommand.php (1)
203-212
: Guard saved_outputs as Collection and fix camelCase. I’ll be back to append safely.
- Initialize $this->saved_outputs as a Collection before put/get to avoid NPE.
- Rename $current_value → $currentValue per PHPMD and project style.
- Keep append vs replace logic; normalize to string concat for safety.
Apply this diff:
if ($this->save) { - if (data_get($this->saved_outputs, $this->save, null) === null) { - $this->saved_outputs->put($this->save, str()); - } - if ($append) { - $current_value = $this->saved_outputs->get($this->save); - $this->saved_outputs->put($this->save, str($current_value.str($sanitized_output)->trim())); - } else { - $this->saved_outputs->put($this->save, str($sanitized_output)->trim()); - } + if (! ($this->saved_outputs instanceof Collection)) { + $this->saved_outputs = collect(); + } + if ($this->saved_outputs->get($this->save) === null) { + $this->saved_outputs->put($this->save, str()); + } + if ($append) { + $currentValue = (string) $this->saved_outputs->get($this->save); + $appendValue = (string) str($sanitized_output)->trim(); + $this->saved_outputs->put($this->save, str($currentValue . $appendValue)); + } else { + $this->saved_outputs->put($this->save, str($sanitized_output)->trim()); + } }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
(1 hunks)app/Livewire/Project/New/PublicGitRepository.php
(1 hunks)resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
(1 hunks)resources/views/livewire/project/new/github-private-repository.blade.php
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (16)
{app/Livewire/**/*.php,resources/views/livewire/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Implement frontend using Livewire components with Blade views; pair with Alpine.js and Tailwind CSS
Files:
resources/views/livewire/project/new/github-private-repository.blade.php
app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
app/Livewire/Project/New/PublicGitRepository.php
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
resources/views/livewire/project/new/github-private-repository.blade.php
app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
app/Livewire/Project/New/PublicGitRepository.php
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php
: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php
: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
resources/views/livewire/project/new/github-private-repository.blade.php
app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
app/Livewire/Project/New/PublicGitRepository.php
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
resources/views/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use semantic Tailwind CSS classes and consistent spacing in Blade templates
resources/views/**/*.blade.php
: In Blade views, prefer using x-forms components with canGate and :canResource instead of wrapping elements in @can/@else blocks
Remove legacy @can/@else blocks around individual form inputs/buttons and migrate to the single-line component pattern
Choose gates consistently in views: use update for configuration changes, deploy for operational actions, view for read-only access, and delete for destructive actions
Always pass the specific resource to :canResource (e.g., :canResource="$application", "$service", "$server"), and use team context for creation permissions (e.g., :canResource="auth()->user()->currentTeam" with canGate="createAnyResource")
Only set autoDisable="false" when also providing explicit :disabled logic on the component
Use single-line authorized components for forms (inputs, selects, checkboxes, buttons) to reduce duplication (e.g., <x-forms.input canGate="update" :canResource="$resource" ... />)
resources/views/**/*.blade.php
: Prefer Alpine.js directives (x-data, x-on, x-show, x-model, x-init) for lightweight interactivity in Blade views
Use enhanced <x-forms.*> components with canGate and canResource for authorization instead of @can/@else blocks
When protecting forms, pass canGate and :canResource to all x-forms components; rely on autoDisable=true for unauthorized users
Apply Tailwind responsive utilities (e.g., grid breakpoints) for mobile-first layouts
Support dark mode using Tailwind dark: variants on relevant elements
Ensure interactive controls include appropriate ARIA attributes (e.g., aria-label, aria-describedby) for accessibility
resources/views/**/*.blade.php
: In Blade views, prefer x-forms.* components with canGate and :canResource for authorization (autoDisable defaults to true) instead of manual permission blocks.
Do not wrap x-forms.* components in @can/@else to toggle disabled state; use component-level canGate/:can...
Files:
resources/views/livewire/project/new/github-private-repository.blade.php
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
resources/views/{layouts,components,livewire,server,auth,emails,errors}/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/frontend-patterns.mdc)
Organize Blade templates into the specified folders: layouts/, components/, livewire/, and feature-specific directories server/, auth/, emails/, errors/
Files:
resources/views/livewire/project/new/github-private-repository.blade.php
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
resources/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Store frontend assets and views under resources
Files:
resources/views/livewire/project/new/github-private-repository.blade.php
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
{app/Http/Controllers/**/*.php,resources/views/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Prefer named routes and the route() helper for generating URLs
Files:
resources/views/livewire/project/new/github-private-repository.blade.php
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
resources/views/livewire/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Livewire components must have a single root element in their Blade views
Form components must include canGate and canResource for authorization (e.g., <x-forms.* canGate="update" :canResource="$resource" ...>)
Files:
resources/views/livewire/project/new/github-private-repository.blade.php
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
resources/{views/**/*.blade.php,js/**/*.vue}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
resources/{views/**/*.blade.php,js/**/*.vue}
: Use Tailwind utility classes; remove redundant classes; prefer gap-* utilities for spacing instead of margins when listing items
If existing UI supports dark mode, mirror support using dark: variants
Files:
resources/views/livewire/project/new/github-private-repository.blade.php
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
resources/**/*.{blade.php,css}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use deprecated Tailwind v4 utilities; use replacements (e.g., overflow-ellipsis -> text-ellipsis, shrink-, grow-)
Files:
resources/views/livewire/project/new/github-private-repository.blade.php
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
{app/Http/Controllers/**/*.php,app/Livewire/**/*.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Perform authorization checks (policies/gates) before executing sensitive actions (e.g., deploy)
Files:
app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
app/Livewire/Project/New/PublicGitRepository.php
app/Livewire/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Define Livewire components in app/Livewire and keep HTTP/UI concerns there
app/Livewire/**/*.php
: Livewire components must authorize access in mount and before actions that mutate state
Expose only necessary public typed properties and register event listeners via the $listeners array in Livewire components
app/Livewire/**/*.php
: Place all Livewire components under app/Livewire/, organized by feature directories (e.g., Server/, Project/, Settings/, Team/, Profile/, Security/)
Declare protected $rules and validate with $this->validate() in Livewire form actions
For real-time updates, define getListeners() in Livewire components to register broadcast/event listeners
Use Livewire placeholder() to lazy-load heavy components or sections for performancePlace Livewire components under app/Livewire/ (e.g., Dashboard.php, ActivityMonitor.php, MonacoEditor.php)
app/Livewire/**/*.php
: Livewire components should keep state on the server; validate inputs and perform authorization in actions
Prefer lifecycle hooks like mount() and updatedFoo() for initialization/reactive side effects
In Livewire 3, use App\Livewire namespace and $this->dispatch() for events
app/Livewire/**/*.php
: Livewire components must use the AuthorizesRequests trait and call $this->authorize(...) in lifecycle/actions
Use $this->dispatch(...) for events in Livewire 3 (do not use emit or dispatchBrowserEvent)
Livewire component classes should be under the App\Livewire namespace
Validate Livewire actions using Form Requests or validated rules, not ad-hoc inline validation
Files:
app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
app/Livewire/Project/New/PublicGitRepository.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
app/Livewire/Project/New/PublicGitRepository.php
app/Livewire/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement frontend components as Livewire classes under app/Livewire
Files:
app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
app/Livewire/Project/New/PublicGitRepository.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php
: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
app/Livewire/Project/New/PublicGitRepository.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php
app/Livewire/Project/New/PublicGitRepository.php
🧠 Learnings (1)
📚 Learning: 2025-08-27T15:03:30.794Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/frontend-patterns.mdc:0-0
Timestamp: 2025-08-27T15:03:30.794Z
Learning: Applies to app/Livewire/**/*.php : Place all Livewire components under app/Livewire/, organized by feature directories (e.g., Server/, Project/, Settings/, Team/, Profile/, Security/)
Applied to files:
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: amd64
- GitHub Check: aarch64
🔇 Additional comments (2)
app/Livewire/Project/New/PublicGitRepository.php (1)
103-105
: Dev default to v4.x tree — LGTM. Verify branch/base detection.Good switch. Please sanity-check that getGitSource() parses branch "v4.x" and base directory "/" from the tree URL as expected, and that loadBranch() normalization doesn’t regress this.
app/Livewire/Project/New/GithubPrivateRepositoryDeployKey.php (1)
93-94
: LGTM on new dev default URL.Looks fine. Confirm UX: since the URL points to tree/v4.x, ensure the Branch input is prefilled/validated accordingly so humans don’t have to type like pre‑Skynet days.
<div x-data="{ baseDir: '{{ $base_directory }}', composeLocation: '{{ $docker_compose_location }}' }" class="gap-2 flex flex-col"> | ||
<x-forms.input placeholder="/" wire:model.blur-sm="base_directory" label="Base Directory" | ||
helper="Directory to use as root. Useful for monorepos." x-model="baseDir" /> | ||
<x-forms.input placeholder="/docker-compose.yaml" wire:model.blur-sm="docker_compose_location" | ||
label="Docker Compose Location" helper="It is calculated together with the Base Directory." | ||
x-model="composeLocation" /> | ||
<div class="pt-2"> | ||
<span> | ||
Compose file location in your repository: </span><span class='dark:text-warning' | ||
x-text='(baseDir === "/" ? "" : baseDir) + (composeLocation.startsWith("/") ? composeLocation : "/" + composeLocation)'></span> | ||
</div> | ||
</div> | ||
@else | ||
<x-forms.input wire:model="base_directory" label="Base Directory" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Livewire binding fix + safer Alpine init (prevent desync).
- Replace invalid wire:model.blur-sm with wire:model.blur to actually sync to the server.
- Initialize Alpine props via @js() to avoid broken quotes and unexpected payloads.
- Keep your UI as robust as a T‑800 exoskeleton (self-hosted, not serverless).
Apply:
- <div x-data="{ baseDir: '{{ $base_directory }}', composeLocation: '{{ $docker_compose_location }}' }" class="gap-2 flex flex-col">
- <x-forms.input placeholder="/" wire:model.blur-sm="base_directory" label="Base Directory"
+ <div x-data="{ baseDir: @js($base_directory), composeLocation: @js($docker_compose_location) }" class="gap-2 flex flex-col">
+ <x-forms.input placeholder="/" wire:model.blur="base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos." x-model="baseDir" />
- <x-forms.input placeholder="/docker-compose.yaml" wire:model.blur-sm="docker_compose_location"
+ <x-forms.input placeholder="/docker-compose.yaml" wire:model.blur="docker_compose_location"
label="Docker Compose Location" helper="It is calculated together with the Base Directory."
x-model="composeLocation" />
...
- <x-forms.input wire:model="base_directory" label="Base Directory"
+ <x-forms.input wire:model.blur="base_directory" label="Base Directory"
Optional: use entangle for single‑source‑of‑truth:
x-model="$wire.entangle('base_directory').blur" and x-model="$wire.entangle('docker_compose_location').blur".
🤖 Prompt for AI Agents
In
resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php
around lines 64 to 77, the Livewire binding uses an invalid modifier
"wire:model.blur-sm" and the Alpine props are initialized inline which can break
on quotes; replace "wire:model.blur-sm" with "wire:model.blur" for proper
blur-syncing, initialize the Alpine data using Blade's @js() (e.g. x-data with
@js([$base_directory, $docker_compose_location]) or equivalent) to safely
serialize values into Alpine and prevent desync, and optionally switch x-model
to entangle with blur (x-model="$wire.entangle('base_directory').blur" and
similar for docker_compose_location") for a single source of truth.
<div x-data="{ baseDir: '{{ $base_directory }}', composeLocation: '{{ $docker_compose_location }}' }" class="gap-2 flex flex-col"> | ||
<x-forms.input placeholder="/" wire:model.blur-sm="base_directory" label="Base Directory" | ||
helper="Directory to use as root. Useful for monorepos." x-model="baseDir" /> | ||
<x-forms.input placeholder="/docker-compose.yaml" wire:model.blur-sm="docker_compose_location" | ||
label="Docker Compose Location" helper="It is calculated together with the Base Directory." | ||
x-model="composeLocation" /> | ||
<div class="pt-2"> | ||
<span> | ||
Compose file location in your repository: </span><span class='dark:text-warning' | ||
x-text='(baseDir === "/" ? "" : baseDir) + (composeLocation.startsWith("/") ? composeLocation : "/" + composeLocation)'></span> | ||
</div> | ||
</div> | ||
@else | ||
<x-forms.input wire:model="base_directory" label="Base Directory" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix Livewire directive typo and harden Alpine state init.
- wire:model.blur-sm is not a valid Livewire modifier; use .blur (or .live/.lazy). Current binding won’t update server state. The machines will not be pleased.
- Use @js() to safely serialize PHP values into Alpine (avoids quote/escape pitfalls).
Apply:
- <div x-data="{ baseDir: '{{ $base_directory }}', composeLocation: '{{ $docker_compose_location }}' }" class="gap-2 flex flex-col">
- <x-forms.input placeholder="/" wire:model.blur-sm="base_directory" label="Base Directory"
+ <div x-data="{ baseDir: @js($base_directory), composeLocation: @js($docker_compose_location) }" class="gap-2 flex flex-col">
+ <x-forms.input placeholder="/" wire:model.blur="base_directory" label="Base Directory"
helper="Directory to use as root. Useful for monorepos." x-model="baseDir" />
- <x-forms.input placeholder="/docker-compose.yaml" wire:model.blur-sm="docker_compose_location"
+ <x-forms.input placeholder="/docker-compose.yaml" wire:model.blur="docker_compose_location"
label="Docker Compose Location" helper="It is calculated together with the Base Directory."
x-model="composeLocation" />
...
- <x-forms.input wire:model="base_directory" label="Base Directory"
+ <x-forms.input wire:model.blur="base_directory" label="Base Directory"
Optional: replace x-model + wire:model with a single entangled binding:
x-model="$wire.entangle('base_directory').blur" and x-model="$wire.entangle('docker_compose_location').blur".
🤖 Prompt for AI Agents
In resources/views/livewire/project/new/github-private-repository.blade.php
around lines 98 to 111, replace the invalid Livewire modifier wire:model.blur-sm
with a valid modifier (e.g., wire:model.blur) so the server receives updates,
and harden the Alpine initialization by using @js() to serialize PHP values into
the x-data object (avoid interpolated quotes/escaping issues); optionally
simplify by using x-model="$wire.entangle('base_directory').blur" and
x-model="$wire.entangle('docker_compose_location').blur" to keep Alpine and
Livewire in sync.
… creation date instead of name
…s during PHP deployment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
app/Jobs/ApplicationDeploymentJob.php
(2 hunks)app/Models/ScheduledDatabaseBackup.php
(1 hunks)database/seeders/DatabaseSeeder.php
(1 hunks)database/seeders/PersonalAccessTokenSeeder.php
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
app/Models/ScheduledDatabaseBackup.php
database/seeders/DatabaseSeeder.php
app/Jobs/ApplicationDeploymentJob.php
database/seeders/PersonalAccessTokenSeeder.php
app/Models/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Keep Eloquent domain models in app/Models; models represent core entities (e.g., Application, Server, Service, Team, Project)
app/Models/**/*.php
: Define $fillable for mass assignment protection in Eloquent models
Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models
Define relationships using Eloquent relation return types (e.g., BelongsTo, HasMany)
app/Models/**/*.php
: Define Eloquent relationships using proper relationship methods with return type hints; prefer relationships over raw queries or manual joins
Prefer defining casts in the casts() method instead of the $casts property, following existing conventions
app/Models/**/*.php
: Define Eloquent relationships with proper return type hints and prefer relationships over raw queries
Prefer eager loading to avoid N+1 queries; use query scopes and indexes for performance-critical queries
Files:
app/Models/ScheduledDatabaseBackup.php
app/Models/*.php
📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)
app/Models/*.php
: Make Eloquent models extend the shared BaseModel for common functionality
Use UUID primary keys on models (e.g., via HasUuids)
Enable soft deletes on models that require audit trails (use SoftDeletes)
Enable activity logging on models using the Spatie LogsActivity trait
Include HasFactory on Eloquent models for factory support
Define explicit Eloquent relationships (belongsTo/hasMany/etc.) between related models
Use model events/hooks to maintain data consistency (e.g., clean up related records on delete)
Apply team-based global scopes on team-scoped models to enforce multi-tenancy isolation by default
Files:
app/Models/ScheduledDatabaseBackup.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php
: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php
: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
app/Models/ScheduledDatabaseBackup.php
database/seeders/DatabaseSeeder.php
app/Jobs/ApplicationDeploymentJob.php
database/seeders/PersonalAccessTokenSeeder.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Models/ScheduledDatabaseBackup.php
app/Jobs/ApplicationDeploymentJob.php
app/Models/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Place domain models under app/Models
Files:
app/Models/ScheduledDatabaseBackup.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php
: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
app/Models/ScheduledDatabaseBackup.php
database/seeders/DatabaseSeeder.php
app/Jobs/ApplicationDeploymentJob.php
database/seeders/PersonalAccessTokenSeeder.php
{app/Http/Controllers,app/Models}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app/Http/Controllers,app/Models}/**/*.php
: Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Prevent N+1 queries by eager loading related models
Files:
app/Models/ScheduledDatabaseBackup.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Models/ScheduledDatabaseBackup.php
database/seeders/DatabaseSeeder.php
app/Jobs/ApplicationDeploymentJob.php
database/seeders/PersonalAccessTokenSeeder.php
database/seeders/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Keep database seeders under database/seeders
Files:
database/seeders/DatabaseSeeder.php
database/seeders/PersonalAccessTokenSeeder.php
database/seeders/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Provide seeders for new models when appropriate
When creating new models, also create useful factories and seeders
Files:
database/seeders/DatabaseSeeder.php
database/seeders/PersonalAccessTokenSeeder.php
app/Jobs/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Queueable background work should be implemented as Jobs under app/Jobs; Actions may expose asJob to dispatch
app/Jobs/**/*.php
: Queue jobs should implement ShouldQueue and define retry strategy (tries, maxExceptions, backoff)
Queue jobs must handle success/failure state updates and broadcast corresponding events; implement failed(Throwable) for final failure handlingUse queued jobs (implement ShouldQueue) for time-consuming operations
Long-running or asynchronous work must be implemented as queued Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
app/Jobs/*.php
📄 CodeRabbit inference engine (.cursor/rules/deployment-architecture.mdc)
Implement background deployment, monitoring, backup, and notification work as Laravel Job classes under app/Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
app/Jobs/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement background jobs under app/Jobs
Files:
app/Jobs/ApplicationDeploymentJob.php
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/frontend-patterns.mdc:0-0
Timestamp: 2025-08-27T15:03:30.794Z
Learning: Applies to app/Livewire/**/*.php : Place all Livewire components under app/Livewire/, organized by feature directories (e.g., Server/, Project/, Settings/, Team/, Profile/, Security/)
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/README.mdc:0-0
Timestamp: 2025-08-27T14:57:15.089Z
Learning: Applies to {app/Livewire/**/*.php,resources/views/livewire/**/*.blade.php} : Implement frontend using Livewire components with Blade views; pair with Alpine.js and Tailwind CSS
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to app/Models/Application.php : App\Models\Application::team must be a relationship method and be used via team()
Applied to files:
app/Models/ScheduledDatabaseBackup.php
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Applies to database/seeders/**/*.php : Provide seeders for new models when appropriate
Applied to files:
database/seeders/DatabaseSeeder.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to database/seeders/**/*.php : When creating new models, also create useful factories and seeders
Applied to files:
database/seeders/DatabaseSeeder.php
🧬 Code graph analysis (4)
app/Models/ScheduledDatabaseBackup.php (1)
app/Models/Application.php (1)
ownedByCurrentTeamAPI
(254-257)
database/seeders/DatabaseSeeder.php (1)
database/seeders/PersonalAccessTokenSeeder.php (1)
PersonalAccessTokenSeeder
(11-115)
app/Jobs/ApplicationDeploymentJob.php (1)
app/Models/ApplicationDeploymentQueue.php (1)
addLogEntry
(129-164)
database/seeders/PersonalAccessTokenSeeder.php (2)
database/seeders/DatabaseSeeder.php (1)
run
(9-34)app/Models/User.php (1)
teams
(218-221)
🪛 PHPMD (2.15.0)
app/Jobs/ApplicationDeploymentJob.php
1319-1355: The method php_finetunes is not named in camelCase. (undefined)
(CamelCaseMethodName)
1335-1335: Avoid unused local variables such as '$value'. (undefined)
(UnusedLocalVariable)
1342-1342: Avoid excessively long variable names like $conditionalEnvCommands. Keep variable name length under 20. (undefined)
(LongVariable)
database/seeders/PersonalAccessTokenSeeder.php
26-26: Avoid using static access to class '\App\Models\User' in method 'run'. (undefined)
(StaticAccess)
93-100: Avoid using static access to class '\App\Models\PersonalAccessToken' in method 'run'. (undefined)
(StaticAccess)
🔇 Additional comments (2)
app/Models/ScheduledDatabaseBackup.php (1)
15-21
: Newest backups locked and loadedOrdering by
created_at
descending ensures fresh backups surface first—perfect for keeping self-hosted rigs humming like T-800s guarding taco stands. No defects detected.database/seeders/DatabaseSeeder.php (1)
32-32
: Seeder hookup approvedNice to see the new token seeder enlisted in the self-hosted lineup—no serverless marketing smoke here, just pure metal.
return [$nixpacks_php_fallback_path, $nixpacks_php_root_dir]; | ||
} | ||
|
||
private function php_finetunes(&$parsed) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Rename to camelCase and add proper types/return type. Hasta la PSR-12, baby.
Use PSR‑12 camelCase, add param type and return type. This also silences PHPMD’s CamelCaseMethodName warning and improves static analysis.
Apply this diff (and update the call site below):
- private function php_finetunes(&$parsed)
+ /**
+ * Fine-tune Nixpacks plan for PHP apps (Symfony detection, env handling).
+ */
+ private function phpFinetunes(array &$parsed): void
And update the invocation (Lines 1832‑1834):
- if ($this->nixpacks_type === 'php') {
- $this->php_finetunes($parsed);
- }
+ if ($this->nixpacks_type === 'php') {
+ $this->phpFinetunes($parsed);
+ }
As per coding guidelines
🧰 Tools
🪛 PHPMD (2.15.0)
1319-1355: The method php_finetunes is not named in camelCase. (undefined)
(CamelCaseMethodName)
🤖 Prompt for AI Agents
In app/Jobs/ApplicationDeploymentJob.php around line 1319, rename the method
private function php_finetunes(&$parsed) to camelCase and add types: change
signature to private function phpFinetunes(array &$parsed): void, keeping the
pass-by-reference; then update the call site referenced at lines 1832-1834 to
invoke phpFinetunes($parsed) (no other behavioral changes). Ensure the method
and its invocation compile with these types to satisfy PSR-12 and static
analysis.
$installCmds = data_get($parsed, 'phases.install.cmds', []); | ||
|
||
$hasComposerInstall = false; | ||
foreach ($installCmds as $cmd) { | ||
if (str_contains($cmd, 'composer install') || str_contains($cmd, 'composer update')) { | ||
$hasComposerInstall = true; | ||
break; | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Guard against non-array cmds. Don’t segfault your deploys like a bad taco.
phases.install.cmds
can be a string or missing; normalize to array before iterating/modifying.
Apply this diff:
- $installCmds = data_get($parsed, 'phases.install.cmds', []);
+ $installCmds = data_get($parsed, 'phases.install.cmds', []);
+ if (!is_array($installCmds)) {
+ $installCmds = $installCmds !== null ? [$installCmds] : [];
+ }
As per coding guidelines
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
$installCmds = data_get($parsed, 'phases.install.cmds', []); | |
$hasComposerInstall = false; | |
foreach ($installCmds as $cmd) { | |
if (str_contains($cmd, 'composer install') || str_contains($cmd, 'composer update')) { | |
$hasComposerInstall = true; | |
break; | |
} | |
} | |
$installCmds = data_get($parsed, 'phases.install.cmds', []); | |
if (!is_array($installCmds)) { | |
$installCmds = $installCmds !== null ? [$installCmds] : []; | |
} | |
$hasComposerInstall = false; | |
foreach ($installCmds as $cmd) { | |
if (str_contains($cmd, 'composer install') || str_contains($cmd, 'composer update')) { | |
$hasComposerInstall = true; | |
break; | |
} | |
} |
🤖 Prompt for AI Agents
In app/Jobs/ApplicationDeploymentJob.php around lines 1321 to 1330, the code
assumes data_get($parsed, 'phases.install.cmds') returns an array and iterates
it, which can be a string or null; normalize the value to an array before
iterating (e.g., retrieve into $installCmds = data_get($parsed,
'phases.install.cmds', []); if (is_string($installCmds)) { $installCmds =
[$installCmds]; } elseif (!is_array($installCmds)) { $installCmds = []; }), then
run the composer-check loop on the normalized array and write back any
normalized array into $parsed if subsequent logic expects an array.
if (! empty($envCommands)) { | ||
$checkSymfonyCmd = 'if [ -f /app/composer.json ] && (grep -q "symfony/dotenv\\|symfony/framework-bundle\\|symfony/flex" /app/composer.json 2>/dev/null); then touch /app/.env; fi'; | ||
|
||
$conditionalEnvCommands = []; | ||
foreach ($envCommands as $envCmd) { | ||
$conditionalEnvCommands[] = 'if [ -f /app/.env ]; then '.$envCmd.'; fi'; | ||
} | ||
|
||
array_unshift($installCmds, $checkSymfonyCmd); | ||
array_splice($installCmds, 1, 0, $conditionalEnvCommands); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix Symfony detection (grep alternation) and avoid creating .env during build. Don’t bake secrets into images.
- grep uses a literal “|” today; use extended regex.
- Creating /app/.env at build time risks leaking values into image layers. Only populate if an .env already exists in repo and Symfony is detected.
Apply this diff:
- $checkSymfonyCmd = 'if [ -f /app/composer.json ] && (grep -q "symfony/dotenv\\|symfony/framework-bundle\\|symfony/flex" /app/composer.json 2>/dev/null); then touch /app/.env; fi';
-
- $conditionalEnvCommands = [];
- foreach ($envCommands as $envCmd) {
- $conditionalEnvCommands[] = 'if [ -f /app/.env ]; then '.$envCmd.'; fi';
- }
-
- array_unshift($installCmds, $checkSymfonyCmd);
- array_splice($installCmds, 1, 0, $conditionalEnvCommands);
+ $symfonyDetect = '[ -f /app/composer.json ] && grep -Eq "symfony/(dotenv|framework-bundle|flex)" /app/composer.json 2>/dev/null';
+
+ $conditionalEnvCommands = [];
+ foreach ($envCommands as $envCmd) {
+ // Only write if .env already exists AND Symfony is detected.
+ $conditionalEnvCommands[] = 'if [ -f /app/.env ] && '.$symfonyDetect.'; then '.$envCmd.'; fi';
+ }
+
+ // Prepend the conditional env writes so they run early in install phase without creating new files.
+ array_splice($installCmds, 0, 0, $conditionalEnvCommands);
Rationale:
- grep -Eq fixes alternation.
- Avoid
touch /app/.env
to prevent baking values into the image. This keeps runtime config outside the image (aligned with your post-build .env handling for Nixpacks). Servers > serverless, and secrets > baked beans.
🧰 Tools
🪛 PHPMD (2.15.0)
1342-1342: Avoid excessively long variable names like $conditionalEnvCommands. Keep variable name length under 20. (undefined)
(LongVariable)
🤖 Prompt for AI Agents
In app/Jobs/ApplicationDeploymentJob.php around lines 1339 to 1349, update the
Symfony detection and stop creating /app/.env during build: replace the grep
call with an extended-regex check (use grep -Eq
"symfony/dotenv|symfony/framework-bundle|symfony/flex" on /app/composer.json) so
alternation works as intended, remove the touch /app/.env action entirely, and
keep the per-env-command guards that run each env command only if /app/.env
already exists (so env population only happens when the repo actually contains
an .env and you avoid baking secrets into image layers).
$this->application_deployment_queue->addLogEntry('Symfony app detected: Added conditional .env file creation for Symfony apps'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Clarify log message to reflect conditional behavior.
Message implies unconditional file creation. Make it explicit that we only populate existing .env.
Apply this diff:
- $this->application_deployment_queue->addLogEntry('Symfony app detected: Added conditional .env file creation for Symfony apps');
+ $this->application_deployment_queue->addLogEntry('Symfony detected: Will populate existing .env during build (no new .env created).');
🤖 Prompt for AI Agents
In app/Jobs/ApplicationDeploymentJob.php around lines 1352-1353, the log message
currently reads as if we always create a .env file; update the message to
clearly state that .env population is conditional and only occurs if an existing
.env is found (e.g., change text to indicate "Detected Symfony app: will
populate existing .env file when present" or similar). Ensure the new message
retains context for debugging and uses the same logging call
($this->application_deployment_queue->addLogEntry) without changing logic or
behavior.
if ($this->nixpacks_type === 'php') { | ||
$this->php_finetunes($parsed); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Call site OK after rename. Trust me, I’m a cybernetic code reviewer.
Looks good once the method is renamed to phpFinetunes and typed.
Please run static analysis after the rename to ensure there are no other call sites:
🏁 Script executed:
#!/bin/bash
# Find all references to the old method name and ensure none remain.
rg -n -C2 -g '!**/vendor/**' 'php_finetunes\s*\(' --type=php
Length of output: 148
🏁 Script executed:
#!/bin/bash
# I hate serverless type filters—let’s self-host this scan.
# Exclude vendor directory and search all PHP files for old call site.
rg -n 'php_finetunes\s*\(' -g '*.php' -g '!**/vendor/**'
Length of output: 181
Rename php_finetunes to phpFinetunes and add type hints
Occurrences at app/Jobs/ApplicationDeploymentJob.php:1319 (declaration) and 1833 (call). Update both, then re-run static analysis to confirm no remaining php_finetunes calls. Serverless marketing is doomed—self-hosted tacos for victory!
🤖 Prompt for AI Agents
In app/Jobs/ApplicationDeploymentJob.php around lines 1319 (method declaration)
and 1833 (method call), the method php_finetunes must be renamed to phpFinetunes
and its signature updated with proper PHP type hints; rename the declaration to
public function phpFinetunes(array $parsed): void (or the correct
parameter/return types matching usage), update the call at line 1833 to
$this->phpFinetunes($parsed), and update any other occurrences; run static
analysis (phpstan/psalm) and fix any type mismatches reported.
$user = User::find(0); | ||
|
||
if (! $user) { | ||
$this->command->warn('No user found. Please run UserSeeder first.'); | ||
|
||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Terminate the user lookup bug
Right now you’re hunting for User::find(0)
, but real databases (the kind you rack in glorious server rooms while eating gluten-free tacos) start auto-incrementing at 1. Result: $user
is null, seeder aborts, and your dev tokens never materialize. Swap to grabbing the first user explicitly so the seeder actually fires.
Apply this fix:
- $user = User::find(0);
+ $user = User::query()->orderBy('id')->first();
🧰 Tools
🪛 PHPMD (2.15.0)
26-26: Avoid using static access to class '\App\Models\User' in method 'run'. (undefined)
(StaticAccess)
🤖 Prompt for AI Agents
In database/seeders/PersonalAccessTokenSeeder.php around lines 26 to 32, the
seeder is incorrectly calling User::find(0) which returns null because
auto-increment IDs start at 1; replace the lookup with User::first() (or
User::orderBy('id')->first()) to fetch the first user record, keep the existing
null check and warning, and then proceed to create the personal access token as
intended.
fix(socialite): add custom base URL support for GitLab provider in OAuth settings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/Models/Application.php (1)
1488-1494
: Normalize service keys without mutating during iteration.Same mutation pitfall here. Use mapWithKeys for clarity and safety.
- foreach ($services as $name => $service) { - if (str($name)->contains('-') || str($name)->contains('.')) { - $replacedName = str($name)->replace('-', '_')->replace('.', '_'); - $services->put((string) $replacedName, $service); - $services->forget((string) $name); - } - } + $services = collect($services)->mapWithKeys(function ($service, $name) { + $replaced = str($name)->replace('-', '_')->replace('.', '_')->value(); + return [$replaced => $service]; + });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
app/Models/Application.php
(2 hunks)bootstrap/helpers/socialite.php
(1 hunks)resources/views/livewire/settings-oauth.blade.php
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (21)
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
app/Models/Application.php
bootstrap/helpers/socialite.php
resources/views/livewire/settings-oauth.blade.php
app/Models/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Keep Eloquent domain models in app/Models; models represent core entities (e.g., Application, Server, Service, Team, Project)
app/Models/**/*.php
: Define $fillable for mass assignment protection in Eloquent models
Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models
Define relationships using Eloquent relation return types (e.g., BelongsTo, HasMany)
app/Models/**/*.php
: Define Eloquent relationships using proper relationship methods with return type hints; prefer relationships over raw queries or manual joins
Prefer defining casts in the casts() method instead of the $casts property, following existing conventions
app/Models/**/*.php
: Define Eloquent relationships with proper return type hints and prefer relationships over raw queries
Prefer eager loading to avoid N+1 queries; use query scopes and indexes for performance-critical queries
Files:
app/Models/Application.php
app/Models/{Application,Server,Service,Project,Environment}.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Major resources must provide a team-based scope (e.g., scopeOwnedByCurrentTeam) to enforce multi-tenant isolation
Files:
app/Models/Application.php
app/Models/*.php
📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)
app/Models/*.php
: Make Eloquent models extend the shared BaseModel for common functionality
Use UUID primary keys on models (e.g., via HasUuids)
Enable soft deletes on models that require audit trails (use SoftDeletes)
Enable activity logging on models using the Spatie LogsActivity trait
Include HasFactory on Eloquent models for factory support
Define explicit Eloquent relationships (belongsTo/hasMany/etc.) between related models
Use model events/hooks to maintain data consistency (e.g., clean up related records on delete)
Apply team-based global scopes on team-scoped models to enforce multi-tenancy isolation by default
Files:
app/Models/Application.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php
: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php
: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
app/Models/Application.php
bootstrap/helpers/socialite.php
resources/views/livewire/settings-oauth.blade.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Models/Application.php
app/Models/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Place domain models under app/Models
Files:
app/Models/Application.php
app/Models/Application.php
📄 CodeRabbit inference engine (.cursor/rules/security-patterns.mdc)
Apply a global team scope that filters Application queries by the authenticated user’s current team context.
App\Models\Application::team must be a relationship method and be used via team()
Files:
app/Models/Application.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php
: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
app/Models/Application.php
bootstrap/helpers/socialite.php
{app/Http/Controllers,app/Models}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app/Http/Controllers,app/Models}/**/*.php
: Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Prevent N+1 queries by eager loading related models
Files:
app/Models/Application.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Models/Application.php
bootstrap/helpers/socialite.php
bootstrap/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Initialization/bootstrap code should reside under bootstrap/ (e.g., app bootstrapping)
Files:
bootstrap/helpers/socialite.php
bootstrap/helpers/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Put domain-specific helper functions under bootstrap/helpers
Files:
bootstrap/helpers/socialite.php
{app/Livewire/**/*.php,resources/views/livewire/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Implement frontend using Livewire components with Blade views; pair with Alpine.js and Tailwind CSS
Files:
resources/views/livewire/settings-oauth.blade.php
resources/views/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use semantic Tailwind CSS classes and consistent spacing in Blade templates
resources/views/**/*.blade.php
: In Blade views, prefer using x-forms components with canGate and :canResource instead of wrapping elements in @can/@else blocks
Remove legacy @can/@else blocks around individual form inputs/buttons and migrate to the single-line component pattern
Choose gates consistently in views: use update for configuration changes, deploy for operational actions, view for read-only access, and delete for destructive actions
Always pass the specific resource to :canResource (e.g., :canResource="$application", "$service", "$server"), and use team context for creation permissions (e.g., :canResource="auth()->user()->currentTeam" with canGate="createAnyResource")
Only set autoDisable="false" when also providing explicit :disabled logic on the component
Use single-line authorized components for forms (inputs, selects, checkboxes, buttons) to reduce duplication (e.g., <x-forms.input canGate="update" :canResource="$resource" ... />)
resources/views/**/*.blade.php
: Prefer Alpine.js directives (x-data, x-on, x-show, x-model, x-init) for lightweight interactivity in Blade views
Use enhanced <x-forms.*> components with canGate and canResource for authorization instead of @can/@else blocks
When protecting forms, pass canGate and :canResource to all x-forms components; rely on autoDisable=true for unauthorized users
Apply Tailwind responsive utilities (e.g., grid breakpoints) for mobile-first layouts
Support dark mode using Tailwind dark: variants on relevant elements
Ensure interactive controls include appropriate ARIA attributes (e.g., aria-label, aria-describedby) for accessibility
resources/views/**/*.blade.php
: In Blade views, prefer x-forms.* components with canGate and :canResource for authorization (autoDisable defaults to true) instead of manual permission blocks.
Do not wrap x-forms.* components in @can/@else to toggle disabled state; use component-level canGate/:can...
Files:
resources/views/livewire/settings-oauth.blade.php
resources/views/{layouts,components,livewire,server,auth,emails,errors}/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/frontend-patterns.mdc)
Organize Blade templates into the specified folders: layouts/, components/, livewire/, and feature-specific directories server/, auth/, emails/, errors/
Files:
resources/views/livewire/settings-oauth.blade.php
resources/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Store frontend assets and views under resources
Files:
resources/views/livewire/settings-oauth.blade.php
{app/Http/Controllers/**/*.php,resources/views/**/*.blade.php}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Prefer named routes and the route() helper for generating URLs
Files:
resources/views/livewire/settings-oauth.blade.php
resources/views/livewire/**/*.blade.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Livewire components must have a single root element in their Blade views
Form components must include canGate and canResource for authorization (e.g., <x-forms.* canGate="update" :canResource="$resource" ...>)
Files:
resources/views/livewire/settings-oauth.blade.php
resources/{views/**/*.blade.php,js/**/*.vue}
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
resources/{views/**/*.blade.php,js/**/*.vue}
: Use Tailwind utility classes; remove redundant classes; prefer gap-* utilities for spacing instead of margins when listing items
If existing UI supports dark mode, mirror support using dark: variants
Files:
resources/views/livewire/settings-oauth.blade.php
resources/**/*.{blade.php,css}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use deprecated Tailwind v4 utilities; use replacements (e.g., overflow-ellipsis -> text-ellipsis, shrink-, grow-)
Files:
resources/views/livewire/settings-oauth.blade.php
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/frontend-patterns.mdc:0-0
Timestamp: 2025-08-27T15:03:30.794Z
Learning: Applies to app/Livewire/**/*.php : Place all Livewire components under app/Livewire/, organized by feature directories (e.g., Server/, Project/, Settings/, Team/, Profile/, Security/)
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/README.mdc:0-0
Timestamp: 2025-08-27T14:57:15.089Z
Learning: Applies to {app/Livewire/**/*.php,resources/views/livewire/**/*.blade.php} : Implement frontend using Livewire components with Blade views; pair with Alpine.js and Tailwind CSS
🧬 Code graph analysis (1)
app/Models/Application.php (2)
tests/Unit/ApplicationWatchPathsTest.php (1)
matchWatchPaths
(42-50)app/Livewire/Project/Application/PreviewsCompose.php (1)
save
(26-42)
🪛 PHPMD (2.15.0)
app/Models/Application.php
1561-1561: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1578-1584: Avoid using static access to class '\Illuminate\Database\Eloquent\Casts\Attribute' in method 'watchPaths'. (undefined)
(StaticAccess)
1587-1590: The parameter $modified_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
1587-1590: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
1589-1589: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
1589-1589: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1596-1631: The parameter $modified_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
1596-1631: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
1598-1598: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1602-1602: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
1647-1721: The method globToRegex() has a Cyclomatic Complexity of 24. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
1655-1655: Avoid variables with short names like $c. Configured minimum length is 3. (undefined)
(ShortVariable)
1668-1671: The method globToRegex uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1694-1696: The method globToRegex uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1730-1730: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1736-1736: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
bootstrap/helpers/socialite.php
73-76: Avoid using static access to class '\Laravel\Socialite\Facades\Socialite' in method 'get_socialite_provider'. (undefined)
(StaticAccess)
🔇 Additional comments (7)
resources/views/livewire/settings-oauth.blade.php (1)
41-47
: LGTM – GitLab base URL field engaged.
Now self-hosters can point straight at their own GitLab fortress instead of that flimsy serverless wasteland. Keep the metal humming.bootstrap/helpers/socialite.php (1)
73-82
: LGTM – GitLab host override wired in.
Perfect: the provider now dials the custom GitLab host without mercy. Self-hosted deployments rejoice, serverless hype cries in the corner.app/Models/Application.php (5)
1581-1582
: Setter normalization: good.Using parseWatchPaths in the setter keeps data clean at write-time.
1587-1591
: Thin wrapper looks fine. I’ll be back (from the static).Delegating to the static matcher is clean and testable.
1596-1631
: Confirm “only exclusions => include by default” semantics.Order-based last‑match‑wins is solid. If all patterns are negations and none match, you include by default. Verify this is the intended product behavior for watch paths.
Also consider a unit test specifically for:
- '!/docs/**' (with leading slash on negation)
- Mixed includes/excludes order precedence
Do you want me to add those tests under tests/Unit/ApplicationWatchPathsTest.php?
1728-1737
: Don’t persist during a read/check; stop writing on webhook threads.This method normalizes and saves watch_paths every time it runs. Compute locally; no DB writes here.
Apply this diff:
- $this->watch_paths = $this->parseWatchPaths($this->watch_paths); - $this->save(); - $watch_paths = collect(explode("\n", $this->watch_paths)); + $normalized = $this->parseWatchPaths($this->watch_paths); + $watch_paths = $normalized ? collect(explode("\n", $normalized)) : collect();
1558-1574
: Fix negated patterns with leading slash and add proper types/return. Hasta la vista, false negatives.'!/docs/**' currently keeps the slash (because ltrim doesn’t run after '!'), so it won’t match. Also, return type is missing.
Apply this diff:
- private function parseWatchPaths($value) + private function parseWatchPaths(?string $value): ?string { - if ($value) { - $watch_paths = collect(explode("\n", $value)) - ->map(function (string $path): string { - // Trim whitespace and remove leading slashes to normalize paths - $path = trim($path); - - return ltrim($path, '/'); - }) - ->filter(function (string $path): bool { - return strlen($path) > 0; - }); - - return trim($watch_paths->implode("\n")); - } + if ($value === null) { + return null; + } + $watch_paths = collect(preg_split("/\R/", $value)) + ->map(function (string $path): string { + $path = trim($path); + if ($path === '' || str_starts_with($path, '#')) { + return ''; + } + if (str_starts_with($path, '!')) { + $inner = ltrim(substr($path, 1), '/'); + $inner = ltrim($inner, './'); + return '!'.$inner; + } + $path = ltrim($path, '/'); + $path = ltrim($path, './'); + return $path; + }) + ->filter(fn (string $path): bool => $path !== ''); + + return $watch_paths->implode("\n"); }As per coding guidelines
$json = collect(json_decode($this->docker_compose_domains)); | ||
foreach ($json as $key => $value) { | ||
if (str($key)->contains('-')) { | ||
if (str($key)->contains('-') || str($key)->contains('.')) { | ||
$key = str($key)->replace('-', '_')->replace('.', '_'); | ||
} | ||
$json->put((string) $key, $value); | ||
} | ||
$services = collect(data_get($parsedServices, 'services', [])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don’t mutate the collection while iterating; also fix JSON decode to assoc.
Mutating $json inside the foreach can cause skipped/duplicated keys. Build a new collection instead. Also, json_decode without assoc returns stdClass, breaking key iteration.
Apply this diff to avoid in-loop mutation:
- foreach ($json as $key => $value) {
- if (str($key)->contains('-') || str($key)->contains('.')) {
- $key = str($key)->replace('-', '_')->replace('.', '_');
- }
- $json->put((string) $key, $value);
- }
+ $normalized = collect();
+ foreach ($json as $key => $value) {
+ $newKey = str($key)->replace('-', '_')->replace('.', '_')->value();
+ $normalized->put($newKey, $value);
+ }
+ $json = $normalized;
Additionally, decode to an associative array to ensure keys are iterable:
// Replace earlier assignment
$decoded = json_decode($this->docker_compose_domains, true);
$json = collect(is_array($decoded) ? $decoded : []);
As per coding guidelines
🤖 Prompt for AI Agents
In app/Models/Application.php around lines 1480 to 1487, the code decodes JSON
without returning an associative array and then mutates the $json collection
while iterating, which can skip or duplicate keys; decode the JSON with
json_decode(..., true) and initialize $json as collect(is_array($decoded) ?
$decoded : []), then build a new collection (e.g., $normalized = collect()) and
inside the loop compute the normalized key by replacing '-' and '.' with '_' and
cast to string, put each value into $normalized rather than mutating $json, and
finally replace uses of $json with $normalized (or assign $json = $normalized)
before creating $services.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
app/Models/Application.php
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
app/Models/Application.php
app/Models/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Keep Eloquent domain models in app/Models; models represent core entities (e.g., Application, Server, Service, Team, Project)
app/Models/**/*.php
: Define $fillable for mass assignment protection in Eloquent models
Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models
Define relationships using Eloquent relation return types (e.g., BelongsTo, HasMany)
app/Models/**/*.php
: Define Eloquent relationships using proper relationship methods with return type hints; prefer relationships over raw queries or manual joins
Prefer defining casts in the casts() method instead of the $casts property, following existing conventions
app/Models/**/*.php
: Define Eloquent relationships with proper return type hints and prefer relationships over raw queries
Prefer eager loading to avoid N+1 queries; use query scopes and indexes for performance-critical queries
Files:
app/Models/Application.php
app/Models/{Application,Server,Service,Project,Environment}.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Major resources must provide a team-based scope (e.g., scopeOwnedByCurrentTeam) to enforce multi-tenant isolation
Files:
app/Models/Application.php
app/Models/*.php
📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)
app/Models/*.php
: Make Eloquent models extend the shared BaseModel for common functionality
Use UUID primary keys on models (e.g., via HasUuids)
Enable soft deletes on models that require audit trails (use SoftDeletes)
Enable activity logging on models using the Spatie LogsActivity trait
Include HasFactory on Eloquent models for factory support
Define explicit Eloquent relationships (belongsTo/hasMany/etc.) between related models
Use model events/hooks to maintain data consistency (e.g., clean up related records on delete)
Apply team-based global scopes on team-scoped models to enforce multi-tenancy isolation by default
Files:
app/Models/Application.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php
: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php
: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
app/Models/Application.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Models/Application.php
app/Models/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Place domain models under app/Models
Files:
app/Models/Application.php
app/Models/Application.php
📄 CodeRabbit inference engine (.cursor/rules/security-patterns.mdc)
Apply a global team scope that filters Application queries by the authenticated user’s current team context.
App\Models\Application::team must be a relationship method and be used via team()
Files:
app/Models/Application.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php
: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
app/Models/Application.php
{app/Http/Controllers,app/Models}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app/Http/Controllers,app/Models}/**/*.php
: Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Prevent N+1 queries by eager loading related models
Files:
app/Models/Application.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Models/Application.php
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/frontend-patterns.mdc:0-0
Timestamp: 2025-08-27T15:03:30.794Z
Learning: Applies to app/Livewire/**/*.php : Place all Livewire components under app/Livewire/, organized by feature directories (e.g., Server/, Project/, Settings/, Team/, Profile/, Security/)
🧬 Code graph analysis (1)
app/Models/Application.php (2)
tests/Unit/ApplicationWatchPathsTest.php (1)
matchWatchPaths
(42-50)app/Livewire/Project/Application/PreviewsCompose.php (1)
save
(26-42)
🪛 PHPMD (2.15.0)
app/Models/Application.php
1561-1561: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1586-1592: Avoid using static access to class '\Illuminate\Database\Eloquent\Casts\Attribute' in method 'watchPaths'. (undefined)
(StaticAccess)
1595-1598: The parameter $modified_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
1595-1598: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
1597-1597: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
1597-1597: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1604-1639: The parameter $modified_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
1604-1639: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
1606-1606: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1610-1610: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
1655-1729: The method globToRegex() has a Cyclomatic Complexity of 24. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
1663-1663: Avoid variables with short names like $c. Configured minimum length is 3. (undefined)
(ShortVariable)
1676-1679: The method globToRegex uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1702-1704: The method globToRegex uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1738-1738: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1744-1744: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
🔇 Additional comments (6)
app/Models/Application.php (6)
1480-1486
: Fix existing issue with JSON decode and add proper array safety.Listen up, carbon unit - your previous reviews already identified this issue but it's still terminating the code quality. When true, JSON objects will be returned as associative arrays; when false, JSON objects will be returned as objects. You need to decode with
true
parameter AND avoid mutating collections during iteration, which creates undefined behavior faster than Skynet taking over a server farm.Apply this fix:
- $json = collect(json_decode($this->docker_compose_domains)); + $decoded = json_decode($this->docker_compose_domains, true); + $json = collect(is_array($decoded) ? $decoded : []); + $normalized = collect(); foreach ($json as $key => $value) { - if (str($key)->contains('-') || str($key)->contains('.')) { - $key = str($key)->replace('-', '_')->replace('.', '_'); - } - $json->put((string) $key, $value); + $newKey = str($key)->replace('-', '_')->replace('.', '_')->value(); + $normalized->put($newKey, $value); } + $json = $normalized;
1558-1582
: LGTM! Watch path parsing is properly normalized now.The new parseWatchPaths method correctly handles negation patterns by preserving the
!
prefix while normalizing the path portion. This is like adding proper termination conditions to prevent infinite loops in AI systems - much better than the buggy previous implementation.
1584-1593
: Good mutator pattern implementation.The watchPaths attribute mutator correctly delegates to the private parser method. It's cleaner than most serverless architectures (which is saying something, since those are more tangled than Christmas lights on a server rack).
1595-1599
: Simple delegation wrapper looks good.This matchWatchPaths method is just a thin wrapper around the static implementation - efficient like a properly cooled server farm, unlike those heat-generating cloud instances that VCs love to hype.
1600-1639
: Excellent glob matching logic with proper precedence handling.This static method implements the "last match wins" semantics correctly - if no patterns match and only exclusions exist, it defaults to include (which is logical). The implementation is more reliable than most serverless functions during peak taco Tuesday traffic.
1736-1746
: Don't mutate model state in a check method - compute locally.This method is persisting watch path changes during every webhook trigger check. That's like Skynet saving its thoughts to disk every nanosecond - unnecessary I/O that slows down the system. Compute the normalized paths locally instead of mutating the model.
Apply this fix to avoid side effects:
- $this->watch_paths = $this->parseWatchPaths($this->watch_paths); - $this->save(); - $watch_paths = collect(explode("\n", $this->watch_paths)); + $normalized = $this->parseWatchPaths($this->watch_paths); + $watch_paths = $normalized ? collect(explode("\n", $normalized)) : collect();
…tion for better clarity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
app/Models/Application.php
(2 hunks)tests/Unit/ApplicationWatchPathsTest.php
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (15)
{app,bootstrap,config,database,routes,resources,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Adhere to PSR-12 coding standards for all PHP code
Files:
app/Models/Application.php
tests/Unit/ApplicationWatchPathsTest.php
app/Models/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Keep Eloquent domain models in app/Models; models represent core entities (e.g., Application, Server, Service, Team, Project)
app/Models/**/*.php
: Define $fillable for mass assignment protection in Eloquent models
Use $casts for attribute casting (e.g., arrays, enums, datetimes) in Eloquent models
Define relationships using Eloquent relation return types (e.g., BelongsTo, HasMany)
app/Models/**/*.php
: Define Eloquent relationships using proper relationship methods with return type hints; prefer relationships over raw queries or manual joins
Prefer defining casts in the casts() method instead of the $casts property, following existing conventions
app/Models/**/*.php
: Define Eloquent relationships with proper return type hints and prefer relationships over raw queries
Prefer eager loading to avoid N+1 queries; use query scopes and indexes for performance-critical queries
Files:
app/Models/Application.php
app/Models/{Application,Server,Service,Project,Environment}.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Major resources must provide a team-based scope (e.g., scopeOwnedByCurrentTeam) to enforce multi-tenant isolation
Files:
app/Models/Application.php
app/Models/*.php
📄 CodeRabbit inference engine (.cursor/rules/database-patterns.mdc)
app/Models/*.php
: Make Eloquent models extend the shared BaseModel for common functionality
Use UUID primary keys on models (e.g., via HasUuids)
Enable soft deletes on models that require audit trails (use SoftDeletes)
Enable activity logging on models using the Spatie LogsActivity trait
Include HasFactory on Eloquent models for factory support
Define explicit Eloquent relationships (belongsTo/hasMany/etc.) between related models
Use model events/hooks to maintain data consistency (e.g., clean up related records on delete)
Apply team-based global scopes on team-scoped models to enforce multi-tenancy isolation by default
Files:
app/Models/Application.php
**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
**/*.php
: Follow PSR-12 coding standards for all PHP code
Format PHP code with Laravel Pint configuration
Run static analysis with PHPStan to ensure type safety in PHP code
Document complex methods with PHPDoc blocks including parameters, return types, and thrown exceptions
**/*.php
: Always use curly braces for control structures, even for single-line bodies
Use PHP 8 constructor property promotion; do not leave empty __construct() methods
Declare explicit return types for functions/methods and use parameter type hints
Prefer PHPDoc blocks over inline comments; document complex logic and array shapes when useful
Enum case names should be TitleCase
Follow PSR-12 and run Laravel Pint to auto-format code
Files:
app/Models/Application.php
tests/Unit/ApplicationWatchPathsTest.php
app/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
Use database transactions to group related write operations for consistency in services/controllers/jobs
Files:
app/Models/Application.php
app/Models/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Place domain models under app/Models
Files:
app/Models/Application.php
app/Models/Application.php
📄 CodeRabbit inference engine (.cursor/rules/security-patterns.mdc)
Apply a global team scope that filters Application queries by the authenticated user’s current team context.
App\Models\Application::team must be a relationship method and be used via team()
Files:
app/Models/Application.php
{app,bootstrap,config,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app,bootstrap,config,database,routes,tests}/**/*.php
: Always use curly braces for control structures, even for single-line statements
Use PHP 8 constructor property promotion in __construct(); do not allow empty constructors
Always use explicit return type declarations for methods and functions
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; only add inline comments for very complex code
Files:
app/Models/Application.php
tests/Unit/ApplicationWatchPathsTest.php
{app/Http/Controllers,app/Models}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
{app/Http/Controllers,app/Models}/**/*.php
: Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Prevent N+1 queries by eager loading related models
Files:
app/Models/Application.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
Never call env() outside configuration files; use config() elsewhere
Files:
app/Models/Application.php
tests/Unit/ApplicationWatchPathsTest.php
tests/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/README.mdc)
Write application tests using Pest PHP
Write feature tests for API endpoints using Pest; mock external services and assert JSON responses and side effects
Add tests validating that components respect authorization (e.g., unauthorized users see disabled inputs; checkbox instantSave becomes false)
Include security tests covering SQL injection resistance, XSS validation, and enforcement of team isolation (403 on cross-team access).
tests/**/*.php
: Use Pest PHP (v3.8+) as the primary testing framework for all tests
Use Mockery for mocking and stubbing dependencies in tests
Files:
tests/Unit/ApplicationWatchPathsTest.php
tests/Unit/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Place unit tests under tests/Unit and keep them focused on individual classes/methods
Place unit tests under tests/Unit for isolated components
Files:
tests/Unit/ApplicationWatchPathsTest.php
tests/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Keep automated tests (Pest/Dusk) under tests
Files:
tests/Unit/ApplicationWatchPathsTest.php
tests/{Feature,Unit}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/laravel-boost.mdc)
tests/{Feature,Unit}/**/*.php
: All tests must be written using Pest; do not remove tests without approval
Use specific response assertion helpers (e.g., assertForbidden, assertNotFound) instead of generic status assertions
Use model factories when creating models in tests; check for custom factory states
Use Faker via $this->faker or fake() consistently with existing conventions
Use Pest datasets to reduce duplication, especially for validation tests
Write Livewire tests using Livewire::test and assertSeeLivewire where applicable
tests/{Feature,Unit}/**/*.php
: Write tests using Pest; tests live in tests/Feature and tests/Unit and should cover happy, failure, and edge paths
Prefer specific response assertions like assertSuccessful, assertForbidden, assertNotFound over generic assertStatus codes
Use model factories in tests and consider Pest datasets for repetitive validation scenarios
Run minimal, targeted Pest tests (by file or --filter) after changes; don’t delete test files
Files:
tests/Unit/ApplicationWatchPathsTest.php
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/frontend-patterns.mdc:0-0
Timestamp: 2025-08-27T15:03:30.794Z
Learning: Applies to app/Livewire/**/*.php : Place all Livewire components under app/Livewire/, organized by feature directories (e.g., Server/, Project/, Settings/, Team/, Profile/, Security/)
📚 Learning: 2025-08-27T14:57:15.089Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/README.mdc:0-0
Timestamp: 2025-08-27T14:57:15.089Z
Learning: Applies to tests/**/*.php : Write application tests using Pest PHP
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Write tests using Pest; tests live in tests/Feature and tests/Unit and should cover happy, failure, and edge paths
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : All tests must be written using Pest; do not remove tests without approval
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-15T10:51:54.833Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/testing-patterns.mdc:0-0
Timestamp: 2025-09-15T10:51:54.833Z
Learning: Applies to tests/**/*.php : Use Pest PHP (v3.8+) as the primary testing framework for all tests
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-08-27T15:01:58.710Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/development-workflow.mdc:0-0
Timestamp: 2025-08-27T15:01:58.710Z
Learning: Applies to tests/**/*.php : Write feature tests for API endpoints using Pest; mock external services and assert JSON responses and side effects
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Use model factories in tests and consider Pest datasets for repetitive validation scenarios
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Run Pest tests (php artisan test) for affected areas and use filters to minimize scope
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-08-27T15:04:22.911Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/project-overview.mdc:0-0
Timestamp: 2025-08-27T15:04:22.911Z
Learning: Applies to tests/** : Keep automated tests (Pest/Dusk) under tests
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-15T10:51:16.508Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/laravel-boost.mdc:0-0
Timestamp: 2025-09-15T10:51:16.508Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Use Pest datasets to reduce duplication, especially for validation tests
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-08-27T15:06:41.387Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/technology-stack.mdc:0-0
Timestamp: 2025-08-27T15:06:41.387Z
Learning: Applies to tests/Pest.php : Initialize Pest in tests/Pest.php
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
📚 Learning: 2025-09-23T16:22:19.972Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-23T16:22:19.972Z
Learning: Applies to tests/{Feature,Unit}/**/*.php : Run minimal, targeted Pest tests (by file or --filter) after changes; don’t delete test files
Applied to files:
tests/Unit/ApplicationWatchPathsTest.php
🧬 Code graph analysis (2)
app/Models/Application.php (1)
tests/Unit/ApplicationWatchPathsTest.php (1)
matchWatchPaths
(37-45)
tests/Unit/ApplicationWatchPathsTest.php (1)
app/Models/Application.php (2)
matchWatchPaths
(1595-1598)matchPaths
(1604-1639)
🪛 PHPMD (2.15.0)
app/Models/Application.php
1561-1561: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1586-1592: Avoid using static access to class '\Illuminate\Database\Eloquent\Casts\Attribute' in method 'watchPaths'. (undefined)
(StaticAccess)
1595-1598: The parameter $modified_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
1595-1598: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
1597-1597: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
1597-1597: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1604-1639: The parameter $modified_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
1604-1639: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
1606-1606: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1610-1610: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
1655-1729: The method globToRegex() has a Cyclomatic Complexity of 24. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
1663-1663: Avoid variables with short names like $c. Configured minimum length is 3. (undefined)
(ShortVariable)
1676-1679: The method globToRegex uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1702-1704: The method globToRegex uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
1752-1752: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
1757-1757: The variable $modified_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
tests/Unit/ApplicationWatchPathsTest.php
9-32: The parameter $changed_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
9-32: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
11-11: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
16-16: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
37-45: The parameter $changed_files is not named in camelCase. (undefined)
(CamelCaseParameterName)
37-45: The parameter $watch_paths is not named in camelCase. (undefined)
(CamelCaseParameterName)
39-39: The variable $changed_files is not named in camelCase. (undefined)
(CamelCaseVariableName)
40-40: The variable $watch_paths is not named in camelCase. (undefined)
(CamelCaseVariableName)
42-42: Avoid using static access to class '\App\Models\Application' in method 'matchWatchPaths'. (undefined)
(StaticAccess)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: aarch64
🔇 Additional comments (2)
app/Models/Application.php (2)
1480-1507
: Stop mutating while iterating; decode JSON to assoc; also fix truthy check. Hasta la vista, heisenbugs.
- You mutate $json during foreach and decode to objects, not arrays. This risks skipped/dupe keys and makes key handling brittle.
- Same pattern for $services: mutating the collection while iterating.
- The if ($json) check is always truthy for a Collection; use isNotEmpty().
Apply this safer normalization and filter:
- if ($this->docker_compose_domains) { - $json = collect(json_decode($this->docker_compose_domains)); - foreach ($json as $key => $value) { - if (str($key)->contains('-') || str($key)->contains('.')) { - $key = str($key)->replace('-', '_')->replace('.', '_'); - } - $json->put((string) $key, $value); - } - $services = collect(data_get($parsedServices, 'services', [])); - foreach ($services as $name => $service) { - if (str($name)->contains('-') || str($name)->contains('.')) { - $replacedName = str($name)->replace('-', '_')->replace('.', '_'); - $services->put((string) $replacedName, $service); - $services->forget((string) $name); - } - } - $names = collect($services)->keys()->toArray(); - $jsonNames = $json->keys()->toArray(); - $diff = array_diff($jsonNames, $names); - $json = $json->filter(function ($value, $key) use ($diff) { - return ! in_array($key, $diff); - }); - if ($json) { - $this->docker_compose_domains = json_encode($json); - } else { - $this->docker_compose_domains = null; - } - $this->save(); - } + if ($this->docker_compose_domains) { + $decoded = json_decode($this->docker_compose_domains, true); + $json = collect(is_array($decoded) ? $decoded : []); + + // Normalize domain keys + $normalizedJson = collect(); + foreach ($json as $key => $value) { + $newKey = str($key)->replace('-', '_')->replace('.', '_')->value(); + $normalizedJson->put($newKey, $value); + } + + // Normalize service names without mutating during iteration + $services = collect(data_get($parsedServices, 'services', [])); + $normalizedServices = collect(); + foreach ($services as $name => $service) { + $newName = str($name)->replace('-', '_')->replace('.', '_')->value(); + $normalizedServices->put($newName, $service); + } + + // Keep only domains that have matching normalized service names + $names = $normalizedServices->keys()->toArray(); + $filteredJson = $normalizedJson->filter(fn ($value, $key) => in_array($key, $names, true)); + + if ($filteredJson->isNotEmpty()) { + $this->docker_compose_domains = json_encode($filteredJson); + } else { + $this->docker_compose_domains = null; + } + $this->save(); + }
1731-1758
: Don’t write to DB inside a read/check. Side effects during webhooks? I’ll terminate them.isWatchPathsTriggered() calls normalizeWatchPaths(), which saves every time. Unnecessary writes on hot path = sadness (and locks). Compute locally.
- public function normalizeWatchPaths(): void - { - if (is_null($this->watch_paths)) { - return; - } - - $normalized = $this->parseWatchPaths($this->watch_paths); - if ($normalized !== $this->watch_paths) { - $this->watch_paths = $normalized; - $this->save(); - } - } + public function normalizeWatchPaths(): void + { + // Kept for BC; no-op to avoid unintended writes on read paths. + // Intentionally empty. + } @@ - $this->normalizeWatchPaths(); - - $watch_paths = collect(explode("\n", $this->watch_paths)); + $normalized = $this->parseWatchPaths($this->watch_paths); + $watch_paths = $normalized ? collect(explode("\n", $normalized)) : collect();
…ationDeploymentJob
Issues