Logging in
dashboard/login.php checks the submitted username/password against the users table with PHP's password_verify() against a bcrypt hash stored in password_hash. There is no password-reset-by-email flow - resetting a password means editing the row directly, via the Users page below or SQL.
A default account is seeded by database/schema.sql:
username: admin
password: TruPath@2026
dashboard/login.php and this guide - treat it as a known value, not a secret, until it's rotated.Session mechanics
All session handling lives in includes/dashboard_session.php:
| Function | Purpose |
|---|---|
dashboard_start_session() | Starts the PHP session if one isn't active yet. Called internally by the functions below. |
dashboard_current_user(): ?array | Returns the logged-in user's session data (id, username, full_name, role), or null if nobody is logged in. |
dashboard_require_login(): array | Redirects to login and exits if nobody is logged in; otherwise returns the current user. Every dashboard page calls this first. |
dashboard_require_role(string $role): array | Calls dashboard_require_login(), then responds 403 and exits if the user's role doesn't match. Only dashboard/users.php uses this today (gated to 'admin') - the only page with role-based access control. |
dashboard_login(array $user): void | Called by login.php after a successful password_verify(). Regenerates the session id first, to prevent session fixation. |
dashboard_logout(): void | Clears and destroys the session. dashboard/logout.php calls this then redirects to login. |
Dashboard pages
All pages share a common header/nav/footer via dashboard/_layout.php, and a common list+modal CRUD pattern (POST action=create|update|delete handled at the top of the same file, ?edit=<id>/?new=1 opening an add/edit dialog, a DataTables-enhanced list). dashboard/pathogens.php is the clearest example of this pattern.
| Page | Purpose |
|---|---|
dashboard/index.php | Overview - record counts and data-library metadata. |
dashboard/reports.php | Browse/filter previously generated reports, download their PDFs. |
dashboard/pathogens.php | Manage the pathogens table - this product's own 12-organism fungal/dermatophyte/yeast panel. |
dashboard/antimicrobials.php | Manage the antimicrobials table (this product's CLINICAL table - every field is actually consumed by ClinicalEngine::profile()). |
dashboard/recommendations.php | Manage per-organism-source antimicrobial recommendation rankings (EMBEDDED_MASTER_ROWS). |
dashboard/icd10.php | Manage ICD-10 codes, including which are "primary" tier - this drives the real codingWarning API response flag. |
dashboard/users.php admin only | Manage dashboard accounts - see below. |
How this product's clinical engine actually differs
This instance is cloned from tpl-womens-health-plus's PHP/MySQL architecture, and its underlying organism panel / drug-info table / master recommendations table are content-identical to tpl-derm's own fungal-drug data - but its clinical algorithms and 1102x1427 report layout are this product's own, ported from the approved TRUFungal PCR Report Generator v1.10 standalone generator:
- 1102x1427 report layout (the Wound/RPP/STI family layout), not Derm's 612x792 canvas, despite sharing Derm's underlying fungal data.
- No resistance-gene concept, no dosing-preset table, no TomSelect dependency - free-text strength/dosing/allergies, plain
<select>pathogen/alternative pickers. allergiesis a single free-text field, not a multi-select list.- A real ICD-10 validation signal. Unlike Derm/Wound, this product tracks "primary" tier codes and surfaces a genuine
codingWarningflag when none of a case's selected codes is primary. - A distinct alternative-ranking algorithm with activity-group diversification (
ClinicalEngine::rankAlternatives()) - scores by coverage, then summed rank position (lower is better), then alphabetically, then diversifies within a tied tier byactivity_groupso the picks aren't three drugs of the same class. - Distinct kidney/liver escalation rules (
ClinicalEngine::profile()) reading the Antimicrobials page's ownkidney/livercolumns directly (no regex text-matching): kidney disease + YELLOW baseline → RED for any drug; liver disease + azole/terbinafine name + GREEN baseline → YELLOW. - Amphotericin-B coverage-key normalization - every amphotericin-B variant collapses to one coverage key.
- A frozen, hardcoded "Pathogens Assessed" panel - 12 hand-authored one-line clinical-context sentences, not derived from the Pathogens table at render time.
- Max 3 detected pathogens, single page, no pagination.
.xlsx in the browser and cache it in localStorage. This build intentionally does not replicate that - update the mapping via the dashboard pages above, or by editing reference_source/TruPath_Generator_Data_Library_Fungal.json and re-running tools/import_data_library.php, the same server-side admin-managed convention every sibling product already uses.Users (add/remove dashboard accounts)
dashboard/users.php is an admin-role-only page for managing who can log into the dashboard:
- Add - username, full name, role (
adminorstaff), and a password (minimum 8 characters, hashed withpassword_hash($password, PASSWORD_DEFAULT)before storage - never stored or logged in plaintext). - Edit - same fields; leave the password field blank to keep the existing password unchanged.
- Delete - removes the account. You cannot delete the account you're currently logged in as (hidden on your own row, and rejected server-side if attempted directly).
admin (can access the Users page) vs. everything else (cannot). No per-page/per-action granularity beyond that single check.What the Admin Dashboard does NOT do
- It does not provide an audit trail of who changed what reference data or when.
- It does not send password-reset emails or support any self-service account-recovery flow - a locked-out account has to be fixed by another
adminuser via the Users page, or directly in the database. - It does not rate-limit or lock out repeated failed login attempts.
- It does not manage the report-generation API's
X-API-Key- that's a separate config value covered in the API docs, unrelated to anyusersrow.