docs: extract ERD documentation and add database schema files

- Remove deprecated valueset migration docs and old project planning files
- Add ERD_EXTRACT.md with complete database table definitions
- Add clqms_database.dbml for database modeling
- Add clqms_database.dbdiagram for visual database design
- Add updated prj_3c.md project documentation
This commit is contained in:
mahdahar 2026-01-15 12:37:37 +07:00
parent 42a5260f9a
commit 351d3b6279
5 changed files with 3897 additions and 23723 deletions

1129
docs/ERD_EXTRACT.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,645 +0,0 @@
# Migration Plan: Valueset VID → VValue
## Overview
Transition from using database `valueset` table (VID as primary key) to the new `App\Libraries\ValueSet` library (VValue as key). This eliminates database joins for lookup values and uses JSON-based static lookup files.
## Current State
- Database `valueset` table with columns: `VID` (PK, INT), `VValue` (VARCHAR), `VDesc` (VARCHAR)
- 30+ places using `->join('valueset', 'valueset.VID = ...')`
- Selects use `valueset.VValue` and `valueset.VDesc` for display text
## Target State
- Use `App\Libraries\ValueSet` library with `getLabel(lookupName, key)` method
- Lookup names use table-prefixed PascalCase (e.g., `patient_Sex`, `test_TestType`, `container_ContainerCapColor`)
- All fields store `VValue` codes directly (e.g., '1', '2', 'M', 'F', 'TEST')
- Remove all `valueset` table joins from queries
- Keep raw field values for codes; use `ValueSet::getLabel()` for display text
- JSON files in `app/Libraries/Data/valuesets/` are already populated
---
## Phase 1: JSON Files Rename
Rename all JSON files in `app/Libraries/Data/valuesets/` to use table-prefixed PascalCase format:
| Old Name | New Name | Source Table | Field |
|----------|----------|--------------|-------|
| `gender.json` | `patient_Sex.json` | patient | Gender |
| `country.json` | `patient_Country.json` | patient | Country |
| `race.json` | `patient_Race.json` | patient | Race |
| `religion.json` | `patient_Religion.json` | patient | Religion |
| `ethnic.json` | `patient_Ethnic.json` | patient | Ethnic |
| `marital_status.json` | `patient_MaritalStatus.json` | patient | MaritalStatus |
| `death_indicator.json` | `patient_DeathIndicator.json` | patient | DeathIndicator |
| `test_type.json` | `test_TestType.json` | testdefsite | TestType |
| `container_cap_color.json` | `container_ContainerCapColor.json` | containerdef | Color |
| `container_class.json` | `container_ContainerClass.json` | containerdef | ConClass |
| `additive.json` | `container_Additive.json` | containerdef | Additive |
| `location_type.json` | `location_LocationType.json` | location | LocType |
| `ws_type.json` | `organization_WorkstationType.json` | workstation | Type |
| `enable_disable.json` | `organization_EnableDisable.json` | workstation | Enable |
| `site_type.json` | `organization_SiteType.json` | site | SiteTypeID |
| `site_class.json` | `organization_SiteClass.json` | site | SiteClassID |
| `numeric_ref_type.json` | `ref_NumericRefType.json` | refnum | NumRefType |
| `range_type.json` | `ref_RangeType.json` | refnum | RangeType |
| `text_ref_type.json` | `ref_TextRefType.json` | reftxt | TxtRefType |
| `reference_type.json` | `test_ReferenceType.json` | testdeftech | RefType |
| `math_sign.json` | `ref_MathSign.json` | refnum | LowSign, HighSign |
| `country.json` | `account_Country.json` | account | Country |
| ... | ... | ... | ... |
All lookup names use `{table}_{Field}` format for clarity and namespace isolation.
---
## Phase 2: Database Schema Migration
### Files to DELETE
| File | Action |
|------|--------|
| `app\Database\Seeds\ValueSetSeeder.php` | DELETE |
| `app\Database\Seeds\ValueSetCountrySeeder.php` | DELETE |
| `app\Database\Seeds\MinimalMasterDataSeeder.php` | DELETE |
| `app\Database\Seeds\PatientSeeder.php` | DELETE |
| `app\Database\Migrations\2025-09-15-130122_ValueSet.php` | DELETE |
### Migration: Modify Columns INT → VARCHAR(10)
**File:** `app\Database\Migrations\2026-01-12-000001_ValuesetVidToVvalue.php`
```php
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class ValuesetVidToVvalue extends Migration
{
public function up()
{
// patient table
$this->forge->modifyColumn('patient', [
'Gender' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'Country' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'Race' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'Religion' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'Ethnic' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'MaritalStatus' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'DeathIndicator' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
]);
// testdefsite table
$this->forge->modifyColumn('testdefsite', [
'TestType' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => false],
]);
// containerdef table
$this->forge->modifyColumn('containerdef', [
'Additive' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'ConClass' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'Color' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
]);
// location table
$this->forge->modifyColumn('location', [
'LocType' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
]);
// workstation table
$this->forge->modifyColumn('workstation', [
'Type' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'Enable' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
]);
// site table
$this->forge->modifyColumn('site', [
'SiteTypeID' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'SiteClassID' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
]);
// account table
$this->forge->modifyColumn('account', [
'Country' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
]);
// refnum table
$this->forge->modifyColumn('refnum', [
'Sex' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'NumRefType' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'RangeType' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'LowSign' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'HighSign' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
]);
// reftxt table
$this->forge->modifyColumn('reftxt', [
'Sex' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'TxtRefType' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
]);
// orderstatus table
$this->forge->modifyColumn('orderstatus', [
'OrderStatus' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => false],
]);
}
public function down()
{
// Revert to INT
$this->forge->modifyColumn('patient', [
'Gender' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'Country' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'Race' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'Religion' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'Ethnic' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'MaritalStatus' => ['type' => 'TINYINT', 'null' => true],
'DeathIndicator' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
]);
$this->forge->modifyColumn('testdefsite', [
'TestType' => ['type' => 'INT', 'null' => false],
]);
$this->forge->modifyColumn('containerdef', [
'Additive' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'ConClass' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'Color' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
]);
$this->forge->modifyColumn('location', [
'LocType' => ['type' => 'INT', 'null' => true],
]);
$this->forge->modifyColumn('workstation', [
'Type' => ['type' => 'TINYINT', 'null' => true],
'Enable' => ['type' => 'INT', 'null' => true],
]);
$this->forge->modifyColumn('site', [
'SiteTypeID' => ['type' => 'INT', 'null' => true],
'SiteClassID' => ['type' => 'INT', 'null' => true],
]);
$this->forge->modifyColumn('account', [
'Country' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
]);
$this->forge->modifyColumn('refnum', [
'Sex' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'NumRefType' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'RangeType' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'LowSign' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'HighSign' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
]);
$this->forge->modifyColumn('reftxt', [
'Sex' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
'TxtRefType' => ['type' => 'INT', 'constraint' => 11, 'null' => true],
]);
$this->forge->modifyColumn('orderstatus', [
'OrderStatus' => ['type' => 'INT', 'null' => false],
]);
}
}
```
**Note:** No data migration needed - dummy data will be lost. This is acceptable for development/testing environments.
---
## Phase 3: Library & Model Updates
### ValueSet Library - Update to read from JSON files
**File:** `app/Libraries/ValueSet.php`
Ensure the library reads from JSON files in `app/Libraries/Data/valuesets/`:
```php
<?php
namespace App\Libraries;
class ValueSet
{
private static $cache = [];
private static function loadFile(string $name): array
{
if (!isset(self::$cache[$name])) {
$path = APPPATH . 'Libraries/Data/valuesets/' . $name . '.json';
if (file_exists($path)) {
$content = file_get_contents($path);
self::$cache[$name] = json_decode($content, true)['values'] ?? [];
} else {
self::$cache[$name] = [];
}
}
return self::$cache[$name];
}
public static function getLabel(string $lookupName, string $key): ?string
{
$values = self::loadFile($lookupName);
foreach ($values as $item) {
if (($item['key'] ?? $item['value'] ?? null) === $key) {
return $item['value'] ?? $item['label'] ?? null;
}
}
return null;
}
public static function getOptions(string $lookupName): array
{
$values = self::loadFile($lookupName);
return array_map(function ($item) {
return [
'key' => $item['key'] ?? '',
'value' => $item['value'] ?? $item['label'] ?? '',
];
}, $values);
}
public static function transformLabels(array $data, array $fieldMappings): array
{
foreach ($data as &$row) {
foreach ($fieldMappings as $field => $lookupName) {
if (isset($row[$field]) && $row[$field] !== null) {
$row[$field . 'Text'] = self::getLabel($lookupName, $row[$field]) ?? '';
}
}
}
return $data;
}
}
```
### ValueSetModel - Deprecate or Repurpose
**File:** `app/Models/ValueSet/ValueSetModel.php`
Options:
1. **Deprecate entirely** - No longer needed after migration
2. **Repurpose for JSON file management** - Read/write to JSON files
3. **Keep as-is for backward compatibility** - If database valuesets are still needed
Recommended: Deprecate and remove references after migration.
---
## Phase 4: Model Changes
### Pattern for Model Updates
**Before:**
```php
$this->select("..., gender.VValue as Gender, gender.VDesc as GenderText")
->join('valueset gender', 'gender.VID = patient.Gender', 'left')
```
**After:**
```php
use App\Libraries\ValueSet;
$this->select("..., patient.Gender");
// After fetching:
$rows = ValueSet::transformLabels($rows, [
'Gender' => 'patient_Sex',
'Country' => 'patient_Country',
'Race' => 'patient_Race',
'Religion' => 'patient_Religion',
'Ethnic' => 'patient_Ethnic',
'DeathIndicator' => 'patient_DeathIndicator',
'MaritalStatus' => 'patient_MaritalStatus',
]);
```
### Models to Modify (8 files)
#### 1. `app/Models/Patient/PatientModel.php`
**Remove:**
- Line 27: `$this->join('valueset vs', 'vs.vid = Gender', 'left');`
- Lines 52-64: All `*.VID as *VID` aliases
- Lines 75-81: All `valueset.*` joins
**Add transformation in `getPatient()`:**
```php
$patient = ValueSet::transformLabels([$patient], [
'Gender' => 'patient_gender',
'Country' => 'patient_country',
'Race' => 'patient_race',
'Religion' => 'patient_religion',
'Ethnic' => 'patient_ethnic',
'DeathIndicator' => 'patient_death_indicator',
'MaritalStatus' => 'patient_marital_status',
])[0];
```
#### 2. `app/Models/Location/LocationModel.php`
**Remove:**
- Lines 18, 30: `->join("valueset v", "v.VID=location.loctype", ...)`
**Add transformation:**
```php
$rows = ValueSet::transformLabels($rows, [
'LocType' => 'location_LocationType',
]);
```
#### 3. `app/Models/Test/TestDefSiteModel.php`
**Remove:**
- Lines 42, 75, 103: `->join("valueset", "valueset.VID=...")`
**Add transformation:**
```php
$rows = ValueSet::transformLabels($rows, [
'TestType' => 'test_TestType',
]);
```
#### 4. `app/Models/Test/TestDefGrpModel.php`
**Remove:**
- Line 32: `->join('valueset vs', 'vs.VID=t.TestType', 'left')`
#### 5. `app/Models/Specimen/ContainerDefModel.php`
**Remove:**
- Lines 20-22, 37-39: All 6 `valueset.*` joins
**Add transformation:**
```php
$rows = ValueSet::transformLabels($rows, [
'Color' => 'container_ContainerCapColor',
'ConClass' => 'container_ContainerClass',
'Additive' => 'container_Additive',
]);
```
#### 6. `app/Models/Organization/SiteModel.php`
**Remove:**
- Lines 38-39: `->join('valueset sitetype'...)` and `->join('valueset siteclass'...)`
**Add transformation:**
```php
$row = ValueSet::transformLabels([$row], [
'SiteTypeID' => 'organization_SiteType',
'SiteClassID' => 'organization_SiteClass',
])[0];
```
#### 7. `app/Models/Organization/AccountModel.php`
**Remove:**
- Line 41: `->join('valueset country'...)`
**Remove from select:**
- Line 36: `country.VID as country`
**Add transformation in controller if needed:**
```php
$rows = ValueSet::transformLabels($rows, [
'Country' => 'account_Country',
]);
```
#### 8. `app/Models/Organization/WorkstationModel.php`
**Remove:**
- Lines 36-37: `->join('valueset wstype'...)` and `->join('valueset enable'...)`
**Add transformation:**
```php
$row = ValueSet::transformLabels([$row], [
'Type' => 'organization_WorkstationType',
'Enable' => 'organization_EnableDisable',
])[0];
```
---
## Phase 5: Controller Changes
### `app/Controllers/TestsController.php`
**Remove:**
- Line 69: `->join("valueset", "valueset.VID=testdefsite.TestType", "left")`
- Line 111: `->join("valueset", "valueset.VID=testdefsite.TestType", "left")`
- Line 140: `->join('valueset vs', 'vs.VID=t.TestType', 'left')`
**Replace `getVValue()` method:**
```php
private function getVValue($vsetID, $vid) {
// DEPRECATED - Use ValueSet::getLabel() instead
return null;
}
```
**Update references from `getVValue()` to `ValueSet::getLabel()`:**
```php
// Before:
'NumRefTypeVValue' => $this->getVValue(46, $r['NumRefType']),
// After:
'NumRefTypeVValue' => \App\Libraries\ValueSet::getLabel('ref_NumericRefType', $r['NumRefType']),
```
**VSetID to Lookup Name Mapping:**
| VSetID | Constant | Lookup Name |
|--------|----------|-------------|
| 44 | `VALUESET_REF_TYPE` | `test_ReferenceType` |
| 45 | `VALUESET_RANGE_TYPE` | `ref_RangeType` |
| 46 | `VALUESET_NUM_REF_TYPE` | `ref_NumericRefType` |
| 47 | `VALUESET_TXT_REF_TYPE` | `ref_TextRefType` |
| 3 | `VALUESET_SEX` | `patient_Sex` |
| 41 | `VALUESET_MATH_SIGN` | `ref_MathSign` |
**Update `getValuesetOptions()` to use JSON:**
```php
private function getValuesetOptions($lookupName)
{
return \App\Libraries\ValueSet::getOptions($lookupName);
}
```
---
## Phase 6: API Endpoints - Replace with JSON-based endpoints
### New API Controller: `app/Controllers/ValueSetApiController.php`
```php
<?php
namespace App\Controllers;
use App\Libraries\ValueSet;
class ValueSetApiController extends \CodeIgniter\Controller
{
use \CodeIgniter\API\ResponseTrait;
public function index(string $lookupName)
{
$data = ValueSet::getOptions($lookupName);
return $this->respond([
'status' => 'success',
'data' => $data
], 200);
}
public function all()
{
$dir = APPPATH . 'Libraries/Data/valuesets/';
$files = glob($dir . '*.json');
$result = [];
foreach ($files as $file) {
$name = basename($file, '.json');
$result[] = [
'name' => $name,
'options' => ValueSet::getOptions($name)
];
}
return $this->respond([
'status' => 'success',
'data' => $result
], 200);
}
}
```
### Update Routes: `app/Config/Routes.php`
```php
$routes->group('api', function ($routes) {
$routes->get('valueset/(:segment)', 'ValueSetApiController::index/$1');
$routes->get('valueset', 'ValueSetApiController::all');
});
```
---
## Phase 7: View Updates
### 1. `app/Views/v2/master/valuesets/valuesets_index.php`
Repurpose to manage JSON-based valuesets instead of database table.
| Before | After |
|--------|-------|
| `fetch(...api/valueset...)` | `fetch(...api/valueset/lookupName...)` |
| Database CRUD operations | File-based CRUD operations |
### 2. `app/Views/v2/master/valuesets/valueset_nested_crud.php`
Repurpose for JSON file management.
### 3. `app/Views/v2/master/valuesets/valueset_dialog.php`
Update for JSON file format.
### 4. `app/Views/v2/master/tests/tests_index.php`
| Before | After |
|--------|-------|
| `type?.VID` | `type?.key` |
| `type?.VValue` | `type?.value` |
| `type?.VDesc` | `type?.label` |
| `{ VID: 1, VValue: 'TEST', ... }` | `{ key: 'TEST', value: 'Test', ... }` |
| `getTypeName(vid)` | `getTypeName(value)` |
| `api/valuesetdef/27` | `api/valueset/test_TestType` |
| Hardcoded fallback: `{ VID: 1, VValue: 'TEST', VDesc: 'Test' }` | `{ key: 'TEST', value: 'Test' }` |
### 5. Additional Views to Update
| View File | Fields to Update | Lookup Name |
|-----------|------------------|-------------|
| `app/Views/v2/patients/patients_index.php` | Gender, Country, Race, Religion, Ethnic, MaritalStatus, DeathIndicator | `patient_*` |
| `app/Views/v2/master/specimen/containers_index.php` | Color, ConClass, Additive | `container_*` |
| `app/Views/v2/master/organization/sites_index.php` | SiteTypeID, SiteClassID | `organization_*` |
| `app/Views/v2/master/organization/workstations_index.php` | Type, Enable | `organization_*` |
| `app/Views/v2/master/organization/accounts_index.php` | Country | `account_Country` |
| `app/Views/v2/master/organization/locations_index.php` | LocType | `location_LocationType` |
---
## Phase 8: Test Files Update
### `tests/feature/ValueSet/ValueSetApiControllerTest.php`
Update tests to use new JSON-based API endpoints.
### `tests/_support/v2/MasterTestCase.php`
Update any valueset-related test data setup.
---
## Testing Checklist
1. **Unit Tests**
- Test `ValueSet::getLabel('patient_Sex', '1')` returns 'Female'
- Test `ValueSet::getLabel('test_TestType', 'TEST')` returns 'Test'
- Test `ValueSet::getOptions('container_ContainerCapColor')` returns correct format
- Test `ValueSet::transformLabels()` with table-prefixed field mappings
2. **Integration Tests**
- Patient CRUD (create, read, update, delete)
- Test definition CRUD
- Location CRUD
- Container definition CRUD
- Organization (site, account, workstation) CRUD
3. **Manual Testing**
- Verify all dropdowns display correct labels
- Verify filtering by valueset fields works
- Verify form submissions save correct VValue codes
---
## Rollback Plan
1. Run migration `down()` to revert column types
2. Restore deleted seeders from git if needed
3. Restore deleted migration file from git
---
## Files Summary
| Phase | Action | Files |
|-------|--------|-------|
| 1 | RENAME | ~50 JSON files in `app/Libraries/Data/valuesets/` |
| 2 | DELETE | 5 seeders, 1 migration |
| 2 | CREATE | 1 migration (column changes) |
| 3 | UPDATE | 1 library (ValueSet.php), ValueSetModel.php deprecation |
| 4 | UPDATE | 8 Model files |
| 5 | UPDATE | 1 Controller, Routes |
| 6 | CREATE | 1 Controller (ValueSetApiController.php) |
| 6 | UPDATE | ~6+ View files |
| 8 | UPDATE | 2+ Test files |
---
## Estimated Effort
- Phase 1 (JSON Rename): 15 minutes
- Phase 2 (Migration): 30 minutes
- Phase 3 (Library + Model): 30 minutes
- Phase 4 (Models): 1.5 hours
- Phase 5 (Controller): 30 minutes
- Phase 6 (API + Views): 2 hours
- Phase 8 (Tests): 30 minutes
- Testing: 1 hour
**Total Estimated Time: ~7 hours**

File diff suppressed because it is too large Load Diff

854
docs/clqms_database.dbml Normal file
View File

@ -0,0 +1,854 @@
// CLQMS Database Schema
// Generated from ERD_EXTRACT.md
// Database Markup Language (DBML) for dbdiagram.io and other tools
// ============================================
// TABLE 1: Organization Structure
// ============================================
Table account {
AccountID int [pk]
AccountName varchar(255)
ParentAccountID int
CreateDate datetime
EndDate datetime
}
Table site {
SiteID int [pk]
AccountID int
SiteName varchar(255)
Location varchar(255)
CreateDate datetime
EndDate datetime
}
Table discipline {
DisciplineID int [pk]
DisciplineName varchar(255)
CreateDate datetime
EndDate datetime
}
Table department {
DepartmentID int [pk]
DepartmentName varchar(255)
DisciplineID int
CreateDate datetime
EndDate datetime
}
Table workstation {
WorkstationID int [pk]
SiteID int
DepartmentID int
WorkstationName varchar(255)
LocalDB boolean
CreateDate datetime
EndDate datetime
}
Table instrument {
InstrumentID int [pk]
SiteID int
WorkstationID int
InstrumentAlias varchar(255)
InstrumentName varchar(255)
InstrumentType varchar(255)
CreateDate datetime
EndDate datetime
}
Table personnel {
PersonnelID int [pk]
SiteID int
PersonnelName varchar(255)
Position varchar(255)
CreateDate datetime
EndDate datetime
}
Table personneldocument {
DocID int [pk]
PersonnelID int
DocType varchar(255)
DocFile blob
ExpiryDate datetime
CreateDate datetime
}
Table personnelaccess {
AccessID int [pk]
PersonnelID int
Role varchar(255)
Permissions text
CreateDate datetime
}
Table location {
LocationID int [pk]
SiteID int
ParentLocationID int
LocationTypeID int
LocationName varchar(255)
CreateDate datetime
EndDate datetime
}
Table locationaddress {
AddressID int [pk]
LocationID int
AddressLine1 varchar(255)
AddressLine2 varchar(255)
City varchar(100)
PostalCode varchar(20)
CreateDate datetime
}
Table patient {
PatientID int [pk]
SiteID int
InternalPID int
FirstName varchar(255)
LastName varchar(255)
DateOfBirth datetime
Sex varchar(10)
Race varchar(50)
Ethnicity varchar(50)
Religion varchar(50)
CreateDate datetime
DelDate datetime
}
Table patientcontact {
ContactID int [pk]
InternalPID int
ContactType varchar(50)
ContactValue varchar(255)
CreateDate datetime
}
Table patientinsurance {
InsuranceID int [pk]
InternalPID int
InsuranceProvider varchar(255)
PolicyNumber varchar(100)
GroupNumber varchar(100)
EffectiveDate datetime
ExpiryDate datetime
CreateDate datetime
}
Table patientvisit {
VisitID int [pk]
InternalPID int
SiteID int
VisitClass varchar(50)
VisitType varchar(50)
VisitDate datetime
DischargeDate datetime
CreateDate datetime
}
Table admission {
AdmissionID int [pk]
VisitID int
PatientID int
SiteID int
AdmissionDate datetime
DischargeDate datetime
ADTCode varchar(50)
ReferringParty varchar(255)
BillingAccount varchar(255)
AttendingDoctor varchar(255)
ReferringDoctor varchar(255)
VitalSigns text
CreateDate datetime
}
Table admissionlocation {
ID int [pk]
AdmissionID int
LocationID int
TransferDate datetime
CreateDate datetime
}
Table testorder {
OrderID varchar(13) [pk]
SiteID int
PatientID int
VisitID int
OrderDate datetime
Urgency varchar(50)
Status varchar(50)
OrderingProvider varchar(255)
ProductionSiteID int
CreateDate datetime
EndDate datetime
}
Table testorderdetail {
OrderDetailID int [pk]
OrderID varchar(13)
TestID int
Priority int
Status varchar(50)
CreateDate datetime
}
Table specimen {
SID varchar(17) [pk]
OrderID varchar(13)
SpecimenDefID int
ParentSID varchar(17)
SpecimenType varchar(50)
SpecimenRole varchar(50)
CollectionDate datetime
CollectionSite int
CollectedBy int
ContainerType varchar(50)
Additive varchar(50)
CollectionMethod varchar(50)
BodySite varchar(50)
SpecimenCondition varchar(50)
Status varchar(50)
CreateDate datetime
EndDate datetime
}
Table specimencollection {
ID int [pk]
SID varchar(17)
Activity varchar(50)
ActivityName varchar(100)
ActRes varchar(50)
LocationID int
EquipmentID int
PersonnelID int
ActivityDate datetime
Notes text
CreateDate datetime
}
Table specimentransport {
TransportID int [pk]
SID varchar(17)
SenderID int
ReceiverID int
TransportDate datetime
Condition text
PackagingID varchar(50)
FromLocation int
ToLocation int
CreateDate datetime
}
Table specimenstorage {
StorageID int [pk]
SID varchar(17)
LocationID int
StorageTemperature decimal(10,2)
StorageDate datetime
ThawCount int
ExpiryDate datetime
CreateDate datetime
}
Table testdef {
TestID int [pk]
TestName varchar(255)
TestCode varchar(50)
LOINCCode varchar(50)
TestType varchar(50)
DisciplineID int
SpecimenTypeID int
ContainerTypeID int
ResultType varchar(50)
ResultUnit varchar(50)
Methodology varchar(255)
CreateDate datetime
EndDate datetime
}
Table testdefsite {
ID int [pk]
TestID int
SiteID int
TestNameLocal varchar(255)
TestCodeLocal varchar(50)
WorkstationID int
InstrumentID int
Active boolean
CreateDate datetime
}
Table testdeftech {
ID int [pk]
TestID int
InstrumentID int
InstrumentTestCode varchar(50)
TestMapping varchar(255)
Active boolean
CreateDate datetime
}
Table calculatedtest {
CalculatedTestID int [pk]
TestID int
Formula text
ParamTestID1 int
ParamTestID2 int
ParamTestID3 int
ParamTestID4 int
CreateDate datetime
}
Table grouptest {
GroupTestID int [pk]
GroupTestName varchar(255)
GroupTestType varchar(50)
CreateDate datetime
}
Table grouptestmember {
ID int [pk]
GroupTestID int
TestID int
Sequence int
CreateDate datetime
}
Table panel {
PanelID int [pk]
PanelName varchar(255)
PanelType varchar(50)
ParentPanelID int
DisciplineID int
CreateDate datetime
EndDate datetime
}
Table panelmember {
ID int [pk]
PanelID int
TestID int
Sequence int
CreateDate datetime
}
Table referencerangenumeric {
RefRangeID int [pk]
TestID int
AgeFrom int
AgeTo int
Sex varchar(10)
LowValue decimal(10,2)
HighValue decimal(10,2)
Unit varchar(20)
SpecimenTypeID int
SiteID int
EffectiveDate datetime
ExpiryDate datetime
CreateDate datetime
}
Table referencerangethreshold {
RefRangeID int [pk]
TestID int
AgeFrom int
AgeTo int
Sex varchar(10)
CutOffLow decimal(10,2)
CutOffHigh decimal(10,2)
GrayZoneLow decimal(10,2)
GrayZoneHigh decimal(10,2)
SpecimenTypeID int
SiteID int
EffectiveDate datetime
ExpiryDate datetime
CreateDate datetime
}
Table referencerangetext {
RefRangeID int [pk]
TestID int
AgeFrom int
AgeTo int
Sex varchar(10)
TextValue text
SpecimenTypeID int
SiteID int
EffectiveDate datetime
ExpiryDate datetime
CreateDate datetime
}
Table calibrator {
CalibratorID int [pk]
CalibratorName varchar(255)
Manufacturer varchar(255)
LotNumber varchar(50)
ExpiryDate datetime
TestID int
CreateDate datetime
}
Table calibration {
CalibrationID int [pk]
InstrumentID int
TestID int
CalibratorID int
Level int
CalibrationDate datetime
Factor decimal(10,4)
Absorbance decimal(10,4)
TargetValue decimal(10,4)
TargetUnit varchar(20)
PersonnelID int
Status varchar(50)
CreateDate datetime
}
Table calparinst {
CalParInstID int [pk]
EquipmentID int
Calibrator varchar(255)
LotNo varchar(50)
ExpiryDate datetime
TestInstID1 int
SampleType varchar(50)
Level int
Concentration decimal(10,4)
CalUnit varchar(20)
CreateDate datetime
}
Table qcmaterial {
QCMaterialID int [pk]
MaterialName varchar(255)
Manufacturer varchar(255)
LotNumber varchar(50)
ExpiryDate datetime
Level int
TestID int
TargetMean decimal(10,4)
TargetSD decimal(10,4)
TargetCV decimal(10,4)
CreateDate datetime
}
Table qcresult {
QCResultID int [pk]
InstrumentID int
TestID int
QCMaterialID int
Level int
QCDate datetime
ResultValue decimal(10,4)
Mean decimal(10,4)
SD decimal(10,4)
CV decimal(10,4)
Sigma decimal(10,4)
ZScore decimal(10,4)
Flag varchar(10)
PersonnelID int
Status varchar(50)
CreateDate datetime
}
Table qcstatistic {
StatisticID int [pk]
InstrumentID int
TestID int
QCMaterialID int
Level int
StatisticDate datetime
Mean decimal(10,4)
SD decimal(10,4)
CV decimal(10,4)
SampleSize int
CreateDate datetime
}
Table patres {
ResultID int [pk]
SID varchar(17)
TestID int
OrderID varchar(13)
ResultValue varchar(100)
ResultNumeric decimal(15,5)
ResultText text
ResultUnit varchar(20)
ResultStatus varchar(50)
PersonnelID int
VerificationDate datetime
VerificationPersonnel int
CreateDate datetime
EndDate datetime
}
Table patrestech {
TechResultID int [pk]
ResultID int
InstrumentID int
RawResult text
ResultDate datetime
RerunCount int
Dilution decimal(10,4)
CreateDate datetime
}
Table patresflag {
FlagID int [pk]
ResultID int
FlagType varchar(10)
FlagDescription varchar(255)
CreateDate datetime
}
Table resultdistribution {
DistributionID int [pk]
ResultID int
RecipientType varchar(50)
RecipientID int
DistributionDate datetime
DistributionMethod varchar(50)
Status varchar(50)
CreateDate datetime
}
Table valuesetmember {
MemberID int [pk]
ValueSetID int
MemberCode varchar(50)
MemberValue varchar(255)
DisplayOrder int
Active boolean
CreateDate datetime
}
Table reagent {
ReagentID int [pk]
ReagentName varchar(255)
Manufacturer varchar(255)
CatalogNumber varchar(100)
LotNumber varchar(50)
ExpiryDate datetime
TestID int
InstrumentID int
CreateDate datetime
}
Table reagentusage {
UsageID int [pk]
ReagentID int
TestID int
UsageDate datetime
QuantityUsed decimal(10,2)
PersonnelID int
OrderID varchar(13)
SID varchar(17)
CreateDate datetime
}
Table product {
ProductID int [pk]
CatalogID int
SiteID int
LotNumber varchar(50)
ExpiryDate datetime
Quantity int
ReorderLevel int
LocationID int
CreateDate datetime
}
Table inventorytransaction {
TransactionID int [pk]
ProductID int
TransactionType varchar(50)
Quantity int
TransactionDate datetime
PersonnelID int
ReferenceID varchar(100)
Notes text
CreateDate datetime
}
Table equipment {
EquipmentID int [pk]
EquipmentName varchar(255)
EquipmentType varchar(50)
Manufacturer varchar(255)
Model varchar(100)
SerialNumber varchar(100)
SiteID int
LocationID int
Status varchar(50)
InstallDate datetime
DecommissionDate datetime
CreateDate datetime
}
Table equipmentmaintenance {
MaintenanceID int [pk]
EquipmentID int
MaintenanceType varchar(100)
MaintenanceDate datetime
Description text
PerformedBy varchar(255)
NextMaintenanceDate datetime
CreateDate datetime
}
Table equipmentactivity {
ActivityID int [pk]
EquipmentID int
ActivityType varchar(100)
ActivityDate datetime
ActivityResult varchar(50)
PersonnelID int
Notes text
CreateDate datetime
}
Table equipmenttestcount {
ID int [pk]
EquipmentID int
TestDate datetime
TestType varchar(50)
TestCount int
CreateDate datetime
}
Table doctor {
DoctorID int [pk]
DoctorName varchar(255)
DoctorCode varchar(50)
Specialty varchar(100)
SIP varchar(50)
PracticeLocation varchar(255)
ContactID int
CreateDate datetime
EndDate datetime
}
Table contactdetail {
DetailID int [pk]
ContactID int
DetailType varchar(50)
DetailValue varchar(255)
CreateDate datetime
}
Table auditarchive {
ArchiveID int [pk]
AuditID int
ArchiveDate datetime
ArchiveLocation varchar(255)
CreateDate datetime
}
Table user {
UserID int [pk]
Username varchar(100)
PasswordHash varchar(255)
PersonnelID int
Role varchar(50)
Status varchar(20)
LastLogin datetime
CreateDate datetime
}
Table usersession {
SessionID int [pk]
UserID int
SessionToken varchar(255)
ExpiryDate datetime
IPAddress varchar(50)
CreateDate datetime
}
Table reporttemplate {
TemplateID int [pk]
TemplateName varchar(255)
TemplateType varchar(50)
DisciplineID int
TemplateConfig text
CreateDate datetime
EndDate datetime
}
Table reportoutput {
OutputID int [pk]
TemplateID int
OrderID varchar(13)
OutputFormat varchar(50)
OutputData blob
GeneratedDate datetime
PersonnelID int
CreateDate datetime
}
Table hosttestmapping {
MappingID int [pk]
HostID int
HostTestCode varchar(50)
LocalTestID int
CreateDate datetime
}
Table hostsynclog {
LogID int [pk]
HostID int
SyncDate datetime
RecordsProcessed int
Errors int
Status varchar(20)
Details text
CreateDate datetime
}
// ============================================
// RELATIONSHIPS
// ============================================
// Organization Structure
Ref: account.ParentAccountID > account.AccountID [delete: cascade]
Ref: site.AccountID > account.AccountID
Ref: department.DisciplineID > discipline.DisciplineID
Ref: workstation.SiteID > site.SiteID
Ref: workstation.DepartmentID > department.DepartmentID
Ref: instrument.SiteID > site.SiteID
Ref: instrument.WorkstationID > workstation.WorkstationID
// Personnel
Ref: personnel.SiteID > site.SiteID
Ref: personneldocument.PersonnelID > personnel.PersonnelID
Ref: personnelaccess.PersonnelID > personnel.PersonnelID
// Location Management
Ref: location.SiteID > site.SiteID
Ref: location.ParentLocationID > location.LocationID
Ref: locationaddress.LocationID > location.LocationID
// Patient Registration
Ref: patient.SiteID > site.SiteID
Ref: patientcontact.InternalPID > patient.InternalPID
Ref: patientinsurance.InternalPID > patient.InternalPID
Ref: patientvisit.InternalPID > patient.InternalPID
Ref: patientvisit.SiteID > site.SiteID
// Patient Admission
Ref: admission.VisitID > patientvisit.VisitID
Ref: admission.PatientID > patient.PatientID
Ref: admission.SiteID > site.SiteID
Ref: admissionlocation.AdmissionID > admission.AdmissionID
Ref: admissionlocation.LocationID > location.LocationID
// Test Ordering
Ref: testorder.SiteID > site.SiteID
Ref: testorder.PatientID > patient.PatientID
Ref: testorder.VisitID > patientvisit.VisitID
Ref: testorder.ProductionSiteID > site.SiteID
Ref: testorderdetail.OrderID > testorder.OrderID
// Specimen Management
Ref: specimen.OrderID > testorder.OrderID
Ref: specimencollection.SID > specimen.SID
Ref: specimencollection.LocationID > location.LocationID
Ref: specimencollection.EquipmentID > instrument.InstrumentID
Ref: specimencollection.PersonnelID > personnel.PersonnelID
Ref: specimentransport.SID > specimen.SID
Ref: specimentransport.SenderID > personnel.PersonnelID
Ref: specimentransport.ReceiverID > personnel.PersonnelID
Ref: specimenstorage.SID > specimen.SID
Ref: specimenstorage.LocationID > location.LocationID
// Test Management
Ref: testdef.DisciplineID > discipline.DisciplineID
Ref: testdefsite.TestID > testdef.TestID
Ref: testdefsite.SiteID > site.SiteID
Ref: testdefsite.WorkstationID > workstation.WorkstationID
Ref: testdefsite.InstrumentID > instrument.InstrumentID
Ref: testdeftech.TestID > testdef.TestID
Ref: testdeftech.InstrumentID > instrument.InstrumentID
Ref: calculatedtest.TestID > testdef.TestID
Ref: grouptestmember.GroupTestID > grouptest.GroupTestID
Ref: grouptestmember.TestID > testdef.TestID
Ref: panel.ParentPanelID > panel.PanelID
Ref: panel.DisciplineID > discipline.DisciplineID
Ref: panelmember.PanelID > panel.PanelID
Ref: panelmember.TestID > testdef.TestID
// Reference Range
Ref: referencerangenumeric.TestID > testdef.TestID
Ref: referencerangenumeric.SiteID > site.SiteID
Ref: referencerangethreshold.TestID > testdef.TestID
Ref: referencerangethreshold.SiteID > site.SiteID
Ref: referencerangetext.TestID > testdef.TestID
Ref: referencerangetext.SiteID > site.SiteID
// Calibration
Ref: calibrator.TestID > testdef.TestID
Ref: calibration.InstrumentID > instrument.InstrumentID
Ref: calibration.TestID > testdef.TestID
Ref: calibration.CalibratorID > calibrator.CalibratorID
Ref: calibration.PersonnelID > personnel.PersonnelID
Ref: calparinst.EquipmentID > instrument.InstrumentID
// Quality Control
Ref: qcmaterial.TestID > testdef.TestID
Ref: qcresult.InstrumentID > instrument.InstrumentID
Ref: qcresult.TestID > testdef.TestID
Ref: qcresult.QCMaterialID > qcmaterial.QCMaterialID
Ref: qcresult.PersonnelID > personnel.PersonnelID
Ref: qcstatistic.InstrumentID > instrument.InstrumentID
Ref: qcstatistic.TestID > testdef.TestID
Ref: qcstatistic.QCMaterialID > qcmaterial.QCMaterialID
// Test Results
Ref: patres.SID > specimen.SID
Ref: patres.TestID > testdef.TestID
Ref: patres.OrderID > testorder.OrderID
Ref: patres.PersonnelID > personnel.PersonnelID
Ref: patrestech.ResultID > patres.ResultID
Ref: patrestech.InstrumentID > instrument.InstrumentID
Ref: patresflag.ResultID > patres.ResultID
Ref: resultdistribution.ResultID > patres.ResultID
// Reagent & Inventory
Ref: reagent.TestID > testdef.TestID
Ref: reagent.InstrumentID > instrument.InstrumentID
Ref: reagentusage.ReagentID > reagent.ReagentID
Ref: reagentusage.TestID > testdef.TestID
Ref: reagentusage.PersonnelID > personnel.PersonnelID
Ref: product.SiteID > site.SiteID
Ref: product.LocationID > location.LocationID
Ref: inventorytransaction.ProductID > product.ProductID
Ref: inventorytransaction.PersonnelID > personnel.PersonnelID
// Equipment Management
Ref: equipment.SiteID > site.SiteID
Ref: equipment.LocationID > location.LocationID
Ref: equipmentmaintenance.EquipmentID > equipment.EquipmentID
Ref: equipmentactivity.EquipmentID > equipment.EquipmentID
Ref: equipmentactivity.PersonnelID > personnel.PersonnelID
Ref: equipmenttestcount.EquipmentID > equipment.EquipmentID
// User & Authentication
Ref: user.PersonnelID > personnel.PersonnelID
Ref: usersession.UserID > user.UserID
// Visualization & Reporting
Ref: reporttemplate.DisciplineID > discipline.DisciplineID
Ref: reportoutput.TemplateID > reporttemplate.TemplateID
Ref: reportoutput.OrderID > testorder.OrderID
Ref: reportoutput.PersonnelID > personnel.PersonnelID
// Host System Integration
Ref: hosttestmapping.LocalTestID > testdef.TestID

File diff suppressed because it is too large Load Diff