- Implement Monthly Entry interface with full data entry grid
- Add batch save with validation and statistics for monthly results
- Support daily comments per day per test
- Add result status indicators and validation summaries
- Consolidate Entry API controller
- Refactor EntryApiController to handle both daily/monthly operations
- Add batch save endpoints with comprehensive validation
- Implement statistics calculation for result entries
- Add Control Test master data management
- Create MasterControlsController for CRUD operations
- Add dialog forms for control test configuration
- Implement control-test associations with QC parameters
- Refactor Report API and views
- Implement new report index with Levey-Jennings charts placeholder
- Add monthly report functionality with result statistics
- Include QC summary with mean, SD, and CV calculations
- UI improvements
- Overhaul dashboard with improved layout
- Update daily entry interface with inline editing
- Enhance master data management with DaisyUI components
- Add proper modal dialogs and form validation
- Database and seeding
- Update migration for control_tests table schema
- Remove redundant migration and seed files
- Update seeders with comprehensive test data
- Documentation
- Update CLAUDE.md with comprehensive project documentation
- Add architecture overview and conventions
BREAKING CHANGES:
- Refactored Entry API endpoints structure
- Removed ReportApiController::view() - consolidated into new report index
5.2 KiB
5.2 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commands
# Development server
php spark serve
# Database migrations
php spark migrate # Run pending migrations
php spark migrate:rollback # Rollback last batch
php spark db seed CmodQcSeeder # Seed initial data
# Run tests
./vendor/bin/phpunit # All tests
./vendor/bin/phpunit tests/unit/SomeTest.php # Specific test file
./vendor/bin/phpunit --coverage-html coverage/ # With coverage report
Architecture
This is a CodeIgniter 4 Quality Control management system with:
- Backend: PHP 8.1+, CodeIgniter 4
- Database: SQL Server (uses
SQLSRVdriver) - Frontend: TailwindCSS + Alpine.js + DaisyUI (CDN-based, no build step)
- Testing: PHPUnit 10
- Icons: FontAwesome 7
Key Components
Models (app/Models/):
BaseModel- Custom base model with automatic camelCase/snake_case conversionfindAll(),find(),first()return camelCase keysinsert(),update()accept camelCase, convert to snake_case for DB
- Organized in subdirectories:
Master/,Qc/
Controllers (app/Controllers/):
PageController- Renders page views withmain_layoutApi\*- Consolidated entry API controllers (DashboardApi, EntryApi, ReportApi)Master\*- CRUD for master data (MasterDepts, MasterTests, MasterControls)Qc\*- QC domain controllers (ControlTests, Results, ResultComments)
Views (app/Views/):
- PHP templates extending
layout/main_layout - Alpine.js components in
x-datablocks - DaisyUI components for UI
Helpers (app/Helpers/):
stringcase_helper.php-camel_to_snake_array(),snake_to_camel_array()- The
stringcasehelper is auto-loaded inBaseController
Database Schema
Tables use soft deletes (deleted_at) and timestamps (created_at, updated_at):
dict_depts,dict_tests,dict_controls- Master datacontrol_tests- Control-test associations with QC parameters (mean, sd)results- Daily test resultsresult_comments- Comments per result
Conventions
Case Convention
- Frontend/JS/API: camelCase
- Backend PHP variables: camelCase
- Database: snake_case
- Models handle automatic conversion; use helpers for manual conversions
API Response Format
return $this->respond([
'status' => 'success',
'message' => 'fetch success',
'data' => $rows
], 200);
Controller Pattern
namespace App\Controllers\Master;
use CodeIgniter\API\ResponseTrait;
use App\Controllers\BaseController;
class DeptsController extends BaseController {
use ResponseTrait;
protected $model;
protected $rules;
public function __construct() {
$this->model = new MasterDeptsModel();
$this->rules = ['name' => 'required|min_length[1]'];
}
public function index() {
$keyword = $this->request->getGet('keyword');
$rows = $this->model->search($keyword);
return $this->respond([...], 200);
}
public function create() {
$input = camel_to_snake_array($this->request->getJSON(true));
if (!$this->validate($this->rules)) {
return $this->failValidationErrors($this->validator->getErrors());
}
$id = $this->model->insert($input, true);
return $this->respondCreated(['status' => 'success', 'message' => $id]);
}
}
Model Pattern
namespace App\Models\Master;
use App\Models\BaseModel;
class MasterDeptsModel extends BaseModel {
protected $table = 'dict_depts';
protected $primaryKey = 'dept_id';
protected $allowedFields = ['dept_name', 'deleted_at'];
protected $useTimestamps = true;
protected $useSoftDeletes = true;
public function search(?string $keyword) {
if ($keyword) {
$this->like('dept_name', $keyword);
}
return $this->findAll();
}
}
Routes Pattern
- Page routes:
$routes->get('/path', 'PageController::method'); - API routes:
$routes->group('api', function($routes) { ... }); - API sub-groups:
api/master,api/qc
Frontend Patterns
- Alpine.js
x-datafor component state (inline or in<script>blocks) - Fetch API for AJAX (no jQuery)
- DaisyUI components for UI
- Modals with
x-showandx-transition window.BASEURLavailable globally for API calls- Views access page data via
$pageData['title'],$pageData['userInitials'],$pageData['userName'],$pageData['userRole']
View Template Pattern
<?= $this->extend("layout/main_layout"); ?>
<?= $this->section("content"); ?>
<main x-data="componentName()">
<!-- UI content -->
</main>
<?= $this->endSection(); ?>
<?= $this->section("script"); ?>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data("componentName", () => ({
// state and methods
}));
});
</script>
<?= $this->endSection(); ?>
Things to Avoid
- Don't skip soft deletes (
deleted_at) - Don't mix concerns - controllers handle HTTP, models handle data
- Don't forget case conversion - use helpers or BaseModel
Response Style
- Use emojis in responses where appropriate to add visual appeal 😊
- Keep responses concise and helpful