# AGENTS.md - AI Agent Guidelines for TinyQC ## Important: Always Use Serena Tools **When editing this codebase, prefer Serena tools over regular file operations:** - Use `find_symbol` to locate code rather than grep/glob when possible - Use `replace_symbol_body` for entire method/class changes - Use `replace_content` with regex for targeted edits - Use `get_symbols_overview` before reading full files - Serena tools provide structured, semantically-aware code editing ## Build/Lint/Test Commands ```bash never start dev server just use the base_url from .env file # Run all tests ./vendor/bin/phpunit composer test # Run single test file ./vendor/bin/phpunit tests/unit/HealthTest.php # Run with coverage ./vendor/bin/phpunit --coverage-html coverage/ # Run specific test method ./vendor/bin/phpunit --filter testMethodName # Run migrations php spark migrate php spark migrate:rollback # Clear cache php spark cache:clear ``` ## Technology Stack | Layer | Technology | |-------|------------| | Backend | CodeIgniter 4 (PHP 8.1+) | | Frontend | Alpine.js + TailwindCSS + DaisyUI | | Database | SQL Server | ## Code Style Guidelines ### PHP **Imports** - Order: CodeIgniter, App namespace, use statements ```php model->findAll(); return $this->respond(['status' => 'success', 'message' => 'fetch success', 'data' => $rows], 200); } catch (\Exception $e) { return $this->failServerError($e->getMessage()); } ``` ### Controllers **Structure** - Extend `BaseController`, use `ResponseTrait` - Define `$model` and `$rules` in `__construct()` - CRUD pattern: `index()`, `show($id)`, `create()`, `update($id)`, `delete($id)` **Input Handling** ```php $input = $this->request->getJSON(true); $input = camel_to_snake_array($input); // Convert before DB ``` **Response Format** ```php return $this->respond([ 'status' => 'success', 'message' => 'fetch success', 'data' => $rows ], 200); ``` **Validation** ```php if (!$this->validate($this->rules)) { return $this->failValidationErrors($this->validator->getErrors()); } ``` ### Models **Structure** - Extend `App\Models\BaseModel` (auto camel/snake conversion) - Always enable: `$useSoftDeletes = true`, `$useTimestamps = true` - Define: `$table`, `$primaryKey`, `$allowedFields` **Example** ```php protected $table = 'results'; protected $primaryKey = 'result_id'; protected $allowedFields = ['control_id', 'test_id', 'res_date', 'res_value']; ``` ### Database Conventions - Primary keys: `{table_singular}_id` (e.g., `result_id`, `control_id`) - Foreign keys: Match referenced PK name - Master tables: Prefix with `master_` - All tables: `created_at`, `updated_at`, `deleted_at` ### Frontend **JavaScript** - No jQuery - use Fetch API - camelCase in JavaScript, snake_case in PHP/DB - Use Alpine.js: `x-data`, `x-model`, `x-show`, `x-for`, `@click` **DaisyUI** - Use DaisyUI components (btn, input, modal, dropdown, etc.) - TailwindCSS for utilities **Base URL** ```javascript const BASEURL = ''; // or window.BASEURL ``` ## File Naming | Component | Pattern | Example | |-----------|---------|---------| | Controller | `PascalCase + Controller` | `ResultsController` | | Model | `PascalCase + Model` | `ResultsModel` | | Migration | `YYYY-MM-DD-XXXXXX_Description.php` | `2026-01-15-000001_Results.php` | | View | `module/action.php` | `entry/daily.php` | ## Things to Avoid - jQuery, over-engineering, skipping soft deletes, hardcoding - Don't mix concerns (Controllers handle HTTP, Models handle data) - Don't forget camel/snake conversion at boundaries - Don't add unnecessary comments ## Post-Change Requirements After changes: run `./vendor/bin/phpunit`, update README.md for new features