- 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
6.0 KiB
6.0 KiB
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
# 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=1not 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
namespace App\Controllers;
class Admin extends BaseController {
public function index() {
// Method body
}
}
API Controllers
- Controllers use
ResponseTraitfor API responses - Use
$this->respond()or$this->response->setJSON()for responses
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
$this->db = \Config\Database::connect();
Query Methods
getRowArray()- returns single row as associative arraygetResultArray()- returns multiple rows as array of arrays- Use parameterized queries to prevent SQL injection
$query = $this->db->query("SELECT * FROM table WHERE id = ?", [$id]);
$row = $query->getRowArray();
$results = $query->getResultArray();
Transactions
$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
$session->set([
'isLoggedIn' => true,
'userid' => (string) $user['USERID'],
'userlevel' => (int) $user['USERLEVEL'],
'userrole' => (string) $role, // 'admin', 'doctor', 'analyst', 'cs'
]);
Session Values
isLoggedIn: booluserid: stringuserlevel: intuserrole: string
Role-Based Access Control
Role Values
1= admin2= doctor (or lab/analyst)3= analyst4= cs (customer service)
Route Filter Syntax
// Single role
['filter' => 'role:1']
// Multiple roles
['filter' => 'role:1,2']
Request/Response Patterns
Getting Input
// 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)
return $this->respond(['data' => $results]);
return $this->response->setJSON(['message' => 'Success']);
View Response (Traditional)
return view('admin/index', $data);
Redirect with Errors
return redirect()->back()->with('errors', ['key' => 'message']);
API Endpoint Patterns
Validation Endpoints
POST /api/{resource}/validate/{id}- validate a recordDELETE /api/{resource}/validate/{id}- unvalidate a record
Route Examples
// 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
try {
// DB operations
} catch (\Throwable $e) {
// Handle error
return $this->response->setJSON(['message' => 'Server error']);
}
Validation Errors
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
// 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 withpassword_verify() - Validate and sanitize all input before use
Helper Functions
Available helpers loaded via helper(['name', 'name2']):
url- URL helpersform- Form helperstext- Text formatting
Database Schema
- Database: SQL Server
- Schema:
dbo - Main database:
GDC_CMOD - Reference database:
glendb - Table naming:
GDC_CMOD.dbo.TABLENAME