The patient portal is a separate authenticated application that shares the same database as the main clinic app, but has its own login, session, and permission layer. Patients can never access any records other than their own. The portal is served from the same codebase and is configurable per-clinic.
patient_portal_accounts stores the patient's hashed password (Argon2id), email, and 2FA status — separate from the patients table so a patient without a portal account still has a clinical record. Account creation can be patient-initiated (self-registration) or staff-initiated.
Portal sessions are separate from staff sessions (different session prefix, different cookie name). Session tokens are rotated on each login and on privilege elevation. Login attempt rate-limiting is enforced at the PHP layer.
pages/patient_forgot_password.php + pages/patient_reset_password.php: standard email-link reset flow. Reset tokens are single-use, hashed in the database, and expire after 60 minutes.
api/otpless_callback.php integrates with OTPless for phone-number-based passwordless login. Patients tap a WhatsApp or SMS link and are logged in without entering a password — useful for patients who struggle with passwords.
api/gfit_oauth_callback.php handles OAuth2 flow. patient_google_fit_tokens stores refresh tokens. api/google_fit.php pulls activity, sleep, and heart-rate data from the Google Fitness REST API and writes to vitals (with source = 'google_fit'). Sync runs on portal login and via a scheduled cron job.
api/apple_health_sync.php receives a signed JSON payload from a companion iOS shortcut or app, validates it against the per-patient token in patient_apple_health_tokens, and ingests step count, sleep, and heart-rate data into vitals. The sync is push-based (patient-side app sends data) rather than pull-based.
gfit_sync_log records each sync attempt (timestamp, records_inserted, error_message) for debugging. Accessible to clinic admins in the patient's record.
pages/patient_abha_tab.php + api/abha.php + api/abha_auth.php: the patient can create a new ABHA (Ayushman Bharat Health Account) number or link an existing one. The OTP-based verification follows the ABDM v3 API specification.
abha_hip_keys stores the clinic's HIP (Health Information Provider) credentials issued by the NHA. These are used to sign all ABDM API calls. The keys are stored encrypted and never exposed to patients or non-admin staff.
abha_consents records every patient consent event (grant, revoke, expire) as required by the ABDM consent flow. abha_otp_sessions tracks in-progress OTP verifications. abha_fetched_records stores health records pulled from other facilities with patient consent.
mood_entries stores timestamped mood scores (1–10) and optional notes logged by the patient from the portal. Entries are visible in the patient's record in the main app, charted over time alongside assessment scores and vitals.
portal_messages is a simple threaded message table (patient_id, user_id, direction, body, read_at). New patient messages trigger a notification to the assigned clinician via the notification_queue.
data_rights_requests: patients can submit a DPDP/GDPR-style Subject Access Request or erasure request from the portal. The request is routed to the clinic admin in the main app's Compliance section.
The demo has real sample data — appointments, patients, prescriptions — so you can explore freely.