diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 8a13e62..7cbc310 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -14,6 +14,7 @@ {"_type":"issue","id":"hc-5ix.4","title":"Session data model: option-backed in-progress healthcheck record","description":"One in-progress session per site at a time. Stored in a custom option (or a CPT — pick during implementation). Shape: id, started_at, finished_at, technician_id, site_url_snapshot, per_step_state { status: not_started|in_progress|done|skipped|blocked|n_a, notes, completed_at }. Designed so phase-3 automation can attach structured findings later.","notes":"Built in phase-1 scaffold; passing lint + WP-eval end-to-end smoke test on testsite.","status":"closed","priority":1,"issue_type":"task","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T14:36:11Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T14:49:27Z","started_at":"2026-06-11T14:41:27Z","closed_at":"2026-06-11T14:49:27Z","labels":["phase-1"],"dependencies":[{"issue_id":"hc-5ix.4","depends_on_id":"hc-5ix","type":"parent-child","created_at":"2026-06-11T15:36:11Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-5ix.2","title":"Plugin skeleton: header, activation hook, deactivation hook, admin menu (Tools → Site Healthcheck), capability gate","notes":"Built in phase-1 scaffold; passing lint + WP-eval end-to-end smoke test on testsite.","status":"closed","priority":1,"issue_type":"task","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T14:36:10Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T14:49:26Z","started_at":"2026-06-11T14:41:27Z","closed_at":"2026-06-11T14:49:26Z","labels":["phase-1"],"dependencies":[{"issue_id":"hc-5ix.2","depends_on_id":"hc-5ix","type":"parent-child","created_at":"2026-06-11T15:36:09Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-5ix.1","title":"Bootstrap: trigger install of wp-site-recovery plugin as step 0","description":"Healthcheck plugin should check on activation if site-recovery is installed; if not, fetch and install from a known URL/ZIP and activate it. Block stepper from starting until recovery is in place.","notes":"Detection half done (status panel + manual link). Auto-install of recovery plugin from a private URL is the wp-site-recovery side of hc-5ix.27 — closing this as 'detection complete'.","status":"closed","priority":1,"issue_type":"task","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T11:26:40Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T15:03:02Z","closed_at":"2026-06-11T15:03:02Z","labels":["phase-1"],"dependencies":[{"issue_id":"hc-5ix.1","depends_on_id":"hc-5ix","type":"parent-child","created_at":"2026-06-11T12:26:39Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"hc-dy9","title":"Plugin: Notes for next time → seed prereq notes on next session","description":"Add a 'Notes for next time' step at the end of the flow as a handover for whoever picks up the next engagement. On starting a new session for the same site_key, the server's step history for the handover step is pulled and used to pre-populate the 'Before You Start' (before) step's notes — prefixed with the prior session's date so the carry-over is obvious.\n\nImplementation:\n- New step file includes/steps/125-handover.php using the existing step pattern (id=handover, standard notes field). No schema or API change required since this is just another step.\n- ATT_HC_Session::start() does a best-effort step_history(handover, site_key, limit=1, exclude_id=current) and on success calls update_step('before', NOT_STARTED, prefix + notes) on the new session. Silent degrade if API unreachable — start should still succeed.\n- Same auto-seed for resume()? Probably not — resuming an existing session would clobber whatever the tech had already typed. Only seed on a genuinely new start.\n\nUser asked for this 2026-06-29 — they want a low-friction handover so engagement context survives between visits.","status":"closed","priority":2,"issue_type":"feature","assignee":"Steve Hanlon","owner":"steve@hanlon.co.uk","created_at":"2026-06-30T09:14:53Z","created_by":"Steve Hanlon","updated_at":"2026-06-30T09:17:44Z","started_at":"2026-06-30T09:15:12Z","closed_at":"2026-06-30T09:17:44Z","close_reason":"Shipped. New step file includes/steps/125-handover.php (id=handover, title='Notes for next time') with blurb + sub_items prompting the tech for what to flag. ATT_HC_Session::start() now ends with a best-effort seed_before_notes_from_prior_handover() call that pulls the prior session's handover notes via step_history(handover, site_key, 1, current_id) and writes them into this session's 'before' step notes prefixed with 'From previous session (YYYY-MM-DD):'. Silent degrade on API failure so the session is never blocked from being created. Verified end-to-end against the live server: handover-test-XXXX site exercises full flow, no-handover-XXXX site confirms no false-positive seed. Plugin-only change — no server deploy needed. Test rows purged from MySQL.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-3y0","title":"Server: deploy notes for VPS","description":"Document deployment to a PHP VPS:\n- PHP version requirements\n- Apache/nginx rewrite to public/index.php\n- File perms for SQLite db file\n- Suggested location (/var/www/att-hc-server/)\n- Generating + setting ATT_HC_API_KEY\n- Backup strategy for the SQLite file (cron + scp/rsync)\n- HTTPS via Let's Encrypt\n\nLives at server/DEPLOY.md.","status":"closed","priority":2,"issue_type":"task","assignee":"Steve Hanlon","owner":"steve@hanlon.co.uk","created_at":"2026-06-29T11:10:27Z","created_by":"Steve Hanlon","updated_at":"2026-06-29T11:23:22Z","started_at":"2026-06-29T11:21:00Z","closed_at":"2026-06-29T11:23:22Z","close_reason":"DEPLOY.md written: requirements, layout, first-time install (rsync + key generation + perms), Apache + nginx vhost templates with Authorization header forwarding, Let's Encrypt, plugin-side wp-config.php constants, SQLite online backup cron, update procedure, health-check curl.","dependencies":[{"issue_id":"hc-3y0","depends_on_id":"hc-0p1","type":"parent-child","created_at":"2026-06-29T12:13:24Z","created_by":"Steve Hanlon","metadata":"{}"},{"issue_id":"hc-3y0","depends_on_id":"hc-rdo","type":"blocks","created_at":"2026-06-29T12:10:37Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-0p1","title":"[epic] Central history server + plugin sync","description":"Replace the local-only session model with a required central server that stores healthcheck history across engagements.\n\nMotivation:\n- Plugin is installed per engagement and uninstalled at the end, so today's local 'previous session' diff dies with it\n- Healthchecks differ between sites; cross-engagement history lets us see prior notes per step and review what's drifted\n- Engagements often span dev + live (different URLs, same logical site), and may run over days/weeks — sometimes never completed\n\nScope:\n- New PHP/SQLite server in server/ (same repo), deployed to a VPS\n- Plugin becomes a write-through client: server is source of truth\n- DB key = (site_key, started_at); site_key defaults to normalised get_site_url() but is editable on start\n- Multiple incomplete sessions per site allowed; on start, tech can Resume or Start fresh\n- Each step card gets a 'view previous notes' link that pulls history from the server\n- Auth: single shared secret as ATT_HC_API_KEY constant in wp-config.php\n- HTTPS required; plain HTTP rejected client-side\n- Server unreachable = Start/Save/Finish block with retry. No offline queue v1.","status":"closed","priority":2,"issue_type":"feature","owner":"steve@hanlon.co.uk","created_at":"2026-06-29T11:09:02Z","created_by":"Steve Hanlon","updated_at":"2026-06-29T11:41:07Z","closed_at":"2026-06-29T11:41:07Z","close_reason":"All 8 child issues closed. Central history server + plugin sync feature complete: PHP/SQLite server with 8 endpoints (incl. /step-counts), schema with composite key (site_key, started_at) + step_updates + audit log, deploy notes for VPS (using /home/www/healthcheck). Plugin: ATT_HC_Api HTTP client with HTTPS guard + loopback dev exception, ATT_HC_Session refactored to write-through (server-of-truth), start screen with site_key + recent-engagements datalist + resume of incomplete sessions + double-click guard, per-step previous-notes disclosure with lazy loading. End-to-end verified across 4 separate test runs.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-5ix.28","title":"Step — Email Delivery Test (send wp_mail to chosen address)","description":"Add a new step that sends a test email via wp_mail() to an address the technician types in. Should detect SMTP plugins in use, surface wp_mail_failed errors, and store the result as a finding so it lands in the report.\n\nDrives a small architectural extension: WPH_Step gains optional render_extra() (output HTML inside the card) and handle_action() (handle a step-specific POST), plus a generic wph_step_action admin-post handler. Demonstrates the drop-in extensibility — adding the step is a single file plus a tiny hook addition.","notes":"Added in commit (next). New file includes/steps/115-email.php — drop-in step, no other source changes beyond the small WPH_Step extension (render_extra + handle_action) and one admin-post handler (wph_step_action). Demonstrates the extensibility pattern: a step can declare its own form + handler without touching any other file.\n\nSmoke-tested on testsite: step appears in correct slot (between small_fixes and wrap_up), autocheck surfaces mailer detection (PHP mail vs. 7 known SMTP plugins) and default From address, render_extra outputs a To: input prefilled with current user's email, handle_action rejects invalid addresses and successfully sends via wp_mail (caught by Local's MailHog).","status":"closed","priority":2,"issue_type":"task","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T17:43:34Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T17:45:47Z","closed_at":"2026-06-11T17:45:47Z","labels":["phase-1"],"dependencies":[{"issue_id":"hc-5ix.28","depends_on_id":"hc-5ix","type":"parent-child","created_at":"2026-06-11T18:43:33Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/includes/class-att-hc-session.php b/includes/class-att-hc-session.php index f7be36e..fdda1eb 100644 --- a/includes/class-att-hc-session.php +++ b/includes/class-att-hc-session.php @@ -84,7 +84,39 @@ final class ATT_HC_Session { ]); update_option(ATT_HC_OPT_SESSION, $data, false); - return new self($data); + $session = new self($data); + + // Carry handover notes from the prior session into the new "before" + // notes. Best-effort: a failure here must not block session creation, + // since the session is already registered on the server above. + self::seed_before_notes_from_prior_handover($session); + + return $session; + } + + /** + * If the prior session for this site left "Notes for next time" (id=handover), + * pre-fill the new session's "Before You Start" (id=before) notes with them, + * prefixed with the prior session's date so it's clear they're carried over. + */ + private static function seed_before_notes_from_prior_handover(self $session): void { + try { + $resp = ATT_HC_Api::step_history('handover', $session->site_key(), 1, $session->id()); + } catch (ATT_HC_Api_Exception $e) { + return; + } + $rows = $resp['history'] ?? []; + if (!$rows) return; + + $notes = trim((string) ($rows[0]['notes'] ?? '')); + if ($notes === '') return; + + $prefix = 'From previous session (' . date('Y-m-d', (int) $rows[0]['started_at']) . "):\n"; + try { + $session->update_step('before', self::STATUS_NOT_STARTED, $prefix . $notes); + } catch (ATT_HC_Api_Exception $e) { + // Already-rare degrade path — the session is alive, just no auto-seed. + } } /** diff --git a/includes/steps/125-handover.php b/includes/steps/125-handover.php new file mode 100644 index 0000000..550a397 --- /dev/null +++ b/includes/steps/125-handover.php @@ -0,0 +1,25 @@ +