System

Activity Log

Unified timeline of data changes (saves, imports, deletes) and backend errors. Filter by type, area, severity, or search.

Data changes (total)1,202
Errors (total)274,149
Today · changes173
Today · errors103,055
Reset

275,351 results · Page 5501 of 5508

tabby_terminal.php
2026-04-20 14:29:30 · anonymous · /backend/tabby_terminal.php
error
Call to undefined function app_settings_map()
Script: /mnt/drive1/customerdb/webui/backend/tabby_terminal.php
IP: 192.168.7.66
Context
{"type":"Error","file":"/mnt/drive1/customerdb/backend/tabby_terminal.php","line":15,"trace":"#0 /mnt/drive1/customerdb/webui/backend/tabby_terminal.php(5): require()\n#1 {main}"}
tabby_terminal.php
2026-04-20 14:28:22 · anonymous · /backend/tabby_terminal.php
error
Call to undefined function app_settings_map()
Script: /mnt/drive1/customerdb/webui/backend/tabby_terminal.php
IP: 34.203.10.131
Context
{"type":"Error","file":"/mnt/drive1/customerdb/backend/tabby_terminal.php","line":15,"trace":"#0 /mnt/drive1/customerdb/webui/backend/tabby_terminal.php(5): require()\n#1 {main}"}
tabby_terminal.php
2026-04-20 14:28:20 · anonymous · /backend/tabby_terminal.php
error
Call to undefined function app_settings_map()
Script: /mnt/drive1/customerdb/webui/backend/tabby_terminal.php
IP: 34.203.10.131
Context
{"type":"Error","file":"/mnt/drive1/customerdb/backend/tabby_terminal.php","line":15,"trace":"#0 /mnt/drive1/customerdb/webui/backend/tabby_terminal.php(5): require()\n#1 {main}"}
tabby_terminal.php
2026-04-20 14:28:19 · anonymous · /backend/tabby_terminal.php
error
Call to undefined function app_settings_map()
Script: /mnt/drive1/customerdb/webui/backend/tabby_terminal.php
IP: 34.203.10.131
Context
{"type":"Error","file":"/mnt/drive1/customerdb/backend/tabby_terminal.php","line":15,"trace":"#0 /mnt/drive1/customerdb/webui/backend/tabby_terminal.php(5): require()\n#1 {main}"}
tabby_terminal.php
2026-04-20 14:28:19 · anonymous · /backend/tabby_terminal.php
error
Call to undefined function app_settings_map()
Script: /mnt/drive1/customerdb/webui/backend/tabby_terminal.php
IP: 34.203.10.131
Context
{"type":"Error","file":"/mnt/drive1/customerdb/backend/tabby_terminal.php","line":15,"trace":"#0 /mnt/drive1/customerdb/webui/backend/tabby_terminal.php(5): require()\n#1 {main}"}
tabby_terminal.php
2026-04-20 14:28:16 · anonymous · /backend/tabby_terminal.php
error
Call to undefined function app_settings_map()
Script: /mnt/drive1/customerdb/webui/backend/tabby_terminal.php
IP: 34.203.10.131
Context
{"type":"Error","file":"/mnt/drive1/customerdb/backend/tabby_terminal.php","line":15,"trace":"#0 /mnt/drive1/customerdb/webui/backend/tabby_terminal.php(5): require()\n#1 {main}"}
tabby_terminal.php
2026-04-20 14:28:15 · anonymous · /backend/tabby_terminal.php
error
Call to undefined function app_settings_map()
Script: /mnt/drive1/customerdb/webui/backend/tabby_terminal.php
IP: 34.203.10.131
Context
{"type":"Error","file":"/mnt/drive1/customerdb/backend/tabby_terminal.php","line":15,"trace":"#0 /mnt/drive1/customerdb/webui/backend/tabby_terminal.php(5): require()\n#1 {main}"}
tabby_terminal.php
2026-04-20 14:27:57 · anonymous · /backend/tabby_terminal.php
error
Call to undefined function app_settings_map()
Script: /mnt/drive1/customerdb/webui/backend/tabby_terminal.php
IP: 192.168.7.66
Context
{"type":"Error","file":"/mnt/drive1/customerdb/backend/tabby_terminal.php","line":15,"trace":"#0 /mnt/drive1/customerdb/webui/backend/tabby_terminal.php(5): require()\n#1 {main}"}
schedule · create
2026-04-20 13:54:03 · admin@ellasalterations.com · /api/appointment_workflow.php
change
appointment_workflow #visit:129358
Context
{"workflow_status":"no_show","visit_id":129358,"order_id":104111}
Before
[]
After
{"workflow_id":"9","source":"visit","source_key":"129358","appointment_date":"2026-04-20","customer_id":"489071","visit_id":"129358","order_id":null,"workflow_status":"no_show","payment_state":null,"payment_method":null,"payment_amount":"0.00","paid_in_advance":"0","report_required":"0","report_attached":"0","report_checked_at":"2026-04-20 13:54:02","provider_notes_text":null,"operator_notes":null,"no_show_email_key":"none","created_at":"2026-04-20 13:54:02","updated_at":"2026-04-20 13:54:02"}
customer_totals · create
2026-04-20 10:56:45 · anonymous · /backend/customer_totals.php
change
customer_totals #20323
Context
[]
Before
[]
After
{"customer_date":"2026-04-20 14:55:00","customer_name":"Edwards","dopu_can":"Edwards","edwards":100,"edwards_type":"mileage","update_flag":"47"}
sysadmin.php
2026-04-19 16:28:30 · anonymous · /backend/api/sysadmin.php?action=backups_list&dir=customerdb-backup
error
DirectoryIterator::__construct(/mnt/drive1/customerdb-backup): Failed to open directory: No such file or directory
Script: /mnt/drive1/customerdb/webui/backend/api/sysadmin.php
IP: 192.168.7.35
Context
{"type":"UnexpectedValueException","file":"/mnt/drive1/customerdb/webui/backend/api/sysadmin.php","line":290,"trace":"#0 /mnt/drive1/customerdb/webui/backend/api/sysadmin.php(290): DirectoryIterator->__construct()\n#1 {main}"}
schedule · create
2026-04-19 15:46:07 · admin@ellasalterations.com · /api/appointment_workflow.php
change
appointment_workflow #visit:129401
Context
{"workflow_status":"no_show","visit_id":129401,"order_id":104154}
Before
[]
After
{"workflow_id":"8","source":"visit","source_key":"129401","appointment_date":"2026-04-19","customer_id":"3478","visit_id":"129401","order_id":null,"workflow_status":"no_show","payment_state":null,"payment_method":null,"payment_amount":"0.00","paid_in_advance":"0","report_required":"0","report_attached":"0","report_checked_at":"2026-04-19 15:46:07","provider_notes_text":null,"operator_notes":"Status: 3/23/2026 Drop Off","no_show_email_key":"none","created_at":"2026-04-19 15:46:07","updated_at":"2026-04-19 15:46:07"}
live_table_manager · delete
2026-04-19 13:19:54 · anonymous · /backend/live_table_manager.php?table=customer_payment_transactions&q=chevy&ok=deleted
change
customer_payment_transactions #5982
Context
[]
Before
{"customer_payment_transaction_id":"5982","payment_id":"63997","order_id":"104085","visit_id":"129332","customer_id":"489019","customer_name":"Chevy Stern","transaction_date":"2026-04-12 00:00:00","payment_method":"Square","payment_type":"Deposit","bucket":"credit","amount":"45.60","tip_amount":"0.00","is_new_customer":"0","source":"payments","created_at":"2026-04-19 13:15:17","updated_at":"2026-04-19 13:15:17"}
After
{"deleted":true}
live_table_manager · delete
2026-04-19 13:19:49 · anonymous · /backend/live_table_manager.php?table=customer_payment_transactions&edit=5983&q=chevy
change
customer_payment_transactions #5983
Context
[]
Before
{"customer_payment_transaction_id":"5983","payment_id":"63998","order_id":"104085","visit_id":"129332","customer_id":"489019","customer_name":"Chevy Stern","transaction_date":"2026-04-12 00:00:00","payment_method":"Square","payment_type":"Deposit","bucket":"credit","amount":"40.00","tip_amount":"0.00","is_new_customer":"0","source":"payments","created_at":"2026-04-19 13:15:17","updated_at":"2026-04-19 13:15:17"}
After
{"deleted":true}
live_table_manager · delete
2026-04-19 13:18:05 · anonymous · /backend/live_table_manager.php?table=customer_payment_transactions&q=chevy&ok=deleted
change
customer_payment_transactions #5984
Context
[]
Before
{"customer_payment_transaction_id":"5984","payment_id":"63999","order_id":"104085","visit_id":"129332","customer_id":"489019","customer_name":"Chevy Stern","transaction_date":"2026-04-12 00:00:00","payment_method":"Square","payment_type":"Balance","bucket":"credit","amount":"40.00","tip_amount":"0.00","is_new_customer":"0","source":"payments","created_at":"2026-04-19 13:15:17","updated_at":"2026-04-19 13:15:17"}
After
{"deleted":true}
live_table_manager · delete
2026-04-19 13:17:53 · anonymous · /backend/live_table_manager.php?table=customer_payment_transactions&q=chevy
change
customer_payment_transactions #5985
Context
[]
Before
{"customer_payment_transaction_id":"5985","payment_id":"64000","order_id":"104085","visit_id":"129332","customer_id":"489019","customer_name":"Chevy Stern","transaction_date":"2026-04-12 00:00:00","payment_method":"Square","payment_type":"Tip","bucket":"tip","amount":"0.00","tip_amount":"0.00","is_new_customer":"0","source":"payments","created_at":"2026-04-19 13:15:17","updated_at":"2026-04-19 13:15:17"}
After
{"deleted":true}
schedule · create
2026-04-18 17:02:58 · admin@ellasalterations.com · /api/appointment_workflow.php
change
appointment_workflow #visit:129391
Context
{"workflow_status":"no_show","visit_id":129391,"order_id":104144}
Before
[]
After
{"workflow_id":"7","source":"visit","source_key":"129391","appointment_date":"2026-04-18","customer_id":"3503","visit_id":"129391","order_id":null,"workflow_status":"no_show","payment_state":null,"payment_method":null,"payment_amount":"0.00","paid_in_advance":"0","report_required":"0","report_attached":"0","report_checked_at":"2026-04-18 17:02:58","provider_notes_text":null,"operator_notes":"App CreatedApp CreatedApp CreatedPayment Type:Credit Paid Date:  3/30/2026 3:30:00 PMPayment Type: Credit Paid Amount: $707.00Payment: 3/30/2026   707","no_show_email_key":"none","created_at":"2026-04-18 17:02:58","updated_at":"2026-04-18 17:02:58"}
schedule · create
2026-04-18 16:34:20 · admin@ellasalterations.com · /api/appointment_workflow.php
change
appointment_workflow #visit:129386
Context
{"workflow_status":"no_show","visit_id":129386,"order_id":104139}
Before
[]
After
{"workflow_id":"6","source":"visit","source_key":"129386","appointment_date":"2026-04-18","customer_id":"3501","visit_id":"129386","order_id":null,"workflow_status":"no_show","payment_state":null,"payment_method":null,"payment_amount":"0.00","paid_in_advance":"0","report_required":"0","report_attached":"0","report_checked_at":"2026-04-18 16:34:20","provider_notes_text":null,"operator_notes":"Project Details 2 silk pants need hem and 1 pair jeansWhen Needed? couple weeksBooked from Custom Booking PageProject Details 2 silk pants need hem and 1 pair jeansWhen Needed? couple weeksBooked from Custom Booking PageProject Details 2 silk pants need hem and 1 pair jeansWhen Needed? couple weeksBooked from Custom Booking PagePayment Type:None Paid Date:  3/20/2026 2:30:00 PMDeposit Amount: $60.00Deposit Date:  3/6/2026","no_show_email_key":"none","created_at":"2026-04-18 16:34:20","updated_at":"2026-04-18 16:34:20"}
send_nextday_customer_emails: mail failed for christyr.ralston@gmail.com: Sent via SMTP (PHPMailer)
2026-04-17 20:00:33 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Christy Ralston","email":"christyr.ralston@gmail.com"}
send_nextday_customer_emails: mail failed for regenttamppansdar@gmail.com: Sent via SMTP (PHPMailer)
2026-04-17 20:00:32 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Sarah Hughes","email":"regenttamppansdar@gmail.com"}
send_nextday_customer_emails: mail failed for qwzx9j@gmail.com: Sent via SMTP (PHPMailer)
2026-04-17 20:00:30 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Nancy Adams","email":"qwzx9j@gmail.com"}
send_nextday_customer_emails: mail failed for roxanne_ad@hotmail.com: Sent via SMTP (PHPMailer)
2026-04-17 20:00:28 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Roxanne Adams","email":"roxanne_ad@hotmail.com"}
send_nextday_customer_emails: mail failed for rammic1017@gmail.com: Sent via SMTP (PHPMailer)
2026-04-17 20:00:27 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Michelle Ramirez","email":"rammic1017@gmail.com"}
send_nextday_customer_emails: mail failed for vgonzalez-saez@hotmail.com: Sent via SMTP (PHPMailer)
2026-04-17 20:00:25 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Victoria Gonzalez","email":"vgonzalez-saez@hotmail.com"}
send_nextday_customer_emails: mail failed for josefinareyes0114@gmail.com: Sent via SMTP (PHPMailer)
2026-04-17 20:00:23 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Josefina Reyes","email":"josefinareyes0114@gmail.com"}
send_nextday_customer_emails: mail failed for honeymstern@gmail.com: Sent via SMTP (PHPMailer)
2026-04-17 20:00:22 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Chevy Stern","email":"honeymstern@gmail.com"}
send_nextday_customer_emails: mail failed for aodonahoe@gmail.com: Sent via SMTP (PHPMailer)
2026-04-17 20:00:20 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Alyssa Odonahoe","email":"aodonahoe@gmail.com"}
send_nextday_customer_emails: mail failed for jjazxhi@gmail.com: Sent via SMTP (PHPMailer)
2026-04-17 20:00:18 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Julian Jazxhi","email":"jjazxhi@gmail.com"}
send_nextday_customer_emails: mail failed for martin110406@sbcglobal.net: Sent via SMTP (PHPMailer)
2026-04-17 20:00:17 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Yolanda Martin","email":"martin110406@sbcglobal.net"}
send_nextday_customer_emails: mail failed for daisymartinez701@yahoo.com: Sent via SMTP (PHPMailer)
2026-04-17 20:00:15 · cli · /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
error
send_nextday_customer_emails.php
Script: /mnt/drive1/customerdb/backend/jobs/send_nextday_customer_emails.php
IP: cli
Context
{"customer":"Daisy Martinez","email":"daisymartinez701@yahoo.com"}
documents · upload
2026-04-17 15:19:31 · anonymous · /backend/documents.php?backend_document_id=21
change
backend_document #22
Context
{"file_name":"2026-04-17-implementation-report.md","mime_type":"application/octet-stream"}
Before
[]
After
{"backend_document_id":"22","document_type":"upload","title":"Codex  Updates 04-17-2026","slug":"codex-updates-04-17-2026","summary_text":"Codex  Updates 04-17-2026","content_markdown":null,"content_html":null,"file_name":"2026-04-17-implementation-report.md","stored_name":"20260417-191931-4b36a7df.md","mime_type":"application/octet-stream","file_size_bytes":"8180","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260417-191931-4b36a7df.md","is_deleted":"0","created_at":"2026-04-17 15:19:31","updated_at":"2026-04-17 15:19:31","editor_content":"# Implementation Report - April 17, 2026\n\n## Scope\nThis document summarizes all completed work from this support/maintenance session, including:\n- Issues found\n- Root causes\n- Fixes implemented\n- Files changed\n- Live deployment actions\n- Verification results\n- Remaining follow-up items\n\nDate: 2026-04-17\n\n---\n\n## 1) Cron Email Failures (421 Downstream server error)\n\n### Reported issue\nCron jobs were failing email delivery from:\n- `/mnt/drive1/customerdb/backend/jobs/run_cron_job.php 7`\n\nBounce details showed:\n- Relay path through `relay.mailchannels.net`\n- Recipient looked like an SMTP host mailbox (`kefa@de-fra-smtpout7.hostinger.io`)\n- Error: `421 Downstream server error`\n\n### Root causes identified\n1. Mis-targeted recipient (SMTP server domain used as mailbox address).\n2. Mail path could fall back to `mail()` when SMTP config was missing/unavailable, which routed through MailChannels.\n\n### Fixes completed\n#### Code hardening\nUpdated `backend/mail_service.php`:\n- Added recipient and sender email validation (`FILTER_VALIDATE_EMAIL`).\n- Improved SMTP security mode handling (`ssl`, `tls`, `none`).\n- SMTP auth now enabled only when username exists.\n- Disabled `mail()` fallback for CLI jobs (cron path), so cron fails explicitly instead of silently routing via MailChannels.\n\n#### Live SMTP configuration\nOn live host (`192.168.7.202`), app settings were updated to Hostinger SMTP:\n- `smtp_host = smtp.hostinger.com`\n- `smtp_port = 465`\n- `smtp_secure = ssl`\n- `smtp_user = admin@ellasalterations.com`\n- `smtp_pass = [updated in DB]`\n- `smtp_from_email = admin@ellasalterations.com`\n- `smtp_from_name = Ella's Alterations`\n- `cron_notify_email = admin@ellasalterations.com`\n- `nightly_report_to_email = admin@ellasalterations.com`\n\n### Validation\n- `app_send_mail()` test on live host returned success via PHPMailer.\n- Cron job re-run succeeded:\n  - `php8.3 /mnt/drive1/customerdb/backend/jobs/run_cron_job.php 7`\n  - Returned `\"ok\": true`\n\n### Follow-up\n- Recommended mailbox password rotation after credentials were shared in chat.\n\n---\n\n## 2) Receipt Disclosure Requirements\n\n### Requested behavior\nEnsure the following actions include required disclosures at the end:\n- Print Receipt\n- Email Receipt\n- Save Receipt (PDF)\n\n### Fixes completed\nUpdated disclosure handling across all receipt generation paths:\n\n#### `frontend/visit.html`\n- Added canonical `REQUIRED_RECEIPT_DISCLOSURES` constant.\n- Added `buildReceiptDisclosureHtml()` to render disclosure blocks.\n- `sendEmailReceipt()` path now appends required disclosures in generated email HTML.\n- `generateVisitReport()` now sends `report_disclaimer_override` to backend PDF generator so saved PDFs use same required text.\n\n#### `frontend/api/visit_report_generate.php`\n- Added support for request payload key: `report_disclaimer_override`.\n- Enhanced disclaimer parser to handle uppercase heading lines with colon format (e.g., `DEPOSIT POLICY:`).\n- Uses override text when provided, otherwise settings fallback.\n\n#### `frontend/receipt.html`\n- Added required disclosure constant and merge logic.\n- Replaced old extra notice injection with required disclosure merge.\n- Terms rendering updated to preserve heading/body format.\n\n### Validation\n- PHP syntax check passed on `frontend/api/visit_report_generate.php`.\n- Confirmed references to new disclosure constants/functions in all required paths.\n\n---\n\n## 3) Dashboard Today Totals Incorrect (5/5 vs expected 8/8)\n\n### Reported issue\nDashboard showed:\n- `Today Customers: 5`\n- `Today New: 5`\nExpected:\n- `8` and `8`\n\n### Root causes identified\nIn `frontend/api/totals_snapshot_live.php`:\n1. Logic prioritized `customer_totals` and only checked `visits` if count was zero.\n   - If `customer_totals` lagged, dashboard stayed low.\n2. A `Walk In` drop-off row needed exclusion for this specific metric.\n\n### Fixes completed\nUpdated `ts_today_payment_totals_live()` in `frontend/api/totals_snapshot_live.php`:\n- Compute drop-off counts from both sources (`customer_totals`, `visits`).\n- Use max of the two counts instead of one-way fallback.\n- Exclude `booking_source = 'walk in'` when visits table has that column.\n\n### Deployment and validation\n- Deployed updated API file to live host.\n- Live endpoint check returned:\n  - `\"today_totals\":{\"total_customers\":8,\"new_customers\":8,...}`\n\n---\n\n## 4) Morning Import Visit Reuse Rules\n\n### Requested rules\nFor morning Setmore import:\n1. If customer has visit type `drop off` or `rescheduled` or `no show`: reuse visit and add Setmore notes.\n2. If customer has visit type `pick up`: create a new visit and add Setmore notes.\n3. If customer has no visit record: create a new visit and add Setmore notes.\n\n### Fixes completed\nUpdated `backend/setmore_service.php`:\n\n#### Rule enforcement\n- `app_setmore_reusable_dropoff_visit()` now inspects latest customer visit and allows reuse only for copy-source statuses (`dropoff`, `rescheduled`, `noshow`).\n- If latest status is pickup, reuse is not selected, so a new visit is created.\n- If no prior visit exists, new visit creation continues as normal.\n\n#### Notes behavior\n- Added `app_setmore_merge_notes()`.\n- Reused visit updates now merge/append Setmore notes instead of replacing existing operator notes.\n\n#### Safety improvement\n- On reused visits, preserve existing `source_key_value` if it belongs to another appointment key.\n\n### Deployment and validation\n- Deployed to live host.\n- Lint with `php8.3 -l` passed.\n- Morning smoke test passed:\n  - `php8.3 /mnt/drive1/customerdb/backend/jobs/smoke_morning_jobs.php`\n\nNote:\n- Default `php -l` binary on host showed parse issue due different PHP binary path; `php8.3` (actual cron/runtime binary) is clean.\n\n---\n\n## 5) Nightly Summary Section Order Drift\n\n### Reported issue\nNightly summary sections had moved around.\n\n### Required order\n1. Daily Detail Report\n2. Daily Summary Report\n3. Month To Date Report\n4. Yearly Summary Report\n5. Daily Imported People List\n6. Alterations Next 7 Days\n\n### Fix completed\nReordered report block assembly in `backend/nightly_reports_service.php` to match exact required sequence.\n\n### Deployment and validation\n- Deployed to live host.\n- `php8.3 -l /mnt/drive1/customerdb/backend/nightly_reports_service.php` passed.\n\n---\n\n## 6) PDF Files Saving with Raw HTML Text\n\n### Reported issue\nSome saved PDFs looked wrong (HTML source printed in the PDF instead of rendered receipt layout).\n\n### Investigation findings\n- Sample file `Hannah-Goncalves-448248-04032026.pdf` is a valid PDF container but includes raw HTML source text (`<!DOCTYPE html>`, tags visible in extracted text).\n- Bulk scan found 4 affected files, all in `04032026` batch:\n  - `Hannah-Goncalves-448248-04032026.pdf`\n  - `Emiliano-Delgado-3226-04032026.pdf`\n  - `Laura-Coyne-488970-04032026.pdf`\n  - `Jamie-Miller-488977-04032026.pdf`\n- Newer reports were rendering normally.\n\n### Fix completed (preventive)\nUpdated `frontend/api/visit_report_generate.php`:\n- Added `vrg_pdf_looks_like_html_source()` quality gate.\n- If generated PDF appears to contain HTML source text, generation now fails fast and does not save corrupt output.\n\n### Deployment and validation\n- Deployed to live host.\n- `php8.3 -l` passed.\n\n### Follow-up required\n- Re-generate the 4 historical affected files from UI (`Save Receipt PDF`) to replace bad copies.\n\n---\n\n## Files Changed In This Session (Core)\n\n### Backend\n- `backend/mail_service.php`\n- `backend/setmore_service.php`\n- `backend/nightly_reports_service.php`\n\n### Frontend\n- `frontend/visit.html`\n- `frontend/receipt.html`\n- `frontend/api/visit_report_generate.php`\n- `frontend/api/totals_snapshot_live.php`\n\n---\n\n## Operational Notes\n\n- Multiple live updates were deployed directly to host `192.168.7.202`.\n- Runtime checks were executed with `php8.3` to match cron/runtime behavior.\n- Temporary maintenance scripts used during diagnosis were deleted from local and remote `/tmp`.\n\n---\n\n## Remaining Action Items\n\n1. Rotate SMTP mailbox password (credential was provided in conversation text).\n2. Re-generate the 4 known bad PDFs from `04032026` batch.\n3. Optional: Add an admin audit endpoint to list historically malformed PDFs using the same detection method, for one-time cleanup.\r\n","is_text_editable":1,"can_edit_inline":1}
documents · upload
2026-04-17 15:18:50 · anonymous · /backend/documents.php
change
backend_document #21
Context
{"file_name":"SESSION_COMPLETION_2026-04-17.md","mime_type":"application/octet-stream"}
Before
[]
After
{"backend_document_id":"21","document_type":"upload","title":"Curser Updates 04-17-2026","slug":"curser-updates-04-17-2026","summary_text":"Curser Updates 04-17-2026","content_markdown":null,"content_html":null,"file_name":"SESSION_COMPLETION_2026-04-17.md","stored_name":"20260417-191850-3b41b6c5.md","mime_type":"application/octet-stream","file_size_bytes":"11631","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260417-191850-3b41b6c5.md","is_deleted":"0","created_at":"2026-04-17 15:18:50","updated_at":"2026-04-17 15:18:50","editor_content":"# Session completion summary — 2026-04-17\n\nThis document records work completed across multiple backend/UI areas: problems observed, root causes, fixes applied, and new or changed behavior. Paths are relative to the repository root (`customerdb`).\n\n---\n\n## 1. Reminders (`backend/reminders.php`)\n\n### Requested behavior\n- Embedded reminders iframe should use more of the layout; later, remove the reminder queue panel entirely and enlarge the embed.\n\n### Changes\n1. **Two-column layout (1/4 + 3/4)**  \n   - Replaced shared `grid cols-2` (~50/50) with a local class `reminders-embed-grid` using `grid-template-columns: 1fr 3fr`, with a `920px` breakpoint stacking to one column (aligned with `page_helpers.php`).\n\n2. **Queue removed; full-width tall iframe**  \n   - Removed the “Reminder Queue” article (stats + table) and all related PHP (`reminder_service.php` queries, `$summary`, `$rows`).\n   - Single `article.panel` with the iframe only.\n   - CSS: `min-height: 720px`, `height: calc(100vh - 200px)` and `calc(100dvh - 200px)` for viewport-relative height (with `vh` fallback).\n   - Removed nested duplicate `.shell` if it had been introduced earlier in this file (payroll had a similar issue; reminders stayed within header shell only).\n\n### Notes\n- `webui/backend/reminders.php` remains a thin loader to `backend/reminders.php`.\n\n---\n\n## 2. Umami analytics (`backend/umami.php`)\n\n### Issues\n- Iframe pointed at a non-existent path (`/backend/umami-embed/login`) → “not found” in the frame.\n- After switching to `https://umami.myexperttailor.com/...`, browsers showed **refused to connect** / embedding failures (CSP / `frame-ancestors`, or network).\n\n### Fixes\n- Set public dashboard URL to the provided Umami website URL.\n- **Embedding:** iframe now targets the **LAN Umami** instance `http://192.168.7.206:3006` with the same `/websites/{uuid}` path so framing is not blocked like the public HTTPS host often is.\n- Copy updated to explain LAN vs public; **Open Public Umami** still opens HTTPS in a new tab.\n\n### Notes\n- True fix for embedding the public host requires server-side headers or a reverse proxy; documented in repo history (`documents_storage`, session logs).\n\n---\n\n## 3. Issue tracker (`backend/issue_tracker.php`)\n\n### Requested behavior\n- Square corners on “boxes,” not rounded.\n\n### Implementation\n- Wrapper class `issue-tracker-square` with overrides for `.panel`, `.card`, `.stat`, `.notice`, inputs, selects, textareas, and `.btn` → `border-radius: 0`.\n- `.done-pill` / `.open-pill` set to `border-radius: 0` for consistency.\n- Scoped so global backend chrome outside the wrapper is unchanged.\n\n---\n\n## 4. Medications (`backend/medication.php`)\n\n### Requested behavior\n- No rounded corners on medication page “boxes.”\n- **Update Medication** as a pill (rounded control); row action aligned with that wording.\n\n### Implementation\n- Wrapper `medication-page-square` with overrides (panels, notices, inputs, buttons square).\n- Exception class **`med-update-pill`** → `border-radius: 999px !important` on:\n  - Submit button in **edit** mode (“Update Medication”).\n  - Table row link (label **Update Medication**, was “Edit”).\n- Local components (`med-calc-row`, `filter-tab`, `badge`, `person-chip`) set to square radii.\n\n### Follow-on (reports)\n- See **§10 Medication reports** (`medication_report.php`).\n\n---\n\n## 5. Medication reports — printable Excel-style (`backend/medication_report.php`)\n\n### Issues\n- `@media print` hid **`.panel:not(.print-keep)`**, which hid almost all report content; “Print” flow was broken for real output.\n- “Due soon” was card layout, not spreadsheet-like.\n\n### Fixes / features\n- **`mrep-excel`** tables: `border-collapse`, full cell borders, gray header row, zebra rows.\n- **Due in next 5 days** converted from flex cards to a **single table** with columns including an on-screen Edit column; **`.mrep-no-print`** hides action column in print.\n- Overdue, by-person inner tables, inactive list → **`mrep-excel`**.\n- Print CSS: hide summary dash, hero actions, buttons; tighten typography; `print-color-adjust: exact` where helpful.\n- Header action: **Print Report** with stable **`id=\"mrep-print-btn\"`**; `page_helpers.php` extended so **anchor** actions can carry **`id`** (same as buttons).\n\n---\n\n## 6. Payroll — stats & theme (`backend/payroll.php`)\n\n### Issues\n- Stat numbers appeared “all black” / not aligned with **settings / theme** CSS variables.\n- Extra **nested `<div class=\"shell\">`** duplicated `app_backend_render_header()`’s shell.\n\n### Fixes\n- **`.pay-stat`**: `var(--backend-box-bg)`, `--backend-line`, `--backend-box-text`, labels `--backend-muted`.\n- **`.worker-yana` / `.worker-lola`**: `var(--teal)` and `var(--accent)` instead of hard-coded hex.\n- All six stats (including **Yana/Lola total rows**) use worker color classes.\n- Tabs / table / paste area hints aligned with backend variables where touched.\n- Unpaid tab badge uses `var(--accent)` + `var(--button-text)`.\n- **Removed inner `.shell` wrapper.**\n\n---\n\n## 7. Payroll — paste import & Excel dates (`backend/payroll_service.php` + `payroll.php`)\n\n### Bugs / issues\n1. **Header row detection** compared normalized Excel headers to a list of **non-normalized** variants (e.g. `amount paid` vs `amount_paid`) → header row often misclassified → wrong column map → skips / zero imports (especially **Yana**-style sheets).\n2. **Excel date serials** and US dates not parsed by `DateTimeImmutable` alone.\n3. **UTF-8 BOM** and **NBSP** breaking header matching.\n4. On paste **exception**, POST resubmit UX; success notice used POST worker string vs canonical.\n\n### Fixes\n- Strip **BOM**; normalize **NBSP** to space in paste text.\n- Build **`$knownHeaderVariants`** using the same **`$norm()`** as header cells.\n- **`$toDate`**: serial range **20000–119999** via **25569** Excel→Unix conversion; explicit `createFromFormat` attempts (`n/j/Y`, `m/d/Y`, etc.) with `DateTimeImmutable::getLastErrors()` guard; fallback parse.\n- Expanded **column aliases** (`customerdatetime`, `custdate`, `client`, etc.).\n- Return array includes **`worker`** (canonical); notice uses it.\n- **Redirect** `?tab=paste&error=...` on paste import exception.\n- **`payroll.php`**: hint text mentions serials and BOM.\n\n---\n\n## 8. Payroll — printable Excel-style (`backend/payroll.php`)\n\n### Features\n- Wrapper **`pay-print-root`**; tables use **`pay-excel`** (grid borders, header strip, zebra).\n- **`@media print`**: hide stats, tabs, mark-paid toolbar, check-all links, inputs/forms inside data tables; compact borders/fonts.\n- **Print** button in hero (`id=\"pay-print-btn\"`) + JS `window.print()`.\n\n---\n\n## 9. Payroll — mark multiple paid (`backend/payroll.php`)\n\n### Bug\n- **Nested `<form>`** for row delete inside the **mark paid** `<form>`. HTML forbids nested forms; the browser **closes the outer form** at the inner `<form>`, so most **`entry_ids[]`** checkboxes were **outside** the mark-paid form → only **one** (or erratic) ID posted.\n\n### Fix\n- Delete control: **`<button type=\"submit\" form=\"payroll-del-{id}\">`**.\n- **Hidden `<form id=\"payroll-del-…\">`** per row, emitted **after** `</form>` of mark-paid (merged Yana + Lola unpaid rows).\n- Main form **`id=\"payroll-mark-paid\"`**.\n\n---\n\n## 10. Stocks & crypto — average cost precision (`backend/stocks_crypto.php`, `backend/stocks_crypto_service.php`)\n\n### Issue\n- **`avg_cost DECIMAL(14,6)`** and form **`step=\"0.000001\"`** / six-decimal display capped precision (problematic for crypto).\n\n### Fixes\n- Schema: **`DECIMAL(24,12)`**; `ALTER` to widen existing DBs (try/catch).\n- Save: pass **numeric string** into SQL (comma stripped, escaped) instead of float stringification for INSERT/UPDATE.\n- Form: **`step=\"any\"`**; edit value from **`trim((string)$editAsset['avg_cost'])`** (DB string).\n- Portfolio avg column: display **string** from DB to avoid float truncation.\n- Chart: **`hist_asset`** path uses JSON-encoded string → **`Number()`** in JS for the avg line.\n\n---\n\n## 11. Stocks & crypto — duplicate ticker / lots (`backend/stocks_crypto_service.php`, `backend/stocks_crypto.php`, `backend/api/stocks_summary.php`)\n\n### Issue\n- **`UNIQUE KEY uq_ticker (ticker)`** prevented a second **BTC** row even when notes differed.\n\n### Fixes\n- New installs: **`KEY ix_stocks_asset_ticker (ticker)`** (non-unique) instead of `uq_ticker`.\n- Existing DBs: **`ALTER TABLE stocks_asset DROP INDEX uq_ticker`** (try/catch); **`ADD KEY ix_stocks_asset_ticker`** if missing (try/catch).\n- **Portfolio / chart links:** `hist={ticker}&hist_asset={stocks_asset_id}` (+ optional `type=` filter) so **avg cost** matches the correct lot when tickers repeat.\n- **Prices tab:** inputs **`name=\"price_a_{stocks_asset_id}\"`**; **`save_prices`** resolves asset id → ticker (duplicate tickers no longer overwrite the same POST key).\n- **`app_stocks_fetch_all_live`:** fetch **once per distinct ticker** (dedupe).\n- **`stocks_summary` API:** each asset includes **`id`** (`stocks_asset_id`).\n\n### Related: `backend/page_helpers.php`\n- **`id`** attribute supported on **link**-type header actions (used by medication report print link).\n\n---\n\n## Files touched (summary)\n\n| File | Nature of change |\n|------|------------------|\n| `backend/reminders.php` | Layout + iframe-only page |\n| `backend/umami.php` | Embed URL, copy, LAN vs public |\n| `backend/issue_tracker.php` | Square-corner scoped CSS |\n| `backend/medication.php` | Square UI + pill update control + row link label |\n| `backend/medication_report.php` | Excel tables + print CSS + print button id on links |\n| `backend/page_helpers.php` | `id` on `<a>` action items |\n| `backend/payroll.php` | Theme vars, no nested shell, Excel/print, paste UX, mark-paid/delete forms |\n| `backend/payroll_service.php` | Paste import robustness, dates, headers, worker in return |\n| `backend/stocks_crypto.php` | avg_cost UI, `hist_asset`, portfolio URLs, `price_a_*` |\n| `backend/stocks_crypto_service.php` | Schema avg_cost, drop uq_ticker, index, save avg string, live fetch dedupe |\n| `backend/api/stocks_summary.php` | `id` on each asset in JSON |\n\nThin loaders under `webui/backend/` were unchanged where they only `require` canonical `backend/*.php`.\n\n---\n\n## Testing suggestions (manual)\n\n1. **Reminders:** load `/backend/reminders.php` — iframe fills width and height sensibly.\n2. **Umami:** confirm LAN iframe loads; public link in new tab.\n3. **Issue tracker / medication:** visual check square corners and pill(s) on medication update path.\n4. **Medication report:** Print preview — tables have grid lines; no empty printout.\n5. **Payroll:** paste Yana/Lola sheets with BOM, serial dates, varied headers; mark **multiple** unpaid rows paid in one submit.\n6. **Payroll print:** Print preview hides chrome; tables print.\n7. **Stocks:** add two **BTC** lots with different notes; set high-precision avg cost; prices tab saves both rows; chart `hist_asset` matches correct avg line; API returns distinct `id` per row.\n\n---\n\n## Known limitations / follow-ups\n\n- **Umami public host** embedding still depends on remote CSP / network; LAN proxy is the reliable approach.\n- **PHP `float`** still limits extreme precision in some JS chart paths; DB stores **12** fractional digits for `avg_cost`.\n- **Payroll paste** very large pastes may hit `max_input_vars` / post size limits (server config), not addressed in code.\n- **Medication** “Update Medication” row link text is long in narrow tables; acceptable per product request.\n\n---\n\n*Generated from implementation session work; adjust dates or add ticket IDs if you track work in an external system.*\n","is_text_editable":1,"can_edit_inline":1}
speed_dial · create
2026-04-17 15:05:43 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #38
Context
[]
Before
[]
After
{"backend_speed_dial_id":"38","link_name":"MUV","link_url":"https://muvfl.com/locations/zephyrhills","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:05:43","updated_at":"2026-04-17 15:05:43"}
speed_dial · create
2026-04-17 15:05:27 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #37
Context
[]
Before
[]
After
{"backend_speed_dial_id":"37","link_name":"Target","link_url":"https://www.target.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:05:27","updated_at":"2026-04-17 15:05:27"}
speed_dial · create
2026-04-17 15:05:13 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #36
Context
[]
Before
[]
After
{"backend_speed_dial_id":"36","link_name":"Video Compress","link_url":"https://freecompress.com/reduce-video","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:05:13","updated_at":"2026-04-17 15:05:13"}
speed_dial · create
2026-04-17 15:04:58 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #35
Context
[]
Before
[]
After
{"backend_speed_dial_id":"35","link_name":"Duke Energy","link_url":"https://www.duke-energy.com/home","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:04:58","updated_at":"2026-04-17 15:04:58"}
speed_dial · create
2026-04-17 15:04:34 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #34
Context
[]
Before
[]
After
{"backend_speed_dial_id":"34","link_name":"Monument Metals","link_url":"https://monumentmetals.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:04:34","updated_at":"2026-04-17 15:04:34"}
speed_dial · create
2026-04-17 15:04:16 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #33
Context
[]
Before
[]
After
{"backend_speed_dial_id":"33","link_name":"Johnson &amp; Johnson Insurance","link_url":"https://www.jjins.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:04:16","updated_at":"2026-04-17 15:04:16"}
speed_dial · create
2026-04-17 15:03:51 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #32
Context
[]
Before
[]
After
{"backend_speed_dial_id":"32","link_name":"Blue Sky","link_url":"https://bsky.app/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:03:51","updated_at":"2026-04-17 15:03:51"}
speed_dial · create
2026-04-17 15:03:32 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #31
Context
[]
Before
[]
After
{"backend_speed_dial_id":"31","link_name":"Civitai","link_url":"https://civitai.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:03:32","updated_at":"2026-04-17 15:03:32"}
speed_dial · create
2026-04-17 15:03:18 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #30
Context
[]
Before
[]
After
{"backend_speed_dial_id":"30","link_name":"Ambient Weather","link_url":"https://ambientweather.net/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:03:18","updated_at":"2026-04-17 15:03:18"}
speed_dial · create
2026-04-17 15:02:52 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #29
Context
[]
Before
[]
After
{"backend_speed_dial_id":"29","link_name":"Threads","link_url":"https://www.threads.net/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:02:52","updated_at":"2026-04-17 15:02:52"}
speed_dial · create
2026-04-17 15:02:41 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #28
Context
[]
Before
[]
After
{"backend_speed_dial_id":"28","link_name":"Mastodon","link_url":"https://mastodon.social/deck/getting-started","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:02:41","updated_at":"2026-04-17 15:02:41"}
speed_dial · create
2026-04-17 15:02:24 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #27
Context
[]
Before
[]
After
{"backend_speed_dial_id":"27","link_name":"Truth Social","link_url":"https://truthsocial.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:02:24","updated_at":"2026-04-17 15:02:24"}
speed_dial · create
2026-04-17 15:02:16 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #26
Context
[]
Before
[]
After
{"backend_speed_dial_id":"26","link_name":"Rumble","link_url":"https://rumble.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:02:16","updated_at":"2026-04-17 15:02:16"}
speed_dial · create
2026-04-17 15:01:32 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #25
Context
[]
Before
[]
After
{"backend_speed_dial_id":"25","link_name":"Tiktok","link_url":"https://www.tiktok.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:01:32","updated_at":"2026-04-17 15:01:32"}
speed_dial · create
2026-04-17 15:01:18 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #24
Context
[]
Before
[]
After
{"backend_speed_dial_id":"24","link_name":"Suno","link_url":"http://suno.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:01:18","updated_at":"2026-04-17 15:01:18"}
speed_dial · create
2026-04-17 15:01:02 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #23
Context
[]
Before
[]
After
{"backend_speed_dial_id":"23","link_name":"Youtube","link_url":"https://www.youtube.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:01:02","updated_at":"2026-04-17 15:01:02"}
speed_dial · create
2026-04-17 15:00:50 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #22
Context
[]
Before
[]
After
{"backend_speed_dial_id":"22","link_name":"Instagram","link_url":"https://www.instagram.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:00:50","updated_at":"2026-04-17 15:00:50"}
speed_dial · create
2026-04-17 15:00:38 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #21
Context
[]
Before
[]
After
{"backend_speed_dial_id":"21","link_name":"Twitter","link_url":"https://x.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 15:00:38","updated_at":"2026-04-17 15:00:38"}
← Prev 1 5499 5500 5501 5502 5503 5508 Next →