Fix bin/publish: use correct .env path for rspade_system Fix bin/publish script: prevent grep exit code 1 from terminating script 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
13 KiB
Executable File
13 KiB
Executable File
Coding Conventions
This document outlines the coding standards and conventions used in RSpade and RSX. Following these conventions ensures consistency across the codebase and compatibility with the framework.
PHP Conventions
Naming Conventions
CRITICAL: This project uses underscore_case for all variables and functions, NOT camelCase.
// CORRECT - Use underscore_case
$user_name = 'John';
$is_active = true;
function get_user_profile() { }
function calculate_total_price() { }
// WRONG - Do not use camelCase
$userName = 'John'; // ❌
$isActive = true; // ❌
function getUserProfile() { } // ❌
function calculateTotalPrice() { } // ❌
Class and File Naming
- Classes: Use PascalCase
- Files: Match class name exactly with
.phpextension - Constants: Use UPPERCASE_WITH_UNDERSCORES
// Class naming
class UserController { } // ✓ PascalCase
class BlogPostManager { } // ✓ PascalCase
class Rsx_Controller { } // ✓ Legacy RSX base classes use underscore
// Constants
const MAX_ATTEMPTS = 5; // ✓
const DEFAULT_CACHE_TTL = 3600; // ✓
Database Conventions
- Tables: Use plural snake_case (e.g.,
users,blog_posts) - Columns: Use snake_case (e.g.,
created_at,user_id) - Foreign Keys: Use
{singular_table}_id(e.g.,user_id,post_id)
// Model with database fields
class BlogPost extends Model
{
protected $table = 'blog_posts'; // plural snake_case
protected $fillable = [
'title',
'content',
'user_id', // foreign key
'published_at', // snake_case
'view_count' // snake_case
];
}
Code Style
RSpade follows PSR-12 with these specific requirements:
namespace App\Models;
use App\RSpade\Core\Database\Models\Rsx_Model_Abstract;
/**
* Blog post model
*
* @property int $id
* @property string $title
* @property string $content
* @property int $user_id
* @property Carbon $created_at
*/
class BlogPost extends Rsx_Model_Abstract
{
protected $fillable = [
'title',
'content',
'user_id',
'status'
];
/**
* Get the author of the post
*
* @return BelongsTo
*/
public function author()
{
return $this->belongsTo(User::class, 'user_id');
}
/**
* Mark post as published
*
* @return bool
*/
public function mark_as_published() // underscore_case method
{
$this->status = 'published';
$this->published_at = now();
return $this->save();
}
/**
* Get formatted title
*
* @return string
*/
public function get_formatted_title() // underscore_case method
{
$max_length = 50;
$title_text = $this->title;
if (strlen($title_text) > $max_length) {
return substr($title_text, 0, $max_length) . '...';
}
return $title_text;
}
}
RSX Attribute Conventions
Attribute Usage
Use PHP 8 attributes for routing, caching, and other decorators:
use App\RSpade\Core\Attributes\{Route, Cache, RateLimit, Middleware};
class UserController extends Rsx_Controller
{
#[Route('/users', methods: ['GET'])]
#[Cache(ttl: 300, tags: ['users'])]
#[RateLimit(max_attempts: 60)]
public function list_users($params)
{
$page_number = $params['page'] ?? 1;
$items_per_page = 20;
return $this->paginate_results($page_number, $items_per_page);
}
#[Route('/users/:id', methods: ['GET'])]
#[Middleware(['auth'])]
public function get_user($params)
{
$user_id = $params['id'];
$include_posts = $params['include_posts'] ?? false;
return $this->load_user_data($user_id, $include_posts);
}
}
Attribute Placement
- Class-level: Applies to all methods in the class
- Method-level: Applies to specific method only
- Multiple attributes: Stack vertically for readability
#[Cors(allowed_origins: ['https://app.example.com'])] // Class-level
#[ApiVersion('v2')] // Class-level
class ApiController extends Rsx_Api
{
#[Route('/api/data', methods: ['GET'])] // Method-level
#[Cache(ttl: 600)] // Method-level
#[RateLimit(max_attempts: 100)] // Method-level
public function get_data($params)
{
// Implementation
}
}
JavaScript Conventions
ES6+ Standards
Use modern JavaScript with ES6+ features:
// Use const/let, arrow functions, destructuring
const process_user_data = (user_data) => {
const { first_name, last_name, email } = user_data;
const full_name = `${first_name} ${last_name}`;
return {
full_name,
email,
display_name: full_name.toLowerCase()
};
};
// Class with static methods for namespacing
class UserManager {
static async load_user(user_id) {
const response = await fetch(`/api/users/${user_id}`);
const user_data = await response.json();
return user_data;
}
static format_user_name(first_name, last_name) {
return `${first_name} ${last_name}`.trim();
}
}
jQuery Usage
Use jQuery for DOM manipulation where appropriate:
$(document).ready(() => {
// Use underscore_case for functions and variables
const init_user_form = () => {
const $form = $('#user_form');
const $submit_button = $form.find('.submit_button');
$submit_button.on('click', async (e) => {
e.preventDefault();
const form_data = get_form_data($form);
await submit_form_data(form_data);
});
};
const get_form_data = ($form) => {
const form_values = {};
$form.find('input, select, textarea').each(function() {
const field_name = $(this).attr('name');
const field_value = $(this).val();
form_values[field_name] = field_value;
});
return form_values;
};
init_user_form();
});
SCSS/CSS Conventions
File Organization
// resources/sass/app.scss
@import 'variables'; // Custom variables
@import 'bootstrap'; // Bootstrap framework
@import 'layout'; // Layout styles
@import 'components'; // Component styles
@import 'pages'; // Page-specific styles
Naming Conventions
Use BEM-style naming with underscores:
// Component naming
.user_card {
padding: 1rem;
border: 1px solid $border_color;
&__header {
font-size: 1.2rem;
margin_bottom: 0.5rem;
}
&__content {
color: $text_color;
}
&--featured {
border_color: $primary_color;
background: $featured_background;
}
}
// Page-specific styles
.page_is_user_profile {
.profile_section {
margin_bottom: 2rem;
}
.profile_stats {
display: flex;
gap: 1rem;
}
}
Database Migration Conventions
Naming
Use descriptive names with timestamps:
// Good migration names
2024_01_15_000001_create_users_table.php
2024_01_15_000002_add_avatar_to_users_table.php
2024_01_15_000003_create_blog_posts_table.php
Structure
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBlogPostsTable extends Migration
{
public function up()
{
Schema::create('blog_posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->unsignedBigInteger('user_id');
$table->enum('status', ['draft', 'published', 'archived']);
$table->datetime('published_at')->nullable();
// Standard tracking columns
$table->unsignedBigInteger('created_by')->nullable();
$table->unsignedBigInteger('updated_by')->nullable();
$table->unsignedBigInteger('deleted_by')->nullable();
$table->timestamps();
$table->softDeletes();
// Indexes
$table->index('user_id');
$table->index('status');
$table->index('published_at');
// Foreign keys
$table->foreign('user_id')->references('id')->on('users');
});
}
public function down()
{
Schema::dropIfExists('blog_posts');
}
}
Testing Conventions
Test Naming
namespace Tests\Unit;
use Tests\TestCase;
class UserServiceTest extends TestCase
{
// Use descriptive test names with underscores
public function test_user_can_be_created()
{
$user_data = [
'name' => 'John Doe',
'email' => 'john@example.com'
];
$user = $this->create_test_user($user_data);
$this->assertNotNull($user->id);
$this->assertEquals('John Doe', $user->name);
}
public function test_user_email_must_be_unique()
{
$existing_user = User::factory()->create([
'email' => 'test@example.com'
]);
$this->expectException(ValidationException::class);
$this->create_user_with_email('test@example.com');
}
}
Documentation Conventions
PHPDoc Comments
/**
* Process user registration
*
* Handles the complete user registration flow including validation,
* user creation, email verification, and initial setup.
*
* @param array $user_data User registration data
* @param bool $send_email Whether to send welcome email
* @return User The created user instance
* @throws ValidationException If validation fails
* @throws RegistrationException If registration cannot be completed
*/
public function process_registration(array $user_data, bool $send_email = true): User
{
// Implementation
}
Inline Comments
Use inline comments sparingly for complex logic:
public function calculate_discount($order_total, $user)
{
$discount_amount = 0;
// Apply loyalty discount for users with 10+ orders
if ($user->order_count >= 10) {
$discount_amount += $order_total * 0.1;
}
// Apply seasonal discount during December
if (date('n') == 12) {
$discount_amount += $order_total * 0.05;
}
// Cap discount at 25% of total
$max_discount = $order_total * 0.25;
return min($discount_amount, $max_discount);
}
Git Commit Conventions
Commit Message Format
<type>: <subject>
<body>
<footer>
Types
- feat: New feature
- fix: Bug fix
- docs: Documentation changes
- style: Code style changes (formatting, missing semicolons, etc.)
- refactor: Code refactoring
- test: Test additions or changes
- chore: Maintenance tasks
Examples
feat: Add user profile image upload
Implemented file upload functionality for user avatars with
automatic resizing and format conversion to WebP.
Closes #123
fix: Correct discount calculation for bulk orders
The previous calculation was not applying the bulk discount
correctly when orders exceeded 100 items.
Environment Configuration
Environment Variables
Use descriptive names in SCREAMING_SNAKE_CASE:
# Application
APP_NAME="RSpade"
APP_ENV=local
APP_DEBUG=true
APP_URL=https://rspade.example.com
# Database
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=rspade
DB_USERNAME=root
DB_PASSWORD=secret
# Cache
CACHE_DRIVER=redis
CACHE_PREFIX=rspade_cache
# RSX Framework
RSX_CACHE_ENABLED=true
RSX_CACHE_TTL=3600
RSX_AUTO_BUILD=true
Error Handling
Exception Messages
Use clear, actionable error messages:
public function process_payment($payment_data)
{
if (!isset($payment_data['amount'])) {
throw new PaymentException(
'Payment amount is required. Please provide a valid amount in the payment_data array.'
);
}
if ($payment_data['amount'] <= 0) {
throw new PaymentException(
sprintf(
'Payment amount must be greater than zero. Received: %s',
$payment_data['amount']
)
);
}
// Process payment...
}
Summary
Key points to remember:
- Always use underscore_case for variables and functions
- Use PascalCase for class names
- Use SCREAMING_SNAKE_CASE for constants
- Follow PSR-12 for general PHP style
- Use PHP 8 attributes for RSX features
- Document complex logic with clear comments
- Write descriptive test names with underscores
- Keep code readable over clever
- Be consistent throughout the codebase