Skip to main content

Getting Started

Zynomi is built on a suite of modern, open-source tools, frameworks, and libraries designed for creating high-performance web and mobile applications.

With this framework, developers have the power to create data-driven dashboards, patient engagement interfaces, and comprehensive tools for healthcare providers. Deploy applications seamlessly across various environments, from on-premises servers to cloud and edge devices, often within the free tier of cloud services.


Quick Start Guide

To get started with Zynomi, you'll need specific cloud subscriptions, some essential and others optional. Most small to medium-sized applications can be deployed within the free service tiers.

Cloud Subscriptions

Cloud Subscriptions

StackDescription
GitHubSource code hosting, with project and issue management. Free GitHub.com membership includes forking sublink mobile website repository and sublink android shell repository, and access to admin web panel.
SupabasePostgres database, authentication, instant APIs, edge functions, and storage. Registration is free. API access credentials, DB credentials, tables including auth.users (readonly), public.profiles, public.devices, public.medication_consumption_logs are provided.
Frappe CloudFor creating sites like https://healthbuddy.frappe.cloud/. Choose the $10 USD monthly plan. Includes site creation, root user registration, user creation, and API access token generation from the settings page.
Google CloudRegistration and enablement of Firebase Push notification.
VercelDeployment platform for hosting applications at the edge. Free membership available at https://vercel.com/.
KoyebFree cloud membership to host docker.

Software Prerequisites

SoftwareDescription
Node.js*Latest LTS version
npm or YARNPackage manager to manage dependencies
VS CodePreferred IDE for development
GitVersion control system
PostmanTool for testing REST & GraphQL APIs
DockerContainer platform for consistent development environments

Development Environment

IonicJS & Nuxt Mobile website

Prerequisites

  • Node.js version 18.x installed.
  • NPM
  • Environment variable
  • Supabase Subscription and Custom Tables under public schema

Supabase Custom Table

devices

The devices table is designed to keep track of client mobile devices and associated Firebase tokens. It is populated when a client logs into the mobile app for the first time. The table is structured to handle multiple mobile devices per user, with each device having a unique device ID and Firebase token. The fields within the table allow for the storage of various device attributes, such as the make, operating system, and model, as well as the Firebase token and other additional attributes. A boolean flag indicates whether the app has been uninstalled from the device or if the device is active. Each entry has timestamps for creation and last modification. The table ensures that each active device for a user is unique through a constraint.

CREATE TABLE devices (
id BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY,
user_id TEXT NOT NULL,
device_id TEXT NOT NULL,
device_make TEXT,
os TEXT,
os_model TEXT,
fbn_token TEXT,
channel_id TEXT,
additional_attributes JSON,
uninstalled BOOLEAN DEFAULT false,
is_active BOOLEAN DEFAULT false NOT NULL,
created_at TIMESTAMP(6) WITH TIME ZONE DEFAULT now() NOT NULL,
modified_at TIMESTAMP(6) WITH TIME ZONE DEFAULT now(),
PRIMARY KEY (id),
CONSTRAINT unique_user_device_active UNIQUE (user_id, device_id, is_active)
);

profiles

The profiles table is designated for storing additional user attributes in Supabase. Although not actively used, it is set up to collect extra details about users through a trigger from the auth.users table, which is read-only within Supabase. It's designed to enrich user profiles with custom attributes.

CREATE TABLE profiles (
id UUID NOT NULL,
updated_at TIMESTAMP(6) WITH TIME ZONE,
avatar_url TEXT,
website TEXT,
email TEXT,
is_sso_user BOOLEAN,
first_name TEXT,
last_name TEXT,
custom_attributes JSONB,
phone TEXT,
PRIMARY KEY (id),
CONSTRAINT profiles_id_fkey FOREIGN KEY (id) REFERENCES "postgres"."auth"."users" ("id")
);

medication_consumption_logs

The medication_consumption_logs table tracks the medication intake by patients or volunteers. They log each consumption event via the mobile app, and this data is used to monitor medication adherence within the Nurse and application dashboards for clinical trials or patient care.

Before you can use the uuid_generate_v4() function in PostgreSQL, you need to enable the uuid-ossp extension, which provides functions to generate UUIDs using this method.

-- Enable the UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE "medication_consumption_logs" (
"id" UUID DEFAULT UUID_GENERATE_V4() NOT NULL,
"encounter_id" TEXT NOT NULL,
"drug" TEXT NOT NULL,
"patient_email" TEXT NOT NULL,
"medication_consumption_timing" TEXT NOT NULL,
"created_at" TIMESTAMPTZ(6) DEFAULT TIMEZONE(CAST('utc' AS TEXT), NOW()) NOT NULL,
"status" TEXT NOT NULL,
"medication_dosage" TEXT,
"additional_attributes" JSON,
PRIMARY KEY ("id")
)

notification_logs

Logs Firebase notifications sent for medication reminders. Includes information about the recipient, device, medication, message content, and the read status, along with the type of notification.

-- Create table for logging Firebase notifications related to medication reminders
CREATE TABLE notification_logs (
id BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY, -- Primary key, uniquely identifies each log entry
email_to TEXT NOT NULL, -- Email address of the recipient
device_id TEXT NOT NULL, -- Unique identifier of the recipient's device
drug_id TEXT, -- Optional identifier of the medication being reminded for
message TEXT NOT NULL, -- Content of the notification sent
sent_at TIMESTAMP(6) WITH TIME ZONE DEFAULT now() NOT NULL, -- Timestamp when the notification was sent, defaults to current time
sent_status TEXT, -- Status of the notification sending process (e.g., 'sent', 'failed')
is_read BOOLEAN DEFAULT false NOT NULL, -- Flag indicating whether the notification has been read
read_at TIMESTAMP(6) WITH TIME ZONE, -- Timestamp when the notification was read, if applicable
notification_type TEXT DEFAULT 'firebase' NOT NULL, -- Type of the notification, defaults to 'firebase'
PRIMARY KEY (id) -- Specifies that the id column is the primary key
);

-- Add a comment to the entire table to describe its purpose
COMMENT ON TABLE notification_logs IS 'Logs Firebase notifications sent for medication reminders. Includes information about the recipient, device, medication, message content, and the read status, along with the type of notification.';

-- Add comments to columns to describe their purpose more precisely
COMMENT ON COLUMN notification_logs.id IS 'Unique identifier for each log entry.';
COMMENT ON COLUMN notification_logs.email_to IS 'Email address to which the notification was sent.';
COMMENT ON COLUMN notification_logs.sent_at IS 'The timestamp when the notification was sent, with timezone information.';
COMMENT ON COLUMN notification_logs.is_read IS 'Boolean indicating if the notification was read by the recipient.';
COMMENT ON COLUMN notification_logs.notification_type IS 'Specifies the type of notification, with a default value of "firebase".';

Supabase Custom Function

fn_get_medication_status

Function (or stored procedure) to generates a report of medication consumption status for a given patient across a specified date range, for a list of drugs and dosage timings. This function is designed to be flexible, allowing for different sets of drugs and dosage timings as needed.

/*
Description:
This function generates a report of medication consumption status for a given patient across a specified date range, for a list of drugs and dosage timings.

Parameters:
- p_patient_email: The email of the patient for whom the report is generated.
- p_drugs: An array of drugs to include in the report.
- p_dosage_timings: An array of dosage timings (e.g., 'morning', 'afternoon', 'night') to consider in the report.
- p_start_date: The start date of the date range for the report.
- p_end_date: The end date of the date range for the report.

Returns:
A table with the following columns:
- target_date: The date for which the report is generated.
- patient_email: The email of the patient.
- drug: The drug considered in the report.
- medication_dosage: The dosage timing for the drug.
- status: The consumption status ('Consumed' or 'Not Consumed').
- latest_consumption_time: The latest timestamp when the medication was consumed.

Usage:
SELECT * FROM get_medication_status(
'example@patient.com',
ARRAY['DrugA', 'DrugB'],
ARRAY['morning', 'afternoon', 'night'],
'2024-01-01',
'2024-01-31'
);

SELECT * FROM get_medication_status(
'kalai.a@patient.com',
ARRAY['Septron 500mg', 'Atenolol 50mg.'],
ARRAY['morning', 'afternoon', 'night'],
'2024-01-03',
'2024-01-07'
);

Note:
The function is designed to be flexible, allowing for different sets of drugs and dosage timings as needed.
*/

CREATE OR REPLACE FUNCTION get_medication_status(
p_patient_email TEXT,
p_drugs TEXT[],
p_dosage_timings TEXT[],
p_start_date DATE,
p_end_date DATE
)
RETURNS TABLE (
target_date DATE,
patient_email TEXT,
drug TEXT,
medication_dosage TEXT,
status TEXT,
latest_consumption_time TIMESTAMP
) AS $$
WITH date_series AS (
SELECT generate_series(p_start_date, p_end_date, '1 day'::interval)::DATE AS target_date
),
expanded_drugs AS (
SELECT
p_patient_email AS patient_email,
unnest(p_drugs) AS drug,
ds.target_date
FROM date_series ds
),
dosage_timings AS (
SELECT unnest(p_dosage_timings) AS medication_dosage
)

SELECT
ed.target_date,
ed.patient_email,
ed.drug,
dt.medication_dosage,
COALESCE(MAX(mcl.status) FILTER (WHERE mcl.medication_dosage = dt.medication_dosage AND mcl.medication_consumption_timing::DATE = ed.target_date), 'Not Consumed') AS status,
MAX(mcl.created_at) FILTER (WHERE mcl.medication_dosage = dt.medication_dosage AND mcl.medication_consumption_timing::DATE = ed.target_date) AS latest_consumption_time
FROM expanded_drugs ed
CROSS JOIN dosage_timings dt
LEFT JOIN medication_consumption_logs mcl
ON mcl.patient_email = ed.patient_email
AND mcl.drug = ed.drug
AND mcl.medication_dosage = dt.medication_dosage
AND mcl.medication_consumption_timing::DATE = ed.target_date
GROUP BY ed.target_date, ed.patient_email, ed.drug, dt.medication_dosage
ORDER BY ed.target_date, ed.drug, dt.medication_dosage;
$$ LANGUAGE sql STABLE;

Frappe Customization

Custom Form Fields

Following doctypes needs to be enhanced with additional form fields as indicated by the orange color.

Drug Prescription

Drug Prescription Custom Fields Placeholder

Healthcare Practitioner

Healthcare Practitioner Custom Fields Placeholder

Patient

Patient Custom Fields Placeholder

Nursing Task

Patient Custom Fields Placeholder

Patient Custom Fields Placeholder

While creating the "clinical_trial" list form fields, create list of clinical trial names.

Defaults

To ensure the correct functioning of the Zynomi application, default Healthcare Practioner and Nurse User must be established within the Frappe system and then set these email values in the .env environment variable file. These records are utilized during the automatic creation of encounters and nursing tasks when a new patient signs up through the mobile app.

Also create Master records for Clinical Trial Programmes in Nursing Task form.

Default Healthcare Practitioner Record

Default Nurse User Record

Setup Steps

Mobile Website

  1. Clone the Repository:

    • Execute git clone [repository_url] to clone the "Zynomi" repository onto your local machine.
  2. Navigate to the Directory:

    • Change your directory with cd [repository_name].
  3. Installing Dependencies:

    • Run npm i to install the necessary dependencies for the project.
  4. Setting Environment Variables in .env file:

FRAPPE_CLOUD_IMAGE_BASE_URL=
API_GATEWAY_BASE_URL=
SUPABASE_URL=
SUPABASE_KEY=
SUPABASE_KEY_SERVICE_KEY=
FRAPPE_REST_API_TOKEN=
FIREBASE_CONFIG_FILE_PATH=
FRAPPE_HEALTHCARE_DEFAULT_PHYSICIAN_EMAIL=
FRAPPE_HEALTHCARE_DEFAULT_NURSE_EMAIL=

Rename sample.env as .env and override the values

  1. Building the Project:

    • Execute npm run generate to generate the static files for the project.
  2. Running the Application:

    • Start the development server using npm run dev.
    • Alternatively, to serve the generated static files, use npm serve .output/public.

Native Android ReactJS Appshell

Prerequisite:

  • Node.js version 18.x installed.
  • Android Studio and Android SDK installed.

Set Up Capacitor:

  • Initialize Capacitor if you haven't already: npx cap init

Build your Application:

  • Ensure your app is built before adding the Android platform: npm run build

Add the Android Platform:

  • Add the Android platform to your project: npx cap add android

Open in Android Studio:

  • Open your app in Android Studio for native changes and to run: npx cap open android

Syncing Your App:

  • If you make changes or install new plugins: npx cap sync

Build the Android App:

  • In Android Studio, select Build > Build Bundle(s) / APK(s) > Build APK(s).

Test on Device or Emulator:

  • Run your app on an emulator or a connected device directly from Android Studio.