# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview CLQMS is a Clinical Laboratory Quality Management System built with CodeIgniter 4 (PHP 8.1+) providing a REST API backend for laboratory operations from patient registration through test resulting. The frontend uses Alpine.js views in `app/Views/v2/`. ## Development Commands ```bash # Install dependencies composer install # Run all tests composer test php vendor/bin/phpunit # Run single test file php vendor/bin/phpunit tests/feature/Patients/PatientIndexTest.php # Run single test method php vendor/bin/phpunit tests/feature/Patients/PatientIndexTest.php --filter=testIndexWithoutParams # Run tests with coverage php vendor/bin/phpunit --coverage-html build/logs/html # Run CLI commands php spark help php spark db:seed DBSeeder ``` ## Architecture ### Directory Structure - `app/Controllers/{Domain}/` - API controllers organized by domain (Patient, Organization, Specimen, Result, Test) - `app/Models/{Domain}/` - Domain models - `app/Libraries/Data/*.json` - Static lookup data (gender, order_priority, specimen_type, etc.) - `app/Views/v2/` - Alpine.js frontend views - `app/Database/Migrations/` - 10 consolidated migrations (2026-01-01-*) - `tests/feature/` - API endpoint tests using `FeatureTestTrait` ### Key Patterns **Controller Pattern:** ```php class PatientController extends Controller { use ResponseTrait; protected $db; protected $model; public function __construct() { $this->db = \Config\Database::connect(); $this->model = new PatientModel(); } public function index() { try { $data = $this->model->findAll(); return $this->respond(['status' => 'success', 'data' => $data], 200); } catch (\Exception $e) { return $this->failServerError($e->getMessage()); } } } ``` **Model Pattern:** Models extend `BaseModel` which auto-normalizes dates to/from UTC via `beforeInsert`/`beforeUpdate` callbacks. Use `allowedFields` for mass assignment and `useSoftDeletes = true` with `deletedField = 'DelDate'` for soft deletes. **API Response Format:** ```json // Success {"status": "success", "message": "...", "data": [...]} // Error {"status": "failed", "message": "..."} ``` ### Lookups Library Use `App\Libraries\Lookups` for static dropdown values (loaded from JSON files, cached): ```php use App\Libraries\Lookups; // Get dropdown-formatted data [{value: '1', label: 'Female'}, ...] $gender = Lookups::get('gender'); // Get label by key $label = Lookups::getLabel('gender', '1'); // 'Female' // Clear cache after modifying lookup data Lookups::clearCache(); ``` For dynamic values managed at runtime, use the `/api/valueset*` endpoints instead. ### JWT Authentication Most API endpoints require JWT auth via `AuthFilter`. Public endpoints include `/v2/login`, `/api/demo/*`, `/api/auth/*`. ## Database Conventions | Element | Convention | |---------|------------| | Tables | snake_case (`patient`, `patvisit`) | | Columns | PascalCase (`InternalPID`, `PatientID`) | | Classes | PascalCase (`PatientController`, `BaseModel`) | | Methods/Variables | camelCase (`getPatient()`, `$internalPID`) | Soft deletes use `DelDate` field - never hard delete records. ## Key Routes | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/auth/login` | JWT authentication | | GET/POST | `/api/patient` | Patient CRUD | | GET/POST | `/api/patvisit` | Patient visits | | POST | `/api/ordertest` | Create orders | | POST | `/api/edge/results` | Instrument integration (tiny-edge middleware) | ## Important Notes - All dates normalized to UTC automatically via `BaseModel` - No comments in code unless explicitly requested - Use transactions for multi-table operations - Validate input before DB operations using CodeIgniter validation rules