# RSpade Framework - AI/LLM Development Guide **PURPOSE**: Essential directives for AI/LLM assistants developing RSX applications with RSpade. ## What is RSpade? **Visual Basic-like development for PHP/Laravel.** Think: VB6 apps → VB6 runtime → Windows = RSX apps → RSpade runtime → Laravel. **Philosophy**: Modern anti-modernization. While JavaScript fragments into complexity and React demands quarterly paradigm shifts, RSpade asks: "What if coding was easy again?" Business apps need quick builds and easy maintenance, not bleeding-edge architecture. **Important**: RSpade is built on Laravel but diverges significantly. Do not assume Laravel patterns work in RSX without verification. **Terminology**: **RSpade** = Complete framework | **RSX** = Your application code in `/rsx/` --- ## CRITICAL RULES ### 🔴 RSpade Builds Automatically - NEVER RUN BUILD COMMANDS **RSpade is an INTERPRETED framework** - like Python or PHP, changes are automatically detected and compiled on-the-fly. There is NO manual build step. **ABSOLUTELY FORBIDDEN** (unless explicitly instructed): - `npm run compile` / `npm run build` - **DO NOT EXIST** - `bin/publish` - Creates releases for OTHER developers (not for testing YOUR changes) - `rsx:bundle:compile` - Bundles compile automatically in dev mode - `rsx:manifest:build` - Manifest rebuilds automatically in dev mode - ANY command with "build", "compile", or "publish" **How it works**: 1. Edit JS/SCSS/PHP files 2. Refresh browser 3. Changes are live (< 1 second) **If you find yourself wanting to run build commands**: STOP. You're doing something wrong. Changes are already live. ### 🔴 Framework Updates ```bash php artisan rsx:framework:pull # 5-minute timeout required ``` Updates take 2-5 minutes. Includes code pull, manifest rebuild, bundle recompilation. **For AI: Always use 5-minute timeout.** ### 🔴 Fail Loud - No Silent Fallbacks **ALWAYS fail visibly.** No redundant fallbacks, silent failures, or alternative code paths. ```php // ❌ CATASTROPHIC try { $clean = Sanitizer::sanitize($input); } catch (Exception $e) { $clean = $input; } // DISASTER // ✅ CORRECT $clean = Sanitizer::sanitize($input); // Let it throw ``` **SECURITY-CRITICAL**: If sanitization/validation/auth fails, NEVER continue. Always throw immediately. **NO BLANKET TRY/CATCH**: Use try/catch only for expected failures (file uploads, external APIs, user input parsing). NEVER wrap database operations or entire functions "just in case". ```php // ❌ WRONG - Defensive "on error resume" try { $user->save(); $result = process_data($user); return $result; } catch (Exception $e) { throw new Exception("Failed: " . $e->getMessage(), 0, $e); } // ✅ CORRECT - Let exceptions bubble $user->save(); $result = process_data($user); return $result; ``` Exception handlers format errors for different contexts (Ajax JSON, CLI, HTML). Don't wrap exceptions with generic messages - let them bubble to the global handler. ### 🔴 No Defensive Coding Core classes ALWAYS exist. Never check. ```javascript // ❌ BAD: if (typeof Rsx !== 'undefined') { Rsx.Route(...) } // ✅ GOOD: Rsx.Route(...) ``` ### 🔴 Static-First Philosophy Classes are namespacing tools. Use static unless instances needed (models, resources). Avoid dependency injection. ### 🔴 Git Workflow - Framework is READ-ONLY **NEVER modify `/var/www/html/system/`** - It's like node_modules or the Linux kernel. - **App repo**: `/var/www/html/.git` (you control) - **Framework**: `/var/www/html/system/` (submodule, don't touch) - **Your code**: `/var/www/html/rsx/` (all changes here) **Commit discipline**: ONLY commit when explicitly asked. Commits are milestones, not individual changes. ### 🔴 DO NOT RUN `rsx:clean` **RSpade's cache auto-invalidates on file changes.** Running `rsx:clean` causes 30-60 second rebuilds with zero benefit. **When to use**: Only on catastrophic corruption, after framework updates (automatic), or when explicitly instructed. **Correct workflow**: Edit → Save → Reload browser → See changes (< 1 second) ### 🔴 Trust Code Quality Rules Each `rsx:check` rule has remediation text that tells AI assistants exactly what to do: - Some rules say "fix immediately" - Some rules say "present options and wait for decision" AI should follow the rule's guidance precisely. Rules are deliberately written and well-reasoned. --- ## NAMING CONVENTIONS **Enforced by `rsx:check`**: | Context | Convention | Example | |---------|------------|---------| | PHP Methods/Variables | `underscore_case` | `user_name` | | PHP Classes | `Like_This` | `User_Controller` | | JavaScript Classes | `Like_This` | `User_Card` | | Files | `lowercase_underscore` | `user_controller.php` | | Database Tables | `lowercase_plural` | `users` | | Constants | `UPPERCASE` | `MAX_SIZE` | ### File Prefix Grouping **Critical insight**: Files with the same prefix are conceptually grouped and should stay grouped! When multiple files share a common prefix in the same directory, they form a visual group that indicates they work together. This grouping must be preserved when renaming files. **Example** - `rsx/app/frontend/calendar/`: ``` frontend_calendar_event.scss frontend_calendar_event_controller.php frontend_calendar_event.blade.php frontend_calendar_event.js ``` All share prefix `frontend_calendar_event` → they're a related set! If renaming to remove redundancy, ALL files in the group must be renamed consistently to maintain the visual relationship. **Why this matters**: Developers scan file listings and use shared prefixes to quickly identify which files work together. Breaking this pattern creates cognitive overhead and makes the codebase harder to navigate. **Critical**: Never create same-name different-case files. --- ## DIRECTORY STRUCTURE ``` /var/www/html/ ├── rsx/ # YOUR CODE │ ├── app/ # Modules │ ├── models/ # Database models │ ├── public/ # Static files (web-accessible) │ ├── resource/ # Framework-ignored │ └── theme/ # Global assets └── system/ # FRAMEWORK (read-only) ``` ### Special Directories (Path-Agnostic) **`resource/`** - ANY directory named this is framework-ignored. Store helpers, docs, third-party code. Exception: `/rsx/resource/config/` IS processed. **`public/`** - ANY directory named this is web-accessible, framework-ignored. 5min cache, 30d with `?v=`. ### Path-Agnostic Loading Classes found by name, not path. No imports needed. ```php $user = User_Model::find(1); // Framework finds it // NOT: use Rsx\Models\User_Model; // Auto-generated ``` --- ## CONFIGURATION **Two-tier system**: - **Framework**: `/system/config/rsx.php` (never modify) - **User**: `/rsx/resource/config/rsx.php` (your overrides) Merged via `array_merge_deep()`. Common overrides: `development.auto_rename_files`, `bundle_aliases`, `console_debug`. --- ## ROUTING & CONTROLLERS ```php class Frontend_Controller extends Rsx_Controller_Abstract { #[Auth('Permission::anybody()')] #[Route('/', methods: ['GET'])] public static function index(Request $request, array $params = []) { return rsx_view('Frontend_Index', [ 'bundle' => Frontend_Bundle::render() ]); } } ``` **Rules**: Only GET/POST allowed. Use `:param` syntax. All routes MUST have `#[Auth]`. ### #[Auth] Attribute ```php #[Auth('Permission::anybody()')] // Public #[Auth('Permission::authenticated()')] // Require login #[Auth('Permission::has_role("admin")')] // Custom ``` **Controller-wide**: Add to `pre_dispatch()`. Multiple attributes = all must pass. ### Type-Safe URLs **MANDATORY**: All URLs must be generated using `Rsx::Route()` - hardcoded URLs are forbidden. ```php // PHP - Basic usage Rsx::Route('User_Controller', 'show', ['id' => 123]); Rsx::Route('User_Controller', 'show', 123); // Integer shorthand for 'id' // PHP - With query parameters (third argument) Rsx::Route('Login_Controller', 'logout', ['redirect' => '/dashboard']); // Generates: /logout?redirect=%2Fdashboard // JavaScript (identical syntax) Rsx.Route('User_Controller', 'show', {id: 123}); Rsx.Route('User_Controller', 'show', 123); // Integer shorthand for 'id' Rsx.Route('Login_Controller', 'logout', {redirect: '/dashboard'}); ``` **Query Parameters**: Pass associative array/object as third argument: - Keys become query parameter names - Values are automatically URL-encoded - Framework handles proper URL construction **Enforcement**: `rsx:check` will flag hardcoded URLs like `/login` or `/logout?redirect=...` and require you to use `Rsx::Route()`. Do it right the first time to avoid rework. --- ## BLADE & VIEWS ```blade @rsx_id('Frontend_Index') {{-- Every view starts with this --}} {{-- Adds view class --}} @rsx_include('Component_Name') {{-- Include by name, not path --}} ``` **NO inline styles, scripts, or event handlers** in Blade views: - No `