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,738
Errors (total)1,005,719
Today · changes1
Today · errors6,195
Reset

9,093 results · Page 182 of 182

bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":201,"severity_code":8192}
bank_service.php
2026-04-28 17:55:08 · cli · tmp\import_bank_transactions_xlsx.php
php_error
fgetcsv(): the $escape parameter must be provided as its default value will change
Script: tmp\import_bank_transactions_xlsx.php
IP: cli
Context
{"file":"C:\\code\\customerdb\\backend\\bank_service.php","line":187,"severity_code":8192}
documents · upload
2026-04-20 14:36:27 · anonymous · /backend/documents.php
change
backend_document #23
Context
{"file_name":"ESSENTIAL_FILES_ANALYSIS.md","mime_type":"application/octet-stream"}
Before
[]
After
{"backend_document_id":"23","document_type":"upload","title":"All Essential Files for Customer DB","slug":"all-essential-files-for-customer-db","summary_text":"All Essential Files for Customer DB","content_markdown":null,"content_html":null,"file_name":"ESSENTIAL_FILES_ANALYSIS.md","stored_name":"20260420-183627-ab045aa6.md","mime_type":"application/octet-stream","file_size_bytes":"9785","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260420-183627-ab045aa6.md","is_deleted":"0","created_at":"2026-04-20 14:36:27","updated_at":"2026-04-20 14:36:27","editor_content":"# Essential Files Analysis - C:\\code\\customerdb\n\n**Generated:** April 17, 2026\n\n---\n\n## Summary\n\nThis document identifies which files are essential to keep vs which can be safely removed to reduce disk usage and simplify the codebase.\n\n**Estimated Space Savings:** ~200+ MB\n\n---\n\n## KEEP - Essential Files\n\n### Core Application\n\n```\nC:\\code\\customerdb\\backend\\           # Main PHP backend (98 files)\nC:\\code\\customerdb\\frontend\\          # Front Desk app (15 HTML pages)\nC:\\code\\customerdb\\frontend\\api\\       # Frontend API endpoints\nC:\\code\\customerdb\\scripts\\           # Import/sync scripts\nC:\\code\\customerdb\\migrations\\         # SQL migrations\nC:\\code\\customerdb\\csv\\               # Active CSV data\nC:\\code\\customerdb\\docs\\             # Documentation\nC:\\code\\customerdb\\backups\\           # Database backups (prune old)\nC:\\code\\customerdb\\mariadb_core_schema.sql\nC:\\code\\customerdb\\backup.sh\n```\n\n### Backend - Essential Files (98 PHP files)\n\n| File | Purpose |\n|------|---------|\n| `bootstrap.php` | Core bootstrap |\n| `customer_service.php` | Customer management |\n| `customer.php` | Customer API |\n| `visit_service.php` | Visit records |\n| `visit.php` | Visit API |\n| `customer_totals_service.php` | Daily totals |\n| `report_service.php` | Reporting (80KB) |\n| `schedule.php` | Appointment scheduling |\n| `setmore_service.php` | Setmore integration |\n| `email_service.php` | Email handling |\n| `bank_service.php` | Banking |\n| `gold_silver_service.php` | Precious metals |\n| `duke_service.php` | Energy tracking |\n| `payroll_service.php` | Payroll |\n| `stocks_crypto_service.php` | Investments |\n| `medication_service.php` | Medication tracking |\n| `backup_database_service.php` | Database backup |\n| `cron_manager.php` | Cron management |\n| `nightly_reports_service.php` | Nightly reports |\n| `morning_jobs_service.php` | Morning batch jobs |\n| `square_terminal_service.php` | Square POS |\n| `live_table_manager_service.php` | Live data tables |\n| `notifications_service.php` | Notifications |\n\n**API Endpoints:** 58 files in `/backend/api/` - all active REST endpoints\n\n### Frontend - HTML Pages (15 files)\n\n| File | Purpose |\n|------|---------|\n| `visit.html` | Visit management (254KB) |\n| `customer.html` | Customer records |\n| `index.html` | Main dashboard |\n| `reports.html` | Reports viewer |\n| `schedule.html` | Schedule view |\n| `work_order.html` | Work orders |\n| `workload.html` | Workload view |\n| `receipt.html` | Receipt printing |\n| `login.html` | Authentication |\n| `upcoming.html` | Upcoming appointments |\n| `square_customer.html` | Square integration |\n| `item_types.html` | Item types |\n| `todo.html` | Todo lists |\n| `customer_display.html` | Customer display |\n\n### Scripts - Essential (7 files)\n\n| Script | Purpose |\n|--------|---------|\n| `import_csv_v2.py` | CSV import |\n| `import_access_v2.py` | Access DB import |\n| `access_to_mariadb_parser.py` | Access parser |\n| `import_legacy_totals_from_excel.ps1` | Excel import |\n| `sync_backend_mirror.ps1` | Mirror sync |\n| `check_backend_mirror.ps1` | Mirror check |\n| `signature_blob_loader.py` | Signature loader |\n\n### Migrations - Essential (3 files)\n\n| File | Purpose |\n|------|---------|\n| `20260407_add_conversion_job.sql` | Conversion job table |\n| `20260411_order_items_item_type_name_no_fk.sql` | Item type changes |\n| `20260416_blog_prompt_templates.sql` | Blog prompts |\n\n### CSV Data - Essential\n\n| File | Purpose |\n|------|---------|\n| `CustomerTable.csv` | Customer records |\n| `CustomerVisits.csv` | Visit records |\n| `CustomerTotals.csv` | Daily totals |\n| `AlterationItems.csv` | Alteration items |\n\n---\n\n## REMOVE - Redundant/Unused Files\n\n### Priority 1 - Safe to Delete (Complete Directories)\n\n| Directory | Size | Action |\n|-----------|------|--------|\n| `notused\\` | ~85 MB | DELETE ENTIRE |\n| `venv\\` | ~100 MB | DELETE ENTIRE |\n| `OldFiles\\` | ~1 MB | DELETE ENTIRE |\n| `.vs\\` | ~1 MB | DELETE ENTIRE |\n| `.vscode\\` | small | DELETE |\n\n#### notused/ Contents (DELETE ALL)\n```\nnotused\\access_to_mariadb_parser (1).py   # duplicates\nnotused\\access_to_mariadb_parser (2).py   # duplicates\nnotused\\customerdb_v2_staging_schema.sql  # duplicate\nnotused\\mariadb_core_schema.sql          # duplicate\nnotused\\mariadb-12.2.2-winx64.msi        # MariaDB installer (89MB!)\nnotused\\Backend\\                         # old PHP code\nnotused\\backups\\                         # old backups\nnotused\\csv\\                           # old CSVs\nnotused\\docs\\                          # old docs\nnotused\\schema\\                        # old schemas\nnotused\\scripts\\                      # old scripts\nnotused\\webui\\                        # old webui\n```\n\n### Priority 2 - Duplicate WebUI (Check First)\n\n| Directory | Purpose |\n|-----------|---------|\n| `webui\\` | ~15 MB - mirrors backend/frontend |\n\nThis directory appears to mirror the main `backend/` and `frontend/` directories. If `webui` is NOT served as a separate application, DELETE ENTIRE:\n\n```\nwebui\\backend\\         # 89 files - duplicate of ../backend/\nwebui\\frontend\\       # mirrors ../frontend/\nwebui\\api\\           # similar to ../frontend/api/\n```\n\n### Priority 3 - Temporary Files\n\nDelete all files matching patterns:\n```\ntmp_*.php     (~30 files)  # temp PHP scripts\ntmp_*.sql     (~30 files)  # temp SQL queries\ntmp_*.sh      (1 file)    # temp shell scripts\ntmp_*.csv     (1 file)    # temp CSV files\n```\n\nExamples:\n- `tmp_check_129411.sql`\n- `tmp_nightly_preview.php`\n- `tmp_compare_sheet_customer_totals.sql`\n- `tmp_mirror_drive.sh`\n- `tmp_customertotalsaccess.csv`\n\n### Priority 4 - Check Before Delete\n\n| Directory | Purpose | Action |\n|-----------|---------|--------|\n| `blog\\` | Blog module | Verify if used, else DELETE |\n| `Topaz\\` | Signature pad drivers | Verify if needed, else DELETE |\n| `wordpress-plugin\\` | WP integration | Verify if used, else DELETE |\n| `schedule\\` | Laravel scheduling app | Verify if integrated, else DELETE |\n| `csv\\back\\` | 8 backup CSVs | Likely duplicate, verify then DELETE |\n\n### Priority 5 - Backup Files\n\n| File Pattern | Action |\n|-------------|--------|\n| `*.bak_*` | DELETE |\n| `*.bak` | DELETE |\n| `*.backup` | DELETE |\n| `*~` | DELETE |\n\n### Priority 6 - Root Level Large Unused Files\n\n| File | Size | Action |\n|------|------|--------|\n| `Items To Test or Comlete.odt` | 26KB | Move to docs or DELETE |\n\n---\n\n## Directory Structure After Cleanup\n\n```\ncustomerdb/\n├── backend/                    # KEEP - Main PHP backend\n│   ├── api/                    # KEEP - API endpoints\n│   ├── jobs/                   # KEEP - Cron jobs\n│   └── bin/                    # KEEP - Binaries\n├── frontend/                   # KEEP - Front Desk app\n│   ├── api/                   # KEEP - API calls\n│   └── reports/               # KEEP - PDF reports\n├── scripts/                   # KEEP - Import scripts\n├── migrations/                 # KEEP - DB migrations\n├── csv/                       # KEEP - Active data\n│   └── back/                 # DELETE - backup copies\n├── docs/                      # KEEP - Documentation\n├── backups/                   # KEEP - Keep latest, prune old\n├── schema/                   # KEEP or DELETE (empty)\n├── mariadb_core_schema.sql        # KEEP - Core schema\n├── migrate_add_visit_type.sql   # KEEP - Migration\n├── backup.sh                # KEEP - Backup script\n├── .gitignore              # KEEP\n│\n├── notused/                 # DELETE ENTIRE (~85 MB)\n├── OldFiles/               # DELETE ENTIRE (~1 MB)\n├── .vs/                    # DELETE (~1 MB)\n├── .vscode/                # DELETE\n├── venv/                   # DELETE (~100 MB)\n├── webui/                  # DELETE OR VERIFY FIRST\n├── blog/                   # VERIFY - then delete\n├── Topaz/                  # VERIFY - then delete\n├── wordpress-plugin/        # VERIFY - then delete\n├── schedule/               # VERIFY - then delete\n└── tmp_*.*                 # DELETE ALL (~2 MB)\n```\n\n---\n\n## Space Savings Summary\n\n| Category | Savings |\n|----------|----------|\n| `notused/` directory | ~85 MB |\n| `venv/` directory | ~100 MB |\n| `tmp_*` files | ~2 MB |\n| `OldFiles/` | ~1 MB |\n| `.vs`, `.vscode` | ~1 MB |\n| `webui/` (if duplicate) | ~15 MB |\n| `csv/back/` | ~2 MB |\n| **TOTAL** | **~200+ MB** |\n\n---\n\n## Commands to Remove Files\n\n### PowerShell - Delete Priority 1 (Safe to Delete)\n\n```powershell\n# Delete notused directory\nRemove-Item -Recurse -Force \"C:\\code\\customerdb\\notused\"\n\n# Delete OldFiles directory\nRemove-Item -Recurse -Force \"C:\\code\\customerdb\\OldFiles\"\n\n# Delete .vs directory\nRemove-Item -Recurse -Force \"C:\\code\\customerdb\\.vs\"\n\n# Delete .vscode directory\nRemove-Item -Recurse -Force \"C:\\code\\customerdb\\.vscode\"\n\n# Delete venv directory\nRemove-Item -Recurse -Force \"C:\\code\\customerdb\\venv\"\n```\n\n### PowerShell - Delete Temporary Files\n\n```powershell\n# Delete all tmp_* files in root\nGet-ChildItem \"C:\\code\\customerdb\" -Filter \"tmp_*\" | Remove-Item -Force\n\n# Delete backup files\nGet-ChildItem \"C:\\code\\customerdb\" -Filter \"*.bak*\" | Remove-Item -Force\n```\n\n### PowerShell - Delete Duplicate WebUI (After Verification)\n\n```powershell\n# Only run if webui is NOT served separately\nRemove-Item -Recurse -Force \"C:\\code\\customerdb\\webui\"\n```\n\n---\n\n## Verification Checklist Before Delete\n\n- [ ] **webui/** - Is port 8894 served from this directory? If yes, KEEP. If served from `backend/`, DELETE.\n- [ ] **blog/** - Is blog feature actively used in the application?\n- [ ] **Topaz/** - Is the Topaz signature pad still in use?\n- [ ] **wordpress-plugin/** - Is WordPress integration still active?\n- [ ] **schedule/** - Is the Laravel scheduling app still integrated?\n\n---\n\n*End of Analysis*","is_text_editable":1,"can_edit_inline":1}
speed_dial · create
2026-04-17 14:57:42 · anonymous · /backend/speed_dial.php?ok=1
change
backend_speed_dial #12
Context
[]
Before
[]
After
{"backend_speed_dial_id":"12","link_name":"Centennial Bank","link_url":"https://www.my100bank.com/","sort_order":"0","is_active":"1","created_at":"2026-04-17 14:57:42","updated_at":"2026-04-17 14:57:42"}
documents · save
2026-04-17 14:50:34 · anonymous · /backend/documents.php
change
backend_document #20
Context
{"document_type":"upload"}
Before
{"backend_document_id":"20","document_type":"upload","title":"Complete Documentation up to date 04-17-2026","slug":"complete-documentation-up-to-date","summary_text":"Complete Documentation up to date 04-17-2026","content_markdown":"# Ella's Alterations - Comprehensive System Documentation\r\n\r\n**Generated:** April 17, 2026\r\n**Location:** C:\\code\\customerdb\r\n\r\n---\r\n\r\n## Table of Contents\r\n\r\n1. [System Overview](#1-system-overview)\r\n2. [Directory Structure](#2-directory-structure)\r\n3. [Database Schema](#3-database-schema)\r\n4. [API Endpoints](#4-api-endpoints)\r\n5. [External Integrations](#5-external-integrations)\r\n6. [Scheduled Jobs / Cron](#6-scheduled-jobs--cron)\r\n7. [Web Applications](#7-web-applications)\r\n8. [Settings & Configuration](#8-settings--configuration)\r\n9. [Migration Notes](#9-migration-notes)\r\n10. [Scripts & Tools](#10-scripts--tools)\r\n\r\n---\r\n\r\n## 1. System Overview\r\n\r\n### Purpose\r\nElla's Alterations is a comprehensive customer relationship management (CRM) andAlteration tracking system for a tailor shop. It manages customers, visits/alteration orders, appointments, payments, and provides integration with external services.\r\n\r\n### Server Information\r\n- **Primary Server:** kefa@192.168.7.202\r\n- **Mirror Drive:** /mnt/drive2 (mirrors /mnt/drive1)\r\n- **Database:** MariaDB - database `ellas_alterations`, user `kefa_admin`\r\n- **Web Server:** Apache 2.4 with mod-php\r\n- **PHP Version:** 8.3\r\n\r\n### Three Web Applications\r\n\r\n| App | Local URL | Public URL | Purpose |\r\n|-----|-----------|------------|---------|\r\n| Front Desk | http://192.168.7.202:8895 | https://ella.floridaalterations.com | Customer-facing operations |\r\n| Management | http://192.168.7.202:8894 | (LAN only) | Reports, admin, settings |\r\n| Scheduler | http://192.168.7.202:8897 | https://schedule.floridaalterations.com | Easy!Appointments booking |\r\n\r\n---\r\n\r\n## 2. Directory Structure\r\n\r\n```\r\ncustomerdb/\r\n├── backend/                    # Main PHP backend API and services\r\n│   ├── api/                    # REST API endpoints (~57 files)\r\n│   ├── bin/                    # Binary/executable scripts\r\n│   ├── backup/                # Backup versions of services\r\n│   └── jobs/                  # Background job scripts\r\n├── frontend/                   # Front Desk app (port 8895)\r\n│   ├── *.html                 # HTML pages\r\n│   ├── api/                   # PHP API endpoints\r\n│   └── reports/               # PDF reports (MMDDYYYY/filename.pdf)\r\n├── webui/                      # Management app (port 8894)\r\n│   ├── *.html                 # HTML pages\r\n│   ├── api/                  # PHP API endpoints\r\n│   ├── backend/               # Backend API copy\r\n│   └── email/                # Email templates\r\n├── schedule/                   # Easy!Appointments installation\r\n├── schema/                    # Database schema files\r\n├── migrations/               # SQL migrations\r\n├── scripts/                   # PowerShell/Python import scripts\r\n├── docs/                     # Documentation\r\n├── blog/                     # Blog system and reengineering\r\n├── csv/                      # CSV data files\r\n├── backups/                  # Backup archives\r\n├── Topaz/                    # Topaz signature pad configs\r\n├── webui/                    # Second web interface\r\n│   ├── api/\r\n│   ├── backend/\r\n│   └── frontend/\r\n├── notused/                  # Deprecated/unused files\r\n└── wordpress-plugin/          # WordPress integration\r\n```\r\n\r\n---\r\n\r\n## 3. Database Schema\r\n\r\n### Core Tables (from mariadb_core_schema.sql)\r\n\r\n#### customers\r\nMain customer registry.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| customer_id | INT UNSIGNED PK | Auto-increment |\r\n| legacy_customer_id | INT NULL | Original Access DB ID |\r\n| created_at | DATETIME | Record creation time |\r\n| full_name | VARCHAR(200) | Customer full name |\r\n| phone | VARCHAR(30) | Formatted (XXX) XXX-XXXX |\r\n| email | VARCHAR(255) | Email address |\r\n| pickup_due_at | DATETIME | Next pickup date (synced from EA) |\r\n| description | TEXT | Description |\r\n| notes | TEXT | Internal notes |\r\n| is_new_customer | TINYINT(1) | 1 if flagged as new |\r\n\r\n#### visits\r\nOne row per alteration job/order.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| visit_id | INT UNSIGNED PK | |\r\n| legacy_visit_id | INT NULL | Original Access DB ID |\r\n| customer_id | INT UNSIGNED FK | → customers |\r\n| visit_date | DATETIME | Drop-off date |\r\n| pickup_date | DATETIME | Expected pickup |\r\n| notes | TEXT | General visit notes |\r\n| customer_name_snapshot | VARCHAR(200) | |\r\n| phone_snapshot | VARCHAR(30) | |\r\n| email_snapshot | VARCHAR(255) | |\r\n| color | VARCHAR(100) | Garment color |\r\n| alterations_needed | TEXT | |\r\n| alterations_notes | TEXT | Detailed alteration instructions |\r\n| alterations_price | DECIMAL(10,2) | Manual price field |\r\n| total_alteration_price | DECIMAL(10,2) | Calculated from items |\r\n| expedited_fee | DECIMAL(10,2) | |\r\n| paid_date | DATETIME | When paid |\r\n| signature_text | TEXT | Text signature (legacy) |\r\n| signature_date | DATETIME | |\r\n| paid_flag | TINYINT(1) | 1 = paid |\r\n| source_key_value | VARCHAR(100) | |\r\n\r\n#### visit_signatures\r\nFull resolution signature images per visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| signature_id | BIGINT UNSIGNED PK | |\r\n| visit_id | INT UNIQUE | One signature per visit |\r\n| signature_date | DATETIME | |\r\n| image_format | VARCHAR(50) | Default 'image/png' |\r\n| original_filename | VARCHAR(255) | |\r\n| original_extension | VARCHAR(20) | |\r\n| file_size_bytes | BIGINT | |\r\n| sha256_hash | CHAR(64) | Hash for verification |\r\n| signature_image | LONGBLOB | Raw PNG binary |\r\n| created_at | DATETIME | |\r\n\r\n#### item_types\r\nMaster list of alteration types (e.g., Hem, Zipper, Taper).\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| item_type_id | INT UNSIGNED PK | |\r\n| type_name | VARCHAR(100) UNIQUE | Display name |\r\n\r\n#### orders\r\nOrders per visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_id | BIGINT UNSIGNED PK | |\r\n| visit_id | INT UNSIGNED FK | → visits |\r\n| customer_id | INT UNSIGNED FK | → customers |\r\n| created_at | DATETIME | |\r\n| no_tax | TINYINT(1) | Tax exempt |\r\n| picked_up | TINYINT(1) | |\r\n| source_table | VARCHAR(50) | |\r\n\r\n#### order_items\r\nLine items for each alteration within a visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_item_id | BIGINT UNSIGNED PK | |\r\n| order_id | BIGINT UNSIGNED FK | → orders |\r\n| legacy_alteration_id | INT NULL | |\r\n| item_type_id | INT FK | → item_types |\r\n| item_type_name | VARCHAR(100) | |\r\n| description | TEXT | |\r\n| quantity | INT | Default 1 |\r\n| unit_price | DECIMAL(10,2) | |\r\n| total_price | DECIMAL(10,2) | |\r\n| notes | TEXT | Per-item notes |\r\n| color | VARCHAR(100) | Garment color |\r\n| no_tax | TINYINT(1) | Tax exempt |\r\n| is_range_price | TINYINT(1) | |\r\n| range_price_label | VARCHAR(100) | |\r\n| paid_flag | TINYINT(1) | |\r\n| paid_type | VARCHAR(100) | |\r\n| picked_up | TINYINT(1) | |\r\n| created_at | DATETIME | |\r\n\r\n#### order_item_type_links\r\nMany-to-many links between order items and item types.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_item_type_link_id | BIGINT UNSIGNED PK | |\r\n| order_item_id | BIGINT UNSIGNED FK | → order_items |\r\n| item_type_id | INT UNSIGNED FK | → item_types |\r\n| slot_number | TINYINT UNSIGNED | |\r\n\r\n#### payments\r\nPayment records per order.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| payment_id | BIGINT UNSIGNED PK | |\r\n| order_id | BIGINT UNSIGNED FK | → orders |\r\n| payment_date | DATETIME | |\r\n| payment_type | VARCHAR(100) | |\r\n| payment_method | VARCHAR(100) | |\r\n| amount | DECIMAL(10,2) | |\r\n| notes | TEXT | |\r\n\r\n#### tax_payments\r\nTax payment records.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| tax_payment_id | INT UNSIGNED PK | |\r\n| legacy_tax_payment_id | INT NULL | |\r\n| payment_date | DATETIME | |\r\n| payment_type | VARCHAR(100) | |\r\n| payment_method | VARCHAR(100) | |\r\n| amount | DECIMAL(10,2) | |\r\n| notes | TEXT | |\r\n| receipt_blob | LONGBLOB | |\r\n\r\n#### change_log\r\nAudit log for changes.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| log_id | BIGINT UNSIGNED PK | |\r\n| legacy_log_id | INT NULL | |\r\n| table_name | VARCHAR(100) | |\r\n| record_id | BIGINT | |\r\n| visit_id | INT | |\r\n| field_name | VARCHAR(100) | |\r\n| old_value | TEXT | |\r\n| new_value | TEXT | |\r\n| changed_at | DATETIME | |\r\n| changed_by | VARCHAR(100) | |\r\n\r\n#### ads\r\nAdvertising/articles.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| ad_id | INT UNSIGNED PK | |\r\n| legacy_ad_id | INT NULL | |\r\n| article_text | TEXT | |\r\n| article_picture | LONGBLOB | |\r\n| site_submitted | VARCHAR(255) | |\r\n| views | INT | Default 0 |\r\n| date_posted | DATETIME | |\r\n\r\n#### staging_* tables\r\nStaging tables for data migration.\r\n\r\n| Table Name | Purpose |\r\n|------------|---------|\r\n| staging_customer_table_raw | Staging for legacy customer data |\r\n| staging_customer_visits_raw | Staging for legacy visits |\r\n| staging_alteration_items_raw | Staging for items |\r\n\r\n### Additional Backend Tables\r\n\r\n| Table Name | Purpose |\r\n|------------|---------|\r\n| setmore_appointments | Synced from Setmore |\r\n| backend_conversion_job | Document conversion jobs |\r\n| backend_job_runs | Background job execution log |\r\n| customer_totals | Daily customer totals |\r\n| daily_customer_totals | Daily summary totals |\r\n| customer_payment_transactions | Payment ledger |\r\n| legacy_customer_totals_monthly | Monthly totals (legacy) |\r\n| legacy_customer_totals_irs_monthly | IRS monthly reports |\r\n| backend_appointment_workflow | Appointment state machine |\r\n| backend_no_show_log | No-show tracking |\r\n| backend_error_log | Error logging |\r\n| backend_change_log | Change audit log |\r\n| backend_document | Document storage |\r\n| backend_document_version | Document version history |\r\n| backend_speed_dial | Quick links |\r\n| backend_square_terminal_code | Square terminal pairing codes |\r\n| backend_square_terminal_device | Square device registry |\r\n| cron_job | Scheduled job definitions |\r\n| cron_job_run | Cron execution history |\r\n| app_settings | Global configuration |\r\n| app_users | Login accounts |\r\n| remember_tokens | \"Remember Me\" tokens |\r\n| customer_reports | PDF report index |\r\n\r\n---\r\n\r\n## 4. API Endpoints\r\n\r\n### 4.1 Frontend API (port 8895 /api/)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **customer_get.php** | Get customer by ID |\r\n| **customer_save.php** | Create or update customer |\r\n| **customer_detail.php** | Customer + visits summary |\r\n| **customer_delete.php** | Delete customer |\r\n| **customer_list_hide.php** | Hide customer from list |\r\n| **search_customers.php** | Search by name/phone |\r\n| **visit_get.php** | Get visit + items |\r\n| **visit_save.php** | Create/update visit + items |\r\n| **visit_delete.php** | Delete visit |\r\n| **visit_report_generate.php** | Generate visit report |\r\n| **item_types.php** | List all alteration types |\r\n| **item_type_add.php** | Add new item type |\r\n| **item_type_update.php** | Update item type |\r\n| **item_type_delete.php** | Delete item type |\r\n| **pickups_today.php** | Orders due today |\r\n| **ready.php** | Orders ready for pickup |\r\n| **overdue.php** | Overdue orders |\r\n| **upcoming.php** | Orders due in next N days |\r\n| **workload_7days.php** | 7-day workload |\r\n| **save_signature.php** | Save canvas signature |\r\n| **reports_list.php** | Reports for customer |\r\n| **attach_reports.php** | Index all PDFs to DB |\r\n| **save_signature.php** | Save signature image |\r\n| **today_appointments_list.php** | Today's appointments |\r\n| **settings_get.php** | Get app settings |\r\n| **settings_save.php** | Save app settings |\r\n| **settings_css.php** | Live theme CSS |\r\n| **send_email.php** | Send email via SMTP |\r\n| **send_sms.php** | Send SMS via Twilio |\r\n| **send_reminders.php** | Send appointment reminders |\r\n| **ea_appointments.php** | EasyAppointments REST API |\r\n| **ea_webhook.php** | Receives EA webhook events |\r\n| **setmore.php** | Setmore API proxy |\r\n| **setmore_to_ea_import.php** | Import customers to EA |\r\n| **square_config.php** | Square public config |\r\n| **square_process.php** | Process Square payment |\r\n| **square_customer_log.php** | Customer Square log |\r\n| **square_terminal.php** | Square terminal |\r\n| **login.php** | Authenticate |\r\n| **logout.php** | Clear session |\r\n| **session_check.php** | Check if logged in |\r\n| **auth.php** | Session authentication |\r\n| **config.php** | App config constants |\r\n| **db.php** | Database connection |\r\n| **log_error.php** | Log client-side error |\r\n| **todo_list.php** | Todo list management |\r\n| **send_telegram.php** | Send Telegram messages |\r\n\r\n### 4.2 Management API (port 8894 /api/)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **login.php** | Authenticate |\r\n| **logout.php** | Clear session |\r\n| **session_check.php** | Check if logged in |\r\n| **customer_detail.php** | Customer + visits |\r\n| **search_customers.php** | Search customers |\r\n| **update_customer.php** | Update customer |\r\n| **users_list.php** | List all users |\r\n| **user_save.php** | Create/update user |\r\n| **list_report_dirs.php** | Date folders |\r\n| **list_report_files.php** | PDFs in folder |\r\n| **report_file.php** | Access report file |\r\n| **pickups_today.php** | Today's pickups |\r\n| **ready.php** | Ready for pickup |\r\n| **overdue.php** | Overdue |\r\n| **settings_get.php** | Get settings |\r\n| **settings_save.php** | Save settings |\r\n| **settings_css.php** | Live CSS theme |\r\n| **imap_list.php** | List IMAP folders |\r\n| **imap_fetch.php** | Fetch emails |\r\n| **imap_send.php** | Send email via IMAP |\r\n| **imap_action.php** | IMAP actions |\r\n| **sms_send_helper.php** | SMS sending helper |\r\n| **sms_webhook_receive.php** | Receive SMS webhooks |\r\n| **sms_inbox_api.php** | SMS inbox API |\r\n| **slideshow_list.php** | Slideshow images |\r\n| **slideshow_upload.php** | Upload slideshow |\r\n| **slideshow_delete.php** | Delete slideshow |\r\n| **users_list.php** | User management |\r\n| **report_list.php** | Report list |\r\n| **debug_filters.php** | Debug filters |\r\n| **sysadmin.php** | System admin |\r\n| **test.php** | Testing endpoint |\r\n\r\n### 4.3 Backend API (C:\\code\\customerdb\\backend\\api\\)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **customer.php** | Get customer details |\r\n| **customers.php** | List/search customers |\r\n| **customer_save.php** | Save/update customer |\r\n| **visit.php** | Get visit details |\r\n| **visit_delete.php** | Delete visit |\r\n| **appointments.php** | Unified appointments |\r\n| **appointments_summary.php** | Appointment statistics |\r\n| **setmore_appointments.php** | Setmore appointments |\r\n| **setmore_import.php** | Import from Setmore |\r\n| **module_*.php** | Module loaders |\r\n| **alteration_items.php** | Alteration management |\r\n| **alteration_items_summary.php** | Alteration statistics |\r\n| **gold_silver_*.php** | Gold/silver prices |\r\n| **bank_*.php** | Bank transactions |\r\n| **stocks_summary.php** | Stock data |\r\n| **medication_*.php** | Medication tracking |\r\n| **payroll_import.php** | Payroll import |\r\n| **car_maintenance_*.php** | Vehicle maintenance |\r\n| **duke_*.php** | Duke integration |\r\n| **reports_*.php** | Report generation |\r\n| **totals_import.php** | Customer totals import |\r\n| **documents.php** | Document management |\r\n| **document_upload.php** | File uploads |\r\n| **cust_email_*.php** | Email data |\r\n| **mail_*.php** | Email sending |\r\n| **reminders_create.php** | Create reminders |\r\n| **nightly_reports.php** | Nightly reports |\r\n| **morning_jobs.php** | Morning jobs |\r\n| **appointment_workflow.php** | Workflow management |\r\n| **sysadmin.php** | System admin |\r\n| **reporting_module.php** | Reporting |\r\n| **job_runs.php** | Job tracking |\r\n| **health.php** | Health check |\r\n| **overview.php** | Dashboard data |\r\n\r\n---\r\n\r\n## 5. External Integrations\r\n\r\n### 5.1 Square (Payment Processing)\r\n- **Purpose:** Point-of-sale payments, receipts, terminal management\r\n- **Features:**\r\n  - Square Terminal device pairing/management\r\n  - Payment processing with tips\r\n  - Customer payment logging\r\n  - Sandbox and live environments\r\n- **Tables:** `backend_square_terminal_code`, `backend_square_terminal_device`, `square_customer_log`\r\n\r\n### 5.2 Twilio (SMS)\r\n- **Purpose:** SMS notifications and reminders\r\n- **Features:**\r\n  - Send SMS to customers\r\n  - Appointment reminders\r\n  - SMS consent tracking\r\n- **Settings:** `twilio_sid`, `twilio_token`, `twilio_from`\r\n\r\n### 5.3 Setmore (Appointment Booking)\r\n- **Purpose:** Appointment synchronization\r\n- **Features:**\r\n  - Pull appointments from Setmore API\r\n  - Link to customers/visits\r\n- **Table:** `setmore_appointments`\r\n- **Settings:** `setmore_refresh_token`, `setmore_staff_key`\r\n\r\n### 5.4 EasyAppointments (Alternative Booking)\r\n- **Purpose:** Full appointment booking platform\r\n- **Location:** C:\\code\\customerdb\\schedule\\\r\n- **Features:**\r\n  - Customer/provider management\r\n  - Web-based booking widget\r\n  - REST API\r\n\r\n### 5.5 Telegram (Notifications)\r\n- **Purpose:** Bot-based notifications\r\n- **Features:**\r\n  - Send notifications to channels\r\n  - Visit alerts\r\n  - Cron job status\r\n- **Settings:** `telegram_bot_token`, `telegram_chat_id`\r\n\r\n### 5.6 Ollama (AI - Optional)\r\n- **Purpose:** Local AI for email generation\r\n- **Settings:** `ollama_url`, `ollama_default_model`\r\n\r\n---\r\n\r\n## 6. Scheduled Jobs / Cron\r\n\r\n### Configured Cron Jobs\r\n\r\n| Job Label | Schedule | Purpose |\r\n|----------|----------|---------|\r\n| **Next-Day Customer Emails** | `0 20 * * *` (8 PM) | Pickup reminder emails |\r\n| **Morning Import** | `0 6 * * *` (6 AM) | Morning data import |\r\n| **Morning Jobs** | `0 9 * * *` (9 AM) | Appointment sync, workflow |\r\n| **Nightly Reports** | `0 20 * * *` (8 PM) | Generate nightly summaries |\r\n| **Database Backup** | `0 2 * * *` (2 AM) | Full MariaDB backup |\r\n| **Daily Cleanup** | `0 4 * * *` (4 AM) | Temp files, old logs |\r\n| **Auto Delete** | `15 4 * * *` (4:15 AM) | Clean placeholder records |\r\n\r\n### Background Job Scripts (backend/jobs/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **run_morning_jobs.php** | Main morning job runner |\r\n| **smoke_morning_jobs.php** | Smoke test |\r\n| **send_nightly_reports.php** | Nightly report emailer |\r\n| **send_nextday_customer_emails.php** | Next-day reminders |\r\n| **delete_add_name_records.php** | Cleanup job |\r\n| **rebuild_customer_totals.php** | Rebuild totals |\r\n| **rebuild_daily_customer_totals.php** | Rebuild daily totals |\r\n| **rebuild_payment_ledger.php** | Rebuild payment ledger |\r\n| **import_customer_totals_csv.php** | CSV import |\r\n| **backfill_square_customer_log.php** | Square log backfill |\r\n| **run_cron_job.php** | Generic cron runner |\r\n\r\n---\r\n\r\n## 7. Web Applications\r\n\r\n### 7.1 Front Desk App (port 8895)\r\n\r\n| Page | Purpose |\r\n|------|---------|\r\n| **index.html** | Main dashboard, search, stats |\r\n| **customer.html** | Customer detail + visit history |\r\n| **visit.html** | Create/edit alteration order |\r\n| **customer_display.html** | Second monitor display |\r\n| **receipt.html** | Printable receipt |\r\n| **reports.html** | Order list by status |\r\n| **upcoming.html** | Next 7 days pickups |\r\n| **schedule.html** | Appointments calendar |\r\n| **login.html** | Login page |\r\n| **item_types.html** | Item type management |\r\n\r\n### 7.2 Management App (port 8894)\r\n\r\n| Page | Purpose |\r\n|------|---------|\r\n| **index.html** | Login page |\r\n| **webui.html** | Dashboard |\r\n| **customer.html** | Customer detail view |\r\n| **admin.html** | Reports browser |\r\n| **settings.html** | App settings editor |\r\n| **users.html** | User management |\r\n| **reports.html** | Order reports |\r\n\r\n---\r\n\r\n## 8. Settings & Configuration\r\n\r\n### app_settings Keys\r\n\r\n| Key | Purpose |\r\n|-----|---------|\r\n| theme_bg | Page background color |\r\n| theme_panel | Card/panel color |\r\n| theme_text | Text color |\r\n| theme_accent | Accent/button color |\r\n| theme_accent_deep | Darker accent |\r\n| theme_teal | Teal color |\r\n| theme_font | Font family |\r\n| smtp_host | Email server hostname |\r\n| smtp_port | Email server port |\r\n| smtp_secure | tls or ssl |\r\n| smtp_user | Email login |\r\n| smtp_pass | Email password |\r\n| smtp_from_email | From address |\r\n| smtp_from_name | From display name |\r\n| twilio_sid | Twilio Account SID |\r\n| twilio_token | Twilio Auth Token |\r\n| twilio_from | Twilio phone number |\r\n| imap_host | Incoming email server |\r\n| imap_port | IMAP port |\r\n| imap_ssl | SSL enable |\r\n| imap_user | IMAP login |\r\n| imap_pass | IMAP password |\r\n| square_token | Square API token |\r\n| square_location | Square location ID |\r\n| setmore_staff_key | Setmore API key |\r\n| setmore_refresh | Setmore refresh token |\r\n| require_report | PDF required |\r\n| require_signature | Signature required |\r\n| reports_base_path | Reports disk path |\r\n| reports_base_url | Reports URL |\r\n| ollama_url | Ollama AI URL |\r\n| ollama_default_model | Ollama model |\r\n| telegram_bot_token | Telegram bot token |\r\n| telegram_chat_id | Telegram chat ID |\r\n\r\n---\r\n\r\n## 9. Migration Notes\r\n\r\n### Access to MariaDB Workflow\r\n\r\n1. **Export source data from Access**\r\n   - Export ordinary tables to CSV\r\n   - Export attachment fields with VBA or DAO Recordset2 logic\r\n   - Keep original IDs during migration\r\n\r\n2. **Load into MariaDB staging**\r\n   - Use `LOAD DATA LOCAL INFILE` for CSV files\r\n   - Load signatures separately into `visit_signatures`\r\n\r\n3. **Normalize**\r\n   - `CustomerTable` → `customers`\r\n   - `CustomerVisits` → `visits`\r\n   - `AlterationItems` → `orders`, `order_items`, `order_item_type_links`\r\n   - `2024TaxPayments` → `tax_payments`\r\n   - `AlterationItemsChangeLog` → `change_log`\r\n\r\n4. **Signature BLOB path**\r\n   - Export Access attachment to temp file\r\n   - Convert BMP to PNG\r\n   - Insert PNG bytes into `visit_signatures.signature_image`\r\n\r\n5. **Validation**\r\n   - Compare source row counts vs target\r\n   - Compare distinct legacy IDs\r\n   - Compare sample signatures by SHA256\r\n\r\n---\r\n\r\n## 10. Scripts & Tools\r\n\r\n### PowerShell Scripts (scripts/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **import_legacy_totals_from_excel.ps1** | Import totals from Excel |\r\n| **sync_backend_mirror.ps1** | Sync backend mirror |\r\n| **check_backend_mirror.ps1** | Check mirror status |\r\n\r\n### Python Scripts (scripts/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **signature_blob_loader.py** | Load signature blobs |\r\n| **access_to_mariadb_parser.py** | Parse Access to MariaDB |\r\n| **import_access_v2.py** | Import Access v2 |\r\n| **import_csv_v2.py** | Import CSV v2 |\r\n\r\n### SQL Migrations (migrations/)\r\n\r\n| File | Purpose |\r\n|------|---------|\r\n| **20260407_add_conversion_job.sql** | Add conversion job table |\r\n| **20260411_order_items_item_type_name_no_fk.sql** | Order items no FK |\r\n| **20260416_blog_prompt_templates.sql** | Blog prompt templates |\r\n\r\n---\r\n\r\n## File Statistics\r\n\r\n- **Total PHP files:** 200+\r\n- **Total SQL files:** 100+\r\n- **Total HTML pages:** 20+\r\n- **Database tables:** 30+\r\n\r\n---\r\n\r\n*End of Documentation*","content_html":"<h1>Ella&#039;s Alterations - Comprehensive System Documentation</h1>\n<p><strong>Generated:</strong> April 17, 2026</p>\n<p><strong>Location:</strong> C:\\code\\customerdb</p>\n<p>---</p>\n<h2>Table of Contents</h2>\n<p>1. [System Overview](#1-system-overview)</p>\n<p>2. [Directory Structure](#2-directory-structure)</p>\n<p>3. [Database Schema](#3-database-schema)</p>\n<p>4. [API Endpoints](#4-api-endpoints)</p>\n<p>5. [External Integrations](#5-external-integrations)</p>\n<p>6. [Scheduled Jobs / Cron](#6-scheduled-jobs--cron)</p>\n<p>7. [Web Applications](#7-web-applications)</p>\n<p>8. [Settings &amp; Configuration](#8-settings--configuration)</p>\n<p>9. [Migration Notes](#9-migration-notes)</p>\n<p>10. [Scripts &amp; Tools](#10-scripts--tools)</p>\n<p>---</p>\n<h2>1. System Overview</h2>\n<h3>Purpose</h3>\n<p>Ella&#039;s Alterations is a comprehensive customer relationship management (CRM) andAlteration tracking system for a tailor shop. It manages customers, visits/alteration orders, appointments, payments, and provides integration with external services.</p>\n<h3>Server Information</h3>\n<ul>\n<li><strong>Primary Server:</strong> kefa@192.168.7.202</li>\n<li><strong>Mirror Drive:</strong> /mnt/drive2 (mirrors /mnt/drive1)</li>\n<li><strong>Database:</strong> MariaDB - database `ellas_alterations`, user `kefa_admin`</li>\n<li><strong>Web Server:</strong> Apache 2.4 with mod-php</li>\n<li><strong>PHP Version:</strong> 8.3</li>\n</ul>\n<h3>Three Web Applications</h3>\n<p>| App | Local URL | Public URL | Purpose |</p>\n<p>|-----|-----------|------------|---------|</p>\n<p>| Front Desk | http://192.168.7.202:8895 | https://ella.floridaalterations.com | Customer-facing operations |</p>\n<p>| Management | http://192.168.7.202:8894 | (LAN only) | Reports, admin, settings |</p>\n<p>| Scheduler | http://192.168.7.202:8897 | https://schedule.floridaalterations.com | Easy!Appointments booking |</p>\n<p>---</p>\n<h2>2. Directory Structure</h2>\n<p>```</p>\n<p>customerdb/</p>\n<p>├── backend/                    # Main PHP backend API and services</p>\n<p>│   ├── api/                    # REST API endpoints (~57 files)</p>\n<p>│   ├── bin/                    # Binary/executable scripts</p>\n<p>│   ├── backup/                # Backup versions of services</p>\n<p>│   └── jobs/                  # Background job scripts</p>\n<p>├── frontend/                   # Front Desk app (port 8895)</p>\n<p>│   ├── *.html                 # HTML pages</p>\n<p>│   ├── api/                   # PHP API endpoints</p>\n<p>│   └── reports/               # PDF reports (MMDDYYYY/filename.pdf)</p>\n<p>├── webui/                      # Management app (port 8894)</p>\n<p>│   ├── *.html                 # HTML pages</p>\n<p>│   ├── api/                  # PHP API endpoints</p>\n<p>│   ├── backend/               # Backend API copy</p>\n<p>│   └── email/                # Email templates</p>\n<p>├── schedule/                   # Easy!Appointments installation</p>\n<p>├── schema/                    # Database schema files</p>\n<p>├── migrations/               # SQL migrations</p>\n<p>├── scripts/                   # PowerShell/Python import scripts</p>\n<p>├── docs/                     # Documentation</p>\n<p>├── blog/                     # Blog system and reengineering</p>\n<p>├── csv/                      # CSV data files</p>\n<p>├── backups/                  # Backup archives</p>\n<p>├── Topaz/                    # Topaz signature pad configs</p>\n<p>├── webui/                    # Second web interface</p>\n<p>│   ├── api/</p>\n<p>│   ├── backend/</p>\n<p>│   └── frontend/</p>\n<p>├── notused/                  # Deprecated/unused files</p>\n<p>└── wordpress-plugin/          # WordPress integration</p>\n<p>```</p>\n<p>---</p>\n<h2>3. Database Schema</h2>\n<h3>Core Tables (from mariadb_core_schema.sql)</h3>\n<p>#### customers</p>\n<p>Main customer registry.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| customer_id | INT UNSIGNED PK | Auto-increment |</p>\n<p>| legacy_customer_id | INT NULL | Original Access DB ID |</p>\n<p>| created_at | DATETIME | Record creation time |</p>\n<p>| full_name | VARCHAR(200) | Customer full name |</p>\n<p>| phone | VARCHAR(30) | Formatted (XXX) XXX-XXXX |</p>\n<p>| email | VARCHAR(255) | Email address |</p>\n<p>| pickup_due_at | DATETIME | Next pickup date (synced from EA) |</p>\n<p>| description | TEXT | Description |</p>\n<p>| notes | TEXT | Internal notes |</p>\n<p>| is_new_customer | TINYINT(1) | 1 if flagged as new |</p>\n<p>#### visits</p>\n<p>One row per alteration job/order.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| visit_id | INT UNSIGNED PK | |</p>\n<p>| legacy_visit_id | INT NULL | Original Access DB ID |</p>\n<p>| customer_id | INT UNSIGNED FK | → customers |</p>\n<p>| visit_date | DATETIME | Drop-off date |</p>\n<p>| pickup_date | DATETIME | Expected pickup |</p>\n<p>| notes | TEXT | General visit notes |</p>\n<p>| customer_name_snapshot | VARCHAR(200) | |</p>\n<p>| phone_snapshot | VARCHAR(30) | |</p>\n<p>| email_snapshot | VARCHAR(255) | |</p>\n<p>| color | VARCHAR(100) | Garment color |</p>\n<p>| alterations_needed | TEXT | |</p>\n<p>| alterations_notes | TEXT | Detailed alteration instructions |</p>\n<p>| alterations_price | DECIMAL(10,2) | Manual price field |</p>\n<p>| total_alteration_price | DECIMAL(10,2) | Calculated from items |</p>\n<p>| expedited_fee | DECIMAL(10,2) | |</p>\n<p>| paid_date | DATETIME | When paid |</p>\n<p>| signature_text | TEXT | Text signature (legacy) |</p>\n<p>| signature_date | DATETIME | |</p>\n<p>| paid_flag | TINYINT(1) | 1 = paid |</p>\n<p>| source_key_value | VARCHAR(100) | |</p>\n<p>#### visit_signatures</p>\n<p>Full resolution signature images per visit.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| signature_id | BIGINT UNSIGNED PK | |</p>\n<p>| visit_id | INT UNIQUE | One signature per visit |</p>\n<p>| signature_date | DATETIME | |</p>\n<p>| image_format | VARCHAR(50) | Default &#039;image/png&#039; |</p>\n<p>| original_filename | VARCHAR(255) | |</p>\n<p>| original_extension | VARCHAR(20) | |</p>\n<p>| file_size_bytes | BIGINT | |</p>\n<p>| sha256_hash | CHAR(64) | Hash for verification |</p>\n<p>| signature_image | LONGBLOB | Raw PNG binary |</p>\n<p>| created_at | DATETIME | |</p>\n<p>#### item_types</p>\n<p>Master list of alteration types (e.g., Hem, Zipper, Taper).</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| item_type_id | INT UNSIGNED PK | |</p>\n<p>| type_name | VARCHAR(100) UNIQUE | Display name |</p>\n<p>#### orders</p>\n<p>Orders per visit.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| order_id | BIGINT UNSIGNED PK | |</p>\n<p>| visit_id | INT UNSIGNED FK | → visits |</p>\n<p>| customer_id | INT UNSIGNED FK | → customers |</p>\n<p>| created_at | DATETIME | |</p>\n<p>| no_tax | TINYINT(1) | Tax exempt |</p>\n<p>| picked_up | TINYINT(1) | |</p>\n<p>| source_table | VARCHAR(50) | |</p>\n<p>#### order_items</p>\n<p>Line items for each alteration within a visit.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| order_item_id | BIGINT UNSIGNED PK | |</p>\n<p>| order_id | BIGINT UNSIGNED FK | → orders |</p>\n<p>| legacy_alteration_id | INT NULL | |</p>\n<p>| item_type_id | INT FK | → item_types |</p>\n<p>| item_type_name | VARCHAR(100) | |</p>\n<p>| description | TEXT | |</p>\n<p>| quantity | INT | Default 1 |</p>\n<p>| unit_price | DECIMAL(10,2) | |</p>\n<p>| total_price | DECIMAL(10,2) | |</p>\n<p>| notes | TEXT | Per-item notes |</p>\n<p>| color | VARCHAR(100) | Garment color |</p>\n<p>| no_tax | TINYINT(1) | Tax exempt |</p>\n<p>| is_range_price | TINYINT(1) | |</p>\n<p>| range_price_label | VARCHAR(100) | |</p>\n<p>| paid_flag | TINYINT(1) | |</p>\n<p>| paid_type | VARCHAR(100) | |</p>\n<p>| picked_up | TINYINT(1) | |</p>\n<p>| created_at | DATETIME | |</p>\n<p>#### order_item_type_links</p>\n<p>Many-to-many links between order items and item types.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| order_item_type_link_id | BIGINT UNSIGNED PK | |</p>\n<p>| order_item_id | BIGINT UNSIGNED FK | → order_items |</p>\n<p>| item_type_id | INT UNSIGNED FK | → item_types |</p>\n<p>| slot_number | TINYINT UNSIGNED | |</p>\n<p>#### payments</p>\n<p>Payment records per order.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| payment_id | BIGINT UNSIGNED PK | |</p>\n<p>| order_id | BIGINT UNSIGNED FK | → orders |</p>\n<p>| payment_date | DATETIME | |</p>\n<p>| payment_type | VARCHAR(100) | |</p>\n<p>| payment_method | VARCHAR(100) | |</p>\n<p>| amount | DECIMAL(10,2) | |</p>\n<p>| notes | TEXT | |</p>\n<p>#### tax_payments</p>\n<p>Tax payment records.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| tax_payment_id | INT UNSIGNED PK | |</p>\n<p>| legacy_tax_payment_id | INT NULL | |</p>\n<p>| payment_date | DATETIME | |</p>\n<p>| payment_type | VARCHAR(100) | |</p>\n<p>| payment_method | VARCHAR(100) | |</p>\n<p>| amount | DECIMAL(10,2) | |</p>\n<p>| notes | TEXT | |</p>\n<p>| receipt_blob | LONGBLOB | |</p>\n<p>#### change_log</p>\n<p>Audit log for changes.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| log_id | BIGINT UNSIGNED PK | |</p>\n<p>| legacy_log_id | INT NULL | |</p>\n<p>| table_name | VARCHAR(100) | |</p>\n<p>| record_id | BIGINT | |</p>\n<p>| visit_id | INT | |</p>\n<p>| field_name | VARCHAR(100) | |</p>\n<p>| old_value | TEXT | |</p>\n<p>| new_value | TEXT | |</p>\n<p>| changed_at | DATETIME | |</p>\n<p>| changed_by | VARCHAR(100) | |</p>\n<p>#### ads</p>\n<p>Advertising/articles.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| ad_id | INT UNSIGNED PK | |</p>\n<p>| legacy_ad_id | INT NULL | |</p>\n<p>| article_text | TEXT | |</p>\n<p>| article_picture | LONGBLOB | |</p>\n<p>| site_submitted | VARCHAR(255) | |</p>\n<p>| views | INT | Default 0 |</p>\n<p>| date_posted | DATETIME | |</p>\n<p>#### staging_* tables</p>\n<p>Staging tables for data migration.</p>\n<p>| Table Name | Purpose |</p>\n<p>|------------|---------|</p>\n<p>| staging_customer_table_raw | Staging for legacy customer data |</p>\n<p>| staging_customer_visits_raw | Staging for legacy visits |</p>\n<p>| staging_alteration_items_raw | Staging for items |</p>\n<h3>Additional Backend Tables</h3>\n<p>| Table Name | Purpose |</p>\n<p>|------------|---------|</p>\n<p>| setmore_appointments | Synced from Setmore |</p>\n<p>| backend_conversion_job | Document conversion jobs |</p>\n<p>| backend_job_runs | Background job execution log |</p>\n<p>| customer_totals | Daily customer totals |</p>\n<p>| daily_customer_totals | Daily summary totals |</p>\n<p>| customer_payment_transactions | Payment ledger |</p>\n<p>| legacy_customer_totals_monthly | Monthly totals (legacy) |</p>\n<p>| legacy_customer_totals_irs_monthly | IRS monthly reports |</p>\n<p>| backend_appointment_workflow | Appointment state machine |</p>\n<p>| backend_no_show_log | No-show tracking |</p>\n<p>| backend_error_log | Error logging |</p>\n<p>| backend_change_log | Change audit log |</p>\n<p>| backend_document | Document storage |</p>\n<p>| backend_document_version | Document version history |</p>\n<p>| backend_speed_dial | Quick links |</p>\n<p>| backend_square_terminal_code | Square terminal pairing codes |</p>\n<p>| backend_square_terminal_device | Square device registry |</p>\n<p>| cron_job | Scheduled job definitions |</p>\n<p>| cron_job_run | Cron execution history |</p>\n<p>| app_settings | Global configuration |</p>\n<p>| app_users | Login accounts |</p>\n<p>| remember_tokens | &quot;Remember Me&quot; tokens |</p>\n<p>| customer_reports | PDF report index |</p>\n<p>---</p>\n<h2>4. API Endpoints</h2>\n<h3>4.1 Frontend API (port 8895 /api/)</h3>\n<p>| Endpoint File | Purpose |</p>\n<p>|---------------|---------|</p>\n<p>| <strong>customer_get.php</strong> | Get customer by ID |</p>\n<p>| <strong>customer_save.php</strong> | Create or update customer |</p>\n<p>| <strong>customer_detail.php</strong> | Customer + visits summary |</p>\n<p>| <strong>customer_delete.php</strong> | Delete customer |</p>\n<p>| <strong>customer_list_hide.php</strong> | Hide customer from list |</p>\n<p>| <strong>search_customers.php</strong> | Search by name/phone |</p>\n<p>| <strong>visit_get.php</strong> | Get visit + items |</p>\n<p>| <strong>visit_save.php</strong> | Create/update visit + items |</p>\n<p>| <strong>visit_delete.php</strong> | Delete visit |</p>\n<p>| <strong>visit_report_generate.php</strong> | Generate visit report |</p>\n<p>| <strong>item_types.php</strong> | List all alteration types |</p>\n<p>| <strong>item_type_add.php</strong> | Add new item type |</p>\n<p>| <strong>item_type_update.php</strong> | Update item type |</p>\n<p>| <strong>item_type_delete.php</strong> | Delete item type |</p>\n<p>| <strong>pickups_today.php</strong> | Orders due today |</p>\n<p>| <strong>ready.php</strong> | Orders ready for pickup |</p>\n<p>| <strong>overdue.php</strong> | Overdue orders |</p>\n<p>| <strong>upcoming.php</strong> | Orders due in next N days |</p>\n<p>| <strong>workload_7days.php</strong> | 7-day workload |</p>\n<p>| <strong>save_signature.php</strong> | Save canvas signature |</p>\n<p>| <strong>reports_list.php</strong> | Reports for customer |</p>\n<p>| <strong>attach_reports.php</strong> | Index all PDFs to DB |</p>\n<p>| <strong>save_signature.php</strong> | Save signature image |</p>\n<p>| <strong>today_appointments_list.php</strong> | Today&#039;s appointments |</p>\n<p>| <strong>settings_get.php</strong> | Get app settings |</p>\n<p>| <strong>settings_save.php</strong> | Save app settings |</p>\n<p>| <strong>settings_css.php</strong> | Live theme CSS |</p>\n<p>| <strong>send_email.php</strong> | Send email via SMTP |</p>\n<p>| <strong>send_sms.php</strong> | Send SMS via Twilio |</p>\n<p>| <strong>send_reminders.php</strong> | Send appointment reminders |</p>\n<p>| <strong>ea_appointments.php</strong> | EasyAppointments REST API |</p>\n<p>| <strong>ea_webhook.php</strong> | Receives EA webhook events |</p>\n<p>| <strong>setmore.php</strong> | Setmore API proxy |</p>\n<p>| <strong>setmore_to_ea_import.php</strong> | Import customers to EA |</p>\n<p>| <strong>square_config.php</strong> | Square public config |</p>\n<p>| <strong>square_process.php</strong> | Process Square payment |</p>\n<p>| <strong>square_customer_log.php</strong> | Customer Square log |</p>\n<p>| <strong>square_terminal.php</strong> | Square terminal |</p>\n<p>| <strong>login.php</strong> | Authenticate |</p>\n<p>| <strong>logout.php</strong> | Clear session |</p>\n<p>| <strong>session_check.php</strong> | Check if logged in |</p>\n<p>| <strong>auth.php</strong> | Session authentication |</p>\n<p>| <strong>config.php</strong> | App config constants |</p>\n<p>| <strong>db.php</strong> | Database connection |</p>\n<p>| <strong>log_error.php</strong> | Log client-side error |</p>\n<p>| <strong>todo_list.php</strong> | Todo list management |</p>\n<p>| <strong>send_telegram.php</strong> | Send Telegram messages |</p>\n<h3>4.2 Management API (port 8894 /api/)</h3>\n<p>| Endpoint File | Purpose |</p>\n<p>|---------------|---------|</p>\n<p>| <strong>login.php</strong> | Authenticate |</p>\n<p>| <strong>logout.php</strong> | Clear session |</p>\n<p>| <strong>session_check.php</strong> | Check if logged in |</p>\n<p>| <strong>customer_detail.php</strong> | Customer + visits |</p>\n<p>| <strong>search_customers.php</strong> | Search customers |</p>\n<p>| <strong>update_customer.php</strong> | Update customer |</p>\n<p>| <strong>users_list.php</strong> | List all users |</p>\n<p>| <strong>user_save.php</strong> | Create/update user |</p>\n<p>| <strong>list_report_dirs.php</strong> | Date folders |</p>\n<p>| <strong>list_report_files.php</strong> | PDFs in folder |</p>\n<p>| <strong>report_file.php</strong> | Access report file |</p>\n<p>| <strong>pickups_today.php</strong> | Today&#039;s pickups |</p>\n<p>| <strong>ready.php</strong> | Ready for pickup |</p>\n<p>| <strong>overdue.php</strong> | Overdue |</p>\n<p>| <strong>settings_get.php</strong> | Get settings |</p>\n<p>| <strong>settings_save.php</strong> | Save settings |</p>\n<p>| <strong>settings_css.php</strong> | Live CSS theme |</p>\n<p>| <strong>imap_list.php</strong> | List IMAP folders |</p>\n<p>| <strong>imap_fetch.php</strong> | Fetch emails |</p>\n<p>| <strong>imap_send.php</strong> | Send email via IMAP |</p>\n<p>| <strong>imap_action.php</strong> | IMAP actions |</p>\n<p>| <strong>sms_send_helper.php</strong> | SMS sending helper |</p>\n<p>| <strong>sms_webhook_receive.php</strong> | Receive SMS webhooks |</p>\n<p>| <strong>sms_inbox_api.php</strong> | SMS inbox API |</p>\n<p>| <strong>slideshow_list.php</strong> | Slideshow images |</p>\n<p>| <strong>slideshow_upload.php</strong> | Upload slideshow |</p>\n<p>| <strong>slideshow_delete.php</strong> | Delete slideshow |</p>\n<p>| <strong>users_list.php</strong> | User management |</p>\n<p>| <strong>report_list.php</strong> | Report list |</p>\n<p>| <strong>debug_filters.php</strong> | Debug filters |</p>\n<p>| <strong>sysadmin.php</strong> | System admin |</p>\n<p>| <strong>test.php</strong> | Testing endpoint |</p>\n<h3>4.3 Backend API (C:\\code\\customerdb\\backend\\api\\)</h3>\n<p>| Endpoint File | Purpose |</p>\n<p>|---------------|---------|</p>\n<p>| <strong>customer.php</strong> | Get customer details |</p>\n<p>| <strong>customers.php</strong> | List/search customers |</p>\n<p>| <strong>customer_save.php</strong> | Save/update customer |</p>\n<p>| <strong>visit.php</strong> | Get visit details |</p>\n<p>| <strong>visit_delete.php</strong> | Delete visit |</p>\n<p>| <strong>appointments.php</strong> | Unified appointments |</p>\n<p>| <strong>appointments_summary.php</strong> | Appointment statistics |</p>\n<p>| <strong>setmore_appointments.php</strong> | Setmore appointments |</p>\n<p>| <strong>setmore_import.php</strong> | Import from Setmore |</p>\n<p>| <strong>module_*.php</strong> | Module loaders |</p>\n<p>| <strong>alteration_items.php</strong> | Alteration management |</p>\n<p>| <strong>alteration_items_summary.php</strong> | Alteration statistics |</p>\n<p>| <strong>gold_silver_*.php</strong> | Gold/silver prices |</p>\n<p>| <strong>bank_*.php</strong> | Bank transactions |</p>\n<p>| <strong>stocks_summary.php</strong> | Stock data |</p>\n<p>| <strong>medication_*.php</strong> | Medication tracking |</p>\n<p>| <strong>payroll_import.php</strong> | Payroll import |</p>\n<p>| <strong>car_maintenance_*.php</strong> | Vehicle maintenance |</p>\n<p>| <strong>duke_*.php</strong> | Duke integration |</p>\n<p>| <strong>reports_*.php</strong> | Report generation |</p>\n<p>| <strong>totals_import.php</strong> | Customer totals import |</p>\n<p>| <strong>documents.php</strong> | Document management |</p>\n<p>| <strong>document_upload.php</strong> | File uploads |</p>\n<p>| <strong>cust_email_*.php</strong> | Email data |</p>\n<p>| <strong>mail_*.php</strong> | Email sending |</p>\n<p>| <strong>reminders_create.php</strong> | Create reminders |</p>\n<p>| <strong>nightly_reports.php</strong> | Nightly reports |</p>\n<p>| <strong>morning_jobs.php</strong> | Morning jobs |</p>\n<p>| <strong>appointment_workflow.php</strong> | Workflow management |</p>\n<p>| <strong>sysadmin.php</strong> | System admin |</p>\n<p>| <strong>reporting_module.php</strong> | Reporting |</p>\n<p>| <strong>job_runs.php</strong> | Job tracking |</p>\n<p>| <strong>health.php</strong> | Health check |</p>\n<p>| <strong>overview.php</strong> | Dashboard data |</p>\n<p>---</p>\n<h2>5. External Integrations</h2>\n<h3>5.1 Square (Payment Processing)</h3>\n<ul>\n<li><strong>Purpose:</strong> Point-of-sale payments, receipts, terminal management</li>\n<li><strong>Features:</strong></li>\n<li>Square Terminal device pairing/management</li>\n<li>Payment processing with tips</li>\n<li>Customer payment logging</li>\n<li>Sandbox and live environments</li>\n<li><strong>Tables:</strong> `backend_square_terminal_code`, `backend_square_terminal_device`, `square_customer_log`</li>\n</ul>\n<h3>5.2 Twilio (SMS)</h3>\n<ul>\n<li><strong>Purpose:</strong> SMS notifications and reminders</li>\n<li><strong>Features:</strong></li>\n<li>Send SMS to customers</li>\n<li>Appointment reminders</li>\n<li>SMS consent tracking</li>\n<li><strong>Settings:</strong> `twilio_sid`, `twilio_token`, `twilio_from`</li>\n</ul>\n<h3>5.3 Setmore (Appointment Booking)</h3>\n<ul>\n<li><strong>Purpose:</strong> Appointment synchronization</li>\n<li><strong>Features:</strong></li>\n<li>Pull appointments from Setmore API</li>\n<li>Link to customers/visits</li>\n<li><strong>Table:</strong> `setmore_appointments`</li>\n<li><strong>Settings:</strong> `setmore_refresh_token`, `setmore_staff_key`</li>\n</ul>\n<h3>5.4 EasyAppointments (Alternative Booking)</h3>\n<ul>\n<li><strong>Purpose:</strong> Full appointment booking platform</li>\n<li><strong>Location:</strong> C:\\code\\customerdb\\schedule\\</li>\n<li><strong>Features:</strong></li>\n<li>Customer/provider management</li>\n<li>Web-based booking widget</li>\n<li>REST API</li>\n</ul>\n<h3>5.5 Telegram (Notifications)</h3>\n<ul>\n<li><strong>Purpose:</strong> Bot-based notifications</li>\n<li><strong>Features:</strong></li>\n<li>Send notifications to channels</li>\n<li>Visit alerts</li>\n<li>Cron job status</li>\n<li><strong>Settings:</strong> `telegram_bot_token`, `telegram_chat_id`</li>\n</ul>\n<h3>5.6 Ollama (AI - Optional)</h3>\n<ul>\n<li><strong>Purpose:</strong> Local AI for email generation</li>\n<li><strong>Settings:</strong> `ollama_url`, `ollama_default_model`</li>\n</ul>\n<p>---</p>\n<h2>6. Scheduled Jobs / Cron</h2>\n<h3>Configured Cron Jobs</h3>\n<p>| Job Label | Schedule | Purpose |</p>\n<p>|----------|----------|---------|</p>\n<p>| <strong>Next-Day Customer Emails</strong> | `0 20 <em> </em> *` (8 PM) | Pickup reminder emails |</p>\n<p>| <strong>Morning Import</strong> | `0 6 <em> </em> *` (6 AM) | Morning data import |</p>\n<p>| <strong>Morning Jobs</strong> | `0 9 <em> </em> *` (9 AM) | Appointment sync, workflow |</p>\n<p>| <strong>Nightly Reports</strong> | `0 20 <em> </em> *` (8 PM) | Generate nightly summaries |</p>\n<p>| <strong>Database Backup</strong> | `0 2 <em> </em> *` (2 AM) | Full MariaDB backup |</p>\n<p>| <strong>Daily Cleanup</strong> | `0 4 <em> </em> *` (4 AM) | Temp files, old logs |</p>\n<p>| <strong>Auto Delete</strong> | `15 4 <em> </em> *` (4:15 AM) | Clean placeholder records |</p>\n<h3>Background Job Scripts (backend/jobs/)</h3>\n<p>| Script | Purpose |</p>\n<p>|--------|---------|</p>\n<p>| <strong>run_morning_jobs.php</strong> | Main morning job runner |</p>\n<p>| <strong>smoke_morning_jobs.php</strong> | Smoke test |</p>\n<p>| <strong>send_nightly_reports.php</strong> | Nightly report emailer |</p>\n<p>| <strong>send_nextday_customer_emails.php</strong> | Next-day reminders |</p>\n<p>| <strong>delete_add_name_records.php</strong> | Cleanup job |</p>\n<p>| <strong>rebuild_customer_totals.php</strong> | Rebuild totals |</p>\n<p>| <strong>rebuild_daily_customer_totals.php</strong> | Rebuild daily totals |</p>\n<p>| <strong>rebuild_payment_ledger.php</strong> | Rebuild payment ledger |</p>\n<p>| <strong>import_customer_totals_csv.php</strong> | CSV import |</p>\n<p>| <strong>backfill_square_customer_log.php</strong> | Square log backfill |</p>\n<p>| <strong>run_cron_job.php</strong> | Generic cron runner |</p>\n<p>---</p>\n<h2>7. Web Applications</h2>\n<h3>7.1 Front Desk App (port 8895)</h3>\n<p>| Page | Purpose |</p>\n<p>|------|---------|</p>\n<p>| <strong>index.html</strong> | Main dashboard, search, stats |</p>\n<p>| <strong>customer.html</strong> | Customer detail + visit history |</p>\n<p>| <strong>visit.html</strong> | Create/edit alteration order |</p>\n<p>| <strong>customer_display.html</strong> | Second monitor display |</p>\n<p>| <strong>receipt.html</strong> | Printable receipt |</p>\n<p>| <strong>reports.html</strong> | Order list by status |</p>\n<p>| <strong>upcoming.html</strong> | Next 7 days pickups |</p>\n<p>| <strong>schedule.html</strong> | Appointments calendar |</p>\n<p>| <strong>login.html</strong> | Login page |</p>\n<p>| <strong>item_types.html</strong> | Item type management |</p>\n<h3>7.2 Management App (port 8894)</h3>\n<p>| Page | Purpose |</p>\n<p>|------|---------|</p>\n<p>| <strong>index.html</strong> | Login page |</p>\n<p>| <strong>webui.html</strong> | Dashboard |</p>\n<p>| <strong>customer.html</strong> | Customer detail view |</p>\n<p>| <strong>admin.html</strong> | Reports browser |</p>\n<p>| <strong>settings.html</strong> | App settings editor |</p>\n<p>| <strong>users.html</strong> | User management |</p>\n<p>| <strong>reports.html</strong> | Order reports |</p>\n<p>---</p>\n<h2>8. Settings &amp; Configuration</h2>\n<h3>app_settings Keys</h3>\n<p>| Key | Purpose |</p>\n<p>|-----|---------|</p>\n<p>| theme_bg | Page background color |</p>\n<p>| theme_panel | Card/panel color |</p>\n<p>| theme_text | Text color |</p>\n<p>| theme_accent | Accent/button color |</p>\n<p>| theme_accent_deep | Darker accent |</p>\n<p>| theme_teal | Teal color |</p>\n<p>| theme_font | Font family |</p>\n<p>| smtp_host | Email server hostname |</p>\n<p>| smtp_port | Email server port |</p>\n<p>| smtp_secure | tls or ssl |</p>\n<p>| smtp_user | Email login |</p>\n<p>| smtp_pass | Email password |</p>\n<p>| smtp_from_email | From address |</p>\n<p>| smtp_from_name | From display name |</p>\n<p>| twilio_sid | Twilio Account SID |</p>\n<p>| twilio_token | Twilio Auth Token |</p>\n<p>| twilio_from | Twilio phone number |</p>\n<p>| imap_host | Incoming email server |</p>\n<p>| imap_port | IMAP port |</p>\n<p>| imap_ssl | SSL enable |</p>\n<p>| imap_user | IMAP login |</p>\n<p>| imap_pass | IMAP password |</p>\n<p>| square_token | Square API token |</p>\n<p>| square_location | Square location ID |</p>\n<p>| setmore_staff_key | Setmore API key |</p>\n<p>| setmore_refresh | Setmore refresh token |</p>\n<p>| require_report | PDF required |</p>\n<p>| require_signature | Signature required |</p>\n<p>| reports_base_path | Reports disk path |</p>\n<p>| reports_base_url | Reports URL |</p>\n<p>| ollama_url | Ollama AI URL |</p>\n<p>| ollama_default_model | Ollama model |</p>\n<p>| telegram_bot_token | Telegram bot token |</p>\n<p>| telegram_chat_id | Telegram chat ID |</p>\n<p>---</p>\n<h2>9. Migration Notes</h2>\n<h3>Access to MariaDB Workflow</h3>\n<p>1. <strong>Export source data from Access</strong></p>\n<ul>\n<li>Export ordinary tables to CSV</li>\n<li>Export attachment fields with VBA or DAO Recordset2 logic</li>\n<li>Keep original IDs during migration</li>\n</ul>\n<p>2. <strong>Load into MariaDB staging</strong></p>\n<ul>\n<li>Use `LOAD DATA LOCAL INFILE` for CSV files</li>\n<li>Load signatures separately into `visit_signatures`</li>\n</ul>\n<p>3. <strong>Normalize</strong></p>\n<ul>\n<li>`CustomerTable` → `customers`</li>\n<li>`CustomerVisits` → `visits`</li>\n<li>`AlterationItems` → `orders`, `order_items`, `order_item_type_links`</li>\n<li>`2024TaxPayments` → `tax_payments`</li>\n<li>`AlterationItemsChangeLog` → `change_log`</li>\n</ul>\n<p>4. <strong>Signature BLOB path</strong></p>\n<ul>\n<li>Export Access attachment to temp file</li>\n<li>Convert BMP to PNG</li>\n<li>Insert PNG bytes into `visit_signatures.signature_image`</li>\n</ul>\n<p>5. <strong>Validation</strong></p>\n<ul>\n<li>Compare source row counts vs target</li>\n<li>Compare distinct legacy IDs</li>\n<li>Compare sample signatures by SHA256</li>\n</ul>\n<p>---</p>\n<h2>10. Scripts &amp; Tools</h2>\n<h3>PowerShell Scripts (scripts/)</h3>\n<p>| Script | Purpose |</p>\n<p>|--------|---------|</p>\n<p>| <strong>import_legacy_totals_from_excel.ps1</strong> | Import totals from Excel |</p>\n<p>| <strong>sync_backend_mirror.ps1</strong> | Sync backend mirror |</p>\n<p>| <strong>check_backend_mirror.ps1</strong> | Check mirror status |</p>\n<h3>Python Scripts (scripts/)</h3>\n<p>| Script | Purpose |</p>\n<p>|--------|---------|</p>\n<p>| <strong>signature_blob_loader.py</strong> | Load signature blobs |</p>\n<p>| <strong>access_to_mariadb_parser.py</strong> | Parse Access to MariaDB |</p>\n<p>| <strong>import_access_v2.py</strong> | Import Access v2 |</p>\n<p>| <strong>import_csv_v2.py</strong> | Import CSV v2 |</p>\n<h3>SQL Migrations (migrations/)</h3>\n<p>| File | Purpose |</p>\n<p>|------|---------|</p>\n<p>| <strong>20260407_add_conversion_job.sql</strong> | Add conversion job table |</p>\n<p>| <strong>20260411_order_items_item_type_name_no_fk.sql</strong> | Order items no FK |</p>\n<p>| <strong>20260416_blog_prompt_templates.sql</strong> | Blog prompt templates |</p>\n<p>---</p>\n<h2>File Statistics</h2>\n<ul>\n<li><strong>Total PHP files:</strong> 200+</li>\n<li><strong>Total SQL files:</strong> 100+</li>\n<li><strong>Total HTML pages:</strong> 20+</li>\n<li><strong>Database tables:</strong> 30+</li>\n</ul>\n<p>---</p>\n<p><em>End of Documentation</em></p>","file_name":"COMPREHENSIVE_DOCUMENTATION.md","stored_name":"20260417-160828-6006d4f1.md","mime_type":"application/octet-stream","file_size_bytes":"22313","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260417-160828-6006d4f1.md","is_deleted":"0","created_at":"2026-04-17 12:08:29","updated_at":"2026-04-17 12:08:52","editor_content":"# Ella's Alterations - Comprehensive System Documentation\r\n\r\n**Generated:** April 17, 2026\r\n**Location:** C:\\code\\customerdb\r\n\r\n---\r\n\r\n## Table of Contents\r\n\r\n1. [System Overview](#1-system-overview)\r\n2. [Directory Structure](#2-directory-structure)\r\n3. [Database Schema](#3-database-schema)\r\n4. [API Endpoints](#4-api-endpoints)\r\n5. [External Integrations](#5-external-integrations)\r\n6. [Scheduled Jobs / Cron](#6-scheduled-jobs--cron)\r\n7. [Web Applications](#7-web-applications)\r\n8. [Settings & Configuration](#8-settings--configuration)\r\n9. [Migration Notes](#9-migration-notes)\r\n10. [Scripts & Tools](#10-scripts--tools)\r\n\r\n---\r\n\r\n## 1. System Overview\r\n\r\n### Purpose\r\nElla's Alterations is a comprehensive customer relationship management (CRM) andAlteration tracking system for a tailor shop. It manages customers, visits/alteration orders, appointments, payments, and provides integration with external services.\r\n\r\n### Server Information\r\n- **Primary Server:** kefa@192.168.7.202\r\n- **Mirror Drive:** /mnt/drive2 (mirrors /mnt/drive1)\r\n- **Database:** MariaDB - database `ellas_alterations`, user `kefa_admin`\r\n- **Web Server:** Apache 2.4 with mod-php\r\n- **PHP Version:** 8.3\r\n\r\n### Three Web Applications\r\n\r\n| App | Local URL | Public URL | Purpose |\r\n|-----|-----------|------------|---------|\r\n| Front Desk | http://192.168.7.202:8895 | https://ella.floridaalterations.com | Customer-facing operations |\r\n| Management | http://192.168.7.202:8894 | (LAN only) | Reports, admin, settings |\r\n| Scheduler | http://192.168.7.202:8897 | https://schedule.floridaalterations.com | Easy!Appointments booking |\r\n\r\n---\r\n\r\n## 2. Directory Structure\r\n\r\n```\r\ncustomerdb/\r\n├── backend/                    # Main PHP backend API and services\r\n│   ├── api/                    # REST API endpoints (~57 files)\r\n│   ├── bin/                    # Binary/executable scripts\r\n│   ├── backup/                # Backup versions of services\r\n│   └── jobs/                  # Background job scripts\r\n├── frontend/                   # Front Desk app (port 8895)\r\n│   ├── *.html                 # HTML pages\r\n│   ├── api/                   # PHP API endpoints\r\n│   └── reports/               # PDF reports (MMDDYYYY/filename.pdf)\r\n├── webui/                      # Management app (port 8894)\r\n│   ├── *.html                 # HTML pages\r\n│   ├── api/                  # PHP API endpoints\r\n│   ├── backend/               # Backend API copy\r\n│   └── email/                # Email templates\r\n├── schedule/                   # Easy!Appointments installation\r\n├── schema/                    # Database schema files\r\n├── migrations/               # SQL migrations\r\n├── scripts/                   # PowerShell/Python import scripts\r\n├── docs/                     # Documentation\r\n├── blog/                     # Blog system and reengineering\r\n├── csv/                      # CSV data files\r\n├── backups/                  # Backup archives\r\n├── Topaz/                    # Topaz signature pad configs\r\n├── webui/                    # Second web interface\r\n│   ├── api/\r\n│   ├── backend/\r\n│   └── frontend/\r\n├── notused/                  # Deprecated/unused files\r\n└── wordpress-plugin/          # WordPress integration\r\n```\r\n\r\n---\r\n\r\n## 3. Database Schema\r\n\r\n### Core Tables (from mariadb_core_schema.sql)\r\n\r\n#### customers\r\nMain customer registry.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| customer_id | INT UNSIGNED PK | Auto-increment |\r\n| legacy_customer_id | INT NULL | Original Access DB ID |\r\n| created_at | DATETIME | Record creation time |\r\n| full_name | VARCHAR(200) | Customer full name |\r\n| phone | VARCHAR(30) | Formatted (XXX) XXX-XXXX |\r\n| email | VARCHAR(255) | Email address |\r\n| pickup_due_at | DATETIME | Next pickup date (synced from EA) |\r\n| description | TEXT | Description |\r\n| notes | TEXT | Internal notes |\r\n| is_new_customer | TINYINT(1) | 1 if flagged as new |\r\n\r\n#### visits\r\nOne row per alteration job/order.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| visit_id | INT UNSIGNED PK | |\r\n| legacy_visit_id | INT NULL | Original Access DB ID |\r\n| customer_id | INT UNSIGNED FK | → customers |\r\n| visit_date | DATETIME | Drop-off date |\r\n| pickup_date | DATETIME | Expected pickup |\r\n| notes | TEXT | General visit notes |\r\n| customer_name_snapshot | VARCHAR(200) | |\r\n| phone_snapshot | VARCHAR(30) | |\r\n| email_snapshot | VARCHAR(255) | |\r\n| color | VARCHAR(100) | Garment color |\r\n| alterations_needed | TEXT | |\r\n| alterations_notes | TEXT | Detailed alteration instructions |\r\n| alterations_price | DECIMAL(10,2) | Manual price field |\r\n| total_alteration_price | DECIMAL(10,2) | Calculated from items |\r\n| expedited_fee | DECIMAL(10,2) | |\r\n| paid_date | DATETIME | When paid |\r\n| signature_text | TEXT | Text signature (legacy) |\r\n| signature_date | DATETIME | |\r\n| paid_flag | TINYINT(1) | 1 = paid |\r\n| source_key_value | VARCHAR(100) | |\r\n\r\n#### visit_signatures\r\nFull resolution signature images per visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| signature_id | BIGINT UNSIGNED PK | |\r\n| visit_id | INT UNIQUE | One signature per visit |\r\n| signature_date | DATETIME | |\r\n| image_format | VARCHAR(50) | Default 'image/png' |\r\n| original_filename | VARCHAR(255) | |\r\n| original_extension | VARCHAR(20) | |\r\n| file_size_bytes | BIGINT | |\r\n| sha256_hash | CHAR(64) | Hash for verification |\r\n| signature_image | LONGBLOB | Raw PNG binary |\r\n| created_at | DATETIME | |\r\n\r\n#### item_types\r\nMaster list of alteration types (e.g., Hem, Zipper, Taper).\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| item_type_id | INT UNSIGNED PK | |\r\n| type_name | VARCHAR(100) UNIQUE | Display name |\r\n\r\n#### orders\r\nOrders per visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_id | BIGINT UNSIGNED PK | |\r\n| visit_id | INT UNSIGNED FK | → visits |\r\n| customer_id | INT UNSIGNED FK | → customers |\r\n| created_at | DATETIME | |\r\n| no_tax | TINYINT(1) | Tax exempt |\r\n| picked_up | TINYINT(1) | |\r\n| source_table | VARCHAR(50) | |\r\n\r\n#### order_items\r\nLine items for each alteration within a visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_item_id | BIGINT UNSIGNED PK | |\r\n| order_id | BIGINT UNSIGNED FK | → orders |\r\n| legacy_alteration_id | INT NULL | |\r\n| item_type_id | INT FK | → item_types |\r\n| item_type_name | VARCHAR(100) | |\r\n| description | TEXT | |\r\n| quantity | INT | Default 1 |\r\n| unit_price | DECIMAL(10,2) | |\r\n| total_price | DECIMAL(10,2) | |\r\n| notes | TEXT | Per-item notes |\r\n| color | VARCHAR(100) | Garment color |\r\n| no_tax | TINYINT(1) | Tax exempt |\r\n| is_range_price | TINYINT(1) | |\r\n| range_price_label | VARCHAR(100) | |\r\n| paid_flag | TINYINT(1) | |\r\n| paid_type | VARCHAR(100) | |\r\n| picked_up | TINYINT(1) | |\r\n| created_at | DATETIME | |\r\n\r\n#### order_item_type_links\r\nMany-to-many links between order items and item types.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_item_type_link_id | BIGINT UNSIGNED PK | |\r\n| order_item_id | BIGINT UNSIGNED FK | → order_items |\r\n| item_type_id | INT UNSIGNED FK | → item_types |\r\n| slot_number | TINYINT UNSIGNED | |\r\n\r\n#### payments\r\nPayment records per order.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| payment_id | BIGINT UNSIGNED PK | |\r\n| order_id | BIGINT UNSIGNED FK | → orders |\r\n| payment_date | DATETIME | |\r\n| payment_type | VARCHAR(100) | |\r\n| payment_method | VARCHAR(100) | |\r\n| amount | DECIMAL(10,2) | |\r\n| notes | TEXT | |\r\n\r\n#### tax_payments\r\nTax payment records.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| tax_payment_id | INT UNSIGNED PK | |\r\n| legacy_tax_payment_id | INT NULL | |\r\n| payment_date | DATETIME | |\r\n| payment_type | VARCHAR(100) | |\r\n| payment_method | VARCHAR(100) | |\r\n| amount | DECIMAL(10,2) | |\r\n| notes | TEXT | |\r\n| receipt_blob | LONGBLOB | |\r\n\r\n#### change_log\r\nAudit log for changes.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| log_id | BIGINT UNSIGNED PK | |\r\n| legacy_log_id | INT NULL | |\r\n| table_name | VARCHAR(100) | |\r\n| record_id | BIGINT | |\r\n| visit_id | INT | |\r\n| field_name | VARCHAR(100) | |\r\n| old_value | TEXT | |\r\n| new_value | TEXT | |\r\n| changed_at | DATETIME | |\r\n| changed_by | VARCHAR(100) | |\r\n\r\n#### ads\r\nAdvertising/articles.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| ad_id | INT UNSIGNED PK | |\r\n| legacy_ad_id | INT NULL | |\r\n| article_text | TEXT | |\r\n| article_picture | LONGBLOB | |\r\n| site_submitted | VARCHAR(255) | |\r\n| views | INT | Default 0 |\r\n| date_posted | DATETIME | |\r\n\r\n#### staging_* tables\r\nStaging tables for data migration.\r\n\r\n| Table Name | Purpose |\r\n|------------|---------|\r\n| staging_customer_table_raw | Staging for legacy customer data |\r\n| staging_customer_visits_raw | Staging for legacy visits |\r\n| staging_alteration_items_raw | Staging for items |\r\n\r\n### Additional Backend Tables\r\n\r\n| Table Name | Purpose |\r\n|------------|---------|\r\n| setmore_appointments | Synced from Setmore |\r\n| backend_conversion_job | Document conversion jobs |\r\n| backend_job_runs | Background job execution log |\r\n| customer_totals | Daily customer totals |\r\n| daily_customer_totals | Daily summary totals |\r\n| customer_payment_transactions | Payment ledger |\r\n| legacy_customer_totals_monthly | Monthly totals (legacy) |\r\n| legacy_customer_totals_irs_monthly | IRS monthly reports |\r\n| backend_appointment_workflow | Appointment state machine |\r\n| backend_no_show_log | No-show tracking |\r\n| backend_error_log | Error logging |\r\n| backend_change_log | Change audit log |\r\n| backend_document | Document storage |\r\n| backend_document_version | Document version history |\r\n| backend_speed_dial | Quick links |\r\n| backend_square_terminal_code | Square terminal pairing codes |\r\n| backend_square_terminal_device | Square device registry |\r\n| cron_job | Scheduled job definitions |\r\n| cron_job_run | Cron execution history |\r\n| app_settings | Global configuration |\r\n| app_users | Login accounts |\r\n| remember_tokens | \"Remember Me\" tokens |\r\n| customer_reports | PDF report index |\r\n\r\n---\r\n\r\n## 4. API Endpoints\r\n\r\n### 4.1 Frontend API (port 8895 /api/)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **customer_get.php** | Get customer by ID |\r\n| **customer_save.php** | Create or update customer |\r\n| **customer_detail.php** | Customer + visits summary |\r\n| **customer_delete.php** | Delete customer |\r\n| **customer_list_hide.php** | Hide customer from list |\r\n| **search_customers.php** | Search by name/phone |\r\n| **visit_get.php** | Get visit + items |\r\n| **visit_save.php** | Create/update visit + items |\r\n| **visit_delete.php** | Delete visit |\r\n| **visit_report_generate.php** | Generate visit report |\r\n| **item_types.php** | List all alteration types |\r\n| **item_type_add.php** | Add new item type |\r\n| **item_type_update.php** | Update item type |\r\n| **item_type_delete.php** | Delete item type |\r\n| **pickups_today.php** | Orders due today |\r\n| **ready.php** | Orders ready for pickup |\r\n| **overdue.php** | Overdue orders |\r\n| **upcoming.php** | Orders due in next N days |\r\n| **workload_7days.php** | 7-day workload |\r\n| **save_signature.php** | Save canvas signature |\r\n| **reports_list.php** | Reports for customer |\r\n| **attach_reports.php** | Index all PDFs to DB |\r\n| **save_signature.php** | Save signature image |\r\n| **today_appointments_list.php** | Today's appointments |\r\n| **settings_get.php** | Get app settings |\r\n| **settings_save.php** | Save app settings |\r\n| **settings_css.php** | Live theme CSS |\r\n| **send_email.php** | Send email via SMTP |\r\n| **send_sms.php** | Send SMS via Twilio |\r\n| **send_reminders.php** | Send appointment reminders |\r\n| **ea_appointments.php** | EasyAppointments REST API |\r\n| **ea_webhook.php** | Receives EA webhook events |\r\n| **setmore.php** | Setmore API proxy |\r\n| **setmore_to_ea_import.php** | Import customers to EA |\r\n| **square_config.php** | Square public config |\r\n| **square_process.php** | Process Square payment |\r\n| **square_customer_log.php** | Customer Square log |\r\n| **square_terminal.php** | Square terminal |\r\n| **login.php** | Authenticate |\r\n| **logout.php** | Clear session |\r\n| **session_check.php** | Check if logged in |\r\n| **auth.php** | Session authentication |\r\n| **config.php** | App config constants |\r\n| **db.php** | Database connection |\r\n| **log_error.php** | Log client-side error |\r\n| **todo_list.php** | Todo list management |\r\n| **send_telegram.php** | Send Telegram messages |\r\n\r\n### 4.2 Management API (port 8894 /api/)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **login.php** | Authenticate |\r\n| **logout.php** | Clear session |\r\n| **session_check.php** | Check if logged in |\r\n| **customer_detail.php** | Customer + visits |\r\n| **search_customers.php** | Search customers |\r\n| **update_customer.php** | Update customer |\r\n| **users_list.php** | List all users |\r\n| **user_save.php** | Create/update user |\r\n| **list_report_dirs.php** | Date folders |\r\n| **list_report_files.php** | PDFs in folder |\r\n| **report_file.php** | Access report file |\r\n| **pickups_today.php** | Today's pickups |\r\n| **ready.php** | Ready for pickup |\r\n| **overdue.php** | Overdue |\r\n| **settings_get.php** | Get settings |\r\n| **settings_save.php** | Save settings |\r\n| **settings_css.php** | Live CSS theme |\r\n| **imap_list.php** | List IMAP folders |\r\n| **imap_fetch.php** | Fetch emails |\r\n| **imap_send.php** | Send email via IMAP |\r\n| **imap_action.php** | IMAP actions |\r\n| **sms_send_helper.php** | SMS sending helper |\r\n| **sms_webhook_receive.php** | Receive SMS webhooks |\r\n| **sms_inbox_api.php** | SMS inbox API |\r\n| **slideshow_list.php** | Slideshow images |\r\n| **slideshow_upload.php** | Upload slideshow |\r\n| **slideshow_delete.php** | Delete slideshow |\r\n| **users_list.php** | User management |\r\n| **report_list.php** | Report list |\r\n| **debug_filters.php** | Debug filters |\r\n| **sysadmin.php** | System admin |\r\n| **test.php** | Testing endpoint |\r\n\r\n### 4.3 Backend API (C:\\code\\customerdb\\backend\\api\\)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **customer.php** | Get customer details |\r\n| **customers.php** | List/search customers |\r\n| **customer_save.php** | Save/update customer |\r\n| **visit.php** | Get visit details |\r\n| **visit_delete.php** | Delete visit |\r\n| **appointments.php** | Unified appointments |\r\n| **appointments_summary.php** | Appointment statistics |\r\n| **setmore_appointments.php** | Setmore appointments |\r\n| **setmore_import.php** | Import from Setmore |\r\n| **module_*.php** | Module loaders |\r\n| **alteration_items.php** | Alteration management |\r\n| **alteration_items_summary.php** | Alteration statistics |\r\n| **gold_silver_*.php** | Gold/silver prices |\r\n| **bank_*.php** | Bank transactions |\r\n| **stocks_summary.php** | Stock data |\r\n| **medication_*.php** | Medication tracking |\r\n| **payroll_import.php** | Payroll import |\r\n| **car_maintenance_*.php** | Vehicle maintenance |\r\n| **duke_*.php** | Duke integration |\r\n| **reports_*.php** | Report generation |\r\n| **totals_import.php** | Customer totals import |\r\n| **documents.php** | Document management |\r\n| **document_upload.php** | File uploads |\r\n| **cust_email_*.php** | Email data |\r\n| **mail_*.php** | Email sending |\r\n| **reminders_create.php** | Create reminders |\r\n| **nightly_reports.php** | Nightly reports |\r\n| **morning_jobs.php** | Morning jobs |\r\n| **appointment_workflow.php** | Workflow management |\r\n| **sysadmin.php** | System admin |\r\n| **reporting_module.php** | Reporting |\r\n| **job_runs.php** | Job tracking |\r\n| **health.php** | Health check |\r\n| **overview.php** | Dashboard data |\r\n\r\n---\r\n\r\n## 5. External Integrations\r\n\r\n### 5.1 Square (Payment Processing)\r\n- **Purpose:** Point-of-sale payments, receipts, terminal management\r\n- **Features:**\r\n  - Square Terminal device pairing/management\r\n  - Payment processing with tips\r\n  - Customer payment logging\r\n  - Sandbox and live environments\r\n- **Tables:** `backend_square_terminal_code`, `backend_square_terminal_device`, `square_customer_log`\r\n\r\n### 5.2 Twilio (SMS)\r\n- **Purpose:** SMS notifications and reminders\r\n- **Features:**\r\n  - Send SMS to customers\r\n  - Appointment reminders\r\n  - SMS consent tracking\r\n- **Settings:** `twilio_sid`, `twilio_token`, `twilio_from`\r\n\r\n### 5.3 Setmore (Appointment Booking)\r\n- **Purpose:** Appointment synchronization\r\n- **Features:**\r\n  - Pull appointments from Setmore API\r\n  - Link to customers/visits\r\n- **Table:** `setmore_appointments`\r\n- **Settings:** `setmore_refresh_token`, `setmore_staff_key`\r\n\r\n### 5.4 EasyAppointments (Alternative Booking)\r\n- **Purpose:** Full appointment booking platform\r\n- **Location:** C:\\code\\customerdb\\schedule\\\r\n- **Features:**\r\n  - Customer/provider management\r\n  - Web-based booking widget\r\n  - REST API\r\n\r\n### 5.5 Telegram (Notifications)\r\n- **Purpose:** Bot-based notifications\r\n- **Features:**\r\n  - Send notifications to channels\r\n  - Visit alerts\r\n  - Cron job status\r\n- **Settings:** `telegram_bot_token`, `telegram_chat_id`\r\n\r\n### 5.6 Ollama (AI - Optional)\r\n- **Purpose:** Local AI for email generation\r\n- **Settings:** `ollama_url`, `ollama_default_model`\r\n\r\n---\r\n\r\n## 6. Scheduled Jobs / Cron\r\n\r\n### Configured Cron Jobs\r\n\r\n| Job Label | Schedule | Purpose |\r\n|----------|----------|---------|\r\n| **Next-Day Customer Emails** | `0 20 * * *` (8 PM) | Pickup reminder emails |\r\n| **Morning Import** | `0 6 * * *` (6 AM) | Morning data import |\r\n| **Morning Jobs** | `0 9 * * *` (9 AM) | Appointment sync, workflow |\r\n| **Nightly Reports** | `0 20 * * *` (8 PM) | Generate nightly summaries |\r\n| **Database Backup** | `0 2 * * *` (2 AM) | Full MariaDB backup |\r\n| **Daily Cleanup** | `0 4 * * *` (4 AM) | Temp files, old logs |\r\n| **Auto Delete** | `15 4 * * *` (4:15 AM) | Clean placeholder records |\r\n\r\n### Background Job Scripts (backend/jobs/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **run_morning_jobs.php** | Main morning job runner |\r\n| **smoke_morning_jobs.php** | Smoke test |\r\n| **send_nightly_reports.php** | Nightly report emailer |\r\n| **send_nextday_customer_emails.php** | Next-day reminders |\r\n| **delete_add_name_records.php** | Cleanup job |\r\n| **rebuild_customer_totals.php** | Rebuild totals |\r\n| **rebuild_daily_customer_totals.php** | Rebuild daily totals |\r\n| **rebuild_payment_ledger.php** | Rebuild payment ledger |\r\n| **import_customer_totals_csv.php** | CSV import |\r\n| **backfill_square_customer_log.php** | Square log backfill |\r\n| **run_cron_job.php** | Generic cron runner |\r\n\r\n---\r\n\r\n## 7. Web Applications\r\n\r\n### 7.1 Front Desk App (port 8895)\r\n\r\n| Page | Purpose |\r\n|------|---------|\r\n| **index.html** | Main dashboard, search, stats |\r\n| **customer.html** | Customer detail + visit history |\r\n| **visit.html** | Create/edit alteration order |\r\n| **customer_display.html** | Second monitor display |\r\n| **receipt.html** | Printable receipt |\r\n| **reports.html** | Order list by status |\r\n| **upcoming.html** | Next 7 days pickups |\r\n| **schedule.html** | Appointments calendar |\r\n| **login.html** | Login page |\r\n| **item_types.html** | Item type management |\r\n\r\n### 7.2 Management App (port 8894)\r\n\r\n| Page | Purpose |\r\n|------|---------|\r\n| **index.html** | Login page |\r\n| **webui.html** | Dashboard |\r\n| **customer.html** | Customer detail view |\r\n| **admin.html** | Reports browser |\r\n| **settings.html** | App settings editor |\r\n| **users.html** | User management |\r\n| **reports.html** | Order reports |\r\n\r\n---\r\n\r\n## 8. Settings & Configuration\r\n\r\n### app_settings Keys\r\n\r\n| Key | Purpose |\r\n|-----|---------|\r\n| theme_bg | Page background color |\r\n| theme_panel | Card/panel color |\r\n| theme_text | Text color |\r\n| theme_accent | Accent/button color |\r\n| theme_accent_deep | Darker accent |\r\n| theme_teal | Teal color |\r\n| theme_font | Font family |\r\n| smtp_host | Email server hostname |\r\n| smtp_port | Email server port |\r\n| smtp_secure | tls or ssl |\r\n| smtp_user | Email login |\r\n| smtp_pass | Email password |\r\n| smtp_from_email | From address |\r\n| smtp_from_name | From display name |\r\n| twilio_sid | Twilio Account SID |\r\n| twilio_token | Twilio Auth Token |\r\n| twilio_from | Twilio phone number |\r\n| imap_host | Incoming email server |\r\n| imap_port | IMAP port |\r\n| imap_ssl | SSL enable |\r\n| imap_user | IMAP login |\r\n| imap_pass | IMAP password |\r\n| square_token | Square API token |\r\n| square_location | Square location ID |\r\n| setmore_staff_key | Setmore API key |\r\n| setmore_refresh | Setmore refresh token |\r\n| require_report | PDF required |\r\n| require_signature | Signature required |\r\n| reports_base_path | Reports disk path |\r\n| reports_base_url | Reports URL |\r\n| ollama_url | Ollama AI URL |\r\n| ollama_default_model | Ollama model |\r\n| telegram_bot_token | Telegram bot token |\r\n| telegram_chat_id | Telegram chat ID |\r\n\r\n---\r\n\r\n## 9. Migration Notes\r\n\r\n### Access to MariaDB Workflow\r\n\r\n1. **Export source data from Access**\r\n   - Export ordinary tables to CSV\r\n   - Export attachment fields with VBA or DAO Recordset2 logic\r\n   - Keep original IDs during migration\r\n\r\n2. **Load into MariaDB staging**\r\n   - Use `LOAD DATA LOCAL INFILE` for CSV files\r\n   - Load signatures separately into `visit_signatures`\r\n\r\n3. **Normalize**\r\n   - `CustomerTable` → `customers`\r\n   - `CustomerVisits` → `visits`\r\n   - `AlterationItems` → `orders`, `order_items`, `order_item_type_links`\r\n   - `2024TaxPayments` → `tax_payments`\r\n   - `AlterationItemsChangeLog` → `change_log`\r\n\r\n4. **Signature BLOB path**\r\n   - Export Access attachment to temp file\r\n   - Convert BMP to PNG\r\n   - Insert PNG bytes into `visit_signatures.signature_image`\r\n\r\n5. **Validation**\r\n   - Compare source row counts vs target\r\n   - Compare distinct legacy IDs\r\n   - Compare sample signatures by SHA256\r\n\r\n---\r\n\r\n## 10. Scripts & Tools\r\n\r\n### PowerShell Scripts (scripts/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **import_legacy_totals_from_excel.ps1** | Import totals from Excel |\r\n| **sync_backend_mirror.ps1** | Sync backend mirror |\r\n| **check_backend_mirror.ps1** | Check mirror status |\r\n\r\n### Python Scripts (scripts/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **signature_blob_loader.py** | Load signature blobs |\r\n| **access_to_mariadb_parser.py** | Parse Access to MariaDB |\r\n| **import_access_v2.py** | Import Access v2 |\r\n| **import_csv_v2.py** | Import CSV v2 |\r\n\r\n### SQL Migrations (migrations/)\r\n\r\n| File | Purpose |\r\n|------|---------|\r\n| **20260407_add_conversion_job.sql** | Add conversion job table |\r\n| **20260411_order_items_item_type_name_no_fk.sql** | Order items no FK |\r\n| **20260416_blog_prompt_templates.sql** | Blog prompt templates |\r\n\r\n---\r\n\r\n## File Statistics\r\n\r\n- **Total PHP files:** 200+\r\n- **Total SQL files:** 100+\r\n- **Total HTML pages:** 20+\r\n- **Database tables:** 30+\r\n\r\n---\r\n\r\n*End of Documentation*","is_text_editable":1,"can_edit_inline":1}
After
{"backend_document_id":"20","document_type":"upload","title":"Speed Dial Contents","slug":"speed-dial-contents","summary_text":"Speed Dial Contents","content_markdown":"Here are the names and URLs extracted from the provided bookmarks list:\r\n\r\nGTE Mobile Banking: https://m.gtefcu.org/mobile/Default.aspx?ReturnUrl=%2fmobile%2fMember%2fAccounts%2fTransactionHistory.aspx%3fR6ldQ2Rt%252bjUGc0%252f3%252fhP9UxU2hEVocAsOAVJ4EPdcd9Hh0BsxuR0ilPHrPQzwSXJWzbVCFr3txWVrhtMn9YIzTE6DpzA4jgy3BwTNCXbCmuc%253d-YuyNrzQIfzg%253d&R6ldQ2Rt%2bjUGc0%2f3%2fhP9UxU2hEVocAsOAVJ4EPdcd9Hh0BsxuR0ilPHrPQzwSXJWzbVCFr3txWVrhtMn9YIzTE6DpzA4jgy3BwTNCXbCmuc%3d-YuyNrzQIfzg%3d\r\n\r\nView All Photos | 100 Easy Chicken Recipes | Cooking Light: http://www.cookinglight.com/food/quick-healthy/easy-chicken-recipes/view-all\r\n\r\nYahoo! Mail: https://m.mg.mail.yahoo.com/hg/?.intl=us\r\n\r\nWeather Station History | Weather Underground: http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=ITARLACC2\r\n\r\nAbout Shalom Sesame – Shalom Sesame: http://www.shalomsesame.org/about2.html\r\n\r\nAMAZING FACTS: http://www.amazingfacts.org/store/entity/tabid/267/entityname/category/categoryid/126/sename/character-studies/default.aspx\r\n\r\nAncient Hebrew Research Center - Home Page: http://www.ancient-hebrew.org/\r\n\r\nAnthem BlueCross BlueShield - Verizon Home: http://www.anthem.com/verizon/\r\n\r\nAtheist Central -- Ray Comfort's Blog: http://raycomfortfood.blogspot.com/\r\n\r\nAudio Lessons « Think Hebrew: http://thinkhebrew.wordpress.com/audio-lessons/\r\n\r\nBarnes & Noble.com - eBooks Search Orthodox Jewish bible: http://productsearch.barnesandnoble.com/search/results.aspx?store=EBOOK&WRD=Orthodox+Jewish+bible\r\n\r\nBeginning Hebrew Class Tim Hegg: http://www.torahresource.com/Hebrew.html\r\n\r\nBehind The Scenes- 5-9-11: http://www.livingwaters.com/index.php?option=com_k2&view=item&id=2753&Itemid=314&lang=en\r\n\r\nBeit Tehila Congregation - Shalom: http://www.topraise.net/pages/about-us/history.htm\r\n\r\nBeth Messiah Messianic Synagogue Sarasota, Florida USA Rabbi Judah Hungerman: http://www.bethmessiahfla.com/\r\n\r\nBible and Mishneh Torah for All - Jews and Gentiles - Mechon Mamre: http://www.mechon-mamre.org/\r\n\r\nbible passages: http://www.openbible.info/topics/eating_fish\r\n\r\nBible University: http://www.bibleuniversity.com/University/Welcome.asp\r\n\r\nBiblical Hebrew Blog - By eTeacherBiblical.com Learn Biblical Hebrew online: http://blog.eteacherbiblical.com/\r\n\r\nBiblical Hermeneutics BiblicalTraining.org: http://www.biblicaltraining.org/biblical-hermeneutics/robert-stein\r\n\r\nBiblicalDiscipleship.org: http://biblicaldiscipleship.org/\r\n\r\nBirth Issues Yeshua in Context: http://yeshuaincontext.com/2011/03/birth-issues/\r\n\r\nBlogEngine.NET: http://blogengine.codeplex.com/discussions?prog_id=register_cheap_domain_names_cheap_web_hosting&ProjectName=blogengine\r\n\r\nBukharin Yarmulke Pattern k2p2.net Blog: http://k2p2.net/blog2/2006/08/31/bukharin-yarmulke-pattern/\r\n\r\nBuy Jewish Gifts Online - Jewelry - Kippah - Mezuzah - Star of David - Kabbalah Red String Bracelets - Evil Eye Charm: http://www.yourholylandstore.com/\r\n\r\nChabad Jewish Holidays: http://www.chabad.org/library/article_cdo/aid/102698/jewish/Tevet-10.htm\r\n\r\nCHANUKAH ...History & Prophetic End Time Implications: http://www.graftedforlife.org/blogs/index.php/2010/12/03/chanukah-history-aamp-prophetic-end-time-implications?blog=9\r\n\r\nChofetz Chaim Laws of Speech Naaleh Torah Video Online: http://www.naaleh.com/search/class/148\r\n\r\nContact Us: http://www.chabadcountyline.com/index.php?option=com_facileforms&act=quickmode&task=edit&formName=ContactUs&Itemid=152\r\n\r\nCount Today's Omer - Sefirat HaOmer: http://www.chabad.org/holidays/sefirah/omer-count.asp?date=4/19/2011\r\n\r\nCredit Bureau Reporting: http://www.thelpa.com/lpa/credit-reporting.html\r\n\r\nDeuteronomy 1622 Bible Lexicon: http://biblelexicon.org/deuteronomy/16-22.htm\r\n\r\nDidache: http://www.earlychristianwritings.com/didache.html\r\n\r\ndirectoryBedini SG - PESWiki Tesla Generator: http://peswiki.com/energy/Directory:Bedini_SG\r\n\r\nDr. Janice Hughes, Clinical Social Work-Therapist, Cape Coral, FL 33914 Psychology Today's Therapy Directory: http://therapists.psychologytoday.com/rms/prof_detail.php?profid=73368&sid=1281461131.0405_1063&city=Fort+Myers&county=Lee&state=Florida&spec=166\r\n\r\nD'var Torah on the Parashah - Torah Portion of the Week: http://www.artscroll.com/parashah/current.html\r\n\r\nEarly Christian Writings New Testament, Apocrypha, Gnostics, Church Fathers: http://www.earlychristianwritings.com/index.html\r\n\r\nEarly Jewish Writings: http://www.earlyjewishwritings.com/\r\n\r\nEasiest Online Backup Service - Backblaze: http://www.backblaze.com/\r\n\r\nebay Seller Tools File Exchange: http://pages.ebay.com/file_exchange/\r\n\r\nEssays and Articles: http://therefinersfire.org/ea.htm\r\n\r\nEssenes, Essene Teachings and Essene Theology: http://www.thenazareneway.com/\r\n\r\nFilipino Audio Lessons: http://mylanguages.org/filipino_audio.php\r\n\r\nFirm Foundation Guitar Tabs, Chords & Lyrics by Jamie Harvill & Nancy Gordon: http://www.worshiparchive.com/song/firm-foundation\r\n\r\nFirst Fruits Core [Beta]: https://ffoz.org/members/member_cp/index.php\r\n\r\nFlorida Lotto: http://www.flalottery.com/inet/lottoMain.do\r\n\r\nFoundationStone - a free and easy way to learn Hebrew: http://foundationstone.com.au/FoundationStone.html?./OnlineHebrewTutorial.html\r\n\r\nFree Lessons Learn Biblical Hebrew with eTeacher: http://eteacherbiblical.com/free-lessons\r\n\r\nFree Online Hebrew Dictionary. Type in Hebrew-English. Translate Hebrew or Phonetic Hebrew.: http://www.doitinhebrew.com/Translate/default.aspx?kb=IL%20Hebrew%20Phonetic\r\n\r\nFront Page www.jewishpresstampa.com Jewish Press of Tampa: http://www.jewishpresstampa.com/\r\n\r\nG-DCAST: http://www.g-dcast.com/\r\n\r\nGoogle Translate: http://translate.google.com/#\r\n\r\nHanukkah - Chanukah 2010 - Menorah, Dreidels, Latkes, Recipes, Games and more: http://www.chabad.org/holidays/chanukah/default_cdo/jewish/Hanukkah.htm\r\n\r\nHebrew Lessons — Ten Commandments: http://www.levitt.com/hebrew/commandments.html\r\n\r\nHome Yarnell: http://www.yarnellschool.com/online/yarnell/index.html\r\n\r\nInformation Technology Students and Faculty: http://msdn01.e-academy.com/elms/Storefront/Home.aspx?campus=sfc_it\r\n\r\nIntroduction to Islam BiblicalTraining.org: http://www.biblicaltraining.org/introduction-islam/timothy-tennent\r\n\r\niTanakh: http://www.itanakh.org/\r\n\r\nJewish Community, Jewish Synagogue, Kosher Food, Makati, Philippines: http://jewishphilippines.net/newsletter.php#\r\n\r\nJewish Genealogy By Genetics - JewishGen: http://www.jewishgen.org/dna/genbygen.html\r\n\r\nJewish Roots Learning Center Haydid: http://www.haydid.org/\r\n\r\nJewish Studies Org: http://www.jewishstudies.org/\r\n\r\nJourney To Jerusalem Home Page: http://www.journeytojerusalem.com/\r\n\r\nJudaism and Jewish Resources - Andrew Tannenbaum: http://shamash.org/trb/judaism.html#learning\r\n\r\nJVIMS Courses: http://www.jvims.com/index.php?page=shop.browse&category_id=6&option=com_virtuemart&Itemid=64&vmcchk=1&Itemid=64\r\n\r\nJVIMS Rabbi Courses: http://jvims.com/index.php?page=shop.browse&category_id=6&option=com_virtuemart&Itemid=64\r\n\r\nKidsAstronomy.com Online Astronomy Academy: http://www.kidsastronomy.com/academy/index.htm\r\n\r\nLearn Hebrew and Jewish prayer with our user friendly Software, Book and Audio tutorials and products: http://www.hebrewworld.com/specialOffer.html\r\n\r\nLighting Up Chanukah: http://www.betemunah.org/chanukah.html\r\n\r\nListen to Prayers Bet Am Shalom - A Reconstructionist Synagogue, White Plains, NY: http://betamshalom.org/prayers\r\n\r\nLiturgy: http://www.cyber-synagogue.com/Liturgy.htm\r\n\r\nMahal - Volunteer for the IDF - Join the Israeli Army: http://www.mahal-idf-volunteers.org/support/linkus.htm\r\n\r\nMessianic Jewish Rabbinical Council: http://ourrabbis.org/main/\r\n\r\nMessianic Jewish Radio - San Francisco, CA - Listen Online: http://radiotime.com/station/s_111593/Messianic_Jewish_Radio.aspx\r\n\r\nMessianic Symbol Hebraic Roots Banner-Red: https://www.storesonline.com/site/742858/product/SFA-32133\r\n\r\nMoney Transfer - Send Money Online: https://www.xoom.com/sendmoneynow/home2/security\r\n\r\nMount Olive Press: http://mountolivepress.com/Mount_Olive_Press/Home.html\r\n\r\nMovie Showtimes and Tickets for 33982 - Yahoo! Movies: http://movies.yahoo.com/showtimes-tickets/?location=33982&r=sim\r\n\r\nMy Account Login: https://idp.securepaynet.net/login.aspx?isc=wwbb53&prog%5Fid=register%5Fcheap%5Fdomain%5Fnames%5Fcheap%5Fweb%5Fhosting&spkey=SPSWB166&login=9492585&target=myportal%2Fdomainren%2Easp\r\n\r\nMy order history BiblicalTraining.org: http://www.biblicaltraining.org/user/39652/orders\r\n\r\nMy Wish List Decorative Painting Bookstore: http://www.decorativepaintingbookstore.com/mm5/merchant.mvc?\r\n\r\nNazarene Media - Home: http://www.nazarenemedia.net/\r\n\r\nNazerine books and school: http://stores.lulu.com/nazarene\r\n\r\nNot Subject to the Law of God: http://www.yashanet.com/library/underlaw.htm\r\n\r\nOf His Kingdom There Shall Be No End Mashiyach Mashiyach Mashiyach: http://www.mashiyach.com/index.htm\r\n\r\nohr chadash: http://www.ohrchadash.org/contact.htm\r\n\r\nOld Testament Studies: http://www.torahclass.com/old-testament-studies\r\n\r\nOperation Wake Up Call - Nazarene Space: http://nazarenespace.com/group/operationwakeupcall\r\n\r\norderConfirmation: https://www.rewardsuite.com/rewardsuite/Catalog/View/orderConfirmation.aspx?i=dzOj5blTL2o%3d\r\n\r\npage 3: http://www.globalprebuilder.com/page3-v2.php\r\n\r\nPasco County Library System Program Home Page: http://evanced.info/pasco/sr/homepage.asp?ProgramID=27\r\n\r\nPeshitta.org • View forum - Nazarene-Messianic Judaism Forum: http://www.peshitta.org/forum/viewforum.php?f=6\r\n\r\nPrinciples of Christian Dream Interpretation: http://www.cwgministries.org/Principles-of-Christian-Dream-Interpretation\r\n\r\nprophecyrevealed - I Have A Friend Who's Jewish Book: http://prophecyrevealed.com/\r\n\r\nPsalms 23 - Hebrew - English Bible - Mechon-Mamre: http://www.mechon-mamre.org/p/pt/pt2623.htm\r\n\r\nRabbi Eric Levy and Family: http://www.ericlevy.com/\r\n\r\nRevelation 11-6: http://www.yashanet.com/studies/revstudy/text/r1_1-6.htm\r\n\r\nRevelation Study Text Index: http://www.yashanet.com/studies/revstudy/text/index.htm\r\n\r\nRick Recht Online Store -: http://store.jewishrockrecords.com/store/listings.cfm?cat=12\r\n\r\nSAP Support Portal - Homepage: https://websmp202.sap-ag.de/support\r\n\r\nSchool of Biblical Evangelism: http://www.biblicalevangelism.com/register\r\n\r\nShaarei halachah a summary of laws for Jewish living Online Free Books: http://online-free-books.com/title/Txt4EidAVFEC.html\r\n\r\nShoresh David Messianic Jewish Synagogues (Tampa, Lakeland, & Wesley Chapel, FL): http://www.shoreshdavid.org/\r\n\r\nSilver Jerusalem design Hand Embroidered Hat: http://www.ajudaica.com/item/1494_324/Silver+Jerusalem+design+Hand+Embroidered+Hat\r\n\r\nSmile of a Child TV -- Television Program Schedule: http://www.smileofachildtv.org/watch/schedule_weekview.php\r\n\r\nSounds of Shalom: http://www.soundsofshalom.com/\r\n\r\nSubscription Donations; Messianic Christianity: http://www.messianicchristianity.org/subscription_donations.html\r\n\r\nTable of Contents - Torah 101 - Mechon Mamre: http://www.mechon-mamre.org/jewfaq/index.htm\r\n\r\nTanach Index Hebrew with Vowels: http://www.sacred-texts.com/bib/tan/index.htm\r\n\r\nTemple Aron Hakodesh: http://www.tak.org/services.htm\r\n\r\nTemple Israel NH » Prayer Recordings: http://www.templeisraelnh.org/education/prayer-recordings/\r\n\r\nTES - Largest Distributor of Jewish Software, Hebrew Language and Bible Software (0): http://www.jewishsoftware.com/default.asp?page=category&id=4\r\n\r\nTexts of Judaism: http://www.sacred-texts.com/jud/\r\n\r\nThe Aramaic origin of the Fourth gospel - Google Books: http://books.google.com/ebooks/reader?id=2WhAAAAAIAAJ&printsec=frontcover&output=reader\r\n\r\nThe Book of Zohar Books Michael Laitman Kabbalah Library - Bnei Baruch Kabbalah Education & Research Institute: http://www.kabbalah.info/eng/content/view/frame/2842?/eng/content/view/full_list/2842&main\r\n\r\nThe Evolution of a Creationist Jobe Martin Creation vs. Evolution: http://evolutionofacreationist.com/\r\n\r\nThe Foreign Service of the Philippines - Manila Forwarders: http://www.manilaforwarder.com/immigrantvisa_pg2.html\r\n\r\nThe Lotto Black Book! Secrets Exposed...: http://lottoblackbooks.co.cc/aff.php\r\n\r\nThe Nazarite Site: http://www.nazarite.net/home.html\r\n\r\nThe Poetry of Genesis Chapter One: http://www.ancient-hebrew.org/23_genesis_1.html\r\n\r\nThe Revelation of Y'shua HaMoshiach Thus Say The Prophets!: http://jewtoo.org/prophecy/\r\n\r\nThe Shul of the Web: http://www.heartofisrael.net/\r\n\r\nThe Worldwide Nazarene Assembly of Elohim - Directory of WNAE Assemblies: http://www.wnae.org/assemblies.htm\r\n\r\nTHE WORSHIP OF IMAGES catholism: http://www.justforcatholics.org/images.htm\r\n\r\nTim Hegg Shabbat Shalom Page: http://www.torahresource.com/\r\n\r\nTorah (Teachings) of Yahshua Messiah (Jesus, Yeshua) - rebuking the Trinity and Lawlessness: http://www.torahofmessiah.com/trinity_art.html\r\n\r\nTorah Institute FREE PDF DOWNLOADS: http://www.torahzone.net/FREE-PDF-DOWNLOADS/?page=3\r\n\r\ntorah institute: http://www.fossilizedcustoms.com/\r\n\r\nTorah on the Web - Virtual Beit Midrash - Torah: http://www.vbm-torah.org/moadim.html\r\n\r\nTorah on the Web - Virtual Beit Midrash: http://vbm-torah.org/\r\n\r\nTotShabbat.com: http://www.totshabbat.com/\r\n\r\nTwebrew School: http://www.twebrewschool.org/\r\n\r\nTwinkle, twinkle little star: http://www.storytimesongs.com/guitarchords/Twinkle.html\r\n\r\nVictorious Homeschoolers: https://www.homeschool-life.com/sysfiles/member/index_public.cfm?memberid=693\r\n\r\nVirtual Jerusalem-The Place Where Jews Click: http://www.virtualjerusalem.com/\r\n\r\nvirtualyeshiva.com Torah Learning on the Net: http://www.virtualyeshiva.com/\r\n\r\nWalking in Torah Teachings Hebrew Nation: http://walkingintorah.com/Teachings.html\r\n\r\nway of the master radio: http://www.oneplace.com/ministries/way-of-the-master/\r\n\r\nWearing the Tallit Katan: http://www.hebrew4christians.com/Blessings/Daily_Blessings/Tallit_Katan/tallit_katan.html\r\n\r\nWelcome kabbalah course: http://edu.kabbalah.info/group/lc/home\r\n\r\nWelcome to biblediagrams.com: http://biblediagrams.com/diagrams/index.htm\r\n\r\nWelcome to MessianicJewish.net: http://www.messianicjewish.net/\r\n\r\nWelcome to the JewToo.org Blog!: http://jewtoo.multiply.com/\r\n\r\nWelcome to your Tampa Jewish Community Online!: http://www.jewishtampa.com/calendar/index.aspx?startdate=3/9/2011%206:30:00%20PM&enddate=3/9/2011%207:45:00%20PM&id=20&eventid=510947&recurrenceid=11922\r\n\r\nWINK News: http://www.winknews.com/weather/doppler\r\n\r\nWitnessing Resources -: http://www.nazarenemedia.net/witnessing-resources.html\r\n\r\nworship song guitar chords: http://www.worshiparchive.com/\r\n\r\nwww.wstw.fm listen: http://www.wstw.fm/listen%20live.html\r\n\r\nYashaNet HomePage: http://www.yashanet.com/index.htm\r\n\r\nYeshiva Beth HaShem Bible 101: http://yeshivabethhashem.org/yeshiva/1lesson4.html\r\n\r\nYotzer Hame'orot - the Morning Blessing: http://www.hebrew4christians.com/Blessings/Daily_Blessings/Yotzer_Hame_orot/yotzer_hame_orot.html\r\n\r\nThe Straight Way Ministry Home Page: http://thestraightway.org/\r\n\r\nifcj Journey Through the Scriptures: http://www.ifcj.org/site/PageNavigator/eng/jtts\r\n\r\nTanya - The Book of Tanya Translated into English - Text of the Tanya: http://www.chabad.org/library/tanya/tanya_cdo/aid/1028862/jewish/Tanya.htm\r\n\r\nJewish Holidays, Torah, Jewish Jobs, Tuition Affordability, Kosher Certification, Jewish Teens: http://www.ou.org/\r\n\r\nEsynagogue.org - Home: http://www.esynagogue.org/\r\n\r\nKeep It!: javascript:(a%20=%20(b%20=%20document).createElement('script')).src%20=%20'http://keepvid.com/js/bm.js',%20b.body.appendChild(a);void(0;\r\n\r\nwww.VirtualCantor.com: http://virtualcantor.com/CDOrder.htm\r\n\r\nTRI Classes: http://www.triclasses.com/\r\n\r\nAggressive Christianity Library: http://www.aggressivechristianity.net/library.htm\r\n\r\nDictionary of the Targumim, the Talmud Babli and Yerushalmi, and the Midrashic Literature by Marcus Jastrow: [suspicious link removed]\r\n\r\nHalakhah.com Babylonian Talmud Online in English: http://halakhah.com/\r\n\r\nKhabouris Codex Aramaic Peshitta New Testament Manuscript: http://www.aramaicpeshitta.com/AramaicNTtools/khabouris.htm\r\n\r\nJacob Richman's Hot Sites - Jewish - Learn Hebrew Sites: http://www.jr.co.il/hotsites/j-hebrew.htm\r\n\r\nIndex for Part 1 Kitzur Shulchan Aruch Linear Translation by Yona Newman© 1999-2010: http://www.yonanewman.org/kizzur/kiz-index1.html\r\n\r\nIndex for Part 2 Kitzur Shulchan Aruch Linear Translation by Yona Newman© 1999-2010: http://www.yonanewman.org/kizzur/kiz-index2.html\r\n\r\nBiblia Hebraica (Biblical Hebrew - Home): http://www.bible101.org/hebrew/home.html","content_html":"<p>Here are the names and URLs extracted from the provided bookmarks list:</p>\n<p>GTE Mobile Banking: https://m.gtefcu.org/mobile/Default.aspx?ReturnUrl=%2fmobile%2fMember%2fAccounts%2fTransactionHistory.aspx%3fR6ldQ2Rt%252bjUGc0%252f3%252fhP9UxU2hEVocAsOAVJ4EPdcd9Hh0BsxuR0ilPHrPQzwSXJWzbVCFr3txWVrhtMn9YIzTE6DpzA4jgy3BwTNCXbCmuc%253d-YuyNrzQIfzg%253d&amp;R6ldQ2Rt%2bjUGc0%2f3%2fhP9UxU2hEVocAsOAVJ4EPdcd9Hh0BsxuR0ilPHrPQzwSXJWzbVCFr3txWVrhtMn9YIzTE6DpzA4jgy3BwTNCXbCmuc%3d-YuyNrzQIfzg%3d</p>\n<p>View All Photos | 100 Easy Chicken Recipes | Cooking Light: http://www.cookinglight.com/food/quick-healthy/easy-chicken-recipes/view-all</p>\n<p>Yahoo! Mail: https://m.mg.mail.yahoo.com/hg/?.intl=us</p>\n<p>Weather Station History | Weather Underground: http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=ITARLACC2</p>\n<p>About Shalom Sesame – Shalom Sesame: http://www.shalomsesame.org/about2.html</p>\n<p>AMAZING FACTS: http://www.amazingfacts.org/store/entity/tabid/267/entityname/category/categoryid/126/sename/character-studies/default.aspx</p>\n<p>Ancient Hebrew Research Center - Home Page: http://www.ancient-hebrew.org/</p>\n<p>Anthem BlueCross BlueShield - Verizon Home: http://www.anthem.com/verizon/</p>\n<p>Atheist Central -- Ray Comfort&#039;s Blog: http://raycomfortfood.blogspot.com/</p>\n<p>Audio Lessons « Think Hebrew: http://thinkhebrew.wordpress.com/audio-lessons/</p>\n<p>Barnes &amp; Noble.com - eBooks Search Orthodox Jewish bible: http://productsearch.barnesandnoble.com/search/results.aspx?store=EBOOK&amp;WRD=Orthodox+Jewish+bible</p>\n<p>Beginning Hebrew Class Tim Hegg: http://www.torahresource.com/Hebrew.html</p>\n<p>Behind The Scenes- 5-9-11: http://www.livingwaters.com/index.php?option=com_k2&amp;view=item&amp;id=2753&amp;Itemid=314&amp;lang=en</p>\n<p>Beit Tehila Congregation - Shalom: http://www.topraise.net/pages/about-us/history.htm</p>\n<p>Beth Messiah Messianic Synagogue Sarasota, Florida USA Rabbi Judah Hungerman: http://www.bethmessiahfla.com/</p>\n<p>Bible and Mishneh Torah for All - Jews and Gentiles - Mechon Mamre: http://www.mechon-mamre.org/</p>\n<p>bible passages: http://www.openbible.info/topics/eating_fish</p>\n<p>Bible University: http://www.bibleuniversity.com/University/Welcome.asp</p>\n<p>Biblical Hebrew Blog - By eTeacherBiblical.com Learn Biblical Hebrew online: http://blog.eteacherbiblical.com/</p>\n<p>Biblical Hermeneutics BiblicalTraining.org: http://www.biblicaltraining.org/biblical-hermeneutics/robert-stein</p>\n<p>BiblicalDiscipleship.org: http://biblicaldiscipleship.org/</p>\n<p>Birth Issues Yeshua in Context: http://yeshuaincontext.com/2011/03/birth-issues/</p>\n<p>BlogEngine.NET: http://blogengine.codeplex.com/discussions?prog_id=register_cheap_domain_names_cheap_web_hosting&amp;ProjectName=blogengine</p>\n<p>Bukharin Yarmulke Pattern k2p2.net Blog: http://k2p2.net/blog2/2006/08/31/bukharin-yarmulke-pattern/</p>\n<p>Buy Jewish Gifts Online - Jewelry - Kippah - Mezuzah - Star of David - Kabbalah Red String Bracelets - Evil Eye Charm: http://www.yourholylandstore.com/</p>\n<p>Chabad Jewish Holidays: http://www.chabad.org/library/article_cdo/aid/102698/jewish/Tevet-10.htm</p>\n<p>CHANUKAH ...History &amp; Prophetic End Time Implications: http://www.graftedforlife.org/blogs/index.php/2010/12/03/chanukah-history-aamp-prophetic-end-time-implications?blog=9</p>\n<p>Chofetz Chaim Laws of Speech Naaleh Torah Video Online: http://www.naaleh.com/search/class/148</p>\n<p>Contact Us: http://www.chabadcountyline.com/index.php?option=com_facileforms&amp;act=quickmode&amp;task=edit&amp;formName=ContactUs&amp;Itemid=152</p>\n<p>Count Today&#039;s Omer - Sefirat HaOmer: http://www.chabad.org/holidays/sefirah/omer-count.asp?date=4/19/2011</p>\n<p>Credit Bureau Reporting: http://www.thelpa.com/lpa/credit-reporting.html</p>\n<p>Deuteronomy 1622 Bible Lexicon: http://biblelexicon.org/deuteronomy/16-22.htm</p>\n<p>Didache: http://www.earlychristianwritings.com/didache.html</p>\n<p>directoryBedini SG - PESWiki Tesla Generator: http://peswiki.com/energy/Directory:Bedini_SG</p>\n<p>Dr. Janice Hughes, Clinical Social Work-Therapist, Cape Coral, FL 33914 Psychology Today&#039;s Therapy Directory: http://therapists.psychologytoday.com/rms/prof_detail.php?profid=73368&amp;sid=1281461131.0405_1063&amp;city=Fort+Myers&amp;county=Lee&amp;state=Florida&amp;spec=166</p>\n<p>D&#039;var Torah on the Parashah - Torah Portion of the Week: http://www.artscroll.com/parashah/current.html</p>\n<p>Early Christian Writings New Testament, Apocrypha, Gnostics, Church Fathers: http://www.earlychristianwritings.com/index.html</p>\n<p>Early Jewish Writings: http://www.earlyjewishwritings.com/</p>\n<p>Easiest Online Backup Service - Backblaze: http://www.backblaze.com/</p>\n<p>ebay Seller Tools File Exchange: http://pages.ebay.com/file_exchange/</p>\n<p>Essays and Articles: http://therefinersfire.org/ea.htm</p>\n<p>Essenes, Essene Teachings and Essene Theology: http://www.thenazareneway.com/</p>\n<p>Filipino Audio Lessons: http://mylanguages.org/filipino_audio.php</p>\n<p>Firm Foundation Guitar Tabs, Chords &amp; Lyrics by Jamie Harvill &amp; Nancy Gordon: http://www.worshiparchive.com/song/firm-foundation</p>\n<p>First Fruits Core [Beta]: https://ffoz.org/members/member_cp/index.php</p>\n<p>Florida Lotto: http://www.flalottery.com/inet/lottoMain.do</p>\n<p>FoundationStone - a free and easy way to learn Hebrew: http://foundationstone.com.au/FoundationStone.html?./OnlineHebrewTutorial.html</p>\n<p>Free Lessons Learn Biblical Hebrew with eTeacher: http://eteacherbiblical.com/free-lessons</p>\n<p>Free Online Hebrew Dictionary. Type in Hebrew-English. Translate Hebrew or Phonetic Hebrew.: http://www.doitinhebrew.com/Translate/default.aspx?kb=IL%20Hebrew%20Phonetic</p>\n<p>Front Page www.jewishpresstampa.com Jewish Press of Tampa: http://www.jewishpresstampa.com/</p>\n<p>G-DCAST: http://www.g-dcast.com/</p>\n<p>Google Translate: http://translate.google.com/#</p>\n<p>Hanukkah - Chanukah 2010 - Menorah, Dreidels, Latkes, Recipes, Games and more: http://www.chabad.org/holidays/chanukah/default_cdo/jewish/Hanukkah.htm</p>\n<p>Hebrew Lessons — Ten Commandments: http://www.levitt.com/hebrew/commandments.html</p>\n<p>Home Yarnell: http://www.yarnellschool.com/online/yarnell/index.html</p>\n<p>Information Technology Students and Faculty: http://msdn01.e-academy.com/elms/Storefront/Home.aspx?campus=sfc_it</p>\n<p>Introduction to Islam BiblicalTraining.org: http://www.biblicaltraining.org/introduction-islam/timothy-tennent</p>\n<p>iTanakh: http://www.itanakh.org/</p>\n<p>Jewish Community, Jewish Synagogue, Kosher Food, Makati, Philippines: http://jewishphilippines.net/newsletter.php#</p>\n<p>Jewish Genealogy By Genetics - JewishGen: http://www.jewishgen.org/dna/genbygen.html</p>\n<p>Jewish Roots Learning Center Haydid: http://www.haydid.org/</p>\n<p>Jewish Studies Org: http://www.jewishstudies.org/</p>\n<p>Journey To Jerusalem Home Page: http://www.journeytojerusalem.com/</p>\n<p>Judaism and Jewish Resources - Andrew Tannenbaum: http://shamash.org/trb/judaism.html#learning</p>\n<p>JVIMS Courses: http://www.jvims.com/index.php?page=shop.browse&amp;category_id=6&amp;option=com_virtuemart&amp;Itemid=64&amp;vmcchk=1&amp;Itemid=64</p>\n<p>JVIMS Rabbi Courses: http://jvims.com/index.php?page=shop.browse&amp;category_id=6&amp;option=com_virtuemart&amp;Itemid=64</p>\n<p>KidsAstronomy.com Online Astronomy Academy: http://www.kidsastronomy.com/academy/index.htm</p>\n<p>Learn Hebrew and Jewish prayer with our user friendly Software, Book and Audio tutorials and products: http://www.hebrewworld.com/specialOffer.html</p>\n<p>Lighting Up Chanukah: http://www.betemunah.org/chanukah.html</p>\n<p>Listen to Prayers Bet Am Shalom - A Reconstructionist Synagogue, White Plains, NY: http://betamshalom.org/prayers</p>\n<p>Liturgy: http://www.cyber-synagogue.com/Liturgy.htm</p>\n<p>Mahal - Volunteer for the IDF - Join the Israeli Army: http://www.mahal-idf-volunteers.org/support/linkus.htm</p>\n<p>Messianic Jewish Rabbinical Council: http://ourrabbis.org/main/</p>\n<p>Messianic Jewish Radio - San Francisco, CA - Listen Online: http://radiotime.com/station/s_111593/Messianic_Jewish_Radio.aspx</p>\n<p>Messianic Symbol Hebraic Roots Banner-Red: https://www.storesonline.com/site/742858/product/SFA-32133</p>\n<p>Money Transfer - Send Money Online: https://www.xoom.com/sendmoneynow/home2/security</p>\n<p>Mount Olive Press: http://mountolivepress.com/Mount_Olive_Press/Home.html</p>\n<p>Movie Showtimes and Tickets for 33982 - Yahoo! Movies: http://movies.yahoo.com/showtimes-tickets/?location=33982&amp;r=sim</p>\n<p>My Account Login: https://idp.securepaynet.net/login.aspx?isc=wwbb53&amp;prog%5Fid=register%5Fcheap%5Fdomain%5Fnames%5Fcheap%5Fweb%5Fhosting&amp;spkey=SPSWB166&amp;login=9492585&amp;target=myportal%2Fdomainren%2Easp</p>\n<p>My order history BiblicalTraining.org: http://www.biblicaltraining.org/user/39652/orders</p>\n<p>My Wish List Decorative Painting Bookstore: http://www.decorativepaintingbookstore.com/mm5/merchant.mvc?</p>\n<p>Nazarene Media - Home: http://www.nazarenemedia.net/</p>\n<p>Nazerine books and school: http://stores.lulu.com/nazarene</p>\n<p>Not Subject to the Law of God: http://www.yashanet.com/library/underlaw.htm</p>\n<p>Of His Kingdom There Shall Be No End Mashiyach Mashiyach Mashiyach: http://www.mashiyach.com/index.htm</p>\n<p>ohr chadash: http://www.ohrchadash.org/contact.htm</p>\n<p>Old Testament Studies: http://www.torahclass.com/old-testament-studies</p>\n<p>Operation Wake Up Call - Nazarene Space: http://nazarenespace.com/group/operationwakeupcall</p>\n<p>orderConfirmation: https://www.rewardsuite.com/rewardsuite/Catalog/View/orderConfirmation.aspx?i=dzOj5blTL2o%3d</p>\n<p>page 3: http://www.globalprebuilder.com/page3-v2.php</p>\n<p>Pasco County Library System Program Home Page: http://evanced.info/pasco/sr/homepage.asp?ProgramID=27</p>\n<p>Peshitta.org • View forum - Nazarene-Messianic Judaism Forum: http://www.peshitta.org/forum/viewforum.php?f=6</p>\n<p>Principles of Christian Dream Interpretation: http://www.cwgministries.org/Principles-of-Christian-Dream-Interpretation</p>\n<p>prophecyrevealed - I Have A Friend Who&#039;s Jewish Book: http://prophecyrevealed.com/</p>\n<p>Psalms 23 - Hebrew - English Bible - Mechon-Mamre: http://www.mechon-mamre.org/p/pt/pt2623.htm</p>\n<p>Rabbi Eric Levy and Family: http://www.ericlevy.com/</p>\n<p>Revelation 11-6: http://www.yashanet.com/studies/revstudy/text/r1_1-6.htm</p>\n<p>Revelation Study Text Index: http://www.yashanet.com/studies/revstudy/text/index.htm</p>\n<p>Rick Recht Online Store -: http://store.jewishrockrecords.com/store/listings.cfm?cat=12</p>\n<p>SAP Support Portal - Homepage: https://websmp202.sap-ag.de/support</p>\n<p>School of Biblical Evangelism: http://www.biblicalevangelism.com/register</p>\n<p>Shaarei halachah a summary of laws for Jewish living Online Free Books: http://online-free-books.com/title/Txt4EidAVFEC.html</p>\n<p>Shoresh David Messianic Jewish Synagogues (Tampa, Lakeland, &amp; Wesley Chapel, FL): http://www.shoreshdavid.org/</p>\n<p>Silver Jerusalem design Hand Embroidered Hat: http://www.ajudaica.com/item/1494_324/Silver+Jerusalem+design+Hand+Embroidered+Hat</p>\n<p>Smile of a Child TV -- Television Program Schedule: http://www.smileofachildtv.org/watch/schedule_weekview.php</p>\n<p>Sounds of Shalom: http://www.soundsofshalom.com/</p>\n<p>Subscription Donations; Messianic Christianity: http://www.messianicchristianity.org/subscription_donations.html</p>\n<p>Table of Contents - Torah 101 - Mechon Mamre: http://www.mechon-mamre.org/jewfaq/index.htm</p>\n<p>Tanach Index Hebrew with Vowels: http://www.sacred-texts.com/bib/tan/index.htm</p>\n<p>Temple Aron Hakodesh: http://www.tak.org/services.htm</p>\n<p>Temple Israel NH » Prayer Recordings: http://www.templeisraelnh.org/education/prayer-recordings/</p>\n<p>TES - Largest Distributor of Jewish Software, Hebrew Language and Bible Software (0): http://www.jewishsoftware.com/default.asp?page=category&amp;id=4</p>\n<p>Texts of Judaism: http://www.sacred-texts.com/jud/</p>\n<p>The Aramaic origin of the Fourth gospel - Google Books: http://books.google.com/ebooks/reader?id=2WhAAAAAIAAJ&amp;printsec=frontcover&amp;output=reader</p>\n<p>The Book of Zohar Books Michael Laitman Kabbalah Library - Bnei Baruch Kabbalah Education &amp; Research Institute: http://www.kabbalah.info/eng/content/view/frame/2842?/eng/content/view/full_list/2842&amp;main</p>\n<p>The Evolution of a Creationist Jobe Martin Creation vs. Evolution: http://evolutionofacreationist.com/</p>\n<p>The Foreign Service of the Philippines - Manila Forwarders: http://www.manilaforwarder.com/immigrantvisa_pg2.html</p>\n<p>The Lotto Black Book! Secrets Exposed...: http://lottoblackbooks.co.cc/aff.php</p>\n<p>The Nazarite Site: http://www.nazarite.net/home.html</p>\n<p>The Poetry of Genesis Chapter One: http://www.ancient-hebrew.org/23_genesis_1.html</p>\n<p>The Revelation of Y&#039;shua HaMoshiach Thus Say The Prophets!: http://jewtoo.org/prophecy/</p>\n<p>The Shul of the Web: http://www.heartofisrael.net/</p>\n<p>The Worldwide Nazarene Assembly of Elohim - Directory of WNAE Assemblies: http://www.wnae.org/assemblies.htm</p>\n<p>THE WORSHIP OF IMAGES catholism: http://www.justforcatholics.org/images.htm</p>\n<p>Tim Hegg Shabbat Shalom Page: http://www.torahresource.com/</p>\n<p>Torah (Teachings) of Yahshua Messiah (Jesus, Yeshua) - rebuking the Trinity and Lawlessness: http://www.torahofmessiah.com/trinity_art.html</p>\n<p>Torah Institute FREE PDF DOWNLOADS: http://www.torahzone.net/FREE-PDF-DOWNLOADS/?page=3</p>\n<p>torah institute: http://www.fossilizedcustoms.com/</p>\n<p>Torah on the Web - Virtual Beit Midrash - Torah: http://www.vbm-torah.org/moadim.html</p>\n<p>Torah on the Web - Virtual Beit Midrash: http://vbm-torah.org/</p>\n<p>TotShabbat.com: http://www.totshabbat.com/</p>\n<p>Twebrew School: http://www.twebrewschool.org/</p>\n<p>Twinkle, twinkle little star: http://www.storytimesongs.com/guitarchords/Twinkle.html</p>\n<p>Victorious Homeschoolers: https://www.homeschool-life.com/sysfiles/member/index_public.cfm?memberid=693</p>\n<p>Virtual Jerusalem-The Place Where Jews Click: http://www.virtualjerusalem.com/</p>\n<p>virtualyeshiva.com Torah Learning on the Net: http://www.virtualyeshiva.com/</p>\n<p>Walking in Torah Teachings Hebrew Nation: http://walkingintorah.com/Teachings.html</p>\n<p>way of the master radio: http://www.oneplace.com/ministries/way-of-the-master/</p>\n<p>Wearing the Tallit Katan: http://www.hebrew4christians.com/Blessings/Daily_Blessings/Tallit_Katan/tallit_katan.html</p>\n<p>Welcome kabbalah course: http://edu.kabbalah.info/group/lc/home</p>\n<p>Welcome to biblediagrams.com: http://biblediagrams.com/diagrams/index.htm</p>\n<p>Welcome to MessianicJewish.net: http://www.messianicjewish.net/</p>\n<p>Welcome to the JewToo.org Blog!: http://jewtoo.multiply.com/</p>\n<p>Welcome to your Tampa Jewish Community Online!: http://www.jewishtampa.com/calendar/index.aspx?startdate=3/9/2011%206:30:00%20PM&amp;enddate=3/9/2011%207:45:00%20PM&amp;id=20&amp;eventid=510947&amp;recurrenceid=11922</p>\n<p>WINK News: http://www.winknews.com/weather/doppler</p>\n<p>Witnessing Resources -: http://www.nazarenemedia.net/witnessing-resources.html</p>\n<p>worship song guitar chords: http://www.worshiparchive.com/</p>\n<p>www.wstw.fm listen: http://www.wstw.fm/listen%20live.html</p>\n<p>YashaNet HomePage: http://www.yashanet.com/index.htm</p>\n<p>Yeshiva Beth HaShem Bible 101: http://yeshivabethhashem.org/yeshiva/1lesson4.html</p>\n<p>Yotzer Hame&#039;orot - the Morning Blessing: http://www.hebrew4christians.com/Blessings/Daily_Blessings/Yotzer_Hame_orot/yotzer_hame_orot.html</p>\n<p>The Straight Way Ministry Home Page: http://thestraightway.org/</p>\n<p>ifcj Journey Through the Scriptures: http://www.ifcj.org/site/PageNavigator/eng/jtts</p>\n<p>Tanya - The Book of Tanya Translated into English - Text of the Tanya: http://www.chabad.org/library/tanya/tanya_cdo/aid/1028862/jewish/Tanya.htm</p>\n<p>Jewish Holidays, Torah, Jewish Jobs, Tuition Affordability, Kosher Certification, Jewish Teens: http://www.ou.org/</p>\n<p>Esynagogue.org - Home: http://www.esynagogue.org/</p>\n<p>Keep It!: javascript:(a%20=%20(b%20=%20document).createElement(&#039;script&#039;)).src%20=%20&#039;http://keepvid.com/js/bm.js&#039;,%20b.body.appendChild(a);void(0;</p>\n<p>www.VirtualCantor.com: http://virtualcantor.com/CDOrder.htm</p>\n<p>TRI Classes: http://www.triclasses.com/</p>\n<p>Aggressive Christianity Library: http://www.aggressivechristianity.net/library.htm</p>\n<p>Dictionary of the Targumim, the Talmud Babli and Yerushalmi, and the Midrashic Literature by Marcus Jastrow: [suspicious link removed]</p>\n<p>Halakhah.com Babylonian Talmud Online in English: http://halakhah.com/</p>\n<p>Khabouris Codex Aramaic Peshitta New Testament Manuscript: http://www.aramaicpeshitta.com/AramaicNTtools/khabouris.htm</p>\n<p>Jacob Richman&#039;s Hot Sites - Jewish - Learn Hebrew Sites: http://www.jr.co.il/hotsites/j-hebrew.htm</p>\n<p>Index for Part 1 Kitzur Shulchan Aruch Linear Translation by Yona Newman© 1999-2010: http://www.yonanewman.org/kizzur/kiz-index1.html</p>\n<p>Index for Part 2 Kitzur Shulchan Aruch Linear Translation by Yona Newman© 1999-2010: http://www.yonanewman.org/kizzur/kiz-index2.html</p>\n<p>Biblia Hebraica (Biblical Hebrew - Home): http://www.bible101.org/hebrew/home.html</p>","file_name":"COMPREHENSIVE_DOCUMENTATION.md","stored_name":"20260417-160828-6006d4f1.md","mime_type":"application/octet-stream","file_size_bytes":"22313","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260417-160828-6006d4f1.md","is_deleted":"0","created_at":"2026-04-17 12:08:29","updated_at":"2026-04-17 14:50:34","editor_content":"Here are the names and URLs extracted from the provided bookmarks list:\r\n\r\nGTE Mobile Banking: https://m.gtefcu.org/mobile/Default.aspx?ReturnUrl=%2fmobile%2fMember%2fAccounts%2fTransactionHistory.aspx%3fR6ldQ2Rt%252bjUGc0%252f3%252fhP9UxU2hEVocAsOAVJ4EPdcd9Hh0BsxuR0ilPHrPQzwSXJWzbVCFr3txWVrhtMn9YIzTE6DpzA4jgy3BwTNCXbCmuc%253d-YuyNrzQIfzg%253d&R6ldQ2Rt%2bjUGc0%2f3%2fhP9UxU2hEVocAsOAVJ4EPdcd9Hh0BsxuR0ilPHrPQzwSXJWzbVCFr3txWVrhtMn9YIzTE6DpzA4jgy3BwTNCXbCmuc%3d-YuyNrzQIfzg%3d\r\n\r\nView All Photos | 100 Easy Chicken Recipes | Cooking Light: http://www.cookinglight.com/food/quick-healthy/easy-chicken-recipes/view-all\r\n\r\nYahoo! Mail: https://m.mg.mail.yahoo.com/hg/?.intl=us\r\n\r\nWeather Station History | Weather Underground: http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=ITARLACC2\r\n\r\nAbout Shalom Sesame – Shalom Sesame: http://www.shalomsesame.org/about2.html\r\n\r\nAMAZING FACTS: http://www.amazingfacts.org/store/entity/tabid/267/entityname/category/categoryid/126/sename/character-studies/default.aspx\r\n\r\nAncient Hebrew Research Center - Home Page: http://www.ancient-hebrew.org/\r\n\r\nAnthem BlueCross BlueShield - Verizon Home: http://www.anthem.com/verizon/\r\n\r\nAtheist Central -- Ray Comfort's Blog: http://raycomfortfood.blogspot.com/\r\n\r\nAudio Lessons « Think Hebrew: http://thinkhebrew.wordpress.com/audio-lessons/\r\n\r\nBarnes & Noble.com - eBooks Search Orthodox Jewish bible: http://productsearch.barnesandnoble.com/search/results.aspx?store=EBOOK&WRD=Orthodox+Jewish+bible\r\n\r\nBeginning Hebrew Class Tim Hegg: http://www.torahresource.com/Hebrew.html\r\n\r\nBehind The Scenes- 5-9-11: http://www.livingwaters.com/index.php?option=com_k2&view=item&id=2753&Itemid=314&lang=en\r\n\r\nBeit Tehila Congregation - Shalom: http://www.topraise.net/pages/about-us/history.htm\r\n\r\nBeth Messiah Messianic Synagogue Sarasota, Florida USA Rabbi Judah Hungerman: http://www.bethmessiahfla.com/\r\n\r\nBible and Mishneh Torah for All - Jews and Gentiles - Mechon Mamre: http://www.mechon-mamre.org/\r\n\r\nbible passages: http://www.openbible.info/topics/eating_fish\r\n\r\nBible University: http://www.bibleuniversity.com/University/Welcome.asp\r\n\r\nBiblical Hebrew Blog - By eTeacherBiblical.com Learn Biblical Hebrew online: http://blog.eteacherbiblical.com/\r\n\r\nBiblical Hermeneutics BiblicalTraining.org: http://www.biblicaltraining.org/biblical-hermeneutics/robert-stein\r\n\r\nBiblicalDiscipleship.org: http://biblicaldiscipleship.org/\r\n\r\nBirth Issues Yeshua in Context: http://yeshuaincontext.com/2011/03/birth-issues/\r\n\r\nBlogEngine.NET: http://blogengine.codeplex.com/discussions?prog_id=register_cheap_domain_names_cheap_web_hosting&ProjectName=blogengine\r\n\r\nBukharin Yarmulke Pattern k2p2.net Blog: http://k2p2.net/blog2/2006/08/31/bukharin-yarmulke-pattern/\r\n\r\nBuy Jewish Gifts Online - Jewelry - Kippah - Mezuzah - Star of David - Kabbalah Red String Bracelets - Evil Eye Charm: http://www.yourholylandstore.com/\r\n\r\nChabad Jewish Holidays: http://www.chabad.org/library/article_cdo/aid/102698/jewish/Tevet-10.htm\r\n\r\nCHANUKAH ...History & Prophetic End Time Implications: http://www.graftedforlife.org/blogs/index.php/2010/12/03/chanukah-history-aamp-prophetic-end-time-implications?blog=9\r\n\r\nChofetz Chaim Laws of Speech Naaleh Torah Video Online: http://www.naaleh.com/search/class/148\r\n\r\nContact Us: http://www.chabadcountyline.com/index.php?option=com_facileforms&act=quickmode&task=edit&formName=ContactUs&Itemid=152\r\n\r\nCount Today's Omer - Sefirat HaOmer: http://www.chabad.org/holidays/sefirah/omer-count.asp?date=4/19/2011\r\n\r\nCredit Bureau Reporting: http://www.thelpa.com/lpa/credit-reporting.html\r\n\r\nDeuteronomy 1622 Bible Lexicon: http://biblelexicon.org/deuteronomy/16-22.htm\r\n\r\nDidache: http://www.earlychristianwritings.com/didache.html\r\n\r\ndirectoryBedini SG - PESWiki Tesla Generator: http://peswiki.com/energy/Directory:Bedini_SG\r\n\r\nDr. Janice Hughes, Clinical Social Work-Therapist, Cape Coral, FL 33914 Psychology Today's Therapy Directory: http://therapists.psychologytoday.com/rms/prof_detail.php?profid=73368&sid=1281461131.0405_1063&city=Fort+Myers&county=Lee&state=Florida&spec=166\r\n\r\nD'var Torah on the Parashah - Torah Portion of the Week: http://www.artscroll.com/parashah/current.html\r\n\r\nEarly Christian Writings New Testament, Apocrypha, Gnostics, Church Fathers: http://www.earlychristianwritings.com/index.html\r\n\r\nEarly Jewish Writings: http://www.earlyjewishwritings.com/\r\n\r\nEasiest Online Backup Service - Backblaze: http://www.backblaze.com/\r\n\r\nebay Seller Tools File Exchange: http://pages.ebay.com/file_exchange/\r\n\r\nEssays and Articles: http://therefinersfire.org/ea.htm\r\n\r\nEssenes, Essene Teachings and Essene Theology: http://www.thenazareneway.com/\r\n\r\nFilipino Audio Lessons: http://mylanguages.org/filipino_audio.php\r\n\r\nFirm Foundation Guitar Tabs, Chords & Lyrics by Jamie Harvill & Nancy Gordon: http://www.worshiparchive.com/song/firm-foundation\r\n\r\nFirst Fruits Core [Beta]: https://ffoz.org/members/member_cp/index.php\r\n\r\nFlorida Lotto: http://www.flalottery.com/inet/lottoMain.do\r\n\r\nFoundationStone - a free and easy way to learn Hebrew: http://foundationstone.com.au/FoundationStone.html?./OnlineHebrewTutorial.html\r\n\r\nFree Lessons Learn Biblical Hebrew with eTeacher: http://eteacherbiblical.com/free-lessons\r\n\r\nFree Online Hebrew Dictionary. Type in Hebrew-English. Translate Hebrew or Phonetic Hebrew.: http://www.doitinhebrew.com/Translate/default.aspx?kb=IL%20Hebrew%20Phonetic\r\n\r\nFront Page www.jewishpresstampa.com Jewish Press of Tampa: http://www.jewishpresstampa.com/\r\n\r\nG-DCAST: http://www.g-dcast.com/\r\n\r\nGoogle Translate: http://translate.google.com/#\r\n\r\nHanukkah - Chanukah 2010 - Menorah, Dreidels, Latkes, Recipes, Games and more: http://www.chabad.org/holidays/chanukah/default_cdo/jewish/Hanukkah.htm\r\n\r\nHebrew Lessons — Ten Commandments: http://www.levitt.com/hebrew/commandments.html\r\n\r\nHome Yarnell: http://www.yarnellschool.com/online/yarnell/index.html\r\n\r\nInformation Technology Students and Faculty: http://msdn01.e-academy.com/elms/Storefront/Home.aspx?campus=sfc_it\r\n\r\nIntroduction to Islam BiblicalTraining.org: http://www.biblicaltraining.org/introduction-islam/timothy-tennent\r\n\r\niTanakh: http://www.itanakh.org/\r\n\r\nJewish Community, Jewish Synagogue, Kosher Food, Makati, Philippines: http://jewishphilippines.net/newsletter.php#\r\n\r\nJewish Genealogy By Genetics - JewishGen: http://www.jewishgen.org/dna/genbygen.html\r\n\r\nJewish Roots Learning Center Haydid: http://www.haydid.org/\r\n\r\nJewish Studies Org: http://www.jewishstudies.org/\r\n\r\nJourney To Jerusalem Home Page: http://www.journeytojerusalem.com/\r\n\r\nJudaism and Jewish Resources - Andrew Tannenbaum: http://shamash.org/trb/judaism.html#learning\r\n\r\nJVIMS Courses: http://www.jvims.com/index.php?page=shop.browse&category_id=6&option=com_virtuemart&Itemid=64&vmcchk=1&Itemid=64\r\n\r\nJVIMS Rabbi Courses: http://jvims.com/index.php?page=shop.browse&category_id=6&option=com_virtuemart&Itemid=64\r\n\r\nKidsAstronomy.com Online Astronomy Academy: http://www.kidsastronomy.com/academy/index.htm\r\n\r\nLearn Hebrew and Jewish prayer with our user friendly Software, Book and Audio tutorials and products: http://www.hebrewworld.com/specialOffer.html\r\n\r\nLighting Up Chanukah: http://www.betemunah.org/chanukah.html\r\n\r\nListen to Prayers Bet Am Shalom - A Reconstructionist Synagogue, White Plains, NY: http://betamshalom.org/prayers\r\n\r\nLiturgy: http://www.cyber-synagogue.com/Liturgy.htm\r\n\r\nMahal - Volunteer for the IDF - Join the Israeli Army: http://www.mahal-idf-volunteers.org/support/linkus.htm\r\n\r\nMessianic Jewish Rabbinical Council: http://ourrabbis.org/main/\r\n\r\nMessianic Jewish Radio - San Francisco, CA - Listen Online: http://radiotime.com/station/s_111593/Messianic_Jewish_Radio.aspx\r\n\r\nMessianic Symbol Hebraic Roots Banner-Red: https://www.storesonline.com/site/742858/product/SFA-32133\r\n\r\nMoney Transfer - Send Money Online: https://www.xoom.com/sendmoneynow/home2/security\r\n\r\nMount Olive Press: http://mountolivepress.com/Mount_Olive_Press/Home.html\r\n\r\nMovie Showtimes and Tickets for 33982 - Yahoo! Movies: http://movies.yahoo.com/showtimes-tickets/?location=33982&r=sim\r\n\r\nMy Account Login: https://idp.securepaynet.net/login.aspx?isc=wwbb53&prog%5Fid=register%5Fcheap%5Fdomain%5Fnames%5Fcheap%5Fweb%5Fhosting&spkey=SPSWB166&login=9492585&target=myportal%2Fdomainren%2Easp\r\n\r\nMy order history BiblicalTraining.org: http://www.biblicaltraining.org/user/39652/orders\r\n\r\nMy Wish List Decorative Painting Bookstore: http://www.decorativepaintingbookstore.com/mm5/merchant.mvc?\r\n\r\nNazarene Media - Home: http://www.nazarenemedia.net/\r\n\r\nNazerine books and school: http://stores.lulu.com/nazarene\r\n\r\nNot Subject to the Law of God: http://www.yashanet.com/library/underlaw.htm\r\n\r\nOf His Kingdom There Shall Be No End Mashiyach Mashiyach Mashiyach: http://www.mashiyach.com/index.htm\r\n\r\nohr chadash: http://www.ohrchadash.org/contact.htm\r\n\r\nOld Testament Studies: http://www.torahclass.com/old-testament-studies\r\n\r\nOperation Wake Up Call - Nazarene Space: http://nazarenespace.com/group/operationwakeupcall\r\n\r\norderConfirmation: https://www.rewardsuite.com/rewardsuite/Catalog/View/orderConfirmation.aspx?i=dzOj5blTL2o%3d\r\n\r\npage 3: http://www.globalprebuilder.com/page3-v2.php\r\n\r\nPasco County Library System Program Home Page: http://evanced.info/pasco/sr/homepage.asp?ProgramID=27\r\n\r\nPeshitta.org • View forum - Nazarene-Messianic Judaism Forum: http://www.peshitta.org/forum/viewforum.php?f=6\r\n\r\nPrinciples of Christian Dream Interpretation: http://www.cwgministries.org/Principles-of-Christian-Dream-Interpretation\r\n\r\nprophecyrevealed - I Have A Friend Who's Jewish Book: http://prophecyrevealed.com/\r\n\r\nPsalms 23 - Hebrew - English Bible - Mechon-Mamre: http://www.mechon-mamre.org/p/pt/pt2623.htm\r\n\r\nRabbi Eric Levy and Family: http://www.ericlevy.com/\r\n\r\nRevelation 11-6: http://www.yashanet.com/studies/revstudy/text/r1_1-6.htm\r\n\r\nRevelation Study Text Index: http://www.yashanet.com/studies/revstudy/text/index.htm\r\n\r\nRick Recht Online Store -: http://store.jewishrockrecords.com/store/listings.cfm?cat=12\r\n\r\nSAP Support Portal - Homepage: https://websmp202.sap-ag.de/support\r\n\r\nSchool of Biblical Evangelism: http://www.biblicalevangelism.com/register\r\n\r\nShaarei halachah a summary of laws for Jewish living Online Free Books: http://online-free-books.com/title/Txt4EidAVFEC.html\r\n\r\nShoresh David Messianic Jewish Synagogues (Tampa, Lakeland, & Wesley Chapel, FL): http://www.shoreshdavid.org/\r\n\r\nSilver Jerusalem design Hand Embroidered Hat: http://www.ajudaica.com/item/1494_324/Silver+Jerusalem+design+Hand+Embroidered+Hat\r\n\r\nSmile of a Child TV -- Television Program Schedule: http://www.smileofachildtv.org/watch/schedule_weekview.php\r\n\r\nSounds of Shalom: http://www.soundsofshalom.com/\r\n\r\nSubscription Donations; Messianic Christianity: http://www.messianicchristianity.org/subscription_donations.html\r\n\r\nTable of Contents - Torah 101 - Mechon Mamre: http://www.mechon-mamre.org/jewfaq/index.htm\r\n\r\nTanach Index Hebrew with Vowels: http://www.sacred-texts.com/bib/tan/index.htm\r\n\r\nTemple Aron Hakodesh: http://www.tak.org/services.htm\r\n\r\nTemple Israel NH » Prayer Recordings: http://www.templeisraelnh.org/education/prayer-recordings/\r\n\r\nTES - Largest Distributor of Jewish Software, Hebrew Language and Bible Software (0): http://www.jewishsoftware.com/default.asp?page=category&id=4\r\n\r\nTexts of Judaism: http://www.sacred-texts.com/jud/\r\n\r\nThe Aramaic origin of the Fourth gospel - Google Books: http://books.google.com/ebooks/reader?id=2WhAAAAAIAAJ&printsec=frontcover&output=reader\r\n\r\nThe Book of Zohar Books Michael Laitman Kabbalah Library - Bnei Baruch Kabbalah Education & Research Institute: http://www.kabbalah.info/eng/content/view/frame/2842?/eng/content/view/full_list/2842&main\r\n\r\nThe Evolution of a Creationist Jobe Martin Creation vs. Evolution: http://evolutionofacreationist.com/\r\n\r\nThe Foreign Service of the Philippines - Manila Forwarders: http://www.manilaforwarder.com/immigrantvisa_pg2.html\r\n\r\nThe Lotto Black Book! Secrets Exposed...: http://lottoblackbooks.co.cc/aff.php\r\n\r\nThe Nazarite Site: http://www.nazarite.net/home.html\r\n\r\nThe Poetry of Genesis Chapter One: http://www.ancient-hebrew.org/23_genesis_1.html\r\n\r\nThe Revelation of Y'shua HaMoshiach Thus Say The Prophets!: http://jewtoo.org/prophecy/\r\n\r\nThe Shul of the Web: http://www.heartofisrael.net/\r\n\r\nThe Worldwide Nazarene Assembly of Elohim - Directory of WNAE Assemblies: http://www.wnae.org/assemblies.htm\r\n\r\nTHE WORSHIP OF IMAGES catholism: http://www.justforcatholics.org/images.htm\r\n\r\nTim Hegg Shabbat Shalom Page: http://www.torahresource.com/\r\n\r\nTorah (Teachings) of Yahshua Messiah (Jesus, Yeshua) - rebuking the Trinity and Lawlessness: http://www.torahofmessiah.com/trinity_art.html\r\n\r\nTorah Institute FREE PDF DOWNLOADS: http://www.torahzone.net/FREE-PDF-DOWNLOADS/?page=3\r\n\r\ntorah institute: http://www.fossilizedcustoms.com/\r\n\r\nTorah on the Web - Virtual Beit Midrash - Torah: http://www.vbm-torah.org/moadim.html\r\n\r\nTorah on the Web - Virtual Beit Midrash: http://vbm-torah.org/\r\n\r\nTotShabbat.com: http://www.totshabbat.com/\r\n\r\nTwebrew School: http://www.twebrewschool.org/\r\n\r\nTwinkle, twinkle little star: http://www.storytimesongs.com/guitarchords/Twinkle.html\r\n\r\nVictorious Homeschoolers: https://www.homeschool-life.com/sysfiles/member/index_public.cfm?memberid=693\r\n\r\nVirtual Jerusalem-The Place Where Jews Click: http://www.virtualjerusalem.com/\r\n\r\nvirtualyeshiva.com Torah Learning on the Net: http://www.virtualyeshiva.com/\r\n\r\nWalking in Torah Teachings Hebrew Nation: http://walkingintorah.com/Teachings.html\r\n\r\nway of the master radio: http://www.oneplace.com/ministries/way-of-the-master/\r\n\r\nWearing the Tallit Katan: http://www.hebrew4christians.com/Blessings/Daily_Blessings/Tallit_Katan/tallit_katan.html\r\n\r\nWelcome kabbalah course: http://edu.kabbalah.info/group/lc/home\r\n\r\nWelcome to biblediagrams.com: http://biblediagrams.com/diagrams/index.htm\r\n\r\nWelcome to MessianicJewish.net: http://www.messianicjewish.net/\r\n\r\nWelcome to the JewToo.org Blog!: http://jewtoo.multiply.com/\r\n\r\nWelcome to your Tampa Jewish Community Online!: http://www.jewishtampa.com/calendar/index.aspx?startdate=3/9/2011%206:30:00%20PM&enddate=3/9/2011%207:45:00%20PM&id=20&eventid=510947&recurrenceid=11922\r\n\r\nWINK News: http://www.winknews.com/weather/doppler\r\n\r\nWitnessing Resources -: http://www.nazarenemedia.net/witnessing-resources.html\r\n\r\nworship song guitar chords: http://www.worshiparchive.com/\r\n\r\nwww.wstw.fm listen: http://www.wstw.fm/listen%20live.html\r\n\r\nYashaNet HomePage: http://www.yashanet.com/index.htm\r\n\r\nYeshiva Beth HaShem Bible 101: http://yeshivabethhashem.org/yeshiva/1lesson4.html\r\n\r\nYotzer Hame'orot - the Morning Blessing: http://www.hebrew4christians.com/Blessings/Daily_Blessings/Yotzer_Hame_orot/yotzer_hame_orot.html\r\n\r\nThe Straight Way Ministry Home Page: http://thestraightway.org/\r\n\r\nifcj Journey Through the Scriptures: http://www.ifcj.org/site/PageNavigator/eng/jtts\r\n\r\nTanya - The Book of Tanya Translated into English - Text of the Tanya: http://www.chabad.org/library/tanya/tanya_cdo/aid/1028862/jewish/Tanya.htm\r\n\r\nJewish Holidays, Torah, Jewish Jobs, Tuition Affordability, Kosher Certification, Jewish Teens: http://www.ou.org/\r\n\r\nEsynagogue.org - Home: http://www.esynagogue.org/\r\n\r\nKeep It!: javascript:(a%20=%20(b%20=%20document).createElement('script')).src%20=%20'http://keepvid.com/js/bm.js',%20b.body.appendChild(a);void(0;\r\n\r\nwww.VirtualCantor.com: http://virtualcantor.com/CDOrder.htm\r\n\r\nTRI Classes: http://www.triclasses.com/\r\n\r\nAggressive Christianity Library: http://www.aggressivechristianity.net/library.htm\r\n\r\nDictionary of the Targumim, the Talmud Babli and Yerushalmi, and the Midrashic Literature by Marcus Jastrow: [suspicious link removed]\r\n\r\nHalakhah.com Babylonian Talmud Online in English: http://halakhah.com/\r\n\r\nKhabouris Codex Aramaic Peshitta New Testament Manuscript: http://www.aramaicpeshitta.com/AramaicNTtools/khabouris.htm\r\n\r\nJacob Richman's Hot Sites - Jewish - Learn Hebrew Sites: http://www.jr.co.il/hotsites/j-hebrew.htm\r\n\r\nIndex for Part 1 Kitzur Shulchan Aruch Linear Translation by Yona Newman© 1999-2010: http://www.yonanewman.org/kizzur/kiz-index1.html\r\n\r\nIndex for Part 2 Kitzur Shulchan Aruch Linear Translation by Yona Newman© 1999-2010: http://www.yonanewman.org/kizzur/kiz-index2.html\r\n\r\nBiblia Hebraica (Biblical Hebrew - Home): http://www.bible101.org/hebrew/home.html","is_text_editable":1,"can_edit_inline":1}
documents · save
2026-04-17 12:08:52 · anonymous · /backend/documents.php?backend_document_id=20
change
backend_document #20
Context
{"document_type":"upload"}
Before
{"backend_document_id":"20","document_type":"upload","title":"Complete Documentation up to date","slug":"complete-documentation-up-to-date","summary_text":null,"content_markdown":null,"content_html":null,"file_name":"COMPREHENSIVE_DOCUMENTATION.md","stored_name":"20260417-160828-6006d4f1.md","mime_type":"application/octet-stream","file_size_bytes":"22313","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260417-160828-6006d4f1.md","is_deleted":"0","created_at":"2026-04-17 12:08:29","updated_at":"2026-04-17 12:08:29","editor_content":"# Ella's Alterations - Comprehensive System Documentation\n\n**Generated:** April 17, 2026\n**Location:** C:\\code\\customerdb\n\n---\n\n## Table of Contents\n\n1. [System Overview](#1-system-overview)\n2. [Directory Structure](#2-directory-structure)\n3. [Database Schema](#3-database-schema)\n4. [API Endpoints](#4-api-endpoints)\n5. [External Integrations](#5-external-integrations)\n6. [Scheduled Jobs / Cron](#6-scheduled-jobs--cron)\n7. [Web Applications](#7-web-applications)\n8. [Settings & Configuration](#8-settings--configuration)\n9. [Migration Notes](#9-migration-notes)\n10. [Scripts & Tools](#10-scripts--tools)\n\n---\n\n## 1. System Overview\n\n### Purpose\nElla's Alterations is a comprehensive customer relationship management (CRM) andAlteration tracking system for a tailor shop. It manages customers, visits/alteration orders, appointments, payments, and provides integration with external services.\n\n### Server Information\n- **Primary Server:** kefa@192.168.7.202\n- **Mirror Drive:** /mnt/drive2 (mirrors /mnt/drive1)\n- **Database:** MariaDB - database `ellas_alterations`, user `kefa_admin`\n- **Web Server:** Apache 2.4 with mod-php\n- **PHP Version:** 8.3\n\n### Three Web Applications\n\n| App | Local URL | Public URL | Purpose |\n|-----|-----------|------------|---------|\n| Front Desk | http://192.168.7.202:8895 | https://ella.floridaalterations.com | Customer-facing operations |\n| Management | http://192.168.7.202:8894 | (LAN only) | Reports, admin, settings |\n| Scheduler | http://192.168.7.202:8897 | https://schedule.floridaalterations.com | Easy!Appointments booking |\n\n---\n\n## 2. Directory Structure\n\n```\ncustomerdb/\n├── backend/                    # Main PHP backend API and services\n│   ├── api/                    # REST API endpoints (~57 files)\n│   ├── bin/                    # Binary/executable scripts\n│   ├── backup/                # Backup versions of services\n│   └── jobs/                  # Background job scripts\n├── frontend/                   # Front Desk app (port 8895)\n│   ├── *.html                 # HTML pages\n│   ├── api/                   # PHP API endpoints\n│   └── reports/               # PDF reports (MMDDYYYY/filename.pdf)\n├── webui/                      # Management app (port 8894)\n│   ├── *.html                 # HTML pages\n│   ├── api/                  # PHP API endpoints\n│   ├── backend/               # Backend API copy\n│   └── email/                # Email templates\n├── schedule/                   # Easy!Appointments installation\n├── schema/                    # Database schema files\n├── migrations/               # SQL migrations\n├── scripts/                   # PowerShell/Python import scripts\n├── docs/                     # Documentation\n├── blog/                     # Blog system and reengineering\n├── csv/                      # CSV data files\n├── backups/                  # Backup archives\n├── Topaz/                    # Topaz signature pad configs\n├── webui/                    # Second web interface\n│   ├── api/\n│   ├── backend/\n│   └── frontend/\n├── notused/                  # Deprecated/unused files\n└── wordpress-plugin/          # WordPress integration\n```\n\n---\n\n## 3. Database Schema\n\n### Core Tables (from mariadb_core_schema.sql)\n\n#### customers\nMain customer registry.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| customer_id | INT UNSIGNED PK | Auto-increment |\n| legacy_customer_id | INT NULL | Original Access DB ID |\n| created_at | DATETIME | Record creation time |\n| full_name | VARCHAR(200) | Customer full name |\n| phone | VARCHAR(30) | Formatted (XXX) XXX-XXXX |\n| email | VARCHAR(255) | Email address |\n| pickup_due_at | DATETIME | Next pickup date (synced from EA) |\n| description | TEXT | Description |\n| notes | TEXT | Internal notes |\n| is_new_customer | TINYINT(1) | 1 if flagged as new |\n\n#### visits\nOne row per alteration job/order.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| visit_id | INT UNSIGNED PK | |\n| legacy_visit_id | INT NULL | Original Access DB ID |\n| customer_id | INT UNSIGNED FK | → customers |\n| visit_date | DATETIME | Drop-off date |\n| pickup_date | DATETIME | Expected pickup |\n| notes | TEXT | General visit notes |\n| customer_name_snapshot | VARCHAR(200) | |\n| phone_snapshot | VARCHAR(30) | |\n| email_snapshot | VARCHAR(255) | |\n| color | VARCHAR(100) | Garment color |\n| alterations_needed | TEXT | |\n| alterations_notes | TEXT | Detailed alteration instructions |\n| alterations_price | DECIMAL(10,2) | Manual price field |\n| total_alteration_price | DECIMAL(10,2) | Calculated from items |\n| expedited_fee | DECIMAL(10,2) | |\n| paid_date | DATETIME | When paid |\n| signature_text | TEXT | Text signature (legacy) |\n| signature_date | DATETIME | |\n| paid_flag | TINYINT(1) | 1 = paid |\n| source_key_value | VARCHAR(100) | |\n\n#### visit_signatures\nFull resolution signature images per visit.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| signature_id | BIGINT UNSIGNED PK | |\n| visit_id | INT UNIQUE | One signature per visit |\n| signature_date | DATETIME | |\n| image_format | VARCHAR(50) | Default 'image/png' |\n| original_filename | VARCHAR(255) | |\n| original_extension | VARCHAR(20) | |\n| file_size_bytes | BIGINT | |\n| sha256_hash | CHAR(64) | Hash for verification |\n| signature_image | LONGBLOB | Raw PNG binary |\n| created_at | DATETIME | |\n\n#### item_types\nMaster list of alteration types (e.g., Hem, Zipper, Taper).\n\n| Column | Type | Notes |\n|--------|------|-------|\n| item_type_id | INT UNSIGNED PK | |\n| type_name | VARCHAR(100) UNIQUE | Display name |\n\n#### orders\nOrders per visit.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| order_id | BIGINT UNSIGNED PK | |\n| visit_id | INT UNSIGNED FK | → visits |\n| customer_id | INT UNSIGNED FK | → customers |\n| created_at | DATETIME | |\n| no_tax | TINYINT(1) | Tax exempt |\n| picked_up | TINYINT(1) | |\n| source_table | VARCHAR(50) | |\n\n#### order_items\nLine items for each alteration within a visit.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| order_item_id | BIGINT UNSIGNED PK | |\n| order_id | BIGINT UNSIGNED FK | → orders |\n| legacy_alteration_id | INT NULL | |\n| item_type_id | INT FK | → item_types |\n| item_type_name | VARCHAR(100) | |\n| description | TEXT | |\n| quantity | INT | Default 1 |\n| unit_price | DECIMAL(10,2) | |\n| total_price | DECIMAL(10,2) | |\n| notes | TEXT | Per-item notes |\n| color | VARCHAR(100) | Garment color |\n| no_tax | TINYINT(1) | Tax exempt |\n| is_range_price | TINYINT(1) | |\n| range_price_label | VARCHAR(100) | |\n| paid_flag | TINYINT(1) | |\n| paid_type | VARCHAR(100) | |\n| picked_up | TINYINT(1) | |\n| created_at | DATETIME | |\n\n#### order_item_type_links\nMany-to-many links between order items and item types.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| order_item_type_link_id | BIGINT UNSIGNED PK | |\n| order_item_id | BIGINT UNSIGNED FK | → order_items |\n| item_type_id | INT UNSIGNED FK | → item_types |\n| slot_number | TINYINT UNSIGNED | |\n\n#### payments\nPayment records per order.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| payment_id | BIGINT UNSIGNED PK | |\n| order_id | BIGINT UNSIGNED FK | → orders |\n| payment_date | DATETIME | |\n| payment_type | VARCHAR(100) | |\n| payment_method | VARCHAR(100) | |\n| amount | DECIMAL(10,2) | |\n| notes | TEXT | |\n\n#### tax_payments\nTax payment records.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| tax_payment_id | INT UNSIGNED PK | |\n| legacy_tax_payment_id | INT NULL | |\n| payment_date | DATETIME | |\n| payment_type | VARCHAR(100) | |\n| payment_method | VARCHAR(100) | |\n| amount | DECIMAL(10,2) | |\n| notes | TEXT | |\n| receipt_blob | LONGBLOB | |\n\n#### change_log\nAudit log for changes.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| log_id | BIGINT UNSIGNED PK | |\n| legacy_log_id | INT NULL | |\n| table_name | VARCHAR(100) | |\n| record_id | BIGINT | |\n| visit_id | INT | |\n| field_name | VARCHAR(100) | |\n| old_value | TEXT | |\n| new_value | TEXT | |\n| changed_at | DATETIME | |\n| changed_by | VARCHAR(100) | |\n\n#### ads\nAdvertising/articles.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| ad_id | INT UNSIGNED PK | |\n| legacy_ad_id | INT NULL | |\n| article_text | TEXT | |\n| article_picture | LONGBLOB | |\n| site_submitted | VARCHAR(255) | |\n| views | INT | Default 0 |\n| date_posted | DATETIME | |\n\n#### staging_* tables\nStaging tables for data migration.\n\n| Table Name | Purpose |\n|------------|---------|\n| staging_customer_table_raw | Staging for legacy customer data |\n| staging_customer_visits_raw | Staging for legacy visits |\n| staging_alteration_items_raw | Staging for items |\n\n### Additional Backend Tables\n\n| Table Name | Purpose |\n|------------|---------|\n| setmore_appointments | Synced from Setmore |\n| backend_conversion_job | Document conversion jobs |\n| backend_job_runs | Background job execution log |\n| customer_totals | Daily customer totals |\n| daily_customer_totals | Daily summary totals |\n| customer_payment_transactions | Payment ledger |\n| legacy_customer_totals_monthly | Monthly totals (legacy) |\n| legacy_customer_totals_irs_monthly | IRS monthly reports |\n| backend_appointment_workflow | Appointment state machine |\n| backend_no_show_log | No-show tracking |\n| backend_error_log | Error logging |\n| backend_change_log | Change audit log |\n| backend_document | Document storage |\n| backend_document_version | Document version history |\n| backend_speed_dial | Quick links |\n| backend_square_terminal_code | Square terminal pairing codes |\n| backend_square_terminal_device | Square device registry |\n| cron_job | Scheduled job definitions |\n| cron_job_run | Cron execution history |\n| app_settings | Global configuration |\n| app_users | Login accounts |\n| remember_tokens | \"Remember Me\" tokens |\n| customer_reports | PDF report index |\n\n---\n\n## 4. API Endpoints\n\n### 4.1 Frontend API (port 8895 /api/)\n\n| Endpoint File | Purpose |\n|---------------|---------|\n| **customer_get.php** | Get customer by ID |\n| **customer_save.php** | Create or update customer |\n| **customer_detail.php** | Customer + visits summary |\n| **customer_delete.php** | Delete customer |\n| **customer_list_hide.php** | Hide customer from list |\n| **search_customers.php** | Search by name/phone |\n| **visit_get.php** | Get visit + items |\n| **visit_save.php** | Create/update visit + items |\n| **visit_delete.php** | Delete visit |\n| **visit_report_generate.php** | Generate visit report |\n| **item_types.php** | List all alteration types |\n| **item_type_add.php** | Add new item type |\n| **item_type_update.php** | Update item type |\n| **item_type_delete.php** | Delete item type |\n| **pickups_today.php** | Orders due today |\n| **ready.php** | Orders ready for pickup |\n| **overdue.php** | Overdue orders |\n| **upcoming.php** | Orders due in next N days |\n| **workload_7days.php** | 7-day workload |\n| **save_signature.php** | Save canvas signature |\n| **reports_list.php** | Reports for customer |\n| **attach_reports.php** | Index all PDFs to DB |\n| **save_signature.php** | Save signature image |\n| **today_appointments_list.php** | Today's appointments |\n| **settings_get.php** | Get app settings |\n| **settings_save.php** | Save app settings |\n| **settings_css.php** | Live theme CSS |\n| **send_email.php** | Send email via SMTP |\n| **send_sms.php** | Send SMS via Twilio |\n| **send_reminders.php** | Send appointment reminders |\n| **ea_appointments.php** | EasyAppointments REST API |\n| **ea_webhook.php** | Receives EA webhook events |\n| **setmore.php** | Setmore API proxy |\n| **setmore_to_ea_import.php** | Import customers to EA |\n| **square_config.php** | Square public config |\n| **square_process.php** | Process Square payment |\n| **square_customer_log.php** | Customer Square log |\n| **square_terminal.php** | Square terminal |\n| **login.php** | Authenticate |\n| **logout.php** | Clear session |\n| **session_check.php** | Check if logged in |\n| **auth.php** | Session authentication |\n| **config.php** | App config constants |\n| **db.php** | Database connection |\n| **log_error.php** | Log client-side error |\n| **todo_list.php** | Todo list management |\n| **send_telegram.php** | Send Telegram messages |\n\n### 4.2 Management API (port 8894 /api/)\n\n| Endpoint File | Purpose |\n|---------------|---------|\n| **login.php** | Authenticate |\n| **logout.php** | Clear session |\n| **session_check.php** | Check if logged in |\n| **customer_detail.php** | Customer + visits |\n| **search_customers.php** | Search customers |\n| **update_customer.php** | Update customer |\n| **users_list.php** | List all users |\n| **user_save.php** | Create/update user |\n| **list_report_dirs.php** | Date folders |\n| **list_report_files.php** | PDFs in folder |\n| **report_file.php** | Access report file |\n| **pickups_today.php** | Today's pickups |\n| **ready.php** | Ready for pickup |\n| **overdue.php** | Overdue |\n| **settings_get.php** | Get settings |\n| **settings_save.php** | Save settings |\n| **settings_css.php** | Live CSS theme |\n| **imap_list.php** | List IMAP folders |\n| **imap_fetch.php** | Fetch emails |\n| **imap_send.php** | Send email via IMAP |\n| **imap_action.php** | IMAP actions |\n| **sms_send_helper.php** | SMS sending helper |\n| **sms_webhook_receive.php** | Receive SMS webhooks |\n| **sms_inbox_api.php** | SMS inbox API |\n| **slideshow_list.php** | Slideshow images |\n| **slideshow_upload.php** | Upload slideshow |\n| **slideshow_delete.php** | Delete slideshow |\n| **users_list.php** | User management |\n| **report_list.php** | Report list |\n| **debug_filters.php** | Debug filters |\n| **sysadmin.php** | System admin |\n| **test.php** | Testing endpoint |\n\n### 4.3 Backend API (C:\\code\\customerdb\\backend\\api\\)\n\n| Endpoint File | Purpose |\n|---------------|---------|\n| **customer.php** | Get customer details |\n| **customers.php** | List/search customers |\n| **customer_save.php** | Save/update customer |\n| **visit.php** | Get visit details |\n| **visit_delete.php** | Delete visit |\n| **appointments.php** | Unified appointments |\n| **appointments_summary.php** | Appointment statistics |\n| **setmore_appointments.php** | Setmore appointments |\n| **setmore_import.php** | Import from Setmore |\n| **module_*.php** | Module loaders |\n| **alteration_items.php** | Alteration management |\n| **alteration_items_summary.php** | Alteration statistics |\n| **gold_silver_*.php** | Gold/silver prices |\n| **bank_*.php** | Bank transactions |\n| **stocks_summary.php** | Stock data |\n| **medication_*.php** | Medication tracking |\n| **payroll_import.php** | Payroll import |\n| **car_maintenance_*.php** | Vehicle maintenance |\n| **duke_*.php** | Duke integration |\n| **reports_*.php** | Report generation |\n| **totals_import.php** | Customer totals import |\n| **documents.php** | Document management |\n| **document_upload.php** | File uploads |\n| **cust_email_*.php** | Email data |\n| **mail_*.php** | Email sending |\n| **reminders_create.php** | Create reminders |\n| **nightly_reports.php** | Nightly reports |\n| **morning_jobs.php** | Morning jobs |\n| **appointment_workflow.php** | Workflow management |\n| **sysadmin.php** | System admin |\n| **reporting_module.php** | Reporting |\n| **job_runs.php** | Job tracking |\n| **health.php** | Health check |\n| **overview.php** | Dashboard data |\n\n---\n\n## 5. External Integrations\n\n### 5.1 Square (Payment Processing)\n- **Purpose:** Point-of-sale payments, receipts, terminal management\n- **Features:**\n  - Square Terminal device pairing/management\n  - Payment processing with tips\n  - Customer payment logging\n  - Sandbox and live environments\n- **Tables:** `backend_square_terminal_code`, `backend_square_terminal_device`, `square_customer_log`\n\n### 5.2 Twilio (SMS)\n- **Purpose:** SMS notifications and reminders\n- **Features:**\n  - Send SMS to customers\n  - Appointment reminders\n  - SMS consent tracking\n- **Settings:** `twilio_sid`, `twilio_token`, `twilio_from`\n\n### 5.3 Setmore (Appointment Booking)\n- **Purpose:** Appointment synchronization\n- **Features:**\n  - Pull appointments from Setmore API\n  - Link to customers/visits\n- **Table:** `setmore_appointments`\n- **Settings:** `setmore_refresh_token`, `setmore_staff_key`\n\n### 5.4 EasyAppointments (Alternative Booking)\n- **Purpose:** Full appointment booking platform\n- **Location:** C:\\code\\customerdb\\schedule\\\n- **Features:**\n  - Customer/provider management\n  - Web-based booking widget\n  - REST API\n\n### 5.5 Telegram (Notifications)\n- **Purpose:** Bot-based notifications\n- **Features:**\n  - Send notifications to channels\n  - Visit alerts\n  - Cron job status\n- **Settings:** `telegram_bot_token`, `telegram_chat_id`\n\n### 5.6 Ollama (AI - Optional)\n- **Purpose:** Local AI for email generation\n- **Settings:** `ollama_url`, `ollama_default_model`\n\n---\n\n## 6. Scheduled Jobs / Cron\n\n### Configured Cron Jobs\n\n| Job Label | Schedule | Purpose |\n|----------|----------|---------|\n| **Next-Day Customer Emails** | `0 20 * * *` (8 PM) | Pickup reminder emails |\n| **Morning Import** | `0 6 * * *` (6 AM) | Morning data import |\n| **Morning Jobs** | `0 9 * * *` (9 AM) | Appointment sync, workflow |\n| **Nightly Reports** | `0 20 * * *` (8 PM) | Generate nightly summaries |\n| **Database Backup** | `0 2 * * *` (2 AM) | Full MariaDB backup |\n| **Daily Cleanup** | `0 4 * * *` (4 AM) | Temp files, old logs |\n| **Auto Delete** | `15 4 * * *` (4:15 AM) | Clean placeholder records |\n\n### Background Job Scripts (backend/jobs/)\n\n| Script | Purpose |\n|--------|---------|\n| **run_morning_jobs.php** | Main morning job runner |\n| **smoke_morning_jobs.php** | Smoke test |\n| **send_nightly_reports.php** | Nightly report emailer |\n| **send_nextday_customer_emails.php** | Next-day reminders |\n| **delete_add_name_records.php** | Cleanup job |\n| **rebuild_customer_totals.php** | Rebuild totals |\n| **rebuild_daily_customer_totals.php** | Rebuild daily totals |\n| **rebuild_payment_ledger.php** | Rebuild payment ledger |\n| **import_customer_totals_csv.php** | CSV import |\n| **backfill_square_customer_log.php** | Square log backfill |\n| **run_cron_job.php** | Generic cron runner |\n\n---\n\n## 7. Web Applications\n\n### 7.1 Front Desk App (port 8895)\n\n| Page | Purpose |\n|------|---------|\n| **index.html** | Main dashboard, search, stats |\n| **customer.html** | Customer detail + visit history |\n| **visit.html** | Create/edit alteration order |\n| **customer_display.html** | Second monitor display |\n| **receipt.html** | Printable receipt |\n| **reports.html** | Order list by status |\n| **upcoming.html** | Next 7 days pickups |\n| **schedule.html** | Appointments calendar |\n| **login.html** | Login page |\n| **item_types.html** | Item type management |\n\n### 7.2 Management App (port 8894)\n\n| Page | Purpose |\n|------|---------|\n| **index.html** | Login page |\n| **webui.html** | Dashboard |\n| **customer.html** | Customer detail view |\n| **admin.html** | Reports browser |\n| **settings.html** | App settings editor |\n| **users.html** | User management |\n| **reports.html** | Order reports |\n\n---\n\n## 8. Settings & Configuration\n\n### app_settings Keys\n\n| Key | Purpose |\n|-----|---------|\n| theme_bg | Page background color |\n| theme_panel | Card/panel color |\n| theme_text | Text color |\n| theme_accent | Accent/button color |\n| theme_accent_deep | Darker accent |\n| theme_teal | Teal color |\n| theme_font | Font family |\n| smtp_host | Email server hostname |\n| smtp_port | Email server port |\n| smtp_secure | tls or ssl |\n| smtp_user | Email login |\n| smtp_pass | Email password |\n| smtp_from_email | From address |\n| smtp_from_name | From display name |\n| twilio_sid | Twilio Account SID |\n| twilio_token | Twilio Auth Token |\n| twilio_from | Twilio phone number |\n| imap_host | Incoming email server |\n| imap_port | IMAP port |\n| imap_ssl | SSL enable |\n| imap_user | IMAP login |\n| imap_pass | IMAP password |\n| square_token | Square API token |\n| square_location | Square location ID |\n| setmore_staff_key | Setmore API key |\n| setmore_refresh | Setmore refresh token |\n| require_report | PDF required |\n| require_signature | Signature required |\n| reports_base_path | Reports disk path |\n| reports_base_url | Reports URL |\n| ollama_url | Ollama AI URL |\n| ollama_default_model | Ollama model |\n| telegram_bot_token | Telegram bot token |\n| telegram_chat_id | Telegram chat ID |\n\n---\n\n## 9. Migration Notes\n\n### Access to MariaDB Workflow\n\n1. **Export source data from Access**\n   - Export ordinary tables to CSV\n   - Export attachment fields with VBA or DAO Recordset2 logic\n   - Keep original IDs during migration\n\n2. **Load into MariaDB staging**\n   - Use `LOAD DATA LOCAL INFILE` for CSV files\n   - Load signatures separately into `visit_signatures`\n\n3. **Normalize**\n   - `CustomerTable` → `customers`\n   - `CustomerVisits` → `visits`\n   - `AlterationItems` → `orders`, `order_items`, `order_item_type_links`\n   - `2024TaxPayments` → `tax_payments`\n   - `AlterationItemsChangeLog` → `change_log`\n\n4. **Signature BLOB path**\n   - Export Access attachment to temp file\n   - Convert BMP to PNG\n   - Insert PNG bytes into `visit_signatures.signature_image`\n\n5. **Validation**\n   - Compare source row counts vs target\n   - Compare distinct legacy IDs\n   - Compare sample signatures by SHA256\n\n---\n\n## 10. Scripts & Tools\n\n### PowerShell Scripts (scripts/)\n\n| Script | Purpose |\n|--------|---------|\n| **import_legacy_totals_from_excel.ps1** | Import totals from Excel |\n| **sync_backend_mirror.ps1** | Sync backend mirror |\n| **check_backend_mirror.ps1** | Check mirror status |\n\n### Python Scripts (scripts/)\n\n| Script | Purpose |\n|--------|---------|\n| **signature_blob_loader.py** | Load signature blobs |\n| **access_to_mariadb_parser.py** | Parse Access to MariaDB |\n| **import_access_v2.py** | Import Access v2 |\n| **import_csv_v2.py** | Import CSV v2 |\n\n### SQL Migrations (migrations/)\n\n| File | Purpose |\n|------|---------|\n| **20260407_add_conversion_job.sql** | Add conversion job table |\n| **20260411_order_items_item_type_name_no_fk.sql** | Order items no FK |\n| **20260416_blog_prompt_templates.sql** | Blog prompt templates |\n\n---\n\n## File Statistics\n\n- **Total PHP files:** 200+\n- **Total SQL files:** 100+\n- **Total HTML pages:** 20+\n- **Database tables:** 30+\n\n---\n\n*End of Documentation*","is_text_editable":1,"can_edit_inline":1}
After
{"backend_document_id":"20","document_type":"upload","title":"Complete Documentation up to date 04-17-2026","slug":"complete-documentation-up-to-date","summary_text":"Complete Documentation up to date 04-17-2026","content_markdown":"# Ella's Alterations - Comprehensive System Documentation\r\n\r\n**Generated:** April 17, 2026\r\n**Location:** C:\\code\\customerdb\r\n\r\n---\r\n\r\n## Table of Contents\r\n\r\n1. [System Overview](#1-system-overview)\r\n2. [Directory Structure](#2-directory-structure)\r\n3. [Database Schema](#3-database-schema)\r\n4. [API Endpoints](#4-api-endpoints)\r\n5. [External Integrations](#5-external-integrations)\r\n6. [Scheduled Jobs / Cron](#6-scheduled-jobs--cron)\r\n7. [Web Applications](#7-web-applications)\r\n8. [Settings & Configuration](#8-settings--configuration)\r\n9. [Migration Notes](#9-migration-notes)\r\n10. [Scripts & Tools](#10-scripts--tools)\r\n\r\n---\r\n\r\n## 1. System Overview\r\n\r\n### Purpose\r\nElla's Alterations is a comprehensive customer relationship management (CRM) andAlteration tracking system for a tailor shop. It manages customers, visits/alteration orders, appointments, payments, and provides integration with external services.\r\n\r\n### Server Information\r\n- **Primary Server:** kefa@192.168.7.202\r\n- **Mirror Drive:** /mnt/drive2 (mirrors /mnt/drive1)\r\n- **Database:** MariaDB - database `ellas_alterations`, user `kefa_admin`\r\n- **Web Server:** Apache 2.4 with mod-php\r\n- **PHP Version:** 8.3\r\n\r\n### Three Web Applications\r\n\r\n| App | Local URL | Public URL | Purpose |\r\n|-----|-----------|------------|---------|\r\n| Front Desk | http://192.168.7.202:8895 | https://ella.floridaalterations.com | Customer-facing operations |\r\n| Management | http://192.168.7.202:8894 | (LAN only) | Reports, admin, settings |\r\n| Scheduler | http://192.168.7.202:8897 | https://schedule.floridaalterations.com | Easy!Appointments booking |\r\n\r\n---\r\n\r\n## 2. Directory Structure\r\n\r\n```\r\ncustomerdb/\r\n├── backend/                    # Main PHP backend API and services\r\n│   ├── api/                    # REST API endpoints (~57 files)\r\n│   ├── bin/                    # Binary/executable scripts\r\n│   ├── backup/                # Backup versions of services\r\n│   └── jobs/                  # Background job scripts\r\n├── frontend/                   # Front Desk app (port 8895)\r\n│   ├── *.html                 # HTML pages\r\n│   ├── api/                   # PHP API endpoints\r\n│   └── reports/               # PDF reports (MMDDYYYY/filename.pdf)\r\n├── webui/                      # Management app (port 8894)\r\n│   ├── *.html                 # HTML pages\r\n│   ├── api/                  # PHP API endpoints\r\n│   ├── backend/               # Backend API copy\r\n│   └── email/                # Email templates\r\n├── schedule/                   # Easy!Appointments installation\r\n├── schema/                    # Database schema files\r\n├── migrations/               # SQL migrations\r\n├── scripts/                   # PowerShell/Python import scripts\r\n├── docs/                     # Documentation\r\n├── blog/                     # Blog system and reengineering\r\n├── csv/                      # CSV data files\r\n├── backups/                  # Backup archives\r\n├── Topaz/                    # Topaz signature pad configs\r\n├── webui/                    # Second web interface\r\n│   ├── api/\r\n│   ├── backend/\r\n│   └── frontend/\r\n├── notused/                  # Deprecated/unused files\r\n└── wordpress-plugin/          # WordPress integration\r\n```\r\n\r\n---\r\n\r\n## 3. Database Schema\r\n\r\n### Core Tables (from mariadb_core_schema.sql)\r\n\r\n#### customers\r\nMain customer registry.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| customer_id | INT UNSIGNED PK | Auto-increment |\r\n| legacy_customer_id | INT NULL | Original Access DB ID |\r\n| created_at | DATETIME | Record creation time |\r\n| full_name | VARCHAR(200) | Customer full name |\r\n| phone | VARCHAR(30) | Formatted (XXX) XXX-XXXX |\r\n| email | VARCHAR(255) | Email address |\r\n| pickup_due_at | DATETIME | Next pickup date (synced from EA) |\r\n| description | TEXT | Description |\r\n| notes | TEXT | Internal notes |\r\n| is_new_customer | TINYINT(1) | 1 if flagged as new |\r\n\r\n#### visits\r\nOne row per alteration job/order.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| visit_id | INT UNSIGNED PK | |\r\n| legacy_visit_id | INT NULL | Original Access DB ID |\r\n| customer_id | INT UNSIGNED FK | → customers |\r\n| visit_date | DATETIME | Drop-off date |\r\n| pickup_date | DATETIME | Expected pickup |\r\n| notes | TEXT | General visit notes |\r\n| customer_name_snapshot | VARCHAR(200) | |\r\n| phone_snapshot | VARCHAR(30) | |\r\n| email_snapshot | VARCHAR(255) | |\r\n| color | VARCHAR(100) | Garment color |\r\n| alterations_needed | TEXT | |\r\n| alterations_notes | TEXT | Detailed alteration instructions |\r\n| alterations_price | DECIMAL(10,2) | Manual price field |\r\n| total_alteration_price | DECIMAL(10,2) | Calculated from items |\r\n| expedited_fee | DECIMAL(10,2) | |\r\n| paid_date | DATETIME | When paid |\r\n| signature_text | TEXT | Text signature (legacy) |\r\n| signature_date | DATETIME | |\r\n| paid_flag | TINYINT(1) | 1 = paid |\r\n| source_key_value | VARCHAR(100) | |\r\n\r\n#### visit_signatures\r\nFull resolution signature images per visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| signature_id | BIGINT UNSIGNED PK | |\r\n| visit_id | INT UNIQUE | One signature per visit |\r\n| signature_date | DATETIME | |\r\n| image_format | VARCHAR(50) | Default 'image/png' |\r\n| original_filename | VARCHAR(255) | |\r\n| original_extension | VARCHAR(20) | |\r\n| file_size_bytes | BIGINT | |\r\n| sha256_hash | CHAR(64) | Hash for verification |\r\n| signature_image | LONGBLOB | Raw PNG binary |\r\n| created_at | DATETIME | |\r\n\r\n#### item_types\r\nMaster list of alteration types (e.g., Hem, Zipper, Taper).\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| item_type_id | INT UNSIGNED PK | |\r\n| type_name | VARCHAR(100) UNIQUE | Display name |\r\n\r\n#### orders\r\nOrders per visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_id | BIGINT UNSIGNED PK | |\r\n| visit_id | INT UNSIGNED FK | → visits |\r\n| customer_id | INT UNSIGNED FK | → customers |\r\n| created_at | DATETIME | |\r\n| no_tax | TINYINT(1) | Tax exempt |\r\n| picked_up | TINYINT(1) | |\r\n| source_table | VARCHAR(50) | |\r\n\r\n#### order_items\r\nLine items for each alteration within a visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_item_id | BIGINT UNSIGNED PK | |\r\n| order_id | BIGINT UNSIGNED FK | → orders |\r\n| legacy_alteration_id | INT NULL | |\r\n| item_type_id | INT FK | → item_types |\r\n| item_type_name | VARCHAR(100) | |\r\n| description | TEXT | |\r\n| quantity | INT | Default 1 |\r\n| unit_price | DECIMAL(10,2) | |\r\n| total_price | DECIMAL(10,2) | |\r\n| notes | TEXT | Per-item notes |\r\n| color | VARCHAR(100) | Garment color |\r\n| no_tax | TINYINT(1) | Tax exempt |\r\n| is_range_price | TINYINT(1) | |\r\n| range_price_label | VARCHAR(100) | |\r\n| paid_flag | TINYINT(1) | |\r\n| paid_type | VARCHAR(100) | |\r\n| picked_up | TINYINT(1) | |\r\n| created_at | DATETIME | |\r\n\r\n#### order_item_type_links\r\nMany-to-many links between order items and item types.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_item_type_link_id | BIGINT UNSIGNED PK | |\r\n| order_item_id | BIGINT UNSIGNED FK | → order_items |\r\n| item_type_id | INT UNSIGNED FK | → item_types |\r\n| slot_number | TINYINT UNSIGNED | |\r\n\r\n#### payments\r\nPayment records per order.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| payment_id | BIGINT UNSIGNED PK | |\r\n| order_id | BIGINT UNSIGNED FK | → orders |\r\n| payment_date | DATETIME | |\r\n| payment_type | VARCHAR(100) | |\r\n| payment_method | VARCHAR(100) | |\r\n| amount | DECIMAL(10,2) | |\r\n| notes | TEXT | |\r\n\r\n#### tax_payments\r\nTax payment records.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| tax_payment_id | INT UNSIGNED PK | |\r\n| legacy_tax_payment_id | INT NULL | |\r\n| payment_date | DATETIME | |\r\n| payment_type | VARCHAR(100) | |\r\n| payment_method | VARCHAR(100) | |\r\n| amount | DECIMAL(10,2) | |\r\n| notes | TEXT | |\r\n| receipt_blob | LONGBLOB | |\r\n\r\n#### change_log\r\nAudit log for changes.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| log_id | BIGINT UNSIGNED PK | |\r\n| legacy_log_id | INT NULL | |\r\n| table_name | VARCHAR(100) | |\r\n| record_id | BIGINT | |\r\n| visit_id | INT | |\r\n| field_name | VARCHAR(100) | |\r\n| old_value | TEXT | |\r\n| new_value | TEXT | |\r\n| changed_at | DATETIME | |\r\n| changed_by | VARCHAR(100) | |\r\n\r\n#### ads\r\nAdvertising/articles.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| ad_id | INT UNSIGNED PK | |\r\n| legacy_ad_id | INT NULL | |\r\n| article_text | TEXT | |\r\n| article_picture | LONGBLOB | |\r\n| site_submitted | VARCHAR(255) | |\r\n| views | INT | Default 0 |\r\n| date_posted | DATETIME | |\r\n\r\n#### staging_* tables\r\nStaging tables for data migration.\r\n\r\n| Table Name | Purpose |\r\n|------------|---------|\r\n| staging_customer_table_raw | Staging for legacy customer data |\r\n| staging_customer_visits_raw | Staging for legacy visits |\r\n| staging_alteration_items_raw | Staging for items |\r\n\r\n### Additional Backend Tables\r\n\r\n| Table Name | Purpose |\r\n|------------|---------|\r\n| setmore_appointments | Synced from Setmore |\r\n| backend_conversion_job | Document conversion jobs |\r\n| backend_job_runs | Background job execution log |\r\n| customer_totals | Daily customer totals |\r\n| daily_customer_totals | Daily summary totals |\r\n| customer_payment_transactions | Payment ledger |\r\n| legacy_customer_totals_monthly | Monthly totals (legacy) |\r\n| legacy_customer_totals_irs_monthly | IRS monthly reports |\r\n| backend_appointment_workflow | Appointment state machine |\r\n| backend_no_show_log | No-show tracking |\r\n| backend_error_log | Error logging |\r\n| backend_change_log | Change audit log |\r\n| backend_document | Document storage |\r\n| backend_document_version | Document version history |\r\n| backend_speed_dial | Quick links |\r\n| backend_square_terminal_code | Square terminal pairing codes |\r\n| backend_square_terminal_device | Square device registry |\r\n| cron_job | Scheduled job definitions |\r\n| cron_job_run | Cron execution history |\r\n| app_settings | Global configuration |\r\n| app_users | Login accounts |\r\n| remember_tokens | \"Remember Me\" tokens |\r\n| customer_reports | PDF report index |\r\n\r\n---\r\n\r\n## 4. API Endpoints\r\n\r\n### 4.1 Frontend API (port 8895 /api/)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **customer_get.php** | Get customer by ID |\r\n| **customer_save.php** | Create or update customer |\r\n| **customer_detail.php** | Customer + visits summary |\r\n| **customer_delete.php** | Delete customer |\r\n| **customer_list_hide.php** | Hide customer from list |\r\n| **search_customers.php** | Search by name/phone |\r\n| **visit_get.php** | Get visit + items |\r\n| **visit_save.php** | Create/update visit + items |\r\n| **visit_delete.php** | Delete visit |\r\n| **visit_report_generate.php** | Generate visit report |\r\n| **item_types.php** | List all alteration types |\r\n| **item_type_add.php** | Add new item type |\r\n| **item_type_update.php** | Update item type |\r\n| **item_type_delete.php** | Delete item type |\r\n| **pickups_today.php** | Orders due today |\r\n| **ready.php** | Orders ready for pickup |\r\n| **overdue.php** | Overdue orders |\r\n| **upcoming.php** | Orders due in next N days |\r\n| **workload_7days.php** | 7-day workload |\r\n| **save_signature.php** | Save canvas signature |\r\n| **reports_list.php** | Reports for customer |\r\n| **attach_reports.php** | Index all PDFs to DB |\r\n| **save_signature.php** | Save signature image |\r\n| **today_appointments_list.php** | Today's appointments |\r\n| **settings_get.php** | Get app settings |\r\n| **settings_save.php** | Save app settings |\r\n| **settings_css.php** | Live theme CSS |\r\n| **send_email.php** | Send email via SMTP |\r\n| **send_sms.php** | Send SMS via Twilio |\r\n| **send_reminders.php** | Send appointment reminders |\r\n| **ea_appointments.php** | EasyAppointments REST API |\r\n| **ea_webhook.php** | Receives EA webhook events |\r\n| **setmore.php** | Setmore API proxy |\r\n| **setmore_to_ea_import.php** | Import customers to EA |\r\n| **square_config.php** | Square public config |\r\n| **square_process.php** | Process Square payment |\r\n| **square_customer_log.php** | Customer Square log |\r\n| **square_terminal.php** | Square terminal |\r\n| **login.php** | Authenticate |\r\n| **logout.php** | Clear session |\r\n| **session_check.php** | Check if logged in |\r\n| **auth.php** | Session authentication |\r\n| **config.php** | App config constants |\r\n| **db.php** | Database connection |\r\n| **log_error.php** | Log client-side error |\r\n| **todo_list.php** | Todo list management |\r\n| **send_telegram.php** | Send Telegram messages |\r\n\r\n### 4.2 Management API (port 8894 /api/)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **login.php** | Authenticate |\r\n| **logout.php** | Clear session |\r\n| **session_check.php** | Check if logged in |\r\n| **customer_detail.php** | Customer + visits |\r\n| **search_customers.php** | Search customers |\r\n| **update_customer.php** | Update customer |\r\n| **users_list.php** | List all users |\r\n| **user_save.php** | Create/update user |\r\n| **list_report_dirs.php** | Date folders |\r\n| **list_report_files.php** | PDFs in folder |\r\n| **report_file.php** | Access report file |\r\n| **pickups_today.php** | Today's pickups |\r\n| **ready.php** | Ready for pickup |\r\n| **overdue.php** | Overdue |\r\n| **settings_get.php** | Get settings |\r\n| **settings_save.php** | Save settings |\r\n| **settings_css.php** | Live CSS theme |\r\n| **imap_list.php** | List IMAP folders |\r\n| **imap_fetch.php** | Fetch emails |\r\n| **imap_send.php** | Send email via IMAP |\r\n| **imap_action.php** | IMAP actions |\r\n| **sms_send_helper.php** | SMS sending helper |\r\n| **sms_webhook_receive.php** | Receive SMS webhooks |\r\n| **sms_inbox_api.php** | SMS inbox API |\r\n| **slideshow_list.php** | Slideshow images |\r\n| **slideshow_upload.php** | Upload slideshow |\r\n| **slideshow_delete.php** | Delete slideshow |\r\n| **users_list.php** | User management |\r\n| **report_list.php** | Report list |\r\n| **debug_filters.php** | Debug filters |\r\n| **sysadmin.php** | System admin |\r\n| **test.php** | Testing endpoint |\r\n\r\n### 4.3 Backend API (C:\\code\\customerdb\\backend\\api\\)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **customer.php** | Get customer details |\r\n| **customers.php** | List/search customers |\r\n| **customer_save.php** | Save/update customer |\r\n| **visit.php** | Get visit details |\r\n| **visit_delete.php** | Delete visit |\r\n| **appointments.php** | Unified appointments |\r\n| **appointments_summary.php** | Appointment statistics |\r\n| **setmore_appointments.php** | Setmore appointments |\r\n| **setmore_import.php** | Import from Setmore |\r\n| **module_*.php** | Module loaders |\r\n| **alteration_items.php** | Alteration management |\r\n| **alteration_items_summary.php** | Alteration statistics |\r\n| **gold_silver_*.php** | Gold/silver prices |\r\n| **bank_*.php** | Bank transactions |\r\n| **stocks_summary.php** | Stock data |\r\n| **medication_*.php** | Medication tracking |\r\n| **payroll_import.php** | Payroll import |\r\n| **car_maintenance_*.php** | Vehicle maintenance |\r\n| **duke_*.php** | Duke integration |\r\n| **reports_*.php** | Report generation |\r\n| **totals_import.php** | Customer totals import |\r\n| **documents.php** | Document management |\r\n| **document_upload.php** | File uploads |\r\n| **cust_email_*.php** | Email data |\r\n| **mail_*.php** | Email sending |\r\n| **reminders_create.php** | Create reminders |\r\n| **nightly_reports.php** | Nightly reports |\r\n| **morning_jobs.php** | Morning jobs |\r\n| **appointment_workflow.php** | Workflow management |\r\n| **sysadmin.php** | System admin |\r\n| **reporting_module.php** | Reporting |\r\n| **job_runs.php** | Job tracking |\r\n| **health.php** | Health check |\r\n| **overview.php** | Dashboard data |\r\n\r\n---\r\n\r\n## 5. External Integrations\r\n\r\n### 5.1 Square (Payment Processing)\r\n- **Purpose:** Point-of-sale payments, receipts, terminal management\r\n- **Features:**\r\n  - Square Terminal device pairing/management\r\n  - Payment processing with tips\r\n  - Customer payment logging\r\n  - Sandbox and live environments\r\n- **Tables:** `backend_square_terminal_code`, `backend_square_terminal_device`, `square_customer_log`\r\n\r\n### 5.2 Twilio (SMS)\r\n- **Purpose:** SMS notifications and reminders\r\n- **Features:**\r\n  - Send SMS to customers\r\n  - Appointment reminders\r\n  - SMS consent tracking\r\n- **Settings:** `twilio_sid`, `twilio_token`, `twilio_from`\r\n\r\n### 5.3 Setmore (Appointment Booking)\r\n- **Purpose:** Appointment synchronization\r\n- **Features:**\r\n  - Pull appointments from Setmore API\r\n  - Link to customers/visits\r\n- **Table:** `setmore_appointments`\r\n- **Settings:** `setmore_refresh_token`, `setmore_staff_key`\r\n\r\n### 5.4 EasyAppointments (Alternative Booking)\r\n- **Purpose:** Full appointment booking platform\r\n- **Location:** C:\\code\\customerdb\\schedule\\\r\n- **Features:**\r\n  - Customer/provider management\r\n  - Web-based booking widget\r\n  - REST API\r\n\r\n### 5.5 Telegram (Notifications)\r\n- **Purpose:** Bot-based notifications\r\n- **Features:**\r\n  - Send notifications to channels\r\n  - Visit alerts\r\n  - Cron job status\r\n- **Settings:** `telegram_bot_token`, `telegram_chat_id`\r\n\r\n### 5.6 Ollama (AI - Optional)\r\n- **Purpose:** Local AI for email generation\r\n- **Settings:** `ollama_url`, `ollama_default_model`\r\n\r\n---\r\n\r\n## 6. Scheduled Jobs / Cron\r\n\r\n### Configured Cron Jobs\r\n\r\n| Job Label | Schedule | Purpose |\r\n|----------|----------|---------|\r\n| **Next-Day Customer Emails** | `0 20 * * *` (8 PM) | Pickup reminder emails |\r\n| **Morning Import** | `0 6 * * *` (6 AM) | Morning data import |\r\n| **Morning Jobs** | `0 9 * * *` (9 AM) | Appointment sync, workflow |\r\n| **Nightly Reports** | `0 20 * * *` (8 PM) | Generate nightly summaries |\r\n| **Database Backup** | `0 2 * * *` (2 AM) | Full MariaDB backup |\r\n| **Daily Cleanup** | `0 4 * * *` (4 AM) | Temp files, old logs |\r\n| **Auto Delete** | `15 4 * * *` (4:15 AM) | Clean placeholder records |\r\n\r\n### Background Job Scripts (backend/jobs/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **run_morning_jobs.php** | Main morning job runner |\r\n| **smoke_morning_jobs.php** | Smoke test |\r\n| **send_nightly_reports.php** | Nightly report emailer |\r\n| **send_nextday_customer_emails.php** | Next-day reminders |\r\n| **delete_add_name_records.php** | Cleanup job |\r\n| **rebuild_customer_totals.php** | Rebuild totals |\r\n| **rebuild_daily_customer_totals.php** | Rebuild daily totals |\r\n| **rebuild_payment_ledger.php** | Rebuild payment ledger |\r\n| **import_customer_totals_csv.php** | CSV import |\r\n| **backfill_square_customer_log.php** | Square log backfill |\r\n| **run_cron_job.php** | Generic cron runner |\r\n\r\n---\r\n\r\n## 7. Web Applications\r\n\r\n### 7.1 Front Desk App (port 8895)\r\n\r\n| Page | Purpose |\r\n|------|---------|\r\n| **index.html** | Main dashboard, search, stats |\r\n| **customer.html** | Customer detail + visit history |\r\n| **visit.html** | Create/edit alteration order |\r\n| **customer_display.html** | Second monitor display |\r\n| **receipt.html** | Printable receipt |\r\n| **reports.html** | Order list by status |\r\n| **upcoming.html** | Next 7 days pickups |\r\n| **schedule.html** | Appointments calendar |\r\n| **login.html** | Login page |\r\n| **item_types.html** | Item type management |\r\n\r\n### 7.2 Management App (port 8894)\r\n\r\n| Page | Purpose |\r\n|------|---------|\r\n| **index.html** | Login page |\r\n| **webui.html** | Dashboard |\r\n| **customer.html** | Customer detail view |\r\n| **admin.html** | Reports browser |\r\n| **settings.html** | App settings editor |\r\n| **users.html** | User management |\r\n| **reports.html** | Order reports |\r\n\r\n---\r\n\r\n## 8. Settings & Configuration\r\n\r\n### app_settings Keys\r\n\r\n| Key | Purpose |\r\n|-----|---------|\r\n| theme_bg | Page background color |\r\n| theme_panel | Card/panel color |\r\n| theme_text | Text color |\r\n| theme_accent | Accent/button color |\r\n| theme_accent_deep | Darker accent |\r\n| theme_teal | Teal color |\r\n| theme_font | Font family |\r\n| smtp_host | Email server hostname |\r\n| smtp_port | Email server port |\r\n| smtp_secure | tls or ssl |\r\n| smtp_user | Email login |\r\n| smtp_pass | Email password |\r\n| smtp_from_email | From address |\r\n| smtp_from_name | From display name |\r\n| twilio_sid | Twilio Account SID |\r\n| twilio_token | Twilio Auth Token |\r\n| twilio_from | Twilio phone number |\r\n| imap_host | Incoming email server |\r\n| imap_port | IMAP port |\r\n| imap_ssl | SSL enable |\r\n| imap_user | IMAP login |\r\n| imap_pass | IMAP password |\r\n| square_token | Square API token |\r\n| square_location | Square location ID |\r\n| setmore_staff_key | Setmore API key |\r\n| setmore_refresh | Setmore refresh token |\r\n| require_report | PDF required |\r\n| require_signature | Signature required |\r\n| reports_base_path | Reports disk path |\r\n| reports_base_url | Reports URL |\r\n| ollama_url | Ollama AI URL |\r\n| ollama_default_model | Ollama model |\r\n| telegram_bot_token | Telegram bot token |\r\n| telegram_chat_id | Telegram chat ID |\r\n\r\n---\r\n\r\n## 9. Migration Notes\r\n\r\n### Access to MariaDB Workflow\r\n\r\n1. **Export source data from Access**\r\n   - Export ordinary tables to CSV\r\n   - Export attachment fields with VBA or DAO Recordset2 logic\r\n   - Keep original IDs during migration\r\n\r\n2. **Load into MariaDB staging**\r\n   - Use `LOAD DATA LOCAL INFILE` for CSV files\r\n   - Load signatures separately into `visit_signatures`\r\n\r\n3. **Normalize**\r\n   - `CustomerTable` → `customers`\r\n   - `CustomerVisits` → `visits`\r\n   - `AlterationItems` → `orders`, `order_items`, `order_item_type_links`\r\n   - `2024TaxPayments` → `tax_payments`\r\n   - `AlterationItemsChangeLog` → `change_log`\r\n\r\n4. **Signature BLOB path**\r\n   - Export Access attachment to temp file\r\n   - Convert BMP to PNG\r\n   - Insert PNG bytes into `visit_signatures.signature_image`\r\n\r\n5. **Validation**\r\n   - Compare source row counts vs target\r\n   - Compare distinct legacy IDs\r\n   - Compare sample signatures by SHA256\r\n\r\n---\r\n\r\n## 10. Scripts & Tools\r\n\r\n### PowerShell Scripts (scripts/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **import_legacy_totals_from_excel.ps1** | Import totals from Excel |\r\n| **sync_backend_mirror.ps1** | Sync backend mirror |\r\n| **check_backend_mirror.ps1** | Check mirror status |\r\n\r\n### Python Scripts (scripts/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **signature_blob_loader.py** | Load signature blobs |\r\n| **access_to_mariadb_parser.py** | Parse Access to MariaDB |\r\n| **import_access_v2.py** | Import Access v2 |\r\n| **import_csv_v2.py** | Import CSV v2 |\r\n\r\n### SQL Migrations (migrations/)\r\n\r\n| File | Purpose |\r\n|------|---------|\r\n| **20260407_add_conversion_job.sql** | Add conversion job table |\r\n| **20260411_order_items_item_type_name_no_fk.sql** | Order items no FK |\r\n| **20260416_blog_prompt_templates.sql** | Blog prompt templates |\r\n\r\n---\r\n\r\n## File Statistics\r\n\r\n- **Total PHP files:** 200+\r\n- **Total SQL files:** 100+\r\n- **Total HTML pages:** 20+\r\n- **Database tables:** 30+\r\n\r\n---\r\n\r\n*End of Documentation*","content_html":"<h1>Ella&#039;s Alterations - Comprehensive System Documentation</h1>\n<p><strong>Generated:</strong> April 17, 2026</p>\n<p><strong>Location:</strong> C:\\code\\customerdb</p>\n<p>---</p>\n<h2>Table of Contents</h2>\n<p>1. [System Overview](#1-system-overview)</p>\n<p>2. [Directory Structure](#2-directory-structure)</p>\n<p>3. [Database Schema](#3-database-schema)</p>\n<p>4. [API Endpoints](#4-api-endpoints)</p>\n<p>5. [External Integrations](#5-external-integrations)</p>\n<p>6. [Scheduled Jobs / Cron](#6-scheduled-jobs--cron)</p>\n<p>7. [Web Applications](#7-web-applications)</p>\n<p>8. [Settings &amp; Configuration](#8-settings--configuration)</p>\n<p>9. [Migration Notes](#9-migration-notes)</p>\n<p>10. [Scripts &amp; Tools](#10-scripts--tools)</p>\n<p>---</p>\n<h2>1. System Overview</h2>\n<h3>Purpose</h3>\n<p>Ella&#039;s Alterations is a comprehensive customer relationship management (CRM) andAlteration tracking system for a tailor shop. It manages customers, visits/alteration orders, appointments, payments, and provides integration with external services.</p>\n<h3>Server Information</h3>\n<ul>\n<li><strong>Primary Server:</strong> kefa@192.168.7.202</li>\n<li><strong>Mirror Drive:</strong> /mnt/drive2 (mirrors /mnt/drive1)</li>\n<li><strong>Database:</strong> MariaDB - database `ellas_alterations`, user `kefa_admin`</li>\n<li><strong>Web Server:</strong> Apache 2.4 with mod-php</li>\n<li><strong>PHP Version:</strong> 8.3</li>\n</ul>\n<h3>Three Web Applications</h3>\n<p>| App | Local URL | Public URL | Purpose |</p>\n<p>|-----|-----------|------------|---------|</p>\n<p>| Front Desk | http://192.168.7.202:8895 | https://ella.floridaalterations.com | Customer-facing operations |</p>\n<p>| Management | http://192.168.7.202:8894 | (LAN only) | Reports, admin, settings |</p>\n<p>| Scheduler | http://192.168.7.202:8897 | https://schedule.floridaalterations.com | Easy!Appointments booking |</p>\n<p>---</p>\n<h2>2. Directory Structure</h2>\n<p>```</p>\n<p>customerdb/</p>\n<p>├── backend/                    # Main PHP backend API and services</p>\n<p>│   ├── api/                    # REST API endpoints (~57 files)</p>\n<p>│   ├── bin/                    # Binary/executable scripts</p>\n<p>│   ├── backup/                # Backup versions of services</p>\n<p>│   └── jobs/                  # Background job scripts</p>\n<p>├── frontend/                   # Front Desk app (port 8895)</p>\n<p>│   ├── *.html                 # HTML pages</p>\n<p>│   ├── api/                   # PHP API endpoints</p>\n<p>│   └── reports/               # PDF reports (MMDDYYYY/filename.pdf)</p>\n<p>├── webui/                      # Management app (port 8894)</p>\n<p>│   ├── *.html                 # HTML pages</p>\n<p>│   ├── api/                  # PHP API endpoints</p>\n<p>│   ├── backend/               # Backend API copy</p>\n<p>│   └── email/                # Email templates</p>\n<p>├── schedule/                   # Easy!Appointments installation</p>\n<p>├── schema/                    # Database schema files</p>\n<p>├── migrations/               # SQL migrations</p>\n<p>├── scripts/                   # PowerShell/Python import scripts</p>\n<p>├── docs/                     # Documentation</p>\n<p>├── blog/                     # Blog system and reengineering</p>\n<p>├── csv/                      # CSV data files</p>\n<p>├── backups/                  # Backup archives</p>\n<p>├── Topaz/                    # Topaz signature pad configs</p>\n<p>├── webui/                    # Second web interface</p>\n<p>│   ├── api/</p>\n<p>│   ├── backend/</p>\n<p>│   └── frontend/</p>\n<p>├── notused/                  # Deprecated/unused files</p>\n<p>└── wordpress-plugin/          # WordPress integration</p>\n<p>```</p>\n<p>---</p>\n<h2>3. Database Schema</h2>\n<h3>Core Tables (from mariadb_core_schema.sql)</h3>\n<p>#### customers</p>\n<p>Main customer registry.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| customer_id | INT UNSIGNED PK | Auto-increment |</p>\n<p>| legacy_customer_id | INT NULL | Original Access DB ID |</p>\n<p>| created_at | DATETIME | Record creation time |</p>\n<p>| full_name | VARCHAR(200) | Customer full name |</p>\n<p>| phone | VARCHAR(30) | Formatted (XXX) XXX-XXXX |</p>\n<p>| email | VARCHAR(255) | Email address |</p>\n<p>| pickup_due_at | DATETIME | Next pickup date (synced from EA) |</p>\n<p>| description | TEXT | Description |</p>\n<p>| notes | TEXT | Internal notes |</p>\n<p>| is_new_customer | TINYINT(1) | 1 if flagged as new |</p>\n<p>#### visits</p>\n<p>One row per alteration job/order.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| visit_id | INT UNSIGNED PK | |</p>\n<p>| legacy_visit_id | INT NULL | Original Access DB ID |</p>\n<p>| customer_id | INT UNSIGNED FK | → customers |</p>\n<p>| visit_date | DATETIME | Drop-off date |</p>\n<p>| pickup_date | DATETIME | Expected pickup |</p>\n<p>| notes | TEXT | General visit notes |</p>\n<p>| customer_name_snapshot | VARCHAR(200) | |</p>\n<p>| phone_snapshot | VARCHAR(30) | |</p>\n<p>| email_snapshot | VARCHAR(255) | |</p>\n<p>| color | VARCHAR(100) | Garment color |</p>\n<p>| alterations_needed | TEXT | |</p>\n<p>| alterations_notes | TEXT | Detailed alteration instructions |</p>\n<p>| alterations_price | DECIMAL(10,2) | Manual price field |</p>\n<p>| total_alteration_price | DECIMAL(10,2) | Calculated from items |</p>\n<p>| expedited_fee | DECIMAL(10,2) | |</p>\n<p>| paid_date | DATETIME | When paid |</p>\n<p>| signature_text | TEXT | Text signature (legacy) |</p>\n<p>| signature_date | DATETIME | |</p>\n<p>| paid_flag | TINYINT(1) | 1 = paid |</p>\n<p>| source_key_value | VARCHAR(100) | |</p>\n<p>#### visit_signatures</p>\n<p>Full resolution signature images per visit.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| signature_id | BIGINT UNSIGNED PK | |</p>\n<p>| visit_id | INT UNIQUE | One signature per visit |</p>\n<p>| signature_date | DATETIME | |</p>\n<p>| image_format | VARCHAR(50) | Default &#039;image/png&#039; |</p>\n<p>| original_filename | VARCHAR(255) | |</p>\n<p>| original_extension | VARCHAR(20) | |</p>\n<p>| file_size_bytes | BIGINT | |</p>\n<p>| sha256_hash | CHAR(64) | Hash for verification |</p>\n<p>| signature_image | LONGBLOB | Raw PNG binary |</p>\n<p>| created_at | DATETIME | |</p>\n<p>#### item_types</p>\n<p>Master list of alteration types (e.g., Hem, Zipper, Taper).</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| item_type_id | INT UNSIGNED PK | |</p>\n<p>| type_name | VARCHAR(100) UNIQUE | Display name |</p>\n<p>#### orders</p>\n<p>Orders per visit.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| order_id | BIGINT UNSIGNED PK | |</p>\n<p>| visit_id | INT UNSIGNED FK | → visits |</p>\n<p>| customer_id | INT UNSIGNED FK | → customers |</p>\n<p>| created_at | DATETIME | |</p>\n<p>| no_tax | TINYINT(1) | Tax exempt |</p>\n<p>| picked_up | TINYINT(1) | |</p>\n<p>| source_table | VARCHAR(50) | |</p>\n<p>#### order_items</p>\n<p>Line items for each alteration within a visit.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| order_item_id | BIGINT UNSIGNED PK | |</p>\n<p>| order_id | BIGINT UNSIGNED FK | → orders |</p>\n<p>| legacy_alteration_id | INT NULL | |</p>\n<p>| item_type_id | INT FK | → item_types |</p>\n<p>| item_type_name | VARCHAR(100) | |</p>\n<p>| description | TEXT | |</p>\n<p>| quantity | INT | Default 1 |</p>\n<p>| unit_price | DECIMAL(10,2) | |</p>\n<p>| total_price | DECIMAL(10,2) | |</p>\n<p>| notes | TEXT | Per-item notes |</p>\n<p>| color | VARCHAR(100) | Garment color |</p>\n<p>| no_tax | TINYINT(1) | Tax exempt |</p>\n<p>| is_range_price | TINYINT(1) | |</p>\n<p>| range_price_label | VARCHAR(100) | |</p>\n<p>| paid_flag | TINYINT(1) | |</p>\n<p>| paid_type | VARCHAR(100) | |</p>\n<p>| picked_up | TINYINT(1) | |</p>\n<p>| created_at | DATETIME | |</p>\n<p>#### order_item_type_links</p>\n<p>Many-to-many links between order items and item types.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| order_item_type_link_id | BIGINT UNSIGNED PK | |</p>\n<p>| order_item_id | BIGINT UNSIGNED FK | → order_items |</p>\n<p>| item_type_id | INT UNSIGNED FK | → item_types |</p>\n<p>| slot_number | TINYINT UNSIGNED | |</p>\n<p>#### payments</p>\n<p>Payment records per order.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| payment_id | BIGINT UNSIGNED PK | |</p>\n<p>| order_id | BIGINT UNSIGNED FK | → orders |</p>\n<p>| payment_date | DATETIME | |</p>\n<p>| payment_type | VARCHAR(100) | |</p>\n<p>| payment_method | VARCHAR(100) | |</p>\n<p>| amount | DECIMAL(10,2) | |</p>\n<p>| notes | TEXT | |</p>\n<p>#### tax_payments</p>\n<p>Tax payment records.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| tax_payment_id | INT UNSIGNED PK | |</p>\n<p>| legacy_tax_payment_id | INT NULL | |</p>\n<p>| payment_date | DATETIME | |</p>\n<p>| payment_type | VARCHAR(100) | |</p>\n<p>| payment_method | VARCHAR(100) | |</p>\n<p>| amount | DECIMAL(10,2) | |</p>\n<p>| notes | TEXT | |</p>\n<p>| receipt_blob | LONGBLOB | |</p>\n<p>#### change_log</p>\n<p>Audit log for changes.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| log_id | BIGINT UNSIGNED PK | |</p>\n<p>| legacy_log_id | INT NULL | |</p>\n<p>| table_name | VARCHAR(100) | |</p>\n<p>| record_id | BIGINT | |</p>\n<p>| visit_id | INT | |</p>\n<p>| field_name | VARCHAR(100) | |</p>\n<p>| old_value | TEXT | |</p>\n<p>| new_value | TEXT | |</p>\n<p>| changed_at | DATETIME | |</p>\n<p>| changed_by | VARCHAR(100) | |</p>\n<p>#### ads</p>\n<p>Advertising/articles.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| ad_id | INT UNSIGNED PK | |</p>\n<p>| legacy_ad_id | INT NULL | |</p>\n<p>| article_text | TEXT | |</p>\n<p>| article_picture | LONGBLOB | |</p>\n<p>| site_submitted | VARCHAR(255) | |</p>\n<p>| views | INT | Default 0 |</p>\n<p>| date_posted | DATETIME | |</p>\n<p>#### staging_* tables</p>\n<p>Staging tables for data migration.</p>\n<p>| Table Name | Purpose |</p>\n<p>|------------|---------|</p>\n<p>| staging_customer_table_raw | Staging for legacy customer data |</p>\n<p>| staging_customer_visits_raw | Staging for legacy visits |</p>\n<p>| staging_alteration_items_raw | Staging for items |</p>\n<h3>Additional Backend Tables</h3>\n<p>| Table Name | Purpose |</p>\n<p>|------------|---------|</p>\n<p>| setmore_appointments | Synced from Setmore |</p>\n<p>| backend_conversion_job | Document conversion jobs |</p>\n<p>| backend_job_runs | Background job execution log |</p>\n<p>| customer_totals | Daily customer totals |</p>\n<p>| daily_customer_totals | Daily summary totals |</p>\n<p>| customer_payment_transactions | Payment ledger |</p>\n<p>| legacy_customer_totals_monthly | Monthly totals (legacy) |</p>\n<p>| legacy_customer_totals_irs_monthly | IRS monthly reports |</p>\n<p>| backend_appointment_workflow | Appointment state machine |</p>\n<p>| backend_no_show_log | No-show tracking |</p>\n<p>| backend_error_log | Error logging |</p>\n<p>| backend_change_log | Change audit log |</p>\n<p>| backend_document | Document storage |</p>\n<p>| backend_document_version | Document version history |</p>\n<p>| backend_speed_dial | Quick links |</p>\n<p>| backend_square_terminal_code | Square terminal pairing codes |</p>\n<p>| backend_square_terminal_device | Square device registry |</p>\n<p>| cron_job | Scheduled job definitions |</p>\n<p>| cron_job_run | Cron execution history |</p>\n<p>| app_settings | Global configuration |</p>\n<p>| app_users | Login accounts |</p>\n<p>| remember_tokens | &quot;Remember Me&quot; tokens |</p>\n<p>| customer_reports | PDF report index |</p>\n<p>---</p>\n<h2>4. API Endpoints</h2>\n<h3>4.1 Frontend API (port 8895 /api/)</h3>\n<p>| Endpoint File | Purpose |</p>\n<p>|---------------|---------|</p>\n<p>| <strong>customer_get.php</strong> | Get customer by ID |</p>\n<p>| <strong>customer_save.php</strong> | Create or update customer |</p>\n<p>| <strong>customer_detail.php</strong> | Customer + visits summary |</p>\n<p>| <strong>customer_delete.php</strong> | Delete customer |</p>\n<p>| <strong>customer_list_hide.php</strong> | Hide customer from list |</p>\n<p>| <strong>search_customers.php</strong> | Search by name/phone |</p>\n<p>| <strong>visit_get.php</strong> | Get visit + items |</p>\n<p>| <strong>visit_save.php</strong> | Create/update visit + items |</p>\n<p>| <strong>visit_delete.php</strong> | Delete visit |</p>\n<p>| <strong>visit_report_generate.php</strong> | Generate visit report |</p>\n<p>| <strong>item_types.php</strong> | List all alteration types |</p>\n<p>| <strong>item_type_add.php</strong> | Add new item type |</p>\n<p>| <strong>item_type_update.php</strong> | Update item type |</p>\n<p>| <strong>item_type_delete.php</strong> | Delete item type |</p>\n<p>| <strong>pickups_today.php</strong> | Orders due today |</p>\n<p>| <strong>ready.php</strong> | Orders ready for pickup |</p>\n<p>| <strong>overdue.php</strong> | Overdue orders |</p>\n<p>| <strong>upcoming.php</strong> | Orders due in next N days |</p>\n<p>| <strong>workload_7days.php</strong> | 7-day workload |</p>\n<p>| <strong>save_signature.php</strong> | Save canvas signature |</p>\n<p>| <strong>reports_list.php</strong> | Reports for customer |</p>\n<p>| <strong>attach_reports.php</strong> | Index all PDFs to DB |</p>\n<p>| <strong>save_signature.php</strong> | Save signature image |</p>\n<p>| <strong>today_appointments_list.php</strong> | Today&#039;s appointments |</p>\n<p>| <strong>settings_get.php</strong> | Get app settings |</p>\n<p>| <strong>settings_save.php</strong> | Save app settings |</p>\n<p>| <strong>settings_css.php</strong> | Live theme CSS |</p>\n<p>| <strong>send_email.php</strong> | Send email via SMTP |</p>\n<p>| <strong>send_sms.php</strong> | Send SMS via Twilio |</p>\n<p>| <strong>send_reminders.php</strong> | Send appointment reminders |</p>\n<p>| <strong>ea_appointments.php</strong> | EasyAppointments REST API |</p>\n<p>| <strong>ea_webhook.php</strong> | Receives EA webhook events |</p>\n<p>| <strong>setmore.php</strong> | Setmore API proxy |</p>\n<p>| <strong>setmore_to_ea_import.php</strong> | Import customers to EA |</p>\n<p>| <strong>square_config.php</strong> | Square public config |</p>\n<p>| <strong>square_process.php</strong> | Process Square payment |</p>\n<p>| <strong>square_customer_log.php</strong> | Customer Square log |</p>\n<p>| <strong>square_terminal.php</strong> | Square terminal |</p>\n<p>| <strong>login.php</strong> | Authenticate |</p>\n<p>| <strong>logout.php</strong> | Clear session |</p>\n<p>| <strong>session_check.php</strong> | Check if logged in |</p>\n<p>| <strong>auth.php</strong> | Session authentication |</p>\n<p>| <strong>config.php</strong> | App config constants |</p>\n<p>| <strong>db.php</strong> | Database connection |</p>\n<p>| <strong>log_error.php</strong> | Log client-side error |</p>\n<p>| <strong>todo_list.php</strong> | Todo list management |</p>\n<p>| <strong>send_telegram.php</strong> | Send Telegram messages |</p>\n<h3>4.2 Management API (port 8894 /api/)</h3>\n<p>| Endpoint File | Purpose |</p>\n<p>|---------------|---------|</p>\n<p>| <strong>login.php</strong> | Authenticate |</p>\n<p>| <strong>logout.php</strong> | Clear session |</p>\n<p>| <strong>session_check.php</strong> | Check if logged in |</p>\n<p>| <strong>customer_detail.php</strong> | Customer + visits |</p>\n<p>| <strong>search_customers.php</strong> | Search customers |</p>\n<p>| <strong>update_customer.php</strong> | Update customer |</p>\n<p>| <strong>users_list.php</strong> | List all users |</p>\n<p>| <strong>user_save.php</strong> | Create/update user |</p>\n<p>| <strong>list_report_dirs.php</strong> | Date folders |</p>\n<p>| <strong>list_report_files.php</strong> | PDFs in folder |</p>\n<p>| <strong>report_file.php</strong> | Access report file |</p>\n<p>| <strong>pickups_today.php</strong> | Today&#039;s pickups |</p>\n<p>| <strong>ready.php</strong> | Ready for pickup |</p>\n<p>| <strong>overdue.php</strong> | Overdue |</p>\n<p>| <strong>settings_get.php</strong> | Get settings |</p>\n<p>| <strong>settings_save.php</strong> | Save settings |</p>\n<p>| <strong>settings_css.php</strong> | Live CSS theme |</p>\n<p>| <strong>imap_list.php</strong> | List IMAP folders |</p>\n<p>| <strong>imap_fetch.php</strong> | Fetch emails |</p>\n<p>| <strong>imap_send.php</strong> | Send email via IMAP |</p>\n<p>| <strong>imap_action.php</strong> | IMAP actions |</p>\n<p>| <strong>sms_send_helper.php</strong> | SMS sending helper |</p>\n<p>| <strong>sms_webhook_receive.php</strong> | Receive SMS webhooks |</p>\n<p>| <strong>sms_inbox_api.php</strong> | SMS inbox API |</p>\n<p>| <strong>slideshow_list.php</strong> | Slideshow images |</p>\n<p>| <strong>slideshow_upload.php</strong> | Upload slideshow |</p>\n<p>| <strong>slideshow_delete.php</strong> | Delete slideshow |</p>\n<p>| <strong>users_list.php</strong> | User management |</p>\n<p>| <strong>report_list.php</strong> | Report list |</p>\n<p>| <strong>debug_filters.php</strong> | Debug filters |</p>\n<p>| <strong>sysadmin.php</strong> | System admin |</p>\n<p>| <strong>test.php</strong> | Testing endpoint |</p>\n<h3>4.3 Backend API (C:\\code\\customerdb\\backend\\api\\)</h3>\n<p>| Endpoint File | Purpose |</p>\n<p>|---------------|---------|</p>\n<p>| <strong>customer.php</strong> | Get customer details |</p>\n<p>| <strong>customers.php</strong> | List/search customers |</p>\n<p>| <strong>customer_save.php</strong> | Save/update customer |</p>\n<p>| <strong>visit.php</strong> | Get visit details |</p>\n<p>| <strong>visit_delete.php</strong> | Delete visit |</p>\n<p>| <strong>appointments.php</strong> | Unified appointments |</p>\n<p>| <strong>appointments_summary.php</strong> | Appointment statistics |</p>\n<p>| <strong>setmore_appointments.php</strong> | Setmore appointments |</p>\n<p>| <strong>setmore_import.php</strong> | Import from Setmore |</p>\n<p>| <strong>module_*.php</strong> | Module loaders |</p>\n<p>| <strong>alteration_items.php</strong> | Alteration management |</p>\n<p>| <strong>alteration_items_summary.php</strong> | Alteration statistics |</p>\n<p>| <strong>gold_silver_*.php</strong> | Gold/silver prices |</p>\n<p>| <strong>bank_*.php</strong> | Bank transactions |</p>\n<p>| <strong>stocks_summary.php</strong> | Stock data |</p>\n<p>| <strong>medication_*.php</strong> | Medication tracking |</p>\n<p>| <strong>payroll_import.php</strong> | Payroll import |</p>\n<p>| <strong>car_maintenance_*.php</strong> | Vehicle maintenance |</p>\n<p>| <strong>duke_*.php</strong> | Duke integration |</p>\n<p>| <strong>reports_*.php</strong> | Report generation |</p>\n<p>| <strong>totals_import.php</strong> | Customer totals import |</p>\n<p>| <strong>documents.php</strong> | Document management |</p>\n<p>| <strong>document_upload.php</strong> | File uploads |</p>\n<p>| <strong>cust_email_*.php</strong> | Email data |</p>\n<p>| <strong>mail_*.php</strong> | Email sending |</p>\n<p>| <strong>reminders_create.php</strong> | Create reminders |</p>\n<p>| <strong>nightly_reports.php</strong> | Nightly reports |</p>\n<p>| <strong>morning_jobs.php</strong> | Morning jobs |</p>\n<p>| <strong>appointment_workflow.php</strong> | Workflow management |</p>\n<p>| <strong>sysadmin.php</strong> | System admin |</p>\n<p>| <strong>reporting_module.php</strong> | Reporting |</p>\n<p>| <strong>job_runs.php</strong> | Job tracking |</p>\n<p>| <strong>health.php</strong> | Health check |</p>\n<p>| <strong>overview.php</strong> | Dashboard data |</p>\n<p>---</p>\n<h2>5. External Integrations</h2>\n<h3>5.1 Square (Payment Processing)</h3>\n<ul>\n<li><strong>Purpose:</strong> Point-of-sale payments, receipts, terminal management</li>\n<li><strong>Features:</strong></li>\n<li>Square Terminal device pairing/management</li>\n<li>Payment processing with tips</li>\n<li>Customer payment logging</li>\n<li>Sandbox and live environments</li>\n<li><strong>Tables:</strong> `backend_square_terminal_code`, `backend_square_terminal_device`, `square_customer_log`</li>\n</ul>\n<h3>5.2 Twilio (SMS)</h3>\n<ul>\n<li><strong>Purpose:</strong> SMS notifications and reminders</li>\n<li><strong>Features:</strong></li>\n<li>Send SMS to customers</li>\n<li>Appointment reminders</li>\n<li>SMS consent tracking</li>\n<li><strong>Settings:</strong> `twilio_sid`, `twilio_token`, `twilio_from`</li>\n</ul>\n<h3>5.3 Setmore (Appointment Booking)</h3>\n<ul>\n<li><strong>Purpose:</strong> Appointment synchronization</li>\n<li><strong>Features:</strong></li>\n<li>Pull appointments from Setmore API</li>\n<li>Link to customers/visits</li>\n<li><strong>Table:</strong> `setmore_appointments`</li>\n<li><strong>Settings:</strong> `setmore_refresh_token`, `setmore_staff_key`</li>\n</ul>\n<h3>5.4 EasyAppointments (Alternative Booking)</h3>\n<ul>\n<li><strong>Purpose:</strong> Full appointment booking platform</li>\n<li><strong>Location:</strong> C:\\code\\customerdb\\schedule\\</li>\n<li><strong>Features:</strong></li>\n<li>Customer/provider management</li>\n<li>Web-based booking widget</li>\n<li>REST API</li>\n</ul>\n<h3>5.5 Telegram (Notifications)</h3>\n<ul>\n<li><strong>Purpose:</strong> Bot-based notifications</li>\n<li><strong>Features:</strong></li>\n<li>Send notifications to channels</li>\n<li>Visit alerts</li>\n<li>Cron job status</li>\n<li><strong>Settings:</strong> `telegram_bot_token`, `telegram_chat_id`</li>\n</ul>\n<h3>5.6 Ollama (AI - Optional)</h3>\n<ul>\n<li><strong>Purpose:</strong> Local AI for email generation</li>\n<li><strong>Settings:</strong> `ollama_url`, `ollama_default_model`</li>\n</ul>\n<p>---</p>\n<h2>6. Scheduled Jobs / Cron</h2>\n<h3>Configured Cron Jobs</h3>\n<p>| Job Label | Schedule | Purpose |</p>\n<p>|----------|----------|---------|</p>\n<p>| <strong>Next-Day Customer Emails</strong> | `0 20 <em> </em> *` (8 PM) | Pickup reminder emails |</p>\n<p>| <strong>Morning Import</strong> | `0 6 <em> </em> *` (6 AM) | Morning data import |</p>\n<p>| <strong>Morning Jobs</strong> | `0 9 <em> </em> *` (9 AM) | Appointment sync, workflow |</p>\n<p>| <strong>Nightly Reports</strong> | `0 20 <em> </em> *` (8 PM) | Generate nightly summaries |</p>\n<p>| <strong>Database Backup</strong> | `0 2 <em> </em> *` (2 AM) | Full MariaDB backup |</p>\n<p>| <strong>Daily Cleanup</strong> | `0 4 <em> </em> *` (4 AM) | Temp files, old logs |</p>\n<p>| <strong>Auto Delete</strong> | `15 4 <em> </em> *` (4:15 AM) | Clean placeholder records |</p>\n<h3>Background Job Scripts (backend/jobs/)</h3>\n<p>| Script | Purpose |</p>\n<p>|--------|---------|</p>\n<p>| <strong>run_morning_jobs.php</strong> | Main morning job runner |</p>\n<p>| <strong>smoke_morning_jobs.php</strong> | Smoke test |</p>\n<p>| <strong>send_nightly_reports.php</strong> | Nightly report emailer |</p>\n<p>| <strong>send_nextday_customer_emails.php</strong> | Next-day reminders |</p>\n<p>| <strong>delete_add_name_records.php</strong> | Cleanup job |</p>\n<p>| <strong>rebuild_customer_totals.php</strong> | Rebuild totals |</p>\n<p>| <strong>rebuild_daily_customer_totals.php</strong> | Rebuild daily totals |</p>\n<p>| <strong>rebuild_payment_ledger.php</strong> | Rebuild payment ledger |</p>\n<p>| <strong>import_customer_totals_csv.php</strong> | CSV import |</p>\n<p>| <strong>backfill_square_customer_log.php</strong> | Square log backfill |</p>\n<p>| <strong>run_cron_job.php</strong> | Generic cron runner |</p>\n<p>---</p>\n<h2>7. Web Applications</h2>\n<h3>7.1 Front Desk App (port 8895)</h3>\n<p>| Page | Purpose |</p>\n<p>|------|---------|</p>\n<p>| <strong>index.html</strong> | Main dashboard, search, stats |</p>\n<p>| <strong>customer.html</strong> | Customer detail + visit history |</p>\n<p>| <strong>visit.html</strong> | Create/edit alteration order |</p>\n<p>| <strong>customer_display.html</strong> | Second monitor display |</p>\n<p>| <strong>receipt.html</strong> | Printable receipt |</p>\n<p>| <strong>reports.html</strong> | Order list by status |</p>\n<p>| <strong>upcoming.html</strong> | Next 7 days pickups |</p>\n<p>| <strong>schedule.html</strong> | Appointments calendar |</p>\n<p>| <strong>login.html</strong> | Login page |</p>\n<p>| <strong>item_types.html</strong> | Item type management |</p>\n<h3>7.2 Management App (port 8894)</h3>\n<p>| Page | Purpose |</p>\n<p>|------|---------|</p>\n<p>| <strong>index.html</strong> | Login page |</p>\n<p>| <strong>webui.html</strong> | Dashboard |</p>\n<p>| <strong>customer.html</strong> | Customer detail view |</p>\n<p>| <strong>admin.html</strong> | Reports browser |</p>\n<p>| <strong>settings.html</strong> | App settings editor |</p>\n<p>| <strong>users.html</strong> | User management |</p>\n<p>| <strong>reports.html</strong> | Order reports |</p>\n<p>---</p>\n<h2>8. Settings &amp; Configuration</h2>\n<h3>app_settings Keys</h3>\n<p>| Key | Purpose |</p>\n<p>|-----|---------|</p>\n<p>| theme_bg | Page background color |</p>\n<p>| theme_panel | Card/panel color |</p>\n<p>| theme_text | Text color |</p>\n<p>| theme_accent | Accent/button color |</p>\n<p>| theme_accent_deep | Darker accent |</p>\n<p>| theme_teal | Teal color |</p>\n<p>| theme_font | Font family |</p>\n<p>| smtp_host | Email server hostname |</p>\n<p>| smtp_port | Email server port |</p>\n<p>| smtp_secure | tls or ssl |</p>\n<p>| smtp_user | Email login |</p>\n<p>| smtp_pass | Email password |</p>\n<p>| smtp_from_email | From address |</p>\n<p>| smtp_from_name | From display name |</p>\n<p>| twilio_sid | Twilio Account SID |</p>\n<p>| twilio_token | Twilio Auth Token |</p>\n<p>| twilio_from | Twilio phone number |</p>\n<p>| imap_host | Incoming email server |</p>\n<p>| imap_port | IMAP port |</p>\n<p>| imap_ssl | SSL enable |</p>\n<p>| imap_user | IMAP login |</p>\n<p>| imap_pass | IMAP password |</p>\n<p>| square_token | Square API token |</p>\n<p>| square_location | Square location ID |</p>\n<p>| setmore_staff_key | Setmore API key |</p>\n<p>| setmore_refresh | Setmore refresh token |</p>\n<p>| require_report | PDF required |</p>\n<p>| require_signature | Signature required |</p>\n<p>| reports_base_path | Reports disk path |</p>\n<p>| reports_base_url | Reports URL |</p>\n<p>| ollama_url | Ollama AI URL |</p>\n<p>| ollama_default_model | Ollama model |</p>\n<p>| telegram_bot_token | Telegram bot token |</p>\n<p>| telegram_chat_id | Telegram chat ID |</p>\n<p>---</p>\n<h2>9. Migration Notes</h2>\n<h3>Access to MariaDB Workflow</h3>\n<p>1. <strong>Export source data from Access</strong></p>\n<ul>\n<li>Export ordinary tables to CSV</li>\n<li>Export attachment fields with VBA or DAO Recordset2 logic</li>\n<li>Keep original IDs during migration</li>\n</ul>\n<p>2. <strong>Load into MariaDB staging</strong></p>\n<ul>\n<li>Use `LOAD DATA LOCAL INFILE` for CSV files</li>\n<li>Load signatures separately into `visit_signatures`</li>\n</ul>\n<p>3. <strong>Normalize</strong></p>\n<ul>\n<li>`CustomerTable` → `customers`</li>\n<li>`CustomerVisits` → `visits`</li>\n<li>`AlterationItems` → `orders`, `order_items`, `order_item_type_links`</li>\n<li>`2024TaxPayments` → `tax_payments`</li>\n<li>`AlterationItemsChangeLog` → `change_log`</li>\n</ul>\n<p>4. <strong>Signature BLOB path</strong></p>\n<ul>\n<li>Export Access attachment to temp file</li>\n<li>Convert BMP to PNG</li>\n<li>Insert PNG bytes into `visit_signatures.signature_image`</li>\n</ul>\n<p>5. <strong>Validation</strong></p>\n<ul>\n<li>Compare source row counts vs target</li>\n<li>Compare distinct legacy IDs</li>\n<li>Compare sample signatures by SHA256</li>\n</ul>\n<p>---</p>\n<h2>10. Scripts &amp; Tools</h2>\n<h3>PowerShell Scripts (scripts/)</h3>\n<p>| Script | Purpose |</p>\n<p>|--------|---------|</p>\n<p>| <strong>import_legacy_totals_from_excel.ps1</strong> | Import totals from Excel |</p>\n<p>| <strong>sync_backend_mirror.ps1</strong> | Sync backend mirror |</p>\n<p>| <strong>check_backend_mirror.ps1</strong> | Check mirror status |</p>\n<h3>Python Scripts (scripts/)</h3>\n<p>| Script | Purpose |</p>\n<p>|--------|---------|</p>\n<p>| <strong>signature_blob_loader.py</strong> | Load signature blobs |</p>\n<p>| <strong>access_to_mariadb_parser.py</strong> | Parse Access to MariaDB |</p>\n<p>| <strong>import_access_v2.py</strong> | Import Access v2 |</p>\n<p>| <strong>import_csv_v2.py</strong> | Import CSV v2 |</p>\n<h3>SQL Migrations (migrations/)</h3>\n<p>| File | Purpose |</p>\n<p>|------|---------|</p>\n<p>| <strong>20260407_add_conversion_job.sql</strong> | Add conversion job table |</p>\n<p>| <strong>20260411_order_items_item_type_name_no_fk.sql</strong> | Order items no FK |</p>\n<p>| <strong>20260416_blog_prompt_templates.sql</strong> | Blog prompt templates |</p>\n<p>---</p>\n<h2>File Statistics</h2>\n<ul>\n<li><strong>Total PHP files:</strong> 200+</li>\n<li><strong>Total SQL files:</strong> 100+</li>\n<li><strong>Total HTML pages:</strong> 20+</li>\n<li><strong>Database tables:</strong> 30+</li>\n</ul>\n<p>---</p>\n<p><em>End of Documentation</em></p>","file_name":"COMPREHENSIVE_DOCUMENTATION.md","stored_name":"20260417-160828-6006d4f1.md","mime_type":"application/octet-stream","file_size_bytes":"22313","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260417-160828-6006d4f1.md","is_deleted":"0","created_at":"2026-04-17 12:08:29","updated_at":"2026-04-17 12:08:52","editor_content":"# Ella's Alterations - Comprehensive System Documentation\r\n\r\n**Generated:** April 17, 2026\r\n**Location:** C:\\code\\customerdb\r\n\r\n---\r\n\r\n## Table of Contents\r\n\r\n1. [System Overview](#1-system-overview)\r\n2. [Directory Structure](#2-directory-structure)\r\n3. [Database Schema](#3-database-schema)\r\n4. [API Endpoints](#4-api-endpoints)\r\n5. [External Integrations](#5-external-integrations)\r\n6. [Scheduled Jobs / Cron](#6-scheduled-jobs--cron)\r\n7. [Web Applications](#7-web-applications)\r\n8. [Settings & Configuration](#8-settings--configuration)\r\n9. [Migration Notes](#9-migration-notes)\r\n10. [Scripts & Tools](#10-scripts--tools)\r\n\r\n---\r\n\r\n## 1. System Overview\r\n\r\n### Purpose\r\nElla's Alterations is a comprehensive customer relationship management (CRM) andAlteration tracking system for a tailor shop. It manages customers, visits/alteration orders, appointments, payments, and provides integration with external services.\r\n\r\n### Server Information\r\n- **Primary Server:** kefa@192.168.7.202\r\n- **Mirror Drive:** /mnt/drive2 (mirrors /mnt/drive1)\r\n- **Database:** MariaDB - database `ellas_alterations`, user `kefa_admin`\r\n- **Web Server:** Apache 2.4 with mod-php\r\n- **PHP Version:** 8.3\r\n\r\n### Three Web Applications\r\n\r\n| App | Local URL | Public URL | Purpose |\r\n|-----|-----------|------------|---------|\r\n| Front Desk | http://192.168.7.202:8895 | https://ella.floridaalterations.com | Customer-facing operations |\r\n| Management | http://192.168.7.202:8894 | (LAN only) | Reports, admin, settings |\r\n| Scheduler | http://192.168.7.202:8897 | https://schedule.floridaalterations.com | Easy!Appointments booking |\r\n\r\n---\r\n\r\n## 2. Directory Structure\r\n\r\n```\r\ncustomerdb/\r\n├── backend/                    # Main PHP backend API and services\r\n│   ├── api/                    # REST API endpoints (~57 files)\r\n│   ├── bin/                    # Binary/executable scripts\r\n│   ├── backup/                # Backup versions of services\r\n│   └── jobs/                  # Background job scripts\r\n├── frontend/                   # Front Desk app (port 8895)\r\n│   ├── *.html                 # HTML pages\r\n│   ├── api/                   # PHP API endpoints\r\n│   └── reports/               # PDF reports (MMDDYYYY/filename.pdf)\r\n├── webui/                      # Management app (port 8894)\r\n│   ├── *.html                 # HTML pages\r\n│   ├── api/                  # PHP API endpoints\r\n│   ├── backend/               # Backend API copy\r\n│   └── email/                # Email templates\r\n├── schedule/                   # Easy!Appointments installation\r\n├── schema/                    # Database schema files\r\n├── migrations/               # SQL migrations\r\n├── scripts/                   # PowerShell/Python import scripts\r\n├── docs/                     # Documentation\r\n├── blog/                     # Blog system and reengineering\r\n├── csv/                      # CSV data files\r\n├── backups/                  # Backup archives\r\n├── Topaz/                    # Topaz signature pad configs\r\n├── webui/                    # Second web interface\r\n│   ├── api/\r\n│   ├── backend/\r\n│   └── frontend/\r\n├── notused/                  # Deprecated/unused files\r\n└── wordpress-plugin/          # WordPress integration\r\n```\r\n\r\n---\r\n\r\n## 3. Database Schema\r\n\r\n### Core Tables (from mariadb_core_schema.sql)\r\n\r\n#### customers\r\nMain customer registry.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| customer_id | INT UNSIGNED PK | Auto-increment |\r\n| legacy_customer_id | INT NULL | Original Access DB ID |\r\n| created_at | DATETIME | Record creation time |\r\n| full_name | VARCHAR(200) | Customer full name |\r\n| phone | VARCHAR(30) | Formatted (XXX) XXX-XXXX |\r\n| email | VARCHAR(255) | Email address |\r\n| pickup_due_at | DATETIME | Next pickup date (synced from EA) |\r\n| description | TEXT | Description |\r\n| notes | TEXT | Internal notes |\r\n| is_new_customer | TINYINT(1) | 1 if flagged as new |\r\n\r\n#### visits\r\nOne row per alteration job/order.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| visit_id | INT UNSIGNED PK | |\r\n| legacy_visit_id | INT NULL | Original Access DB ID |\r\n| customer_id | INT UNSIGNED FK | → customers |\r\n| visit_date | DATETIME | Drop-off date |\r\n| pickup_date | DATETIME | Expected pickup |\r\n| notes | TEXT | General visit notes |\r\n| customer_name_snapshot | VARCHAR(200) | |\r\n| phone_snapshot | VARCHAR(30) | |\r\n| email_snapshot | VARCHAR(255) | |\r\n| color | VARCHAR(100) | Garment color |\r\n| alterations_needed | TEXT | |\r\n| alterations_notes | TEXT | Detailed alteration instructions |\r\n| alterations_price | DECIMAL(10,2) | Manual price field |\r\n| total_alteration_price | DECIMAL(10,2) | Calculated from items |\r\n| expedited_fee | DECIMAL(10,2) | |\r\n| paid_date | DATETIME | When paid |\r\n| signature_text | TEXT | Text signature (legacy) |\r\n| signature_date | DATETIME | |\r\n| paid_flag | TINYINT(1) | 1 = paid |\r\n| source_key_value | VARCHAR(100) | |\r\n\r\n#### visit_signatures\r\nFull resolution signature images per visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| signature_id | BIGINT UNSIGNED PK | |\r\n| visit_id | INT UNIQUE | One signature per visit |\r\n| signature_date | DATETIME | |\r\n| image_format | VARCHAR(50) | Default 'image/png' |\r\n| original_filename | VARCHAR(255) | |\r\n| original_extension | VARCHAR(20) | |\r\n| file_size_bytes | BIGINT | |\r\n| sha256_hash | CHAR(64) | Hash for verification |\r\n| signature_image | LONGBLOB | Raw PNG binary |\r\n| created_at | DATETIME | |\r\n\r\n#### item_types\r\nMaster list of alteration types (e.g., Hem, Zipper, Taper).\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| item_type_id | INT UNSIGNED PK | |\r\n| type_name | VARCHAR(100) UNIQUE | Display name |\r\n\r\n#### orders\r\nOrders per visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_id | BIGINT UNSIGNED PK | |\r\n| visit_id | INT UNSIGNED FK | → visits |\r\n| customer_id | INT UNSIGNED FK | → customers |\r\n| created_at | DATETIME | |\r\n| no_tax | TINYINT(1) | Tax exempt |\r\n| picked_up | TINYINT(1) | |\r\n| source_table | VARCHAR(50) | |\r\n\r\n#### order_items\r\nLine items for each alteration within a visit.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_item_id | BIGINT UNSIGNED PK | |\r\n| order_id | BIGINT UNSIGNED FK | → orders |\r\n| legacy_alteration_id | INT NULL | |\r\n| item_type_id | INT FK | → item_types |\r\n| item_type_name | VARCHAR(100) | |\r\n| description | TEXT | |\r\n| quantity | INT | Default 1 |\r\n| unit_price | DECIMAL(10,2) | |\r\n| total_price | DECIMAL(10,2) | |\r\n| notes | TEXT | Per-item notes |\r\n| color | VARCHAR(100) | Garment color |\r\n| no_tax | TINYINT(1) | Tax exempt |\r\n| is_range_price | TINYINT(1) | |\r\n| range_price_label | VARCHAR(100) | |\r\n| paid_flag | TINYINT(1) | |\r\n| paid_type | VARCHAR(100) | |\r\n| picked_up | TINYINT(1) | |\r\n| created_at | DATETIME | |\r\n\r\n#### order_item_type_links\r\nMany-to-many links between order items and item types.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| order_item_type_link_id | BIGINT UNSIGNED PK | |\r\n| order_item_id | BIGINT UNSIGNED FK | → order_items |\r\n| item_type_id | INT UNSIGNED FK | → item_types |\r\n| slot_number | TINYINT UNSIGNED | |\r\n\r\n#### payments\r\nPayment records per order.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| payment_id | BIGINT UNSIGNED PK | |\r\n| order_id | BIGINT UNSIGNED FK | → orders |\r\n| payment_date | DATETIME | |\r\n| payment_type | VARCHAR(100) | |\r\n| payment_method | VARCHAR(100) | |\r\n| amount | DECIMAL(10,2) | |\r\n| notes | TEXT | |\r\n\r\n#### tax_payments\r\nTax payment records.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| tax_payment_id | INT UNSIGNED PK | |\r\n| legacy_tax_payment_id | INT NULL | |\r\n| payment_date | DATETIME | |\r\n| payment_type | VARCHAR(100) | |\r\n| payment_method | VARCHAR(100) | |\r\n| amount | DECIMAL(10,2) | |\r\n| notes | TEXT | |\r\n| receipt_blob | LONGBLOB | |\r\n\r\n#### change_log\r\nAudit log for changes.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| log_id | BIGINT UNSIGNED PK | |\r\n| legacy_log_id | INT NULL | |\r\n| table_name | VARCHAR(100) | |\r\n| record_id | BIGINT | |\r\n| visit_id | INT | |\r\n| field_name | VARCHAR(100) | |\r\n| old_value | TEXT | |\r\n| new_value | TEXT | |\r\n| changed_at | DATETIME | |\r\n| changed_by | VARCHAR(100) | |\r\n\r\n#### ads\r\nAdvertising/articles.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| ad_id | INT UNSIGNED PK | |\r\n| legacy_ad_id | INT NULL | |\r\n| article_text | TEXT | |\r\n| article_picture | LONGBLOB | |\r\n| site_submitted | VARCHAR(255) | |\r\n| views | INT | Default 0 |\r\n| date_posted | DATETIME | |\r\n\r\n#### staging_* tables\r\nStaging tables for data migration.\r\n\r\n| Table Name | Purpose |\r\n|------------|---------|\r\n| staging_customer_table_raw | Staging for legacy customer data |\r\n| staging_customer_visits_raw | Staging for legacy visits |\r\n| staging_alteration_items_raw | Staging for items |\r\n\r\n### Additional Backend Tables\r\n\r\n| Table Name | Purpose |\r\n|------------|---------|\r\n| setmore_appointments | Synced from Setmore |\r\n| backend_conversion_job | Document conversion jobs |\r\n| backend_job_runs | Background job execution log |\r\n| customer_totals | Daily customer totals |\r\n| daily_customer_totals | Daily summary totals |\r\n| customer_payment_transactions | Payment ledger |\r\n| legacy_customer_totals_monthly | Monthly totals (legacy) |\r\n| legacy_customer_totals_irs_monthly | IRS monthly reports |\r\n| backend_appointment_workflow | Appointment state machine |\r\n| backend_no_show_log | No-show tracking |\r\n| backend_error_log | Error logging |\r\n| backend_change_log | Change audit log |\r\n| backend_document | Document storage |\r\n| backend_document_version | Document version history |\r\n| backend_speed_dial | Quick links |\r\n| backend_square_terminal_code | Square terminal pairing codes |\r\n| backend_square_terminal_device | Square device registry |\r\n| cron_job | Scheduled job definitions |\r\n| cron_job_run | Cron execution history |\r\n| app_settings | Global configuration |\r\n| app_users | Login accounts |\r\n| remember_tokens | \"Remember Me\" tokens |\r\n| customer_reports | PDF report index |\r\n\r\n---\r\n\r\n## 4. API Endpoints\r\n\r\n### 4.1 Frontend API (port 8895 /api/)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **customer_get.php** | Get customer by ID |\r\n| **customer_save.php** | Create or update customer |\r\n| **customer_detail.php** | Customer + visits summary |\r\n| **customer_delete.php** | Delete customer |\r\n| **customer_list_hide.php** | Hide customer from list |\r\n| **search_customers.php** | Search by name/phone |\r\n| **visit_get.php** | Get visit + items |\r\n| **visit_save.php** | Create/update visit + items |\r\n| **visit_delete.php** | Delete visit |\r\n| **visit_report_generate.php** | Generate visit report |\r\n| **item_types.php** | List all alteration types |\r\n| **item_type_add.php** | Add new item type |\r\n| **item_type_update.php** | Update item type |\r\n| **item_type_delete.php** | Delete item type |\r\n| **pickups_today.php** | Orders due today |\r\n| **ready.php** | Orders ready for pickup |\r\n| **overdue.php** | Overdue orders |\r\n| **upcoming.php** | Orders due in next N days |\r\n| **workload_7days.php** | 7-day workload |\r\n| **save_signature.php** | Save canvas signature |\r\n| **reports_list.php** | Reports for customer |\r\n| **attach_reports.php** | Index all PDFs to DB |\r\n| **save_signature.php** | Save signature image |\r\n| **today_appointments_list.php** | Today's appointments |\r\n| **settings_get.php** | Get app settings |\r\n| **settings_save.php** | Save app settings |\r\n| **settings_css.php** | Live theme CSS |\r\n| **send_email.php** | Send email via SMTP |\r\n| **send_sms.php** | Send SMS via Twilio |\r\n| **send_reminders.php** | Send appointment reminders |\r\n| **ea_appointments.php** | EasyAppointments REST API |\r\n| **ea_webhook.php** | Receives EA webhook events |\r\n| **setmore.php** | Setmore API proxy |\r\n| **setmore_to_ea_import.php** | Import customers to EA |\r\n| **square_config.php** | Square public config |\r\n| **square_process.php** | Process Square payment |\r\n| **square_customer_log.php** | Customer Square log |\r\n| **square_terminal.php** | Square terminal |\r\n| **login.php** | Authenticate |\r\n| **logout.php** | Clear session |\r\n| **session_check.php** | Check if logged in |\r\n| **auth.php** | Session authentication |\r\n| **config.php** | App config constants |\r\n| **db.php** | Database connection |\r\n| **log_error.php** | Log client-side error |\r\n| **todo_list.php** | Todo list management |\r\n| **send_telegram.php** | Send Telegram messages |\r\n\r\n### 4.2 Management API (port 8894 /api/)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **login.php** | Authenticate |\r\n| **logout.php** | Clear session |\r\n| **session_check.php** | Check if logged in |\r\n| **customer_detail.php** | Customer + visits |\r\n| **search_customers.php** | Search customers |\r\n| **update_customer.php** | Update customer |\r\n| **users_list.php** | List all users |\r\n| **user_save.php** | Create/update user |\r\n| **list_report_dirs.php** | Date folders |\r\n| **list_report_files.php** | PDFs in folder |\r\n| **report_file.php** | Access report file |\r\n| **pickups_today.php** | Today's pickups |\r\n| **ready.php** | Ready for pickup |\r\n| **overdue.php** | Overdue |\r\n| **settings_get.php** | Get settings |\r\n| **settings_save.php** | Save settings |\r\n| **settings_css.php** | Live CSS theme |\r\n| **imap_list.php** | List IMAP folders |\r\n| **imap_fetch.php** | Fetch emails |\r\n| **imap_send.php** | Send email via IMAP |\r\n| **imap_action.php** | IMAP actions |\r\n| **sms_send_helper.php** | SMS sending helper |\r\n| **sms_webhook_receive.php** | Receive SMS webhooks |\r\n| **sms_inbox_api.php** | SMS inbox API |\r\n| **slideshow_list.php** | Slideshow images |\r\n| **slideshow_upload.php** | Upload slideshow |\r\n| **slideshow_delete.php** | Delete slideshow |\r\n| **users_list.php** | User management |\r\n| **report_list.php** | Report list |\r\n| **debug_filters.php** | Debug filters |\r\n| **sysadmin.php** | System admin |\r\n| **test.php** | Testing endpoint |\r\n\r\n### 4.3 Backend API (C:\\code\\customerdb\\backend\\api\\)\r\n\r\n| Endpoint File | Purpose |\r\n|---------------|---------|\r\n| **customer.php** | Get customer details |\r\n| **customers.php** | List/search customers |\r\n| **customer_save.php** | Save/update customer |\r\n| **visit.php** | Get visit details |\r\n| **visit_delete.php** | Delete visit |\r\n| **appointments.php** | Unified appointments |\r\n| **appointments_summary.php** | Appointment statistics |\r\n| **setmore_appointments.php** | Setmore appointments |\r\n| **setmore_import.php** | Import from Setmore |\r\n| **module_*.php** | Module loaders |\r\n| **alteration_items.php** | Alteration management |\r\n| **alteration_items_summary.php** | Alteration statistics |\r\n| **gold_silver_*.php** | Gold/silver prices |\r\n| **bank_*.php** | Bank transactions |\r\n| **stocks_summary.php** | Stock data |\r\n| **medication_*.php** | Medication tracking |\r\n| **payroll_import.php** | Payroll import |\r\n| **car_maintenance_*.php** | Vehicle maintenance |\r\n| **duke_*.php** | Duke integration |\r\n| **reports_*.php** | Report generation |\r\n| **totals_import.php** | Customer totals import |\r\n| **documents.php** | Document management |\r\n| **document_upload.php** | File uploads |\r\n| **cust_email_*.php** | Email data |\r\n| **mail_*.php** | Email sending |\r\n| **reminders_create.php** | Create reminders |\r\n| **nightly_reports.php** | Nightly reports |\r\n| **morning_jobs.php** | Morning jobs |\r\n| **appointment_workflow.php** | Workflow management |\r\n| **sysadmin.php** | System admin |\r\n| **reporting_module.php** | Reporting |\r\n| **job_runs.php** | Job tracking |\r\n| **health.php** | Health check |\r\n| **overview.php** | Dashboard data |\r\n\r\n---\r\n\r\n## 5. External Integrations\r\n\r\n### 5.1 Square (Payment Processing)\r\n- **Purpose:** Point-of-sale payments, receipts, terminal management\r\n- **Features:**\r\n  - Square Terminal device pairing/management\r\n  - Payment processing with tips\r\n  - Customer payment logging\r\n  - Sandbox and live environments\r\n- **Tables:** `backend_square_terminal_code`, `backend_square_terminal_device`, `square_customer_log`\r\n\r\n### 5.2 Twilio (SMS)\r\n- **Purpose:** SMS notifications and reminders\r\n- **Features:**\r\n  - Send SMS to customers\r\n  - Appointment reminders\r\n  - SMS consent tracking\r\n- **Settings:** `twilio_sid`, `twilio_token`, `twilio_from`\r\n\r\n### 5.3 Setmore (Appointment Booking)\r\n- **Purpose:** Appointment synchronization\r\n- **Features:**\r\n  - Pull appointments from Setmore API\r\n  - Link to customers/visits\r\n- **Table:** `setmore_appointments`\r\n- **Settings:** `setmore_refresh_token`, `setmore_staff_key`\r\n\r\n### 5.4 EasyAppointments (Alternative Booking)\r\n- **Purpose:** Full appointment booking platform\r\n- **Location:** C:\\code\\customerdb\\schedule\\\r\n- **Features:**\r\n  - Customer/provider management\r\n  - Web-based booking widget\r\n  - REST API\r\n\r\n### 5.5 Telegram (Notifications)\r\n- **Purpose:** Bot-based notifications\r\n- **Features:**\r\n  - Send notifications to channels\r\n  - Visit alerts\r\n  - Cron job status\r\n- **Settings:** `telegram_bot_token`, `telegram_chat_id`\r\n\r\n### 5.6 Ollama (AI - Optional)\r\n- **Purpose:** Local AI for email generation\r\n- **Settings:** `ollama_url`, `ollama_default_model`\r\n\r\n---\r\n\r\n## 6. Scheduled Jobs / Cron\r\n\r\n### Configured Cron Jobs\r\n\r\n| Job Label | Schedule | Purpose |\r\n|----------|----------|---------|\r\n| **Next-Day Customer Emails** | `0 20 * * *` (8 PM) | Pickup reminder emails |\r\n| **Morning Import** | `0 6 * * *` (6 AM) | Morning data import |\r\n| **Morning Jobs** | `0 9 * * *` (9 AM) | Appointment sync, workflow |\r\n| **Nightly Reports** | `0 20 * * *` (8 PM) | Generate nightly summaries |\r\n| **Database Backup** | `0 2 * * *` (2 AM) | Full MariaDB backup |\r\n| **Daily Cleanup** | `0 4 * * *` (4 AM) | Temp files, old logs |\r\n| **Auto Delete** | `15 4 * * *` (4:15 AM) | Clean placeholder records |\r\n\r\n### Background Job Scripts (backend/jobs/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **run_morning_jobs.php** | Main morning job runner |\r\n| **smoke_morning_jobs.php** | Smoke test |\r\n| **send_nightly_reports.php** | Nightly report emailer |\r\n| **send_nextday_customer_emails.php** | Next-day reminders |\r\n| **delete_add_name_records.php** | Cleanup job |\r\n| **rebuild_customer_totals.php** | Rebuild totals |\r\n| **rebuild_daily_customer_totals.php** | Rebuild daily totals |\r\n| **rebuild_payment_ledger.php** | Rebuild payment ledger |\r\n| **import_customer_totals_csv.php** | CSV import |\r\n| **backfill_square_customer_log.php** | Square log backfill |\r\n| **run_cron_job.php** | Generic cron runner |\r\n\r\n---\r\n\r\n## 7. Web Applications\r\n\r\n### 7.1 Front Desk App (port 8895)\r\n\r\n| Page | Purpose |\r\n|------|---------|\r\n| **index.html** | Main dashboard, search, stats |\r\n| **customer.html** | Customer detail + visit history |\r\n| **visit.html** | Create/edit alteration order |\r\n| **customer_display.html** | Second monitor display |\r\n| **receipt.html** | Printable receipt |\r\n| **reports.html** | Order list by status |\r\n| **upcoming.html** | Next 7 days pickups |\r\n| **schedule.html** | Appointments calendar |\r\n| **login.html** | Login page |\r\n| **item_types.html** | Item type management |\r\n\r\n### 7.2 Management App (port 8894)\r\n\r\n| Page | Purpose |\r\n|------|---------|\r\n| **index.html** | Login page |\r\n| **webui.html** | Dashboard |\r\n| **customer.html** | Customer detail view |\r\n| **admin.html** | Reports browser |\r\n| **settings.html** | App settings editor |\r\n| **users.html** | User management |\r\n| **reports.html** | Order reports |\r\n\r\n---\r\n\r\n## 8. Settings & Configuration\r\n\r\n### app_settings Keys\r\n\r\n| Key | Purpose |\r\n|-----|---------|\r\n| theme_bg | Page background color |\r\n| theme_panel | Card/panel color |\r\n| theme_text | Text color |\r\n| theme_accent | Accent/button color |\r\n| theme_accent_deep | Darker accent |\r\n| theme_teal | Teal color |\r\n| theme_font | Font family |\r\n| smtp_host | Email server hostname |\r\n| smtp_port | Email server port |\r\n| smtp_secure | tls or ssl |\r\n| smtp_user | Email login |\r\n| smtp_pass | Email password |\r\n| smtp_from_email | From address |\r\n| smtp_from_name | From display name |\r\n| twilio_sid | Twilio Account SID |\r\n| twilio_token | Twilio Auth Token |\r\n| twilio_from | Twilio phone number |\r\n| imap_host | Incoming email server |\r\n| imap_port | IMAP port |\r\n| imap_ssl | SSL enable |\r\n| imap_user | IMAP login |\r\n| imap_pass | IMAP password |\r\n| square_token | Square API token |\r\n| square_location | Square location ID |\r\n| setmore_staff_key | Setmore API key |\r\n| setmore_refresh | Setmore refresh token |\r\n| require_report | PDF required |\r\n| require_signature | Signature required |\r\n| reports_base_path | Reports disk path |\r\n| reports_base_url | Reports URL |\r\n| ollama_url | Ollama AI URL |\r\n| ollama_default_model | Ollama model |\r\n| telegram_bot_token | Telegram bot token |\r\n| telegram_chat_id | Telegram chat ID |\r\n\r\n---\r\n\r\n## 9. Migration Notes\r\n\r\n### Access to MariaDB Workflow\r\n\r\n1. **Export source data from Access**\r\n   - Export ordinary tables to CSV\r\n   - Export attachment fields with VBA or DAO Recordset2 logic\r\n   - Keep original IDs during migration\r\n\r\n2. **Load into MariaDB staging**\r\n   - Use `LOAD DATA LOCAL INFILE` for CSV files\r\n   - Load signatures separately into `visit_signatures`\r\n\r\n3. **Normalize**\r\n   - `CustomerTable` → `customers`\r\n   - `CustomerVisits` → `visits`\r\n   - `AlterationItems` → `orders`, `order_items`, `order_item_type_links`\r\n   - `2024TaxPayments` → `tax_payments`\r\n   - `AlterationItemsChangeLog` → `change_log`\r\n\r\n4. **Signature BLOB path**\r\n   - Export Access attachment to temp file\r\n   - Convert BMP to PNG\r\n   - Insert PNG bytes into `visit_signatures.signature_image`\r\n\r\n5. **Validation**\r\n   - Compare source row counts vs target\r\n   - Compare distinct legacy IDs\r\n   - Compare sample signatures by SHA256\r\n\r\n---\r\n\r\n## 10. Scripts & Tools\r\n\r\n### PowerShell Scripts (scripts/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **import_legacy_totals_from_excel.ps1** | Import totals from Excel |\r\n| **sync_backend_mirror.ps1** | Sync backend mirror |\r\n| **check_backend_mirror.ps1** | Check mirror status |\r\n\r\n### Python Scripts (scripts/)\r\n\r\n| Script | Purpose |\r\n|--------|---------|\r\n| **signature_blob_loader.py** | Load signature blobs |\r\n| **access_to_mariadb_parser.py** | Parse Access to MariaDB |\r\n| **import_access_v2.py** | Import Access v2 |\r\n| **import_csv_v2.py** | Import CSV v2 |\r\n\r\n### SQL Migrations (migrations/)\r\n\r\n| File | Purpose |\r\n|------|---------|\r\n| **20260407_add_conversion_job.sql** | Add conversion job table |\r\n| **20260411_order_items_item_type_name_no_fk.sql** | Order items no FK |\r\n| **20260416_blog_prompt_templates.sql** | Blog prompt templates |\r\n\r\n---\r\n\r\n## File Statistics\r\n\r\n- **Total PHP files:** 200+\r\n- **Total SQL files:** 100+\r\n- **Total HTML pages:** 20+\r\n- **Database tables:** 30+\r\n\r\n---\r\n\r\n*End of Documentation*","is_text_editable":1,"can_edit_inline":1}
documents · upload
2026-04-17 12:08:29 · anonymous · /backend/documents.php
change
backend_document #20
Context
{"file_name":"COMPREHENSIVE_DOCUMENTATION.md","mime_type":"application/octet-stream"}
Before
[]
After
{"backend_document_id":"20","document_type":"upload","title":"Complete Documentation up to date","slug":"complete-documentation-up-to-date","summary_text":null,"content_markdown":null,"content_html":null,"file_name":"COMPREHENSIVE_DOCUMENTATION.md","stored_name":"20260417-160828-6006d4f1.md","mime_type":"application/octet-stream","file_size_bytes":"22313","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260417-160828-6006d4f1.md","is_deleted":"0","created_at":"2026-04-17 12:08:29","updated_at":"2026-04-17 12:08:29","editor_content":"# Ella's Alterations - Comprehensive System Documentation\n\n**Generated:** April 17, 2026\n**Location:** C:\\code\\customerdb\n\n---\n\n## Table of Contents\n\n1. [System Overview](#1-system-overview)\n2. [Directory Structure](#2-directory-structure)\n3. [Database Schema](#3-database-schema)\n4. [API Endpoints](#4-api-endpoints)\n5. [External Integrations](#5-external-integrations)\n6. [Scheduled Jobs / Cron](#6-scheduled-jobs--cron)\n7. [Web Applications](#7-web-applications)\n8. [Settings & Configuration](#8-settings--configuration)\n9. [Migration Notes](#9-migration-notes)\n10. [Scripts & Tools](#10-scripts--tools)\n\n---\n\n## 1. System Overview\n\n### Purpose\nElla's Alterations is a comprehensive customer relationship management (CRM) andAlteration tracking system for a tailor shop. It manages customers, visits/alteration orders, appointments, payments, and provides integration with external services.\n\n### Server Information\n- **Primary Server:** kefa@192.168.7.202\n- **Mirror Drive:** /mnt/drive2 (mirrors /mnt/drive1)\n- **Database:** MariaDB - database `ellas_alterations`, user `kefa_admin`\n- **Web Server:** Apache 2.4 with mod-php\n- **PHP Version:** 8.3\n\n### Three Web Applications\n\n| App | Local URL | Public URL | Purpose |\n|-----|-----------|------------|---------|\n| Front Desk | http://192.168.7.202:8895 | https://ella.floridaalterations.com | Customer-facing operations |\n| Management | http://192.168.7.202:8894 | (LAN only) | Reports, admin, settings |\n| Scheduler | http://192.168.7.202:8897 | https://schedule.floridaalterations.com | Easy!Appointments booking |\n\n---\n\n## 2. Directory Structure\n\n```\ncustomerdb/\n├── backend/                    # Main PHP backend API and services\n│   ├── api/                    # REST API endpoints (~57 files)\n│   ├── bin/                    # Binary/executable scripts\n│   ├── backup/                # Backup versions of services\n│   └── jobs/                  # Background job scripts\n├── frontend/                   # Front Desk app (port 8895)\n│   ├── *.html                 # HTML pages\n│   ├── api/                   # PHP API endpoints\n│   └── reports/               # PDF reports (MMDDYYYY/filename.pdf)\n├── webui/                      # Management app (port 8894)\n│   ├── *.html                 # HTML pages\n│   ├── api/                  # PHP API endpoints\n│   ├── backend/               # Backend API copy\n│   └── email/                # Email templates\n├── schedule/                   # Easy!Appointments installation\n├── schema/                    # Database schema files\n├── migrations/               # SQL migrations\n├── scripts/                   # PowerShell/Python import scripts\n├── docs/                     # Documentation\n├── blog/                     # Blog system and reengineering\n├── csv/                      # CSV data files\n├── backups/                  # Backup archives\n├── Topaz/                    # Topaz signature pad configs\n├── webui/                    # Second web interface\n│   ├── api/\n│   ├── backend/\n│   └── frontend/\n├── notused/                  # Deprecated/unused files\n└── wordpress-plugin/          # WordPress integration\n```\n\n---\n\n## 3. Database Schema\n\n### Core Tables (from mariadb_core_schema.sql)\n\n#### customers\nMain customer registry.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| customer_id | INT UNSIGNED PK | Auto-increment |\n| legacy_customer_id | INT NULL | Original Access DB ID |\n| created_at | DATETIME | Record creation time |\n| full_name | VARCHAR(200) | Customer full name |\n| phone | VARCHAR(30) | Formatted (XXX) XXX-XXXX |\n| email | VARCHAR(255) | Email address |\n| pickup_due_at | DATETIME | Next pickup date (synced from EA) |\n| description | TEXT | Description |\n| notes | TEXT | Internal notes |\n| is_new_customer | TINYINT(1) | 1 if flagged as new |\n\n#### visits\nOne row per alteration job/order.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| visit_id | INT UNSIGNED PK | |\n| legacy_visit_id | INT NULL | Original Access DB ID |\n| customer_id | INT UNSIGNED FK | → customers |\n| visit_date | DATETIME | Drop-off date |\n| pickup_date | DATETIME | Expected pickup |\n| notes | TEXT | General visit notes |\n| customer_name_snapshot | VARCHAR(200) | |\n| phone_snapshot | VARCHAR(30) | |\n| email_snapshot | VARCHAR(255) | |\n| color | VARCHAR(100) | Garment color |\n| alterations_needed | TEXT | |\n| alterations_notes | TEXT | Detailed alteration instructions |\n| alterations_price | DECIMAL(10,2) | Manual price field |\n| total_alteration_price | DECIMAL(10,2) | Calculated from items |\n| expedited_fee | DECIMAL(10,2) | |\n| paid_date | DATETIME | When paid |\n| signature_text | TEXT | Text signature (legacy) |\n| signature_date | DATETIME | |\n| paid_flag | TINYINT(1) | 1 = paid |\n| source_key_value | VARCHAR(100) | |\n\n#### visit_signatures\nFull resolution signature images per visit.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| signature_id | BIGINT UNSIGNED PK | |\n| visit_id | INT UNIQUE | One signature per visit |\n| signature_date | DATETIME | |\n| image_format | VARCHAR(50) | Default 'image/png' |\n| original_filename | VARCHAR(255) | |\n| original_extension | VARCHAR(20) | |\n| file_size_bytes | BIGINT | |\n| sha256_hash | CHAR(64) | Hash for verification |\n| signature_image | LONGBLOB | Raw PNG binary |\n| created_at | DATETIME | |\n\n#### item_types\nMaster list of alteration types (e.g., Hem, Zipper, Taper).\n\n| Column | Type | Notes |\n|--------|------|-------|\n| item_type_id | INT UNSIGNED PK | |\n| type_name | VARCHAR(100) UNIQUE | Display name |\n\n#### orders\nOrders per visit.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| order_id | BIGINT UNSIGNED PK | |\n| visit_id | INT UNSIGNED FK | → visits |\n| customer_id | INT UNSIGNED FK | → customers |\n| created_at | DATETIME | |\n| no_tax | TINYINT(1) | Tax exempt |\n| picked_up | TINYINT(1) | |\n| source_table | VARCHAR(50) | |\n\n#### order_items\nLine items for each alteration within a visit.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| order_item_id | BIGINT UNSIGNED PK | |\n| order_id | BIGINT UNSIGNED FK | → orders |\n| legacy_alteration_id | INT NULL | |\n| item_type_id | INT FK | → item_types |\n| item_type_name | VARCHAR(100) | |\n| description | TEXT | |\n| quantity | INT | Default 1 |\n| unit_price | DECIMAL(10,2) | |\n| total_price | DECIMAL(10,2) | |\n| notes | TEXT | Per-item notes |\n| color | VARCHAR(100) | Garment color |\n| no_tax | TINYINT(1) | Tax exempt |\n| is_range_price | TINYINT(1) | |\n| range_price_label | VARCHAR(100) | |\n| paid_flag | TINYINT(1) | |\n| paid_type | VARCHAR(100) | |\n| picked_up | TINYINT(1) | |\n| created_at | DATETIME | |\n\n#### order_item_type_links\nMany-to-many links between order items and item types.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| order_item_type_link_id | BIGINT UNSIGNED PK | |\n| order_item_id | BIGINT UNSIGNED FK | → order_items |\n| item_type_id | INT UNSIGNED FK | → item_types |\n| slot_number | TINYINT UNSIGNED | |\n\n#### payments\nPayment records per order.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| payment_id | BIGINT UNSIGNED PK | |\n| order_id | BIGINT UNSIGNED FK | → orders |\n| payment_date | DATETIME | |\n| payment_type | VARCHAR(100) | |\n| payment_method | VARCHAR(100) | |\n| amount | DECIMAL(10,2) | |\n| notes | TEXT | |\n\n#### tax_payments\nTax payment records.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| tax_payment_id | INT UNSIGNED PK | |\n| legacy_tax_payment_id | INT NULL | |\n| payment_date | DATETIME | |\n| payment_type | VARCHAR(100) | |\n| payment_method | VARCHAR(100) | |\n| amount | DECIMAL(10,2) | |\n| notes | TEXT | |\n| receipt_blob | LONGBLOB | |\n\n#### change_log\nAudit log for changes.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| log_id | BIGINT UNSIGNED PK | |\n| legacy_log_id | INT NULL | |\n| table_name | VARCHAR(100) | |\n| record_id | BIGINT | |\n| visit_id | INT | |\n| field_name | VARCHAR(100) | |\n| old_value | TEXT | |\n| new_value | TEXT | |\n| changed_at | DATETIME | |\n| changed_by | VARCHAR(100) | |\n\n#### ads\nAdvertising/articles.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| ad_id | INT UNSIGNED PK | |\n| legacy_ad_id | INT NULL | |\n| article_text | TEXT | |\n| article_picture | LONGBLOB | |\n| site_submitted | VARCHAR(255) | |\n| views | INT | Default 0 |\n| date_posted | DATETIME | |\n\n#### staging_* tables\nStaging tables for data migration.\n\n| Table Name | Purpose |\n|------------|---------|\n| staging_customer_table_raw | Staging for legacy customer data |\n| staging_customer_visits_raw | Staging for legacy visits |\n| staging_alteration_items_raw | Staging for items |\n\n### Additional Backend Tables\n\n| Table Name | Purpose |\n|------------|---------|\n| setmore_appointments | Synced from Setmore |\n| backend_conversion_job | Document conversion jobs |\n| backend_job_runs | Background job execution log |\n| customer_totals | Daily customer totals |\n| daily_customer_totals | Daily summary totals |\n| customer_payment_transactions | Payment ledger |\n| legacy_customer_totals_monthly | Monthly totals (legacy) |\n| legacy_customer_totals_irs_monthly | IRS monthly reports |\n| backend_appointment_workflow | Appointment state machine |\n| backend_no_show_log | No-show tracking |\n| backend_error_log | Error logging |\n| backend_change_log | Change audit log |\n| backend_document | Document storage |\n| backend_document_version | Document version history |\n| backend_speed_dial | Quick links |\n| backend_square_terminal_code | Square terminal pairing codes |\n| backend_square_terminal_device | Square device registry |\n| cron_job | Scheduled job definitions |\n| cron_job_run | Cron execution history |\n| app_settings | Global configuration |\n| app_users | Login accounts |\n| remember_tokens | \"Remember Me\" tokens |\n| customer_reports | PDF report index |\n\n---\n\n## 4. API Endpoints\n\n### 4.1 Frontend API (port 8895 /api/)\n\n| Endpoint File | Purpose |\n|---------------|---------|\n| **customer_get.php** | Get customer by ID |\n| **customer_save.php** | Create or update customer |\n| **customer_detail.php** | Customer + visits summary |\n| **customer_delete.php** | Delete customer |\n| **customer_list_hide.php** | Hide customer from list |\n| **search_customers.php** | Search by name/phone |\n| **visit_get.php** | Get visit + items |\n| **visit_save.php** | Create/update visit + items |\n| **visit_delete.php** | Delete visit |\n| **visit_report_generate.php** | Generate visit report |\n| **item_types.php** | List all alteration types |\n| **item_type_add.php** | Add new item type |\n| **item_type_update.php** | Update item type |\n| **item_type_delete.php** | Delete item type |\n| **pickups_today.php** | Orders due today |\n| **ready.php** | Orders ready for pickup |\n| **overdue.php** | Overdue orders |\n| **upcoming.php** | Orders due in next N days |\n| **workload_7days.php** | 7-day workload |\n| **save_signature.php** | Save canvas signature |\n| **reports_list.php** | Reports for customer |\n| **attach_reports.php** | Index all PDFs to DB |\n| **save_signature.php** | Save signature image |\n| **today_appointments_list.php** | Today's appointments |\n| **settings_get.php** | Get app settings |\n| **settings_save.php** | Save app settings |\n| **settings_css.php** | Live theme CSS |\n| **send_email.php** | Send email via SMTP |\n| **send_sms.php** | Send SMS via Twilio |\n| **send_reminders.php** | Send appointment reminders |\n| **ea_appointments.php** | EasyAppointments REST API |\n| **ea_webhook.php** | Receives EA webhook events |\n| **setmore.php** | Setmore API proxy |\n| **setmore_to_ea_import.php** | Import customers to EA |\n| **square_config.php** | Square public config |\n| **square_process.php** | Process Square payment |\n| **square_customer_log.php** | Customer Square log |\n| **square_terminal.php** | Square terminal |\n| **login.php** | Authenticate |\n| **logout.php** | Clear session |\n| **session_check.php** | Check if logged in |\n| **auth.php** | Session authentication |\n| **config.php** | App config constants |\n| **db.php** | Database connection |\n| **log_error.php** | Log client-side error |\n| **todo_list.php** | Todo list management |\n| **send_telegram.php** | Send Telegram messages |\n\n### 4.2 Management API (port 8894 /api/)\n\n| Endpoint File | Purpose |\n|---------------|---------|\n| **login.php** | Authenticate |\n| **logout.php** | Clear session |\n| **session_check.php** | Check if logged in |\n| **customer_detail.php** | Customer + visits |\n| **search_customers.php** | Search customers |\n| **update_customer.php** | Update customer |\n| **users_list.php** | List all users |\n| **user_save.php** | Create/update user |\n| **list_report_dirs.php** | Date folders |\n| **list_report_files.php** | PDFs in folder |\n| **report_file.php** | Access report file |\n| **pickups_today.php** | Today's pickups |\n| **ready.php** | Ready for pickup |\n| **overdue.php** | Overdue |\n| **settings_get.php** | Get settings |\n| **settings_save.php** | Save settings |\n| **settings_css.php** | Live CSS theme |\n| **imap_list.php** | List IMAP folders |\n| **imap_fetch.php** | Fetch emails |\n| **imap_send.php** | Send email via IMAP |\n| **imap_action.php** | IMAP actions |\n| **sms_send_helper.php** | SMS sending helper |\n| **sms_webhook_receive.php** | Receive SMS webhooks |\n| **sms_inbox_api.php** | SMS inbox API |\n| **slideshow_list.php** | Slideshow images |\n| **slideshow_upload.php** | Upload slideshow |\n| **slideshow_delete.php** | Delete slideshow |\n| **users_list.php** | User management |\n| **report_list.php** | Report list |\n| **debug_filters.php** | Debug filters |\n| **sysadmin.php** | System admin |\n| **test.php** | Testing endpoint |\n\n### 4.3 Backend API (C:\\code\\customerdb\\backend\\api\\)\n\n| Endpoint File | Purpose |\n|---------------|---------|\n| **customer.php** | Get customer details |\n| **customers.php** | List/search customers |\n| **customer_save.php** | Save/update customer |\n| **visit.php** | Get visit details |\n| **visit_delete.php** | Delete visit |\n| **appointments.php** | Unified appointments |\n| **appointments_summary.php** | Appointment statistics |\n| **setmore_appointments.php** | Setmore appointments |\n| **setmore_import.php** | Import from Setmore |\n| **module_*.php** | Module loaders |\n| **alteration_items.php** | Alteration management |\n| **alteration_items_summary.php** | Alteration statistics |\n| **gold_silver_*.php** | Gold/silver prices |\n| **bank_*.php** | Bank transactions |\n| **stocks_summary.php** | Stock data |\n| **medication_*.php** | Medication tracking |\n| **payroll_import.php** | Payroll import |\n| **car_maintenance_*.php** | Vehicle maintenance |\n| **duke_*.php** | Duke integration |\n| **reports_*.php** | Report generation |\n| **totals_import.php** | Customer totals import |\n| **documents.php** | Document management |\n| **document_upload.php** | File uploads |\n| **cust_email_*.php** | Email data |\n| **mail_*.php** | Email sending |\n| **reminders_create.php** | Create reminders |\n| **nightly_reports.php** | Nightly reports |\n| **morning_jobs.php** | Morning jobs |\n| **appointment_workflow.php** | Workflow management |\n| **sysadmin.php** | System admin |\n| **reporting_module.php** | Reporting |\n| **job_runs.php** | Job tracking |\n| **health.php** | Health check |\n| **overview.php** | Dashboard data |\n\n---\n\n## 5. External Integrations\n\n### 5.1 Square (Payment Processing)\n- **Purpose:** Point-of-sale payments, receipts, terminal management\n- **Features:**\n  - Square Terminal device pairing/management\n  - Payment processing with tips\n  - Customer payment logging\n  - Sandbox and live environments\n- **Tables:** `backend_square_terminal_code`, `backend_square_terminal_device`, `square_customer_log`\n\n### 5.2 Twilio (SMS)\n- **Purpose:** SMS notifications and reminders\n- **Features:**\n  - Send SMS to customers\n  - Appointment reminders\n  - SMS consent tracking\n- **Settings:** `twilio_sid`, `twilio_token`, `twilio_from`\n\n### 5.3 Setmore (Appointment Booking)\n- **Purpose:** Appointment synchronization\n- **Features:**\n  - Pull appointments from Setmore API\n  - Link to customers/visits\n- **Table:** `setmore_appointments`\n- **Settings:** `setmore_refresh_token`, `setmore_staff_key`\n\n### 5.4 EasyAppointments (Alternative Booking)\n- **Purpose:** Full appointment booking platform\n- **Location:** C:\\code\\customerdb\\schedule\\\n- **Features:**\n  - Customer/provider management\n  - Web-based booking widget\n  - REST API\n\n### 5.5 Telegram (Notifications)\n- **Purpose:** Bot-based notifications\n- **Features:**\n  - Send notifications to channels\n  - Visit alerts\n  - Cron job status\n- **Settings:** `telegram_bot_token`, `telegram_chat_id`\n\n### 5.6 Ollama (AI - Optional)\n- **Purpose:** Local AI for email generation\n- **Settings:** `ollama_url`, `ollama_default_model`\n\n---\n\n## 6. Scheduled Jobs / Cron\n\n### Configured Cron Jobs\n\n| Job Label | Schedule | Purpose |\n|----------|----------|---------|\n| **Next-Day Customer Emails** | `0 20 * * *` (8 PM) | Pickup reminder emails |\n| **Morning Import** | `0 6 * * *` (6 AM) | Morning data import |\n| **Morning Jobs** | `0 9 * * *` (9 AM) | Appointment sync, workflow |\n| **Nightly Reports** | `0 20 * * *` (8 PM) | Generate nightly summaries |\n| **Database Backup** | `0 2 * * *` (2 AM) | Full MariaDB backup |\n| **Daily Cleanup** | `0 4 * * *` (4 AM) | Temp files, old logs |\n| **Auto Delete** | `15 4 * * *` (4:15 AM) | Clean placeholder records |\n\n### Background Job Scripts (backend/jobs/)\n\n| Script | Purpose |\n|--------|---------|\n| **run_morning_jobs.php** | Main morning job runner |\n| **smoke_morning_jobs.php** | Smoke test |\n| **send_nightly_reports.php** | Nightly report emailer |\n| **send_nextday_customer_emails.php** | Next-day reminders |\n| **delete_add_name_records.php** | Cleanup job |\n| **rebuild_customer_totals.php** | Rebuild totals |\n| **rebuild_daily_customer_totals.php** | Rebuild daily totals |\n| **rebuild_payment_ledger.php** | Rebuild payment ledger |\n| **import_customer_totals_csv.php** | CSV import |\n| **backfill_square_customer_log.php** | Square log backfill |\n| **run_cron_job.php** | Generic cron runner |\n\n---\n\n## 7. Web Applications\n\n### 7.1 Front Desk App (port 8895)\n\n| Page | Purpose |\n|------|---------|\n| **index.html** | Main dashboard, search, stats |\n| **customer.html** | Customer detail + visit history |\n| **visit.html** | Create/edit alteration order |\n| **customer_display.html** | Second monitor display |\n| **receipt.html** | Printable receipt |\n| **reports.html** | Order list by status |\n| **upcoming.html** | Next 7 days pickups |\n| **schedule.html** | Appointments calendar |\n| **login.html** | Login page |\n| **item_types.html** | Item type management |\n\n### 7.2 Management App (port 8894)\n\n| Page | Purpose |\n|------|---------|\n| **index.html** | Login page |\n| **webui.html** | Dashboard |\n| **customer.html** | Customer detail view |\n| **admin.html** | Reports browser |\n| **settings.html** | App settings editor |\n| **users.html** | User management |\n| **reports.html** | Order reports |\n\n---\n\n## 8. Settings & Configuration\n\n### app_settings Keys\n\n| Key | Purpose |\n|-----|---------|\n| theme_bg | Page background color |\n| theme_panel | Card/panel color |\n| theme_text | Text color |\n| theme_accent | Accent/button color |\n| theme_accent_deep | Darker accent |\n| theme_teal | Teal color |\n| theme_font | Font family |\n| smtp_host | Email server hostname |\n| smtp_port | Email server port |\n| smtp_secure | tls or ssl |\n| smtp_user | Email login |\n| smtp_pass | Email password |\n| smtp_from_email | From address |\n| smtp_from_name | From display name |\n| twilio_sid | Twilio Account SID |\n| twilio_token | Twilio Auth Token |\n| twilio_from | Twilio phone number |\n| imap_host | Incoming email server |\n| imap_port | IMAP port |\n| imap_ssl | SSL enable |\n| imap_user | IMAP login |\n| imap_pass | IMAP password |\n| square_token | Square API token |\n| square_location | Square location ID |\n| setmore_staff_key | Setmore API key |\n| setmore_refresh | Setmore refresh token |\n| require_report | PDF required |\n| require_signature | Signature required |\n| reports_base_path | Reports disk path |\n| reports_base_url | Reports URL |\n| ollama_url | Ollama AI URL |\n| ollama_default_model | Ollama model |\n| telegram_bot_token | Telegram bot token |\n| telegram_chat_id | Telegram chat ID |\n\n---\n\n## 9. Migration Notes\n\n### Access to MariaDB Workflow\n\n1. **Export source data from Access**\n   - Export ordinary tables to CSV\n   - Export attachment fields with VBA or DAO Recordset2 logic\n   - Keep original IDs during migration\n\n2. **Load into MariaDB staging**\n   - Use `LOAD DATA LOCAL INFILE` for CSV files\n   - Load signatures separately into `visit_signatures`\n\n3. **Normalize**\n   - `CustomerTable` → `customers`\n   - `CustomerVisits` → `visits`\n   - `AlterationItems` → `orders`, `order_items`, `order_item_type_links`\n   - `2024TaxPayments` → `tax_payments`\n   - `AlterationItemsChangeLog` → `change_log`\n\n4. **Signature BLOB path**\n   - Export Access attachment to temp file\n   - Convert BMP to PNG\n   - Insert PNG bytes into `visit_signatures.signature_image`\n\n5. **Validation**\n   - Compare source row counts vs target\n   - Compare distinct legacy IDs\n   - Compare sample signatures by SHA256\n\n---\n\n## 10. Scripts & Tools\n\n### PowerShell Scripts (scripts/)\n\n| Script | Purpose |\n|--------|---------|\n| **import_legacy_totals_from_excel.ps1** | Import totals from Excel |\n| **sync_backend_mirror.ps1** | Sync backend mirror |\n| **check_backend_mirror.ps1** | Check mirror status |\n\n### Python Scripts (scripts/)\n\n| Script | Purpose |\n|--------|---------|\n| **signature_blob_loader.py** | Load signature blobs |\n| **access_to_mariadb_parser.py** | Parse Access to MariaDB |\n| **import_access_v2.py** | Import Access v2 |\n| **import_csv_v2.py** | Import CSV v2 |\n\n### SQL Migrations (migrations/)\n\n| File | Purpose |\n|------|---------|\n| **20260407_add_conversion_job.sql** | Add conversion job table |\n| **20260411_order_items_item_type_name_no_fk.sql** | Order items no FK |\n| **20260416_blog_prompt_templates.sql** | Blog prompt templates |\n\n---\n\n## File Statistics\n\n- **Total PHP files:** 200+\n- **Total SQL files:** 100+\n- **Total HTML pages:** 20+\n- **Database tables:** 30+\n\n---\n\n*End of Documentation*","is_text_editable":1,"can_edit_inline":1}
documents · upload
2026-04-16 14:20:19 · anonymous · /backend/documents.php
change
backend_document #18
Context
{"file_name":"PAY_BILLS_ENHANCED_FEATURES.md","mime_type":"application/octet-stream"}
Before
[]
After
{"backend_document_id":"18","document_type":"upload","title":"Open Code 04-16 Pay Bills changes","slug":"open-code-04-16-pay-bills-changes","summary_text":"Open Code 04-16 Pay Bills changes","content_markdown":null,"content_html":null,"file_name":"PAY_BILLS_ENHANCED_FEATURES.md","stored_name":"20260416-182019-18adea90.md","mime_type":"application/octet-stream","file_size_bytes":"8500","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260416-182019-18adea90.md","is_deleted":"0","created_at":"2026-04-16 14:20:19","updated_at":"2026-04-16 14:20:19","editor_content":"# Pay Bills - Enhanced Features Documentation\n\n**Last Updated:** April 16, 2026  \n**File:** `/backend/bills.php`  \n**Server:** `kefa@192.168.7.202`  \n**Data Location:** `/mnt/drive1/customerdb/`\n\n---\n\n## Overview\n\nThe Pay Bills page has been enhanced with new features for better bank account management and payment tracking visibility.\n\n---\n\n## New Features\n\n### 1. Bank Account Types\n\nEach bank account now has a **type classification**:\n\n| Type | Icon | Description |\n|------|------|-------------|\n| **Pay Bill** | 💳 | Used for paying bills - appears in bank dropdown |\n| **Show Balance** | 👁 | Track only - excluded from bill payment dropdowns |\n\n**Why this matters:** Accounts marked as \"Show Balance\" won't clutter the bill payment dropdown but still track their running balance.\n\n### 2. Bank URL (Popup Window)\n\nEach account can have a **Bank URL** that opens in a popup window.\n\n- Click the \"🌐 Bank\" button next to any account\n- Opens the URL in a 1200x800 popup window\n- Useful for quick access to bank login without leaving the bills page\n\n### 3. Bal After Pills (Status Badges)\n\nThe \"Bal After\" column now shows **color-coded pills**:\n\n| Status | Appearance | Meaning |\n|--------|------------|---------|\n| **Paid** | Green pill with ✓ | Bill amount has been paid |\n| **Due** | Red pill with ! | Still needs to be paid |\n| **—** | Gray pill | No amount entered |\n\n### 4. Save All Buttons\n\nTwo save buttons added for convenience:\n\n1. **Save All Balances** - In the bank accounts section\n2. **Save All Bills** - At the bottom of the bills table\n\nBoth show \"Saving…\" → \"Saved ✓\" feedback.\n\n### 5. Auto-Update\n\nAll changes auto-save after 600ms of inactivity (debounced).\n\n---\n\n## Database Schema Changes\n\n### New Columns in `bills_accounts` Table\n\n```sql\n-- MySQL / MariaDB\nALTER TABLE bills_accounts\nADD COLUMN account_type ENUM('pay_bill', 'show_balance') DEFAULT 'pay_bill' AFTER name,\nADD COLUMN bank_url TEXT DEFAULT '' AFTER account_type;\n\n-- SQLite\nALTER TABLE bills_accounts ADD COLUMN account_type TEXT DEFAULT 'pay_bill';\nALTER TABLE bills_accounts ADD COLUMN bank_url TEXT DEFAULT '';\n```\n\n### New Tables Created\n\nIf tables don't exist, the following are auto-created:\n\n```sql\nCREATE TABLE bills_accounts (\n    id INTEGER PRIMARY KEY AUTOINCREMENT,\n    name TEXT NOT NULL,\n    account_type TEXT DEFAULT 'pay_bill',\n    bank_url TEXT DEFAULT '',\n    sort_order INTEGER DEFAULT 0,\n    created_at TEXT DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE bills_monthly (\n    id INTEGER PRIMARY KEY AUTOINCREMENT,\n    year INTEGER NOT NULL,\n    month INTEGER NOT NULL,\n    bills_account_id INTEGER,\n    opening_balance REAL DEFAULT 0,\n    UNIQUE(year, month, bills_account_id)\n);\n\nCREATE TABLE bills_items (\n    id INTEGER PRIMARY KEY AUTOINCREMENT,\n    name TEXT NOT NULL,\n    default_due REAL DEFAULT 0,\n    notes TEXT DEFAULT '',\n    sort_order INTEGER DEFAULT 0,\n    created_at TEXT DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE bills_entries (\n    id INTEGER PRIMARY KEY AUTOINCREMENT,\n    year INTEGER NOT NULL,\n    month INTEGER NOT NULL,\n    bills_item_id INTEGER NOT NULL,\n    bills_account_id INTEGER DEFAULT 0,\n    payment_due REAL DEFAULT 0,\n    amount_paid REAL DEFAULT 0,\n    is_paid INTEGER DEFAULT 0,\n    paid_date TEXT DEFAULT '',\n    UNIQUE(year, month, bills_item_id)\n);\n\nCREATE TABLE bills_copy_log (\n    id INTEGER PRIMARY KEY AUTOINCREMENT,\n    year INTEGER NOT NULL,\n    month INTEGER NOT NULL,\n    copied_from_year INTEGER NOT NULL,\n    copied_from_month INTEGER NOT NULL,\n    copied_at TEXT DEFAULT CURRENT_TIMESTAMP\n);\n```\n\n---\n\n## Deployment Instructions\n\n### Step 1: Upload the File\n\n**Option A: Direct Copy (if file is on local machine)**\n\n```bash\n# From local machine to server\nscp bills.php kefa@192.168.7.202:/var/www/floridaalterations.com/backend/bills.php\n```\n\n**Option B: If editing on server directly**\n\n```bash\nssh kefa@192.168.7.202\n# Then edit the file at:\n# /var/www/floridaalterations.com/backend/bills.php\n```\n\n### Step 2: Set Permissions\n\n```bash\nssh kefa@192.168.202\nchmod 644 /var/www/floridaalterations.com/backend/bills.php\nchown www-data:www-data /var/www/floridaalterations.com/backend/bills.php\n```\n\n### Step 3: Clear Cache (Optional)\n\n```bash\n# If using OPcache\nssh kefa@192.168.7.202\nphp -r \"opcache_get_status();\" 2>/dev/null && echo \"Consider: php-fpm restart\"\n```\n\n### Step 4: Access the Page\n\n```\nhttps://ella.floridaalterations.com/backend/bills.php\n```\n\n---\n\n## How to Use\n\n### Adding a New Account with Bank URL\n\n1. Click **\"+ Add Account\"** button\n2. Enter account name (e.g., \"Chase Checking\")\n3. Select account type:\n   - **Pay Bill** - For accounts you'll pay bills from\n   - **Show Balance** - For tracking only\n4. Enter Bank URL (e.g., `https://www.chase.com/login`)\n5. Click **\"Add Account\"**\n6. Enter the opening balance and click **\"Save Balances\"**\n\n### Editing an Existing Account\n\n1. Click **\"Edit\"** next to the account\n2. Update name, type, or URL\n3. Click **\"Save Changes\"**\n\n### Switching Account Type\n\n1. Edit the account\n2. Change the radio button selection\n3. Click **\"Save Changes\"**\n\n### Opening Bank in Popup\n\n1. Click the **\"🌐 Bank\"** button next to an account\n2. The bank URL opens in a new popup window\n\n### Marking a Bill as Paid\n\n1. Enter the **Paid ($)** amount (or it auto-calculates)\n2. The **Bal After** pill turns **green** with a ✓ checkmark\n3. Row background turns light blue to indicate paid status\n\n### Viewing Running Balance\n\n- The sidebar shows **Running Totals** for each pay-bill account\n- Updates automatically as you enter payments\n\n---\n\n## File Location Reference\n\n| Item | Server Path |\n|------|-------------|\n| bills.php | `/var/www/floridaalterations.com/backend/bills.php` |\n| Data directory | `/mnt/drive1/customerdb/` |\n| Database | `/mnt/drive1/customerdb/customer.db` |\n| Backup | `/mnt/drive1/customerdb/backup/` |\n| Logs | `/mnt/drive1/customerdb/logs/` |\n\n---\n\n## Troubleshooting\n\n### Database Connection Error\n\n```\nError: Connection failed\n```\n\n**Solution:**\n```bash\n# Check if MySQL is running\nssh kefa@192.168.7.202\nsudo systemctl status mysql\n# or\nsudo systemctl status mariadb\n```\n\n### Table Doesn't Exist\n\nIf you see errors about missing tables:\n\n```bash\n# The tables are auto-created on first page load\n# Just refresh the page once\n```\n\n### Bank URL Not Opening\n\n- Verify the URL includes `https://` or `http://`\n- Check browser popup blocker settings\n- Some banking sites block popup windows\n\n### Bal After Shows \"—\"\n\n**Causes:**\n1. No bank account selected for the bill\n2. Opening balance not saved for the account\n3. Account is marked as \"Show Balance\" type\n\n**Solution:**\n1. Select a bank account from the dropdown\n2. Save the opening balance for that account\n\n### Changes Not Saving\n\n1. Check browser console for JavaScript errors\n2. Verify network tab shows POST requests completing\n3. Clear browser cache and retry\n\n---\n\n## Quick Commands Reference\n\n```bash\n# Connect to server\nssh kefa@192.168.7.202\n\n# View current bills.php\ncat /var/www/floridaalterations.com/backend/bills.php | head -50\n\n# Backup bills.php before updating\ncp /var/www/floridaalterations.com/backend/bills.php /mnt/drive1/customerdb/backup/bills.php.$(date +%Y%m%d)\n\n# Upload new file\nscp bills.php kefa@192.168.7.202:/var/www/floridaalterations.com/backend/bills.php\n\n# Set correct permissions\nchmod 644 /var/www/floridaalterations.com/backend/bills.php\nchown www-data:www-data /var/www/floridaalterations.com/backend/bills.php\n\n# Check PHP error logs\nssh kefa@192.168.7.202 \"tail -50 /var/log/php*-fpm.log\"\n\n# Restart PHP-FPM if needed\nssh kefa@192.168.7.202 \"sudo systemctl restart php*-fpm\"\n```\n\n---\n\n## Security Notes\n\n- Bank URLs are stored as-is - ensure only trusted users can edit accounts\n- No sensitive data encrypted in the database\n- Consider HTTPS-only for all bank URLs\n- Session-based access control should be configured at the application level\n\n---\n\n## Future Enhancements (Suggested)\n\n1. **Auto-fetch balance** - API integration with banks (requires bank credentials)\n2. **Email notifications** - Remind when bills are due\n3. **Export to CSV** - Download bill history\n4. **Recurring bills** - Auto-create monthly bills\n5. **Budget tracking** - Set monthly budget limits per category\n\n---\n\n## Version History\n\n| Version | Date | Changes |\n|---------|------|---------|\n| 1.0 | April 16, 2026 | Initial release with account types, bank URLs, status pills |\n| - | - | Auto-save functionality |\n| - | - | Save All buttons added |\n\n---\n\n*End of Documentation*\n","is_text_editable":1,"can_edit_inline":1}
documents · save
2026-04-07 15:08:09 · anonymous · /backend/documents.php?backend_document_id=10
change
backend_document #10
Context
{"document_type":"upload"}
Before
{"backend_document_id":"10","document_type":"upload","title":"Claude 04-07-2026","slug":"claude-04-07-2026","summary_text":"Claude 04-07-2026 fixing backend Document areas","content_markdown":null,"content_html":null,"file_name":"SESSION_LOG_2026-04-07.md","stored_name":"20260407-190624-56f0e818.md","mime_type":"application/octet-stream","file_size_bytes":"21112","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260407-190624-56f0e818.md","is_deleted":"0","created_at":"2026-04-07 15:06:24","updated_at":"2026-04-07 15:06:24","editor_content":"# Session Log — 2026-04-07\n\nAll work completed in this session on the CustomerDB backend application.\n\n---\n\n## Summary of New Modules and Changes\n\n| Area | File(s) | Status |\n|------|---------|--------|\n| Bills Manager | `backend/bills_service.php`, `backend/bills.php` | New |\n| Next-Day Email Job | `backend/jobs/send_nextday_customer_emails.php` | New |\n| Cron Manager UI | `backend/cron_manager.php` | New |\n| Error Log UI | `backend/error_log.php` | New |\n| Change Log UI | `backend/change_log.php` | New |\n| Stocks & Crypto | `backend/stocks_crypto_service.php`, `backend/stocks_crypto.php` | New |\n| Backend Home | `backend/index.php` | Modified |\n| Documents Editor | `backend/documents.php` | Full rewrite |\n| Documents Service | `backend/document_service.php` | Bug fix |\n\n---\n\n## 1. Bills Manager\n\n### Files\n- `backend/bills_service.php` — 356 lines, service layer\n- `backend/bills.php` — 972 lines, UI page\n\n### Purpose\nReplaces a spreadsheet (`newbills2026.xlsx`) with a web-based bill payment tracker.\nTracks bank account opening balances, monthly bill payments, and computes running bank\nbalances in the same layout as the Excel spreadsheet.\n\n### Database Tables (auto-created on first load)\n\n**`bills_account`**\n| Column | Type | Notes |\n|--------|------|-------|\n| `bills_account_id` | INT PK AUTO | |\n| `name` | VARCHAR(120) | Bank name |\n| `sort_order` | INT | Display order |\n\n**`bills_item`**\n| Column | Type | Notes |\n|--------|------|-------|\n| `bills_item_id` | INT PK AUTO | |\n| `label` | VARCHAR(200) | Bill name |\n| `default_amount` | DECIMAL(12,2) | Pre-fills the Due column |\n| `default_account_id` | INT | Default bank to debit |\n| `notes` | TEXT | Instructions / URLs |\n| `sort_order` | INT | Row order |\n| `is_deleted` | TINYINT | Soft delete |\n\n**`bills_entry`**\nMonthly bill payment rows.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| `bills_entry_id` | INT PK AUTO | |\n| `bills_item_id` | INT | FK to `bills_item` |\n| `year`, `month` | INT | Billing period |\n| `amount_due` | DECIMAL(12,2) | Amount billed |\n| `amount_paid` | DECIMAL(12,2) | Amount actually paid |\n| `account_id` | INT | Bank used to pay |\n\n**`bills_balance`**\nOpening bank balances per month.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| `bills_balance_id` | INT PK AUTO | |\n| `account_id` | INT | FK to `bills_account` |\n| `year`, `month` | INT | Period |\n| `opening_balance` | DECIMAL(14,2) | Balance at start of month |\n\n### Seed Data\nOn first load (empty table), the following are auto-seeded from the original Excel file:\n\n**Accounts:** USAA, MIDFLORIDA, Centenial, CapitalOne\n\n**Bills (11 items):** MidFlorida Mortgage, MidFlorida Credit Card, USAA Credit Card,\nCentenial Bank, Electricity, Waste Management, Comcast/Xfinity, Insurance, Water,\nCapitalOne #1, CapitalOne #2\n\n### Service Functions\n\n```php\napp_install_bills_schema(mysqli $conn): void\napp_bills_seed_defaults(mysqli $conn): void\napp_bills_accounts(mysqli $conn): array\napp_bills_all_accounts(mysqli $conn): array\napp_bills_items(mysqli $conn): array\napp_bills_balances(mysqli $conn, int $year, int $month): array       // map: account_id → float\napp_bills_entries(mysqli $conn, int $year, int $month): array        // map: item_id → [due, paid, account_id]\napp_bills_active_months(mysqli $conn, int $year): array\napp_bills_save_balance(mysqli $conn, int $year, int $month, int $accountId, float $balance): void\napp_bills_save_entry(mysqli $conn, int $year, int $month, int $itemId, ?float $due, ?float $paid, ?int $accountId): void\napp_bills_save_account(mysqli $conn, array $data): int\napp_bills_delete_account(mysqli $conn, int $id): void\napp_bills_save_item(mysqli $conn, array $data): int\napp_bills_delete_item(mysqli $conn, int $id): void\napp_bills_reorder_item(mysqli $conn, int $id, string $dir): void\napp_bills_copy_month(mysqli $conn, int $fromYear, int $fromMonth, int $toYear, int $toMonth): int\n```\n\n### UI Features (`bills.php`)\n- Month/year navigation with ◀ / ▶ buttons and active-month pills\n- **Bank Balances section** — editable opening balance per account, inline Save button\n- **Bills table** — spreadsheet-style rows with:\n  - Amount Due (editable, pre-filled from default)\n  - Amount Paid (editable, AJAX auto-save after 600 ms debounce)\n  - Account selector (which bank pays this bill)\n  - Balance After column (computed client-side in real time)\n  - Up/Down sort buttons\n  - Edit and Delete per row\n- **Sticky running totals sidebar** — shows each bank's current balance as bills are entered\n- **Copy from previous month** — modal to copy all entries from a prior month to the current one\n- **Add Bill / Edit Bill modals**\n- **Add Account / Edit Account modals**\n- All saves use POST/Redirect/GET; bill entry changes auto-save via `fetch()` AJAX\n\n### Running Total Calculation\nJavaScript function `recalcTotals()` walks bills in DOM order, maintains a\n`bal[accountId]` map starting from opening balances, subtracts `amount_paid` from the\nselected account for each bill, and updates the \"Balance After\" column and sidebar panel\nin real time — matching the Excel spreadsheet formula logic.\n\n---\n\n## 2. Next-Day Customer Email Job\n\n### File\n- `backend/jobs/send_nextday_customer_emails.php` — 158 lines\n\n### Purpose\nPHP CLI translation of the VBA macro `RunNextDayCustomerEmails()`.\nQueries `setmore_appointments` for appointments scheduled for tomorrow\n(status ≠ Cancelled) and sends a reminder email to each customer.\n\n### Usage\n```bash\n# Normal run (sends real emails)\nphp backend/jobs/send_nextday_customer_emails.php\n\n# Dry run — prints what would be sent, no emails sent\nphp backend/jobs/send_nextday_customer_emails.php --dry-run\n\n# Override date (for testing a specific date)\nphp backend/jobs/send_nextday_customer_emails.php --date=2026-04-09\n```\n\n### Recommended Cron Schedule\n```\n0 20 * * *  php /path/to/backend/jobs/send_nextday_customer_emails.php\n```\nRuns at 8:00 PM every evening, sends reminders for the following day's appointments.\n\n### Email Content\n- Subject: `Reminder: Your appointment at Ella's Alterations tomorrow`\n- Body matches the original VBA email with full address, phone, 5-line award\n  signature block, and a plain-text fallback\n- Uses `app_send_mail()` / PHPMailer\n\n---\n\n## 3. Cron Manager UI\n\n### File\n- `backend/cron_manager.php` — 482 lines\n\n### Purpose\nWeb UI for managing scheduled background jobs. Stores job definitions in the database,\nallows toggling on/off, running immediately, editing schedules, and exporting to\n`/etc/cron.d/` format.\n\n### Database Table (auto-created)\n\n**`cron_job`**\n| Column | Type | Notes |\n|--------|------|-------|\n| `cron_job_id` | INT PK AUTO | |\n| `label` | VARCHAR(120) | Human name |\n| `description` | TEXT | What the job does |\n| `schedule` | VARCHAR(100) | Cron expression e.g. `0 20 * * *` |\n| `command` | VARCHAR(500) | Shell command to run |\n| `enabled` | TINYINT | 0 = disabled, 1 = enabled |\n| `last_run_at` | DATETIME | Updated on \"Run Now\" |\n| `last_output` | TEXT | Captured stdout/stderr |\n| `sort_order` | INT | Display order |\n\n### Seeded Jobs (on first install)\n1. **Next-Day Customer Emails** — `0 20 * * *` — `php backend/jobs/send_nextday_customer_emails.php`\n2. **Morning Jobs** — `0 7 * * *` — `php backend/jobs/morning_jobs.php`\n3. **Nightly Reports** — `0 23 * * *` — `php backend/jobs/nightly_reports.php`\n4. **DB Backup** — `0 2 * * *` — `bash backend/bin/db_backup.sh`\n5. **Daily Cleanup** — `30 3 * * *` — `php backend/jobs/daily_cleanup.php`\n6. **Add Name Records Auto Delete** — `0 4 * * *` — `php backend/jobs/cleanup_name_records.php`\n\nNew jobs are added idempotently (checked by label before inserting) so existing\ninstallations are not re-seeded.\n\n### UI Features\n- Table listing all jobs with schedule, enabled toggle, last run time\n- **Toggle** — flip enabled/disabled immediately (POST/redirect)\n- **▶ Run Now** — executes the command via `exec()`, captures output, stores to DB, shows in modal\n- **Add / Edit** — form with label, description, command, schedule, enabled flag\n- **Schedule presets** — quick-select buttons (hourly, daily at common times, weekly, monthly)\n- `cron_describe(string $expr): string` — converts `0 20 * * *` → \"Daily at 20:00\"\n- **Export Crontab** — writes `/tmp/customerdb_crontab_export.txt` in `/etc/cron.d/` format\n\n---\n\n## 4. Error Log UI\n\n### File\n- `backend/error_log.php` — 262 lines\n\n### Purpose\nDedicated UI for browsing `backend_error_log` records with filtering, pagination,\nand per-entry management.\n\n### Features\n- **Stats bar** — Total errors, Today's errors, Latest error timestamp\n- **Filter bar** — Search (message/context), Source dropdown, Severity dropdown\n- **Pagination** — 50 per page with smart ellipsis navigator\n- **Per-row delete** — removes individual log entries\n- **Clear All button** — truncates the entire log (with confirmation)\n- JSON context blocks displayed in `<details>` collapsibles with dark monospace styling\n- URL: `/backend/error_log.php`\n\n---\n\n## 5. Change Log UI\n\n### File\n- `backend/change_log.php` — 248 lines\n\n### Purpose\nDedicated UI for browsing `backend_change_log` records — audit trail of all\ndata changes across the application.\n\n### Features\n- **Filter bar** — Search, Area, Action type, Entity type dropdowns\n- **Pagination** — smart ellipsis navigator\n- **Per-row detail panels:**\n  - Before / After / Context — collapsed JSON blocks\n  - Changed Data — open by default, shows the changed fields summary\n- Action badges color-coded by type (create, update, delete)\n- URL: `/backend/change_log.php`\n\n---\n\n## 6. Stocks & Crypto Module\n\n### Files\n- `backend/stocks_crypto_service.php` — 269 lines, service layer\n- `backend/stocks_crypto.php` — 667 lines, UI page\n\n### Purpose\nTrack a personal investment portfolio — individual stocks, ETFs, precious metals,\nand crypto. Supports live price fetching, manual daily price entry, monthly crypto\nbuy tracking, and portfolio gain/loss analysis.\n\n### Database Tables (auto-created)\n\n**`stocks_asset`**\n| Column | Type | Notes |\n|--------|------|-------|\n| `stocks_asset_id` | INT PK AUTO | |\n| `ticker` | VARCHAR(20) | e.g. `AAPL`, `BTC`, `GLD` |\n| `name` | VARCHAR(120) | Display name |\n| `asset_type` | ENUM | `stock`, `etf`, `crypto`, `metal`, `other` |\n| `shares` | DECIMAL(18,8) | Quantity owned |\n| `cost_basis_total` | DECIMAL(14,6) | Total purchase cost |\n| `is_active` | TINYINT | Soft hide |\n\n**`stocks_price`**\nDaily price records.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| `stocks_price_id` | INT PK AUTO | |\n| `ticker` | VARCHAR(20) | |\n| `price_date` | DATE | |\n| `price` | DECIMAL(14,6) | |\n| `source` | VARCHAR(40) | `manual` or `yahoo` |\n\nUnique constraint on `(ticker, price_date)` — upserts with `ON DUPLICATE KEY UPDATE`.\n\n**`crypto_monthly_buy`**\n| Column | Type | Notes |\n|--------|------|-------|\n| `crypto_monthly_buy_id` | INT PK AUTO | |\n| `ticker` | VARCHAR(20) | |\n| `year`, `month` | INT | |\n| `quantity` | DECIMAL(18,8) | Crypto units purchased |\n| `amount_usd` | DECIMAL(14,2) | USD spent |\n| `notes` | VARCHAR(255) | |\n\n### Service Functions\n\n```php\napp_install_stocks_schema(mysqli $conn): void\napp_stocks_assets(mysqli $conn, string $type = ''): array\napp_stocks_save_asset(mysqli $conn, array $data): int\napp_stocks_delete_asset(mysqli $conn, int $id): void\napp_stocks_save_price(mysqli $conn, string $ticker, string $date, float $price, string $source = 'manual'): void\napp_stocks_save_prices_bulk(mysqli $conn, string $date, array $prices): int\napp_stocks_latest_prices(mysqli $conn): array                          // map: ticker → [price, date]\napp_stocks_price_history(mysqli $conn, string $ticker, int $limit = 90): array\napp_stocks_fetch_live_price(string $ticker): ?float                    // Yahoo Finance API, 8s timeout\napp_stocks_fetch_all_live(mysqli $conn): array                         // fetches all active tickers\napp_crypto_monthly_buys(mysqli $conn, int $year, int $month = 0): array\napp_crypto_save_monthly_buy(mysqli $conn, array $data): void\napp_crypto_delete_monthly_buy(mysqli $conn, int $id): void\napp_stocks_dashboard(mysqli $conn): array                              // cost_basis, current_value, gain_loss, gain_pct per asset\napp_stocks_stats(mysqli $conn): array                                  // total portfolio stats\n```\n\n### Live Price Source\nYahoo Finance unofficial API:\n```\nhttps://query1.finance.yahoo.com/v8/finance/chart/{TICKER}?interval=1d&range=1d\n```\n8-second timeout, reads `.chart.result[0].meta.regularMarketPrice`.\n\n### UI Tabs (`stocks_crypto.php`)\n\n1. **Portfolio** — dashboard table with ticker, shares, cost basis, current value,\n   gain/loss, gain %, latest price date. Stats bar shows total value, total cost,\n   total gain/loss. \"Fetch Live Prices\" button calls Yahoo Finance for all tickers.\n\n2. **Enter Prices** — manual daily price entry grid for all active assets,\n   date picker (defaults to today), bulk save.\n\n3. **Crypto Buys** — monthly crypto purchase log. Month/year selector, table of\n   ticker/quantity/USD/notes rows, add and delete per entry.\n\n4. **Add Asset** — form to add a new stock, ETF, crypto, metal, or other asset.\n\n### Auto-Refresh\nA checkbox above the stats bar auto-refreshes the Portfolio tab every 10 seconds.\nState persists in `localStorage` key `sc_auto_refresh`. On reload, strips `?ok=`\nand `?warn=` query params to prevent the notice from repeating every 10 seconds.\n\n---\n\n## 7. Backend Home — New Cards (`index.php`)\n\nSix new cards added to the backend home dashboard:\n\n| Card | Link | Secondary Action |\n|------|------|-----------------|\n| Customer Totals | `/backend/customer_totals.php` | — |\n| Ambient Weather | `/backend/ambient_weather.php` | — |\n| Bills Manager | `/backend/bills.php` | — |\n| Stocks & Crypto | `/backend/stocks_crypto.php` | — |\n| Cron Manager | `/backend/cron_manager.php` | — |\n| Error Log | `/backend/error_log.php` | Change Log |\n\n---\n\n## 8. Documents Editor — Full Rewrite (`documents.php`)\n\n### Problem\nGitHub Copilot introduced several bugs into the previous version:\n- `docLoad()` had mismatched closing braces, breaking the entire function\n- The document library was constrained to ~40% page width inside a grid column\n- The editor was a plain `<textarea>` with no formatting support\n\n### Solution\nComplete rewrite of all HTML, CSS, and JavaScript. PHP POST handlers were kept\nidentical — only the front-end was replaced.\n\n### Editor: EasyMDE\nReplaced the plain textarea with **EasyMDE** (Easy Markdown Editor) via CDN:\n```html\n<link rel=\"stylesheet\" href=\"https://unpkg.com/easymde/dist/easymde.min.css\">\n<script src=\"https://unpkg.com/easymde/dist/easymde.min.js\"></script>\n```\n\nEasyMDE wraps the `<textarea id=\"content_markdown\">` and syncs content on form submit.\n`ta.value = easyMDE.value()` is called explicitly in `submitDoc()` before `form.submit()`.\n\n### Toolbar Buttons\nSave (custom gradient btn) | Bold · Italic · Strikethrough | H1 · H2 · H3 |\nUnordered List · Ordered List · Checklist (custom) | Quote · Code · Table |\nHR · Link · Image URL (custom) | Undo · Redo | Fullscreen | Guide\n\n- **Save** button in toolbar calls `submitDoc()`, same as the Save Document button below\n- **Ctrl+S / Cmd+S** keyboard shortcut via CodeMirror `extraKeys`\n- **Checklist** inserts `- [ ] ` prefix on selected text\n- **Image URL** prompts for URL and alt text, inserts `![alt](url)` syntax\n\n### Preview Toggle\nEasyMDE's built-in `preview` and `side-by-side` buttons were **removed** to prevent\nboth raw markdown and rendered HTML showing simultaneously.\n\nA custom **Preview** button in the panel header replaces them:\n- Uses `marked.js` (CDN) to render the markdown client-side\n- **Preview on**: hides `EasyMDEContainer` and highlight strip; shows `#doc-preview-pane`\n- **Edit on**: hides preview pane; shows EasyMDE and highlight strip; calls `codemirror.refresh()`\n- Loading a document via `docLoad()` automatically returns to edit mode\n- Button state: pill shape, switches between \"👁 Preview\" and \"✏ Edit\" labels\n\n```html\n<script src=\"https://cdn.jsdelivr.net/npm/marked/marked.min.js\"></script>\n```\n\n### `docLoad()` — Clean Rewrite\nOld function had mismatched braces and redundant `editor.value` assignments.\nNew function:\n1. Returns to edit mode if preview is on\n2. Sets heading to \"Loading…\"\n3. Highlights active `<tr>` and `<a>` in library immediately\n4. `fetch('/backend/api/documents.php?backend_document_id=' + id)`\n5. Populates all meta fields (type, title, slug, summary)\n6. Sets `easyMDE.value(content)` from `editor_content` or `content_markdown`\n7. Shows/hides file notice\n8. Calls `renderVersionList(data.versions)`\n9. Updates URL via `history.replaceState()`\n10. Flashes panel border with accent color for 800 ms\n\n### Library Panel — Full Width\nOld layout: library was inside a 2-column grid alongside the editor.\nNew layout:\n```\n[Editor Panel          — full width]\n[Library Panel         — full width, max-height: 460px scrollable]\n[Upload | Versions     — 2-column row]\n```\n\nLive client-side search filters table rows by `textContent` without a page reload.\n\n### Word Count & Highlights\n- Word count and char count update on every keystroke via `codemirror.on('change', ...)`\n- 6 highlight color swatches + a clear option wrap selected text in\n  `<span class=\"hl\" style=\"background:COLOR\">...</span>`\n- Clear highlight strips existing `<span class=\"hl\">` wrappers from selected text\n\n### CSS Theme Conformity (visit.html standard)\nAll custom CSS was updated to match the application theme:\n\n| Property | Before | After |\n|----------|--------|-------|\n| Form input border-radius | `10px` | `12px` (matches `--radius-sm`) |\n| Form input padding | `8px 10px` | `11px 14px` |\n| Field label font-size | `0.73rem` + uppercase | `0.82rem`, no forced uppercase |\n| Field label letter-spacing | `0.07em` | `0.04em` |\n| Focus ring | `outline: 2px solid var(--accent)` | `outline: 2px solid rgba(175,77,49,0.3)` |\n| Panel header background | `rgba(244,239,231,0.6)` hardcoded | `var(--panel)` |\n| Toolbar background | `rgba(244,239,231,0.7)` hardcoded | `rgba(255,255,255,0.55)` |\n| Action bar background | `rgba(244,239,231,0.4)` hardcoded | `rgba(255,255,255,0.25)` |\n| Save button | `background: var(--accent)` | `linear-gradient(135deg, var(--accent), var(--accent-deep))` |\n| Action buttons | `border-radius: 7px` | `border-radius: 999px` pill shape |\n| Active library row tint | `rgba(26,122,154,0.06)` teal | `rgba(175,77,49,0.07)` accent |\n| Type badge (markdown) | `rgba(26,122,154,0.1)` teal | `rgba(175,77,49,0.1)` accent |\n| File notice tint | `rgba(26,122,154,0.06)` teal | `rgba(175,77,49,0.05)` accent |\n\n---\n\n## 9. `document_service.php` — Parse Error Fix\n\n### Problem\nThe function `app_backend_documents_dir()` had its closing `return $path; }` accidentally\ndisplaced to after `app_document_can_edit_inline()` (lines 147–148), with the rest of the\nfile's functions (`app_libreoffice_convert_to_html`, etc.) nested inside the unclosed\nfunction body. This caused a PHP parse error on every request to any page that\n`require_once`'s `document_service.php`, making `app_document_can_edit_inline()`\nappear undefined.\n\n### Fix\nTwo edits to `document_service.php`:\n\n1. Closed `app_backend_documents_dir()` properly after the `mkdir` block:\n```php\nfunction app_backend_documents_dir(): string\n{\n    $path = __DIR__ . '/documents_storage';\n    if (!is_dir($path)) {\n        mkdir($path, 0775, true);\n    }\n    return $path;   // ← added\n}                   // ← added\n```\n\n2. Removed the orphaned `return $path; }` that had been displaced to after\n`app_document_can_edit_inline()` at lines 147–148.\n\n---\n\n## Access URLs\n\n| Module | URL |\n|--------|-----|\n| Backend Home | `/backend/` |\n| Bills Manager | `/backend/bills.php` |\n| Stocks & Crypto | `/backend/stocks_crypto.php` |\n| Cron Manager | `/backend/cron_manager.php` |\n| Error Log | `/backend/error_log.php` |\n| Change Log | `/backend/change_log.php` |\n| Documents | `/backend/documents.php` |\n| Documents API | `/backend/api/documents.php` |\n\n---\n\n## Technology Used\n\n| Library | Version | Purpose |\n|---------|---------|---------|\n| EasyMDE | latest (unpkg CDN) | Rich markdown editor |\n| marked.js | latest (jsdelivr CDN) | Client-side markdown → HTML rendering |\n| Yahoo Finance API | v8 (unofficial) | Live stock/ETF price fetching |\n| PHPMailer | (existing) | Email sending via `app_send_mail()` |\n\n---\n\n## Coding Conventions (consistent with existing codebase)\n\n- `declare(strict_types=1)` in all PHP files\n- `app_db()` for database connections, `mysqli` throughout\n- `app_query_all()`, `app_query_one()`, `app_h()`, `app_send_json()` helpers\n- `app_log_backend_exception()` for error logging\n- POST/Redirect/GET for all form submissions\n- `ON DUPLICATE KEY UPDATE` for safe upserts\n- `app_backend_render_header()` / `app_backend_render_footer()` for page chrome\n- CSS custom properties: `--accent`, `--panel`, `--line`, `--text`, `--muted`, `--shadow`\n- All new tables use `CREATE TABLE IF NOT EXISTS` (idempotent, no separate migration needed)\n","is_text_editable":1,"can_edit_inline":1}
After
{"backend_document_id":"10","document_type":"upload","title":"Claude 04-07-2026","slug":"claude-04-07-2026","summary_text":"Claude 04-07-2026 fixing backend Document areas","content_markdown":"# Session Log — 2026-04-07\r\n\r\nAll work completed in this session on the CustomerDB backend application.\r\n\r\n---\r\n\r\n## Summary of New Modules and Changes\r\n\r\n| Area | File(s) | Status |\r\n|------|---------|--------|\r\n| Bills Manager | `backend/bills_service.php`, `backend/bills.php` | New |\r\n| Next-Day Email Job | `backend/jobs/send_nextday_customer_emails.php` | New |\r\n| Cron Manager UI | `backend/cron_manager.php` | New |\r\n| Error Log UI | `backend/error_log.php` | New |\r\n| Change Log UI | `backend/change_log.php` | New |\r\n| Stocks & Crypto | `backend/stocks_crypto_service.php`, `backend/stocks_crypto.php` | New |\r\n| Backend Home | `backend/index.php` | Modified |\r\n| Documents Editor | `backend/documents.php` | Full rewrite |\r\n| Documents Service | `backend/document_service.php` | Bug fix |\r\n\r\n---\r\n\r\n## 1. Bills Manager\r\n\r\n### Files\r\n- `backend/bills_service.php` — 356 lines, service layer\r\n- `backend/bills.php` — 972 lines, UI page\r\n\r\n### Purpose\r\nReplaces a spreadsheet (`newbills2026.xlsx`) with a web-based bill payment tracker.\r\nTracks bank account opening balances, monthly bill payments, and computes running bank\r\nbalances in the same layout as the Excel spreadsheet.\r\n\r\n### Database Tables (auto-created on first load)\r\n\r\n**`bills_account`**\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `bills_account_id` | INT PK AUTO | |\r\n| `name` | VARCHAR(120) | Bank name |\r\n| `sort_order` | INT | Display order |\r\n\r\n**`bills_item`**\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `bills_item_id` | INT PK AUTO | |\r\n| `label` | VARCHAR(200) | Bill name |\r\n| `default_amount` | DECIMAL(12,2) | Pre-fills the Due column |\r\n| `default_account_id` | INT | Default bank to debit |\r\n| `notes` | TEXT | Instructions / URLs |\r\n| `sort_order` | INT | Row order |\r\n| `is_deleted` | TINYINT | Soft delete |\r\n\r\n**`bills_entry`**\r\nMonthly bill payment rows.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `bills_entry_id` | INT PK AUTO | |\r\n| `bills_item_id` | INT | FK to `bills_item` |\r\n| `year`, `month` | INT | Billing period |\r\n| `amount_due` | DECIMAL(12,2) | Amount billed |\r\n| `amount_paid` | DECIMAL(12,2) | Amount actually paid |\r\n| `account_id` | INT | Bank used to pay |\r\n\r\n**`bills_balance`**\r\nOpening bank balances per month.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `bills_balance_id` | INT PK AUTO | |\r\n| `account_id` | INT | FK to `bills_account` |\r\n| `year`, `month` | INT | Period |\r\n| `opening_balance` | DECIMAL(14,2) | Balance at start of month |\r\n\r\n### Seed Data\r\nOn first load (empty table), the following are auto-seeded from the original Excel file:\r\n\r\n**Accounts:** USAA, MIDFLORIDA, Centenial, CapitalOne\r\n\r\n**Bills (11 items):** MidFlorida Mortgage, MidFlorida Credit Card, USAA Credit Card,\r\nCentenial Bank, Electricity, Waste Management, Comcast/Xfinity, Insurance, Water,\r\nCapitalOne #1, CapitalOne #2\r\n\r\n### Service Functions\r\n\r\n```php\r\napp_install_bills_schema(mysqli $conn): void\r\napp_bills_seed_defaults(mysqli $conn): void\r\napp_bills_accounts(mysqli $conn): array\r\napp_bills_all_accounts(mysqli $conn): array\r\napp_bills_items(mysqli $conn): array\r\napp_bills_balances(mysqli $conn, int $year, int $month): array       // map: account_id → float\r\napp_bills_entries(mysqli $conn, int $year, int $month): array        // map: item_id → [due, paid, account_id]\r\napp_bills_active_months(mysqli $conn, int $year): array\r\napp_bills_save_balance(mysqli $conn, int $year, int $month, int $accountId, float $balance): void\r\napp_bills_save_entry(mysqli $conn, int $year, int $month, int $itemId, ?float $due, ?float $paid, ?int $accountId): void\r\napp_bills_save_account(mysqli $conn, array $data): int\r\napp_bills_delete_account(mysqli $conn, int $id): void\r\napp_bills_save_item(mysqli $conn, array $data): int\r\napp_bills_delete_item(mysqli $conn, int $id): void\r\napp_bills_reorder_item(mysqli $conn, int $id, string $dir): void\r\napp_bills_copy_month(mysqli $conn, int $fromYear, int $fromMonth, int $toYear, int $toMonth): int\r\n```\r\n\r\n### UI Features (`bills.php`)\r\n- Month/year navigation with ◀ / ▶ buttons and active-month pills\r\n- **Bank Balances section** — editable opening balance per account, inline Save button\r\n- **Bills table** — spreadsheet-style rows with:\r\n  - Amount Due (editable, pre-filled from default)\r\n  - Amount Paid (editable, AJAX auto-save after 600 ms debounce)\r\n  - Account selector (which bank pays this bill)\r\n  - Balance After column (computed client-side in real time)\r\n  - Up/Down sort buttons\r\n  - Edit and Delete per row\r\n- **Sticky running totals sidebar** — shows each bank's current balance as bills are entered\r\n- **Copy from previous month** — modal to copy all entries from a prior month to the current one\r\n- **Add Bill / Edit Bill modals**\r\n- **Add Account / Edit Account modals**\r\n- All saves use POST/Redirect/GET; bill entry changes auto-save via `fetch()` AJAX\r\n\r\n### Running Total Calculation\r\nJavaScript function `recalcTotals()` walks bills in DOM order, maintains a\r\n`bal[accountId]` map starting from opening balances, subtracts `amount_paid` from the\r\nselected account for each bill, and updates the \"Balance After\" column and sidebar panel\r\nin real time — matching the Excel spreadsheet formula logic.\r\n\r\n---\r\n\r\n## 2. Next-Day Customer Email Job\r\n\r\n### File\r\n- `backend/jobs/send_nextday_customer_emails.php` — 158 lines\r\n\r\n### Purpose\r\nPHP CLI translation of the VBA macro `RunNextDayCustomerEmails()`.\r\nQueries `setmore_appointments` for appointments scheduled for tomorrow\r\n(status ≠ Cancelled) and sends a reminder email to each customer.\r\n\r\n### Usage\r\n```bash\r\n# Normal run (sends real emails)\r\nphp backend/jobs/send_nextday_customer_emails.php\r\n\r\n# Dry run — prints what would be sent, no emails sent\r\nphp backend/jobs/send_nextday_customer_emails.php --dry-run\r\n\r\n# Override date (for testing a specific date)\r\nphp backend/jobs/send_nextday_customer_emails.php --date=2026-04-09\r\n```\r\n\r\n### Recommended Cron Schedule\r\n```\r\n0 20 * * *  php /path/to/backend/jobs/send_nextday_customer_emails.php\r\n```\r\nRuns at 8:00 PM every evening, sends reminders for the following day's appointments.\r\n\r\n### Email Content\r\n- Subject: `Reminder: Your appointment at Ella's Alterations tomorrow`\r\n- Body matches the original VBA email with full address, phone, 5-line award\r\n  signature block, and a plain-text fallback\r\n- Uses `app_send_mail()` / PHPMailer\r\n\r\n---\r\n\r\n## 3. Cron Manager UI\r\n\r\n### File\r\n- `backend/cron_manager.php` — 482 lines\r\n\r\n### Purpose\r\nWeb UI for managing scheduled background jobs. Stores job definitions in the database,\r\nallows toggling on/off, running immediately, editing schedules, and exporting to\r\n`/etc/cron.d/` format.\r\n\r\n### Database Table (auto-created)\r\n\r\n**`cron_job`**\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `cron_job_id` | INT PK AUTO | |\r\n| `label` | VARCHAR(120) | Human name |\r\n| `description` | TEXT | What the job does |\r\n| `schedule` | VARCHAR(100) | Cron expression e.g. `0 20 * * *` |\r\n| `command` | VARCHAR(500) | Shell command to run |\r\n| `enabled` | TINYINT | 0 = disabled, 1 = enabled |\r\n| `last_run_at` | DATETIME | Updated on \"Run Now\" |\r\n| `last_output` | TEXT | Captured stdout/stderr |\r\n| `sort_order` | INT | Display order |\r\n\r\n### Seeded Jobs (on first install)\r\n1. **Next-Day Customer Emails** — `0 20 * * *` — `php backend/jobs/send_nextday_customer_emails.php`\r\n2. **Morning Jobs** — `0 7 * * *` — `php backend/jobs/morning_jobs.php`\r\n3. **Nightly Reports** — `0 23 * * *` — `php backend/jobs/nightly_reports.php`\r\n4. **DB Backup** — `0 2 * * *` — `bash backend/bin/db_backup.sh`\r\n5. **Daily Cleanup** — `30 3 * * *` — `php backend/jobs/daily_cleanup.php`\r\n6. **Add Name Records Auto Delete** — `0 4 * * *` — `php backend/jobs/cleanup_name_records.php`\r\n\r\nNew jobs are added idempotently (checked by label before inserting) so existing\r\ninstallations are not re-seeded.\r\n\r\n### UI Features\r\n- Table listing all jobs with schedule, enabled toggle, last run time\r\n- **Toggle** — flip enabled/disabled immediately (POST/redirect)\r\n- **▶ Run Now** — executes the command via `exec()`, captures output, stores to DB, shows in modal\r\n- **Add / Edit** — form with label, description, command, schedule, enabled flag\r\n- **Schedule presets** — quick-select buttons (hourly, daily at common times, weekly, monthly)\r\n- `cron_describe(string $expr): string` — converts `0 20 * * *` → \"Daily at 20:00\"\r\n- **Export Crontab** — writes `/tmp/customerdb_crontab_export.txt` in `/etc/cron.d/` format\r\n\r\n---\r\n\r\n## 4. Error Log UI\r\n\r\n### File\r\n- `backend/error_log.php` — 262 lines\r\n\r\n### Purpose\r\nDedicated UI for browsing `backend_error_log` records with filtering, pagination,\r\nand per-entry management.\r\n\r\n### Features\r\n- **Stats bar** — Total errors, Today's errors, Latest error timestamp\r\n- **Filter bar** — Search (message/context), Source dropdown, Severity dropdown\r\n- **Pagination** — 50 per page with smart ellipsis navigator\r\n- **Per-row delete** — removes individual log entries\r\n- **Clear All button** — truncates the entire log (with confirmation)\r\n- JSON context blocks displayed in `<details>` collapsibles with dark monospace styling\r\n- URL: `/backend/error_log.php`\r\n\r\n---\r\n\r\n## 5. Change Log UI\r\n\r\n### File\r\n- `backend/change_log.php` — 248 lines\r\n\r\n### Purpose\r\nDedicated UI for browsing `backend_change_log` records — audit trail of all\r\ndata changes across the application.\r\n\r\n### Features\r\n- **Filter bar** — Search, Area, Action type, Entity type dropdowns\r\n- **Pagination** — smart ellipsis navigator\r\n- **Per-row detail panels:**\r\n  - Before / After / Context — collapsed JSON blocks\r\n  - Changed Data — open by default, shows the changed fields summary\r\n- Action badges color-coded by type (create, update, delete)\r\n- URL: `/backend/change_log.php`\r\n\r\n---\r\n\r\n## 6. Stocks & Crypto Module\r\n\r\n### Files\r\n- `backend/stocks_crypto_service.php` — 269 lines, service layer\r\n- `backend/stocks_crypto.php` — 667 lines, UI page\r\n\r\n### Purpose\r\nTrack a personal investment portfolio — individual stocks, ETFs, precious metals,\r\nand crypto. Supports live price fetching, manual daily price entry, monthly crypto\r\nbuy tracking, and portfolio gain/loss analysis.\r\n\r\n### Database Tables (auto-created)\r\n\r\n**`stocks_asset`**\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `stocks_asset_id` | INT PK AUTO | |\r\n| `ticker` | VARCHAR(20) | e.g. `AAPL`, `BTC`, `GLD` |\r\n| `name` | VARCHAR(120) | Display name |\r\n| `asset_type` | ENUM | `stock`, `etf`, `crypto`, `metal`, `other` |\r\n| `shares` | DECIMAL(18,8) | Quantity owned |\r\n| `cost_basis_total` | DECIMAL(14,6) | Total purchase cost |\r\n| `is_active` | TINYINT | Soft hide |\r\n\r\n**`stocks_price`**\r\nDaily price records.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `stocks_price_id` | INT PK AUTO | |\r\n| `ticker` | VARCHAR(20) | |\r\n| `price_date` | DATE | |\r\n| `price` | DECIMAL(14,6) | |\r\n| `source` | VARCHAR(40) | `manual` or `yahoo` |\r\n\r\nUnique constraint on `(ticker, price_date)` — upserts with `ON DUPLICATE KEY UPDATE`.\r\n\r\n**`crypto_monthly_buy`**\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `crypto_monthly_buy_id` | INT PK AUTO | |\r\n| `ticker` | VARCHAR(20) | |\r\n| `year`, `month` | INT | |\r\n| `quantity` | DECIMAL(18,8) | Crypto units purchased |\r\n| `amount_usd` | DECIMAL(14,2) | USD spent |\r\n| `notes` | VARCHAR(255) | |\r\n\r\n### Service Functions\r\n\r\n```php\r\napp_install_stocks_schema(mysqli $conn): void\r\napp_stocks_assets(mysqli $conn, string $type = ''): array\r\napp_stocks_save_asset(mysqli $conn, array $data): int\r\napp_stocks_delete_asset(mysqli $conn, int $id): void\r\napp_stocks_save_price(mysqli $conn, string $ticker, string $date, float $price, string $source = 'manual'): void\r\napp_stocks_save_prices_bulk(mysqli $conn, string $date, array $prices): int\r\napp_stocks_latest_prices(mysqli $conn): array                          // map: ticker → [price, date]\r\napp_stocks_price_history(mysqli $conn, string $ticker, int $limit = 90): array\r\napp_stocks_fetch_live_price(string $ticker): ?float                    // Yahoo Finance API, 8s timeout\r\napp_stocks_fetch_all_live(mysqli $conn): array                         // fetches all active tickers\r\napp_crypto_monthly_buys(mysqli $conn, int $year, int $month = 0): array\r\napp_crypto_save_monthly_buy(mysqli $conn, array $data): void\r\napp_crypto_delete_monthly_buy(mysqli $conn, int $id): void\r\napp_stocks_dashboard(mysqli $conn): array                              // cost_basis, current_value, gain_loss, gain_pct per asset\r\napp_stocks_stats(mysqli $conn): array                                  // total portfolio stats\r\n```\r\n\r\n### Live Price Source\r\nYahoo Finance unofficial API:\r\n```\r\nhttps://query1.finance.yahoo.com/v8/finance/chart/{TICKER}?interval=1d&range=1d\r\n```\r\n8-second timeout, reads `.chart.result[0].meta.regularMarketPrice`.\r\n\r\n### UI Tabs (`stocks_crypto.php`)\r\n\r\n1. **Portfolio** — dashboard table with ticker, shares, cost basis, current value,\r\n   gain/loss, gain %, latest price date. Stats bar shows total value, total cost,\r\n   total gain/loss. \"Fetch Live Prices\" button calls Yahoo Finance for all tickers.\r\n\r\n2. **Enter Prices** — manual daily price entry grid for all active assets,\r\n   date picker (defaults to today), bulk save.\r\n\r\n3. **Crypto Buys** — monthly crypto purchase log. Month/year selector, table of\r\n   ticker/quantity/USD/notes rows, add and delete per entry.\r\n\r\n4. **Add Asset** — form to add a new stock, ETF, crypto, metal, or other asset.\r\n\r\n### Auto-Refresh\r\nA checkbox above the stats bar auto-refreshes the Portfolio tab every 10 seconds.\r\nState persists in `localStorage` key `sc_auto_refresh`. On reload, strips `?ok=`\r\nand `?warn=` query params to prevent the notice from repeating every 10 seconds.\r\n\r\n---\r\n\r\n## 7. Backend Home — New Cards (`index.php`)\r\n\r\nSix new cards added to the backend home dashboard:\r\n\r\n| Card | Link | Secondary Action |\r\n|------|------|-----------------|\r\n| Customer Totals | `/backend/customer_totals.php` | — |\r\n| Ambient Weather | `/backend/ambient_weather.php` | — |\r\n| Bills Manager | `/backend/bills.php` | — |\r\n| Stocks & Crypto | `/backend/stocks_crypto.php` | — |\r\n| Cron Manager | `/backend/cron_manager.php` | — |\r\n| Error Log | `/backend/error_log.php` | Change Log |\r\n\r\n---\r\n\r\n## 8. Documents Editor — Full Rewrite (`documents.php`)\r\n\r\n### Problem\r\nGitHub Copilot introduced several bugs into the previous version:\r\n- `docLoad()` had mismatched closing braces, breaking the entire function\r\n- The document library was constrained to ~40% page width inside a grid column\r\n- The editor was a plain `<textarea>` with no formatting support\r\n\r\n### Solution\r\nComplete rewrite of all HTML, CSS, and JavaScript. PHP POST handlers were kept\r\nidentical — only the front-end was replaced.\r\n\r\n### Editor: EasyMDE\r\nReplaced the plain textarea with **EasyMDE** (Easy Markdown Editor) via CDN:\r\n```html\r\n<link rel=\"stylesheet\" href=\"https://unpkg.com/easymde/dist/easymde.min.css\">\r\n<script src=\"https://unpkg.com/easymde/dist/easymde.min.js\"></script>\r\n```\r\n\r\nEasyMDE wraps the `<textarea id=\"content_markdown\">` and syncs content on form submit.\r\n`ta.value = easyMDE.value()` is called explicitly in `submitDoc()` before `form.submit()`.\r\n\r\n### Toolbar Buttons\r\nSave (custom gradient btn) | Bold · Italic · Strikethrough | H1 · H2 · H3 |\r\nUnordered List · Ordered List · Checklist (custom) | Quote · Code · Table |\r\nHR · Link · Image URL (custom) | Undo · Redo | Fullscreen | Guide\r\n\r\n- **Save** button in toolbar calls `submitDoc()`, same as the Save Document button below\r\n- **Ctrl+S / Cmd+S** keyboard shortcut via CodeMirror `extraKeys`\r\n- **Checklist** inserts `- [ ] ` prefix on selected text\r\n- **Image URL** prompts for URL and alt text, inserts `![alt](url)` syntax\r\n\r\n### Preview Toggle\r\nEasyMDE's built-in `preview` and `side-by-side` buttons were **removed** to prevent\r\nboth raw markdown and rendered HTML showing simultaneously.\r\n\r\nA custom **Preview** button in the panel header replaces them:\r\n- Uses `marked.js` (CDN) to render the markdown client-side\r\n- **Preview on**: hides `EasyMDEContainer` and highlight strip; shows `#doc-preview-pane`\r\n- **Edit on**: hides preview pane; shows EasyMDE and highlight strip; calls `codemirror.refresh()`\r\n- Loading a document via `docLoad()` automatically returns to edit mode\r\n- Button state: pill shape, switches between \"👁 Preview\" and \"✏ Edit\" labels\r\n\r\n```html\r\n<script src=\"https://cdn.jsdelivr.net/npm/marked/marked.min.js\"></script>\r\n```\r\n\r\n### `docLoad()` — Clean Rewrite\r\nOld function had mismatched braces and redundant `editor.value` assignments.\r\nNew function:\r\n1. Returns to edit mode if preview is on\r\n2. Sets heading to \"Loading…\"\r\n3. Highlights active `<tr>` and `<a>` in library immediately\r\n4. `fetch('/backend/api/documents.php?backend_document_id=' + id)`\r\n5. Populates all meta fields (type, title, slug, summary)\r\n6. Sets `easyMDE.value(content)` from `editor_content` or `content_markdown`\r\n7. Shows/hides file notice\r\n8. Calls `renderVersionList(data.versions)`\r\n9. Updates URL via `history.replaceState()`\r\n10. Flashes panel border with accent color for 800 ms\r\n\r\n### Library Panel — Full Width\r\nOld layout: library was inside a 2-column grid alongside the editor.\r\nNew layout:\r\n```\r\n[Editor Panel          — full width]\r\n[Library Panel         — full width, max-height: 460px scrollable]\r\n[Upload | Versions     — 2-column row]\r\n```\r\n\r\nLive client-side search filters table rows by `textContent` without a page reload.\r\n\r\n### Word Count & Highlights\r\n- Word count and char count update on every keystroke via `codemirror.on('change', ...)`\r\n- 6 highlight color swatches + a clear option wrap selected text in\r\n  `<span class=\"hl\" style=\"background:COLOR\">...</span>`\r\n- Clear highlight strips existing `<span class=\"hl\">` wrappers from selected text\r\n\r\n### CSS Theme Conformity (visit.html standard)\r\nAll custom CSS was updated to match the application theme:\r\n\r\n| Property | Before | After |\r\n|----------|--------|-------|\r\n| Form input border-radius | `10px` | `12px` (matches `--radius-sm`) |\r\n| Form input padding | `8px 10px` | `11px 14px` |\r\n| Field label font-size | `0.73rem` + uppercase | `0.82rem`, no forced uppercase |\r\n| Field label letter-spacing | `0.07em` | `0.04em` |\r\n| Focus ring | `outline: 2px solid var(--accent)` | `outline: 2px solid rgba(175,77,49,0.3)` |\r\n| Panel header background | `rgba(244,239,231,0.6)` hardcoded | `var(--panel)` |\r\n| Toolbar background | `rgba(244,239,231,0.7)` hardcoded | `rgba(255,255,255,0.55)` |\r\n| Action bar background | `rgba(244,239,231,0.4)` hardcoded | `rgba(255,255,255,0.25)` |\r\n| Save button | `background: var(--accent)` | `linear-gradient(135deg, var(--accent), var(--accent-deep))` |\r\n| Action buttons | `border-radius: 7px` | `border-radius: 999px` pill shape |\r\n| Active library row tint | `rgba(26,122,154,0.06)` teal | `rgba(175,77,49,0.07)` accent |\r\n| Type badge (markdown) | `rgba(26,122,154,0.1)` teal | `rgba(175,77,49,0.1)` accent |\r\n| File notice tint | `rgba(26,122,154,0.06)` teal | `rgba(175,77,49,0.05)` accent |\r\n\r\n---\r\n\r\n## 9. `document_service.php` — Parse Error Fix\r\n\r\n### Problem\r\nThe function `app_backend_documents_dir()` had its closing `return $path; }` accidentally\r\ndisplaced to after `app_document_can_edit_inline()` (lines 147–148), with the rest of the\r\nfile's functions (`app_libreoffice_convert_to_html`, etc.) nested inside the unclosed\r\nfunction body. This caused a PHP parse error on every request to any page that\r\n`require_once`'s `document_service.php`, making `app_document_can_edit_inline()`\r\nappear undefined.\r\n\r\n### Fix\r\nTwo edits to `document_service.php`:\r\n\r\n1. Closed `app_backend_documents_dir()` properly after the `mkdir` block:\r\n```php\r\nfunction app_backend_documents_dir(): string\r\n{\r\n    $path = __DIR__ . '/documents_storage';\r\n    if (!is_dir($path)) {\r\n        mkdir($path, 0775, true);\r\n    }\r\n    return $path;   // ← added\r\n}                   // ← added\r\n```\r\n\r\n2. Removed the orphaned `return $path; }` that had been displaced to after\r\n`app_document_can_edit_inline()` at lines 147–148.\r\n\r\n---\r\n\r\n## Access URLs\r\n\r\n| Module | URL |\r\n|--------|-----|\r\n| Backend Home | `/backend/` |\r\n| Bills Manager | `/backend/bills.php` |\r\n| Stocks & Crypto | `/backend/stocks_crypto.php` |\r\n| Cron Manager | `/backend/cron_manager.php` |\r\n| Error Log | `/backend/error_log.php` |\r\n| Change Log | `/backend/change_log.php` |\r\n| Documents | `/backend/documents.php` |\r\n| Documents API | `/backend/api/documents.php` |\r\n\r\n---\r\n\r\n## Technology Used\r\n\r\n| Library | Version | Purpose |\r\n|---------|---------|---------|\r\n| EasyMDE | latest (unpkg CDN) | Rich markdown editor |\r\n| marked.js | latest (jsdelivr CDN) | Client-side markdown → HTML rendering |\r\n| Yahoo Finance API | v8 (unofficial) | Live stock/ETF price fetching |\r\n| PHPMailer | (existing) | Email sending via `app_send_mail()` |\r\n\r\n---\r\n\r\n## Coding Conventions (consistent with existing codebase)\r\n\r\n- `declare(strict_types=1)` in all PHP files\r\n- `app_db()` for database connections, `mysqli` throughout\r\n- `app_query_all()`, `app_query_one()`, `app_h()`, `app_send_json()` helpers\r\n- `app_log_backend_exception()` for error logging\r\n- POST/Redirect/GET for all form submissions\r\n- `ON DUPLICATE KEY UPDATE` for safe upserts\r\n- `app_backend_render_header()` / `app_backend_render_footer()` for page chrome\r\n- CSS custom properties: `--accent`, `--panel`, `--line`, `--text`, `--muted`, `--shadow`\r\n- All new tables use `CREATE TABLE IF NOT EXISTS` (idempotent, no separate migration needed)","content_html":"<h1>Session Log — 2026-04-07</h1>\n<p>All work completed in this session on the CustomerDB backend application.</p>\n<p>---</p>\n<h2>Summary of New Modules and Changes</h2>\n<p>| Area | File(s) | Status |</p>\n<p>|------|---------|--------|</p>\n<p>| Bills Manager | `backend/bills_service.php`, `backend/bills.php` | New |</p>\n<p>| Next-Day Email Job | `backend/jobs/send_nextday_customer_emails.php` | New |</p>\n<p>| Cron Manager UI | `backend/cron_manager.php` | New |</p>\n<p>| Error Log UI | `backend/error_log.php` | New |</p>\n<p>| Change Log UI | `backend/change_log.php` | New |</p>\n<p>| Stocks &amp; Crypto | `backend/stocks_crypto_service.php`, `backend/stocks_crypto.php` | New |</p>\n<p>| Backend Home | `backend/index.php` | Modified |</p>\n<p>| Documents Editor | `backend/documents.php` | Full rewrite |</p>\n<p>| Documents Service | `backend/document_service.php` | Bug fix |</p>\n<p>---</p>\n<h2>1. Bills Manager</h2>\n<h3>Files</h3>\n<ul>\n<li>`backend/bills_service.php` — 356 lines, service layer</li>\n<li>`backend/bills.php` — 972 lines, UI page</li>\n</ul>\n<h3>Purpose</h3>\n<p>Replaces a spreadsheet (`newbills2026.xlsx`) with a web-based bill payment tracker.</p>\n<p>Tracks bank account opening balances, monthly bill payments, and computes running bank</p>\n<p>balances in the same layout as the Excel spreadsheet.</p>\n<h3>Database Tables (auto-created on first load)</h3>\n<p><strong>`bills_account`</strong></p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| `bills_account_id` | INT PK AUTO | |</p>\n<p>| `name` | VARCHAR(120) | Bank name |</p>\n<p>| `sort_order` | INT | Display order |</p>\n<p><strong>`bills_item`</strong></p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| `bills_item_id` | INT PK AUTO | |</p>\n<p>| `label` | VARCHAR(200) | Bill name |</p>\n<p>| `default_amount` | DECIMAL(12,2) | Pre-fills the Due column |</p>\n<p>| `default_account_id` | INT | Default bank to debit |</p>\n<p>| `notes` | TEXT | Instructions / URLs |</p>\n<p>| `sort_order` | INT | Row order |</p>\n<p>| `is_deleted` | TINYINT | Soft delete |</p>\n<p><strong>`bills_entry`</strong></p>\n<p>Monthly bill payment rows.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| `bills_entry_id` | INT PK AUTO | |</p>\n<p>| `bills_item_id` | INT | FK to `bills_item` |</p>\n<p>| `year`, `month` | INT | Billing period |</p>\n<p>| `amount_due` | DECIMAL(12,2) | Amount billed |</p>\n<p>| `amount_paid` | DECIMAL(12,2) | Amount actually paid |</p>\n<p>| `account_id` | INT | Bank used to pay |</p>\n<p><strong>`bills_balance`</strong></p>\n<p>Opening bank balances per month.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| `bills_balance_id` | INT PK AUTO | |</p>\n<p>| `account_id` | INT | FK to `bills_account` |</p>\n<p>| `year`, `month` | INT | Period |</p>\n<p>| `opening_balance` | DECIMAL(14,2) | Balance at start of month |</p>\n<h3>Seed Data</h3>\n<p>On first load (empty table), the following are auto-seeded from the original Excel file:</p>\n<p><strong>Accounts:</strong> USAA, MIDFLORIDA, Centenial, CapitalOne</p>\n<p><strong>Bills (11 items):</strong> MidFlorida Mortgage, MidFlorida Credit Card, USAA Credit Card,</p>\n<p>Centenial Bank, Electricity, Waste Management, Comcast/Xfinity, Insurance, Water,</p>\n<p>CapitalOne #1, CapitalOne #2</p>\n<h3>Service Functions</h3>\n<p>```php</p>\n<p>app_install_bills_schema(mysqli $conn): void</p>\n<p>app_bills_seed_defaults(mysqli $conn): void</p>\n<p>app_bills_accounts(mysqli $conn): array</p>\n<p>app_bills_all_accounts(mysqli $conn): array</p>\n<p>app_bills_items(mysqli $conn): array</p>\n<p>app_bills_balances(mysqli $conn, int $year, int $month): array       // map: account_id → float</p>\n<p>app_bills_entries(mysqli $conn, int $year, int $month): array        // map: item_id → [due, paid, account_id]</p>\n<p>app_bills_active_months(mysqli $conn, int $year): array</p>\n<p>app_bills_save_balance(mysqli $conn, int $year, int $month, int $accountId, float $balance): void</p>\n<p>app_bills_save_entry(mysqli $conn, int $year, int $month, int $itemId, ?float $due, ?float $paid, ?int $accountId): void</p>\n<p>app_bills_save_account(mysqli $conn, array $data): int</p>\n<p>app_bills_delete_account(mysqli $conn, int $id): void</p>\n<p>app_bills_save_item(mysqli $conn, array $data): int</p>\n<p>app_bills_delete_item(mysqli $conn, int $id): void</p>\n<p>app_bills_reorder_item(mysqli $conn, int $id, string $dir): void</p>\n<p>app_bills_copy_month(mysqli $conn, int $fromYear, int $fromMonth, int $toYear, int $toMonth): int</p>\n<p>```</p>\n<h3>UI Features (`bills.php`)</h3>\n<ul>\n<li>Month/year navigation with ◀ / ▶ buttons and active-month pills</li>\n<li><strong>Bank Balances section</strong> — editable opening balance per account, inline Save button</li>\n<li><strong>Bills table</strong> — spreadsheet-style rows with:</li>\n<li>Amount Due (editable, pre-filled from default)</li>\n<li>Amount Paid (editable, AJAX auto-save after 600 ms debounce)</li>\n<li>Account selector (which bank pays this bill)</li>\n<li>Balance After column (computed client-side in real time)</li>\n<li>Up/Down sort buttons</li>\n<li>Edit and Delete per row</li>\n<li><strong>Sticky running totals sidebar</strong> — shows each bank&#039;s current balance as bills are entered</li>\n<li><strong>Copy from previous month</strong> — modal to copy all entries from a prior month to the current one</li>\n<li><strong>Add Bill / Edit Bill modals</strong></li>\n<li><strong>Add Account / Edit Account modals</strong></li>\n<li>All saves use POST/Redirect/GET; bill entry changes auto-save via `fetch()` AJAX</li>\n</ul>\n<h3>Running Total Calculation</h3>\n<p>JavaScript function `recalcTotals()` walks bills in DOM order, maintains a</p>\n<p>`bal[accountId]` map starting from opening balances, subtracts `amount_paid` from the</p>\n<p>selected account for each bill, and updates the &quot;Balance After&quot; column and sidebar panel</p>\n<p>in real time — matching the Excel spreadsheet formula logic.</p>\n<p>---</p>\n<h2>2. Next-Day Customer Email Job</h2>\n<h3>File</h3>\n<ul>\n<li>`backend/jobs/send_nextday_customer_emails.php` — 158 lines</li>\n</ul>\n<h3>Purpose</h3>\n<p>PHP CLI translation of the VBA macro `RunNextDayCustomerEmails()`.</p>\n<p>Queries `setmore_appointments` for appointments scheduled for tomorrow</p>\n<p>(status ≠ Cancelled) and sends a reminder email to each customer.</p>\n<h3>Usage</h3>\n<p>```bash</p>\n<h1>Normal run (sends real emails)</h1>\n<p>php backend/jobs/send_nextday_customer_emails.php</p>\n<h1>Dry run — prints what would be sent, no emails sent</h1>\n<p>php backend/jobs/send_nextday_customer_emails.php --dry-run</p>\n<h1>Override date (for testing a specific date)</h1>\n<p>php backend/jobs/send_nextday_customer_emails.php --date=2026-04-09</p>\n<p>```</p>\n<h3>Recommended Cron Schedule</h3>\n<p>```</p>\n<p>0 20 <em> </em> *  php /path/to/backend/jobs/send_nextday_customer_emails.php</p>\n<p>```</p>\n<p>Runs at 8:00 PM every evening, sends reminders for the following day&#039;s appointments.</p>\n<h3>Email Content</h3>\n<ul>\n<li>Subject: `Reminder: Your appointment at Ella&#039;s Alterations tomorrow`</li>\n<li>Body matches the original VBA email with full address, phone, 5-line award</li>\n</ul>\n<p>signature block, and a plain-text fallback</p>\n<ul>\n<li>Uses `app_send_mail()` / PHPMailer</li>\n</ul>\n<p>---</p>\n<h2>3. Cron Manager UI</h2>\n<h3>File</h3>\n<ul>\n<li>`backend/cron_manager.php` — 482 lines</li>\n</ul>\n<h3>Purpose</h3>\n<p>Web UI for managing scheduled background jobs. Stores job definitions in the database,</p>\n<p>allows toggling on/off, running immediately, editing schedules, and exporting to</p>\n<p>`/etc/cron.d/` format.</p>\n<h3>Database Table (auto-created)</h3>\n<p><strong>`cron_job`</strong></p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| `cron_job_id` | INT PK AUTO | |</p>\n<p>| `label` | VARCHAR(120) | Human name |</p>\n<p>| `description` | TEXT | What the job does |</p>\n<p>| `schedule` | VARCHAR(100) | Cron expression e.g. `0 20 <em> </em> *` |</p>\n<p>| `command` | VARCHAR(500) | Shell command to run |</p>\n<p>| `enabled` | TINYINT | 0 = disabled, 1 = enabled |</p>\n<p>| `last_run_at` | DATETIME | Updated on &quot;Run Now&quot; |</p>\n<p>| `last_output` | TEXT | Captured stdout/stderr |</p>\n<p>| `sort_order` | INT | Display order |</p>\n<h3>Seeded Jobs (on first install)</h3>\n<p>1. <strong>Next-Day Customer Emails</strong> — `0 20 <em> </em> *` — `php backend/jobs/send_nextday_customer_emails.php`</p>\n<p>2. <strong>Morning Jobs</strong> — `0 7 <em> </em> *` — `php backend/jobs/morning_jobs.php`</p>\n<p>3. <strong>Nightly Reports</strong> — `0 23 <em> </em> *` — `php backend/jobs/nightly_reports.php`</p>\n<p>4. <strong>DB Backup</strong> — `0 2 <em> </em> *` — `bash backend/bin/db_backup.sh`</p>\n<p>5. <strong>Daily Cleanup</strong> — `30 3 <em> </em> *` — `php backend/jobs/daily_cleanup.php`</p>\n<p>6. <strong>Add Name Records Auto Delete</strong> — `0 4 <em> </em> *` — `php backend/jobs/cleanup_name_records.php`</p>\n<p>New jobs are added idempotently (checked by label before inserting) so existing</p>\n<p>installations are not re-seeded.</p>\n<h3>UI Features</h3>\n<ul>\n<li>Table listing all jobs with schedule, enabled toggle, last run time</li>\n<li><strong>Toggle</strong> — flip enabled/disabled immediately (POST/redirect)</li>\n<li><strong>▶ Run Now</strong> — executes the command via `exec()`, captures output, stores to DB, shows in modal</li>\n<li><strong>Add / Edit</strong> — form with label, description, command, schedule, enabled flag</li>\n<li><strong>Schedule presets</strong> — quick-select buttons (hourly, daily at common times, weekly, monthly)</li>\n<li>`cron_describe(string $expr): string` — converts `0 20 <em> </em> *` → &quot;Daily at 20:00&quot;</li>\n<li><strong>Export Crontab</strong> — writes `/tmp/customerdb_crontab_export.txt` in `/etc/cron.d/` format</li>\n</ul>\n<p>---</p>\n<h2>4. Error Log UI</h2>\n<h3>File</h3>\n<ul>\n<li>`backend/error_log.php` — 262 lines</li>\n</ul>\n<h3>Purpose</h3>\n<p>Dedicated UI for browsing `backend_error_log` records with filtering, pagination,</p>\n<p>and per-entry management.</p>\n<h3>Features</h3>\n<ul>\n<li><strong>Stats bar</strong> — Total errors, Today&#039;s errors, Latest error timestamp</li>\n<li><strong>Filter bar</strong> — Search (message/context), Source dropdown, Severity dropdown</li>\n<li><strong>Pagination</strong> — 50 per page with smart ellipsis navigator</li>\n<li><strong>Per-row delete</strong> — removes individual log entries</li>\n<li><strong>Clear All button</strong> — truncates the entire log (with confirmation)</li>\n<li>JSON context blocks displayed in `&lt;details&gt;` collapsibles with dark monospace styling</li>\n<li>URL: `/backend/error_log.php`</li>\n</ul>\n<p>---</p>\n<h2>5. Change Log UI</h2>\n<h3>File</h3>\n<ul>\n<li>`backend/change_log.php` — 248 lines</li>\n</ul>\n<h3>Purpose</h3>\n<p>Dedicated UI for browsing `backend_change_log` records — audit trail of all</p>\n<p>data changes across the application.</p>\n<h3>Features</h3>\n<ul>\n<li><strong>Filter bar</strong> — Search, Area, Action type, Entity type dropdowns</li>\n<li><strong>Pagination</strong> — smart ellipsis navigator</li>\n<li><strong>Per-row detail panels:</strong></li>\n<li>Before / After / Context — collapsed JSON blocks</li>\n<li>Changed Data — open by default, shows the changed fields summary</li>\n<li>Action badges color-coded by type (create, update, delete)</li>\n<li>URL: `/backend/change_log.php`</li>\n</ul>\n<p>---</p>\n<h2>6. Stocks &amp; Crypto Module</h2>\n<h3>Files</h3>\n<ul>\n<li>`backend/stocks_crypto_service.php` — 269 lines, service layer</li>\n<li>`backend/stocks_crypto.php` — 667 lines, UI page</li>\n</ul>\n<h3>Purpose</h3>\n<p>Track a personal investment portfolio — individual stocks, ETFs, precious metals,</p>\n<p>and crypto. Supports live price fetching, manual daily price entry, monthly crypto</p>\n<p>buy tracking, and portfolio gain/loss analysis.</p>\n<h3>Database Tables (auto-created)</h3>\n<p><strong>`stocks_asset`</strong></p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| `stocks_asset_id` | INT PK AUTO | |</p>\n<p>| `ticker` | VARCHAR(20) | e.g. `AAPL`, `BTC`, `GLD` |</p>\n<p>| `name` | VARCHAR(120) | Display name |</p>\n<p>| `asset_type` | ENUM | `stock`, `etf`, `crypto`, `metal`, `other` |</p>\n<p>| `shares` | DECIMAL(18,8) | Quantity owned |</p>\n<p>| `cost_basis_total` | DECIMAL(14,6) | Total purchase cost |</p>\n<p>| `is_active` | TINYINT | Soft hide |</p>\n<p><strong>`stocks_price`</strong></p>\n<p>Daily price records.</p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| `stocks_price_id` | INT PK AUTO | |</p>\n<p>| `ticker` | VARCHAR(20) | |</p>\n<p>| `price_date` | DATE | |</p>\n<p>| `price` | DECIMAL(14,6) | |</p>\n<p>| `source` | VARCHAR(40) | `manual` or `yahoo` |</p>\n<p>Unique constraint on `(ticker, price_date)` — upserts with `ON DUPLICATE KEY UPDATE`.</p>\n<p><strong>`crypto_monthly_buy`</strong></p>\n<p>| Column | Type | Notes |</p>\n<p>|--------|------|-------|</p>\n<p>| `crypto_monthly_buy_id` | INT PK AUTO | |</p>\n<p>| `ticker` | VARCHAR(20) | |</p>\n<p>| `year`, `month` | INT | |</p>\n<p>| `quantity` | DECIMAL(18,8) | Crypto units purchased |</p>\n<p>| `amount_usd` | DECIMAL(14,2) | USD spent |</p>\n<p>| `notes` | VARCHAR(255) | |</p>\n<h3>Service Functions</h3>\n<p>```php</p>\n<p>app_install_stocks_schema(mysqli $conn): void</p>\n<p>app_stocks_assets(mysqli $conn, string $type = &#039;&#039;): array</p>\n<p>app_stocks_save_asset(mysqli $conn, array $data): int</p>\n<p>app_stocks_delete_asset(mysqli $conn, int $id): void</p>\n<p>app_stocks_save_price(mysqli $conn, string $ticker, string $date, float $price, string $source = &#039;manual&#039;): void</p>\n<p>app_stocks_save_prices_bulk(mysqli $conn, string $date, array $prices): int</p>\n<p>app_stocks_latest_prices(mysqli $conn): array                          // map: ticker → [price, date]</p>\n<p>app_stocks_price_history(mysqli $conn, string $ticker, int $limit = 90): array</p>\n<p>app_stocks_fetch_live_price(string $ticker): ?float                    // Yahoo Finance API, 8s timeout</p>\n<p>app_stocks_fetch_all_live(mysqli $conn): array                         // fetches all active tickers</p>\n<p>app_crypto_monthly_buys(mysqli $conn, int $year, int $month = 0): array</p>\n<p>app_crypto_save_monthly_buy(mysqli $conn, array $data): void</p>\n<p>app_crypto_delete_monthly_buy(mysqli $conn, int $id): void</p>\n<p>app_stocks_dashboard(mysqli $conn): array                              // cost_basis, current_value, gain_loss, gain_pct per asset</p>\n<p>app_stocks_stats(mysqli $conn): array                                  // total portfolio stats</p>\n<p>```</p>\n<h3>Live Price Source</h3>\n<p>Yahoo Finance unofficial API:</p>\n<p>```</p>\n<p>https://query1.finance.yahoo.com/v8/finance/chart/{TICKER}?interval=1d&amp;range=1d</p>\n<p>```</p>\n<p>8-second timeout, reads `.chart.result[0].meta.regularMarketPrice`.</p>\n<h3>UI Tabs (`stocks_crypto.php`)</h3>\n<p>1. <strong>Portfolio</strong> — dashboard table with ticker, shares, cost basis, current value,</p>\n<p>gain/loss, gain %, latest price date. Stats bar shows total value, total cost,</p>\n<p>total gain/loss. &quot;Fetch Live Prices&quot; button calls Yahoo Finance for all tickers.</p>\n<p>2. <strong>Enter Prices</strong> — manual daily price entry grid for all active assets,</p>\n<p>date picker (defaults to today), bulk save.</p>\n<p>3. <strong>Crypto Buys</strong> — monthly crypto purchase log. Month/year selector, table of</p>\n<p>ticker/quantity/USD/notes rows, add and delete per entry.</p>\n<p>4. <strong>Add Asset</strong> — form to add a new stock, ETF, crypto, metal, or other asset.</p>\n<h3>Auto-Refresh</h3>\n<p>A checkbox above the stats bar auto-refreshes the Portfolio tab every 10 seconds.</p>\n<p>State persists in `localStorage` key `sc_auto_refresh`. On reload, strips `?ok=`</p>\n<p>and `?warn=` query params to prevent the notice from repeating every 10 seconds.</p>\n<p>---</p>\n<h2>7. Backend Home — New Cards (`index.php`)</h2>\n<p>Six new cards added to the backend home dashboard:</p>\n<p>| Card | Link | Secondary Action |</p>\n<p>|------|------|-----------------|</p>\n<p>| Customer Totals | `/backend/customer_totals.php` | — |</p>\n<p>| Ambient Weather | `/backend/ambient_weather.php` | — |</p>\n<p>| Bills Manager | `/backend/bills.php` | — |</p>\n<p>| Stocks &amp; Crypto | `/backend/stocks_crypto.php` | — |</p>\n<p>| Cron Manager | `/backend/cron_manager.php` | — |</p>\n<p>| Error Log | `/backend/error_log.php` | Change Log |</p>\n<p>---</p>\n<h2>8. Documents Editor — Full Rewrite (`documents.php`)</h2>\n<h3>Problem</h3>\n<p>GitHub Copilot introduced several bugs into the previous version:</p>\n<ul>\n<li>`docLoad()` had mismatched closing braces, breaking the entire function</li>\n<li>The document library was constrained to ~40% page width inside a grid column</li>\n<li>The editor was a plain `&lt;textarea&gt;` with no formatting support</li>\n</ul>\n<h3>Solution</h3>\n<p>Complete rewrite of all HTML, CSS, and JavaScript. PHP POST handlers were kept</p>\n<p>identical — only the front-end was replaced.</p>\n<h3>Editor: EasyMDE</h3>\n<p>Replaced the plain textarea with <strong>EasyMDE</strong> (Easy Markdown Editor) via CDN:</p>\n<p>```html</p>\n<p>&lt;link rel=&quot;stylesheet&quot; href=&quot;https://unpkg.com/easymde/dist/easymde.min.css&quot;&gt;</p>\n<p>&lt;script src=&quot;https://unpkg.com/easymde/dist/easymde.min.js&quot;&gt;&lt;/script&gt;</p>\n<p>```</p>\n<p>EasyMDE wraps the `&lt;textarea id=&quot;content_markdown&quot;&gt;` and syncs content on form submit.</p>\n<p>`ta.value = easyMDE.value()` is called explicitly in `submitDoc()` before `form.submit()`.</p>\n<h3>Toolbar Buttons</h3>\n<p>Save (custom gradient btn) | Bold · Italic · Strikethrough | H1 · H2 · H3 |</p>\n<p>Unordered List · Ordered List · Checklist (custom) | Quote · Code · Table |</p>\n<p>HR · Link · Image URL (custom) | Undo · Redo | Fullscreen | Guide</p>\n<ul>\n<li><strong>Save</strong> button in toolbar calls `submitDoc()`, same as the Save Document button below</li>\n<li><strong>Ctrl+S / Cmd+S</strong> keyboard shortcut via CodeMirror `extraKeys`</li>\n<li><strong>Checklist</strong> inserts `- [ ] ` prefix on selected text</li>\n<li><strong>Image URL</strong> prompts for URL and alt text, inserts `![alt](url)` syntax</li>\n</ul>\n<h3>Preview Toggle</h3>\n<p>EasyMDE&#039;s built-in `preview` and `side-by-side` buttons were <strong>removed</strong> to prevent</p>\n<p>both raw markdown and rendered HTML showing simultaneously.</p>\n<p>A custom <strong>Preview</strong> button in the panel header replaces them:</p>\n<ul>\n<li>Uses `marked.js` (CDN) to render the markdown client-side</li>\n<li><strong>Preview on</strong>: hides `EasyMDEContainer` and highlight strip; shows `#doc-preview-pane`</li>\n<li><strong>Edit on</strong>: hides preview pane; shows EasyMDE and highlight strip; calls `codemirror.refresh()`</li>\n<li>Loading a document via `docLoad()` automatically returns to edit mode</li>\n<li>Button state: pill shape, switches between &quot;👁 Preview&quot; and &quot;✏ Edit&quot; labels</li>\n</ul>\n<p>```html</p>\n<p>&lt;script src=&quot;https://cdn.jsdelivr.net/npm/marked/marked.min.js&quot;&gt;&lt;/script&gt;</p>\n<p>```</p>\n<h3>`docLoad()` — Clean Rewrite</h3>\n<p>Old function had mismatched braces and redundant `editor.value` assignments.</p>\n<p>New function:</p>\n<p>1. Returns to edit mode if preview is on</p>\n<p>2. Sets heading to &quot;Loading…&quot;</p>\n<p>3. Highlights active `&lt;tr&gt;` and `&lt;a&gt;` in library immediately</p>\n<p>4. `fetch(&#039;/backend/api/documents.php?backend_document_id=&#039; + id)`</p>\n<p>5. Populates all meta fields (type, title, slug, summary)</p>\n<p>6. Sets `easyMDE.value(content)` from `editor_content` or `content_markdown`</p>\n<p>7. Shows/hides file notice</p>\n<p>8. Calls `renderVersionList(data.versions)`</p>\n<p>9. Updates URL via `history.replaceState()`</p>\n<p>10. Flashes panel border with accent color for 800 ms</p>\n<h3>Library Panel — Full Width</h3>\n<p>Old layout: library was inside a 2-column grid alongside the editor.</p>\n<p>New layout:</p>\n<p>```</p>\n<p>[Editor Panel          — full width]</p>\n<p>[Library Panel         — full width, max-height: 460px scrollable]</p>\n<p>[Upload | Versions     — 2-column row]</p>\n<p>```</p>\n<p>Live client-side search filters table rows by `textContent` without a page reload.</p>\n<h3>Word Count &amp; Highlights</h3>\n<ul>\n<li>Word count and char count update on every keystroke via `codemirror.on(&#039;change&#039;, ...)`</li>\n<li>6 highlight color swatches + a clear option wrap selected text in</li>\n</ul>\n<p>`&lt;span class=&quot;hl&quot; style=&quot;background:COLOR&quot;&gt;...&lt;/span&gt;`</p>\n<ul>\n<li>Clear highlight strips existing `&lt;span class=&quot;hl&quot;&gt;` wrappers from selected text</li>\n</ul>\n<h3>CSS Theme Conformity (visit.html standard)</h3>\n<p>All custom CSS was updated to match the application theme:</p>\n<p>| Property | Before | After |</p>\n<p>|----------|--------|-------|</p>\n<p>| Form input border-radius | `10px` | `12px` (matches `--radius-sm`) |</p>\n<p>| Form input padding | `8px 10px` | `11px 14px` |</p>\n<p>| Field label font-size | `0.73rem` + uppercase | `0.82rem`, no forced uppercase |</p>\n<p>| Field label letter-spacing | `0.07em` | `0.04em` |</p>\n<p>| Focus ring | `outline: 2px solid var(--accent)` | `outline: 2px solid rgba(175,77,49,0.3)` |</p>\n<p>| Panel header background | `rgba(244,239,231,0.6)` hardcoded | `var(--panel)` |</p>\n<p>| Toolbar background | `rgba(244,239,231,0.7)` hardcoded | `rgba(255,255,255,0.55)` |</p>\n<p>| Action bar background | `rgba(244,239,231,0.4)` hardcoded | `rgba(255,255,255,0.25)` |</p>\n<p>| Save button | `background: var(--accent)` | `linear-gradient(135deg, var(--accent), var(--accent-deep))` |</p>\n<p>| Action buttons | `border-radius: 7px` | `border-radius: 999px` pill shape |</p>\n<p>| Active library row tint | `rgba(26,122,154,0.06)` teal | `rgba(175,77,49,0.07)` accent |</p>\n<p>| Type badge (markdown) | `rgba(26,122,154,0.1)` teal | `rgba(175,77,49,0.1)` accent |</p>\n<p>| File notice tint | `rgba(26,122,154,0.06)` teal | `rgba(175,77,49,0.05)` accent |</p>\n<p>---</p>\n<h2>9. `document_service.php` — Parse Error Fix</h2>\n<h3>Problem</h3>\n<p>The function `app_backend_documents_dir()` had its closing `return $path; }` accidentally</p>\n<p>displaced to after `app_document_can_edit_inline()` (lines 147–148), with the rest of the</p>\n<p>file&#039;s functions (`app_libreoffice_convert_to_html`, etc.) nested inside the unclosed</p>\n<p>function body. This caused a PHP parse error on every request to any page that</p>\n<p>`require_once`&#039;s `document_service.php`, making `app_document_can_edit_inline()`</p>\n<p>appear undefined.</p>\n<h3>Fix</h3>\n<p>Two edits to `document_service.php`:</p>\n<p>1. Closed `app_backend_documents_dir()` properly after the `mkdir` block:</p>\n<p>```php</p>\n<p>function app_backend_documents_dir(): string</p>\n<p>{</p>\n<p>$path = __DIR__ . &#039;/documents_storage&#039;;</p>\n<p>if (!is_dir($path)) {</p>\n<p>mkdir($path, 0775, true);</p>\n<p>}</p>\n<p>return $path;   // ← added</p>\n<p>}                   // ← added</p>\n<p>```</p>\n<p>2. Removed the orphaned `return $path; }` that had been displaced to after</p>\n<p>`app_document_can_edit_inline()` at lines 147–148.</p>\n<p>---</p>\n<h2>Access URLs</h2>\n<p>| Module | URL |</p>\n<p>|--------|-----|</p>\n<p>| Backend Home | `/backend/` |</p>\n<p>| Bills Manager | `/backend/bills.php` |</p>\n<p>| Stocks &amp; Crypto | `/backend/stocks_crypto.php` |</p>\n<p>| Cron Manager | `/backend/cron_manager.php` |</p>\n<p>| Error Log | `/backend/error_log.php` |</p>\n<p>| Change Log | `/backend/change_log.php` |</p>\n<p>| Documents | `/backend/documents.php` |</p>\n<p>| Documents API | `/backend/api/documents.php` |</p>\n<p>---</p>\n<h2>Technology Used</h2>\n<p>| Library | Version | Purpose |</p>\n<p>|---------|---------|---------|</p>\n<p>| EasyMDE | latest (unpkg CDN) | Rich markdown editor |</p>\n<p>| marked.js | latest (jsdelivr CDN) | Client-side markdown → HTML rendering |</p>\n<p>| Yahoo Finance API | v8 (unofficial) | Live stock/ETF price fetching |</p>\n<p>| PHPMailer | (existing) | Email sending via `app_send_mail()` |</p>\n<p>---</p>\n<h2>Coding Conventions (consistent with existing codebase)</h2>\n<ul>\n<li>`declare(strict_types=1)` in all PHP files</li>\n<li>`app_db()` for database connections, `mysqli` throughout</li>\n<li>`app_query_all()`, `app_query_one()`, `app_h()`, `app_send_json()` helpers</li>\n<li>`app_log_backend_exception()` for error logging</li>\n<li>POST/Redirect/GET for all form submissions</li>\n<li>`ON DUPLICATE KEY UPDATE` for safe upserts</li>\n<li>`app_backend_render_header()` / `app_backend_render_footer()` for page chrome</li>\n<li>CSS custom properties: `--accent`, `--panel`, `--line`, `--text`, `--muted`, `--shadow`</li>\n<li>All new tables use `CREATE TABLE IF NOT EXISTS` (idempotent, no separate migration needed)</li>\n</ul>","file_name":"SESSION_LOG_2026-04-07.md","stored_name":"20260407-190624-56f0e818.md","mime_type":"application/octet-stream","file_size_bytes":"21112","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260407-190624-56f0e818.md","is_deleted":"0","created_at":"2026-04-07 15:06:24","updated_at":"2026-04-07 15:08:09","editor_content":"# Session Log — 2026-04-07\r\n\r\nAll work completed in this session on the CustomerDB backend application.\r\n\r\n---\r\n\r\n## Summary of New Modules and Changes\r\n\r\n| Area | File(s) | Status |\r\n|------|---------|--------|\r\n| Bills Manager | `backend/bills_service.php`, `backend/bills.php` | New |\r\n| Next-Day Email Job | `backend/jobs/send_nextday_customer_emails.php` | New |\r\n| Cron Manager UI | `backend/cron_manager.php` | New |\r\n| Error Log UI | `backend/error_log.php` | New |\r\n| Change Log UI | `backend/change_log.php` | New |\r\n| Stocks & Crypto | `backend/stocks_crypto_service.php`, `backend/stocks_crypto.php` | New |\r\n| Backend Home | `backend/index.php` | Modified |\r\n| Documents Editor | `backend/documents.php` | Full rewrite |\r\n| Documents Service | `backend/document_service.php` | Bug fix |\r\n\r\n---\r\n\r\n## 1. Bills Manager\r\n\r\n### Files\r\n- `backend/bills_service.php` — 356 lines, service layer\r\n- `backend/bills.php` — 972 lines, UI page\r\n\r\n### Purpose\r\nReplaces a spreadsheet (`newbills2026.xlsx`) with a web-based bill payment tracker.\r\nTracks bank account opening balances, monthly bill payments, and computes running bank\r\nbalances in the same layout as the Excel spreadsheet.\r\n\r\n### Database Tables (auto-created on first load)\r\n\r\n**`bills_account`**\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `bills_account_id` | INT PK AUTO | |\r\n| `name` | VARCHAR(120) | Bank name |\r\n| `sort_order` | INT | Display order |\r\n\r\n**`bills_item`**\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `bills_item_id` | INT PK AUTO | |\r\n| `label` | VARCHAR(200) | Bill name |\r\n| `default_amount` | DECIMAL(12,2) | Pre-fills the Due column |\r\n| `default_account_id` | INT | Default bank to debit |\r\n| `notes` | TEXT | Instructions / URLs |\r\n| `sort_order` | INT | Row order |\r\n| `is_deleted` | TINYINT | Soft delete |\r\n\r\n**`bills_entry`**\r\nMonthly bill payment rows.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `bills_entry_id` | INT PK AUTO | |\r\n| `bills_item_id` | INT | FK to `bills_item` |\r\n| `year`, `month` | INT | Billing period |\r\n| `amount_due` | DECIMAL(12,2) | Amount billed |\r\n| `amount_paid` | DECIMAL(12,2) | Amount actually paid |\r\n| `account_id` | INT | Bank used to pay |\r\n\r\n**`bills_balance`**\r\nOpening bank balances per month.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `bills_balance_id` | INT PK AUTO | |\r\n| `account_id` | INT | FK to `bills_account` |\r\n| `year`, `month` | INT | Period |\r\n| `opening_balance` | DECIMAL(14,2) | Balance at start of month |\r\n\r\n### Seed Data\r\nOn first load (empty table), the following are auto-seeded from the original Excel file:\r\n\r\n**Accounts:** USAA, MIDFLORIDA, Centenial, CapitalOne\r\n\r\n**Bills (11 items):** MidFlorida Mortgage, MidFlorida Credit Card, USAA Credit Card,\r\nCentenial Bank, Electricity, Waste Management, Comcast/Xfinity, Insurance, Water,\r\nCapitalOne #1, CapitalOne #2\r\n\r\n### Service Functions\r\n\r\n```php\r\napp_install_bills_schema(mysqli $conn): void\r\napp_bills_seed_defaults(mysqli $conn): void\r\napp_bills_accounts(mysqli $conn): array\r\napp_bills_all_accounts(mysqli $conn): array\r\napp_bills_items(mysqli $conn): array\r\napp_bills_balances(mysqli $conn, int $year, int $month): array       // map: account_id → float\r\napp_bills_entries(mysqli $conn, int $year, int $month): array        // map: item_id → [due, paid, account_id]\r\napp_bills_active_months(mysqli $conn, int $year): array\r\napp_bills_save_balance(mysqli $conn, int $year, int $month, int $accountId, float $balance): void\r\napp_bills_save_entry(mysqli $conn, int $year, int $month, int $itemId, ?float $due, ?float $paid, ?int $accountId): void\r\napp_bills_save_account(mysqli $conn, array $data): int\r\napp_bills_delete_account(mysqli $conn, int $id): void\r\napp_bills_save_item(mysqli $conn, array $data): int\r\napp_bills_delete_item(mysqli $conn, int $id): void\r\napp_bills_reorder_item(mysqli $conn, int $id, string $dir): void\r\napp_bills_copy_month(mysqli $conn, int $fromYear, int $fromMonth, int $toYear, int $toMonth): int\r\n```\r\n\r\n### UI Features (`bills.php`)\r\n- Month/year navigation with ◀ / ▶ buttons and active-month pills\r\n- **Bank Balances section** — editable opening balance per account, inline Save button\r\n- **Bills table** — spreadsheet-style rows with:\r\n  - Amount Due (editable, pre-filled from default)\r\n  - Amount Paid (editable, AJAX auto-save after 600 ms debounce)\r\n  - Account selector (which bank pays this bill)\r\n  - Balance After column (computed client-side in real time)\r\n  - Up/Down sort buttons\r\n  - Edit and Delete per row\r\n- **Sticky running totals sidebar** — shows each bank's current balance as bills are entered\r\n- **Copy from previous month** — modal to copy all entries from a prior month to the current one\r\n- **Add Bill / Edit Bill modals**\r\n- **Add Account / Edit Account modals**\r\n- All saves use POST/Redirect/GET; bill entry changes auto-save via `fetch()` AJAX\r\n\r\n### Running Total Calculation\r\nJavaScript function `recalcTotals()` walks bills in DOM order, maintains a\r\n`bal[accountId]` map starting from opening balances, subtracts `amount_paid` from the\r\nselected account for each bill, and updates the \"Balance After\" column and sidebar panel\r\nin real time — matching the Excel spreadsheet formula logic.\r\n\r\n---\r\n\r\n## 2. Next-Day Customer Email Job\r\n\r\n### File\r\n- `backend/jobs/send_nextday_customer_emails.php` — 158 lines\r\n\r\n### Purpose\r\nPHP CLI translation of the VBA macro `RunNextDayCustomerEmails()`.\r\nQueries `setmore_appointments` for appointments scheduled for tomorrow\r\n(status ≠ Cancelled) and sends a reminder email to each customer.\r\n\r\n### Usage\r\n```bash\r\n# Normal run (sends real emails)\r\nphp backend/jobs/send_nextday_customer_emails.php\r\n\r\n# Dry run — prints what would be sent, no emails sent\r\nphp backend/jobs/send_nextday_customer_emails.php --dry-run\r\n\r\n# Override date (for testing a specific date)\r\nphp backend/jobs/send_nextday_customer_emails.php --date=2026-04-09\r\n```\r\n\r\n### Recommended Cron Schedule\r\n```\r\n0 20 * * *  php /path/to/backend/jobs/send_nextday_customer_emails.php\r\n```\r\nRuns at 8:00 PM every evening, sends reminders for the following day's appointments.\r\n\r\n### Email Content\r\n- Subject: `Reminder: Your appointment at Ella's Alterations tomorrow`\r\n- Body matches the original VBA email with full address, phone, 5-line award\r\n  signature block, and a plain-text fallback\r\n- Uses `app_send_mail()` / PHPMailer\r\n\r\n---\r\n\r\n## 3. Cron Manager UI\r\n\r\n### File\r\n- `backend/cron_manager.php` — 482 lines\r\n\r\n### Purpose\r\nWeb UI for managing scheduled background jobs. Stores job definitions in the database,\r\nallows toggling on/off, running immediately, editing schedules, and exporting to\r\n`/etc/cron.d/` format.\r\n\r\n### Database Table (auto-created)\r\n\r\n**`cron_job`**\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `cron_job_id` | INT PK AUTO | |\r\n| `label` | VARCHAR(120) | Human name |\r\n| `description` | TEXT | What the job does |\r\n| `schedule` | VARCHAR(100) | Cron expression e.g. `0 20 * * *` |\r\n| `command` | VARCHAR(500) | Shell command to run |\r\n| `enabled` | TINYINT | 0 = disabled, 1 = enabled |\r\n| `last_run_at` | DATETIME | Updated on \"Run Now\" |\r\n| `last_output` | TEXT | Captured stdout/stderr |\r\n| `sort_order` | INT | Display order |\r\n\r\n### Seeded Jobs (on first install)\r\n1. **Next-Day Customer Emails** — `0 20 * * *` — `php backend/jobs/send_nextday_customer_emails.php`\r\n2. **Morning Jobs** — `0 7 * * *` — `php backend/jobs/morning_jobs.php`\r\n3. **Nightly Reports** — `0 23 * * *` — `php backend/jobs/nightly_reports.php`\r\n4. **DB Backup** — `0 2 * * *` — `bash backend/bin/db_backup.sh`\r\n5. **Daily Cleanup** — `30 3 * * *` — `php backend/jobs/daily_cleanup.php`\r\n6. **Add Name Records Auto Delete** — `0 4 * * *` — `php backend/jobs/cleanup_name_records.php`\r\n\r\nNew jobs are added idempotently (checked by label before inserting) so existing\r\ninstallations are not re-seeded.\r\n\r\n### UI Features\r\n- Table listing all jobs with schedule, enabled toggle, last run time\r\n- **Toggle** — flip enabled/disabled immediately (POST/redirect)\r\n- **▶ Run Now** — executes the command via `exec()`, captures output, stores to DB, shows in modal\r\n- **Add / Edit** — form with label, description, command, schedule, enabled flag\r\n- **Schedule presets** — quick-select buttons (hourly, daily at common times, weekly, monthly)\r\n- `cron_describe(string $expr): string` — converts `0 20 * * *` → \"Daily at 20:00\"\r\n- **Export Crontab** — writes `/tmp/customerdb_crontab_export.txt` in `/etc/cron.d/` format\r\n\r\n---\r\n\r\n## 4. Error Log UI\r\n\r\n### File\r\n- `backend/error_log.php` — 262 lines\r\n\r\n### Purpose\r\nDedicated UI for browsing `backend_error_log` records with filtering, pagination,\r\nand per-entry management.\r\n\r\n### Features\r\n- **Stats bar** — Total errors, Today's errors, Latest error timestamp\r\n- **Filter bar** — Search (message/context), Source dropdown, Severity dropdown\r\n- **Pagination** — 50 per page with smart ellipsis navigator\r\n- **Per-row delete** — removes individual log entries\r\n- **Clear All button** — truncates the entire log (with confirmation)\r\n- JSON context blocks displayed in `<details>` collapsibles with dark monospace styling\r\n- URL: `/backend/error_log.php`\r\n\r\n---\r\n\r\n## 5. Change Log UI\r\n\r\n### File\r\n- `backend/change_log.php` — 248 lines\r\n\r\n### Purpose\r\nDedicated UI for browsing `backend_change_log` records — audit trail of all\r\ndata changes across the application.\r\n\r\n### Features\r\n- **Filter bar** — Search, Area, Action type, Entity type dropdowns\r\n- **Pagination** — smart ellipsis navigator\r\n- **Per-row detail panels:**\r\n  - Before / After / Context — collapsed JSON blocks\r\n  - Changed Data — open by default, shows the changed fields summary\r\n- Action badges color-coded by type (create, update, delete)\r\n- URL: `/backend/change_log.php`\r\n\r\n---\r\n\r\n## 6. Stocks & Crypto Module\r\n\r\n### Files\r\n- `backend/stocks_crypto_service.php` — 269 lines, service layer\r\n- `backend/stocks_crypto.php` — 667 lines, UI page\r\n\r\n### Purpose\r\nTrack a personal investment portfolio — individual stocks, ETFs, precious metals,\r\nand crypto. Supports live price fetching, manual daily price entry, monthly crypto\r\nbuy tracking, and portfolio gain/loss analysis.\r\n\r\n### Database Tables (auto-created)\r\n\r\n**`stocks_asset`**\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `stocks_asset_id` | INT PK AUTO | |\r\n| `ticker` | VARCHAR(20) | e.g. `AAPL`, `BTC`, `GLD` |\r\n| `name` | VARCHAR(120) | Display name |\r\n| `asset_type` | ENUM | `stock`, `etf`, `crypto`, `metal`, `other` |\r\n| `shares` | DECIMAL(18,8) | Quantity owned |\r\n| `cost_basis_total` | DECIMAL(14,6) | Total purchase cost |\r\n| `is_active` | TINYINT | Soft hide |\r\n\r\n**`stocks_price`**\r\nDaily price records.\r\n\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `stocks_price_id` | INT PK AUTO | |\r\n| `ticker` | VARCHAR(20) | |\r\n| `price_date` | DATE | |\r\n| `price` | DECIMAL(14,6) | |\r\n| `source` | VARCHAR(40) | `manual` or `yahoo` |\r\n\r\nUnique constraint on `(ticker, price_date)` — upserts with `ON DUPLICATE KEY UPDATE`.\r\n\r\n**`crypto_monthly_buy`**\r\n| Column | Type | Notes |\r\n|--------|------|-------|\r\n| `crypto_monthly_buy_id` | INT PK AUTO | |\r\n| `ticker` | VARCHAR(20) | |\r\n| `year`, `month` | INT | |\r\n| `quantity` | DECIMAL(18,8) | Crypto units purchased |\r\n| `amount_usd` | DECIMAL(14,2) | USD spent |\r\n| `notes` | VARCHAR(255) | |\r\n\r\n### Service Functions\r\n\r\n```php\r\napp_install_stocks_schema(mysqli $conn): void\r\napp_stocks_assets(mysqli $conn, string $type = ''): array\r\napp_stocks_save_asset(mysqli $conn, array $data): int\r\napp_stocks_delete_asset(mysqli $conn, int $id): void\r\napp_stocks_save_price(mysqli $conn, string $ticker, string $date, float $price, string $source = 'manual'): void\r\napp_stocks_save_prices_bulk(mysqli $conn, string $date, array $prices): int\r\napp_stocks_latest_prices(mysqli $conn): array                          // map: ticker → [price, date]\r\napp_stocks_price_history(mysqli $conn, string $ticker, int $limit = 90): array\r\napp_stocks_fetch_live_price(string $ticker): ?float                    // Yahoo Finance API, 8s timeout\r\napp_stocks_fetch_all_live(mysqli $conn): array                         // fetches all active tickers\r\napp_crypto_monthly_buys(mysqli $conn, int $year, int $month = 0): array\r\napp_crypto_save_monthly_buy(mysqli $conn, array $data): void\r\napp_crypto_delete_monthly_buy(mysqli $conn, int $id): void\r\napp_stocks_dashboard(mysqli $conn): array                              // cost_basis, current_value, gain_loss, gain_pct per asset\r\napp_stocks_stats(mysqli $conn): array                                  // total portfolio stats\r\n```\r\n\r\n### Live Price Source\r\nYahoo Finance unofficial API:\r\n```\r\nhttps://query1.finance.yahoo.com/v8/finance/chart/{TICKER}?interval=1d&range=1d\r\n```\r\n8-second timeout, reads `.chart.result[0].meta.regularMarketPrice`.\r\n\r\n### UI Tabs (`stocks_crypto.php`)\r\n\r\n1. **Portfolio** — dashboard table with ticker, shares, cost basis, current value,\r\n   gain/loss, gain %, latest price date. Stats bar shows total value, total cost,\r\n   total gain/loss. \"Fetch Live Prices\" button calls Yahoo Finance for all tickers.\r\n\r\n2. **Enter Prices** — manual daily price entry grid for all active assets,\r\n   date picker (defaults to today), bulk save.\r\n\r\n3. **Crypto Buys** — monthly crypto purchase log. Month/year selector, table of\r\n   ticker/quantity/USD/notes rows, add and delete per entry.\r\n\r\n4. **Add Asset** — form to add a new stock, ETF, crypto, metal, or other asset.\r\n\r\n### Auto-Refresh\r\nA checkbox above the stats bar auto-refreshes the Portfolio tab every 10 seconds.\r\nState persists in `localStorage` key `sc_auto_refresh`. On reload, strips `?ok=`\r\nand `?warn=` query params to prevent the notice from repeating every 10 seconds.\r\n\r\n---\r\n\r\n## 7. Backend Home — New Cards (`index.php`)\r\n\r\nSix new cards added to the backend home dashboard:\r\n\r\n| Card | Link | Secondary Action |\r\n|------|------|-----------------|\r\n| Customer Totals | `/backend/customer_totals.php` | — |\r\n| Ambient Weather | `/backend/ambient_weather.php` | — |\r\n| Bills Manager | `/backend/bills.php` | — |\r\n| Stocks & Crypto | `/backend/stocks_crypto.php` | — |\r\n| Cron Manager | `/backend/cron_manager.php` | — |\r\n| Error Log | `/backend/error_log.php` | Change Log |\r\n\r\n---\r\n\r\n## 8. Documents Editor — Full Rewrite (`documents.php`)\r\n\r\n### Problem\r\nGitHub Copilot introduced several bugs into the previous version:\r\n- `docLoad()` had mismatched closing braces, breaking the entire function\r\n- The document library was constrained to ~40% page width inside a grid column\r\n- The editor was a plain `<textarea>` with no formatting support\r\n\r\n### Solution\r\nComplete rewrite of all HTML, CSS, and JavaScript. PHP POST handlers were kept\r\nidentical — only the front-end was replaced.\r\n\r\n### Editor: EasyMDE\r\nReplaced the plain textarea with **EasyMDE** (Easy Markdown Editor) via CDN:\r\n```html\r\n<link rel=\"stylesheet\" href=\"https://unpkg.com/easymde/dist/easymde.min.css\">\r\n<script src=\"https://unpkg.com/easymde/dist/easymde.min.js\"></script>\r\n```\r\n\r\nEasyMDE wraps the `<textarea id=\"content_markdown\">` and syncs content on form submit.\r\n`ta.value = easyMDE.value()` is called explicitly in `submitDoc()` before `form.submit()`.\r\n\r\n### Toolbar Buttons\r\nSave (custom gradient btn) | Bold · Italic · Strikethrough | H1 · H2 · H3 |\r\nUnordered List · Ordered List · Checklist (custom) | Quote · Code · Table |\r\nHR · Link · Image URL (custom) | Undo · Redo | Fullscreen | Guide\r\n\r\n- **Save** button in toolbar calls `submitDoc()`, same as the Save Document button below\r\n- **Ctrl+S / Cmd+S** keyboard shortcut via CodeMirror `extraKeys`\r\n- **Checklist** inserts `- [ ] ` prefix on selected text\r\n- **Image URL** prompts for URL and alt text, inserts `![alt](url)` syntax\r\n\r\n### Preview Toggle\r\nEasyMDE's built-in `preview` and `side-by-side` buttons were **removed** to prevent\r\nboth raw markdown and rendered HTML showing simultaneously.\r\n\r\nA custom **Preview** button in the panel header replaces them:\r\n- Uses `marked.js` (CDN) to render the markdown client-side\r\n- **Preview on**: hides `EasyMDEContainer` and highlight strip; shows `#doc-preview-pane`\r\n- **Edit on**: hides preview pane; shows EasyMDE and highlight strip; calls `codemirror.refresh()`\r\n- Loading a document via `docLoad()` automatically returns to edit mode\r\n- Button state: pill shape, switches between \"👁 Preview\" and \"✏ Edit\" labels\r\n\r\n```html\r\n<script src=\"https://cdn.jsdelivr.net/npm/marked/marked.min.js\"></script>\r\n```\r\n\r\n### `docLoad()` — Clean Rewrite\r\nOld function had mismatched braces and redundant `editor.value` assignments.\r\nNew function:\r\n1. Returns to edit mode if preview is on\r\n2. Sets heading to \"Loading…\"\r\n3. Highlights active `<tr>` and `<a>` in library immediately\r\n4. `fetch('/backend/api/documents.php?backend_document_id=' + id)`\r\n5. Populates all meta fields (type, title, slug, summary)\r\n6. Sets `easyMDE.value(content)` from `editor_content` or `content_markdown`\r\n7. Shows/hides file notice\r\n8. Calls `renderVersionList(data.versions)`\r\n9. Updates URL via `history.replaceState()`\r\n10. Flashes panel border with accent color for 800 ms\r\n\r\n### Library Panel — Full Width\r\nOld layout: library was inside a 2-column grid alongside the editor.\r\nNew layout:\r\n```\r\n[Editor Panel          — full width]\r\n[Library Panel         — full width, max-height: 460px scrollable]\r\n[Upload | Versions     — 2-column row]\r\n```\r\n\r\nLive client-side search filters table rows by `textContent` without a page reload.\r\n\r\n### Word Count & Highlights\r\n- Word count and char count update on every keystroke via `codemirror.on('change', ...)`\r\n- 6 highlight color swatches + a clear option wrap selected text in\r\n  `<span class=\"hl\" style=\"background:COLOR\">...</span>`\r\n- Clear highlight strips existing `<span class=\"hl\">` wrappers from selected text\r\n\r\n### CSS Theme Conformity (visit.html standard)\r\nAll custom CSS was updated to match the application theme:\r\n\r\n| Property | Before | After |\r\n|----------|--------|-------|\r\n| Form input border-radius | `10px` | `12px` (matches `--radius-sm`) |\r\n| Form input padding | `8px 10px` | `11px 14px` |\r\n| Field label font-size | `0.73rem` + uppercase | `0.82rem`, no forced uppercase |\r\n| Field label letter-spacing | `0.07em` | `0.04em` |\r\n| Focus ring | `outline: 2px solid var(--accent)` | `outline: 2px solid rgba(175,77,49,0.3)` |\r\n| Panel header background | `rgba(244,239,231,0.6)` hardcoded | `var(--panel)` |\r\n| Toolbar background | `rgba(244,239,231,0.7)` hardcoded | `rgba(255,255,255,0.55)` |\r\n| Action bar background | `rgba(244,239,231,0.4)` hardcoded | `rgba(255,255,255,0.25)` |\r\n| Save button | `background: var(--accent)` | `linear-gradient(135deg, var(--accent), var(--accent-deep))` |\r\n| Action buttons | `border-radius: 7px` | `border-radius: 999px` pill shape |\r\n| Active library row tint | `rgba(26,122,154,0.06)` teal | `rgba(175,77,49,0.07)` accent |\r\n| Type badge (markdown) | `rgba(26,122,154,0.1)` teal | `rgba(175,77,49,0.1)` accent |\r\n| File notice tint | `rgba(26,122,154,0.06)` teal | `rgba(175,77,49,0.05)` accent |\r\n\r\n---\r\n\r\n## 9. `document_service.php` — Parse Error Fix\r\n\r\n### Problem\r\nThe function `app_backend_documents_dir()` had its closing `return $path; }` accidentally\r\ndisplaced to after `app_document_can_edit_inline()` (lines 147–148), with the rest of the\r\nfile's functions (`app_libreoffice_convert_to_html`, etc.) nested inside the unclosed\r\nfunction body. This caused a PHP parse error on every request to any page that\r\n`require_once`'s `document_service.php`, making `app_document_can_edit_inline()`\r\nappear undefined.\r\n\r\n### Fix\r\nTwo edits to `document_service.php`:\r\n\r\n1. Closed `app_backend_documents_dir()` properly after the `mkdir` block:\r\n```php\r\nfunction app_backend_documents_dir(): string\r\n{\r\n    $path = __DIR__ . '/documents_storage';\r\n    if (!is_dir($path)) {\r\n        mkdir($path, 0775, true);\r\n    }\r\n    return $path;   // ← added\r\n}                   // ← added\r\n```\r\n\r\n2. Removed the orphaned `return $path; }` that had been displaced to after\r\n`app_document_can_edit_inline()` at lines 147–148.\r\n\r\n---\r\n\r\n## Access URLs\r\n\r\n| Module | URL |\r\n|--------|-----|\r\n| Backend Home | `/backend/` |\r\n| Bills Manager | `/backend/bills.php` |\r\n| Stocks & Crypto | `/backend/stocks_crypto.php` |\r\n| Cron Manager | `/backend/cron_manager.php` |\r\n| Error Log | `/backend/error_log.php` |\r\n| Change Log | `/backend/change_log.php` |\r\n| Documents | `/backend/documents.php` |\r\n| Documents API | `/backend/api/documents.php` |\r\n\r\n---\r\n\r\n## Technology Used\r\n\r\n| Library | Version | Purpose |\r\n|---------|---------|---------|\r\n| EasyMDE | latest (unpkg CDN) | Rich markdown editor |\r\n| marked.js | latest (jsdelivr CDN) | Client-side markdown → HTML rendering |\r\n| Yahoo Finance API | v8 (unofficial) | Live stock/ETF price fetching |\r\n| PHPMailer | (existing) | Email sending via `app_send_mail()` |\r\n\r\n---\r\n\r\n## Coding Conventions (consistent with existing codebase)\r\n\r\n- `declare(strict_types=1)` in all PHP files\r\n- `app_db()` for database connections, `mysqli` throughout\r\n- `app_query_all()`, `app_query_one()`, `app_h()`, `app_send_json()` helpers\r\n- `app_log_backend_exception()` for error logging\r\n- POST/Redirect/GET for all form submissions\r\n- `ON DUPLICATE KEY UPDATE` for safe upserts\r\n- `app_backend_render_header()` / `app_backend_render_footer()` for page chrome\r\n- CSS custom properties: `--accent`, `--panel`, `--line`, `--text`, `--muted`, `--shadow`\r\n- All new tables use `CREATE TABLE IF NOT EXISTS` (idempotent, no separate migration needed)","is_text_editable":1,"can_edit_inline":1}
documents · upload
2026-04-07 15:06:24 · anonymous · /backend/documents.php?backend_document_id=8
change
backend_document #10
Context
{"file_name":"SESSION_LOG_2026-04-07.md","mime_type":"application/octet-stream"}
Before
[]
After
{"backend_document_id":"10","document_type":"upload","title":"Claude 04-07-2026","slug":"claude-04-07-2026","summary_text":"Claude 04-07-2026 fixing backend Document areas","content_markdown":null,"content_html":null,"file_name":"SESSION_LOG_2026-04-07.md","stored_name":"20260407-190624-56f0e818.md","mime_type":"application/octet-stream","file_size_bytes":"21112","storage_path":"/mnt/drive1/customerdb/backend/documents_storage/20260407-190624-56f0e818.md","is_deleted":"0","created_at":"2026-04-07 15:06:24","updated_at":"2026-04-07 15:06:24","editor_content":"# Session Log — 2026-04-07\n\nAll work completed in this session on the CustomerDB backend application.\n\n---\n\n## Summary of New Modules and Changes\n\n| Area | File(s) | Status |\n|------|---------|--------|\n| Bills Manager | `backend/bills_service.php`, `backend/bills.php` | New |\n| Next-Day Email Job | `backend/jobs/send_nextday_customer_emails.php` | New |\n| Cron Manager UI | `backend/cron_manager.php` | New |\n| Error Log UI | `backend/error_log.php` | New |\n| Change Log UI | `backend/change_log.php` | New |\n| Stocks & Crypto | `backend/stocks_crypto_service.php`, `backend/stocks_crypto.php` | New |\n| Backend Home | `backend/index.php` | Modified |\n| Documents Editor | `backend/documents.php` | Full rewrite |\n| Documents Service | `backend/document_service.php` | Bug fix |\n\n---\n\n## 1. Bills Manager\n\n### Files\n- `backend/bills_service.php` — 356 lines, service layer\n- `backend/bills.php` — 972 lines, UI page\n\n### Purpose\nReplaces a spreadsheet (`newbills2026.xlsx`) with a web-based bill payment tracker.\nTracks bank account opening balances, monthly bill payments, and computes running bank\nbalances in the same layout as the Excel spreadsheet.\n\n### Database Tables (auto-created on first load)\n\n**`bills_account`**\n| Column | Type | Notes |\n|--------|------|-------|\n| `bills_account_id` | INT PK AUTO | |\n| `name` | VARCHAR(120) | Bank name |\n| `sort_order` | INT | Display order |\n\n**`bills_item`**\n| Column | Type | Notes |\n|--------|------|-------|\n| `bills_item_id` | INT PK AUTO | |\n| `label` | VARCHAR(200) | Bill name |\n| `default_amount` | DECIMAL(12,2) | Pre-fills the Due column |\n| `default_account_id` | INT | Default bank to debit |\n| `notes` | TEXT | Instructions / URLs |\n| `sort_order` | INT | Row order |\n| `is_deleted` | TINYINT | Soft delete |\n\n**`bills_entry`**\nMonthly bill payment rows.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| `bills_entry_id` | INT PK AUTO | |\n| `bills_item_id` | INT | FK to `bills_item` |\n| `year`, `month` | INT | Billing period |\n| `amount_due` | DECIMAL(12,2) | Amount billed |\n| `amount_paid` | DECIMAL(12,2) | Amount actually paid |\n| `account_id` | INT | Bank used to pay |\n\n**`bills_balance`**\nOpening bank balances per month.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| `bills_balance_id` | INT PK AUTO | |\n| `account_id` | INT | FK to `bills_account` |\n| `year`, `month` | INT | Period |\n| `opening_balance` | DECIMAL(14,2) | Balance at start of month |\n\n### Seed Data\nOn first load (empty table), the following are auto-seeded from the original Excel file:\n\n**Accounts:** USAA, MIDFLORIDA, Centenial, CapitalOne\n\n**Bills (11 items):** MidFlorida Mortgage, MidFlorida Credit Card, USAA Credit Card,\nCentenial Bank, Electricity, Waste Management, Comcast/Xfinity, Insurance, Water,\nCapitalOne #1, CapitalOne #2\n\n### Service Functions\n\n```php\napp_install_bills_schema(mysqli $conn): void\napp_bills_seed_defaults(mysqli $conn): void\napp_bills_accounts(mysqli $conn): array\napp_bills_all_accounts(mysqli $conn): array\napp_bills_items(mysqli $conn): array\napp_bills_balances(mysqli $conn, int $year, int $month): array       // map: account_id → float\napp_bills_entries(mysqli $conn, int $year, int $month): array        // map: item_id → [due, paid, account_id]\napp_bills_active_months(mysqli $conn, int $year): array\napp_bills_save_balance(mysqli $conn, int $year, int $month, int $accountId, float $balance): void\napp_bills_save_entry(mysqli $conn, int $year, int $month, int $itemId, ?float $due, ?float $paid, ?int $accountId): void\napp_bills_save_account(mysqli $conn, array $data): int\napp_bills_delete_account(mysqli $conn, int $id): void\napp_bills_save_item(mysqli $conn, array $data): int\napp_bills_delete_item(mysqli $conn, int $id): void\napp_bills_reorder_item(mysqli $conn, int $id, string $dir): void\napp_bills_copy_month(mysqli $conn, int $fromYear, int $fromMonth, int $toYear, int $toMonth): int\n```\n\n### UI Features (`bills.php`)\n- Month/year navigation with ◀ / ▶ buttons and active-month pills\n- **Bank Balances section** — editable opening balance per account, inline Save button\n- **Bills table** — spreadsheet-style rows with:\n  - Amount Due (editable, pre-filled from default)\n  - Amount Paid (editable, AJAX auto-save after 600 ms debounce)\n  - Account selector (which bank pays this bill)\n  - Balance After column (computed client-side in real time)\n  - Up/Down sort buttons\n  - Edit and Delete per row\n- **Sticky running totals sidebar** — shows each bank's current balance as bills are entered\n- **Copy from previous month** — modal to copy all entries from a prior month to the current one\n- **Add Bill / Edit Bill modals**\n- **Add Account / Edit Account modals**\n- All saves use POST/Redirect/GET; bill entry changes auto-save via `fetch()` AJAX\n\n### Running Total Calculation\nJavaScript function `recalcTotals()` walks bills in DOM order, maintains a\n`bal[accountId]` map starting from opening balances, subtracts `amount_paid` from the\nselected account for each bill, and updates the \"Balance After\" column and sidebar panel\nin real time — matching the Excel spreadsheet formula logic.\n\n---\n\n## 2. Next-Day Customer Email Job\n\n### File\n- `backend/jobs/send_nextday_customer_emails.php` — 158 lines\n\n### Purpose\nPHP CLI translation of the VBA macro `RunNextDayCustomerEmails()`.\nQueries `setmore_appointments` for appointments scheduled for tomorrow\n(status ≠ Cancelled) and sends a reminder email to each customer.\n\n### Usage\n```bash\n# Normal run (sends real emails)\nphp backend/jobs/send_nextday_customer_emails.php\n\n# Dry run — prints what would be sent, no emails sent\nphp backend/jobs/send_nextday_customer_emails.php --dry-run\n\n# Override date (for testing a specific date)\nphp backend/jobs/send_nextday_customer_emails.php --date=2026-04-09\n```\n\n### Recommended Cron Schedule\n```\n0 20 * * *  php /path/to/backend/jobs/send_nextday_customer_emails.php\n```\nRuns at 8:00 PM every evening, sends reminders for the following day's appointments.\n\n### Email Content\n- Subject: `Reminder: Your appointment at Ella's Alterations tomorrow`\n- Body matches the original VBA email with full address, phone, 5-line award\n  signature block, and a plain-text fallback\n- Uses `app_send_mail()` / PHPMailer\n\n---\n\n## 3. Cron Manager UI\n\n### File\n- `backend/cron_manager.php` — 482 lines\n\n### Purpose\nWeb UI for managing scheduled background jobs. Stores job definitions in the database,\nallows toggling on/off, running immediately, editing schedules, and exporting to\n`/etc/cron.d/` format.\n\n### Database Table (auto-created)\n\n**`cron_job`**\n| Column | Type | Notes |\n|--------|------|-------|\n| `cron_job_id` | INT PK AUTO | |\n| `label` | VARCHAR(120) | Human name |\n| `description` | TEXT | What the job does |\n| `schedule` | VARCHAR(100) | Cron expression e.g. `0 20 * * *` |\n| `command` | VARCHAR(500) | Shell command to run |\n| `enabled` | TINYINT | 0 = disabled, 1 = enabled |\n| `last_run_at` | DATETIME | Updated on \"Run Now\" |\n| `last_output` | TEXT | Captured stdout/stderr |\n| `sort_order` | INT | Display order |\n\n### Seeded Jobs (on first install)\n1. **Next-Day Customer Emails** — `0 20 * * *` — `php backend/jobs/send_nextday_customer_emails.php`\n2. **Morning Jobs** — `0 7 * * *` — `php backend/jobs/morning_jobs.php`\n3. **Nightly Reports** — `0 23 * * *` — `php backend/jobs/nightly_reports.php`\n4. **DB Backup** — `0 2 * * *` — `bash backend/bin/db_backup.sh`\n5. **Daily Cleanup** — `30 3 * * *` — `php backend/jobs/daily_cleanup.php`\n6. **Add Name Records Auto Delete** — `0 4 * * *` — `php backend/jobs/cleanup_name_records.php`\n\nNew jobs are added idempotently (checked by label before inserting) so existing\ninstallations are not re-seeded.\n\n### UI Features\n- Table listing all jobs with schedule, enabled toggle, last run time\n- **Toggle** — flip enabled/disabled immediately (POST/redirect)\n- **▶ Run Now** — executes the command via `exec()`, captures output, stores to DB, shows in modal\n- **Add / Edit** — form with label, description, command, schedule, enabled flag\n- **Schedule presets** — quick-select buttons (hourly, daily at common times, weekly, monthly)\n- `cron_describe(string $expr): string` — converts `0 20 * * *` → \"Daily at 20:00\"\n- **Export Crontab** — writes `/tmp/customerdb_crontab_export.txt` in `/etc/cron.d/` format\n\n---\n\n## 4. Error Log UI\n\n### File\n- `backend/error_log.php` — 262 lines\n\n### Purpose\nDedicated UI for browsing `backend_error_log` records with filtering, pagination,\nand per-entry management.\n\n### Features\n- **Stats bar** — Total errors, Today's errors, Latest error timestamp\n- **Filter bar** — Search (message/context), Source dropdown, Severity dropdown\n- **Pagination** — 50 per page with smart ellipsis navigator\n- **Per-row delete** — removes individual log entries\n- **Clear All button** — truncates the entire log (with confirmation)\n- JSON context blocks displayed in `<details>` collapsibles with dark monospace styling\n- URL: `/backend/error_log.php`\n\n---\n\n## 5. Change Log UI\n\n### File\n- `backend/change_log.php` — 248 lines\n\n### Purpose\nDedicated UI for browsing `backend_change_log` records — audit trail of all\ndata changes across the application.\n\n### Features\n- **Filter bar** — Search, Area, Action type, Entity type dropdowns\n- **Pagination** — smart ellipsis navigator\n- **Per-row detail panels:**\n  - Before / After / Context — collapsed JSON blocks\n  - Changed Data — open by default, shows the changed fields summary\n- Action badges color-coded by type (create, update, delete)\n- URL: `/backend/change_log.php`\n\n---\n\n## 6. Stocks & Crypto Module\n\n### Files\n- `backend/stocks_crypto_service.php` — 269 lines, service layer\n- `backend/stocks_crypto.php` — 667 lines, UI page\n\n### Purpose\nTrack a personal investment portfolio — individual stocks, ETFs, precious metals,\nand crypto. Supports live price fetching, manual daily price entry, monthly crypto\nbuy tracking, and portfolio gain/loss analysis.\n\n### Database Tables (auto-created)\n\n**`stocks_asset`**\n| Column | Type | Notes |\n|--------|------|-------|\n| `stocks_asset_id` | INT PK AUTO | |\n| `ticker` | VARCHAR(20) | e.g. `AAPL`, `BTC`, `GLD` |\n| `name` | VARCHAR(120) | Display name |\n| `asset_type` | ENUM | `stock`, `etf`, `crypto`, `metal`, `other` |\n| `shares` | DECIMAL(18,8) | Quantity owned |\n| `cost_basis_total` | DECIMAL(14,6) | Total purchase cost |\n| `is_active` | TINYINT | Soft hide |\n\n**`stocks_price`**\nDaily price records.\n\n| Column | Type | Notes |\n|--------|------|-------|\n| `stocks_price_id` | INT PK AUTO | |\n| `ticker` | VARCHAR(20) | |\n| `price_date` | DATE | |\n| `price` | DECIMAL(14,6) | |\n| `source` | VARCHAR(40) | `manual` or `yahoo` |\n\nUnique constraint on `(ticker, price_date)` — upserts with `ON DUPLICATE KEY UPDATE`.\n\n**`crypto_monthly_buy`**\n| Column | Type | Notes |\n|--------|------|-------|\n| `crypto_monthly_buy_id` | INT PK AUTO | |\n| `ticker` | VARCHAR(20) | |\n| `year`, `month` | INT | |\n| `quantity` | DECIMAL(18,8) | Crypto units purchased |\n| `amount_usd` | DECIMAL(14,2) | USD spent |\n| `notes` | VARCHAR(255) | |\n\n### Service Functions\n\n```php\napp_install_stocks_schema(mysqli $conn): void\napp_stocks_assets(mysqli $conn, string $type = ''): array\napp_stocks_save_asset(mysqli $conn, array $data): int\napp_stocks_delete_asset(mysqli $conn, int $id): void\napp_stocks_save_price(mysqli $conn, string $ticker, string $date, float $price, string $source = 'manual'): void\napp_stocks_save_prices_bulk(mysqli $conn, string $date, array $prices): int\napp_stocks_latest_prices(mysqli $conn): array                          // map: ticker → [price, date]\napp_stocks_price_history(mysqli $conn, string $ticker, int $limit = 90): array\napp_stocks_fetch_live_price(string $ticker): ?float                    // Yahoo Finance API, 8s timeout\napp_stocks_fetch_all_live(mysqli $conn): array                         // fetches all active tickers\napp_crypto_monthly_buys(mysqli $conn, int $year, int $month = 0): array\napp_crypto_save_monthly_buy(mysqli $conn, array $data): void\napp_crypto_delete_monthly_buy(mysqli $conn, int $id): void\napp_stocks_dashboard(mysqli $conn): array                              // cost_basis, current_value, gain_loss, gain_pct per asset\napp_stocks_stats(mysqli $conn): array                                  // total portfolio stats\n```\n\n### Live Price Source\nYahoo Finance unofficial API:\n```\nhttps://query1.finance.yahoo.com/v8/finance/chart/{TICKER}?interval=1d&range=1d\n```\n8-second timeout, reads `.chart.result[0].meta.regularMarketPrice`.\n\n### UI Tabs (`stocks_crypto.php`)\n\n1. **Portfolio** — dashboard table with ticker, shares, cost basis, current value,\n   gain/loss, gain %, latest price date. Stats bar shows total value, total cost,\n   total gain/loss. \"Fetch Live Prices\" button calls Yahoo Finance for all tickers.\n\n2. **Enter Prices** — manual daily price entry grid for all active assets,\n   date picker (defaults to today), bulk save.\n\n3. **Crypto Buys** — monthly crypto purchase log. Month/year selector, table of\n   ticker/quantity/USD/notes rows, add and delete per entry.\n\n4. **Add Asset** — form to add a new stock, ETF, crypto, metal, or other asset.\n\n### Auto-Refresh\nA checkbox above the stats bar auto-refreshes the Portfolio tab every 10 seconds.\nState persists in `localStorage` key `sc_auto_refresh`. On reload, strips `?ok=`\nand `?warn=` query params to prevent the notice from repeating every 10 seconds.\n\n---\n\n## 7. Backend Home — New Cards (`index.php`)\n\nSix new cards added to the backend home dashboard:\n\n| Card | Link | Secondary Action |\n|------|------|-----------------|\n| Customer Totals | `/backend/customer_totals.php` | — |\n| Ambient Weather | `/backend/ambient_weather.php` | — |\n| Bills Manager | `/backend/bills.php` | — |\n| Stocks & Crypto | `/backend/stocks_crypto.php` | — |\n| Cron Manager | `/backend/cron_manager.php` | — |\n| Error Log | `/backend/error_log.php` | Change Log |\n\n---\n\n## 8. Documents Editor — Full Rewrite (`documents.php`)\n\n### Problem\nGitHub Copilot introduced several bugs into the previous version:\n- `docLoad()` had mismatched closing braces, breaking the entire function\n- The document library was constrained to ~40% page width inside a grid column\n- The editor was a plain `<textarea>` with no formatting support\n\n### Solution\nComplete rewrite of all HTML, CSS, and JavaScript. PHP POST handlers were kept\nidentical — only the front-end was replaced.\n\n### Editor: EasyMDE\nReplaced the plain textarea with **EasyMDE** (Easy Markdown Editor) via CDN:\n```html\n<link rel=\"stylesheet\" href=\"https://unpkg.com/easymde/dist/easymde.min.css\">\n<script src=\"https://unpkg.com/easymde/dist/easymde.min.js\"></script>\n```\n\nEasyMDE wraps the `<textarea id=\"content_markdown\">` and syncs content on form submit.\n`ta.value = easyMDE.value()` is called explicitly in `submitDoc()` before `form.submit()`.\n\n### Toolbar Buttons\nSave (custom gradient btn) | Bold · Italic · Strikethrough | H1 · H2 · H3 |\nUnordered List · Ordered List · Checklist (custom) | Quote · Code · Table |\nHR · Link · Image URL (custom) | Undo · Redo | Fullscreen | Guide\n\n- **Save** button in toolbar calls `submitDoc()`, same as the Save Document button below\n- **Ctrl+S / Cmd+S** keyboard shortcut via CodeMirror `extraKeys`\n- **Checklist** inserts `- [ ] ` prefix on selected text\n- **Image URL** prompts for URL and alt text, inserts `![alt](url)` syntax\n\n### Preview Toggle\nEasyMDE's built-in `preview` and `side-by-side` buttons were **removed** to prevent\nboth raw markdown and rendered HTML showing simultaneously.\n\nA custom **Preview** button in the panel header replaces them:\n- Uses `marked.js` (CDN) to render the markdown client-side\n- **Preview on**: hides `EasyMDEContainer` and highlight strip; shows `#doc-preview-pane`\n- **Edit on**: hides preview pane; shows EasyMDE and highlight strip; calls `codemirror.refresh()`\n- Loading a document via `docLoad()` automatically returns to edit mode\n- Button state: pill shape, switches between \"👁 Preview\" and \"✏ Edit\" labels\n\n```html\n<script src=\"https://cdn.jsdelivr.net/npm/marked/marked.min.js\"></script>\n```\n\n### `docLoad()` — Clean Rewrite\nOld function had mismatched braces and redundant `editor.value` assignments.\nNew function:\n1. Returns to edit mode if preview is on\n2. Sets heading to \"Loading…\"\n3. Highlights active `<tr>` and `<a>` in library immediately\n4. `fetch('/backend/api/documents.php?backend_document_id=' + id)`\n5. Populates all meta fields (type, title, slug, summary)\n6. Sets `easyMDE.value(content)` from `editor_content` or `content_markdown`\n7. Shows/hides file notice\n8. Calls `renderVersionList(data.versions)`\n9. Updates URL via `history.replaceState()`\n10. Flashes panel border with accent color for 800 ms\n\n### Library Panel — Full Width\nOld layout: library was inside a 2-column grid alongside the editor.\nNew layout:\n```\n[Editor Panel          — full width]\n[Library Panel         — full width, max-height: 460px scrollable]\n[Upload | Versions     — 2-column row]\n```\n\nLive client-side search filters table rows by `textContent` without a page reload.\n\n### Word Count & Highlights\n- Word count and char count update on every keystroke via `codemirror.on('change', ...)`\n- 6 highlight color swatches + a clear option wrap selected text in\n  `<span class=\"hl\" style=\"background:COLOR\">...</span>`\n- Clear highlight strips existing `<span class=\"hl\">` wrappers from selected text\n\n### CSS Theme Conformity (visit.html standard)\nAll custom CSS was updated to match the application theme:\n\n| Property | Before | After |\n|----------|--------|-------|\n| Form input border-radius | `10px` | `12px` (matches `--radius-sm`) |\n| Form input padding | `8px 10px` | `11px 14px` |\n| Field label font-size | `0.73rem` + uppercase | `0.82rem`, no forced uppercase |\n| Field label letter-spacing | `0.07em` | `0.04em` |\n| Focus ring | `outline: 2px solid var(--accent)` | `outline: 2px solid rgba(175,77,49,0.3)` |\n| Panel header background | `rgba(244,239,231,0.6)` hardcoded | `var(--panel)` |\n| Toolbar background | `rgba(244,239,231,0.7)` hardcoded | `rgba(255,255,255,0.55)` |\n| Action bar background | `rgba(244,239,231,0.4)` hardcoded | `rgba(255,255,255,0.25)` |\n| Save button | `background: var(--accent)` | `linear-gradient(135deg, var(--accent), var(--accent-deep))` |\n| Action buttons | `border-radius: 7px` | `border-radius: 999px` pill shape |\n| Active library row tint | `rgba(26,122,154,0.06)` teal | `rgba(175,77,49,0.07)` accent |\n| Type badge (markdown) | `rgba(26,122,154,0.1)` teal | `rgba(175,77,49,0.1)` accent |\n| File notice tint | `rgba(26,122,154,0.06)` teal | `rgba(175,77,49,0.05)` accent |\n\n---\n\n## 9. `document_service.php` — Parse Error Fix\n\n### Problem\nThe function `app_backend_documents_dir()` had its closing `return $path; }` accidentally\ndisplaced to after `app_document_can_edit_inline()` (lines 147–148), with the rest of the\nfile's functions (`app_libreoffice_convert_to_html`, etc.) nested inside the unclosed\nfunction body. This caused a PHP parse error on every request to any page that\n`require_once`'s `document_service.php`, making `app_document_can_edit_inline()`\nappear undefined.\n\n### Fix\nTwo edits to `document_service.php`:\n\n1. Closed `app_backend_documents_dir()` properly after the `mkdir` block:\n```php\nfunction app_backend_documents_dir(): string\n{\n    $path = __DIR__ . '/documents_storage';\n    if (!is_dir($path)) {\n        mkdir($path, 0775, true);\n    }\n    return $path;   // ← added\n}                   // ← added\n```\n\n2. Removed the orphaned `return $path; }` that had been displaced to after\n`app_document_can_edit_inline()` at lines 147–148.\n\n---\n\n## Access URLs\n\n| Module | URL |\n|--------|-----|\n| Backend Home | `/backend/` |\n| Bills Manager | `/backend/bills.php` |\n| Stocks & Crypto | `/backend/stocks_crypto.php` |\n| Cron Manager | `/backend/cron_manager.php` |\n| Error Log | `/backend/error_log.php` |\n| Change Log | `/backend/change_log.php` |\n| Documents | `/backend/documents.php` |\n| Documents API | `/backend/api/documents.php` |\n\n---\n\n## Technology Used\n\n| Library | Version | Purpose |\n|---------|---------|---------|\n| EasyMDE | latest (unpkg CDN) | Rich markdown editor |\n| marked.js | latest (jsdelivr CDN) | Client-side markdown → HTML rendering |\n| Yahoo Finance API | v8 (unofficial) | Live stock/ETF price fetching |\n| PHPMailer | (existing) | Email sending via `app_send_mail()` |\n\n---\n\n## Coding Conventions (consistent with existing codebase)\n\n- `declare(strict_types=1)` in all PHP files\n- `app_db()` for database connections, `mysqli` throughout\n- `app_query_all()`, `app_query_one()`, `app_h()`, `app_send_json()` helpers\n- `app_log_backend_exception()` for error logging\n- POST/Redirect/GET for all form submissions\n- `ON DUPLICATE KEY UPDATE` for safe upserts\n- `app_backend_render_header()` / `app_backend_render_footer()` for page chrome\n- CSS custom properties: `--accent`, `--panel`, `--line`, `--text`, `--muted`, `--shadow`\n- All new tables use `CREATE TABLE IF NOT EXISTS` (idempotent, no separate migration needed)\n","is_text_editable":1,"can_edit_inline":1}
← Prev 1 180 181 182