tinyqc/CLAUDE.md
mahdahar 0a96b04bdf feat: Implement Monthly Entry interface and consolidate Entry API controller
- 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
2026-01-21 13:41:37 +07:00

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 SQLSRV driver)
  • 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 conversion
    • findAll(), find(), first() return camelCase keys
    • insert(), update() accept camelCase, convert to snake_case for DB
  • Organized in subdirectories: Master/, Qc/

Controllers (app/Controllers/):

  • PageController - Renders page views with main_layout
  • Api\* - 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-data blocks
  • DaisyUI components for UI

Helpers (app/Helpers/):

  • stringcase_helper.php - camel_to_snake_array(), snake_to_camel_array()
  • The stringcase helper is auto-loaded in BaseController

Database Schema

Tables use soft deletes (deleted_at) and timestamps (created_at, updated_at):

  • dict_depts, dict_tests, dict_controls - Master data
  • control_tests - Control-test associations with QC parameters (mean, sd)
  • results - Daily test results
  • result_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-data for component state (inline or in <script> blocks)
  • Fetch API for AJAX (no jQuery)
  • DaisyUI components for UI
  • Modals with x-show and x-transition
  • window.BASEURL available 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

  1. Don't skip soft deletes (deleted_at)
  2. Don't mix concerns - controllers handle HTTP, models handle data
  3. 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