This commit introduces a complete documentation suite, refactors the API layer for
better consistency, and updates the database schema and seeding logic.
Key Changes:
- Documentation:
- Added `CLAUDE.md` with development guidelines and architecture overview.
- Created `docs/` directory with detailed guides for architecture, development,
and source tree analysis.
- Database & Migrations:
- Implemented `RenameMasterColumns` migration to standardize column naming
(e.g., `name` -> `dept_name`, `name` -> `control_name`).
- Added `CmodQcSeeder` to populate the system with realistic sample data
for depts, controls, tests, and results.
- Backend API:
- Created `DashboardApiController` with `getRecent()` for dashboard stats.
- Created `ReportApiController` for managed reporting access.
- Updated `app/Config/Routes.php` with new API groupings and documentation routes.
- Frontend & Views:
- Refactored master data views (`dept`, `test`, `control`) to use Alpine.js
and the updated API structure.
- Modernized `dashboard.php` and `main_layout.php` with improved UI/UX.
- Infrastructure:
- Updated `.gitignore` to exclude development-specific artifacts (`_bmad/`, `.claude/`).
138 lines
9.2 KiB
PHP
138 lines
9.2 KiB
PHP
<?php
|
|
|
|
namespace App\Database\Seeds;
|
|
|
|
use CodeIgniter\Database\Seeder;
|
|
|
|
class CmodQcSeeder extends Seeder
|
|
{
|
|
public function run()
|
|
{
|
|
// 1. Insert Departments (4 entries)
|
|
$depts = [
|
|
['name' => 'Chemistry'],
|
|
['name' => 'Hematology'],
|
|
['name' => 'Immunology'],
|
|
['name' => 'Urinalysis'],
|
|
];
|
|
$this->db->table('master_depts')->insertBatch($depts);
|
|
$deptIds = $this->db->table('master_depts')->select('dept_id')->get()->getResultArray();
|
|
$deptIdMap = array_column($deptIds, 'dept_id');
|
|
|
|
// 2. Insert Controls (6 entries - 2 per dept for first 3 depts)
|
|
$controls = [
|
|
['dept_id' => $deptIdMap[0], 'name' => 'QC Normal Chemistry', 'lot' => 'QC2024001', 'producer' => 'BioRad', 'exp_date' => '2025-12-31'],
|
|
['dept_id' => $deptIdMap[0], 'name' => 'QC High Chemistry', 'lot' => 'QC2024002', 'producer' => 'BioRad', 'exp_date' => '2025-12-31'],
|
|
['dept_id' => $deptIdMap[1], 'name' => 'QC Normal Hema', 'lot' => 'QC2024003', 'producer' => 'Streck', 'exp_date' => '2025-11-30'],
|
|
['dept_id' => $deptIdMap[1], 'name' => 'QC Low Hema', 'lot' => 'QC2024004', 'producer' => 'Streck', 'exp_date' => '2025-11-30'],
|
|
['dept_id' => $deptIdMap[2], 'name' => 'QC Normal Immuno', 'lot' => 'QC2024005', 'producer' => 'Roche', 'exp_date' => '2025-10-31'],
|
|
['dept_id' => $deptIdMap[3], 'name' => 'QC Normal Urine', 'lot' => 'QC2024006', 'producer' => 'Siemens', 'exp_date' => '2025-09-30'],
|
|
];
|
|
$this->db->table('master_controls')->insertBatch($controls);
|
|
$controlIds = $this->db->table('master_controls')->select('control_id')->get()->getResultArray();
|
|
$controlIdMap = array_column($controlIds, 'control_id');
|
|
|
|
// 3. Insert Tests (10 entries)
|
|
$tests = [
|
|
['dept_id' => $deptIdMap[0], 'name' => 'Glucose', 'unit' => 'mg/dL', 'method' => 'GOD-PAP', 'cva' => 5, 'ba' => 3, 'tea' => 10],
|
|
['dept_id' => $deptIdMap[0], 'name' => 'Creatinine', 'unit' => 'mg/dL', 'method' => 'Jaffe', 'cva' => 4, 'ba' => 2, 'tea' => 8],
|
|
['dept_id' => $deptIdMap[0], 'name' => 'Urea Nitrogen', 'unit' => 'mg/dL', 'method' => 'UREASE', 'cva' => 5, 'ba' => 3, 'tea' => 12],
|
|
['dept_id' => $deptIdMap[0], 'name' => 'Cholesterol', 'unit' => 'mg/dL', 'method' => 'CHOD-PAP', 'cva' => 6, 'ba' => 4, 'tea' => 15],
|
|
['dept_id' => $deptIdMap[1], 'name' => 'WBC', 'unit' => 'x10^3/uL', 'method' => 'Impedance', 'cva' => 8, 'ba' => 5, 'tea' => 20],
|
|
['dept_id' => $deptIdMap[1], 'name' => 'RBC', 'unit' => 'x10^6/uL', 'method' => 'Impedance', 'cva' => 3, 'ba' => 2, 'tea' => 8],
|
|
['dept_id' => $deptIdMap[1], 'name' => 'Hemoglobin', 'unit' => 'g/dL', 'method' => 'Cyanmethemoglobin', 'cva' => 2, 'ba' => 1, 'tea' => 5],
|
|
['dept_id' => $deptIdMap[2], 'name' => 'TSH', 'unit' => 'mIU/L', 'method' => 'ECLIA', 'cva' => 10, 'ba' => 6, 'tea' => 25],
|
|
['dept_id' => $deptIdMap[2], 'name' => 'Free T4', 'unit' => 'ng/dL', 'method' => 'ECLIA', 'cva' => 8, 'ba' => 5, 'tea' => 20],
|
|
['dept_id' => $deptIdMap[3], 'name' => 'Urine Protein', 'unit' => 'mg/dL', 'method' => 'Dipstick', 'cva' => 10, 'ba' => 8, 'tea' => 30],
|
|
];
|
|
$this->db->table('master_tests')->insertBatch($tests);
|
|
$testIds = $this->db->table('master_tests')->select('test_id')->get()->getResultArray();
|
|
$testIdMap = array_column($testIds, 'test_id');
|
|
|
|
// 4. Insert Control-Tests (15 entries - 3 per control for first 5 controls)
|
|
$controlTests = [
|
|
['control_id' => $controlIdMap[0], 'test_id' => $testIdMap[0], 'mean' => 95, 'sd' => 5],
|
|
['control_id' => $controlIdMap[0], 'test_id' => $testIdMap[1], 'mean' => 1.0, 'sd' => 0.05],
|
|
['control_id' => $controlIdMap[0], 'test_id' => $testIdMap[2], 'mean' => 15, 'sd' => 1.2],
|
|
['control_id' => $controlIdMap[1], 'test_id' => $testIdMap[0], 'mean' => 180, 'sd' => 12],
|
|
['control_id' => $controlIdMap[1], 'test_id' => $testIdMap[1], 'mean' => 2.5, 'sd' => 0.15],
|
|
['control_id' => $controlIdMap[1], 'test_id' => $testIdMap[3], 'mean' => 200, 'sd' => 15],
|
|
['control_id' => $controlIdMap[2], 'test_id' => $testIdMap[4], 'mean' => 7.5, 'sd' => 0.6],
|
|
['control_id' => $controlIdMap[2], 'test_id' => $testIdMap[5], 'mean' => 4.8, 'sd' => 0.2],
|
|
['control_id' => $controlIdMap[2], 'test_id' => $testIdMap[6], 'mean' => 14.5, 'sd' => 0.5],
|
|
['control_id' => $controlIdMap[3], 'test_id' => $testIdMap[4], 'mean' => 3.5, 'sd' => 0.3],
|
|
['control_id' => $controlIdMap[3], 'test_id' => $testIdMap[5], 'mean' => 2.5, 'sd' => 0.15],
|
|
['control_id' => $controlIdMap[4], 'test_id' => $testIdMap[7], 'mean' => 2.5, 'sd' => 0.3],
|
|
['control_id' => $controlIdMap[4], 'test_id' => $testIdMap[8], 'mean' => 1.2, 'sd' => 0.1],
|
|
['control_id' => $controlIdMap[5], 'test_id' => $testIdMap[9], 'mean' => 10, 'sd' => 1.5],
|
|
['control_id' => $controlIdMap[0], 'test_id' => $testIdMap[3], 'mean' => 150, 'sd' => 10],
|
|
];
|
|
$this->db->table('control_tests')->insertBatch($controlTests);
|
|
$ctRows = $this->db->table('control_tests')->select('control_test_id, control_id, test_id')->get()->getResultArray();
|
|
|
|
// 5. Insert Results (50 entries - random values around mean)
|
|
$results = [];
|
|
$faker = \Faker\Factory::create();
|
|
$resultDate = date('2024-12-01');
|
|
|
|
// Pre-calculate control_test info for result generation
|
|
$ctInfo = [];
|
|
foreach ($ctRows as $ct) {
|
|
$key = $ct['control_id'] . '-' . $ct['test_id'];
|
|
$ctInfo[$key] = $ct['control_test_id'];
|
|
}
|
|
|
|
$resultCount = 0;
|
|
foreach ($ctRows as $ct) {
|
|
// Generate 3-4 results per control-test
|
|
$numResults = $faker->numberBetween(3, 4);
|
|
|
|
for ($i = 0; $i < $numResults && $resultCount < 50; $i++) {
|
|
// Generate random date within December 2024
|
|
$resDate = date('Y-m-d', strtotime($resultDate . ' +' . $faker->numberBetween(0, 20) . ' days'));
|
|
|
|
// Get mean/sd for value generation
|
|
$mean = $this->db->table('control_tests')
|
|
->where('control_test_id', $ct['control_test_id'])
|
|
->get()
|
|
->getRowArray()['mean'] ?? 100;
|
|
$sd = $this->db->table('control_tests')
|
|
->where('control_test_id', $ct['control_test_id'])
|
|
->get()
|
|
->getRowArray()['sd'] ?? 5;
|
|
|
|
// Generate value within +/- 2-3 SD
|
|
$value = $mean + ($faker->randomFloat(2, -2.5, 2.5) * $sd);
|
|
|
|
$results[] = [
|
|
'control_id' => $ct['control_id'],
|
|
'test_id' => $ct['test_id'],
|
|
'res_date' => $resDate,
|
|
'res_value' => round($value, 2),
|
|
'res_comment' => null,
|
|
'created_at' => date('Y-m-d H:i:s'),
|
|
'updated_at' => date('Y-m-d H:i:s'),
|
|
];
|
|
$resultCount++;
|
|
}
|
|
}
|
|
$this->db->table('results')->insertBatch($results);
|
|
$resultIds = $this->db->table('results')->select('result_id, control_id, test_id, res_date')->get()->getResultArray();
|
|
|
|
// 6. Insert Result Comments (10 entries - monthly comments for various control-test combos)
|
|
$resultComments = [
|
|
['control_id' => $controlIdMap[0], 'test_id' => $testIdMap[0], 'comment_month' => '2024-12', 'com_text' => 'Slight drift observed, instrument recalibrated on 12/15'],
|
|
['control_id' => $controlIdMap[1], 'test_id' => $testIdMap[3], 'comment_month' => '2024-12', 'com_text' => 'High cholesterol values noted, lot change recommended'],
|
|
['control_id' => $controlIdMap[2], 'test_id' => $testIdMap[4], 'comment_month' => '2024-12', 'com_text' => 'WBC controls stable throughout the month'],
|
|
['control_id' => $controlIdMap[3], 'test_id' => $testIdMap[5], 'comment_month' => '2024-12', 'com_text' => 'RBC QC intermittent shift, probe cleaned'],
|
|
['control_id' => $controlIdMap[4], 'test_id' => $testIdMap[7], 'comment_month' => '2024-12', 'com_text' => 'TSH assay maintenance performed on 12/10'],
|
|
['control_id' => $controlIdMap[5], 'test_id' => $testIdMap[9], 'comment_month' => '2024-12', 'com_text' => 'Urine protein controls within range'],
|
|
['control_id' => $controlIdMap[0], 'test_id' => $testIdMap[1], 'comment_month' => '2024-12', 'com_text' => 'Creatinine QC stable, no issues'],
|
|
['control_id' => $controlIdMap[1], 'test_id' => $testIdMap[0], 'comment_month' => '2024-12', 'com_text' => 'Glucose high QC showed consistent elevation, reagent lot changed'],
|
|
['control_id' => $controlIdMap[2], 'test_id' => $testIdMap[6], 'comment_month' => '2024-12', 'com_text' => 'Hemoglobin QC performance acceptable'],
|
|
['control_id' => $controlIdMap[4], 'test_id' => $testIdMap[8], 'comment_month' => '2024-12', 'com_text' => 'Free T4 calibration curve verified'],
|
|
];
|
|
$this->db->table('result_comments')->insertBatch($resultComments);
|
|
}
|
|
}
|