Atomic component discipline, the Page → Layout → Skin → Theme composition model, and the full screen inventory (auth, core, and Healthcare's built Core OPD module) with proposed routes and endpoints.
surfaces.md, access-model.md,
10-BACKEND.md. Standing in for the real ui/ app until the frontend stack is chosen
and this placeholder is replaced with actual routed pages.Four layers, each only extending the one below it. Nothing below "Skin" is ever tenant-aware; nothing above "Component behavior" is ever business-logic-aware.
A Page owns data-fetching and composes Organisms/Templates into its own content, then hands that content to Layout as children. Layout owns chrome and skin/theme resolution — a Page never reads skin or theme directly.
Page (e.g. LoginPage, DashboardPage, ConsultPage)
→ fetches its own data
→ composes Templates/Organisms into `children`
→ renders <Layout>{children}</Layout>
Layout (e.g. AuthLayout, AppLayout)
→ resolves activeSkin (from subdomain → organisation → domain)
→ resolves activeTheme (nested under activeSkin; user/session preference or skin default)
→ provides both to everything it renders via context (tokens + terminology strings)
→ renders NavShell / PrimaryNav (AppLayout only) + {children}
Derived from the patterns already repeated across Hope Clinic's built screens — these are the reusable pieces every domain's screens should be assembled from, not redesigned per module.
| Component | Notes |
|---|---|
| Button | Primary / secondary / danger variants (e.g. "Create staff account", "Deactivate", "Submit prescription · Patient OUT"). |
| Input / Select / DateInput / Checkbox | Bare form controls, label rendered by the FormField molecule, not the atom itself. |
| StatusPill | Colored short label — WAITING / IN / OUT / DONE, ACTIVE / CANCELLED, Coming Soon. |
| Badge | Plan/entitlement badges — "Core OPD — Included", "Optional Add-on — Coming Soon". |
| Icon, Avatar/RoleTag, LinkTab | Nav and identity primitives. |
| Component | Notes |
|---|---|
| FormField | Label + input + inline error. Every form on every screenshot uses this shape. |
| SearchBar | Filter input + Search + Clear/Show all — Patient List, Visit History, Patient History, Front Desk lookup. |
| StatCard | Count + label, color-coded — the unit that composes into StatBar. |
| FilterRow | Multi-field filter (patient/year/month + Apply/Clear) — Visit History. |
| ModuleTile | Title + entitlement badge — one cell of the dashboard's tile grid. |
| TableRow / PaginationControl | Row rendering + "Previous / Page X of Y / Next" — identical across every list screen. |
| Component | Composed of | Behavior owned |
|---|---|---|
| NavShell | Logo/org name, user name + role badge, Log out | Session display, logout action |
| PrimaryNav / TabNav | LinkTab list | Active-route highlighting, permission-based visibility |
| StatBar | StatCard × N | Live counts (Waiting/In/Out/Done) — Dashboard, Front Desk, Doctor Consultation all reuse this exact organism |
| TableList | SearchBar/FilterRow + count line + table + PaginationControl | Search, filter, paginate — Patient List, Visit History, Staff Accounts, Medicine Catalogue all reuse this shape |
| ModuleTileGrid | ModuleTile × N | Reads entitlement state, renders enabled vs. "Coming Soon" |
| VisitHistoryModal | Modal + FilterRow + status list | Per-patient visit drill-down, audit-logged open event |
| MedicineLineEditor | Repeatable FormField row (Medicine/Dosage/Frequency/Duration/Timing) + Add/Remove | Dynamic row add/remove, per-field "Print" toggles |
| ConsultationForm | Symptoms/Diagnosis/Examination/Reports fields + MedicineLineEditor + Follow-up + Investigations/Advice | Save draft vs. Submit-and-mark-OUT, previous-consultations copy-forward |
| Component | Used by |
|---|---|
| AuthLayout | Login, Password Recovery, Password Help, Change Password — centered card, no PrimaryNav, still skinned (org logo resolved from subdomain before login) |
| AppLayout | Every authenticated page — NavShell + PrimaryNav + content slot, resolves activeSkin/activeTheme |
| DashboardTemplate | Dashboard — StatBar (optional, permission-gated) + ModuleTileGrid |
| ListDetailTemplate | Patient List, Visit History, Staff Accounts, Medicine Catalogue, Patient History |
| QueueConsultTemplate | Front Desk (Today's Visits & Tokens), Doctor Consultation queue + detail |
Build one real skin now (Hope Clinic, Healthcare domain) against actual data. Don't design a second skin speculatively — just make sure adding one is a config change, not a component change.
| Layer | Allowed to override | Never touches |
|---|---|---|
| Skin | Logo, org/brand name, accent color default, terminology strings (Patient/Visit/Prescription), which modules render in the tile grid | Component markup, component behavior, layout structure |
| Skin theme | Color tokens, light/dark mode, density | Branding/logo, terminology, module set — those belong to the parent skin, not the theme |
One login per organisation, resolved from the wildcard subdomain (surfaces.md §5.1) — no separate admin/employee login. Uses AuthLayout.
| Screen | Route | Status | Who | User story | Endpoint(s) | Purpose |
|---|---|---|---|---|---|---|
| Login | /account/login |
proposed | Public, pre-auth | As clinic staff, I sign in with username/password to reach my role's dashboard. | POST /api/v1/auth/login |
Resolve org from hostname (ORGANISATION_NOT_FOUND if unrecognized), authenticate, issue JWT (roles/permissions/scopes claims). |
| Password Recovery | /account/password-recovery |
proposed | Public, pre-auth | As a user who forgot my password, I request a reset link/code. | POST /api/v1/auth/password-recovery |
Self-service reset initiation, scoped to the resolved organisation. |
| Password Help | /account/password-help |
proposed | Public, pre-auth | As a user stuck on reset, I want plain guidance or a contact path. | Static content — no endpoint | Fallback support content when self-service reset isn't enough. |
| Forced Change Password | /account/change-password |
proposed | Authenticated, must_change_password |
As a new staff member given a temporary password, I must set my own before using the app. | POST /api/v1/auth/change-password |
Security gate — blocks dashboard access until cleared (Administration screenshot shows "Temporary password" issuance that requires this). |
Per surfaces.md §2.2 — not entitlement-gated, available to every organisation regardless of subscribed modules. Only Dashboard has a built screenshot today; the rest are spec-only.
| Screen | Route | Status | Permission | User story | Endpoint(s) | Purpose |
|---|---|---|---|---|---|---|
| Dashboard | / |
built | Authenticated, all roles | As any staff member, I land on one dashboard showing today's activity and the modules I'm authorised for. | GET /api/v1/dashboard/summaryGET /api/v1/modules/entitled |
Role-agnostic landing page; sections render per-permission, not per-role redirect (surfaces.md §5.2). |
| Organisation (Enterprise Units) | /organisation |
planned | ORG_VIEW |
As an admin, I view/manage our branch & department structure. | GET /api/v1/organisation/units |
ps_enterprise_units tree — org-defined types, not a fixed hierarchy. |
| Organisation Masters | /organisation-masters |
planned | Manage classifications | As an admin, I manage department/position/responsibility masters and classification codes. | GET/POST /api/v1/organisation-masters |
Classification catalogue admin, org-scoped. |
| Access Control | /access-control |
planned | Manage roles & permissions | As an admin, I define roles and assign permissions to staff. | GET/POST /api/v1/access-control/rolesGET /api/v1/access-control/permissions |
ps_roles / ps_permissions / ps_role_permissions admin. |
| Help | /help |
planned | Authenticated | As any user, I look up in-app help. | GET /api/v1/help/articles |
Support content, org/domain-aware. |
| Profile | /profile |
planned | Authenticated, own record only | As any user, I view/edit my own profile and change my password voluntarily. | GET/PATCH /api/v1/profile |
Self-service account page. |
The three entitled "Core OPD" modules plus the two CLINIC_ADMIN-only oversight surfaces (Administration, Clinic Records). All have real screenshots. Route names for the two oversight surfaces are proposed — not yet confirmed against Hope Clinic's actual network calls.
| Screen | Route | Status | Role | User story | Endpoint(s) | Purpose |
|---|---|---|---|---|---|---|
| Front Desk — Patient Registry | /modules/front-desk (tab: registry) |
built | FRONT_DESK | As front desk staff, I search for an existing patient before registering a new one, to avoid duplicates. | GET /api/v1/modules/front-desk/patients?q=POST /api/v1/modules/front-desk/patients |
Patient intake into health_patients. |
| Front Desk — Today's Visits & Tokens | /modules/front-desk (tab: tokens) |
built | FRONT_DESK | As front desk staff, I create a token for a patient's visit and track live queue state per doctor. | POST /api/v1/modules/front-desk/visitsGET /api/v1/modules/front-desk/visits/today |
health_visits token/queue state machine (Waiting/In/Out/Done); surfaces prior-day visits needing closure. |
| Front Desk — Billing & Prescription Release | /modules/front-desk (tab: billing) |
built | FRONT_DESK | As front desk staff, I release billing and the printed prescription once a patient's consult is OUT. | GET /api/v1/modules/front-desk/billing/pendingPOST /api/v1/modules/front-desk/billing/{visitId}/release |
Closes the visit's billing/pharmacy-release state on health_visits. |
| Doctor Consultation — Queue | /modules/doctor-consultation |
built | MD_DOCTOR, DERMATOLOGIST | As a doctor, I see my waiting/in-progress patients so I know who to call next. | GET /api/v1/modules/doctor-consultation/queue |
Per-doctor view of health_visits, scoped to the treating doctor's own tokens. |
| Doctor Consultation — Consult Detail | /modules/doctor-consultation/visits/:visitId |
built | MD_DOCTOR, DERMATOLOGIST (treating doctor only) | As the treating doctor, I record symptoms/diagnosis/treatment and submit a prescription, marking the patient OUT. | GET /api/v1/modules/doctor-consultation/visits/{id}POST /api/v1/modules/doctor-consultation/visits/{id}/consultation |
Writes health_consultations + health_prescription_items; record-level check (§6.3 of 10-BACKEND.md) restricts clinical content to the treating doctor. |
| Patient History — list | /modules/doctor-consultation/patients |
built | MD_DOCTOR, DERMATOLOGIST | As a doctor, I look up any registered patient to review their full recorded history. | GET /api/v1/modules/doctor-consultation/patients?q= |
Directory over health_patients; every detailed-history open is audit-logged. |
| Patient History — visit detail modal | modal, opened from list | built | MD_DOCTOR, DERMATOLOGIST | As a doctor, I open one patient's visit list, filterable by year/month. | GET /api/v1/modules/doctor-consultation/patients/{id}/visits |
Per-patient health_visits history; writes to ps_audit_logs on open. |
| Pharmacy — Prescription Queue | /modules/pharmacy (tab: queue) |
built | PHARMACY | As pharmacy staff, I see prescriptions pending dispense. | GET /api/v1/modules/pharmacy/queue |
Reads health_prescription_items where dispense is pending. |
| Pharmacy — Medicine Catalogue | /modules/pharmacy (tab: catalogue) |
built | PHARMACY | As pharmacy staff, I maintain the shared regular-use medicine list doctors pick suggestions from. | GET /api/v1/modules/pharmacy/medicinesPOST /api/v1/modules/pharmacy/medicines |
health_medicines — a suggestion catalogue only; editing it never rewrites an already-issued prescription. |
| Administration — Staff Accounts | /administration (tab: staff) |
built route proposed | CLINIC_ADMIN | As the clinic admin, I create staff logins with a temporary password and see everyone's account status. | GET /api/v1/administration/staffPOST /api/v1/administration/staff |
ps_users + role assignment for this org; sets must_change_password. |
| Administration — Plans & Module Pricing | /administration (tab: plans) |
built route proposed | CLINIC_ADMIN | As the clinic admin, I see our current plan and available add-ons — read-only. | GET /api/v1/administration/subscription |
Read-only view over ps_pricing_plans / ps_module_pricing / ps_organisation_subscriptions — commercial metadata, never itself an access gate. |
| Clinic Records — Patient List | /clinic-records (tab: patients) |
built route proposed | CLINIC_ADMIN | As the clinic admin, I get operational oversight of registered patients without seeing clinical notes. | GET /api/v1/clinic-records/patients |
Same health_patients data as Patient History, deliberately without health_consultations content. |
| Clinic Records — Visit History | /clinic-records (tab: visits) |
built route proposed | CLINIC_ADMIN | As the clinic admin, I review the operational visit register — billing/pharmacy status, not clinical content. | GET /api/v1/clinic-records/visits |
health_visits oversight; reuses the same VisitHistoryModal as Patient History. |
| Item | Why it's open |
|---|---|
| Frontend framework/stack | No decision recorded anywhere in streamlined/ — this file is still a stand-in placeholder. Every component/template name above is framework-agnostic on purpose. |
| Administration & Clinic Records — real routes | Reverse-engineered from screenshots only; actual Hope Clinic network calls weren't captured for these two screens the way the schema-validation pass captured others. |
| Where skin/theme resolution happens | Server-side injected at the AppLayout/AuthLayout render, vs. client-fetched after hostname resolution — either satisfies the composition model in §1, not decided which yet. |
| All endpoint paths in §4–§6 | routes/api.php doesn't exist yet (pre-scaffolding, per project status) — these are proposed names following the /api/v1 + envelope convention in 10-BACKEND.md §8, to be confirmed when routes are actually written. |