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/`).
5.0 KiB
5.0 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 6
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\*- Generic entry API controllers (Dashboard, Report, Entry)Master\*- CRUD for master data (Depts, Tests, Controls)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()
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