- Moved all V2 controllers (Lab, Requests, Samples, Users) to App\Controllers - Removed deprecated role controllers (Admin, Doctor, Analyst, CustomerService) - Simplified routes by removing /v2 prefix - Added AGENTS.md with project conventions and TODO.md with task tracking - Updated README.md with RBAC documentation - Fixed hardcoded dates, status color mappings, and duplicate database calls
268 lines
6.0 KiB
Markdown
268 lines
6.0 KiB
Markdown
# AGENTS.md
|
|
|
|
This file provides guidance to agents when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
This is a CodeIgniter 4 PHP application for a laboratory management system (CMOD). It uses SQL Server database with role-based access control for different user types (admin, doctor/analyst, customer service).
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
# Run all tests
|
|
./vendor/bin/phpunit
|
|
composer test
|
|
|
|
# Run single test file
|
|
./vendor/bin/phpunit tests/unit/HealthTest.php
|
|
|
|
# Run single test method
|
|
./vendor/bin/phpunit tests/unit/HealthTest.php --filter testIsDefinedAppPath
|
|
|
|
# Development server (Linux/Mac)
|
|
php spark serve
|
|
|
|
# List all routes
|
|
php spark list
|
|
|
|
# Create controller
|
|
php spark make:controller Admin
|
|
|
|
# Create model
|
|
php spark make:model User
|
|
```
|
|
|
|
## Code Style Guidelines
|
|
|
|
### PHP Standards
|
|
- Use PHP 8.1+ features (typed properties, match expressions where appropriate)
|
|
- Always declare return types for public methods
|
|
- Use `strict_types=1` not required (CodeIgniter doesn't use it)
|
|
- No comments unless explaining complex logic (per project convention)
|
|
|
|
### Naming Conventions
|
|
- **Classes**: PascalCase (e.g., `Admin`, `UserController`)
|
|
- **Methods**: camelCase (e.g., `index()`, `getUsers()`)
|
|
- **Variables**: camelCase (e.g., `$userId`, `$dataList`)
|
|
- **Constants**: UPPER_SNAKE_CASE (e.g., `DB_HOST`)
|
|
- **Database tables**: UPPER_SNAKE_CASE (e.g., `GDC_CMOD.dbo.USERS`)
|
|
- **Views**: lowercase with underscores (e.g., `admin/index.php`)
|
|
|
|
### Controller Patterns
|
|
|
|
#### Base Controllers
|
|
- All controllers extend `App\Controllers\BaseController`
|
|
- BaseController extends CodeIgniter\Controller
|
|
|
|
```php
|
|
namespace App\Controllers;
|
|
|
|
class Admin extends BaseController {
|
|
public function index() {
|
|
// Method body
|
|
}
|
|
}
|
|
```
|
|
|
|
#### API Controllers
|
|
- Controllers use `ResponseTrait` for API responses
|
|
- Use `$this->respond()` or `$this->response->setJSON()` for responses
|
|
|
|
```php
|
|
namespace App\Controllers;
|
|
|
|
use App\Controllers\BaseController;
|
|
use CodeIgniter\API\ResponseTrait;
|
|
|
|
class Users extends BaseController {
|
|
use ResponseTrait;
|
|
|
|
protected $db;
|
|
|
|
public function __construct() {
|
|
$this->db = \Config\Database::connect();
|
|
helper(['url', 'form', 'text']);
|
|
}
|
|
|
|
public function index() {
|
|
$query = $this->db->query("SELECT * FROM table");
|
|
return $this->respond(['data' => $query->getResultArray()]);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Database Operations
|
|
|
|
#### Connection Pattern
|
|
```php
|
|
$this->db = \Config\Database::connect();
|
|
```
|
|
|
|
#### Query Methods
|
|
- `getRowArray()` - returns single row as associative array
|
|
- `getResultArray()` - returns multiple rows as array of arrays
|
|
- Use parameterized queries to prevent SQL injection
|
|
|
|
```php
|
|
$query = $this->db->query("SELECT * FROM table WHERE id = ?", [$id]);
|
|
$row = $query->getRowArray();
|
|
$results = $query->getResultArray();
|
|
```
|
|
|
|
#### Transactions
|
|
```php
|
|
$this->db->transBegin();
|
|
try {
|
|
$this->db->query("INSERT INTO ...", [$data]);
|
|
$this->db->transCommit();
|
|
} catch (\Throwable $e) {
|
|
$this->db->transRollback();
|
|
return $this->response->setJSON(['message' => 'Error']);
|
|
}
|
|
```
|
|
|
|
### Session Management
|
|
|
|
#### Session Structure
|
|
```php
|
|
$session->set([
|
|
'isLoggedIn' => true,
|
|
'userid' => (string) $user['USERID'],
|
|
'userlevel' => (int) $user['USERLEVEL'],
|
|
'userrole' => (string) $role, // 'admin', 'doctor', 'analyst', 'cs'
|
|
]);
|
|
```
|
|
|
|
#### Session Values
|
|
- `isLoggedIn`: bool
|
|
- `userid`: string
|
|
- `userlevel`: int
|
|
- `userrole`: string
|
|
|
|
### Role-Based Access Control
|
|
|
|
#### Role Values
|
|
- `1` = admin
|
|
- `2` = doctor (or lab/analyst)
|
|
- `3` = analyst
|
|
- `4` = cs (customer service)
|
|
|
|
#### Route Filter Syntax
|
|
```php
|
|
// Single role
|
|
['filter' => 'role:1']
|
|
|
|
// Multiple roles
|
|
['filter' => 'role:1,2']
|
|
```
|
|
|
|
### Request/Response Patterns
|
|
|
|
#### Getting Input
|
|
```php
|
|
// POST data
|
|
$input = $this->request->getJSON(true);
|
|
$userid = $input['userid'];
|
|
|
|
// Query parameters
|
|
$date1 = $this->request->getVar('date1') ?? date('Y-m-d');
|
|
```
|
|
|
|
#### JSON Response (V2 API)
|
|
```php
|
|
return $this->respond(['data' => $results]);
|
|
return $this->response->setJSON(['message' => 'Success']);
|
|
```
|
|
|
|
#### View Response (Traditional)
|
|
```php
|
|
return view('admin/index', $data);
|
|
```
|
|
|
|
#### Redirect with Errors
|
|
```php
|
|
return redirect()->back()->with('errors', ['key' => 'message']);
|
|
```
|
|
|
|
### API Endpoint Patterns
|
|
|
|
#### Validation Endpoints
|
|
- `POST /api/{resource}/validate/{id}` - validate a record
|
|
- `DELETE /api/{resource}/validate/{id}` - unvalidate a record
|
|
|
|
#### Route Examples
|
|
```php
|
|
// Admin routes
|
|
$routes->group('admin', ['filter' => 'role:1'], function($routes) {
|
|
$routes->get('/', 'Admin::index');
|
|
$routes->get('users', 'Admin::users');
|
|
$routes->get('api/users', 'Users::index');
|
|
$routes->post('api/users', 'Users::create');
|
|
});
|
|
|
|
// Lab routes
|
|
$routes->group('lab', ['filter' => 'role:2'], function($routes) {
|
|
$routes->get('/', 'Lab::index');
|
|
$routes->get('api/requests', 'Requests::index');
|
|
});
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
#### Database Operations
|
|
```php
|
|
try {
|
|
// DB operations
|
|
} catch (\Throwable $e) {
|
|
// Handle error
|
|
return $this->response->setJSON(['message' => 'Server error']);
|
|
}
|
|
```
|
|
|
|
#### Validation Errors
|
|
```php
|
|
if ($condition) {
|
|
return $this->response->setJSON(['message' => 'Error message']);
|
|
}
|
|
```
|
|
|
|
### Views
|
|
|
|
#### View Pattern
|
|
- Views are plain PHP files in `app/Views/`
|
|
- Use `<?php echo $variable; ?>` syntax
|
|
- Pass data as associative array
|
|
|
|
```php
|
|
// Controller
|
|
$data['dataList'] = $results;
|
|
return view('admin/index', $data);
|
|
|
|
// View
|
|
<?php foreach ($dataList as $item): ?>
|
|
<tr><td><?= esc($item['name']) ?></td></tr>
|
|
<?php endforeach; ?>
|
|
```
|
|
|
|
### Security
|
|
|
|
- Always use parameterized queries (never interpolate directly)
|
|
- Use `esc()` when outputting user data in views
|
|
- Hash passwords with `password_hash()` and verify with `password_verify()`
|
|
- Validate and sanitize all input before use
|
|
|
|
### Helper Functions
|
|
|
|
Available helpers loaded via `helper(['name', 'name2'])`:
|
|
- `url` - URL helpers
|
|
- `form` - Form helpers
|
|
- `text` - Text formatting
|
|
|
|
### Database Schema
|
|
|
|
- Database: SQL Server
|
|
- Schema: `dbo`
|
|
- Main database: `GDC_CMOD`
|
|
- Reference database: `glendb`
|
|
- Table naming: `GDC_CMOD.dbo.TABLENAME`
|