chore: cleanup old files and Serena config

This commit is contained in:
mahdahar 2026-03-11 10:05:49 +07:00
parent 3ab2258b1b
commit 643413c8d3
12 changed files with 0 additions and 1002 deletions

1
.serena/.gitignore vendored
View File

@ -1 +0,0 @@
/cache

View File

@ -1,103 +0,0 @@
# Coding Conventions & Standards
## PHP Standards
- PHP 8.1+ features (typed properties, match expressions)
- Always declare return types for public methods
- No comments unless explaining complex logic
- Use `esc()` when outputting user data in views
## Naming Conventions
| Type | Convention | Example |
|------|------------|---------|
| 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` |
| Routes | lowercase | `/admin/users` |
## Controller Patterns
```php
namespace App\Controllers;
class Admin extends BaseController {
public function index() { }
}
// 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']);
}
}
```
## Database Operations
```php
$this->db = \Config\Database::connect();
// Parameterized queries only
$query = $this->db->query("SELECT * FROM table WHERE id = ?", [$id]);
$row = $query->getRowArray();
$results = $query->getResultArray();
// Transactions
$this->db->transBegin();
try {
$this->db->query("INSERT INTO ...", [$data]);
$this->db->transCommit();
} catch (\Throwable $e) {
$this->db->transRollback();
}
```
## Request/Response Patterns
```php
// GET input
$date1 = $this->request->getVar('date1') ?? date('Y-m-d');
// POST JSON
$input = $this->request->getJSON(true);
// JSON response
return $this->respond(['data' => $results]);
return $this->response->setJSON(['message' => 'Success']);
// View response
return view('admin/index', $data);
// Redirect with errors
return redirect()->back()->with('errors', ['key' => 'message']);
```
## Session Structure
```php
session()->set([
'isLoggedIn' => true,
'userid' => (string) $user['USERID'],
'userroleid' => (int) $user['USERROLEID'],
'userrole' => (string) $role,
]);
```
## Security Guidelines
- Use parameterized queries (never interpolate directly)
- Hash passwords with `password_hash()` / `password_verify()`
- Validate and sanitize all input before use
- Use `esc()` when outputting user data in views
## Validation Endpoints
- `POST /api/{resource}/validate/{id}` - validate a record
- `DELETE /api/{resource}/validate/{id}` - unvalidate a record

View File

@ -1,134 +0,0 @@
# Development Commands
## Testing
```bash
# Run all tests
composer test
./vendor/bin/phpunit
# Run single test file
./vendor/bin/phpunit tests/unit/HealthTest.php
# Run single test method
./vendor/bin/phpunit tests/unit/HealthTest.php --filter testIsDefinedAppPath
# Generate code coverage report
./vendor/bin/phpunit --colors --coverage-text=tests/coverage.txt --coverage-html=tests/coverage/ -d memory_limit=1024m
```
## Development Server
```bash
# Start development server
php spark serve
```
## Code Generation (CLI)
```bash
# Create controller
php spark make:controller Admin
# Create model
php spark make:model User
```
## Routing
```bash
# List all routes
php spark list
```
## Git Commands (Windows)
```bash
# Check git status
git status
# Check git diff
git diff
# View recent commits
git log
# Add files to staging
git add .
# Create commit
git commit -m "message"
# Push to remote
git push
# Pull from remote
git pull
```
## File System Commands (Windows)
```bash
# List directory contents
ls
dir
# Change directory
cd directory_name
# Create directory
mkdir directory_name
# Copy files
copy source destination
# Move files
move source destination
# Remove files
del filename
rm filename
# Find files by name
dir /s /b filename
# Search content in files
findstr /s /i "search_term" *.php
```
## CodeIgniter-Specific
```bash
# Clear cache
php spark cache:clear
# Clear view cache
php spark cache:clear
# Install dependencies
composer install
composer update
# Dump autoload
composer dump-autoload
```
## What to do after completing a task
1. **Run tests**
```bash
composer test
```
2. **Check for errors**
- Review any output from tests
- Check for lint errors or warnings
3. **Verify the changes**
- Test the functionality manually
- Check if any routes or filters were affected
4. **Update documentation** (if needed)
- Add new routes to documentation
- Update CHECKLIST.md if it's a new feature
5. **Commit changes** (only when explicitly asked)
```bash
git add .
git commit -m "describe changes"
```
**Important**: Never commit changes unless explicitly asked by the user.

View File

@ -1,38 +0,0 @@
# GDC CMOD - Laboratory Management System
## Purpose
CodeIgniter 4 PHP application for laboratory management (GDC CMOD - Laboratory Request Management System). Handles specimen collection tracking, request validation, and result management with role-based access control.
## Tech Stack
- **Framework**: CodeIgniter 4 (PHP 8.1+)
- **Database**: SQL Server (primary) + Firebird/InterBase (legacy patient data via ODBC)
- **Frontend**: TailwindCSS + DaisyUI 5 + Alpine.js + Font Awesome 7
- **Testing**: PHPUnit 10.x
- **Server**: Windows (XAMPP/IIS)
## Database Architecture
- **Primary DB**: SQL Server (`GDC_CMOD.dbo`) via Microsoft ODBC Driver (MSOLEDBSQL)
- **Legacy DB**: Firebird/InterBase (`GLENEAGLES` via ODBC)
- **Connection**: `\Config\Database::connect()` returns MySQLi connection (configured as SQLSRV)
- **No CI4 Models**: Uses raw SQL queries via `Database::connect()->query()`
## Key Database Tables
- `GDC_CMOD.dbo.USERS` - Users with `USERID`, `USERROLEID`, `PASSWORD`
- `GDC_CMOD.dbo.CM_REQUESTS` - Validation tracking (`ISVAL1`, `ISVAL2`, validation users/dates)
- `GDC_CMOD.dbo.TUBES` - Sample collection status
- `GDC_CMOD.dbo.V_DASHBOARD_DEV` - Dashboard data view
- `glendb.dbo.*` - Legacy Firebird patient data
## Architecture Overview
- **Session-based authentication** with role-based access control (RBAC)
- **Dual-level validation** system requiring 2 different users to validate the same request
- **Role groups** filter middleware for routing control
- **API endpoints** for JSON responses
- **Page controllers** for HTML views
## Current Pending Features (CHECKLIST.md)
- Restrict Print/Save-to-PDF to CS Role only
- Add Dedicated Print Button
- Update PDF Report Metadata (Replace 'Printed By' with validating user's name)
- Reprint Label functionality
- Print Result Audit (Track when result reports are printed/exported)

View File

@ -1,107 +0,0 @@
# Project Structure
## Directory Layout
```
gdc_cmod/
├── app/ # Application code
│ ├── Controllers/ # Controllers (API & Pages)
│ │ ├── Pages/ # Page controllers by role
│ │ │ ├── AdminController.php
│ │ │ ├── CsController.php
│ │ │ ├── LabController.php
│ │ │ ├── PhlebotomistController.php
│ │ │ └── SuperuserController.php
│ │ ├── ApiDashboard.php
│ │ ├── ApiRequestsAuditController.php
│ │ ├── ApiValidateController.php
│ │ ├── AuthController.php
│ │ ├── BaseController.php
│ │ ├── ErrorPage.php
│ │ ├── Home.php
│ │ ├── LabelController.php
│ │ ├── RequestsController.php
│ │ ├── SamplesController.php
│ │ └── UsersController.php
│ ├── Config/ # Configuration
│ │ ├── App.php
│ │ ├── Database.php
│ │ ├── Filters.php # Filter definitions
│ │ ├── Routes.php # Route definitions
│ │ └── ...
│ ├── Database/ # Database configurations
│ ├── Filters/ # Custom filters
│ │ ├── GuestFilter.php
│ │ ├── RoleFilter.php
│ │ └── .gitkeep
│ ├── Helpers/ # Helper functions
│ ├── Language/ # Language files
│ ├── Libraries/ # Custom libraries
│ ├── Models/ # Models (none used in this project)
│ ├── ThirdParty/ # Third-party code
│ └── Views/ # Views
│ ├── admin/ # Admin views
│ ├── cs/ # CS views
│ ├── errors/ # Error pages
│ ├── lab/ # Lab views
│ ├── phlebo/ # Phlebo views
│ ├── shared/ # Shared components
│ ├── superuser/ # Superuser views
│ └── ...
├── public/ # Web root
│ ├── index.php # Front controller
│ ├── .htaccess
│ ├── web.config
│ ├── css/ # Local CSS
│ └── js/ # Local JavaScript
├── tests/ # PHPUnit tests
│ ├── _support/ # Test support files
│ ├── database/ # Database tests
│ ├── session/ # Session tests
│ ├── unit/ # Unit tests
│ └── README.md
├── writable/ # Writeable directories
├── vendor/ # Composer dependencies
├── .env # Environment variables (git ignored)
├── env # Example environment file
├── .gitignore # Git ignore rules
├── AGENTS.md # Agent guidelines (this file)
├── CHECKLIST.md # Feature checklist
├── CLAUDE.md # Claude Code guidelines
├── composer.json # Composer dependencies
├── composer.lock # Locked dependencies
├── phpunit.xml.dist # PHPUnit configuration
├── preload.php # PHP OpCache preload
├── README.md # Project README
├── spark # CodeIgniter CLI tool
└── LICENSE # MIT License
```
## Key Files & Their Purposes
### Configuration
- **app/Config/Database.php** - Database connections (SQL Server + Firebird ODBC)
- **app/Config/Filters.php** - Filter definitions (RoleFilter, GuestFilter)
- **app/Config/Routes.php** - Route definitions (API and page routes)
- **app/Config/App.php** - Application settings (baseURL, etc.)
### Controllers
- **Pages/[Role]Controller.php** - Page controllers for each role
- **Api[Resource]Controller.php** - API controllers for JSON endpoints
- **AuthController.php** - Authentication (login/logout)
- **UsersController.php** - User management API
- **RequestsController.php** - Request validation API
- **SamplesController.php** - Sample collection API
### Filters
- **app/Filters/RoleFilter.php** - Check user role on protected routes
- **app/Filters/GuestFilter.php** - Redirect logged-in users from public pages
### Views
- **views/shared/** - Shared components used across roles
- **views/{role}/** - Role-specific views
- **views/login.php** - Login page
### Tests
- **tests/unit/** - Unit tests (HealthTest, etc.)
- **tests/database/** - Database tests
- **tests/session/** - Session tests

View File

@ -1,104 +0,0 @@
# Role-Based Access Control (RBAC)
## Role Definitions
| Role ID | Name | Route Prefix | Permissions |
|---------|------|--------------|-------------|
| 0 | Superuser | `/superuser` | Full access + Users CRUD |
| 1 | Admin | `/admin` | Full access + Users CRUD |
| 2 | Lab | `/lab` | Request validation, Sample collection |
| 3 | Phlebo | `/phlebo` | Specimen collection, Dashboard |
| 4 | CS | `/cs` | Dashboard, Status Monitoring, Patient Inquiry |
## Route Filtering
### Role Filter
```php
// Single role
['filter' => 'role:1']
// Multiple roles
['filter' => 'role:1,2']
```
### Filter Usage
**app/Filters/RoleFilter.php**
- Checks `session()->get('isLoggedIn')` - redirects to `/login` if not logged in
- Checks role ID against allowed roles from route arguments
- Redirects to `/unauthorized` if role not authorized
**app/Filters/GuestFilter.php**
- Redirects logged-in users to role-based dashboard
- Use for public-only routes (e.g., `/login`)
## Route Prefixes & Controllers
### Superuser (Role 0)
- `/superuser` - Pages\SuperuserController::index
- `/superuser/users` - Pages\SuperuserController::users
- `/superuser/validate` - Pages\SuperuserController::validatePage
### Admin (Role 1)
- `/admin` - Pages\AdminController::index
- `/admin/users` - Pages\AdminController::users
- `/admin/validate` - Pages\AdminController::validationPage
### Lab (Role 2)
- `/lab` - Pages\LabController::index
- `/lab/validate` - Pages\LabController::validationPage
### Phlebo (Role 3)
- `/phlebo` - Pages\PhlebotomistController::index
### CS (Role 4)
- `/cs` - Pages\CsController::index
## Validation System (Dual-Level)
Validation requires 2 different users to validate the same request:
**First Validation:**
- Sets `ISVAL1=1`
- Records `VAL1USER` (username)
- Records `VAL1DATE` (datetime)
**Second Validation (different user):**
- Sets `ISVAL2=1`
- Records `VAL2USER` (username)
- Records `VAL2DATE` (datetime)
**Validation Permission:**
- Available to Role 0, 1, 2 (Superuser, Admin, Lab)
## Unvalidation
- Available to Role 0, 1 (Superuser, Admin)
- Sets `ISVAL1=0` and `ISVAL2=0`, clears validation user/date fields
## Authentication Flow
1. **AuthController::login()** - Verifies credentials against `GDC_CMOD.dbo.USERS`, sets session
2. **RoleFilter** - Runs on protected routes, checks `session()->get('isLoggedIn')` and role ID
3. **GuestFilter** - Runs on public routes, redirects logged-in users to dashboard
## API Endpoint Permissions
### Users Management
- **Access**: Role 0, 1 (Superuser, Admin)
- **Endpoints**: GET, POST, PATCH, DELETE on `/api/users`
### Requests
- **Access**: Role 0, 1, 2, 3, 4 (All Roles)
- **Endpoints**:
- `GET /api/requests` - Dashboard data
- `POST /api/requests/validate/:id` - Validate request
- `DELETE /api/requests/validate/:id` - Unvalidate request
- `GET /api/requests/:id/audit` - Audit trail
### Samples
- **Access**: All Roles for collect/show
- **Unreceive**: Role 0, 1 only
- **Endpoints**:
- `POST /api/samples/collect/:accessnumber` - Mark sample collected
- `GET /api/samples/:accessnumber` - Show sample info
- `DELETE /api/samples/receive/:accessnumber` - Unreceive sample

View File

@ -1,136 +0,0 @@
# Route Patterns
## Route File Structure
File: **app/Config/Routes.php**
## Public Routes
```php
$routes->get('/', 'Home::index');
$routes->get('/login', 'AuthController::loginPage', ['filter' => 'guest']);
$routes->post('/login', 'AuthController::login', ['filter' => 'guest']);
$routes->get('/logout', 'AuthController::logout');
$routes->patch('/setPassword', 'AuthController::setPassword');
```
## Label Routes (Public)
```php
$routes->get('label/coll/(:any)', 'LabelController::coll/$1');
$routes->get('label/dispatch/(:any)/(:any)', 'LabelController::dispatch/$1/$2');
$routes->get('label/all/(:any)', 'LabelController::print_all/$1');
```
## API Routes (Protected by Role Filter)
File: **app/Config/Routes.php** - `$routes->group('api', ...)` block
### Users Management
```php
$routes->group('users', ['filter' => 'role:0,1'], function ($routes) {
$routes->get('', 'UsersController::index'); // Get all users
$routes->post('', 'UsersController::create'); // Create user
$routes->patch('(:any)', 'UsersController::update/$1'); // Update user
$routes->delete('(:any)', 'UsersController::delete/$1'); // Delete user
});
```
### Requests
```php
$routes->group('requests', ['filter' => 'role:0,1,2,3,4'], function ($routes) {
$routes->get('', 'RequestsController::index'); // Dashboard data
$routes->get('(:any)/audit', 'ApiRequestsAuditController::show/$1'); // Audit trail
$routes->post('validate/(:any)', 'RequestsController::val/$1'); // Validate request
$routes->delete('validate/(:any)', 'RequestsController::unval/$1'); // Unvalidate request
});
```
### Validate API
```php
$routes->group('validate', ['filter' => 'role:0,1,2'], function ($routes) {
$routes->get('unvalidated', 'ApiValidateController::unvalidated'); // Get unvalidated requests
});
```
### Samples
```php
$routes->group('samples', function ($routes) {
// Collect & Show - All Roles
$routes->group('', ['filter' => 'role:0,1,2,3,4'], function ($routes) {
$routes->post('collect/(:any)', 'SamplesController::collect/$1');
$routes->get('(:any)', 'SamplesController::show/$1');
});
// Unreceive - Only Superuser (0) and Admin (1)
$routes->group('', ['filter' => 'role:0,1'], function ($routes) {
$routes->delete('receive/(:any)', 'SamplesController::unreceive/$1');
});
});
```
## Page Routes (Protected by Role Filter)
### Superuser (Role 0)
```php
$routes->group('superuser', ['filter' => 'role:0'], function ($routes) {
$routes->get('', 'Pages\SuperuserController::index');
$routes->get('users', 'Pages\SuperuserController::users');
$routes->get('validate', 'Pages\SuperuserController::validatePage');
});
```
### Admin (Role 1)
```php
$routes->group('admin', ['filter' => 'role:1'], function ($routes) {
$routes->get('', 'Pages\AdminController::index');
$routes->get('users', 'Pages\AdminController::users');
$routes->get('validate', 'Pages\AdminController::validationPage');
});
```
### Lab (Role 2)
```php
$routes->group('lab', ['filter' => 'role:2'], function ($routes) {
$routes->get('', 'Pages\LabController::index');
$routes->get('validate', 'Pages\LabController::validationPage');
});
```
### Phlebo (Role 3)
```php
$routes->group('phlebo', ['filter' => 'role:3'], function ($routes) {
$routes->get('', 'Pages\PhlebotomistController::index');
});
```
### CS (Role 4)
```php
$routes->group('cs', ['filter' => 'role:4'], function ($routes) {
$routes->get('', 'Pages\CsController::index');
});
```
## Error Handling
```php
$routes->set404Override(function () {
$response = service('response');
$response->setStatusCode(404);
echo view('errors/notfound');
});
$routes->get('/unauthorized', 'ErrorPage::unauthorized');
```
## Route Filter Order
1. **Before filters** (run before request):
- `forcehttps` - Force HTTPS
- `pagecache` - Web page caching
- `role` - Role-based access (on protected routes)
- `guest` - Guest-only (on public routes)
2. **After filters** (run after response):
- `pagecache` - Web page caching
- `performance` - Performance metrics
- `toolbar` - Debug toolbar
## Route Naming Conventions
- API endpoints: kebab-case, under `/api/` prefix
- Page routes: kebab-case, grouped by role
- Resource endpoints: standard REST pattern (`/resource/{id}`)
- Action endpoints: kebab-case, snake_case for parameters

View File

@ -1,132 +0,0 @@
# the name by which the project can be referenced within Serena
project_name: "gdc_cmod"
# list of languages for which language servers are started; choose from:
# al bash clojure cpp csharp
# csharp_omnisharp dart elixir elm erlang
# fortran fsharp go groovy haskell
# java julia kotlin lua markdown
# matlab nix pascal perl php
# powershell python python_jedi r rego
# ruby ruby_solargraph rust scala swift
# terraform toml typescript typescript_vts vue
# yaml zig
# (This list may be outdated. For the current list, see values of Language enum here:
# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py
# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.)
# Note:
# - For C, use cpp
# - For JavaScript, use typescript
# - For Free Pascal/Lazarus, use pascal
# Special requirements:
# Some languages require additional setup/installations.
# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers
# When using multiple languages, the first language server that supports a given file will be used for that file.
# The first language is the default language and the respective language server will be used as a fallback.
# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
languages:
- php
# the encoding used by text files in the project
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
encoding: "utf-8"
# whether to use project's .gitignore files to ignore files
ignore_all_files_in_gitignore: true
# list of additional paths to ignore in all projects
# same syntax as gitignore, so you can use * and **
ignored_paths: []
# whether the project is in read-only mode
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
# Added on 2025-04-18
read_only: false
# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
# Below is the complete list of tools for convenience.
# To make sure you have the latest list of tools, and to view their descriptions,
# execute `uv run scripts/print_tool_overview.py`.
#
# * `activate_project`: Activates a project by name.
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
# * `create_text_file`: Creates/overwrites a file in the project directory.
# * `delete_lines`: Deletes a range of lines within a file.
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
# * `execute_shell_command`: Executes a shell command.
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
# * `initial_instructions`: Gets the initial instructions for the current project.
# Should only be used in settings where the system prompt cannot be set,
# e.g. in clients you have no control over, like Claude Desktop.
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
# * `insert_at_line`: Inserts content at a given line in a file.
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
# * `list_memories`: Lists memories in Serena's project-specific memory store.
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
# * `read_file`: Reads a file within the project directory.
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
# * `remove_project`: Removes a project from the Serena configuration.
# * `replace_lines`: Replaces a range of lines within a file with new content.
# * `replace_symbol_body`: Replaces the full definition of a symbol.
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
# * `search_for_pattern`: Performs a search for a pattern in the project.
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
# * `switch_modes`: Activates modes by providing a list of their names
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
excluded_tools: []
# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default)
included_optional_tools: []
# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools.
# This cannot be combined with non-empty excluded_tools or included_optional_tools.
fixed_tools: []
# list of mode names to that are always to be included in the set of active modes
# The full set of modes to be activated is base_modes + default_modes.
# If the setting is undefined, the base_modes from the global configuration (serena_config.yml) apply.
# Otherwise, this setting overrides the global configuration.
# Set this to [] to disable base modes for this project.
# Set this to a list of mode names to always include the respective modes for this project.
base_modes:
# list of mode names that are to be activated by default.
# The full set of modes to be activated is base_modes + default_modes.
# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply.
# Otherwise, this overrides the setting from the global configuration (serena_config.yml).
# This setting can, in turn, be overridden by CLI parameters (--mode).
default_modes:
# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ""
# override of the corresponding setting in serena_config.yml, see the documentation there.
# If null or missing, the value from the global config is used.
symbol_info_budget:
# The language backend to use for this project.
# If not set, the global setting from serena_config.yml is used.
# Valid values: LSP, JetBrains
# Note: the backend is fixed at startup. If a project with a different backend
# is activated post-init, an error will be returned.
language_backend:
# list of regex patterns which, when matched, mark a memory entry as readonly.
# Extends the list from the global configuration, merging the two lists.
read_only_memory_patterns: []
# line ending convention to use when writing source files.
# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default)
# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings.
line_ending:

44
TODO.md
View File

@ -1,44 +0,0 @@
# Project Checklist: Glen RME & Lab Management System
**Last Updated:** 20260212
Pending:
- sample other for MCU is annoying
- report2 go to cmod
Completed:
- Update User Role levels (Standardize roles: Superuser, Admin, Lab, Phlebo, CS)
- Role-Based Dashboard Filtering (Filter by patient_status or service_type)
- Fix Table Sorting (Enable sorting by "No Register" and "Patient Name")
- Fix Language Toggle (Toggle lab result preview between Indonesian and English)
- Apply Row Color-Coding (Color-code "No Register" column)
- Initialize RME Sidebar Menu (Create menu items)
- Dashboard Performance (When getting data more than 100 rows, it load too slow)
- Dashboard for Lab -> no test with only number, remove request with empty test
- Dashboard for Others -> complete
- Refactor same views/*role* to views/shared
- Move all CDN to local
- Remove 'status' field on dashboard
- Restrict 'Validate' to Lab, Admin, Superuser
- Hide/Disable 'Validation' button after 2nd validation (Prevent redundant validation actions)
- Restrict 'UnValidate' to Admin, Superuser
- Remove 'UnCollect'
- Audit Trail (Track all actions: validation, unvalidation, collection, uncollection)
- Create Validate Page
- Sync color with old gdc_cmod
- Add Val1 Val2 on the result
- Show Print / PDF button when val1 val2 done
- Restrict Print/Save-to-PDF to CS Role only (Admin, Lab, CS can print/save)
- Add Receive to Audit
- Put all action to dropdown on request / dashboard
- Auto generate PDF on second val
- Validate delay when loading result
- Reprint Label (Add functionality to reprint labels)
- Create Eng Result UI UX on request dashboard
- Test and fix PDF Generation
- Print Result Audit (Track when result reports are printed/exported, log user and timestamp)
- Test and fix Reprint label
- fasten the load of val page
- preview result for validate for su adm lab
- auto generate pdf after 2 val from preview
- add datetime val1 val2

View File

@ -1,29 +0,0 @@
USE [GDC_CMOD]
GO
/****** Object: Table [dbo].[AUDIT_EVENTS] Script Date: 1/23/2026 4:38:31 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[AUDIT_EVENTS](
[ACCESSNUMBER] [varchar](20) NOT NULL,
[EVENT_TYPE] [varchar](20) NOT NULL,
[USERID] [varchar](50) NOT NULL,
[EVENT_AT] [datetime] NOT NULL,
[REASON] [varchar](500) NULL,
CONSTRAINT [PK_AUDIT_EVENTS] PRIMARY KEY CLUSTERED
(
[ACCESSNUMBER] ASC,
[EVENT_TYPE] ASC,
[EVENT_AT] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[AUDIT_EVENTS] ADD DEFAULT (getdate()) FOR [EVENT_AT]
GO

View File

@ -1,172 +0,0 @@
<?php
/**
* Batch PDF Generator CLI Script
* Uses curl to CI4 web endpoint (avoids slow CLI database queries)
*
* Usage: php script.php accessnumbers.txt
*
* Input file format: One accessnumber per line
* Example:
* 202403110001
* 202403110002
* 202403110003
*/
// Check command line arguments
if ($argc < 2) {
echo "Usage: php script.php <accessnumbers_file>\n";
echo "Example: php script.php batch.txt\n\n";
echo "File format: One accessnumber per line\n";
exit(1);
}
$inputFile = $argv[1];
if (!file_exists($inputFile)) {
echo "Error: File not found: $inputFile\n";
exit(1);
}
// Base URL for CI4 endpoint
// Using batch/pdf endpoint (no auth required)
// Dev: localhost/gdc_cmod/ | Prod: glenlis/cmod/
$baseUrl = 'http://localhost/gdc_cmod/batch/pdf';
// Read accessnumbers from file
$lines = file($inputFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if ($lines === false) {
echo "Error: Could not read file: $inputFile\n";
exit(1);
}
$accessnumbers = array_filter(array_map('trim', $lines));
$total = count($accessnumbers);
if ($total === 0) {
echo "Error: No accessnumbers found in file\n";
exit(1);
}
echo "Processing $inputFile\n";
echo "Found $total access number(s) via $baseUrl\n";
echo str_repeat("-", 60) . "\n";
// Statistics
$stats = [
'success' => 0,
'failed' => 0,
'details' => []
];
// Process each accessnumber
foreach ($accessnumbers as $index => $accessnumber) {
$current = $index + 1;
$startTime = microtime(true);
echo "[$current/$total] $accessnumber... ";
try {
$url = "$baseUrl/$accessnumber/pdf";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, true); // Include headers in output
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$redirectUrl = curl_getinfo($ch, CURLINFO_REDIRECT_URL);
$finalUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
$curlError = curl_error($ch);
curl_close($ch);
if ($curlError) {
throw new \Exception("cURL error: $curlError");
}
// Debug: Show redirect info
if ($httpCode !== 200) {
$debug = "HTTP $httpCode";
if ($redirectUrl) {
$debug .= " -> $redirectUrl";
}
if ($finalUrl !== $url) {
$debug .= " (final: $finalUrl)";
}
throw new \Exception($debug);
}
// Remove headers from response body
$headerSize = strpos($response, "\r\n\r\n");
if ($headerSize !== false) {
$response = substr($response, $headerSize + 4);
}
$data = json_decode($response, true);
if (!isset($data['success']) || !$data['success']) {
$error = $data['error'] ?? 'Unknown error';
throw new \Exception($error);
}
$jobId = $data['jobId'] ?? 'unknown';
$lang = $data['lang'] ?? 'Unknown';
$isRegen = $data['isRegen'] ?? false;
$regenText = $isRegen ? ' (regen)' : '';
$elapsed = round((microtime(true) - $startTime) * 1000);
echo "QUEUED (job: $jobId, lang: $lang$regenText, ${elapsed}ms)\n";
$stats['success']++;
$stats['details'][] = [
'accessnumber' => $accessnumber,
'status' => 'success',
'jobId' => $jobId,
'language' => $lang,
'time_ms' => $elapsed
];
} catch (\Exception $e) {
$elapsed = round((microtime(true) - $startTime) * 1000);
echo "FAILED (" . $e->getMessage() . ", ${elapsed}ms)\n";
$stats['failed']++;
$stats['details'][] = [
'accessnumber' => $accessnumber,
'status' => 'failed',
'error' => $e->getMessage(),
'time_ms' => $elapsed
];
}
}
echo str_repeat("-", 60) . "\n";
echo "Complete: " . $stats['success'] . " queued, " . $stats['failed'] . " failed\n";
// Save detailed log
$logFile = 'batch_pdf_' . date('Ymd_His') . '.log';
$logContent = "Batch PDF Generation Log\n";
$logContent .= "Generated: " . date('Y-m-d H:i:s') . "\n";
$logContent .= "Input file: $inputFile\n";
$logContent .= "Endpoint: $baseUrl\n";
$logContent .= "Total: $total, Success: {$stats['success']}, Failed: {$stats['failed']}\n";
$logContent .= str_repeat("-", 60) . "\n";
foreach ($stats['details'] as $detail) {
$logContent .= $detail['accessnumber'] . " | " . $detail['status'];
if (isset($detail['jobId'])) {
$logContent .= " | job: " . $detail['jobId'];
$logContent .= " | lang: " . $detail['language'];
}
if (isset($detail['error'])) {
$logContent .= " | error: " . $detail['error'];
}
$logContent .= " | " . $detail['time_ms'] . "ms\n";
}
file_put_contents($logFile, $logContent);
echo "Log saved to: $logFile\n";
exit($stats['failed'] > 0 ? 1 : 0);

View File

@ -1,2 +0,0 @@
202403110001
202403110002