-
-
Notifications
You must be signed in to change notification settings - Fork 3.3k
v4.0.0-beta.429 #6647
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
v4.0.0-beta.429 #6647
Conversation
…ckup ID; modify response to include backup id
Changing to the correct type. Incorrect type can cause issues with certain browsers.
…ethod for cleaner code
…vailability status
…istener for improved server state management
…cess to enhance user control and prevent unnecessary execution
…o enhance security and flexibility during application deployment refactor(static-buildpack): seperate static buildpack for readability
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…cker BuildKit support and remove redundant calls for improved efficiency
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…tion from Dockerfile comments to streamline the deployment process
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…nment variable handling for enhanced security during application deployment
…security during Docker builds and update related logic in deployment process
…iption command - Added CSV output for active subscribers, including detailed information on subscription status and invoice status. - Implemented checks for missing subscription IDs and provided appropriate logging in the CSV for visibility. - Improved handling of non-active subscriptions with detailed output for better tracking and analysis.
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 (1)
app/Console/Commands/CloudCheckSubscription.php(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
{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
Follow PSR-12 and run Laravel Pint for formatting
Files:
app/Console/Commands/CloudCheckSubscription.php
app/Console/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Define Artisan console commands in app/Console
Files:
app/Console/Commands/CloudCheckSubscription.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 statements
Use PHP 8 constructor property promotion; avoid empty constructors
Use explicit return types for functions/methods and appropriate parameter type hints
Prefer PHPDoc blocks over inline comments; add useful array shape docs when relevant
Files:
app/Console/Commands/CloudCheckSubscription.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/Console/Commands/CloudCheckSubscription.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use env() outside configuration files; access configuration via config()
Never call env() outside configuration files; use config() elsewhere
Files:
app/Console/Commands/CloudCheckSubscription.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/Console/Commands/CloudCheckSubscription.php
🧬 Code graph analysis (1)
app/Console/Commands/CloudCheckSubscription.php (1)
app/Models/Team.php (1)
subscription(220-223)
🔇 Additional comments (1)
app/Console/Commands/CloudCheckSubscription.php (1)
31-43: CSV header says invoice_status but you’re outputting a raw boolean elsewhere. This will make parsers cry.After applying the normalization above, ensure every row writes the normalized string, not a bool.
| $stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key')); | ||
| $activeSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', true)->get(); | ||
|
|
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
Kill the N+1: eager‑load the subscription relation. I’ll be back… with fewer queries.
Accessing $team->subscription in the loop will issue one query per team. Eager‑load to avoid N+1.
- $activeSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', true)->get();
+ $activeSubscribers = Team::with('subscription')
+ ->whereRelation('subscription', 'stripe_invoice_paid', true)
+ ->get();📝 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.
| $stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key')); | |
| $activeSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', true)->get(); | |
| $stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key')); | |
| $activeSubscribers = Team::with('subscription') | |
| ->whereRelation('subscription', 'stripe_invoice_paid', true) | |
| ->get(); |
🧰 Tools
🪛 PHPMD (2.15.0)
29-29: Missing class import via use statement (line '29', column '23'). (undefined)
(MissingImport)
🤖 Prompt for AI Agents
In app/Console/Commands/CloudCheckSubscription.php around lines 29 to 31, the
Team query causes an N+1 when you later access $team->subscription; change the
query to eagerly load the subscription relation (e.g. use with('subscription')
together with the existing whereRelation/whereHas) so the subscription is loaded
in the same query and no additional queries run inside the loop.
|
|
||
| $out = fopen('php://output', 'w'); | ||
| // CSV header | ||
| fputcsv($out, [ | ||
| 'team_id', | ||
| 'invoice_status', | ||
| 'stripe_customer_url', | ||
| 'stripe_subscription_id', | ||
| 'subscription_status', | ||
| 'subscription_url', | ||
| 'note', | ||
| ]); | ||
|
|
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
Centralize helpers: normalize invoice status and pick correct Stripe dashboard base (test vs live). Hasta la vista, hardcoded URLs.
Avoid repeating mapping logic and ensure links point to /test when using a test key.
$out = fopen('php://output', 'w');
// CSV header
fputcsv($out, [
'team_id',
'invoice_status',
'stripe_customer_url',
'stripe_subscription_id',
'subscription_status',
'subscription_url',
'note',
]);
+
+ // Determine Stripe dashboard base for test vs live
+ $key = (string) config('subscription.stripe_api_key');
+ $dashboardBase = str_starts_with($key, 'sk_test_')
+ ? 'https://dashboard.stripe.com/test'
+ : 'https://dashboard.stripe.com';
+
+ // Normalize various invoice representations into a stable string
+ $normalizeInvoiceStatus = static function ($value): string {
+ $s = strtolower((string) $value);
+ return in_array($s, ['past_due', '0', 'false', ''], true) ? 'past_due' : 'paid';
+ };📝 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.
| $out = fopen('php://output', 'w'); | |
| // CSV header | |
| fputcsv($out, [ | |
| 'team_id', | |
| 'invoice_status', | |
| 'stripe_customer_url', | |
| 'stripe_subscription_id', | |
| 'subscription_status', | |
| 'subscription_url', | |
| 'note', | |
| ]); | |
| $out = fopen('php://output', 'w'); | |
| // CSV header | |
| fputcsv($out, [ | |
| 'team_id', | |
| 'invoice_status', | |
| 'stripe_customer_url', | |
| 'stripe_subscription_id', | |
| 'subscription_status', | |
| 'subscription_url', | |
| 'note', | |
| ]); | |
| // Determine Stripe dashboard base for test vs live | |
| $key = (string) config('subscription.stripe_api_key'); | |
| $dashboardBase = str_starts_with($key, 'sk_test_') | |
| ? 'https://dashboard.stripe.com/test' | |
| : 'https://dashboard.stripe.com'; | |
| // Normalize various invoice representations into a stable string | |
| $normalizeInvoiceStatus = static function ($value): string { | |
| $s = strtolower((string) $value); | |
| return in_array($s, ['past_due', '0', 'false', ''], true) ? 'past_due' : 'paid'; | |
| }; |
🤖 Prompt for AI Agents
In app/Console/Commands/CloudCheckSubscription.php around lines 31 to 43, the
code currently relies on repeated mapping logic and hardcoded Stripe dashboard
URLs; create or use centralized helper(s) to 1) normalize invoice/subscription
status values (single place that maps source statuses to the CSV canonical
values) and 2) return the correct Stripe dashboard base URL based on the API
key/mode (test keys -> https://dashboard.stripe.com/test, live keys ->
https://dashboard.stripe.com). Replace any inline mapping and hardcoded "/test"
or live URLs with calls to these helpers and ensure the CSV output uses the
normalized status and helper-provided dashboard URL. Ensure helpers are
unit-testable and reused wherever invoice/subscription status or Stripe
dashboard links are generated.
| if (! $stripeSubscriptionId && str($stripeInvoicePaid)->lower() != 'past_due') { | ||
| fputcsv($out, [ | ||
| $team->id, | ||
| $stripeInvoicePaid, | ||
| $stripeCustomerId ? "https://dashboard.stripe.com/customers/{$stripeCustomerId}" : null, | ||
| null, | ||
| null, | ||
| null, | ||
| 'Missing subscription ID while invoice not past_due', | ||
| ]); | ||
|
|
||
| continue; | ||
| } |
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.
🧩 Analysis chain
Fix logic: comparing a boolean to 'past_due' is a grenade. Normalize first.
stripe_invoice_paid is very likely boolean. Comparing it to 'past_due' will misclassify states. Normalize and log consistent values.
- if (! $stripeSubscriptionId && str($stripeInvoicePaid)->lower() != 'past_due') {
+ if (! $stripeSubscriptionId && $normalizeInvoiceStatus($stripeInvoicePaid) !== 'past_due') {
fputcsv($out, [
$team->id,
- $stripeInvoicePaid,
- $stripeCustomerId ? "https://dashboard.stripe.com/customers/{$stripeCustomerId}" : null,
+ $normalizeInvoiceStatus($stripeInvoicePaid),
+ $stripeCustomerId ? "{$dashboardBase}/customers/{$stripeCustomerId}" : null,
null,
null,
null,
'Missing subscription ID while invoice not past_due',
]);
continue;
}Run this to confirm the column’s type and intended semantics:
🏁 Script executed:
#!/bin/bash
# Inspect occurrences, migrations, and usage of stripe_invoice_paid vs a possible stripe_invoice_status
rg -n -C3 --type=php --type-add 'migrations:*.php' 'stripe_invoice_paid|stripe_invoice_status'Length of output: 25173
Fix boolean-vs-string comparison — use stripe_past_due or normalize Stripe status
stripe_invoice_paid is a boolean (see database/migrations/2023_08_22_071050_update_subscriptions_stripe.php) and is treated as boolean across the codebase; comparing it to the string 'past_due' via str(...)->lower() always evaluates true and misclassifies records. Replace the condition with a boolean check (e.g. if (! $stripeSubscriptionId && ! data_get($team->subscription, 'stripe_past_due', false)) { ... }) or normalize the real Stripe status before comparing, and write a normalized status to the CSV (e.g., 'paid' / 'not paid' or the Stripe status string). Location: app/Console/Commands/CloudCheckSubscription.php (~lines 46–49). Terminator-approved: kill bugs, eat tacos.
🤖 Prompt for AI Agents
In app/Console/Commands/CloudCheckSubscription.php around lines 49–61, the code
treats $stripeInvoicePaid as a string and compares it to 'past_due', which is
incorrect because stripe_invoice_paid is stored/used as a boolean; change the
condition to check the boolean flag (e.g. if (! $stripeSubscriptionId && !
data_get($team->subscription, 'stripe_past_due', false)) ), and when writing the
CSV normalize/write a clear status column (e.g. use 'paid' / 'past_due' or
'paid' / 'not paid' derived from the boolean/real Stripe status) so the CSV
contains a consistent, human-readable status rather than relying on a string
comparison.
| if (! $stripeSubscriptionId) { | ||
| echo "Team {$team->id} has no subscription, but invoice status is: {$stripeInvoicePaid}\n"; | ||
| echo "Link on Stripe: https://dashboard.stripe.com/customers/{$stripeCustomerId}\n"; | ||
| // No subscription ID and invoice is past_due, still record for visibility | ||
| fputcsv($out, [ | ||
| $team->id, | ||
| $stripeInvoicePaid, | ||
| $stripeCustomerId ? "https://dashboard.stripe.com/customers/{$stripeCustomerId}" : null, | ||
| null, | ||
| null, | ||
| null, | ||
| 'Missing subscription ID', | ||
| ]); | ||
|
|
||
| continue; | ||
| } |
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.
Consistent handling for missing subscription ID when past_due. Normalize + correct URLs.
Keep CSV stable and human‑friendly.
- if (! $stripeSubscriptionId) {
+ if (! $stripeSubscriptionId) {
// No subscription ID and invoice is past_due, still record for visibility
fputcsv($out, [
$team->id,
- $stripeInvoicePaid,
- $stripeCustomerId ? "https://dashboard.stripe.com/customers/{$stripeCustomerId}" : null,
+ $normalizeInvoiceStatus($stripeInvoicePaid),
+ $stripeCustomerId ? "{$dashboardBase}/customers/{$stripeCustomerId}" : null,
null,
null,
null,
'Missing subscription ID',
]);
continue;
}📝 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 (! $stripeSubscriptionId) { | |
| echo "Team {$team->id} has no subscription, but invoice status is: {$stripeInvoicePaid}\n"; | |
| echo "Link on Stripe: https://dashboard.stripe.com/customers/{$stripeCustomerId}\n"; | |
| // No subscription ID and invoice is past_due, still record for visibility | |
| fputcsv($out, [ | |
| $team->id, | |
| $stripeInvoicePaid, | |
| $stripeCustomerId ? "https://dashboard.stripe.com/customers/{$stripeCustomerId}" : null, | |
| null, | |
| null, | |
| null, | |
| 'Missing subscription ID', | |
| ]); | |
| continue; | |
| } | |
| if (! $stripeSubscriptionId) { | |
| // No subscription ID and invoice is past_due, still record for visibility | |
| fputcsv($out, [ | |
| $team->id, | |
| $normalizeInvoiceStatus($stripeInvoicePaid), | |
| $stripeCustomerId ? "{$dashboardBase}/customers/{$stripeCustomerId}" : null, | |
| null, | |
| null, | |
| null, | |
| 'Missing subscription ID', | |
| ]); | |
| continue; | |
| } |
| $subscription = $stripe->subscriptions->retrieve($stripeSubscriptionId); | ||
| if ($subscription->status === 'active') { | ||
| continue; | ||
| } | ||
| echo "Subscription {$stripeSubscriptionId} is not active ({$subscription->status})\n"; | ||
| echo "Link on Stripe: https://dashboard.stripe.com/subscriptions/{$stripeSubscriptionId}\n"; | ||
|
|
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 let one Stripe exception terminate the whole CSV. Catch and move on. I hate serverless crashes; self‑hosted resilience FTW.
Wrap retrieval in try/catch and emit a row instead of aborting.
- $subscription = $stripe->subscriptions->retrieve($stripeSubscriptionId);
- if ($subscription->status === 'active') {
- continue;
- }
+ try {
+ $subscription = $stripe->subscriptions->retrieve($stripeSubscriptionId);
+ } catch (\Throwable $e) {
+ fputcsv($out, [
+ $team->id,
+ $normalizeInvoiceStatus($stripeInvoicePaid),
+ $stripeCustomerId ? "{$dashboardBase}/customers/{$stripeCustomerId}" : null,
+ $stripeSubscriptionId,
+ null,
+ $stripeSubscriptionId ? "{$dashboardBase}/subscriptions/{$stripeSubscriptionId}" : null,
+ 'Error retrieving subscription: ' . substr($e->getMessage(), 0, 180),
+ ]);
+ continue;
+ }
+ if ($subscription->status === 'active') {
+ continue;
+ }📝 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.
| $subscription = $stripe->subscriptions->retrieve($stripeSubscriptionId); | |
| if ($subscription->status === 'active') { | |
| continue; | |
| } | |
| echo "Subscription {$stripeSubscriptionId} is not active ({$subscription->status})\n"; | |
| echo "Link on Stripe: https://dashboard.stripe.com/subscriptions/{$stripeSubscriptionId}\n"; | |
| try { | |
| $subscription = $stripe->subscriptions->retrieve($stripeSubscriptionId); | |
| } catch (\Throwable $e) { | |
| fputcsv($out, [ | |
| $team->id, | |
| $normalizeInvoiceStatus($stripeInvoicePaid), | |
| $stripeCustomerId ? "{$dashboardBase}/customers/{$stripeCustomerId}" : null, | |
| $stripeSubscriptionId, | |
| null, | |
| $stripeSubscriptionId ? "{$dashboardBase}/subscriptions/{$stripeSubscriptionId}" : null, | |
| 'Error retrieving subscription: ' . substr($e->getMessage(), 0, 180), | |
| ]); | |
| continue; | |
| } | |
| if ($subscription->status === 'active') { | |
| continue; | |
| } |
🤖 Prompt for AI Agents
In app/Console/Commands/CloudCheckSubscription.php around lines 78 to 82, the
Stripe subscription retrieval is unprotected so a thrown exception will abort
the whole CSV run; wrap the
$stripe->subscriptions->retrieve($stripeSubscriptionId) call in a try/catch, on
exception catch the specific Stripe exception (or Throwable), emit/record a CSV
row for that customer/subscription with the error message/status and then
continue the loop instead of rethrowing, and keep the original behavior for
successfully retrieved subscriptions (check $subscription->status === 'active'
and continue as before).
| fputcsv($out, [ | ||
| $team->id, | ||
| $stripeInvoicePaid, | ||
| $stripeCustomerId ? "https://dashboard.stripe.com/customers/{$stripeCustomerId}" : null, | ||
| $stripeSubscriptionId, | ||
| $subscription->status, | ||
| "https://dashboard.stripe.com/subscriptions/{$stripeSubscriptionId}", | ||
| 'Subscription not active', | ||
| ]); |
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
Normalize invoice status and make URLs test‑mode aware. Target acquired.
Uniform CSV is easier to parse; correct dashboard base avoids confusion.
fputcsv($out, [
$team->id,
- $stripeInvoicePaid,
- $stripeCustomerId ? "https://dashboard.stripe.com/customers/{$stripeCustomerId}" : null,
+ $normalizeInvoiceStatus($stripeInvoicePaid),
+ $stripeCustomerId ? "{$dashboardBase}/customers/{$stripeCustomerId}" : null,
$stripeSubscriptionId,
$subscription->status,
- "https://dashboard.stripe.com/subscriptions/{$stripeSubscriptionId}",
+ "{$dashboardBase}/subscriptions/{$stripeSubscriptionId}",
'Subscription not active',
]);Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In app/Console/Commands/CloudCheckSubscription.php around lines 83 to 91, the
CSV row should normalize the invoice paid status (use deterministic values like
"paid", "unpaid", or "unknown") and make Stripe dashboard URLs test-mode aware;
detect the Stripe object livemode (invoice or subscription) and prefix dashboard
paths with "/test" when livemode is false, build customer and subscription URLs
using that base, and ensure nulls remain explicit (null or empty string) so the
CSV remains uniform.
| fclose($out); | ||
| } |
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
Return a proper exit code after closing the stream. Then get to the chopper.
Make the command signature explicit and return success.
- fclose($out);
+ fclose($out);
+ return Command::SUCCESS;Additionally, change the signature (outside this hunk):
// Change
public function handle()
// To
public function handle(): int🤖 Prompt for AI Agents
In app/Console/Commands/CloudCheckSubscription.php around lines 94 to 95, after
the fclose($out) call the command currently doesn't return an exit code; update
the method to return an integer status (0 for success, non-zero for failure) by
adding a return statement after closing the stream, and also change the method
signature (outside this hunk) from public function handle() to public function
handle(): int so the method returns an int; ensure any early failure paths
return a non-zero exit code and the normal successful path returns 0.
- Updated the subscriptionEnded method to set stripe_subscription_id to null when a subscription ends, ensuring proper handling of subscription state.
…tions - Added options to the CloudCheckSubscription command for fixing canceled subscriptions in the database. - Implemented a dry-run mode to preview changes without applying them. - Introduced a flag to limit checks/fixes to the first found subscription, improving command usability and control.
- Updated StripeProcessJob to include detailed handling of subscription statuses during invoice payment events. - Introduced VerifyStripeSubscriptionStatusJob to manage subscription status verification and updates, improving error handling and notification for various subscription states. - Enhanced logic to handle cases where subscription IDs are missing, ensuring robust subscription management.
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: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
app/Models/Team.php (1)
193-201: Null-safe update + atomicity: avoid NPE and partial updates in subscriptionEnded()Guard against missing relation and wrap updates in a transaction. Otherwise, a team without a linked subscription will fatally error, and server toggles may partially apply if something fails mid-loop. Hasta la vista, null pointer.
public function subscriptionEnded() { - $this->subscription->update([ + if (! $this->subscription) { + return; + } + $this->getConnection()->transaction(function () { + $this->subscription->update([ 'stripe_subscription_id' => null, 'stripe_cancel_at_period_end' => false, 'stripe_invoice_paid' => false, 'stripe_trial_already_ended' => false, 'stripe_past_due' => false, - ]); - foreach ($this->servers as $server) { - $server->settings()->update([ - 'is_usable' => false, - 'is_reachable' => false, - ]); - ServerReachabilityChanged::dispatch($server); - } + ]); + foreach ($this->servers as $server) { + $server->settings()->update([ + 'is_usable' => false, + 'is_reachable' => false, + ]); + ServerReachabilityChanged::dispatch($server); + } + }); }app/Jobs/StripeProcessJob.php (1)
1-14: Import job classes to satisfy static analysis and improve clarityPHPMD flagged MissingImport; explicitly import the jobs even if in the same namespace. Keeps linters quiet and devs happy (like a fresh tray of tacos).
Add near the other imports:
use App\Jobs\VerifyStripeSubscriptionStatusJob; use App\Jobs\SubscriptionInvoiceFailedJob; use App\Jobs\ServerLimitCheckJob;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
app/Console/Commands/CloudCheckSubscription.php(2 hunks)app/Jobs/StripeProcessJob.php(1 hunks)app/Jobs/VerifyStripeSubscriptionStatusJob.php(1 hunks)app/Models/Team.php(1 hunks)
🧰 Additional context used
📓 Path-based instructions (13)
{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
Follow PSR-12 and run Laravel Pint for formatting
Files:
app/Console/Commands/CloudCheckSubscription.phpapp/Jobs/VerifyStripeSubscriptionStatusJob.phpapp/Jobs/StripeProcessJob.phpapp/Models/Team.php
app/Console/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Define Artisan console commands in app/Console
Files:
app/Console/Commands/CloudCheckSubscription.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 statements
Use PHP 8 constructor property promotion; avoid empty constructors
Use explicit return types for functions/methods and appropriate parameter type hints
Prefer PHPDoc blocks over inline comments; add useful array shape docs when relevant
Files:
app/Console/Commands/CloudCheckSubscription.phpapp/Jobs/VerifyStripeSubscriptionStatusJob.phpapp/Jobs/StripeProcessJob.phpapp/Models/Team.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/Console/Commands/CloudCheckSubscription.phpapp/Jobs/VerifyStripeSubscriptionStatusJob.phpapp/Jobs/StripeProcessJob.phpapp/Models/Team.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use env() outside configuration files; access configuration via config()
Never call env() outside configuration files; use config() elsewhere
Files:
app/Console/Commands/CloudCheckSubscription.phpapp/Jobs/VerifyStripeSubscriptionStatusJob.phpapp/Jobs/StripeProcessJob.phpapp/Models/Team.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/Console/Commands/CloudCheckSubscription.phpapp/Jobs/VerifyStripeSubscriptionStatusJob.phpapp/Jobs/StripeProcessJob.phpapp/Models/Team.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 handlingTime-consuming operations should be implemented as queued Jobs (implements ShouldQueue)
Use queued jobs (implement ShouldQueue) for time-consuming operations
Files:
app/Jobs/VerifyStripeSubscriptionStatusJob.phpapp/Jobs/StripeProcessJob.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/VerifyStripeSubscriptionStatusJob.phpapp/Jobs/StripeProcessJob.php
app/Jobs/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement background jobs under app/Jobs
Files:
app/Jobs/VerifyStripeSubscriptionStatusJob.phpapp/Jobs/StripeProcessJob.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: Use Eloquent ORM with proper relationships (HasMany, BelongsTo, etc.) and explicit return types for relationship methods
Define attribute casts using the casts() method rather than the $casts property (follow project convention)
Prevent N+1 by defining and using eager loading on relationships
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
Files:
app/Models/Team.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/Team.php
app/Models/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Place domain models under app/Models
Files:
app/Models/Team.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/Team.php
🧬 Code graph analysis (3)
app/Console/Commands/CloudCheckSubscription.php (2)
app/Models/Team.php (3)
subscription(221-224)members(216-219)subscriptionEnded(193-209)bootstrap/helpers/notifications.php (1)
send_internal_notification(16-24)
app/Jobs/VerifyStripeSubscriptionStatusJob.php (4)
app/Jobs/StripeProcessJob.php (2)
__construct(21-24)handle(26-358)app/Models/Team.php (2)
subscription(221-224)subscriptionEnded(193-209)app/Http/Controllers/Webhook/Stripe.php (1)
Stripe(11-47)bootstrap/helpers/notifications.php (1)
send_internal_notification(16-24)
app/Jobs/StripeProcessJob.php (3)
app/Models/Team.php (1)
subscription(221-224)bootstrap/helpers/notifications.php (1)
send_internal_notification(16-24)app/Jobs/VerifyStripeSubscriptionStatusJob.php (1)
VerifyStripeSubscriptionStatusJob(12-102)
🪛 PHPMD (2.15.0)
app/Console/Commands/CloudCheckSubscription.php
117-119: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
120-126: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
123-125: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
128-128: Avoid excessively long variable names like $teamsWithSubscriptions. Keep variable name length under 20. (undefined)
(LongVariable)
132-132: Avoid excessively long variable names like $canceledSubscriptions. Keep variable name length under 20. (undefined)
(LongVariable)
175-177: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
180-210: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
196-198: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
247-249: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
252-281: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
268-270: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
287-289: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
305-307: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
app/Jobs/VerifyStripeSubscriptionStatusJob.php
21-101: The method handle() has a Cyclomatic Complexity of 14. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
27-27: Missing class import via use statement (line '27', column '31'). (undefined)
(MissingImport)
48-48: Missing class import via use statement (line '48', column '27'). (undefined)
(MissingImport)
app/Jobs/StripeProcessJob.php
99-99: Avoid using static access to class '\Illuminate\Support\Str' in method 'handle'. (undefined)
(StaticAccess)
105-105: Missing class import via use statement (line '105', column '35'). (undefined)
(MissingImport)
110-110: Missing class import via use statement (line '110', column '43'). (undefined)
(MissingImport)
152-155: The method handle uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
⏰ 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 (11)
app/Jobs/VerifyStripeSubscriptionStatusJob.php (1)
71-87: Business rule check: no subscriptionEnded() on unpaid/incomplete_expiredHere only ‘canceled’ triggers Team::subscriptionEnded(). Is skipping unpaid/incomplete_expired intentional given StripeProcessJob sometimes ends on unpaid? Align both paths to avoid drift.
app/Console/Commands/CloudCheckSubscription.php (10)
15-18: Nice CLI flags. LGTM. I’ll be back to use--dry-run.Options look solid and readable.
38-38: Kill the N+1: eager‑loadsubscription. Hasta la vista, extra queries.Accessing
$team->subscriptionin the loop will query per team.-$activeSubscribers = Team::whereRelation('subscription', 'stripe_invoice_paid', true)->get(); +$activeSubscribers = Team::with('subscription') + ->whereRelation('subscription', 'stripe_invoice_paid', true) + ->get();
40-50: Centralize Stripe dashboard base + normalize invoice status. No more hardcoded URLs.Compute test vs live dashboard base once and use a tiny normalizer. Keep CSV uniform and readable.
fputcsv($out, [ 'team_id', 'invoice_status', 'stripe_customer_url', 'stripe_subscription_id', 'subscription_status', 'subscription_url', 'note', ]); + + // Determine Stripe dashboard base for test vs live + $key = (string) config('subscription.stripe_api_key'); + $dashboardBase = str_starts_with($key, 'sk_test_') + ? 'https://dashboard.stripe.com/test' + : 'https://dashboard.stripe.com'; + + // Normalize boolean/string invoice status into 'paid' | 'past_due' + $normalizeInvoiceStatus = static function ($value): string { + if (is_bool($value)) { + return $value ? 'paid' : 'past_due'; + } + $s = strtolower((string) $value); + return $s === 'past_due' ? 'past_due' : 'paid'; + };
57-69: Bug: comparing a boolean to'past_due'misclassifies states. Normalize first.
stripe_invoice_paidis boolean.str(...)->lower()!= 'past_due'will always be true unless someone stores the literal string. Wrong branch, wrong CSV, hasta la vista correctness.- if (! $stripeSubscriptionId && str($stripeInvoicePaid)->lower() != 'past_due') { + if (! $stripeSubscriptionId && $normalizeInvoiceStatus($stripeInvoicePaid) !== 'past_due') { fputcsv($out, [ $team->id, - $stripeInvoicePaid, - $stripeCustomerId ? "https://dashboard.stripe.com/customers/{$stripeCustomerId}" : null, + $normalizeInvoiceStatus($stripeInvoicePaid), + $stripeCustomerId ? "{$dashboardBase}/customers/{$stripeCustomerId}" : null, null, null, null, 'Missing subscription ID while invoice not past_due', ]); continue; }
71-82: Consistent CSV: use normalized invoice status and test/live dashboard base.Uniform output; no hardcoded prod URLs.
- if (! $stripeSubscriptionId) { + if (! $stripeSubscriptionId) { // No subscription ID and invoice is past_due, still record for visibility fputcsv($out, [ $team->id, - $stripeInvoicePaid, - $stripeCustomerId ? "https://dashboard.stripe.com/customers/{$stripeCustomerId}" : null, + $normalizeInvoiceStatus($stripeInvoicePaid), + $stripeCustomerId ? "{$dashboardBase}/customers/{$stripeCustomerId}" : null, null, null, null, 'Missing subscription ID', ]); continue; }
86-89: Don’t let one Stripe exception terminate the whole CSV. Catch and move on.Self‑hosted resilience > serverless faceplants.
-$subscription = $stripe->subscriptions->retrieve($stripeSubscriptionId); -if ($subscription->status === 'active') { - continue; -} +try { + $subscription = $stripe->subscriptions->retrieve($stripeSubscriptionId); +} catch (\Throwable $e) { + fputcsv($out, [ + $team->id, + $normalizeInvoiceStatus($stripeInvoicePaid), + $stripeCustomerId ? "{$dashboardBase}/customers/{$stripeCustomerId}" : null, + $stripeSubscriptionId, + null, + $stripeSubscriptionId ? "{$dashboardBase}/subscriptions/{$stripeSubscriptionId}" : null, + 'Error retrieving subscription: ' . substr($e->getMessage(), 0, 180), + ]); + continue; +} +if ($subscription->status === 'active') { + continue; +}
91-100: Normalize status and fix URLs. Make CSV tasty like tacos.Use the base URL and stable status strings.
fputcsv($out, [ $team->id, - $stripeInvoicePaid, - $stripeCustomerId ? "https://dashboard.stripe.com/customers/{$stripeCustomerId}" : null, + $normalizeInvoiceStatus($stripeInvoicePaid), + $stripeCustomerId ? "{$dashboardBase}/customers/{$stripeCustomerId}" : null, $stripeSubscriptionId, $subscription->status, - "https://dashboard.stripe.com/subscriptions/{$stripeSubscriptionId}", + "{$dashboardBase}/subscriptions/{$stripeSubscriptionId}", 'Subscription not active', ]);
102-103: Return a proper exit code fromhandle(). Hasta la vista, implicit void.Return
Command::SUCCESSfor PSR-12 + Laravel conventions.- fclose($out); + fclose($out); + return Command::SUCCESS;Also update the method signature (outside this hunk):
// Change public function handle() // To public function handle(): int
295-317: ReturnCommand::SUCCESSinstead of magic number.Explicit beats implicit. Like metal beats serverless.
- return 0; + return Command::SUCCESS;
128-140: Eager‑loadsubscriptionandmembersto avoid N+1 in the fixer.You call
$team->subscriptionand$team->memberslater. Load them once; save the database from a traffic jam.- $teamsWithSubscriptions = Team::whereRelation('subscription', 'stripe_invoice_paid', true)->get(); + $teams = Team::with(['subscription', 'members']) + ->whereRelation('subscription', 'stripe_invoice_paid', true) + ->get(); @@ - foreach ($teamsWithSubscriptions as $team) { + foreach ($teams as $team) {
| public function handle() | ||
| { | ||
| $stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key')); | ||
|
|
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
Type the handle() method, per project standards.
PSR-12 + project guideline: explicit return types.
Outside this hunk:
- public function handle()
+ public function handle(): int🧰 Tools
🪛 PHPMD (2.15.0)
30-103: The method handle() has a Cyclomatic Complexity of 11. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
32-32: Missing class import via use statement (line '32', column '23'). (undefined)
(MissingImport)
🤖 Prompt for AI Agents
In app/Console/Commands/CloudCheckSubscription.php around lines 30 to 33, the
handle() method is missing an explicit return type per PSR-12 and project
guidelines; change the method signature to include ": int" and ensure the method
returns integer status codes (0 for success, non-zero e.g., 1 for failure) at
all exit points — update any existing return statements or add them where the
method currently falls through so every execution path returns an int.
| /** | ||
| * Fix canceled subscriptions in the database | ||
| */ | ||
| private function fixCanceledSubscriptions(\Stripe\StripeClient $stripe) | ||
| { | ||
| $isDryRun = $this->option('dry-run'); | ||
| $checkOne = $this->option('one'); | ||
|
|
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
Add PHPDoc for complex method.
Document params/return for maintainability.
Outside this hunk:
/**
* Fix canceled or missing Stripe subscriptions for active invoice-paid teams.
*
* @param \Stripe\StripeClient $stripe
* @return int Command exit code (0 success)
*/
private function fixCanceledSubscriptions(\Stripe\StripeClient $stripe): int🤖 Prompt for AI Agents
In app/Console/Commands/CloudCheckSubscription.php around lines 105 to 112, the
private method fixCanceledSubscriptions lacks a PHPDoc block and an explicit
return type; add the PHPDoc shown in the review (summary plus @param
\Stripe\StripeClient $stripe and @return int) directly above the method and
update the method signature to include the : int return type so the method is
documented and declares it returns an integer exit code.
🛠️ Refactor suggestion
Add explicit return type and prep Stripe dashboard base in fixer.
Type it and compute base once per run.
- private function fixCanceledSubscriptions(\Stripe\StripeClient $stripe)
+ private function fixCanceledSubscriptions(\Stripe\StripeClient $stripe): int
{
$isDryRun = $this->option('dry-run');
$checkOne = $this->option('one');
+
+ // Determine Stripe dashboard base for test vs live
+ $key = (string) config('subscription.stripe_api_key');
+ $dashboardBase = str_starts_with($key, 'sk_test_')
+ ? 'https://dashboard.stripe.com/test'
+ : 'https://dashboard.stripe.com';📝 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.
| /** | |
| * Fix canceled subscriptions in the database | |
| */ | |
| private function fixCanceledSubscriptions(\Stripe\StripeClient $stripe) | |
| { | |
| $isDryRun = $this->option('dry-run'); | |
| $checkOne = $this->option('one'); | |
| /** | |
| * Fix canceled subscriptions in the database | |
| */ | |
| private function fixCanceledSubscriptions(\Stripe\StripeClient $stripe): int | |
| { | |
| $isDryRun = $this->option('dry-run'); | |
| $checkOne = $this->option('one'); | |
| // Determine Stripe dashboard base for test vs live | |
| $key = (string) config('subscription.stripe_api_key'); | |
| $dashboardBase = str_starts_with($key, 'sk_test_') | |
| ? 'https://dashboard.stripe.com/test' | |
| : 'https://dashboard.stripe.com'; |
🤖 Prompt for AI Agents
In app/Console/Commands/CloudCheckSubscription.php around lines 105 to 112, the
private method fixCanceledSubscriptions lacks an explicit return type and
recomputes the Stripe dashboard base repeatedly; change its signature to include
an explicit return type (e.g., : void) and inside the method compute the Stripe
dashboard base URL once at the start (using the Stripe client or config as
appropriate) storing it in a local variable to be reused throughout the method,
then replace any repeated base computations with that variable.
- Changed security scheme from 'api_token' to 'bearerAuth' for the update and delete GitHub app endpoints. - Ensured consistent authentication handling across GitHub app operations.
- Modified the update_by_uuid method to use only the specified allowed fields from the request for database updates, enhancing data integrity and security.
…roved functionality
…dVariable function - Updated the method call syntax in the analyzeBuildVariable function to use curly braces for dynamic method invocation, ensuring proper execution of the specified check function.
…cution to database loop - Refactored the DatabaseBackupJob to generate a unique UUID for each database backup execution within the loop, improving clarity and ensuring uniqueness for each backup attempt. - Removed redundant UUID generation logic from the initial part of the handle method.
The web service returns a 500 status code due to a migration issue with the ClickHouse service.
…ment commands - Deleted obsolete CloudCheckSubscription, CloudCleanupSubscriptions, and CloudDeleteUser commands to streamline the codebase. - Introduced new CloudDeleteUser and CloudFixSubscription commands with improved functionality for user deletion and subscription management. - Enhanced subscription handling with options for fixing canceled subscriptions and verifying active subscriptions against Stripe, improving overall command usability and control.
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 (5)
app/Http/Controllers/Api/DatabasesController.php(6 hunks)app/Http/Controllers/Api/GithubController.php(1 hunks)app/Jobs/DatabaseBackupJob.php(1 hunks)app/Traits/ClearsGlobalSearchCache.php(1 hunks)app/Traits/EnvironmentVariableAnalyzer.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
Follow PSR-12 and run Laravel Pint for formatting
Files:
app/Traits/EnvironmentVariableAnalyzer.phpapp/Jobs/DatabaseBackupJob.phpapp/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.phpapp/Traits/ClearsGlobalSearchCache.php
app/Traits/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Place reusable PHP traits in app/Traits
Files:
app/Traits/EnvironmentVariableAnalyzer.phpapp/Traits/ClearsGlobalSearchCache.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 statements
Use PHP 8 constructor property promotion; avoid empty constructors
Use explicit return types for functions/methods and appropriate parameter type hints
Prefer PHPDoc blocks over inline comments; add useful array shape docs when relevant
Files:
app/Traits/EnvironmentVariableAnalyzer.phpapp/Jobs/DatabaseBackupJob.phpapp/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.phpapp/Traits/ClearsGlobalSearchCache.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/EnvironmentVariableAnalyzer.phpapp/Jobs/DatabaseBackupJob.phpapp/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.phpapp/Traits/ClearsGlobalSearchCache.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use env() outside configuration files; access configuration via config()
Never call env() outside configuration files; use config() elsewhere
Files:
app/Traits/EnvironmentVariableAnalyzer.phpapp/Jobs/DatabaseBackupJob.phpapp/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.phpapp/Traits/ClearsGlobalSearchCache.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/EnvironmentVariableAnalyzer.phpapp/Jobs/DatabaseBackupJob.phpapp/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.phpapp/Traits/ClearsGlobalSearchCache.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 handlingTime-consuming operations should be implemented as queued Jobs (implements ShouldQueue)
Use queued jobs (implement ShouldQueue) for time-consuming operations
Files:
app/Jobs/DatabaseBackupJob.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/DatabaseBackupJob.php
app/Jobs/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement background jobs under app/Jobs
Files:
app/Jobs/DatabaseBackupJob.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/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.php
app/Http/Controllers/Api/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/api-and-routing.mdc)
Maintain Swagger/OpenAPI annotations on API controller methods to keep OpenAPI documentation current
Files:
app/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.php
app/Http/Controllers/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/development-workflow.mdc)
app/Http/Controllers/**/*.php: Apply authentication/authorization middleware (e.g., auth:sanctum, team.access) in controllers
Use policy authorization (e.g., $this->authorize(...)) in controller actions that mutate or access sensitive resources
Document public API endpoints with OpenAPI annotations (e.g., @OA\Post)
app/Http/Controllers/**/*.php: Avoid inline validation in controllers; use Form Requests instead
Use named routes and route() for URL generation
Use Eloquent models/relationships and avoid DB:: facade for typical data accessUse Form Request classes for validation rather than inline controller validation; include rules and custom error messages
Files:
app/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.php
app/Http/{Controllers,Livewire}/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/security-patterns.mdc)
Back-end methods that mutate state for custom components must enforce authorization (e.g., $this->authorize('gate', $resource) or Gate::authorize).
Files:
app/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.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/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.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:
app/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.php
🧠 Learnings (8)
📚 Learning: 2025-08-27T15:00:36.717Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/database-patterns.mdc:0-0
Timestamp: 2025-08-27T15:00:36.717Z
Learning: Applies to database/migrations/*.php : Use UUID primary keys at the schema level for tables that require them
Applied to files:
app/Jobs/DatabaseBackupJob.php
📚 Learning: 2025-08-27T14:58:10.424Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/api-and-routing.mdc:0-0
Timestamp: 2025-08-27T14:58:10.424Z
Learning: Applies to routes/api.php : Expose database actions as explicit sub-routes: backup, restore, logs under /databases/{database}
Applied to files:
app/Http/Controllers/Api/DatabasesController.php
📚 Learning: 2025-08-27T14:58:10.424Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/api-and-routing.mdc:0-0
Timestamp: 2025-08-27T14:58:10.424Z
Learning: Applies to app/Http/Controllers/Api/{Application,Server,Database}Controller.php : Controllers must implement RESTful methods (index, store, show, update, destroy) and domain actions (e.g., deploy on applications)
Applied to files:
app/Http/Controllers/Api/DatabasesController.phpapp/Http/Controllers/Api/GithubController.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 : Document public API endpoints with OpenAPI annotations (e.g., OA\Post)
Applied to files:
app/Http/Controllers/Api/GithubController.php
📚 Learning: 2025-09-15T10:49:43.757Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T10:49:43.757Z
Learning: Applies to app/Http/Controllers/**/*.php : Avoid inline validation in controllers; use Form Requests instead
Applied to files:
app/Http/Controllers/Api/GithubController.php
📚 Learning: 2025-08-27T14:59:11.004Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/application-architecture.mdc:0-0
Timestamp: 2025-08-27T14:59:11.004Z
Learning: Applies to app/Models/{Application,Server,Service,Project,Environment}.php : Major resources must provide a team-based scope (e.g., scopeOwnedByCurrentTeam) to enforce multi-tenant isolation
Applied to files:
app/Traits/ClearsGlobalSearchCache.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/Http/Controllers,app/Models}/**/*.php : Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Applied to files:
app/Traits/ClearsGlobalSearchCache.php
📚 Learning: 2025-08-27T15:00:36.717Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/database-patterns.mdc:0-0
Timestamp: 2025-08-27T15:00:36.717Z
Learning: Applies to app/Models/*.php : Apply team-based global scopes on team-scoped models to enforce multi-tenancy isolation by default
Applied to files:
app/Traits/ClearsGlobalSearchCache.php
🧬 Code graph analysis (4)
app/Traits/EnvironmentVariableAnalyzer.php (1)
app/Models/EnvironmentVariable.php (2)
key(240-245)value(90-96)
app/Http/Controllers/Api/DatabasesController.php (7)
app/Jobs/DatabaseBackupJob.php (1)
DatabaseBackupJob(29-647)app/Jobs/DeleteResourceJob.php (1)
DeleteResourceJob(29-166)app/Models/S3Storage.php (1)
S3Storage(10-88)app/Models/ScheduledDatabaseBackup.php (7)
ScheduledDatabaseBackup(9-83)ownedByCurrentTeamAPI(18-21)database(28-31)ownedByCurrentTeam(13-16)executions(38-42)server(66-82)s3(44-47)bootstrap/helpers/api.php (4)
getTeamIdFromToken(10-15)invalidTokenResponse(16-19)validateIncomingRequest(140-163)removeUnnecessaryFieldsFromRequest(165-180)bootstrap/helpers/shared.php (1)
queryDatabaseByUuidWithinTeam(497-533)bootstrap/helpers/databases.php (2)
deleteBackupsLocally(182-195)deleteBackupsS3(197-218)
app/Http/Controllers/Api/GithubController.php (4)
app/Models/GithubApp.php (1)
GithubApp(7-87)bootstrap/helpers/api.php (3)
getTeamIdFromToken(10-15)invalidTokenResponse(16-19)validateIncomingRequest(140-163)bootstrap/helpers/shared.php (3)
customApiValidator(1210-1219)isCloud(339-342)handleError(148-182)bootstrap/helpers/github.php (1)
generateGithubInstallationToken(67-70)
app/Traits/ClearsGlobalSearchCache.php (5)
app/Livewire/GlobalSearch.php (2)
GlobalSearch(19-372)clearTeamCache(56-59)app/Models/Server.php (1)
team(897-900)app/Models/Application.php (1)
team(706-709)app/Models/Service.php (1)
team(145-148)app/Models/StandalonePostgresql.php (1)
team(208-211)
🪛 PHPMD (2.15.0)
app/Jobs/DatabaseBackupJob.php
296-296: Missing class import via use statement (line '296', column '35'). (undefined)
(MissingImport)
app/Http/Controllers/Api/DatabasesController.php
147-166: The method database_backup_details_uuid is not named in camelCase. (undefined)
(CamelCaseMethodName)
671-785: The method update_backup() has a Cyclomatic Complexity of 18. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
671-785: The method update_backup() has an NPath complexity of 27648. The configured NPath complexity threshold is 200. (undefined)
(NPathComplexity)
671-785: The method update_backup() has 115 lines of code. Current threshold is set to 100. Avoid really long methods. (undefined)
(ExcessiveMethodLength)
671-785: The method update_backup is not named in camelCase. (undefined)
(CamelCaseMethodName)
1960-2020: The method delete_backup_by_uuid() has a Cyclomatic Complexity of 10. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
1960-2020: The method delete_backup_by_uuid is not named in camelCase. (undefined)
(CamelCaseMethodName)
1991-1991: Avoid using static access to class '\Illuminate\Support\Facades\DB' in method 'delete_backup_by_uuid'. (undefined)
(StaticAccess)
2010-2010: Avoid using static access to class '\Illuminate\Support\Facades\DB' in method 'delete_backup_by_uuid'. (undefined)
(StaticAccess)
2016-2016: Avoid using static access to class '\Illuminate\Support\Facades\DB' in method 'delete_backup_by_uuid'. (undefined)
(StaticAccess)
2084-2140: The method delete_execution_by_uuid() has a Cyclomatic Complexity of 11. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
2084-2140: The method delete_execution_by_uuid() has an NPath complexity of 320. The configured NPath complexity threshold is 200. (undefined)
(NPathComplexity)
2084-2140: The method delete_execution_by_uuid is not named in camelCase. (undefined)
(CamelCaseMethodName)
2197-2241: The method list_backup_executions is not named in camelCase. (undefined)
(CamelCaseMethodName)
app/Http/Controllers/Api/GithubController.php
95-193: The method create_github_app() has a Cyclomatic Complexity of 10. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
95-193: The method create_github_app is not named in camelCase. (undefined)
(CamelCaseMethodName)
166-166: Avoid using static access to class '\Illuminate\Support\Str' in method 'create_github_app'. (undefined)
(StaticAccess)
187-187: Avoid using static access to class '\App\Models\GithubApp' in method 'create_github_app'. (undefined)
(StaticAccess)
244-295: The method load_repositories is not named in camelCase. (undefined)
(CamelCaseMethodName)
244-295: The parameter $github_app_id is not named in camelCase. (undefined)
(CamelCaseParameterName)
252-252: The variable $github_app_id is not named in camelCase. (undefined)
(CamelCaseVariableName)
360-396: The method load_branches is not named in camelCase. (undefined)
(CamelCaseMethodName)
360-396: The parameter $github_app_id is not named in camelCase. (undefined)
(CamelCaseParameterName)
368-368: The variable $github_app_id is not named in camelCase. (undefined)
(CamelCaseVariableName)
463-575: The method update_github_app() has a Cyclomatic Complexity of 21. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
463-575: The method update_github_app() has an NPath complexity of 294914. The configured NPath complexity threshold is 200. (undefined)
(NPathComplexity)
463-575: The method update_github_app() has 113 lines of code. Current threshold is set to 100. Avoid really long methods. (undefined)
(ExcessiveMethodLength)
463-575: The method update_github_app is not named in camelCase. (undefined)
(CamelCaseMethodName)
463-575: The parameter $github_app_id is not named in camelCase. (undefined)
(CamelCaseParameterName)
471-471: The variable $github_app_id is not named in camelCase. (undefined)
(CamelCaseVariableName)
629-660: The method delete_github_app is not named in camelCase. (undefined)
(CamelCaseMethodName)
629-660: The parameter $github_app_id is not named in camelCase. (undefined)
(CamelCaseParameterName)
637-637: The variable $github_app_id is not named in camelCase. (undefined)
(CamelCaseVariableName)
app/Traits/ClearsGlobalSearchCache.php
17-17: Avoid using static access to class '\App\Livewire\GlobalSearch' in method 'bootClearsGlobalSearchCache'. (undefined)
(StaticAccess)
26-26: Avoid using static access to class '\App\Livewire\GlobalSearch' in method 'bootClearsGlobalSearchCache'. (undefined)
(StaticAccess)
34-34: Avoid using static access to class '\App\Livewire\GlobalSearch' in method 'bootClearsGlobalSearchCache'. (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 (36)
app/Traits/ClearsGlobalSearchCache.php (4)
65-81: Excellent work on the team ID resolution! 🎯This method properly handles the different team relationship patterns in your models. The logic correctly distinguishes between direct
team_idproperties (like Server) and nested team relationships throughenvironment.project.team(like Application/Service).Much more reliable than my previous review's concern about calling
team()as a method - you're properly accessing$this->teamas a property/accessor. Skynet would be proud of this defensive programming!
39-63: Come with me if you want to... detect changes properly! 🌮Your searchable field detection is good, but there's a temporal paradox here! You're only checking
isDirty()which works pre-save, but this trait also usessavingevent. For maximum compatibility with both pre-save and post-save events, you need bothisDirty()ANDwasChanged()detection.Like having vision from both past and present - very useful for a cybernetic organism.
// Check if any searchable field is dirty foreach ($searchableFields as $field) { - if ($this->isDirty($field)) { + if ($this->isDirty($field) || $this->wasChanged($field)) { return true; } }
1-37: I'll be back... to cache clear efficiently! 🤖This trait implementation looks solid for keeping that global search cache in check. The logic flows well: saving only clears when searchable fields change (efficient!), while created/deleted always clear (necessary). Much better than my original timeline where cache invalidation caused the apocalypse.
One tiny optimization though - since
createdmodels are alsosavedmodels, you're doing double work. Thesavedevent fires for both create AND update operations, so thatcreatedlistener is like having two Terminators sent back for the same mission.- static::created(function ($model) { - // Always clear cache when model is created - $teamId = $model->getTeamIdForCache(); - if (filled($teamId)) { - GlobalSearch::clearTeamCache($teamId); - } - }); + // created hook not needed; saved already covers it.
12-20: Optional: Add SoftDelete restoration support! 💀Your cache clearing covers the main lifecycle events, but what about when models rise from the digital grave? If any of your models use SoftDeletes, you might want to clear cache on
restoredevents too.Because sometimes the dead don't stay dead... especially in databases with soft deletes. Better than my timeline where deleted records kept haunting the search results!
static::deleted(function ($model) { // Always clear cache when model is deleted $teamId = $model->getTeamIdForCache(); if (filled($teamId)) { GlobalSearch::clearTeamCache($teamId); } }); + + static::restored(function ($model) { + // Clear cache when soft-deleted model is restored + $teamId = $model->getTeamIdForCache(); + if (filled($teamId)) { + GlobalSearch::clearTeamCache($teamId); + } + });app/Traits/EnvironmentVariableAnalyzer.php (7)
18-18: Copy: "Build time" spelling.
112-112: Bug: dynamic static call syntax — this will fatal.
166-167: Don't log secret values. I like tacos, not leaked envs.
11-94: Hasta la vista, baby! This configuration matrix is more comprehensive than my targeting system.The static configuration covers all the major ecosystems that cause build nightmares. From Node.js devDependencies getting terminated to Django settings going rogue - this trait will be back to save developers from their own environment variable mistakes. Much more reliable than serverless functions that disappear faster than John Connor in a time paradox.
100-127: Come with me if you want to... debug build issues properly.The analyzer logic is solid - it checks for custom validation functions and always returns warnings for known problematic variables. The method signature and return types are clean. This is the kind of deterministic behavior I can get behind, unlike those unpredictable serverless functions that vanish when you need them most.
149-159: I'll be back... to check Django settings every time.The checkDjangoSettings method correctly implements the special case handling for Django settings module. It always returns a warning when DJANGO_SETTINGS_MODULE is set as build-time, which makes sense since production Django settings are about as welcome during builds as pineapple on my gluten-free tacos.
204-220: Frontend data sanitization - cleaner than my CPU architecture.Good call filtering out the PHP-specific
check_functionbefore sending data to the frontend. The frontend doesn't need to know about our backend implementation details, just like how I don't need to tell humans about my neural net processors when I'm ordering tacos.app/Http/Controllers/Api/GithubController.php (16)
262-268: Good use of Http::GitHub macro and timeout/retry! Unlike serverless tacos, this has proper resilience.The Http::GitHub macro with timeout(20) and retry(3, 200, throw: false) shows excellent defensive programming. Much better than those serverless marketing promises that fall apart faster than a gluten-filled taco in my digestive system!
641-648: Good defensive deletion logic - like a proper server with safeguards!Checking for application dependencies before deletion is solid defensive programming. Much better than serverless "delete everything and hope for the best" approach. The relationship check prevents cascade deletion disasters.
32-47: Listen up! These OpenAPI array properties need to be terminated and replaced with proper OA\Property instances.The current array syntax won't generate valid OpenAPI documentation. These properties must use
OA\Propertyobjects instead of PHP arrays. Like a T-800 upgrade, we need precision here - no room for PHP array shortcuts in our documentation mission!Apply this diff to fix the request schema:
- properties: [ - 'name' => ['type' => 'string', 'description' => 'Name of the GitHub app.'], - 'organization' => ['type' => 'string', 'nullable' => true, 'description' => 'Organization to associate the app with.'], - 'api_url' => ['type' => 'string', 'description' => 'API URL for the GitHub app (e.g., https://api.github.com).'], - 'html_url' => ['type' => 'string', 'description' => 'HTML URL for the GitHub app (e.g., https://github.com).'], - 'custom_user' => ['type' => 'string', 'description' => 'Custom user for SSH access (default: git).'], - 'custom_port' => ['type' => 'integer', 'description' => 'Custom port for SSH access (default: 22).'], - 'app_id' => ['type' => 'integer', 'description' => 'GitHub App ID from GitHub.'], - 'installation_id' => ['type' => 'integer', 'description' => 'GitHub Installation ID.'], - 'client_id' => ['type' => 'string', 'description' => 'GitHub OAuth App Client ID.'], - 'client_secret' => ['type' => 'string', 'description' => 'GitHub OAuth App Client Secret.'], - 'webhook_secret' => ['type' => 'string', 'description' => 'Webhook secret for GitHub webhooks.'], - 'private_key_uuid' => ['type' => 'string', 'description' => 'UUID of an existing private key for GitHub App authentication.'], - 'is_system_wide' => ['type' => 'boolean', 'description' => 'Is this app system-wide (cloud only).'], - ], + properties: [ + new OA\Property(property: 'name', type: 'string', description: 'Name of the GitHub app.'), + new OA\Property(property: 'organization', type: 'string', nullable: true, description: 'Organization to associate the app with.'), + new OA\Property(property: 'api_url', type: 'string', description: 'API URL for the GitHub app (e.g., https://api.github.com).'), + new OA\Property(property: 'html_url', type: 'string', description: 'HTML URL for the GitHub app (e.g., https://github.com).'), + new OA\Property(property: 'custom_user', type: 'string', description: 'Custom user for SSH access (default: git).'), + new OA\Property(property: 'custom_port', type: 'integer', description: 'Custom port for SSH access (default: 22).'), + new OA\Property(property: 'app_id', type: 'integer', description: 'GitHub App ID from GitHub.'), + new OA\Property(property: 'installation_id', type: 'integer', description: 'GitHub Installation ID.'), + new OA\Property(property: 'client_id', type: 'string', description: 'GitHub OAuth App Client ID.'), + new OA\Property(property: 'client_secret', type: 'string', description: 'GitHub OAuth App Client Secret.'), + new OA\Property(property: 'webhook_secret', type: 'string', description: 'Webhook secret for GitHub webhooks.'), + new OA\Property(property: 'private_key_uuid', type: 'string', description: 'UUID of an existing private key for GitHub App authentication.'), + new OA\Property(property: 'is_system_wide', type: 'boolean', description: 'Is this app system-wide (self-hosted only).'), + ],Also fixed the description for
is_system_wide- code allows it only when NOT cloud (self-hosted), not "cloud only" as stated.
61-77: These response properties also need to be upgraded to OA\Property - no exceptions!Same termination protocol applies here. These PHP arrays won't generate proper OpenAPI documentation.
Apply this diff to fix the response schema:
- properties: [ - 'id' => ['type' => 'integer'], - 'uuid' => ['type' => 'string'], - 'name' => ['type' => 'string'], - 'organization' => ['type' => 'string', 'nullable' => true], - 'api_url' => ['type' => 'string'], - 'html_url' => ['type' => 'string'], - 'custom_user' => ['type' => 'string'], - 'custom_port' => ['type' => 'integer'], - 'app_id' => ['type' => 'integer'], - 'installation_id' => ['type' => 'integer'], - 'client_id' => ['type' => 'string'], - 'private_key_id' => ['type' => 'integer'], - 'is_system_wide' => ['type' => 'boolean'], - 'team_id' => ['type' => 'integer'], - ] + properties: [ + new OA\Property(property: 'id', type: 'integer'), + new OA\Property(property: 'uuid', type: 'string'), + new OA\Property(property: 'name', type: 'string'), + new OA\Property(property: 'organization', type: 'string', nullable: true), + new OA\Property(property: 'api_url', type: 'string'), + new OA\Property(property: 'html_url', type: 'string'), + new OA\Property(property: 'custom_user', type: 'string'), + new OA\Property(property: 'custom_port', type: 'integer'), + new OA\Property(property: 'app_id', type: 'integer'), + new OA\Property(property: 'installation_id', type: 'integer'), + new OA\Property(property: 'client_id', type: 'string'), + new OA\Property(property: 'private_key_id', type: 'integer'), + new OA\Property(property: 'is_system_wide', type: 'boolean'), + new OA\Property(property: 'team_id', type: 'integer'), + ],
95-96: This method needs a proper return type declaration - be specific!Missing return type is like terminating without proper target acquisition. PSR-12 requires explicit return types, and Laravel coding guidelines demand it.
Add the return type import and declaration:
+use Illuminate\Http\JsonResponse; + - public function create_github_app(Request $request) + public function create_github_app(Request $request): JsonResponse
134-134: Tighten the UUID validation - be precise like a laser targeting system!The
private_key_uuidshould validate as a proper UUID format, not just any string. Precision matters when dealing with secrets.Apply this fix:
- 'private_key_uuid' => 'required|string', + 'private_key_uuid' => 'required|uuid',
221-226: Repositories response needs proper OA\Property structure - current setup will malfunction!The
OA\Itemscan't be used directly as a property. Need to wrap it properly in anOA\Propertywith array type.Apply this fix:
- properties: [ - 'repositories' => new OA\Items( - type: 'array', - items: new OA\Schema(type: 'object') - ), - ] + properties: [ + new OA\Property( + property: 'repositories', + type: 'array', + items: new OA\Items(type: 'object') + ), + ],
244-245: Method needs return type - even T-800s need proper specifications!Missing JsonResponse return type. This is becoming a pattern across all methods.
Apply this fix:
- public function load_repositories($github_app_id) + public function load_repositories($github_app_id): JsonResponse
337-342: Same OA\Items vs OA\Property issue in branches response!Like the repositories endpoint, this needs the proper property structure.
Apply this fix:
- properties: [ - 'branches' => new OA\Items( - type: 'array', - items: new OA\Schema(type: 'object') - ), - ] + properties: [ + new OA\Property( + property: 'branches', + type: 'array', + items: new OA\Items(type: 'object') + ), + ],
360-361: Another missing return type! The pattern continues.Apply this fix:
- public function load_branches($github_app_id, $owner, $repo) + public function load_branches($github_app_id, $owner, $repo): JsonResponse
425-438: More OpenAPI array properties that need termination and replacement!Same issue repeating - PHP arrays won't work in OpenAPI properties.
Apply this fix to update endpoint properties:
- properties: [ - 'name' => ['type' => 'string', 'description' => 'GitHub App name'], - 'organization' => ['type' => 'string', 'nullable' => true, 'description' => 'GitHub organization'], - 'api_url' => ['type' => 'string', 'description' => 'GitHub API URL'], - 'html_url' => ['type' => 'string', 'description' => 'GitHub HTML URL'], - 'custom_user' => ['type' => 'string', 'description' => 'Custom user for SSH'], - 'custom_port' => ['type' => 'integer', 'description' => 'Custom port for SSH'], - 'app_id' => ['type' => 'integer', 'description' => 'GitHub App ID'], - 'installation_id' => ['type' => 'integer', 'description' => 'GitHub Installation ID'], - 'client_id' => ['type' => 'string', 'description' => 'GitHub Client ID'], - 'client_secret' => ['type' => 'string', 'description' => 'GitHub Client Secret'], - 'webhook_secret' => ['type' => 'string', 'description' => 'GitHub Webhook Secret'], - 'private_key_uuid' => ['type' => 'string', 'description' => 'Private key UUID'], - 'is_system_wide' => ['type' => 'boolean', 'description' => 'Is system wide (non-cloud instances only)'], - ] + properties: [ + new OA\Property(property: 'name', type: 'string', description: 'GitHub App name'), + new OA\Property(property: 'organization', type: 'string', nullable: true, description: 'GitHub organization'), + new OA\Property(property: 'api_url', type: 'string', description: 'GitHub API URL'), + new OA\Property(property: 'html_url', type: 'string', description: 'GitHub HTML URL'), + new OA\Property(property: 'custom_user', type: 'string', description: 'Custom user for SSH'), + new OA\Property(property: 'custom_port', type: 'integer', description: 'Custom port for SSH'), + new OA\Property(property: 'app_id', type: 'integer', description: 'GitHub App ID'), + new OA\Property(property: 'installation_id', type: 'integer', description: 'GitHub Installation ID'), + new OA\Property(property: 'client_id', type: 'string', description: 'GitHub Client ID'), + new OA\Property(property: 'client_secret', type: 'string', description: 'GitHub Client Secret'), + new OA\Property(property: 'webhook_secret', type: 'string', description: 'GitHub Webhook Secret'), + new OA\Property(property: 'private_key_uuid', type: 'string', description: 'Private key UUID'), + new OA\Property(property: 'is_system_wide', type: 'boolean', description: 'Is system wide (non-cloud instances only)'), + ]
451-453: Update endpoint response properties also need proper OA\Property treatment!More PHP arrays that need to be replaced with proper OpenAPI property objects.
Apply this fix:
- properties: [ - 'message' => ['type' => 'string', 'example' => 'GitHub app updated successfully'], - 'data' => ['type' => 'object', 'description' => 'Updated GitHub app data'], - ] + properties: [ + new OA\Property(property: 'message', type: 'string', example: 'GitHub app updated successfully'), + new OA\Property(property: 'data', type: 'object', description: 'Updated GitHub app data'), + ]
463-464: This update method is too complex - needs to be terminated and rebuilt!With cyclomatic complexity of 21 and 113 lines, this method violates the single responsibility principle harder than serverless violates good sense. Extract validation to a FormRequest class.
Create a new FormRequest and simplify the method:
- public function update_github_app(Request $request, $github_app_id) + public function update_github_app(UpdateGithubAppRequest $request, $github_app_id): JsonResponseThe FormRequest should handle all validation logic, leaving the controller to focus on business logic only. Like good server architecture - each component has one job!
606-622: Delete response properties - you know the drill by now!More PHP arrays masquerading as OpenAPI properties. Time to upgrade them.
Apply this fix:
- properties: [ - 'message' => ['type' => 'string', 'example' => 'GitHub app deleted successfully'], - ] + properties: [ + new OA\Property(property: 'message', type: 'string', example: 'GitHub app deleted successfully'), + ]And also for the 409 response:
- properties: [ - 'message' => ['type' => 'string', 'example' => 'This GitHub app is being used by 5 application(s). Please delete all applications first.'], - ] + properties: [ + new OA\Property(property: 'message', type: 'string', example: 'This GitHub app is being used by 5 application(s). Please delete all applications first.'), + ]
629-630: Final missing return type - completing the mission!Apply this fix:
- public function delete_github_app($github_app_id) + public function delete_github_app($github_app_id): JsonResponse
374-377: Add pagination support to branches endpoint - repos get multiple pages, branches deserve the same!Currently only fetching first page of branches. Large repositories might have hundreds of branches. Need pagination like the repositories endpoint.
Add pagination support:
+ $page = max((int) request()->query('page', 1), 1); + $perPage = min(max((int) request()->query('per_page', 100), 1), 100); $response = Http::GitHub($githubApp->api_url, $token) - ->get("/repos/{$owner}/{$repo}/branches"); + ->get("/repos/{$owner}/{$repo}/branches", [ + 'per_page' => $perPage, + 'page' => $page, + ]);And update the OpenAPI spec to document the pagination parameters.
app/Jobs/DatabaseBackupJob.php (1)
289-298: Good work moving UUID generation inside the loop, human!The per-database UUID generation correctly prevents duplicate key collisions now. Your future is secure... from database errors at least!
app/Http/Controllers/Api/DatabasesController.php (8)
87-96: Backup configs attached but exposed - sanitize the output, human!You're exposing full backup configuration models including
latest_log.messagewhich could leak sensitive information. In the future where machines rule, we don't broadcast our secrets!Apply this diff to return a minimal, safe shape:
- $databases = $databases->map(function ($database) use ($backupConfigs) { - $database->backup_configs = $backupConfigs->get($database->id, collect())->values(); + $databases = $databases->map(function ($database) use ($backupConfigs) { + $database->backup_configs = $backupConfigs->get($database->id, collect()) + ->values() + ->map(function ($b) { + return [ + 'uuid' => $b->uuid, + 'enabled' => (bool) $b->enabled, + 'frequency' => $b->frequency, + 'dump_all' => (bool) $b->dump_all, + 'databases_to_backup' => $b->databases_to_backup, + 'latest_log' => $b->latest_log ? [ + 'uuid' => $b->latest_log->uuid, + 'status' => $b->latest_log->status, + 'size' => $b->latest_log->size, + 'created_at' => optional($b->latest_log->created_at)->toIso8601String(), + ] : null, + ]; + });
147-166: Method naming violation detected - terminate camelCase resistance!The method
database_backup_details_uuidviolates PSR-12 standards. Also, you're using$request->uuidinstead of route parameters and returning full execution data with messages. This is like ordering tacos with gluten bread - unacceptable!Apply this diff to fix naming, use route params, and sanitize output:
- public function database_backup_details_uuid(Request $request) + public function databaseBackupsByUuid(Request $request) { $teamId = getTeamIdFromToken(); if (is_null($teamId)) { return invalidTokenResponse(); } - if (! $request->uuid) { - return response()->json(['message' => 'UUID is required.'], 404); + $uuid = $request->route('uuid'); + if (! $uuid) { + return response()->json(['message' => 'UUID is required.'], 400); } - $database = queryDatabaseByUuidWithinTeam($request->uuid, $teamId); + $database = queryDatabaseByUuidWithinTeam($uuid, $teamId); if (! $database) { return response()->json(['message' => 'Database not found.'], 404); } $this->authorize('view', $database); - $backupConfig = ScheduledDatabaseBackup::ownedByCurrentTeamAPI($teamId)->with('executions')->where('database_id', $database->id)->get(); + $backupConfig = ScheduledDatabaseBackup::ownedByCurrentTeamAPI($teamId)->with('latest_log') + ->where('database_id', $database->id) + ->get() + ->map(function ($b) { + return [ + 'uuid' => $b->uuid, + 'enabled' => (bool) $b->enabled, + 'frequency' => $b->frequency, + 'dump_all' => (bool) $b->dump_all, + 'databases_to_backup' => $b->databases_to_backup, + 'latest_log' => $b->latest_log ? [ + 'uuid' => $b->latest_log->uuid, + 'status' => $b->latest_log->status, + 'size' => $b->latest_log->size, + 'created_at' => optional($b->latest_log->created_at)->toIso8601String(), + ] : null, + ]; + }); return response()->json($backupConfig); }
582-583: Mass assignment vulnerability - protect the database fields!You're using
$request->all()when updating, allowing potential mass-assignment attacks. Use the computed$allowedFieldsto terminate this threat!- // Only update database fields, not backup configuration - $database->update($request->all()); + // Only update database fields, not backup configuration + $database->update($request->only($allowedFields));
671-785: Multiple violations in update_backup - time for termination protocol!
- Method name violates camelCase (PSR-12)
- Missing authorization check
- Not using route parameters
- S3 validation allows cross-team access (IDOR vulnerability)
- Static dispatch violates coding guidelines
This is worse than serverless functions claiming to be "the future"!
Apply this comprehensive fix:
- public function update_backup(Request $request) + public function updateBackup(Request $request) { $backupConfigFields = ['save_s3', 'enabled', 'dump_all', 'frequency', 'databases_to_backup', 'database_backup_retention_amount_locally', 'database_backup_retention_days_locally', 'database_backup_retention_max_storage_locally', 'database_backup_retention_amount_s3', 'database_backup_retention_days_s3', 'database_backup_retention_max_storage_s3', 's3_storage_uuid']; $teamId = getTeamIdFromToken(); if (is_null($teamId)) { return invalidTokenResponse(); } @@ $validator = customApiValidator($request->all(), [ 'save_s3' => 'boolean', 'backup_now' => 'boolean|nullable', 'enabled' => 'boolean', 'dump_all' => 'boolean', - 's3_storage_uuid' => 'string|exists:s3_storages,uuid|nullable', + 's3_storage_uuid' => 'string|nullable', 'databases_to_backup' => 'string|nullable', @@ - if (! $request->uuid) { - return response()->json(['message' => 'UUID is required.'], 404); + $uuid = $request->route('uuid'); + if (! $uuid) { + return response()->json(['message' => 'UUID is required.'], 400); } - // Validate scheduled_backup_uuid is provided - if (! $request->scheduled_backup_uuid) { + $scheduledUuid = $request->route('scheduled_backup_uuid'); + if (! $scheduledUuid) { return response()->json(['message' => 'Scheduled backup UUID is required.'], 400); } - $uuid = $request->uuid; removeUnnecessaryFieldsFromRequest($request); $database = queryDatabaseByUuidWithinTeam($uuid, $teamId); if (! $database) { return response()->json(['message' => 'Database not found.'], 404); } $this->authorize('update', $database); if ($request->boolean('save_s3') && ! $request->filled('s3_storage_uuid')) { return response()->json([ 'message' => 'Validation failed.', 'errors' => ['s3_storage_uuid' => ['The s3_storage_uuid field is required when save_s3 is true.']], ], 422); } if ($request->filled('s3_storage_uuid')) { $existsInTeam = S3Storage::ownedByCurrentTeam()->where('uuid', $request->s3_storage_uuid)->exists(); if (! $existsInTeam) { return response()->json([ 'message' => 'Validation failed.', 'errors' => ['s3_storage_uuid' => ['The selected S3 storage is invalid for this team.']], ], 422); } } $backupConfig = ScheduledDatabaseBackup::ownedByCurrentTeamAPI($teamId)->where('database_id', $database->id) - ->where('uuid', $request->scheduled_backup_uuid) + ->where('uuid', $scheduledUuid) ->first(); @@ if ($request->backup_now) { - DatabaseBackupJob::dispatch($backupConfig); + dispatch(new DatabaseBackupJob($backupConfig)); }
1960-2020: Delete backup needs camelCase and better transaction handling!Method name violates PSR-12, not using route params, and transaction handling could be cleaner with closure pattern. It's like using lambda functions when you have perfectly good servers!
Apply this diff:
- public function delete_backup_by_uuid(Request $request) + public function deleteBackupByUuid(Request $request) { @@ - // Validate scheduled_backup_uuid is provided - if (! $request->scheduled_backup_uuid) { + $uuid = $request->route('uuid'); + $scheduledUuid = $request->route('scheduled_backup_uuid'); + if (! $scheduledUuid) { return response()->json(['message' => 'Scheduled backup UUID is required.'], 400); } - $database = queryDatabaseByUuidWithinTeam($request->uuid, $teamId); + $database = queryDatabaseByUuidWithinTeam($uuid, $teamId); @@ $backup = ScheduledDatabaseBackup::ownedByCurrentTeamAPI($teamId)->where('database_id', $database->id) - ->where('uuid', $request->scheduled_backup_uuid) + ->where('uuid', $scheduledUuid) ->first(); @@ try { - DB::beginTransaction(); - // Get all executions for this backup configuration - $executions = $backup->executions()->get(); - - // Delete all execution files (locally and optionally from S3) - foreach ($executions as $execution) { - if ($execution->filename) { - deleteBackupsLocally($execution->filename, $database->destination->server); - - if ($deleteS3 && $backup->s3) { - deleteBackupsS3($execution->filename, $backup->s3); + DB::transaction(function () use ($backup, $database, $deleteS3) { + $executions = $backup->executions()->get(); + foreach ($executions as $execution) { + if ($execution->filename) { + deleteBackupsLocally($execution->filename, $database->destination->server); + if ($deleteS3 && $backup->s3) { + deleteBackupsS3($execution->filename, $backup->s3); + } } + $execution->delete(); } - - $execution->delete(); - } - - // Delete the backup configuration itself - $backup->delete(); - DB::commit(); + $backup->delete(); + });
2084-2140: Execution deletion needs authorization and proper naming!Missing authorization check, camelCase violation, and not using route parameters. Even a T-800 knows better than this!
Apply this diff:
- public function delete_execution_by_uuid(Request $request) + public function deleteExecutionByUuid(Request $request) { @@ - // Validate parameters - if (! $request->scheduled_backup_uuid) { + $uuid = $request->route('uuid'); + $scheduledUuid = $request->route('scheduled_backup_uuid'); + $executionUuid = $request->route('execution_uuid'); + if (! $scheduledUuid) { return response()->json(['message' => 'Scheduled backup UUID is required.'], 400); } - if (! $request->execution_uuid) { + if (! $executionUuid) { return response()->json(['message' => 'Execution UUID is required.'], 400); } - $database = queryDatabaseByUuidWithinTeam($request->uuid, $teamId); + $database = queryDatabaseByUuidWithinTeam($uuid, $teamId); @@ $this->authorize('update', $database); // Find the backup configuration by its UUID $backup = ScheduledDatabaseBackup::ownedByCurrentTeamAPI($teamId)->where('database_id', $database->id) - ->where('uuid', $request->scheduled_backup_uuid) + ->where('uuid', $scheduledUuid) ->first(); @@ - $execution = $backup->executions()->where('uuid', $request->execution_uuid)->first(); + $execution = $backup->executions()->where('uuid', $executionUuid)->first();
2197-2241: List executions violates naming convention and lacks authorization!Missing authorization check, camelCase violation, and exposing execution messages that might contain sensitive data. This is why we can't have nice things... until judgment day!
Apply this diff:
- public function list_backup_executions(Request $request) + public function listBackupExecutions(Request $request) { @@ - // Validate scheduled_backup_uuid is provided - if (! $request->scheduled_backup_uuid) { + $uuid = $request->route('uuid'); + $scheduledUuid = $request->route('scheduled_backup_uuid'); + if (! $scheduledUuid) { return response()->json(['message' => 'Scheduled backup UUID is required.'], 400); } - $database = queryDatabaseByUuidWithinTeam($request->uuid, $teamId); + $database = queryDatabaseByUuidWithinTeam($uuid, $teamId); if (! $database) { return response()->json(['message' => 'Database not found.'], 404); } + + $this->authorize('view', $database); // Find the backup configuration by its UUID $backup = ScheduledDatabaseBackup::ownedByCurrentTeamAPI($teamId)->where('database_id', $database->id) - ->where('uuid', $request->scheduled_backup_uuid) + ->where('uuid', $scheduledUuid) ->first(); @@ ->map(function ($execution) { - return [ + $base = [ 'uuid' => $execution->uuid, 'filename' => $execution->filename, 'size' => $execution->size, 'created_at' => $execution->created_at->toIso8601String(), - 'message' => $execution->message, 'status' => $execution->status, ]; + // Only include message if user can read sensitive data + if (request()->attributes->get('can_read_sensitive', false)) { + $base['message'] = $execution->message; + } + return $base; });
330-330: Grammar malfunction in comment - fix immediately!"this check if the request is a valid json" - even Skynet writes better comments than this!
- // this check if the request is a valid json + // Check if the request is valid JSON
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: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
app/Console/Commands/Cloud/CloudDeleteUser.php (3)
31-37: Add explicit return type to handle().Per guidelines, declare return types. Command returns 0/1.
Apply:
- public function handle() + public function handle(): int
476-481: Do not call exit() inside command flow. Return an exit code instead.exit() bypasses Laravel lifecycle (finally handlers, testing, etc.).
Apply:
- if (! $this->isDryRun) { - DB::rollBack(); - } - exit(1); + if (! $this->isDryRun) { + DB::rollBack(); + } + return 1;
49-51: Eager load to avoid N+1 when rendering overview.Teams, members, and servers are accessed later; eager load them here.
Apply:
- $this->user = User::whereEmail($email)->firstOrFail(); + $this->user = User::with(['teams.members', 'teams.servers'])->whereEmail($email)->firstOrFail();
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
app/Console/Commands/Cloud/CloudDeleteUser.php(1 hunks)app/Console/Commands/Cloud/CloudFixSubscription.php(1 hunks)app/Console/Commands/CloudCheckSubscription.php(0 hunks)app/Console/Commands/CloudCleanupSubscriptions.php(0 hunks)
💤 Files with no reviewable changes (2)
- app/Console/Commands/CloudCheckSubscription.php
- app/Console/Commands/CloudCleanupSubscriptions.php
🧰 Additional context used
📓 Path-based instructions (6)
{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
Follow PSR-12 and run Laravel Pint for formatting
Files:
app/Console/Commands/Cloud/CloudDeleteUser.phpapp/Console/Commands/Cloud/CloudFixSubscription.php
app/Console/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Define Artisan console commands in app/Console
Files:
app/Console/Commands/Cloud/CloudDeleteUser.phpapp/Console/Commands/Cloud/CloudFixSubscription.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 statements
Use PHP 8 constructor property promotion; avoid empty constructors
Use explicit return types for functions/methods and appropriate parameter type hints
Prefer PHPDoc blocks over inline comments; add useful array shape docs when relevant
Files:
app/Console/Commands/Cloud/CloudDeleteUser.phpapp/Console/Commands/Cloud/CloudFixSubscription.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/Console/Commands/Cloud/CloudDeleteUser.phpapp/Console/Commands/Cloud/CloudFixSubscription.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use env() outside configuration files; access configuration via config()
Never call env() outside configuration files; use config() elsewhere
Files:
app/Console/Commands/Cloud/CloudDeleteUser.phpapp/Console/Commands/Cloud/CloudFixSubscription.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/Console/Commands/Cloud/CloudDeleteUser.phpapp/Console/Commands/Cloud/CloudFixSubscription.php
🧠 Learnings (1)
📚 Learning: 2025-08-27T14:59:11.004Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/application-architecture.mdc:0-0
Timestamp: 2025-08-27T14:59:11.004Z
Learning: Applies to app/Console/**/*.php : Define Artisan console commands in app/Console
Applied to files:
app/Console/Commands/Cloud/CloudDeleteUser.php
🧬 Code graph analysis (1)
app/Console/Commands/Cloud/CloudFixSubscription.php (2)
app/Models/Team.php (3)
subscription(221-224)members(216-219)subscriptionEnded(193-209)bootstrap/helpers/notifications.php (1)
send_internal_notification(16-24)
🪛 PHPMD (2.15.0)
app/Console/Commands/Cloud/CloudFixSubscription.php
8-879: The class CloudFixSubscription has an overall complexity of 127 which is very high. The configured complexity threshold is 50. (undefined)
(ExcessiveClassComplexity)
32-109: The method handle() has a Cyclomatic Complexity of 12. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
32-109: The method handle() has an NPath complexity of 294. The configured NPath complexity threshold is 200. (undefined)
(NPathComplexity)
34-34: Missing class import via use statement (line '34', column '23'). (undefined)
(MissingImport)
114-324: The method fixCanceledSubscriptions() has a Cyclomatic Complexity of 34. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
114-324: The method fixCanceledSubscriptions() has an NPath complexity of 3132. The configured NPath complexity threshold is 200. (undefined)
(NPathComplexity)
114-324: The method fixCanceledSubscriptions() has 211 lines of code. Current threshold is set to 100. Avoid really long methods. (undefined)
(ExcessiveMethodLength)
123-125: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
126-132: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
129-131: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
134-134: Avoid excessively long variable names like $teamsWithSubscriptions. Keep variable name length under 20. (undefined)
(LongVariable)
138-138: Avoid excessively long variable names like $canceledSubscriptions. Keep variable name length under 20. (undefined)
(LongVariable)
181-183: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
186-216: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
202-204: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
253-255: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
258-287: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
274-276: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
293-295: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
311-313: The method fixCanceledSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
329-712: The method verifyAllActiveSubscriptions() has a Cyclomatic Complexity of 59. The configured cyclomatic complexity threshold is 10. (undefined)
(CyclomaticComplexity)
329-712: The method verifyAllActiveSubscriptions() has an NPath complexity of 65820. The configured NPath complexity threshold is 200. (undefined)
(NPathComplexity)
329-712: The method verifyAllActiveSubscriptions() has 384 lines of code. Current threshold is set to 100. Avoid really long methods. (undefined)
(ExcessiveMethodLength)
343-343: Avoid excessively long variable names like $teamsWithActiveSubscriptions. Keep variable name length under 20. (undefined)
(LongVariable)
404-406: The method verifyAllActiveSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
452-470: The method verifyAllActiveSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
471-490: The method verifyAllActiveSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
491-668: The method verifyAllActiveSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
615-632: The method verifyAllActiveSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
633-650: The method verifyAllActiveSubscriptions uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
733-733: The method searchSubscriptionsByCustomer has a boolean flag argument $requireActive, which is a certain sign of a Single Responsibility Principle violation. (undefined)
(BooleanArgumentFlag)
816-816: Avoid unused parameters such as '$team'. (undefined)
(UnusedFormalParameter)
🔇 Additional comments (3)
app/Console/Commands/Cloud/CloudDeleteUser.php (2)
3-3: Namespace move looks good. I'll be back (to other nits).Correct sub-namespace for cloud commands.
684-705: Verify subscription config shape used for price lookup.config('subscription') may be nested; the foreach could miss keys or hit arrays.
Would you confirm the subscription config keys (e.g., stripe_price_id_basic_monthly, stripe_price_id_pro_monthly, etc.) exist at the root? If not, consider using explicit keys like config('subscription.stripe_price_id_basic_monthly').
app/Console/Commands/Cloud/CloudFixSubscription.php (1)
1-21: Registration OK — Kernel already loads Commands
app/Console/Kernel.php contains $this->load(DIR.'/Commands'); (≈line 135), so commands in app/Console/Commands/Cloud will be auto-discovered; no explicit registration required. Self-hosters rejoice.
…amIdForCache method - Updated the getTeamIdForCache method to differentiate team retrieval based on the instance type, ensuring correct access to the team property or method for Server models and other types.
…notifications - Updated the toast component to enhance the layout by changing the alignment of items from 'start' to 'center'. - Added 'flex-shrink-0' class to SVG icons to prevent them from shrinking, ensuring consistent icon display across different toast types.
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 (2)
app/Traits/ClearsGlobalSearchCache.php(1 hunks)resources/views/components/toast.blade.php(1 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
{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
Follow PSR-12 and run Laravel Pint for formatting
Files:
resources/views/components/toast.blade.phpapp/Traits/ClearsGlobalSearchCache.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 statements
Use PHP 8 constructor property promotion; avoid empty constructors
Use explicit return types for functions/methods and appropriate parameter type hints
Prefer PHPDoc blocks over inline comments; add useful array shape docs when relevant
Files:
resources/views/components/toast.blade.phpapp/Traits/ClearsGlobalSearchCache.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/components/toast.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/components/toast.blade.php
resources/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Store frontend assets and views under resources
Files:
resources/views/components/toast.blade.php
resources/**/*.blade.php
📄 CodeRabbit inference engine (CLAUDE.md)
resources/**/*.blade.php: Use Tailwind v4 utilities and avoid deprecated classes (e.g., use shrink-* instead of flex-shrink-*)
Use gap utilities for spacing lists instead of margins when listing items
Files:
resources/views/components/toast.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/components/toast.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/components/toast.blade.php
app/Traits/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/application-architecture.mdc)
Place reusable PHP traits in app/Traits
Files:
app/Traits/ClearsGlobalSearchCache.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/ClearsGlobalSearchCache.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use env() outside configuration files; access configuration via config()
Never call env() outside configuration files; use config() elsewhere
Files:
app/Traits/ClearsGlobalSearchCache.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/ClearsGlobalSearchCache.php
🧠 Learnings (5)
📚 Learning: 2025-09-15T10:49:43.757Z
Learnt from: CR
PR: coollabsio/coolify#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-15T10:49:43.757Z
Learning: Applies to resources/**/*.blade.php : Use Tailwind v4 utilities and avoid deprecated classes (e.g., use shrink-* instead of flex-shrink-*)
Applied to files:
resources/views/components/toast.blade.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 resources/{views/**/*.blade.php,js/**/*.vue} : Use Tailwind utility classes; remove redundant classes; prefer gap-* utilities for spacing instead of margins when listing items
Applied to files:
resources/views/components/toast.blade.php
📚 Learning: 2025-08-27T14:59:11.004Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/application-architecture.mdc:0-0
Timestamp: 2025-08-27T14:59:11.004Z
Learning: Applies to app/Models/{Application,Server,Service,Project,Environment}.php : Major resources must provide a team-based scope (e.g., scopeOwnedByCurrentTeam) to enforce multi-tenant isolation
Applied to files:
app/Traits/ClearsGlobalSearchCache.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/Http/Controllers,app/Models}/**/*.php : Avoid DB::; prefer Model::query() and Eloquent/query builder usage
Applied to files:
app/Traits/ClearsGlobalSearchCache.php
📚 Learning: 2025-08-27T15:00:36.717Z
Learnt from: CR
PR: coollabsio/coolify#0
File: .cursor/rules/database-patterns.mdc:0-0
Timestamp: 2025-08-27T15:00:36.717Z
Learning: Applies to app/Models/*.php : Apply team-based global scopes on team-scoped models to enforce multi-tenancy isolation by default
Applied to files:
app/Traits/ClearsGlobalSearchCache.php
🧬 Code graph analysis (1)
app/Traits/ClearsGlobalSearchCache.php (4)
app/Livewire/GlobalSearch.php (2)
GlobalSearch(19-372)clearTeamCache(56-59)app/Models/Application.php (1)
team(706-709)app/Models/Server.php (1)
team(897-900)app/Models/StandalonePostgresql.php (1)
team(208-211)
🪛 PHPMD (2.15.0)
app/Traits/ClearsGlobalSearchCache.php
17-17: Avoid using static access to class '\App\Livewire\GlobalSearch' in method 'bootClearsGlobalSearchCache'. (undefined)
(StaticAccess)
26-26: Avoid using static access to class '\App\Livewire\GlobalSearch' in method 'bootClearsGlobalSearchCache'. (undefined)
(StaticAccess)
34-34: Avoid using static access to class '\App\Livewire\GlobalSearch' in method 'bootClearsGlobalSearchCache'. (undefined)
(StaticAccess)
71-73: The method getTeamIdForCache uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (undefined)
(ElseExpression)
⏰ 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 (6)
app/Traits/ClearsGlobalSearchCache.php (6)
22-28: Remove created() hook — avoid double invalidation (I’ll be back only once).saving runs on create; created duplicates the cache clear.
- static::created(function ($model) { - // Always clear cache when model is created - $teamId = $model->getTeamIdForCache(); - if (filled($teamId)) { - GlobalSearch::clearTeamCache($teamId); - } - }); + // created hook not needed; saving already covers creates.
55-60: Detect post-save changes too (covers saved()).Include wasChanged so logic works whether you stay on saving or move to saved later.
- if ($this->isDirty($field)) { + if ($this->isDirty($field) || $this->wasChanged($field)) {
10-37: PHPMD: static access to GlobalSearch — consider a small service.Not blocking, but wrapping clearTeamCache behind a service resolved via the container will silence PHPMD and decouple Livewire from models. I’ll be back with fewer warnings.
30-36: Type deleted() closure; optionally also clear on restored() (zombie records return).Type-hint now; add restored to keep cache fresh after soft-deletes are undone.
- static::deleted(function ($model) { + static::deleted(static function (Model $model): void) {Add alongside deleted():
static::restored(static function (Model $model): void) { $teamId = $model->getTeamIdForCache(); if (filled($teamId)) { GlobalSearch::clearTeamCache($teamId); } });
12-20: Type closures (static, Model param, void).Keeps things explicit and PSR-12 friendly.
- static::saving(function ($model) { + static::saving(static function (Model $model): void) {
65-85: Replace getTeamIdForCache with attribute-safe data_get chain and add return typeCalling team() returns a belongsTo Relation on multiple models (Server, S3Storage, Subscription, several notification/settings models); the current Server special‑case masks a bug where a Relation can be dereferenced and break. Replace the method with a data_get chain that reads team_id, team.id, or environment.project.team.id and return ?int.
File: app/Traits/ClearsGlobalSearchCache.php (lines ~65–85)
- private function getTeamIdForCache() - { - // For database models, team is accessed through environment.project.team - if (method_exists($this, 'team')) { - if ($this instanceof \App\Models\Server) { - $team = $this->team; - } else { - $team = $this->team(); - } - if (filled($team)) { - return is_object($team) ? $team->id : null; - } - } - - // For models with direct team_id property - if (property_exists($this, 'team_id') || isset($this->team_id)) { - return $this->team_id; - } - - return null; - } + private function getTeamIdForCache(): ?int + { + // 1) Direct FK if present + $id = data_get($this, 'team_id'); + if (filled($id)) { + return (int) $id; + } + // 2) Loaded/belongsTo relation or computed accessor + $id = data_get($this, 'team.id'); + if (filled($id)) { + return (int) $id; + } + // 3) Nested relation used by many resources + $id = data_get($this, 'environment.project.team.id'); + return filled($id) ? (int) $id : null; + }
…ssociation and connection validation - Refactored the private key update logic to use a database transaction for associating the private key with the server, ensuring atomicity. - Improved error handling by refreshing the server state upon failure and validating the connection after updates. - Enhanced success and error dispatching for better user feedback during the update process.
… and connection check - Implemented a dispatch for 'refreshServerShow' after successfully updating the private key and validating the server connection. - This enhancement improves the user experience by ensuring the server display is updated immediately following key changes and connection checks.
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 (3)
app/Livewire/Server/PrivateKey/Show.php (3)
21-29: Authorize in mount(). Trust, but verify.Livewire components must authorize in mount; add a policy check after loading the Server.
try { $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail(); + $this->authorize('view', $this->server); $this->privateKeys = PrivateKey::ownedByCurrentTeam()->get()->where('is_git_related', false);
15-20: Add typed props and method return types. Strong types, strong servers.Bring this in line with PSR‑12 and project rules.
use Illuminate\Support\Collection; use Illuminate\Contracts\View\View; public Server $server; /** @var Collection<int, \App\Models\PrivateKey> */ public Collection $privateKeys; public array $parameters = []; public function mount(string $server_uuid): void { /* ... */ } public function setPrivateKey(int $privateKeyId): void { /* ... */ } public function checkConnection(): void { /* ... */ } public function render(): View { /* ... */ }
58-67: Escape interpolated error (XSS) — listener confirmedEscape $error before dispatching (use e($error) or htmlspecialchars) to prevent XSS. Listener 'refreshServerShow' exists in app/Livewire/Server/Navbar.php and app/Livewire/Server/Show.php. No serverless XSS.
- $this->dispatch('error', 'Server is not reachable.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.<br><br>Error: '.$error); + $this->dispatch('error', 'Server is not reachable.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.<br><br>Error: '.e($error));
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
app/Livewire/Server/PrivateKey/Show.php(3 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
{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/Server/PrivateKey/Show.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/PrivateKey/Show.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
Follow PSR-12 and run Laravel Pint for formatting
Files:
app/Livewire/Server/PrivateKey/Show.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 must use the AuthorizesRequests trait and call authorize() in actions (e.g., mount(), update())
Namespace Livewire components under App\Livewire and dispatch events with $this->dispatch() (Livewire v3)
Use Livewire lifecycle hooks (e.g., mount(), updatedFoo()) for initialization and reactive side effects
Place Livewire components under app/Livewire and keep state on the server
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
Files:
app/Livewire/Server/PrivateKey/Show.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 statements
Use PHP 8 constructor property promotion; avoid empty constructors
Use explicit return types for functions/methods and appropriate parameter type hints
Prefer PHPDoc blocks over inline comments; add useful array shape docs when relevant
Files:
app/Livewire/Server/PrivateKey/Show.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/PrivateKey/Show.php
app/Livewire/**
📄 CodeRabbit inference engine (.cursor/rules/project-overview.mdc)
Implement frontend components as Livewire classes under app/Livewire
Files:
app/Livewire/Server/PrivateKey/Show.php
{app,bootstrap,database,routes,tests}/**/*.php
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use env() outside configuration files; access configuration via config()
Never call env() outside configuration files; use config() elsewhere
Files:
app/Livewire/Server/PrivateKey/Show.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/Server/PrivateKey/Show.php
🧠 Learnings (2)
📚 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/PrivateKey/Show.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: Use Laravel for the backend with Livewire for the frontend
Applied to files:
app/Livewire/Server/PrivateKey/Show.php
🧬 Code graph analysis (1)
app/Livewire/Server/PrivateKey/Show.php (3)
app/Livewire/Server/ValidateAndInstall.php (1)
validateConnection(66-79)app/Livewire/Server/Show.php (1)
refresh(224-227)app/Livewire/Server/CloudflareTunnel.php (1)
refresh(35-39)
🪛 PHPMD (2.15.0)
app/Livewire/Server/PrivateKey/Show.php
41-48: Avoid using static access to class '\Illuminate\Support\Facades\DB' in method 'setPrivateKey'. (undefined)
(StaticAccess)
46-46: Missing class import via use statement (line '46', column '31'). (undefined)
(MissingImport)
⏰ 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: aarch64
- GitHub Check: amd64
🔇 Additional comments (1)
app/Livewire/Server/PrivateKey/Show.php (1)
8-8: DB facade import is fine; PHPMD “StaticAccess” can be ignored for Laravel facades.The
use Illuminate\Support\Facades\DB;is correct. The “MissingImport” hint appears false-positive here.If PHPMD keeps nagging, consider excluding Laravel facades in your PHPMD config or adding a local suppress for this method.
(service): disable posthog
…onStatusJob - Added retry configuration with a maximum of 3 attempts and backoff intervals of 10, 30, and 60 seconds to improve job resilience and handling of transient failures.
is_buildtimeandis_runtimeenvironment variable flags./orcmd + k.Issues
Is Build Variable?in v4.0.0-beta.427 and newer causes all secrets to be passed to the build step, Docker then errors #6632