fix: show UnVal button for validated but incomplete requests
- Update UnVal visibility condition from ISVAL check to VAL1USER && VAL2USER - Fix validated-but-incomplete requests missing the UnVal action button - Align isValidated() function with same logic for consistency - Refactor AGENTS.md formatting
This commit is contained in:
parent
643413c8d3
commit
09a1c6715f
265
AGENTS.md
265
AGENTS.md
@ -1,173 +1,158 @@
|
|||||||
# AGENTS.md
|
# AGENTS.md
|
||||||
|
Guidance for coding agents working in `D:\data\www\gdc_cmod`.
|
||||||
|
|
||||||
This file provides guidance to agents when working with code in this repository.
|
## 1) Repository Summary
|
||||||
|
- Stack: CodeIgniter 4 + PHP 8.1+.
|
||||||
|
- Package manager: Composer.
|
||||||
|
- Test framework: PHPUnit 10 (`phpunit.xml.dist`).
|
||||||
|
- App domain: laboratory workflow (requests, samples, validation, reporting).
|
||||||
|
- Auth: session-based, route filters (`role`, `guest`).
|
||||||
|
- Data sources: SQL Server (`GDC_CMOD.dbo`) + legacy Firebird integration.
|
||||||
|
- Frontend: PHP views with Tailwind/DaisyUI/Alpine assets from `public/`.
|
||||||
|
|
||||||
## Project Overview
|
## 2) Rule Files Check
|
||||||
|
- Cursor rules: not found (`.cursor/rules/` and `.cursorrules` absent).
|
||||||
|
- Copilot rules: not found (`.github/copilot-instructions.md` absent).
|
||||||
|
- If these files are later added, treat them as high-priority instructions.
|
||||||
|
|
||||||
CodeIgniter 4 PHP application for laboratory management (GDC CMOD). Handles specimen tracking, request validation, and result management with role-based access control. SQL Server database with Firebird legacy patient data.
|
## 2.1) Codebase-Memory MCP Workflow (Default)
|
||||||
|
- This repository is indexed in `codebase-memory-mcp` (session project `D-data-www-gdc_cmod`).
|
||||||
## Tool Usage
|
- Before broad architecture analysis, run:
|
||||||
|
- `index_status` (confirm graph is ready)
|
||||||
Always use Serena MCP tools for anything possible:
|
- `get_architecture` for `languages`, `packages`, `layers`, `file_tree`
|
||||||
- Use `serena_find_symbol` instead of grep when looking for classes, methods, or functions
|
- Prefer `search_graph` + `get_code_snippet` + `trace_call_path` for impact/call-chain questions.
|
||||||
- Use `serena_search_for_pattern` instead of grep for code pattern searches
|
- For change impact before commits, use `detect_changes(scope='all'|'branch')`.
|
||||||
- Use `serena_read_file` or `serena_replace_content` instead of Read/Edit tools
|
- Important: results can be noisy due to minified vendor assets in `public/js/*.min.js`.
|
||||||
- Use `serena_find_referencing_symbols` to find where symbols are used
|
- When querying routes/hotspots, scope to app PHP files (`file_pattern='app/**/*.php'`) where possible.
|
||||||
- Use `serena_replace_symbol_body` or `serena_insert_after_symbol` for code modifications
|
|
||||||
- Only use Bash for shell commands (git, composer, php, etc.)
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
|
## 3) Core Commands
|
||||||
```bash
|
```bash
|
||||||
# Run all tests
|
# install deps
|
||||||
composer test
|
composer install
|
||||||
./vendor/bin/phpunit
|
|
||||||
|
|
||||||
# Run single test file
|
# run dev server
|
||||||
./vendor/bin/phpunit tests/unit/HealthTest.php
|
|
||||||
|
|
||||||
# Run single test method
|
|
||||||
./vendor/bin/phpunit tests/unit/HealthTest.php --filter testIsDefinedAppPath
|
|
||||||
|
|
||||||
# Development server
|
|
||||||
php spark serve
|
php spark serve
|
||||||
|
|
||||||
# List all routes
|
# list spark commands
|
||||||
|
php spark
|
||||||
|
|
||||||
|
# list routes (preferred)
|
||||||
|
php spark routes
|
||||||
|
|
||||||
|
# alternate command used in this repo
|
||||||
php spark list
|
php spark list
|
||||||
|
|
||||||
# Create controller/model
|
|
||||||
php spark make:controller Admin
|
|
||||||
php spark make:model User
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## PHP Standards
|
## 4) Test Commands (Use These)
|
||||||
|
```bash
|
||||||
|
# full suite
|
||||||
|
composer test
|
||||||
|
|
||||||
- PHP 8.1+ features (typed properties, match expressions)
|
# full suite (direct)
|
||||||
- Always declare return types for public methods
|
./vendor/bin/phpunit
|
||||||
- No comments unless explaining complex logic
|
|
||||||
- Use `esc()` when outputting user data in views
|
|
||||||
|
|
||||||
## Naming Conventions
|
# windows direct
|
||||||
|
vendor\bin\phpunit
|
||||||
|
|
||||||
| Type | Convention | Example |
|
# single test file
|
||||||
|------|------------|---------|
|
./vendor/bin/phpunit tests/unit/ReportTest.php
|
||||||
| Classes | PascalCase | `Admin`, `UserController` |
|
|
||||||
| Methods/Variables | camelCase | `getUsers()`, `$userId` |
|
|
||||||
| Constants | UPPER_SNAKE_CASE | `DB_HOST` |
|
|
||||||
| Database tables | UPPER_SNAKE_CASE | `GDC_CMOD.dbo.USERS` |
|
|
||||||
| Views | lowercase_underscores | `admin/index.php` |
|
|
||||||
|
|
||||||
## Role-Based Access Control
|
# single test class
|
||||||
|
./vendor/bin/phpunit --filter ReportTest
|
||||||
|
|
||||||
| Role ID | Name | Route Prefix |
|
# single test method
|
||||||
|---------|------|--------------|
|
./vendor/bin/phpunit tests/unit/HealthTest.php --filter testIsDefinedAppPath
|
||||||
| 0 | Superuser | `/superuser` |
|
|
||||||
| 1 | Admin | `/admin` |
|
|
||||||
| 2 | Lab | `/lab` |
|
|
||||||
| 3 | Phlebo | `/phlebo` |
|
|
||||||
| 4 | CS | `/cs` |
|
|
||||||
|
|
||||||
```php
|
# single test directory
|
||||||
// Single role
|
./vendor/bin/phpunit tests/unit
|
||||||
['filter' => 'role:1']
|
|
||||||
// Multiple roles
|
|
||||||
['filter' => 'role:1,2']
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Controller Patterns
|
## 5) Lint / Static Analysis
|
||||||
|
- No dedicated linter/formatter configs were found (`phpcs`, `php-cs-fixer`, `pint`).
|
||||||
```php
|
- No static analysis configs were found (`phpstan`, `psalm`).
|
||||||
namespace App\Controllers;
|
- Use syntax lint for changed PHP files:
|
||||||
|
```bash
|
||||||
class Admin extends BaseController {
|
php -l app/Controllers/RequestsController.php
|
||||||
public function index() { }
|
php -l app/Config/Routes.php
|
||||||
}
|
|
||||||
|
|
||||||
// API Controllers use ResponseTrait
|
|
||||||
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']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
- If you add QA tooling, update this file with exact commands.
|
||||||
|
|
||||||
## Database Operations
|
## 6) Code Organization
|
||||||
|
- Controllers: `app/Controllers` and `app/Controllers/Pages`.
|
||||||
|
- Filters: `app/Filters`, aliases in `app/Config/Filters.php`.
|
||||||
|
- Routes: `app/Config/Routes.php`.
|
||||||
|
- Views: `app/Views/...`.
|
||||||
|
- Tests: `tests/unit`, `tests/database`, `tests/session`, `tests/_support`.
|
||||||
|
- Most DB access uses raw SQL (`\Config\Database::connect()`), not CI models.
|
||||||
|
|
||||||
```php
|
## 7) Style Rules (PHP)
|
||||||
$this->db = \Config\Database::connect();
|
|
||||||
|
|
||||||
// Parameterized queries only
|
### Imports and namespaces
|
||||||
$query = $this->db->query("SELECT * FROM table WHERE id = ?", [$id]);
|
- Keep valid namespace per folder.
|
||||||
$row = $query->getRowArray();
|
- Use `use` imports for frequently referenced classes.
|
||||||
$results = $query->getResultArray();
|
- Remove unused imports.
|
||||||
|
- Keep one class per file.
|
||||||
|
|
||||||
// Transactions
|
### Formatting
|
||||||
$this->db->transBegin();
|
- Prefer 4 spaces in new/edited code.
|
||||||
try {
|
- Existing files may contain mixed tabs/spaces; avoid full-file reformat churn.
|
||||||
$this->db->query("INSERT INTO ...", [$data]);
|
- Keep methods small; extract helpers for complex branching.
|
||||||
$this->db->transCommit();
|
- Keep comments sparse; only explain non-obvious logic.
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$this->db->transRollback();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Request/Response Patterns
|
### Types
|
||||||
|
- Add parameter and return types in new/modified methods when practical.
|
||||||
|
- Prefer explicit casts for session/DB values used in role or numeric logic.
|
||||||
|
- Prefer strict comparisons (`===`, `!==`) over loose comparisons.
|
||||||
|
|
||||||
```php
|
### Naming
|
||||||
// GET input
|
- Classes: `PascalCase`.
|
||||||
$date1 = $this->request->getVar('date1') ?? date('Y-m-d');
|
- Methods/variables: `camelCase`.
|
||||||
|
- Constants: `UPPER_SNAKE_CASE` (`ROLE_NAMES`).
|
||||||
|
- SQL identifiers follow existing DB naming (often uppercase).
|
||||||
|
- Views use existing naming conventions (lowercase/underscores).
|
||||||
|
|
||||||
// POST JSON
|
## 8) Imports, Responses, and Controller Patterns
|
||||||
$input = $this->request->getJSON(true);
|
- API endpoints commonly use `CodeIgniter\API\ResponseTrait`.
|
||||||
|
- JSON responses: `$this->response->setJSON([...])` or `$this->respond([...])`.
|
||||||
|
- HTML responses: `return view('path/to/view', $data);`.
|
||||||
|
- Inputs: `getGet()`, `getPost()`, `getJSON(true)` based on content type.
|
||||||
|
- Validate required inputs early and return errors promptly.
|
||||||
|
|
||||||
// JSON response
|
## 9) SQL and Data Safety
|
||||||
return $this->respond(['data' => $results]);
|
- Prefer parameterized queries for all user/session-controlled values.
|
||||||
return $this->response->setJSON(['message' => 'Success']);
|
- Good: `$db->query('... WHERE ACCESSNUMBER = ?', [$accessNumber]);`
|
||||||
|
- Avoid: SQL string interpolation with raw request/session data.
|
||||||
|
- Use transactions for multi-step writes that must be atomic.
|
||||||
|
- Preserve dual-validation behavior (`ISVAL1/ISVAL2`, two distinct users).
|
||||||
|
- Keep audit logging writes (`AUDIT_EVENTS`, `AUDIT_REQUESTS`) intact when changing flows.
|
||||||
|
|
||||||
// View response
|
## 10) Error Handling and Logging
|
||||||
return view('admin/index', $data);
|
- Return consistent JSON shape for API failures (`status`, `message`).
|
||||||
|
- For external HTTP/cURL calls, check HTTP code and handle failures explicitly.
|
||||||
|
- Use `log_message('error', ...)` for operational failures.
|
||||||
|
- Do not expose secrets, stack traces, or sensitive internals to clients.
|
||||||
|
|
||||||
// Redirect with errors
|
## 11) Security Requirements
|
||||||
return redirect()->back()->with('errors', ['key' => 'message']);
|
- Escape user-facing output in views with `esc()`.
|
||||||
```
|
- Enforce auth + role checks through route filters and session state.
|
||||||
|
- Use `password_hash()` and `password_verify()` for credentials.
|
||||||
|
- Never commit `.env` or secrets.
|
||||||
|
|
||||||
## Session Structure
|
## 12) Role and Routing Conventions
|
||||||
|
- Role IDs:
|
||||||
|
- `0` Superuser
|
||||||
|
- `1` Admin
|
||||||
|
- `2` Lab
|
||||||
|
- `3` Phlebo
|
||||||
|
- `4` CS
|
||||||
|
- Route filter examples:
|
||||||
|
- Single role: `['filter' => 'role:1']`
|
||||||
|
- Multiple roles: `['filter' => 'role:0,1,2']`
|
||||||
|
|
||||||
```php
|
## 13) Agent Change Checklist
|
||||||
session()->set([
|
- Make minimal, targeted changes.
|
||||||
'isLoggedIn' => true,
|
- Do not revert unrelated local modifications.
|
||||||
'userid' => (string) $user['USERID'],
|
- Keep backward compatibility for response payloads unless asked otherwise.
|
||||||
'userroleid' => (int) $user['USERROLEID'],
|
- Run at least one relevant test file after code changes.
|
||||||
'userrole' => (string) $role,
|
- If no tests exist for a changed behavior, add focused tests when feasible.
|
||||||
]);
|
- Update this file when commands/conventions/tooling change.
|
||||||
```
|
|
||||||
|
|
||||||
## Validation Endpoints
|
|
||||||
|
|
||||||
- `POST /api/{resource}/validate/{id}` - validate a record
|
|
||||||
- `DELETE /api/{resource}/validate/{id}` - unvalidate a record
|
|
||||||
|
|
||||||
## Security
|
|
||||||
|
|
||||||
- Use parameterized queries (never interpolate directly)
|
|
||||||
- Hash passwords with `password_hash()` / `password_verify()`
|
|
||||||
- Validate and sanitize all input before use
|
|
||||||
|
|
||||||
## Database Schema
|
|
||||||
|
|
||||||
- Primary: SQL Server (`GDC_CMOD.dbo`)
|
|
||||||
- Legacy: Firebird (`GLENEAGLES` via ODBC)
|
|
||||||
- No CI4 Models - raw SQL queries via `Database::connect()`
|
|
||||||
|
|
||||||
## Dual-Level Validation
|
|
||||||
|
|
||||||
Validation requires 2 different users:
|
|
||||||
1. First: `ISVAL1=1`, `VAL1USER`, `VAL1DATE`
|
|
||||||
2. Second (different user): `ISVAL2=1`, `VAL2USER`, `VAL2DATE`
|
|
||||||
|
|||||||
@ -326,7 +326,7 @@ $canUnval = $userLevel <= 1;
|
|||||||
<ul tabindex="0"
|
<ul tabindex="0"
|
||||||
class="dropdown-content menu bg-base-100 rounded-box z-50 w-48 p-2 shadow-lg border border-base-300 text-xs">
|
class="dropdown-content menu bg-base-100 rounded-box z-50 w-48 p-2 shadow-lg border border-base-300 text-xs">
|
||||||
<?php if ($isAdminSuper): ?>
|
<?php if ($isAdminSuper): ?>
|
||||||
<li x-show="req.ISVAL == 1 && req.ISPENDING != 1">
|
<li x-show="(req.VAL1USER && req.VAL2USER) && req.ISPENDING != 1">
|
||||||
<?php if ($canUnval): ?>
|
<?php if ($canUnval): ?>
|
||||||
<a @click="openUnvalDialog(req.SP_ACCESSNUMBER)" class="text-error hover:bg-error/10">
|
<a @click="openUnvalDialog(req.SP_ACCESSNUMBER)" class="text-error hover:bg-error/10">
|
||||||
<i class="fa fa-times-circle mr-2"></i> UnVal
|
<i class="fa fa-times-circle mr-2"></i> UnVal
|
||||||
|
|||||||
@ -206,7 +206,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
isValidated(item) {
|
isValidated(item) {
|
||||||
return item.ISVAL == 1 && item.ISPENDING != 1;
|
return item.VAL1USER && item.VAL2USER && item.ISPENDING != 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
computeValidatedCount() {
|
computeValidatedCount() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user