Product Guide · Part 5 · Final

The layer underneath.

Audit logs, performance, settings, backups, suspension. The pages your team rarely opens — and that quietly carry every other page in the product. This is the unglamorous, load-bearing tier.

13-minute read 4 sections · 10 pages Compliance-ready by default
System health · live
All systems operational
Uptime
99.98%
Audit entries (24h)
1,847
Auto-backup
12 min ago
Suspended accounts
1
14:32:07visit_completedReem Al-Sayed · dr-ahmed
14:31:54queue_startedYousef Hammad · dr-ahmed
14:30:12backup_exportedauto-snapshot
14:28:41doctor_suspendeddr-mona
The stack

What you've seen, and what carries it.

Parts 1 through 4 covered the surfaces clinical staff live on every day. Part 5 covers what supports them: the audit trail, the analytics, the settings, the backup. Boring on a good day. Critical on a bad one.

Parts 1 & 2

Solo workspace

Doctor dashboard, reception dashboard, and the secondary pages that orbit them.

Covered
Parts 3 & 4

Station workspace

Multi-doctor admin, specialty routing, and per-doctor / per-receptionist screens in station mode.

Covered
Part 5

Admin & lifecycle layer

Audit, analytics, settings, backups, suspension. Carries every page above without ever being the page.

You are here
Section 01 · Audit & Compliance

Every action. Forever. Searchable.

Two pages — Audit Logs and Chat Audit — make every sensitive action and every staff message reconstructable. Compliance asks 'what happened on April 18 at 3pm', and the answer is one filter pill away. The trail is permanent — there's no edit, no delete.

At a glance
  • WhoStation admin · Solo doctor
  • OutcomeAudit-ready, by default
myclinic-system.com/station/audit-logs
Audit logs
Every sensitive action across the entire station — by every doctor and reception user — is recorded here.
1,847 entries · last 24h
Allqueue_started42visit_completed38patient_created12patient_edited7patient_deleted1doctor_suspended1backup_exported4login18
ActionMessageUserWhen
doctor_suspendedDr. Mona suspended — outstanding paymentadmin2026-05-06 14:28:41
visit_completedReem Al-Sayed · Cardiology examination · Rx: Amlodipine 5 mgdr-ahmed2026-05-06 14:32:07
queue_startedYousef Hammad — Examination · pinned to dr-ahmeddr-ahmed2026-05-06 14:31:54
queue_createdMona Farouk · Cardiology · shared (Any doctor)reception-mai2026-05-06 14:28:00
patient_editedTarek Helal — phone changed to +20 100 555 5520reception-mai2026-05-06 14:14:22
patient_deletedTest patient removed — created 2 minutes prioradmin2026-05-06 13:48:11
backup_exportedauto-snapshot · 12.3 MB · station_backup_2026-05-06_1430.jsonsystem2026-05-06 14:30:12
loginSuccessful login from 197.32.88.41dr-sara2026-05-06 08:02:18
Chat audit · todaylive
View all →
reception-maidr-ahmed· Cardiology14:14:00
Tarek's family asked specifically for you — pinned.
dr-saradr-ahmed· Cardiology14:18:32
Tarek's family asked specifically for you — pinned.
Cardiology room is free if you need it after the next one.
Floating comments

Numbered annotations on the mockup.

1
Why

Filter pills, not a multi-select

Action types are dynamic — pulled from what's actually in the data. 'All' is hardcoded as the first pill so reception always knows where 'unfiltered' lives.

2
Why

Action badges are colour-coded by severity

destructive (delete), warning (edit), primary (state change), info (creation), success (login). Five categories, five colours, scannable in seconds.

3
Why

Timestamps in ISO, never relative

Audit logs need to survive timezone shifts, daylight savings, and questions asked six months later. '14:32:07 yesterday' is a UX smell here.

4
Why

Username link, never email

Username is the canonical identity in audit. Email can change; usernames don't. dr-ahmed last year is dr-ahmed today.

5
Why

Chat audit is its own page

Same source-of-truth concept (replayable record), different shape. Date-grouped feed with reply nesting. Live tail via WebSocket; filters apply in real time.

Components

Building blocks.

<ActionFilterPills/>

ActionFilterPills

Dynamic pill row — All + every action that's actually in the log.

BehaviourPills generated from `Array.from(new Set(actions))`. Active pill highlighted; URL-synced.
DoRender in observed-frequency order, not alphabetical. Most-used filters land first.
Don'tHide pills past N=10. Audit has long-tail actions; admin needs all of them.
<AuditTable/>

AuditTable

Action · Message · User · When. Read-only, sortable, paginated.

BehaviourServer-side filter and pagination. Loads 50 rows per page; jumping past page 5 prompts a date filter.
DoKeep the "Message" column truncated with hover-tooltip. Long entries kill scan-time.
Don'tAdd inline actions ('Undo', 'Restore'). Audit is read-only — the trail is the trail.
<ChatAuditFeed/>

ChatAuditFeed

Date-grouped message feed with reply nesting.

BehaviourLive tail via socket; filter (doctor/date/search) applies to the live stream too.
DoShow specialty next to doctor names. Routing context is part of the audit.
Don'tAllow message edits or deletes anywhere. The audit is immutable — even bad messages.
<AuditWriter (server-side)/>

AuditWriter (server-side)

Writes one row per sensitive action across the entire app.

BehaviourAppend-only table. No update path. Failures are logged but never block the user action.
DoLog the actor, target, before/after on edits. Compliance asks for diffs, not just events.
Don'tTry to summarise. Raw events are reconstructable; summaries are interpretation.
User flow

Reconstructing 'who did what, when'.

01

Pick action type

patient_deleted, queue_started, doctor_suspended — whatever you're chasing.

02

Bound the time

From/to date inputs above the table. Default is today.

03

Read the row

Action · Message · User · ISO timestamp. Four fields, complete picture.

04

Export if needed

Improvement: CSV export for the regulator. Currently view-only.

Pro tips

Get more out of this layer.

Compliance

Audit lives forever

There is no retention policy in the schema. If your jurisdiction requires one, add it as a scheduled job — but consult legal first. Most clinics keep the trail indefinitely.

Speed

Bookmark filtered URLs

Filters live in URL params. 'All patient_deleted entries last quarter' becomes a bookmark — same view, every time.

Insight

Cross-reference Chat Audit

When something looks off in the action log, Chat Audit is where the human reasoning lives. 'Why was this patient removed?' often has an answer in the messages.

Improvement

Diff view for edits

Improvement: 'patient_edited' currently shows a one-line message. A before/after diff would let admin see exactly what changed without opening the patient.

Section 02 · Performance · Medications · Financial

Three dashboards, one rhythm.

Performance, Medications, and (in solo) Financial share a layout: date-range presets, stat cards, charts. Different data, identical mental model. Open one, you've effectively learned all three.

At a glance
  • WhoStation admin · Solo doctor
  • OutcomeOperational decisions, defensible
myclinic-system.com/station/performance
Performance
Station-wide visit analytics. Filter by a single doctor for a per-doctor view.
2026-04-06 → 2026-05-06
TodayYesterday7d30d90dCustomDoctor:All doctors
Total visits
287
Examinations
156
Follow-ups
97
Consultations
34
Avg waiting
11m
Avg session
9.2m
Idle time
18%
ETA finish
17:42
Daily visits
peak: 18 (Tue)
Apr 6Apr 22May 6
Gender split
287total
Male 172Female 115
Top diagnoses · 30d
1Hypertension47
2Type 2 diabetes32
3Acute pharyngitis28
4Iron deficiency anemia21
5Migraine, tension type18
Solo Performance has no doctor filter — there's only one doctor. Station Performance defaults to "All doctors" with a per-doctor scope.
Floating comments

Numbered annotations on the mockup.

1
Why

Date presets in a row, custom revealed on click

Today · Yesterday · 7d · 30d · 90d · Custom. Custom expands to From/To inputs + Apply. The Apply button is critical — load doesn't fire on every keystroke.

2
Why

Stat cards as the always-readable layer

Charts are for understanding, stats are for glancing. The stat row should answer 'is this period normal?' in 5 seconds. 8 cards is the upper bound.

3
Why

Custom SVG charts, not a library

Recharts and Chart.js add 100+ KB for what's mostly a single line and a pie. The product hand-rolls them — gradient fills, axes, hover circles, all in CSS-positioned SVG.

4
Why

Top-N lists, not a tag cloud

Top diagnoses, top medications — always ranked, always with counts and bars. Bar lengths are normalised within the list, so 'second most prescribed' is glanceable.

5
Why

Per-doctor filter only on Station

Solo doctor's Performance has no doctor selector — there's only one. Station's Performance defaults to 'All doctors' but lets admin scope to a single doctor.

Components

Building blocks.

<DateRangePresets/>

DateRangePresets

Today · Yesterday · 7d · 30d · 90d · Custom — the same row across all three dashboards.

BehaviourSwitching presets fires a load. Custom reveals From/To and an Apply button.
DoPersist the preset in URL. Reload should not reset to 'Today'.
Don'tAuto-apply on every Custom-input change. The user is mid-typing.
<StatCard/>

StatCard

Icon + label + tabular value + tone. Used everywhere data needs a header number.

Behaviour8 max per dashboard; layout is responsive 4×2 → 2×4 → 1×8.
DoTabular numerics. Otherwise comparing periods is harder than it should be.
Don'tAdd deltas without a comparison period defined. 'No change' next to '+12%' is meaningless without saying vs. what.
<DailyTrendLine/>

DailyTrendLine

Custom SVG line with gradient fill — daily visits, prescriptions, or revenue.

BehaviourHover circles + tooltip showing exact day count. Peak label always visible.
DoShow a "no data" empty state with the right message ("No visits in this period"), not a flat 0-line.
Don'tAdd zoom/pan. Date range is a separate control; double-controlling time confuses.
<DonutChart (gender / visit type / active vs idle)/>

DonutChart (gender / visit type / active vs idle)

Two- or three-segment donut with center label.

BehaviourComputed gradient fills. Legend cards below show segment counts.
DoStick to ≤4 segments. Beyond that, a bar chart is honest; a donut is decorative.
Don'tAnimate spin-in. It's the same data after every load — animation is friction.
<TopNList/>

TopNList

Numbered ranking — top 10 diagnoses, top 10 medications.

BehaviourBars are length-normalised within the list; #1 fills the bar.
DoShow counts beside the bar, not on hover. Audit-friendly, copy-pastable.
Don'tTruncate name aggressively. Long diagnoses are common; ellipsis them only past a real measured limit.
<Sparkline (Medications table)/>

Sparkline (Medications table)

Tiny per-row trend line in the Medications Analytics table.

Behaviour30-day mini line embedded in the row, no axis, no labels.
DoPair with "last used" date. A sparkline + a date is more useful than either alone.
Don'tAdd hover tooltips. Sparklines are pre-attentive — interaction is overkill.
User flow

A monthly review, in four moves.

01

Switch to 30d

Default Today is for live ops; review needs a window.

02

Scan the stats

Visits, breakdown by type, avg duration, idle time — the period in eight numbers.

03

Read the trend

Line chart for volume, bar for top diagnoses, donut for type split.

04

Act on the outlier

One spike usually has one cause. Cross-reference Audit Logs if "what happened?" is the question.

Pro tips

Get more out of this layer.

Speed

Bookmark URL with date range

Date range lives in URL. 'Last quarter, dr-ahmed only' becomes a bookmarked tab — open it monthly.

Discipline

Solo doctors get Financial

Station owners don't see /doctor/financial — billing in station mode is the admin's job, handled in /station/settings + external invoicing. Solo bundles the dashboard.

Improvement

Export to CSV

Improvement: every dashboard could ship a 'Export this view' button to CSV. Currently the data is reportable only by screenshot.

Insight

Don't conflate volume with revenue

A "follow-up spike" can be flat revenue (often free or discounted). Always read the visit-type breakdown alongside the volume line.

Insight

Top diagnoses = your specialty signal

If the top 10 diagnoses don't match what you think you treat, the chart is either teaching you something or revealing data-entry drift. Both are worth investigating.

Improvement

Anomaly badges

Improvement: stat cards could surface a small ⚠ when the value is >2σ from the trailing 90d mean. Anomalies hide in plain sight today.

Section 03 · Settings & Consultation Reminder

Sticky knobs that change everyone's day.

Settings is one form, five sections — clinic identity, working hours, queue flow, prescription footer, automatic backup. Consultation Reminder (solo only) is the WhatsApp follow-up template that fires N days after every completed examination. Both are 'edit rarely, depend everywhere'.

At a glance
  • WhoStation admin · Solo doctor
  • OutcomeBehaviour change without redeploy
myclinic-system.com/station/settings
Settings
Station-wide identity, schedule, prescription footer, and backup. Applies to every doctor in the station.
Clinic identityUpdated 2 hours ago
Al Nour Medical Clinic
Dr. Ahmad Yousef
/uploads/logo.png
Working hours & schedule
SunMonTueWedThuFriSat
09:00
17:00
12
Per-day overrides: Thursday uses 09:00–14:00 · all other days use the default.
Queue flow & no-show
Late at 10 min, no-show at 30 min, reinsert after 2 waiting. Plain-English summary of the four numbers below.
10
30
2
On
Automatic backup
Enabled
60
12 min ago
Last 10 snapshots
Consultation reminderSolo only
Hello 👋 It's been a while since your last consultation — we hope you're feeling well. Reply here if you'd like to book a follow-up.
118 / 4000 characters · last saved 14:30:12
60 days
Last sweep: dispatched 4 · skipped 12 · failed 0
Floating comments

Numbered annotations on the mockup.

1
Why

Sections, not tabs

Tabs hide settings; sections expose them. The page is meant to be scanned end-to-end the first time, then jumped-to via Cmd+F.

2
Why

Working hours: defaults + per-day overrides

Most clinics have one schedule; some have a different Friday. Defaults handle the common case; per-day overrides handle the exception without duplicating the form.

3
Why

Queue flow: late tolerance + no-show after

Two independent thresholds. 'Late' is a soft signal (warn reception); 'No-show' is a hard transition (auto-status flip). Separating them prevents 'just a bit late' from becoming a no-show.

4
Why

Auto-backup: off by default

Backup runs only if explicitly enabled. The clinic should know what's writing snapshots — silent automation is the wrong default for compliance-sensitive data.

5
Why

WhatsApp reminder, not email

Egypt and most of MyClinic's catchment use WhatsApp as the primary channel. Email reminders would have ~30% open rates; WhatsApp messages get read in minutes.

Components

Building blocks.

<SettingsForm/>

SettingsForm

One form, five collapsible sections, one Save.

BehaviourOptimistic save with toast. 'Updated [date]' badge in the header.
DoSurface validation inline on the offending field. Don't block save until the user fixes errors elsewhere.
Don'tAdd an 'Are you sure?' modal on Save. The user clicked Save; they're sure.
<WorkingHoursEditor/>

WorkingHoursEditor

Day-of-week toggles + default start/end + optional per-day overrides.

BehaviourClicking a day enables overrides; otherwise reads "Uses default · 08:00–17:00".
DoShow the rendered schedule as a strip below the editor. Live preview > inferring from form state.
Don'tValidate that hours overlap appointments. That's an appointment-page concern, not a settings concern.
<QueueFlowSettings/>

QueueFlowSettings

Smart queue prioritisation toggle, auto-move, late tolerance, no-show after, reinsert-after-N.

BehaviourNumbers in minutes; range bounded (0–240).
DoShow a one-line plain-English summary above the inputs. 'Late at 10 min, no-show at 30 min' is faster to grok than four input boxes.
Don'tConflate late and no-show into one field. They serve different conversations.
<AutoBackupSettings/>

AutoBackupSettings

Toggle + interval (minutes). Retains last 10 snapshots automatically.

BehaviourDisabled state shows interval as plain text. Enabled state surfaces a 'Last snapshot: 12 min ago' line.
DoDefault to Off. The clinic chooses to opt in.
Don'tAllow interval < 5 min. Under-frequent isn't an issue; over-frequent fills disk for no benefit.
<ReminderTemplateForm (solo)/>

ReminderTemplateForm (solo)

WhatsApp follow-up template with optional image.

BehaviourText + image + days-after + enabled toggle. 'Run now' button manually triggers the sweep.
DoShow the per-clinic placeholder substitutions ({{patient_name}}, {{clinic_name}}) in the help text.
Don'tSend a "test" message to the doctor's own number. They're not the audience; the patient is.
User flow

Configuring a new station, in four moves.

01

Identity

Clinic name, doctor name, logo URL.

02

Schedule

Working days + default hours + per-day overrides.

03

Queue flow

Late tolerance, no-show after, smart prioritisation.

04

Backup

Enable auto-backup, set the interval.

Pro tips

Get more out of this layer.

Discipline

Settings live in the database, not in env vars

Changes apply immediately, no redeploy. This is by design — settings are operations, not configuration.

Insight

Set late + no-show carefully

Tight thresholds create no-show inflation; loose thresholds let walk-ins block reception. Most clinics land at "late = 10 min, no-show = 30 min".

Insight

Reminder text: keep it short, kind, optional

A two-sentence "hope you're well, reply if you'd like a follow-up" outperforms a six-sentence template. Patients reply to humans, not to forms.

Improvement

Templated reminders per visit type

Improvement: a follow-up examination needs a different message than a chronic-care follow-up. One template per visit_type would close that gap.

Missing

Multi-language settings

Improvement: clinic identity + reminder text could carry a per-language variant. Today they're a single string each.

Compliance

Audit your changes

Settings changes write to /audit-logs as edits. If a setting was changed 3 weeks ago, the trail tells you who and when.

Section 04 · Backup & Lifecycle

Suspend, snapshot, restore. Never delete.

The lifecycle layer covers what happens when accounts pause, when data needs to leave, and when the day before yesterday needs to come back. Suspension over deletion, snapshots over manual exports, soft-delete over hard. The recovery path always exists.

At a glance
  • WhoStation admin · Solo doctor
  • OutcomeReversible by default
myclinic-system.com/doctor/backup
Backup
Export, import, or snapshot the entire clinic database.
auto-backup · enabled
Export database

Download a complete JSON backup — patients, visits, prescriptions, medications, appointments, queue, attachments, and settings.

Keep backups in a secure location. The file contains sensitive patient information.
Import from backup

Restore data from a previously exported JSON file. Existing records with matching IDs are skipped — no overwrites.

Validation + duplicate detection
Auto-saved snapshots10 / 10
Oldest auto-rotated as new ones arrive
station_backup_2026-05-06_1430.json12.3 MB12 min ago
station_backup_2026-05-06_1330.json12.3 MB1 hour ago
station_backup_2026-05-06_1230.json12.2 MB2 hours ago
station_backup_2026-05-06_1130.json12.2 MB3 hours ago
Suspended account · dr-monaSuspended
Reason
Outstanding payment
Suspended at
2026-05-06 14:28:41
History preserved
142 visits · 24 patients
Suspended state preserves the trail. No queue items, no audit data, no past visits are touched.
Soft-delete pattern · Patient, Visit, and Prescription records carry a deletedAt field. Deleting from the UI sets the timestamp; queries filter by where: { deletedAt: null }. Recovery is a SQL operation — intentional inconvenience for irreversible-feeling actions.
Floating comments

Numbered annotations on the mockup.

1
Why

Backup is JSON, not SQL

Self-contained, human-readable, portable. SQL dumps are tied to a schema version; JSON is durable across migrations.

2
Why

Import skips duplicates, never overwrites

If a record with the same id exists, it's preserved. The import is additive — a safety guarantee that lets reception experiment without fear.

3
Why

Auto-snapshots are timestamped, file-listed

Every snapshot is a real file on disk, listed by name and size. No magical retention; admin can see what's there and how big.

4
Why

Suspension preserves history

Suspending dr-mona doesn't touch her past visits, her audit trail, or her patients. She can't log in; everything else continues.

5
Why

Soft-delete with deletedAt timestamp

Patients, visits, prescriptions all carry deletedAt. Queries filter by `where: { deletedAt: null }`. The data is recoverable; the UI just hides it.

Components

Building blocks.

<BackupExport/>

BackupExport

One-click full-clinic export to JSON.

BehaviourIncludes patients, visits, prescriptions, medications, appointments, queue, attachments, settings.
DoSurface the file size before download. 12 MB on slow connections matters.
Don'tStrip patient identifiers. Backup is full-fidelity by definition.
<BackupImport/>

BackupImport

JSON file dropzone with validation.

BehaviourMin 50 bytes; checks shape; returns counts of imported vs skipped.
DoShow the import counts as a toast: 'Patients 8 · Visits 23 · Skipped 4'.
Don'tAllow overwrites. Importing should never destroy what's already there.
<SnapshotList/>

SnapshotList

Filename · size · timestamp for every retained auto-snapshot.

BehaviourFilename is monospace; size is right-aligned; timestamp is human-readable but tabular.
DoLink to "Settings · Auto-backup" if the list is empty.
Don'tDelete-button on snapshots. Auto-rotation handles retention; manual delete creates ambiguity.
<SuspensionFlow/>

SuspensionFlow

Confirm-then-suspend a doctor or reception account.

BehaviourConfirm modal with explicit phrasing. Suspended status renders /suspended page on next request.
DoShow the suspension reason in /audit-logs message field. "outstanding payment" or whatever the truth is.
Don'tAuto-suspend on inactivity. Suspension is a deliberate operations decision, not a behavioural one.
<ReactivationButton/>

ReactivationButton

Flip a suspended user back to active.

BehaviourOne click; writes a `doctor_activated` audit event.
DoSurface "Reactivate" prominently on the Doctors / Reception staff table for suspended rows.
Don'tRequire admin to set a new password to reactivate. Suspension and credentials are different concerns.
<Soft-delete (Patient / Visit)/>

Soft-delete (Patient / Visit)

`deletedAt` timestamp on the record; queries filter by null.

BehaviourUI hides the row; the data is intact. Audit logs the delete with action `patient_deleted`.
DoReserve hard-delete for genuine bad data (test patients, typos).
Don'tBuild an 'undelete' UI for clinical staff. The recovery path is admin via SQL, intentionally inconvenient.
User flow

A staff departure, in four moves.

01

Suspend account

From /station/doctors → row → Suspend. Confirm.

02

Reassign their queue

Pinned items become invisible. Reception edits each pinned row's assignment to "Shared".

03

Audit the suspension

`doctor_suspended` lands in /audit-logs with the reason in the message field.

04

Reactivate or leave

Suspended is a state, not a tombstone. Reactivation is one click whenever they return.

Pro tips

Get more out of this layer.

Discipline

Suspend, don't delete

Deleting a doctor leaves orphan visits. Suspending preserves the trail. Deletion is for test accounts and typos only.

Hygiene

Test the import path quarterly

Backups are only as good as the restore. Take a snapshot, import it into a staging clinic, verify the patient count. Quarterly is the minimum.

Insight

Snapshots are local files

Auto-snapshots live on the server's disk. For off-site backup, schedule a job to copy the latest snapshot to S3/Drive/your secure location.

Improvement

Cloud-backed snapshots

Improvement: a built-in 'backup to S3-compatible bucket' option would close the off-site backup gap without scripting.

Missing

Snapshot diff

Improvement: "diff this snapshot against current state" would let admin see what's changed since a known-good point. Currently only re-import gives that signal.

Security

Encrypt at rest

JSON snapshots are sensitive — patient names, phones, diagnoses. Encrypt the storage volume; never copy snapshots into version control.

End of guide

That's the whole product.

Five parts, every screen — from the consultation cockpit to the audit trail, from the routing model to the snapshot list. The product was designed to read in this order, but every page stands on its own. Bookmark the parts you need.

20+
Pages mocked
60+
Components broken down
100+
Pro tips & improvements
Built with care for the way real clinics work.