TrustBeacon Auditor Development Documentation
Version: 0.1.8

Purpose

This file is a technical record for developers who need to maintain or extend
TrustBeacon Auditor. It explains the version 0.1.8 admin dashboard
implementation: what was built, why it was structured this way, and where a
future developer should and should not make changes.

No development documentation file existed before this version. This file was
created to hold that record going forward, using the same plain-text style as
readme.txt, changelog.txt, scoring.txt, findings.txt, and roadmap.txt in this
directory.

-------------------------------------------------------------------------------
1. Administrative architecture
-------------------------------------------------------------------------------

Before 0.1.8, admin/class-admin-page.php was a single class that both handled
the audit request AND printed every line of HTML, including a large inline
results table and a business-summary table with an inline style attribute.

In 0.1.8, TBAUD_Admin_Page (admin/class-admin-page.php) is a controller only.
It:

* Registers the admin menu and stores the returned page hook suffix.
* Registers an admin_enqueue_scripts callback that enqueues the dashboard
  stylesheet only when the current hook suffix matches the stored one.
* Reads the current domain (home_url() host).
* Verifies the capability check and the wpta_run_audit_nonce nonce, then
  calls TBAUD_Audit_Runner::run() exactly as before if the form was
  submitted and the nonce is valid.
* Delegates all markup to view partials in admin/views/ via a small
  render_view() helper that copies an array of variables into local scope
  and includes the matching view-*.php file.

New views (admin/views/):

* view-header.php - title, audited domain, Run Audit/Re-scan button, nonce
  field, notice, and the unobtrusive version line.
* view-disclaimer.php - the public-trust disclaimer text.
* view-empty-state.php - the pre-audit introductory panel.
* view-score-summary.php - the Trust Score gauge, grade, and status counts.
* view-category-summary.php - the four security category cards.
* view-findings.php - findings grouped by category.

New assets:

* admin/assets/css/trustbeacon-admin.css - the entire dashboard stylesheet.
  Enqueued only on the Trust Auditor admin page (see enqueue_assets()).
  No JavaScript file was created. The only interactive behavior needed -
  expanding a finding's recommendation and business impact - is handled by
  a native HTML <details>/<summary> element, which needs no script and
  degrades to "always visible if you click it" behavior with zero risk of
  broken functionality if the browser has JavaScript disabled.

Data passed from the audit engine into the presentation layer:

* TBAUD_Audit_Runner::run() still returns the same
  array( 'domain', 'score', 'grade', 'findings' ) shape it always has.
  TBAUD_Admin_Page reads that array and passes score/grade/findings
  (or derived summaries of findings) into view partials. It never
  reconstructs or second-guesses that array.

-------------------------------------------------------------------------------
2. Presentation mapping
-------------------------------------------------------------------------------

Trust Score display (no recalculation):

view-score-summary.php receives $score and $grade exactly as returned by
TBAUD_Score_Calculator via the audit results array. The view clamps the
score into 0-100 only for safe SVG math (max(0, min(100, ...))) and computes
the SVG circle's stroke-dashoffset from that clamped value. It does not
recompute the score or the grade text.

Finding counts:

TBAUD_Presentation_Helper::count_by_status() walks the findings array once
and buckets each finding's (already-set) status into pass/warn/fail/info/
other. It does not change any finding's status or score. The `other` bucket
exists defensively - no checker currently emits anything besides PASS, WARN,
FAIL, or INFO, but if one ever did, the finding would still be counted
(nothing is silently dropped) and would still appear in the grouped findings
list.

Category ratings to visual status classes:

TBAUD_Presentation_Helper::calculate_category_summary() and its private
rate_group() helper contain the exact same averaging logic and 90/75/60
thresholds as the previous TBAUD_Admin_Page::calculate_category_summary()/
rate_group(). The only change is the return shape: each group now returns
array( 'label' => <translated string>, 'key' => <stable untranslated string,
e.g. "excellent" or "review"> ). The `key` exists purely so
view-category-summary.php can pick a CSS class (tbaud-card--excellent, etc.)
without pattern-matching translated text, which would break in any
non-English locale. If you change the rating thresholds or wording, both
`label` and `key` should be updated together in rate_group().

Grouping findings:

TBAUD_Presentation_Helper::group_by_category() builds an associative array
keyed by each finding's `category` field, preserving the order categories
are first encountered. It does not sort, filter, or deduplicate findings.

Preserving every original finding field:

view-findings.php prints category (as the group heading), check, status
(as both a decorative dot, a screen-reader-only text node, and a visible
badge), score, message, recommendation, and business_impact for every
finding. Recommendation and business_impact are only wrapped in a
<details> element if at least one of them is non-empty; if a finding has
neither (as some INFO findings do), no empty disclosure is rendered.

-------------------------------------------------------------------------------
3. Security and data integrity
-------------------------------------------------------------------------------

Capability and nonce protections:

render_page() still returns immediately if
!current_user_can( 'manage_options' ), unchanged from the previous version.
process_audit_request() still requires a valid wpta_run_audit_nonce nonce
for action wpta_run_audit_action before calling TBAUD_Audit_Runner::run().
Both checks were moved, not altered.

Escaping and sanitization boundaries:

Every view partial escapes output the same way the previous single-file
renderer did: esc_html()/esc_html_e() for text nodes, esc_attr()/
esc_attr_e() for attribute values, and sanitize_text_field()/wp_unslash()
on the incoming nonce and domain. No raw, unescaped finding data is ever
echoed. Domain input still passes through TBAUD_Audit_Runner::clean_domain()
before reaching any checker (unchanged).

Confirmation that scoring/audit/category-rating calculations were not
changed:

* TBAUD_Score_Calculator, TBAUD_Finding, TBAUD_Audit_Runner, and every file
  under checks/ are byte-for-byte unchanged in this version.
* TBAUD_Presentation_Helper::rate_group() reproduces the previous
  TBAUD_Admin_Page::rate_group() math exactly (same accumulation, same
  90/75/60 thresholds); see tests/test-presentation-helper.php for a
  regression assertion confirming the total-score/grade math is unchanged.

Confirmation that no fabricated or live-monitoring data was introduced:

* view-empty-state.php contains no score, gauge, counts, or finding-shaped
  markup - only descriptive text and a Run Audit button.
* No polling, setInterval, cron hook, or background request was added.
  The only network activity remains the on-demand checks TBAUD_Audit_Runner
  already performed when Run Audit/Re-scan is submitted.

-------------------------------------------------------------------------------
4. Accessibility
-------------------------------------------------------------------------------

Keyboard behavior:

The Run Audit/Re-scan control is a standard <button type="submit">, and the
recommendation/business-impact disclosures are native <details>/<summary>
elements. Both are natively keyboard-operable (Tab to focus, Enter/Space to
activate) with no custom JavaScript key handling required.

Focus indicators:

.tbaud-dashboard :focus-visible sets a visible 2px outline in the dashboard's
blue accent color, so keyboard focus is never invisible against the dark
background.

Screen-reader status text:

Each finding's status dot has aria-hidden="true" (it is decorative), and is
paired with a .screen-reader-text span containing the literal status word
(PASS/WARN/FAIL/INFO) plus a visible badge with the same text. The Trust
Score gauge's outer wrapper carries role="img" and an aria-label summarizing
the score and grade in a full sentence, since the SVG itself is marked
aria-hidden.

Contrast considerations:

Status colors (green/yellow/red/blue) were chosen against the dashboard's
near-black background (#0b0d10) and card surface (#14171c) for readability,
but status is never conveyed by color alone anywhere in this dashboard -
every status also has adjacent text (PASS/WARN/FAIL/INFO, or a rating label
like "Excellent"/"Needs Attention").

Non-color status indicators:

See above - dots are always paired with text badges or labels.

Behavior when JavaScript is unavailable:

The dashboard was intentionally built with no JavaScript file at all. The
Trust Score gauge is a static server-rendered SVG (the stroke-dashoffset is
computed in PHP, not animated by script). The only "interactive" behavior -
expanding recommendation/business impact - uses <details>, which is fully
functional with JavaScript disabled. There is nothing in this dashboard that
stops working without JavaScript.

-------------------------------------------------------------------------------
5. Responsive design
-------------------------------------------------------------------------------

Desktop layout:

Category cards use `grid-template-columns: repeat(auto-fit, minmax(200px, 1fr))`
so cards wrap naturally as the admin content area widens or narrows with the
WordPress admin sidebar.

Tablet layout (max-width: 782px, WordPress's own folding-menu breakpoint):

Card minimum width drops to 160px and the score-summary gap tightens, so the
gauge and count list stay on one row longer before wrapping.

Narrow WordPress-admin layout (max-width: 600px, WordPress's own
mobile-menu breakpoint):

Dashboard padding shrinks, the header's title/button row stacks vertically,
category cards drop to a single column, and each finding's check name takes
the full row width above its badge/score instead of being squeezed
alongside them.

These two breakpoints intentionally match WordPress core's own admin
breakpoints (782px and 600px) rather than inventing new ones, so the
dashboard reflows at the same points the surrounding wp-admin chrome does.

-------------------------------------------------------------------------------
6. Testing and verification
-------------------------------------------------------------------------------

Every command executed during this implementation:

  apt-get update
  apt-get install -y php-cli          (installed PHP 8.3.6 in the build
                                        environment; no PHP interpreter was
                                        preinstalled)
  find . -name "*.php" | sort | while read -r f; do php -l "$f"; done
  php tests/test-presentation-helper.php
  php tests/test-render-smoke.php

PHP syntax-check results:

`php -l` reported "No syntax errors detected" for all 20 PHP files in the
plugin (11 pre-existing, 9 new: class-admin-page.php, the 6 view files,
class-presentation-helper.php, and the 2 test files are additional).

Test-suite results:

tests/test-presentation-helper.php: 22 assertions, 0 failed. Covers
count_by_status, group_by_category, status_key, score_tier_key, and
calculate_category_summary, plus a regression check of
TBAUD_Score_Calculator::calculate_total_score()/get_grade().

tests/test-render-smoke.php: 32 assertions, 0 failed. Renders the real
TBAUD_Admin_Page against WordPress-function stubs (tests/wp-stubs.php) to
check the pre-audit empty state, the completed-results state, and asset
enqueue scoping.

PHP 7.4 compatibility review:

No PHP 7.4 interpreter was available in the build environment (not present
in the Ubuntu 24.04 apt repositories used for this build) and none of the
allowed network domains provided one, so 7.4 could not be run directly.
Instead, every new/changed file was manually reviewed and grepped for
PHP 8-only constructs: the nullsafe operator (?->), enums, readonly
properties, str_contains()/str_starts_with()/str_ends_with(), match
expressions, and named arguments. None were found. All new code uses only
constructs already present in the pre-existing 7.4-compatible codebase
(arrays, ??, static methods, foreach, switch, sprintf/printf).

Asset-loading verification:

tests/test-render-smoke.php calls TBAUD_Admin_Page::enqueue_assets()
directly with both the plugin's own hook suffix and an unrelated one
(edit.php), and asserts the stylesheet is enqueued only in the first case.

Pre-audit-state verification:

tests/test-render-smoke.php asserts the empty-state render contains the
"No audit has been run yet" panel and a Run Audit button, and explicitly
asserts it does NOT contain any "tbaud-gauge" markup, so a pre-audit page
load can never be mistaken for a completed audit.

Completed-results-state verification:

tests/test-render-smoke.php asserts the results render contains the gauge,
the exact calculated grade text, and all four category headings, using
fixture findings (not live network checks).

Verification that all seven original finding fields remain available:

tests/test-render-smoke.php loops over category, check, status, and message
for every fixture finding and asserts each value's escaped form appears in
the rendered HTML, then separately asserts recommendation and
business_impact text appear for every finding that has them. Score is
verified via the overall displayed total score.

-------------------------------------------------------------------------------
7. Maintenance guidance
-------------------------------------------------------------------------------

Where future dashboard styling should be changed:

admin/assets/css/trustbeacon-admin.css only. It is organized into numbered
section comments (theme tokens, header, disclaimer, section shell, status
dots, score summary, category cards, findings, empty state, responsive
breakpoints) - find the matching section rather than searching the whole
file. All colors are CSS custom properties on .tbaud-dashboard; change a
token there to retheme the whole dashboard at once.

Where presentation behavior should be changed:

admin/views/*.php for markup, and includes/class-presentation-helper.php
for counting/grouping/key-mapping logic. admin/class-admin-page.php should
only need to change if a new view needs new data passed into it, or if the
request-handling flow itself changes (new form fields, different capability,
etc.).

Which engine and scoring files must NOT be altered for visual-only work:

* includes/class-finding.php (score normalization per status)
* includes/class-score-calculator.php (total score and grade)
* includes/class-audit-runner.php (which checkers run and how results are
  normalized)
* every file under checks/ (the individual audit checks)

TBAUD_Presentation_Helper::rate_group() reproduces the category-rating
thresholds, but if those thresholds ever need to change, treat that as a
scoring/behavior change requiring the same care as editing
class-score-calculator.php, not a routine visual tweak - it affects the
Excellent/Good/Fair/Needs Attention labels shown to site owners.

Known limitations or technical debt:

* No PHP 7.4 interpreter was available to run the test suite directly under
  7.4; compatibility was confirmed by manual review instead of execution.
* tests/ is a small, dependency-free assertion script rather than a full
  PHPUnit suite with WordPress test scaffolding, because the plugin has
  neither today. If PHPUnit/WP-CLI test scaffolding is added later, these
  assertions can be ported into proper test methods with minimal changes.
* The category-rating labels/keys are duplicated as a small lookup inside
  rate_group() (five possible outcomes). If a sixth rating tier is ever
  added, remember to add both a translated label and a stable key, and add
  a matching .tbaud-card--<key> / .tbaud-status-dot--<key> CSS rule.
