clqms-be/CLAUDE.md

127 lines
3.9 KiB
Markdown

# 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