OpenEMR System Architecture
OpenEMR System Architecture
Revision History of this Document
- 2007-06-20
- Original document by Rod Roark (http://www.sunsetsystems.com/)
- 2007-07-10
- Minor updates for the new claims table and "effective dates" in insurance_data.
- 2007-08-02
- Updated with "restoreSession" notes (section 11) and FreeB replacement info.
- 2009-01-13
- Updates for internal A/R and miscellaneous other improvements.
- 2009-12-03
- Migrated this document to the OpenEMR wiki to improve collaboration. Snapshot
- 2009-12-04-->
- Extensive modifications for OpenEMR 3.1.0 and greater versions by OpenEMR Community.
Introduction
This is a compilation of notes that will be of interest to developers who wish to become involved with OpenEMR, or to users who are interested in technical aspects of the project. Creation of this document was generously sponsored by Sam Rajan, IPPF, and volunteer contributors.
Other Resources
Online Resources
The http://www.open-emr.org/ is the home page for the project, which includes a manual, demo site, forums and a documentation wiki.
Resources included within the OpenEMR package
The Documentation directory of the OpenEMR distribution contains the User Manual and other earlier notes, technical and otherwise:
- Current:
- INSTALL provides installation and upgrading instructions
- README provides a general description of OpenEMR
- Documentation/Complete_Vaccine_Listing.pdf A standard listing of vaccinations.
- de_identification_readme.txt Instructions for setting up de- identification of patient data.
- Documentation/Emergency_User_README.txt Describes how to use the Emergency Login feature
- Documentation/Payment_Posting_ZHH.pdf Description of how to use the billing module.
- Documentation/README.phpgacl discusses phpGACL, which OpenEMR uses for access control.
- Documentation/README-Log-Backup.txt How to set up a log rotation in OpenEMR.
- Documentation/SystemArchitecture.txt provides a link to this wiki page.
- Current:
- Somewhat Outdated:
- Documentation/IPPF_Guides directory contains some nice visual documentation.
- Documentation/User_Guide directory contains the OpenEMR 4.0 User Manual (HTML version). Note this is now considered outdated since OpenEMR 4.1+ and above maintain the User Manual on the wiki.
- Somewhat Outdated:
- Very Outdated:
- Documentation/3rd_Party_Form_API.txt describes the interface as originally designed for encounter forms.(outdated)
- Documentation/Database.pdf has some information about the original database design.(outdated)
- Documentation/FAQ is also quite old and doesn't cover much.(outdated)
- Documentation/Functions.pdf describes interfaces implemented by some modules in the library directory.(outdated)
- Documentation/HISTORY.txt is a brief summary of OpenEMR versions thru about 2002.(outdated)
- Documentation/modifications.txt is a brief list of the modules that must change in order to add data items to patient demographics.(outdated)
- Documentation/NoIP.txt is an obsolete list of broken links.(outdated)
- Documentation/OpenEMR_Backend_Spec.txt is a description of some interfaces implemented in the library directory.(outdated)
- Documentation/OpenEMR-Win2003-server-install-new.html briefly discusses installation of OpenEMR on Windows 2003.(outdated)
- Documentation/Package.txt has some old notes about creating an OpenEMR distribution release.(outdated)
- Documentation/Readme.txt seems to be mostly a disclaimer regarding HIPAA compliance.(outdated)
- accounting/README.sql-ledger which describes setup of SQL-Ledger with OpenEMR. (outdated)
- Changelog which is not current.(outdated)
- Very Outdated:
Database
File:OpenEmrOriginalSchema.pdf - Full Graphical Map of the current schema as of version 3.2.0.
OpenEMR installs many database tables. Following is a list, with brief descriptions:
- addresses - Contains street addresses for two other tables: insurance_companies and pharmacies. So it is effectively an extension of those tables. This is inconsistent in that some other tables (e.g. facility, patient_data, users) have their addresses embedded. The "foreign_id" column equals the "id" of the foreign table, but curiously the addresses table does not identify the foreign table itself.
- amc_misc_data - For tracking of some Automated Measure Calculations (AMC). (added in version 4.1.0)
- array - I don't see anything that uses this.
- ar_activity – This is the primary repository for Accounts Receivable information. In general it contains multiple rows per encounter (visit). Each row corresponds to either a payment or an adjustment. Columns are:
- pid, encounter: Identifies the visit.
- sequence_no: A “line number” of the activity item for this visit.
- code, modifier: Identifies a particular service item, if any, that this payment or adjustment is for; generally useful only for insurance.
- payer_type: 0 = patient, 1 = primary insurance, 2 = secondary insurance, etc.
- post_time: A timestamp for the event posting.
- post_user: The ID of the user who posted the item.
- session_id: The ID of the associated ar_session table row, if any; generally useful only for insurance.
- memo: Used for the insurance adjustment reason, if applicable.
- pay_amount: The amount paid, if this is a payment.
- adj_amount: The amount of adjustment, if this is an adjustment.
- ar_session – Also for Accounts Receivable, this table is applicable to insurance EOBs. Each row corresponds to a “posting session” in which a single payment covers a set of claims. Columns are:
- session_id: A unique numeric identifier for the session.
- payer_id: The ID of the payer in the insurance_companies table.
- user_id: The ID of the user who is posting the session.
- closed: Indicates if the session is complete (1=yes, 0=no).
- reference: Normally a check number or EOB number.
- check_date: The check date as provided by the payer.
- deposit_date: The date that the receiver deposits the payment.
- pay_total: The amount of the payment.
- audit_details: Used by patient portal(s). (added in version 4.1.0)
- audit_master: Used by patient portal(s). (added in version 4.1.0)
- automatic_notification - For the patient automatic notification module (works with tables notification_settings and notification_log).
- batchcom - Records messages sent to groups of patients using the "Batch Communication Tool".
- billing - Billing items. Contains a row for every CPT4 code, HCPCS code, and ICD9 code recorded into an encounter. In addition has a row for each co-pay entered. The billing process also maintains state information in this table.
- categories - Defines the tree of document category types. These are the category names that you see when viewing patient documents. Note that the "parent" column is a reference to the "id" column of the same table, thus the tree structure.
- categories_seq - Holds the value of the last-used "id" for the categories table.
- categories_to_documents - Cross-references the categories and documents tables.
- chart_tracker – This supports the “chart tracking” feature whereby you can keep track of the location and history of paper charts. For each check-out or check-in, it records the patient ID, timestamp, user and location.
- claims - records events related to the queueing and generation of claims. The Billing page summarizes this information for each encounter shown.
- clinical_plans - Used by CDR engine. (added in version 4.1.0)
- clinical_plans_rules - Used by CDR engine. (added in version 4.1.0)
- clinical_rules - Used by CDR engine. (added in version 4.1.0)
- codes - The table of available billing codes including their modifiers, descriptions and fees. For the U.S. these will normally be CPT, HCPCS and ICD9 codes.
- code_types - Stores the code types used in the codes table. (added in version 4.0.0)
- config - Not sure what this is.
- config_seq - Presumably the last "id" used in the config table.
- documents - Holds metadata for patient documents. The "foreign_id" column references "pid" in the patient_data table.
- documents_legal_categories - Used by patient portal(s). (added in version 4.1.0)
- documents_legal_detail - Used by patient portal(s). (added in version 4.1.0)
- documents_legal_master - Used by patient portal(s). (added in version 4.1.0)
- drugs - Supports in-house drug sales. This is the list of available drugs.
- drug_inventory - Supports in-house drug sales. Each row represents a "lot" of purchased drugs.
- drug_sales - Supports in-house drug sales. Each row represents a drug sale, i.e. an invoice line item.
- drug_templates - Supports in-house drug sales. Each row represents a shortcut for a common dispensation of a drug.
- eligibility_response - For insurance eligibility checking feature. (added in version 4.0.0)
- eligibility_verification - For insurance eligibility checking feature. (added in version 4.0.0)
- employer_data - Contains patient employer information. The "pid" column references "pid" in the patient_data table. In general there is more than one of these accumulated per patient, and the current one is that with the most recent "date" value. This is inconsistent with subscriber employer information, which is included in the insurance_data table.
- facility - Facilities are entered for treatment or billing purposes, or both. It is important that exactly one facility has its "billing_location" flag set, as this is the one used as the billing facility in generated claims.
- fee_sheet_options – Supports a method of categorizing services in the Fee Sheet. For each category and item within the category, it identifies one or more specific services that would be added to the Fee Sheet when that item is selected.
- forms - An index of all encounter form instances.
- form_* - Most "encounter forms" (other EHR systems call these "templates") implement a table whose name is "form_" followed by the name of the form.
- form_encounter - This is the "encounter form" table for the most basic information about the patient encounter. Most importantly this contains the encounter date. Some A/R data is included: last payer level billed, last payer level closed, last statement date, and number of statements previously sent.
- form_misc_billing_options - An encounter form that is a catch-all for billing information that is not always needed and is not captured elsewhere. For example, a specialist will put "prior authorization" numbers here.
- gacl_* - Contains all the access control tables (embedded php-GACL)
- geo_country_reference - Maps country names to codes. I don't think this is used.
- geo_zone_reference - Maps U.S. states, Canadian provinces and some other geographic regions to codes. I don't think this is used either.
- globals - Stores settings. (added in version 4.0.0)
- gprelations - Used to link pnotes with other items such as documents. (added in version 3.2.0)
- groups - Used to assign one or more "group names" to each user. Supports grouping of users.
- history_data - This maps 1:1 with the patient_data table and stores information about the patient's medical history.
- immunizations - Records immunizations given to patients.
- insurance_companies - These are the payers. Most importantly it contains the payer's name and the external payer ID (cms_id). However may clearinghouses will map your payer names to the IDs, so you might not need to put in the IDs.
- insurance_data - Contains rows of insurance information for each patient, including at least one each for primary, secondary and tertiary insurance. Holds information about each patient insurance plan, including subscriber information. An important recent improvement to this is the maintenance of the "date" column which is the effective date of the plan; thus it is possible to store multiple plans of each type, with different effective dates. "provider" here is a reference to insurance_companies.id.
- insurance_numbers - Cross-references providers and insurance companies, and contains information specific to that relation, such as the credentialing number assigned by the insurance company to that provider. Where insurance_company_id is NULL, this indicates "default" values for the provider.
- integration_mapping - With the need for SQL-Ledger eliminated, this table is obsolete. It associates certain items in the OpenEMR database (MySQL) with corresponding items in the SQL-Ledger database (PostgreSQL). local_table and local_id are values for the OpenEMR table name and primary key. foreign_table and foreign_id are those for the SQL-Ledger database. The logical entities of interest are users (providers), and patients.
- issue_encounter - Cross-references the lists table (representing "issues") with encounters (identified by patient ID and encounter ID). The idea here is to identify those encounters that address a given problem of a given patient.
- lang_constants - Supports language translation. Assigns an ID to each translatable string.
- lang_custom - Records local translation modifications. (added in version 4.0.0)
- lang_definitions - Supports language translation. Provides the translation string for each language and string ID.
- lang_languages - Supports language translation. Identifies the supported languages.
- layout_options – Defines the visual layout for patient demographics, history, referrals and some types of issues. This table is maintained and customized via the Layouts administrative interface.
- lbf_data -Supports and records Layout based forms data (added in version 3.2.0)
- lists - These are patient "issues": medical problems, allergies, medications, surgeries, etc. They are similar to patient history items, but represent those items currently under treatment and thus that one might logically want to associate with encounters.
- lists_touch - Tracks whether items in 'lists' have been used. This allows the option to choose 'none' for items in 'lists'. (added in version 4.2.0)
- list_options – Defines most static lists. This table is maintained and customized via the Lists administrative interface.
- log - A history of information access events. This table can become very large and as of yet there is no easy too for cleaning it out or archiving it. The logging feature also needs work in that some things are not logged that should be.
- notes - I'm not sure if or how this table is used.
- notification_log - For the patient automatic notification module (works with tables automatic_notification and notification_settings)
- notification_settings - For the patient automatic notification module (works with tables automatic_notification and notification_log)
- onotes - These are the "office notes" recorded and viewed in the Notes panel.
- openemr_modules - used internally by the embedded PostNuke code.
- openemr_modules_vars - used internally by the embedded PostNuke code.
- openemr_postcalendar_categories - These are the definitions of the calendar event categories. You maintain these by going into Administration / Calendar / Categories in OpenEMR.
- openemr_postcalendar_events - These are individual calendar events: appointments, In Office, Out of Office, lunch, reserved times, etc. Many of these will be repeating events, however repeating appointments are not supported.
- openemr_postcalendar_limits - used internally by the embedded PostNuke code.
- openemr_postcalendar_topics - used internally by the embedded PostNuke code.
- openemr_session_info - used internally by the embedded PostNuke code.
- patient_access_offsite - Stores patient credentials for embedded patient portal. (added in version 4.1.0)
- patient_access_onsite - Stores patient credentials for third party offsite patient portals. (added in version 4.1.0)
- patient_data - The primary repository for patient demographics.
- patient_reminders - Used by CDR engine. (added in version 4.1.0)
- payments - Records information entered via the "Payment" popup window (accessable from the dropdown in the patient menu).
- pharmacies - The list of pharmacies. This also references the "addresses" and "phone_numbers" tables via its "id" column.
- phone_numbers - Contains telephone numbers of insurance_companies and pharmacies, and like the addresses table is effectively an extension of those tables.
- pma_bookmark - Contains information about the canned reports available via the dropdown in the Reports menu. We recommend not using this feature because it's crude and confusing. *(And now missing entirely from version 3.1+)* --Tony - www.mi-squared.com 08:37, 29 December 2009 (UTC)
- pma_column_info - Doesn't seem to be used.
- pma_history - Doesn't seem to be used.
- pma_pdf_pages - Doesn't seem to be used.
- pma_relation - Doesn't seem to be used.
- pma_table_coords - Doesn't seem to be used.
- pma_table_info - Doesn't seem to be used.
- pnotes - Patient notes. This is a very useful feature where notes associated with a specific patient may be passed around among different users within the clinic, and eventually marked as closed. The assigned_to column indicates who is the current owner of the issue.
- prescriptions - Prescriptions. In the case of in-house dispensation, drug_id will indicate the drug dispensed.
- prices – Contains price information for products and services, and supports multiple price levels. This table obsoletes the “fee” column of the “codes” table. Note that the price levels are defined in the “list_options” table (list_id = “pricelevel”).
- procedure_order - For procedure/lab module. (added in version 4.0.0)
- procedure_report - For procedure/lab module. (added in version 4.0.0)
- procedure_result - For procedure/lab module. (added in version 4.0.0)
- procedure_type - For procedure/lab module. (added in version 4.0.0)
- registry - Contains metadata regarding "registered" encountered forms. The Administration / Forms panel is used to register forms and maintain this information.
- sequences - Holds the last "id" used by the integration_mapping table and for encounter IDs.
- transactions - Records entries made in the Transactions panel.
- users - This is a dual-purpose table. It supports the list of local users with their login names, passwords and other information; and it supports the Address Book. Non-local users are identifiable by having an empty "username" value.
- users_facility - Used to support restrictions for multiple facilities setups.
- x12_partners - These are the entities to whom electronic claims are sent. Normally there is just one, a clearinghouse. Referenced by the insurance_companies and billing tables.
Customization of OpenEMR
Most configuration happens with changes to interface/globals.php and includes/config.php. However there are some other modules where customization may be needed:
- custom/clickoptions.txt - May be customized to contain your preferred selections for issue titles (names of medical problems, allergies, etc.). Needs to be done concurrently with library/lists.inc file.
- custom/code_types.inc.php - If you code your encounters using methods other than CPT4, ICD9 and HCPCS then you will want to customize this and also load your custom codes into the "codes" table.
- custom/statement.inc.php - This is your template for patient statements or collection letters. It must be customized for your practice.
- custom/export_demographics.php - A placeholder for a script to export patient demographics to another system. export_labworks.php and export_xml.php are examples of such scripts.
- custom/refer.php - A placeholder for a referral management system. One option is to subscribe to refercare.org and then replace this script with the provided refercare.php script.
- interface/billing/billing_process.php - Customize X12 partner settings.
- library/lists.inc - Customize Issue Types.
- library/classes/class.ezpdf.php - Customize some general pdf settings.
Calendar Architecture
From some of my old notes when I was studying the PostNuke calendar design:
- openemr_postcalendar_events is referenced in:
- interface/main/calendar/modules/PostCalendar/pnuser.php
- interface/main/calendar/modules/PostCalendar/pnuserapi.php
- interface/main/calendar/modules/PostCalendar/pninit.php
- interface/main/calendar/modules/PostCalendar/common.api.php
- interface/main/calendar/modules/PostCalendar/pntables.php
- interface/main/calendar/modules/PostCalendar/pnadmin.php
- interface/main/calendar/modules/PostCalendar/pnadminapi.php
- interface/main/calendar/modules/PostCalendar/plugins/function.pc_filter.php
- interface/reports/appt_encounter_report.php
- pnuser.php: function postcalendar_user_submit($args): invoked on event submission, at end writes success message, clears form vars, calls buildSubmitForm.
- common.api.php: function postcalendar_userapi_buildSubmitForm($args,$admin=false) creates a ton of output which is then written via the submit.html template.
- submit.html: is the template used to generate the redisplayed submit form.
- small_navigation.html: included to generate the date selector and view buttons.
- function.pc_date_select.php: builds date selector with jump button, should maybe enhance this to accept a specified default date, or else change the PostCalendar current working date from submit.html.
- function.pc_url.php: builds the urls for the links in the view buttons.
OpenEMR Dependencies
Ubuntu 8.04 and on Debian 4.0
This list of dependencies from installation of OpenEMR on Ubuntu 8.04 and on Debian 4.0 may be helpful. These are the packages that were added to a basic installation. Installing these will also cause many other required dependencies to be installed:
- apache2-mpm-prefork
- mysql-server
- libapache2-mod-php5
- libdate-calc-perl
- libdbd-mysql-perl
- libdbi-perl
- libhtml-parser-perl
- libtiff-tools
- libwww-mechanize-perl
- libxml-parser-perl
- php5
- php5-mysql
- php5-cli
- php5-gd
- php5-xsl
- php5-curl
- php5-mcrypt
- php-soap
- imagemagick
Redhat Enterprise 5 / CentOS 5
These are the rpm package names. "yum install <pkgname>" generally works.
- php-mysql
- php-gd
PHP Sessions and Browser Windows
Before August of 2007 OpenEMR worked poorly, even dangerously, when used in multiple top-level browser windows on the same machine. The underlying problem is that most web browsers cannot support separate cookie-based sessions in this case, because all windows share the same cookie storage area. There is more information about the general issue at http://aranea.zuavra.net/index.php/80/ .
Then a JavaScript-based solution was implemented as follows:
- interface/login/login.php was modified to delete the session cookie when a new login occurs. This ensures that a unique session ID is generated for each login (we assume you start each new browser window session with a login).
- A JavaScript function restoreSession() was created via the script library/restoreSession.php. This script is included in every top-level window. When called, the function restores the session cookie's value to the session ID that was supplied when the window was created.
- Many other scripts (about 200!) where changed to call "top.restoreSession()" wherever a server-side script is invoked. For example, "onclick='top.restoreSession()'" was added to every "<a href=...>" tag.
The effect of all this is to make the top-level window the storage area for the session cookie. So by creating multiple top-level browser windows and logging in separately to each, you can have multiple OpenEMR sessions concurrently on your desktop. This is a valuable feature for busy users who must juggle multiple tasks at once.
Naturally this impacts future development. You must include a JavaScript call to top.restoreSession() wherever you invoke a PHP script that requires current session data (which is most of them). The most common ways of doing this are by including the onclick handler as described above, and by including "onsubmit='return top.restoreSession()'" in <form> tags.