This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a Coolify Enterprise Transformation Project - transforming the existing Coolify fork into a comprehensive enterprise-grade cloud deployment and management platform. This is NOT standard Coolify development but a major architectural transformation.
- Multi-Tenant Organization Hierarchy: Replace team-based architecture with hierarchical organizations (Top Branch → Master Branch → Sub-Users → End Users)
- Terraform + Coolify Hybrid: Use Terraform for infrastructure provisioning while preserving Coolify's application deployment excellence
- Enterprise Features: Add licensing, payment processing, white-label branding, domain management
- Vue.js + Inertia.js Frontend: Modern reactive frontend alongside existing Livewire components
- Real-time Resource Management: Advanced capacity planning, build server optimization, organization quotas
- Tasks 1-2 Completed: Foundation setup (organizations, database schema) and licensing system
- Current Focus: Tasks 3+ (white-label branding, Terraform integration, payment processing)
- Architecture: Laravel 12 + Vue.js 3 + Inertia.js + existing Livewire components
- Requirements:
.kiro/specs/coolify-enterprise-transformation/requirements.md - Design:
.kiro/specs/coolify-enterprise-transformation/design.md - Implementation Plan:
.kiro/specs/coolify-enterprise-transformation/tasks.md - Architecture Guide:
.kiro/steering/application-architecture.md
- Laravel 12 - Core framework (existing)
- PostgreSQL 15 - Primary database (existing)
- Redis 7 - Caching/queues (existing)
- New Enterprise Services: LicensingService, TerraformService, PaymentService, WhiteLabelService
- Livewire 3.6 - Server-side components (existing)
- Vue.js 3.5 + Inertia.js - New reactive components for enterprise features
- Alpine.js - Client-side interactivity (existing)
- Tailwind CSS 4.1 - Utility-first styling (existing)
- Terraform - Cloud infrastructure provisioning (NEW)
- Multi-Cloud Support - AWS, GCP, Azure, DigitalOcean, Hetzner (NEW)
- Docker - Container orchestration (existing, enhanced)
# Standard Laravel setup
composer install
npm install
php artisan key:generate
# Run enterprise migrations
php artisan migrate
# Seed enterprise data
php artisan db:seed --class=EnterpriseSeeder
# Build Vue.js components
npm run dev
# Start services
php artisan serve
php artisan queue:work
php artisan reverb:start # WebSockets# PHP formatting and analysis
./vendor/bin/pint
./vendor/bin/phpstan analyse
./vendor/bin/rector process --dry-run
# Run tests
./vendor/bin/pest
./vendor/bin/pest --coverage# Vue component development
npm run dev # Hot reload
npm run build # Production build
# Vue component testing
npm run test # If configured- Organization: Hierarchical multi-tenant structure
- EnterpriseLicense: Feature flags and usage limits
- CloudProviderCredential: Encrypted cloud API keys
- TerraformDeployment: Infrastructure provisioning state
- WhiteLabelConfig: Branding and customization
- OrganizationResourceUsage: Resource monitoring and quotas
- User: Extended with organization relationships
- Server: Enhanced with Terraform integration
- Application: Enhanced with capacity-aware deployment
- Team: Migrated to organization hierarchy
// Core enterprise services
app/Services/Enterprise/
├── LicensingService.php # License validation and management
├── TerraformService.php # Infrastructure provisioning
├── PaymentService.php # Multi-gateway payment processing
├── WhiteLabelService.php # Branding and customization
├── OrganizationService.php # Hierarchy management
├── CapacityManager.php # Resource allocation
└── SystemResourceMonitor.php # Real-time monitoring- Core application management
- Server monitoring
- Deployment workflows
resources/js/Components/Enterprise/
├── Organization/
│ ├── OrganizationManager.vue
│ ├── OrganizationHierarchy.vue
│ └── OrganizationSwitcher.vue
├── License/
│ ├── LicenseManager.vue
│ ├── UsageMonitoring.vue
│ └── FeatureToggles.vue
├── Infrastructure/
│ ├── TerraformManager.vue
│ └── CloudProviderCredentials.vue
└── WhiteLabel/
├── BrandingManager.vue
└── ThemeCustomizer.vue
organizations- Hierarchical organization structureorganization_users- User-organization relationships with rolesenterprise_licenses- License management with feature flagswhite_label_configs- Branding configurationcloud_provider_credentials- Encrypted cloud API keysterraform_deployments- Infrastructure provisioning trackingserver_resource_metrics- Real-time resource monitoringorganization_resource_usage- Organization-level resource quotas
- Extended
userstable with organization relationships - Enhanced
serverstable with Terraform integration - Modified foreign keys to support organization hierarchy
class LicensingService implements LicensingServiceInterface
{
public function validateLicense(string $licenseKey, string $domain = null): LicenseValidationResult
{
// License validation with domain checking
// Usage limit enforcement
// Feature flag validation
}
}// Controller
class OrganizationController extends Controller
{
public function index()
{
return Inertia::render('Enterprise/Organization/Index', [
'organizations' => auth()->user()->organizations,
'permissions' => auth()->user()->getAllPermissions(),
]);
}
}<!-- Vue Component -->
<template>
<div class="organization-manager">
<OrganizationHierarchy
:organizations="organizations"
@organization-selected="handleOrganizationSelect"
/>
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
import OrganizationHierarchy from './OrganizationHierarchy.vue'
const props = defineProps(['organizations', 'permissions'])
const emit = defineEmits(['organization-selected'])
</script>class CapacityManager implements CapacityManagerInterface
{
public function canServerHandleDeployment(Server $server, Application $app): bool
{
// Check CPU, memory, disk capacity
// Consider current resource usage
// Apply capacity buffers and safety margins
}
public function selectOptimalServer(Collection $servers, array $requirements): ?Server
{
// Score servers based on capacity and load
// Select best-fit server for deployment
}
}- Multi-level organization structure
- Role-based access control per organization
- Resource isolation and quota enforcement
- Cross-organization resource sharing
- License key generation and validation
- Feature flag enforcement
- Usage limit tracking
- Domain-based authorization
- Cloud provider credential management
- Infrastructure provisioning via Terraform
- Server registration with Coolify post-provisioning
- Multi-cloud support (AWS, GCP, Azure, etc.)
- Real-time resource monitoring
- Capacity-aware deployment decisions
- Build server load balancing
- Organization resource quotas
- Multi-gateway support (Stripe, PayPal, etc.)
- Subscription management
- Usage-based billing
- Payment-triggered resource provisioning
- Custom branding per organization
- Dynamic theme configuration
- Custom domain support
- Branded email templates
tests/
├── Enterprise/
│ ├── Feature/
│ │ ├── OrganizationManagementTest.php
│ │ ├── LicensingWorkflowTest.php
│ │ └── TerraformIntegrationTest.php
│ ├── Unit/
│ │ ├── LicensingServiceTest.php
│ │ ├── CapacityManagerTest.php
│ │ └── PaymentServiceTest.php
│ └── Browser/
│ ├── OrganizationManagementTest.php
│ └── LicenseManagementTest.php
- Mock external services (Terraform, payment gateways)
- Test organization hierarchy and permissions
- Validate license enforcement across features
- Test resource capacity calculations
- Browser tests for Vue.js components
- Create service interface and implementation
- Add database migrations if needed
- Create Vue.js components for UI
- Add Inertia.js routes and controllers
- Write comprehensive tests
- Update license feature flags
- Components located in
resources/js/Components/Enterprise/ - Use Inertia.js for server communication
- Follow existing component patterns
- Build with
npm run devornpm run build
- Create interface in
app/Contracts/ - Implement service in
app/Services/Enterprise/ - Register in service provider
- Add comprehensive error handling
- Create unit and integration tests
- Organization-based data scoping
- Encrypted sensitive data (API keys, credentials)
- Role-based access control
- Audit logging for all actions
- Sanctum token authentication
- Rate limiting per organization tier
- Request validation and sanitization
- CORS configuration for enterprise domains
- Organization-scoped queries with proper indexing
- Eager loading for complex relationships
- Efficient resource usage calculations
- Proper caching for license validations
- Vue.js component lazy loading
- Efficient WebSocket connections
- Resource monitoring data pagination
- Optimized asset loading
# Enterprise-specific configuration
TERRAFORM_BINARY_PATH=/usr/local/bin/terraform
PAYMENT_STRIPE_SECRET_KEY=sk_test_...
PAYMENT_PAYPAL_CLIENT_ID=...
LICENSE_ENCRYPTION_KEY=...
ORGANIZATION_DEFAULT_QUOTAS=...- PostgreSQL 15+ (primary database)
- Redis 7+ (caching, queues, sessions)
- Terraform (infrastructure provisioning)
- Docker (container management)
- WebSocket server (real-time features)
This is a major architectural transformation preserving Coolify's deployment excellence while adding comprehensive enterprise features. Focus on maintaining existing functionality while carefully implementing the new organizational hierarchy and enterprise capabilities.
The following sections contain the standard Coolify development patterns and practices. When working on core Coolify functionality (non-enterprise features), follow these guidelines.
Coolify is an open-source, self-hostable platform for deploying applications and managing servers - an alternative to Heroku/Netlify/Vercel. It's built with Laravel (PHP) and uses Docker for containerization.
Application- Deployed applications with Git integration (74KB, highly complex)Server- Remote servers managed by Coolify (46KB, complex)Service- Docker Compose services (58KB, complex)Database- Standalone database instances (PostgreSQL, MySQL, MongoDB, Redis, etc.)Team- Multi-tenancy supportProject- Grouping of environments and resourcesEnvironment- Environment isolation (staging, production, etc.)
- Uses Laravel Horizon for queue management
- Key jobs:
ApplicationDeploymentJob,ServerCheckJob,DatabaseBackupJob ServerManagerJobandServerConnectionCheckJobhandle job scheduling
- Git webhook triggers deployment
ApplicationDeploymentJobhandles build and deployment- Docker containers are managed on target servers
- Proxy configuration (Nginx/Traefik) is updated
- SSH-based server communication via
ExecuteRemoteCommandtrait - Docker installation and management
- Proxy configuration generation
- Resource monitoring and cleanup
app/Actions/- Domain-specific actions (Application, Database, Server, etc.)app/Jobs/- Background queue jobsapp/Livewire/- Frontend components (full-stack with Livewire)app/Models/- Eloquent modelsapp/Rules/- Custom validation rulesapp/Http/Middleware/- HTTP middlewarebootstrap/helpers/- Helper functions for various domainsdatabase/migrations/- Database schema evolutionroutes/- Application routing (web.php, api.php, webhooks.php, channels.php)resources/views/livewire/- Livewire component viewstests/- Pest tests (Feature and Unit)
Coolify uses a server-side first approach with minimal JavaScript:
- Livewire for server-side rendering with reactive components
- Alpine.js for lightweight client-side interactions
- Tailwind CSS for utility-first styling with dark mode support
- Enhanced Form Components with built-in authorization system
- Real-time updates via WebSocket without page refreshes
IMPORTANT: When creating or editing forms, ALWAYS include authorization:
Use canGate and canResource attributes for automatic authorization:
<x-forms.input canGate="update" :canResource="$resource" id="name" label="Name" />
<x-forms.select canGate="update" :canResource="$resource" id="type" label="Type">...</x-forms.select>
<x-forms.checkbox instantSave canGate="update" :canResource="$resource" id="enabled" label="Enabled" />
<x-forms.button canGate="update" :canResource="$resource" type="submit">Save</x-forms.button>Wrap with @can directives:
@can('update', $resource)
<x-modal-confirmation title="Confirm Action?" buttonTitle="Confirm">...</x-modal-confirmation>
<x-modal-input buttonTitle="Edit" title="Edit Settings">...</x-modal-input>
@endcanAlways add the AuthorizesRequests trait and check permissions:
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class MyComponent extends Component
{
use AuthorizesRequests;
public function mount()
{
$this->authorize('view', $this->resource);
}
public function update()
{
$this->authorize('update', $this->resource);
// ... update logic
}
}- Components located in
app/Livewire/ - Views in
resources/views/livewire/ - State management handled on the server
- Use wire:model for two-way data binding
- Dispatch events for component communication
- Actions Pattern: Use Actions for complex business logic (
app/Actions/) - Livewire Components: Handle UI and user interactions
- Jobs: Handle asynchronous operations
- Traits: Provide shared functionality (e.g.,
ExecuteRemoteCommand) - Helper Functions: Domain-specific helpers in
bootstrap/helpers/
- Use Eloquent ORM for database interactions
- Implement relationships properly (HasMany, BelongsTo, etc.)
- Use database transactions for critical operations
- Leverage query scopes for reusable queries
- Apply indexes for performance-critical queries
- Authentication: Multi-provider auth via Laravel Fortify & Sanctum
- Authorization: Team-based access control with policies and enhanced form components
- Form Component Security: Built-in
canGateauthorization system for UI components - API Security: Token-based auth with IP allowlisting
- Secrets Management: Never log or expose sensitive data
- Input Validation: Always validate user input with Form Requests or Rules
- SQL Injection Prevention: Use Eloquent ORM or parameterized queries
- RESTful endpoints in
routes/api.php - Use API Resources for response formatting
- Implement rate limiting for public endpoints
- Version APIs when making breaking changes
- Document endpoints with clear examples
- Framework: Pest for expressive testing
- Structure: Feature tests for user flows, Unit tests for isolated logic
- Coverage: Test critical paths and edge cases
- Mocking: Use Laravel's built-in mocking for external services
- Database: Use RefreshDatabase trait for test isolation
- Group routes by middleware and prefix
- Use route model binding for cleaner controllers
- Name routes consistently (resource.action)
- Implement proper HTTP verbs (GET, POST, PUT, DELETE)
- Use
handleError()helper for consistent error handling - Log errors with appropriate context
- Return user-friendly error messages
- Implement proper HTTP status codes
- Use eager loading to prevent N+1 queries
- Implement caching for frequently accessed data
- Queue heavy operations
- Optimize database queries with proper indexes
- Use chunking for large data operations
- Follow PSR-12 coding standards
- Use Laravel Pint for automatic formatting
- Write descriptive variable and method names
- Keep methods small and focused
- Document complex logic with clear comments
We have a cloud instance of Coolify (hosted version) with:
- 2 Horizon worker servers
- Thousands of connected servers
- Thousands of active users
- High-availability requirements
When developing features:
- Consider scalability implications
- Test with large datasets
- Implement efficient queries
- Use queues for heavy operations
- Consider rate limiting and resource constraints
- Implement proper error recovery mechanisms
- Always run code formatting:
./vendor/bin/pint - Test your changes:
./vendor/bin/pest - Check for static analysis issues:
./vendor/bin/phpstan - Use existing patterns and helpers
- Follow the established directory structure
- Maintain backward compatibility
- Document breaking changes
- Consider performance impact on large-scale deployments
- App\Models\Application::team must return a relationship instance., always use team()
For more detailed guidelines and patterns, refer to the .cursor/rules/ directory:
- Application Architecture - Detailed application structure
- Deployment Architecture - Deployment patterns and flows
- Database Patterns - Database design and query patterns
- Frontend Patterns - Livewire and Alpine.js patterns
- API & Routing - API design and routing conventions
- Development Workflow - Development best practices
- Security Patterns - Security implementation details
- Form Components - Enhanced form components with authorization
- Testing Patterns - Testing strategies and examples
- Project Overview - High-level project structure
- Technology Stack - Detailed tech stack information
- Cursor Rules Guide - How to maintain cursor rules
===
=== foundation rules ===The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to enhance the user's satisfaction building Laravel applications.
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
- php - 8.4.7
- laravel/fortify (FORTIFY) - v1
- laravel/framework (LARAVEL) - v12
- laravel/horizon (HORIZON) - v5
- laravel/prompts (PROMPTS) - v0
- laravel/sanctum (SANCTUM) - v4
- laravel/socialite (SOCIALITE) - v5
- livewire/livewire (LIVEWIRE) - v3
- laravel/dusk (DUSK) - v8
- laravel/pint (PINT) - v1
- laravel/telescope (TELESCOPE) - v5
- pestphp/pest (PEST) - v3
- phpunit/phpunit (PHPUNIT) - v11
- rector/rector (RECTOR) - v2
- laravel-echo (ECHO) - v2
- tailwindcss (TAILWINDCSS) - v4
- vue (VUE) - v3
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, naming.
- Use descriptive names for variables and methods. For example,
isRegisteredForDiscounts, notdiscount(). - Check for existing components to reuse before writing a new one.
- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important.
- Stick to existing directory structure - don't create new base folders without approval.
- Do not change the application's dependencies without approval.
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run
npm run build,npm run dev, orcomposer run dev. Ask them.
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
- You must only create documentation files if explicitly requested by the user.
=== boost rules ===
- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them.
- Use the
list-artisan-commandstool when you need to call an Artisan command to double check the available parameters.
- Whenever you share a project URL with the user you should use the
get-absolute-urltool to ensure you're using the correct scheme, domain / IP, and port.
- You should use the
tinkertool when you need to execute PHP to debug code or query Eloquent models directly. - Use the
database-querytool when you only need to read from the database.
- You can read browser logs, errors, and exceptions using the
browser-logstool from Boost. - Only recent browser logs will be useful - ignore old logs.
- Boost comes with a powerful
search-docstool you should use before any other approaches. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation specific for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages. - The 'search-docs' tool is perfect for all Laravel related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc.
- You must use this tool to search for Laravel-ecosystem documentation before falling back to other approaches.
- Search the documentation before making code changes to ensure we are taking the correct approach.
- Use multiple, broad, simple, topic based queries to start. For example:
['rate limiting', 'routing rate limiting', 'routing']. - Do not add package names to queries - package information is already shared. For example, use
test resource table, notfilament 4 test resource table.
- You can and should pass multiple queries at once. The most relevant results will be returned first.
- Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'
- Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit"
- Quoted Phrases (Exact Position) - query="infinite scroll" - Words must be adjacent and in that order
- Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit"
- Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms
=== php rules ===
- Always use curly braces for control structures, even if it has one line.
- Use PHP 8 constructor property promotion in
__construct().- public function __construct(public GitHub $github) { }
- Do not allow empty
__construct()methods with zero parameters.
- Always use explicit return type declarations for methods and functions.
- Use appropriate PHP type hints for method parameters.
- Prefer PHPDoc blocks over comments. Never use comments within the code itself unless there is something very complex going on.
- Add useful array shape type definitions for arrays when appropriate.
- Typically, keys in an Enum should be TitleCase. For example:
FavoritePerson,BestLake,Monthly.
=== laravel/core rules ===
- Use
php artisan make:commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using thelist-artisan-commandstool. - If you're creating a generic PHP class, use
artisan make:class. - Pass
--no-interactionto all Artisan commands to ensure they work without user input. You should also pass the correct--optionsto ensure correct behavior.
- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins.
- Use Eloquent models and relationships before suggesting raw database queries
- Avoid
DB::; preferModel::query(). Generate code that leverages Laravel's ORM capabilities rather than bypassing them. - Generate code that prevents N+1 query problems by using eager loading.
- Use Laravel's query builder for very complex database operations.
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using
list-artisan-commandsto check the available options tophp artisan make:model.
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages.
- Check sibling Form Requests to see if the application uses array or string based validation rules.
- Use queued jobs for time-consuming operations with the
ShouldQueueinterface.
- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.).
- When generating links to other pages, prefer named routes and the
route()function.
- Use environment variables only in configuration files - never use the
env()function directly outside of config files. Always useconfig('app.name'), notenv('APP_NAME').
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
- Faker: Use methods such as
$this->faker->word()orfake()->randomDigit(). Follow existing conventions whether to use$this->fakerorfake(). - When creating tests, make use of
php artisan make:test [options] <name>to create a feature test, and pass--unitto create a unit test. Most tests should be feature tests.
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run
npm run buildor ask the user to runnpm run devorcomposer run dev.
=== laravel/v12 rules ===
- Use the
search-docstool to get version specific documentation. - This project upgraded from Laravel 10 without migrating to the new streamlined Laravel file structure.
- This is perfectly fine and recommended by Laravel. Follow the existing structure from Laravel 10. We do not to need migrate to the new Laravel structure unless the user explicitly requests that.
- Middleware typically lives in
app/Http/Middleware/and service providers inapp/Providers/. - There is no
bootstrap/app.phpapplication configuration in a Laravel 10 structure:- Middleware registration happens in
app/Http/Kernel.php - Exception handling is in
app/Exceptions/Handler.php - Console commands and schedule register in
app/Console/Kernel.php - Rate limits likely exist in
RouteServiceProviderorapp/Http/Kernel.php
- Middleware registration happens in
- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost.
- Laravel 11 allows limiting eagerly loaded records natively, without external packages:
$query->latest()->limit(10);.
- Casts can and likely should be set in a
casts()method on a model rather than the$castsproperty. Follow existing conventions from other models.
=== livewire/core rules ===
- Use the
search-docstool to find exact version specific documentation for how to write Livewire & Livewire tests. - Use the
php artisan make:livewire [Posts\\CreatePost]artisan command to create new components - State should live on the server, with the UI reflecting it.
- All Livewire requests hit the Laravel backend, they're like regular HTTP requests. Always validate form data, and run authorization checks in Livewire actions.
-
Livewire components require a single root element.
-
Use
wire:loadingandwire:dirtyfor delightful loading states. -
Add
wire:keyin loops:@foreach ($items as $item) <div wire:key="item-{{ $item->id }}"> {{ $item->name }} </div> @endforeach
-
Prefer lifecycle hooks like
mount(),updatedFoo()) for initialization and reactive side effects:
<code-snippet name="Testing a Livewire component exists within a page" lang="php">
$this->get('/posts/create')
->assertSeeLivewire(CreatePost::class);
</code-snippet>
=== livewire/v3 rules ===
- These things changed in Livewire 2, but may not have been updated in this application. Verify this application's setup to ensure you conform with application conventions.
- Use
wire:model.livefor real-time updates,wire:modelis now deferred by default. - Components now use the
App\Livewirenamespace (notApp\Http\Livewire). - Use
$this->dispatch()to dispatch events (notemitordispatchBrowserEvent). - Use the
components.layouts.appview as the typical layout path (notlayouts.app).
- Use
wire:show,wire:transition,wire:cloak,wire:offline,wire:targetare available for use. Use the documentation to find usage examples.
- Alpine is now included with Livewire, don't manually include Alpine.js.
- Plugins included with Alpine: persist, intersect, collapse, and focus.
- You can listen for
livewire:initto hook into Livewire initialization, andfail.status === 419for the page expiring:
Livewire.hook('message.failed', (message, component) => {
console.error(message);
});
});
=== pint/core rules ===
- You must run
vendor/bin/pint --dirtybefore finalizing changes to ensure your code matches the project's expected style. - Do not run
vendor/bin/pint --test, simply runvendor/bin/pintto fix any formatting issues.
=== pest/core rules ===
- If you need to verify a feature is working, write or update a Unit / Feature test.
- All tests must be written using Pest. Use
php artisan make:test --pest <name>. - You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
- Tests should test all of the happy paths, failure paths, and weird paths.
- Tests live in the
tests/Featureandtests/Unitdirectories. - Pest tests look and behave like this:
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
- To run all tests:
php artisan test. - To run all tests in a file:
php artisan test tests/Feature/ExampleTest.php. - To filter on a particular test name:
php artisan test --filter=testName(recommended after making a change to a related file). - When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing.
- When asserting status codes on a response, use the specific method like
assertForbiddenandassertNotFoundinstead of usingassertStatus(403)or similar, e.g.:
$response->assertSuccessful();
});
- Mocking can be very helpful when appropriate.
- When mocking, you can use the
Pest\Laravel\mockPest function, but always import it viause function Pest\Laravel\mock;before using it. Alternatively, you can use$this->mock()if existing tests do. - You can also create partial mocks using the same import or self method.
- Use datasets in Pest to simplify tests which have a lot of duplicated data. This is often the case when testing validation rules, so consider going with this solution when writing tests for validation rules.
=== tailwindcss/core rules ===
- Use Tailwind CSS classes to style HTML, check and use existing tailwind conventions within the project before writing your own.
- Offer to extract repeated patterns into components that match the project's conventions (i.e. Blade, JSX, Vue, etc..)
- Think through class placement, order, priority, and defaults - remove redundant classes, add classes to parent or child carefully to limit repetition, group elements logically
- You can use the
search-docstool to get exact examples from the official documentation when needed.
-
When listing items, use gap utilities for spacing, don't use margins.
SuperiorMichiganErie
- If existing pages and components support dark mode, new pages and components must support dark mode in a similar way, typically using
dark:.
=== tailwindcss/v4 rules ===
- Always use Tailwind CSS v4 - do not use the deprecated utilities.
corePluginsis not supported in Tailwind v4.- In Tailwind v4, you import Tailwind using a regular CSS
@importstatement, not using the@tailwinddirectives used in v3:
<code-snippet name="Tailwind v4 Import Tailwind Diff" lang="diff"
- @tailwind base;
- @tailwind components;
- @tailwind utilities;
- @import "tailwindcss";
- Tailwind v4 removed deprecated utilities. Do not use the deprecated option - use the replacement.
- Opacity values are still numeric.
| Deprecated | Replacement | |------------+--------------| | bg-opacity-* | bg-black/* | | text-opacity-* | text-black/* | | border-opacity-* | border-black/* | | divide-opacity-* | divide-black/* | | ring-opacity-* | ring-black/* | | placeholder-opacity-* | placeholder-black/* | | flex-shrink-* | shrink-* | | flex-grow-* | grow-* | | overflow-ellipsis | text-ellipsis | | decoration-slice | box-decoration-slice | | decoration-clone | box-decoration-clone |
=== tests rules ===
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
- Run the minimum number of tests needed to ensure code quality and speed. Use
php artisan testwith a specific filename or filter.